QUEUE *QueueDelete( QUEUE *q ) { if ( q ) { if ( q->Val ) inchi_free(q->Val); inchi_free( q ); } return NULL; }
void FreeNeighList( NEIGH_LIST *pp ) { if ( pp ) { if ( pp[0] ) { inchi_free( pp[0] ); } inchi_free( pp ); } }
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If INCHI_IOSTREAM type is INCHI_IOSTREAM_STRING, flush INCHI_IOSTREAM string buffer to file (if non-NULL) and another file f2 supplied as parameter (typically, it will be stderr); then free buffer. If INCHI_IOSTREAM type is INCHI_IOSTREAM_FILE, just flush the both files. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ void inchi_ios_flush2(INCHI_IOSTREAM* ios, FILE *f2) { if (ios->type == INCHI_IOSTREAM_STRING) { if (ios->s.pStr) { if (ios->s.nUsedLength > 0) { if (ios->f) { fprintf(ios->f,"%-s", ios->s.pStr); fflush(ios->f); } if (f2!=ios->f) fprintf(f2,"%-s", ios->s.pStr); inchi_free(ios->s.pStr ); ios->s.pStr = NULL; ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0; } } } else if (ios->type == INCHI_IOSTREAM_FILE) { /* output to plain file: just flush it. */ if ( (ios->f) && (ios->f!=stderr) && (ios->f!=stdout) ) fflush(ios->f); if ( f2 && f2!=stderr && f2!=stdout) fflush(f2); } return; }
void CurTreeFree( CUR_TREE *cur_tree ) { if ( cur_tree ) { inchi_free( cur_tree->tree ); memset( cur_tree, 0, sizeof(*cur_tree) ); } }
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If INCHI_IOSTREAM type is INCHI_IOSTREAM_STRING, flush INCHI_IOSTREAM string buffer to file (if non-NULL); then free buffer. If INCHI_IOSTREAM type is INCHI_IOSTREAM_FILE, just flush the file. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ void inchi_ios_flush(INCHI_IOSTREAM* ios) { if (ios->type == INCHI_IOSTREAM_STRING) { if (ios->s.pStr) { if (ios->s.nUsedLength > 0) { if (ios->f) { fprintf(ios->f,"%-s", ios->s.pStr); fflush(ios->f); } inchi_free(ios->s.pStr ); ios->s.pStr = NULL; ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0; } } } else if (ios->type == INCHI_IOSTREAM_FILE) { /* output to plain file: just flush it. */ fflush(ios->f); } return; }
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Close INCHI_IOSTREAM: free string buffer and close the file. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ void inchi_ios_close(INCHI_IOSTREAM* ios) { if (ios->s.pStr) inchi_free(ios->s.pStr); ios->s.pStr = NULL; ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0; if ( (ios->f) && (ios->f!=stderr) && (ios->f!=stdout) && (ios->f!=stdin)) fclose(ios->f); return; }
/* Reset INCHI_IOSTREAM: set string buffer ptr to NULL (after freeing memory) but do not close associated file. */ void inchi_ios_free_str(INCHI_IOSTREAM *ios) { if ( NULL==ios ) return; if ( ios->s.pStr && ios->s.nAllocatedLength) inchi_free(ios->s.pStr); ios->s.pStr = NULL; ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0; return; }
QUEUE *QueueCreate( int nTotLength, int nSize ) { QUEUE *q = NULL; QINT_TYPE *Val = NULL; if ( nTotLength < 1 || nSize != (int)sizeof(QINT_TYPE) || !(q = (QUEUE *) inchi_calloc( 1, sizeof(QUEUE)) ) || !(Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize) )) { if ( q ) inchi_free(q); return NULL; } q->Val = Val; /* q->nSize = nSize; */ q->nTotLength = nTotLength; return q; }
int CurTreeReAlloc( CUR_TREE *cur_tree ) { if ( cur_tree ) { if ( cur_tree->tree && cur_tree->max_len > 0 && cur_tree->incr_len > 0 ) { void *p = cur_tree->tree; if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( cur_tree->max_len + cur_tree->incr_len, sizeof(cur_tree->tree[0]) ) ) { memcpy( cur_tree->tree, p, cur_tree->cur_len * sizeof(cur_tree->tree[0]) ); inchi_free( p ); cur_tree->max_len += cur_tree->incr_len; return 0; /* ok */ } } } return -1; /* error */ /* <BRKPT> */ }
/* Close INCHI_IOSTREAM: free string buffer and close associated file. */ void inchi_ios_close(INCHI_IOSTREAM* ios) { if ( NULL==ios ) return; if (ios->s.pStr) { inchi_free(ios->s.pStr); } ios->s.pStr = NULL; ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0; if ( NULL!=ios->f && stdout!=ios->f && stderr!=ios->f && stdin!=ios->f ) fclose(ios->f); return; }
/* This function's flushes previously hidden output and resets string stream returns n chars on success, otherwise -1 */ int inchi_ios_flush_not_displayed( INCHI_IOSTREAM * ios ) { char *obuf = NULL; int ret; if ( !ios ) return -1; obuf = (char *) inchi_calloc( ios->s.nUsedLength + 1, sizeof(char) ); if ( !obuf ) return -1; strcpy( obuf, ios->s.pStr); ios->s.nUsedLength = 0; ret = inchi_ios_print( ios, "%s", obuf ); inchi_free( obuf ); return ret; }
int CurTreeAlloc( CUR_TREE *cur_tree, int num_atoms ) { if ( cur_tree ) { if ( cur_tree->tree && cur_tree->max_len > 0 && !(cur_tree->max_len % num_atoms) ) { /* do not reallocate */ cur_tree->cur_len = 0; cur_tree->incr_len = num_atoms; memset( cur_tree->tree, 0, cur_tree->max_len * sizeof(cur_tree->tree[0]) ); return 0; /* ok */ } inchi_free( cur_tree->tree ); memset( cur_tree, 0, sizeof(*cur_tree) ); if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( num_atoms, sizeof(cur_tree->tree[0]) ) ) { cur_tree->incr_len = cur_tree->max_len = num_atoms; return 0; /* ok */ } } return -1; /* error */ /* <BRKPT> */ }
/* Make a copy of INCHI_IOSTREAM */ int inchi_ios_create_copy(INCHI_IOSTREAM* ios, INCHI_IOSTREAM* ios0) { if ( ios ) memset( ios, 0, sizeof(*ios) ); ios->type = ios0->type; if ( ios->type == INCHI_IOSTREAM_TYPE_STRING ) { if ( ios->s.pStr ) inchi_free( ios->s.pStr ); ios->s.pStr = (char *) inchi_calloc( ios0->s.nAllocatedLength, sizeof(char) ); if ( ios->s.pStr ) { ios->s.nUsedLength = ios0->s.nUsedLength; ios->s.nPtr = ios0->s.nPtr; } else return -1; /* no memory */ } ios->f = ios0->f; return 0; }
/**************************************************************************************** * * In this neighbor list the (vertex number) = (canonical number) - 1 * Since LinearCT is sorted so that parents are in ascending order * and all neighbors of a parent are smaller than the parent and are * in ascending order, the neighbors in the NEIGH_LIST are automatically * sorted in ascending order */ NEIGH_LIST *CreateNeighListFromLinearCT( AT_NUMB *LinearCT, int nLenCT, int num_atoms ) { /* atom numbers in LinearCT are canonical numbers * order: parent[i] > neigh[i][0] < neigh[i][1]...<neigh[i][n] < parent[i+1] > neigh[i+1][0] < ... * parent[i] < parent[i+1] */ int i, j; S_CHAR *valence = NULL; NEIGH_LIST *pp = NULL; AT_NUMB *pAtList = NULL; AT_RANK n_vertex, n_neigh; int err = 1, num_bonds; int length, start; if ( (int)LinearCT[0] > num_atoms ) { goto exit_function; } if ( !(valence = (S_CHAR*)inchi_calloc( num_atoms+1, sizeof(valence[0]) ) ) ) { goto exit_function; } for ( i = 1, num_bonds = 0, n_vertex = LinearCT[0]; i < nLenCT; i ++ ) { if ( (n_neigh = LinearCT[i]) < n_vertex ) { valence[n_neigh] ++; valence[n_vertex] ++; num_bonds += 2; } else if ( (int)(n_vertex = n_neigh) > num_atoms ) { goto exit_function; } } if ( (int)n_vertex != num_atoms ) { goto exit_function; } length = num_bonds + num_atoms + 1; if ( pp = (NEIGH_LIST *) inchi_calloc((num_atoms+1), sizeof(NEIGH_LIST)) ) { if ( pAtList = (AT_NUMB *) inchi_malloc( length*sizeof(*pAtList) ) ) { /* create empty connection table */ for ( i = 1, length = 0; i <= num_atoms; i ++ ) { start = length; length += (valence[i]+1); pp[i-1] = pAtList + start; pp[i-1][0] = 0; } /* fill out the CT */ for ( i = 1, n_vertex = LinearCT[0]-1; i < nLenCT; i ++ ) { if ( (n_neigh = LinearCT[i]-1) < n_vertex ) { /* vertex - neighbor connection */ j = (int)(++pp[(int)n_vertex][0]); pp[(int)n_vertex][j] = n_neigh; /* neighbor - vertex connection */ j = (int)(++pp[(int)n_neigh][0]); pp[(int)n_neigh][j] = n_vertex; } else if ( (int)(n_vertex = n_neigh) >= num_atoms ) { goto exit_function; } } err = 0; } } exit_function: if ( valence ) { inchi_free( valence ); } if ( err ) { if ( pAtList ) inchi_free( pAtList ); if ( pp ) { inchi_free( pp ); pp = NULL; } } return pp; }
EXPIMP_TEMPLATE INCHI_API int INCHI_DECL GetINCHIKeyFromINCHI(const char* szINCHISource, const int xtra1, const int xtra2, char* szINCHIKey, char* szXtra1, char* szXtra2) { int ret = INCHIKEY_OK; int ret1 = INCHIKEY_OK; int cn; size_t slen, i, j, jproto=0, ncp, pos_slash1=0; char *str = NULL, *smajor = NULL, *sminor = NULL, *sproto=NULL, *stmp = NULL, tmp[MINOUTLENGTH]; unsigned char digest_major[32], digest_minor[32]; char flagstd = 'S', /* standard key */ flagnonstd = 'N', /* non-standard key */ flagver = 'A', /* InChI v. 1 */ flagproto = 'N'; /* no [de]protonization , by default */ int nprotons; /* Protonization encoding: N 0 O +1 P +2 Q +3 R +4 S +5 T +6 U +7 V +8 W +9 X +10 Y +11 Z +12 M -1 L-2 K -3 J -4 I -5 H -6 G -7 F -8 E -9 D -10 C -11 B -12 A < -12 or > +12 */ static const char *pplus = "OPQRSTUVWXYZ"; static const char *pminus = "MLKJIHGFEDCB"; int bStdFormat = 0; size_t bytelen = 32; /* Check if input is a valid InChI string */ /* .. non-empty */ if (szINCHISource==NULL) return INCHIKEY_EMPTY_INPUT; slen = strlen(szINCHISource); /* .. has valid prefix */ if (slen<LEN_INCHI_STRING_PREFIX+3) return INCHIKEY_INVALID_INCHI_PREFIX; if (memcmp(szINCHISource,INCHI_STRING_PREFIX,LEN_INCHI_STRING_PREFIX)) return INCHIKEY_INVALID_INCHI_PREFIX; /* .. has InChI version 1 */ /* if (!isdigit(szINCHISource[LEN_INCHI_STRING_PREFIX]) ) */ if ( szINCHISource[LEN_INCHI_STRING_PREFIX] != '1' ) return INCHIKEY_INVALID_INCHI_PREFIX; /* .. optionally has a 'standard' flag character */ pos_slash1 = LEN_INCHI_STRING_PREFIX+1; if (szINCHISource[pos_slash1]=='S') { /* Standard InChI ==> standard InChIKey */ bStdFormat = 1; pos_slash1++; } /* .. has trailing slash in the right place */ if (szINCHISource[pos_slash1]!='/') return INCHIKEY_INVALID_INCHI_PREFIX; /* .. the rest of source string contains at least one a..Z0.9 or slash */ /* TODO: improve/add full string check */ if (!isalnum(szINCHISource[pos_slash1+1] ) && ( szINCHISource[pos_slash1+1]!='/' ) ) return INCHIKEY_INVALID_INCHI; /*^^^ Ok. Will use a local copy of the source. */ extract_inchi_substring(&str, szINCHISource, slen); if (NULL==str) { ret = INCHIKEY_NOT_ENOUGH_MEMORY; goto fin; } slen = strlen(str); /*^^^ Make buffers. */ smajor = (char*) inchi_calloc( slen+1, sizeof(char)); if (NULL==smajor) { ret = INCHIKEY_NOT_ENOUGH_MEMORY; goto fin; } sminor = (char*) inchi_calloc( 2*slen + 2, sizeof(char)); /* we may double the length ... */ if (NULL==sminor) { ret = INCHIKEY_NOT_ENOUGH_MEMORY; goto fin; } stmp = (char*) inchi_calloc( slen+1, sizeof(char)); if (NULL==stmp) { ret = INCHIKEY_NOT_ENOUGH_MEMORY; goto fin; } sproto = (char*) inchi_calloc( slen+1, sizeof(char)); if (NULL==sproto) { ret = INCHIKEY_NOT_ENOUGH_MEMORY; goto fin; } szINCHIKey[0] = '\0'; /*^^^ Extract the major block. */ smajor[0] = '\0'; for (j = pos_slash1 + 1; j < slen-1; j++) { if (str[j]=='/') { cn = str[j+1]; switch (cn) { /* anything allowed from a major part */ case 'c': case 'h': case 'q': continue; /* "/p"; protons now go to to special string, not to minor hash */ case 'p': jproto = j; continue; /* "/f", "/r" : may not occur in stdInChI */ case 'f': case 'r': if ( bStdFormat ) { ret = INCHIKEY_INVALID_STD_INCHI; goto fin; } break; /* anything allowed from a minor part */ default: break; } break; } } j++; if (j==slen) j++; else j--; ncp=0; if (jproto) ncp = jproto - pos_slash1 - 1; else ncp = j - pos_slash1 - 1; /*^^^ Trim 'InChI=1[S]/' */ memcpy(smajor,str+pos_slash1+1, ncp*sizeof(str[0])); smajor[ncp]='\0'; /* Treat protonization */ if (jproto) { /* 2009-01-07 fix bug/typo: assigned incorrect length to the protonation segment of /* source string ( was sproto[ncp]='\0'; should be sproto[lenproto]='\0'; ) */ int lenproto = j - jproto; if (lenproto<3) { /* empty "/p", should not occur */ ret = INCHIKEY_INVALID_INCHI; goto fin; } memcpy(sproto,str+pos_slash1+ncp+1, lenproto*sizeof(str[0])); sproto[lenproto]='\0'; nprotons = strtol( sproto+2, NULL, 10 ); if (nprotons > 0) { if (nprotons > 12) flagproto = 'A'; else flagproto = pplus[nprotons-1]; } else if (nprotons < 0) { if (nprotons < -12) flagproto = 'A'; else flagproto = pminus[-nprotons-1]; } else { /* should never occur */ ret = INCHIKEY_INVALID_STD_INCHI; goto fin; } } /*^^^ Extract the minor block. */ if (j != slen+1) /*^^^ check that something exists at right.*/ { ncp = slen-j; memcpy(sminor,str+j, (ncp)*sizeof(str[0])); sminor[ncp]='\0'; } else sminor[0]='\0'; #if INCHIKEY_DEBUG fprintf(stdout,"Source: {%-s}\n",str); fprintf(stdout,"SMajor: {%-s}\n",smajor); fprintf(stdout,"SMinor: {%-s}\n",sminor); fprintf(stdout,"SProto: {%-s}\n",sproto); #endif /*^^^ Compute and compose the InChIKey string. */ /*^^^ Major hash sub-string. */ for( i = 0; i < 32; i++ ) digest_major[i] = 0; sha2_csum( (unsigned char *) smajor, (int) strlen(smajor), digest_major ); /* !!! */ strcpy(tmp, base26_triplet_1(digest_major)); strcpy(tmp, base26_triplet_2(digest_major)); strcpy(tmp, base26_triplet_3(digest_major) ); strcpy(tmp, base26_triplet_4(digest_major) ); strcpy(tmp, base26_dublet_for_bits_56_to_64(digest_major)); sprintf(tmp,"%-.3s%-.3s%-.3s%-.3s%-.2s", base26_triplet_1(digest_major), base26_triplet_2(digest_major), base26_triplet_3(digest_major), base26_triplet_4(digest_major), base26_dublet_for_bits_56_to_64(digest_major)); strcat(szINCHIKey, tmp); #if (INCHIKEY_DEBUG>1) fprint_digest(stderr, "Major hash, full SHA-256",digest_major); #endif /*^^^ Minor hash sub-string. */ for( i = 0; i < 32; i++ ) digest_minor[i] = 0; slen = strlen(sminor); if ((slen>0)&&(slen<255)) { strcpy(stmp, sminor); strcpy(sminor+slen,stmp); } sha2_csum( (unsigned char *) sminor, (int) strlen(sminor), digest_minor ); #if (INCHIKEY_DEBUG>1) fprint_digest(stderr, "Minor hash, full SHA-256",digest_minor); #endif strcat(szINCHIKey, "-"); sprintf(tmp,"%-.3s%-.3s%-.2s", base26_triplet_1(digest_minor), base26_triplet_2(digest_minor), base26_dublet_for_bits_28_to_36(digest_minor)); strcat(szINCHIKey, tmp); /* Append a standard/non-standard flag */ slen = strlen(szINCHIKey); if ( bStdFormat ) szINCHIKey[slen] = flagstd; else szINCHIKey[slen] = flagnonstd; /*^^^ Append InChI v.1 flag */ szINCHIKey[slen+1] = flagver; /*^^^ Append dash */ szINCHIKey[slen+2] = '-'; /*^^^ Append protonization flag */ szINCHIKey[slen+3] = flagproto; szINCHIKey[slen+4] = '\0'; #if INCHIKEY_DEBUG fprintf(stdout,"szINCHIKey: {%-s}\n",szINCHIKey); #endif /* Hash extensions */ if ( xtra1 && szXtra1 ) { get_xtra_hash_major_hex(digest_major, szXtra1); #if INCHIKEY_DEBUG fprintf(stderr,"XHash1=%-s\n",szXtra1); fprintf(stderr,"j=%-d\n",j); #endif } if ( xtra2 && szXtra2 ) { get_xtra_hash_minor_hex(digest_minor, szXtra2); #if INCHIKEY_DEBUG fprintf(stderr,"XHash2=%-s\n",szXtra2); fprintf(stderr,"j=%-d\n",j); #endif } fin:if (NULL!=str) inchi_free(str); if (NULL!=smajor) inchi_free(smajor); if (NULL!=sminor) inchi_free(sminor); if (NULL!=stmp) inchi_free(stmp); if (NULL!=sproto) inchi_free(sproto); if ( (ret==INCHIKEY_OK) && (ret1!=INCHIKEY_OK) ) ret = ret1; return ret; }
/* Print to string buffer or to file+stderr */ int inchi_ios_eprint( INCHI_IOSTREAM * ios, const char* lpszFormat, ... ) { int ret=0, ret2=0; va_list argList; if (!ios) return -1; if (ios->type == INCHI_IOSTREAM_STRING) /* was #if ( defined(TARGET_API_LIB) || defined(BUILD_CINCHI_WITH_INCHIKEY) ) */ { /* output to string buffer */ int max_len, nAddLength = 0; char *new_str = NULL; my_va_start( argList, lpszFormat ); max_len = GetMaxPrintfLength( lpszFormat, argList); va_end( argList ); if ( max_len >= 0 ) { if ( ios->s.nAllocatedLength - ios->s.nUsedLength <= max_len ) { /* enlarge output string */ nAddLength = inchi_max( INCHI_ADD_STR_LEN, max_len ); new_str = (char *)inchi_calloc( ios->s.nAllocatedLength + nAddLength, sizeof(new_str[0]) ); if ( new_str ) { if ( ios->s.pStr ) { if ( ios->s.nUsedLength > 0 ) { memcpy( new_str, ios->s.pStr, sizeof(new_str[0])* ios->s.nUsedLength ); } inchi_free( ios->s.pStr ); } ios->s.pStr = new_str; ios->s.nAllocatedLength += nAddLength; } else { return -1; /* failed */ } } /* output */ my_va_start( argList, lpszFormat ); ret = vsprintf( ios->s.pStr + ios->s.nUsedLength, lpszFormat, argList ); va_end(argList); if ( ret >= 0 ) { ios->s.nUsedLength += ret; } return ret; } return -1; } else if (ios->type == INCHI_IOSTREAM_FILE) { if ( ios->f) { /* output to plain file */ my_va_start( argList, lpszFormat ); ret = inchi_vfprintf( ios->f, lpszFormat, argList ); va_end( argList ); #if ( !defined(TARGET_API_LIB) && !defined(BUILD_LIB_FOR_WINCHI) ) /*^^^ No output to stderr from within dll or GUI program */ if ( ios->f != stderr ) { my_va_start( argList, lpszFormat ); ret2 = vfprintf( stderr, lpszFormat, argList ); va_end( argList ); } #endif return ret? ret : ret2; } } /* no output */ return 0; }
int INChIToOrigAtom( INCHI_IOSTREAM *inp_molfile, ORIG_ATOM_DATA *orig_at_data, int bMergeAllInputStructures, int bGetOrigCoord, int bDoNotAddH, int vABParityUnknown, INPUT_TYPE nInputType, char *pSdfLabel, char *pSdfValue, long *lSdfId, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr ) { /* inp_ATOM *at = NULL; */ int num_dimensions_new; int num_inp_bonds_new; int num_inp_atoms_new; inp_ATOM *at_new = NULL; inp_ATOM *at_old = NULL; int nNumAtoms = 0; MOL_COORD *szCoordNew = NULL; MOL_COORD *szCoordOld = NULL; int i, j; if ( pStrErr ) { pStrErr[0] = '\0'; } /*FreeOrigAtData( orig_at_data );*/ if ( lSdfId ) *lSdfId = 0; do { at_old = orig_at_data? orig_at_data->at : NULL; /* save pointer to the previous allocation */ szCoordOld = orig_at_data? orig_at_data->szCoord : NULL; num_inp_atoms_new = INChIToInpAtom( inp_molfile, (bGetOrigCoord && orig_at_data)? &szCoordNew : NULL, bDoNotAddH, vABParityUnknown, nInputType, orig_at_data? &at_new:NULL, MAX_ATOMS, &num_dimensions_new, &num_inp_bonds_new, pSdfLabel, pSdfValue, lSdfId, pInpAtomFlags, err, pStrErr ); if ( num_inp_atoms_new <= 0 && !*err ) { MOLFILE_ERR_SET (*err, 0, "Empty structure"); *err = 98; } else if ( orig_at_data && !num_inp_atoms_new && 10 < *err && *err < 20 && orig_at_data->num_inp_atoms > 0 && bMergeAllInputStructures ) { *err = 0; /* end of file */ break; } else if ( num_inp_atoms_new > 0 && orig_at_data ) { /* merge pOrigDataTmp + orig_at_data => pOrigDataTmp; */ nNumAtoms = num_inp_atoms_new + orig_at_data->num_inp_atoms; if ( nNumAtoms >= MAX_ATOMS ) { MOLFILE_ERR_SET (*err, 0, "Too many atoms"); *err = 70; orig_at_data->num_inp_atoms = -1; } else if ( !at_old ) { /* the first structure */ orig_at_data->at = at_new; orig_at_data->szCoord = szCoordNew; at_new = NULL; szCoordNew = NULL; orig_at_data->num_inp_atoms = num_inp_atoms_new; orig_at_data->num_inp_bonds = num_inp_bonds_new; orig_at_data->num_dimensions = num_dimensions_new; } else if ( (orig_at_data->at = ( inp_ATOM* ) inchi_calloc( nNumAtoms, sizeof(inp_ATOM) )) && (!szCoordNew || (orig_at_data->szCoord = (MOL_COORD *) inchi_calloc( nNumAtoms, sizeof(MOL_COORD) ))) ) { /* switch at_new <--> orig_at_data->at; */ if ( orig_at_data->num_inp_atoms ) { memcpy( orig_at_data->at, at_old, orig_at_data->num_inp_atoms * sizeof(orig_at_data->at[0]) ); /* adjust numbering in the newly read structure */ for ( i = 0; i < num_inp_atoms_new; i ++ ) { for ( j = 0; j < at_new[i].valence; j ++ ) { at_new[i].neighbor[j] += orig_at_data->num_inp_atoms; } at_new[i].orig_at_number += orig_at_data->num_inp_atoms; /* 12-19-2003 */ } if ( orig_at_data->szCoord && szCoordOld ) { memcpy( orig_at_data->szCoord, szCoordOld, orig_at_data->num_inp_atoms * sizeof(MOL_COORD) ); } } if ( at_old ) { inchi_free( at_old ); at_old = NULL; } if ( szCoordOld ) { inchi_free( szCoordOld ); szCoordOld = NULL; } /* copy newly read structure */ memcpy( orig_at_data->at + orig_at_data->num_inp_atoms, at_new, num_inp_atoms_new * sizeof(orig_at_data->at[0]) ); if ( orig_at_data->szCoord && szCoordNew ) { memcpy( orig_at_data->szCoord + orig_at_data->num_inp_atoms, szCoordNew, num_inp_atoms_new * sizeof(MOL_COORD) ); } /* add other things */ orig_at_data->num_inp_atoms += num_inp_atoms_new; orig_at_data->num_inp_bonds += num_inp_bonds_new; orig_at_data->num_dimensions = inchi_max(num_dimensions_new, orig_at_data->num_dimensions); } else { MOLFILE_ERR_SET (*err, 0, "Out of RAM"); *err = -1; } } else if ( num_inp_atoms_new > 0 ) { nNumAtoms += num_inp_atoms_new; } if ( at_new ) { inchi_free( at_new ); at_new = NULL; } } while ( !*err && bMergeAllInputStructures ); /* if ( !*err ) { orig_at_data->num_components = MarkDisconnectedComponents( orig_at_data ); if ( orig_at_data->num_components == 0 ) { MOLFILE_ERR_SET (*err, 0, "No components found"); *err = 99; } if ( orig_at_data->num_components < 0 ) { MOLFILE_ERR_SET (*err, 0, "Too many components"); *err = 99; } } */ if ( szCoordNew ) { inchi_free( szCoordNew ); } if ( at_new ) { inchi_free( at_new ); } if ( !*err && orig_at_data ) { /* added testing (orig_at_data != NULL) */ if ( ReconcileAllCmlBondParities( orig_at_data->at, orig_at_data->num_inp_atoms, 0 ) ) { MOLFILE_ERR_SET (*err, 0, "Cannot reconcile stereobond parities"); /* <BRKPT> */ if (!orig_at_data->num_dimensions) { *err = 1; } } } if ( *err ) { FreeOrigAtData( orig_at_data ); } if ( *err && !(10 < *err && *err < 20) && pStrErr && !pStrErr[0] ) { MOLFILE_ERR_SET (*err, 0, "Unknown error"); /* <BRKPT> */ } return orig_at_data? orig_at_data->num_inp_atoms : nNumAtoms; }
/*********************************************************************************** * NEIGH_LIST pp[] is an array of pointers to the lists of neighboring atoms numbers * The first number in each list is a number of neighbors. * In case of bDoubleBondSquare != 0 neighbors connected by the double bond appear 2 times * The first element pp[0] is a pointer to be deallocated to free all the lists. */ NEIGH_LIST *CreateNeighList( int num_atoms, int num_at_tg, sp_ATOM* at, int bDoubleBondSquare, T_GROUP_INFO *t_group_info ) { /* +1 to add NULL termination */ NEIGH_LIST *pp = (NEIGH_LIST *) inchi_calloc((num_at_tg+1), sizeof(NEIGH_LIST)); T_GROUP *t_group = NULL; AT_NUMB *nEndpointAtomNumber = NULL; int num_t_groups = 0; int nFirstEndpointAtNoPos; AT_NUMB *pAtList = NULL; int length, start, val, i, j; if ( pp ) { if ( num_at_tg > num_atoms ) { t_group = t_group_info->t_group; num_t_groups = t_group_info->num_t_groups; nEndpointAtomNumber = t_group_info->nEndpointAtomNumber; } if ( !bDoubleBondSquare ) { for ( i = 0, length = 0; i < num_atoms; i ++ ) { length += (int)at[i].valence + (num_t_groups && at[i].endpoint); } length += num_atoms; for ( i = 0; i < num_t_groups; i ++ ) { length += (int)t_group[i].nNumEndpoints; } length += num_t_groups; } else { for ( i = 0, length = 0; i < num_atoms; i ++ ) { val = (int)at[i].valence; for ( j = 0; j < val; j ++ ) { length += 1 + (bDoubleBondSquare && BOND_DOUBLE == at[i].bond_type[j]); } length += (num_t_groups && at[i].endpoint); } length += num_atoms; for ( i = 0; i < num_t_groups; i ++ ) { length += (int)t_group[i].nNumEndpoints; } length += num_t_groups; } length ++; /* +1 to save number of neighbors */ if ( pAtList = (AT_NUMB *) inchi_malloc( length*sizeof(*pAtList) ) ) { if ( !bDoubleBondSquare ) { for ( i = 0, length = 0; i < num_atoms; i ++ ) { val = at[i].valence; start = length ++; for ( j = 0; j < val; j ++ ) { pAtList[length ++] = at[i].neighbor[j]; } /* add endpoint */ if (num_t_groups && at[i].endpoint) { pAtList[length ++] = num_atoms + (int)at[i].endpoint - 1; } pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */ pp[i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */ } } else { for ( i = 0, length = 0; i < num_atoms; i ++ ) { val = at[i].valence; start = length ++; for ( j = 0; j < val; j ++ ) { pAtList[length ++] = at[i].neighbor[j]; if ( bDoubleBondSquare && BOND_DOUBLE == at[i].bond_type[j] ) { pAtList[length ++] = at[i].neighbor[j]; /* a list of neighbor orig. numbers */ } } /* add endpoint */ if (num_t_groups && at[i].endpoint) { pAtList[length ++] = num_atoms + (int)at[i].endpoint - 1; } pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */ pp[i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */ } } /* add t-groups */ for ( i = 0; i < num_t_groups; i ++ ) { val = (int)t_group[i].nNumEndpoints; start = length ++; nFirstEndpointAtNoPos = (int)t_group[i].nFirstEndpointAtNoPos; for ( j = 0; j < val; j ++ ) { pAtList[length ++] = nEndpointAtomNumber[nFirstEndpointAtNoPos+j]; } pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */ pp[num_atoms+i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */ } } else { inchi_free ( pp ); return NULL; } } return pp; }
int inchi_ios_print_nodisplay( INCHI_IOSTREAM * ios, const char* lpszFormat, ... ) { if (!ios) return -1; if (ios->type == INCHI_IOSTREAM_STRING) { /* output to string buffer */ int ret=0, max_len; va_list argList; my_va_start( argList, lpszFormat ); max_len = GetMaxPrintfLength( lpszFormat, argList); va_end( argList ); if ( max_len >= 0 ) { if ( ios->s.nAllocatedLength - ios->s.nUsedLength <= max_len ) { /* enlarge output string */ int nAddLength = inchi_max( INCHI_ADD_STR_LEN, max_len ); char *new_str = (char *)inchi_calloc( ios->s.nAllocatedLength + nAddLength, sizeof(new_str[0]) ); if ( new_str ) { if ( ios->s.pStr ) { if ( ios->s.nUsedLength > 0 ) { memcpy( new_str, ios->s.pStr, sizeof(new_str[0])*ios->s.nUsedLength ); } inchi_free( ios->s.pStr ); } ios->s.pStr = new_str; ios->s.nAllocatedLength += nAddLength; } else { return -1; /* failed */ } } /* output */ my_va_start( argList, lpszFormat ); ret = vsprintf( ios->s.pStr + ios->s.nUsedLength, lpszFormat, argList ); va_end(argList); if ( ret >= 0 ) { ios->s.nUsedLength += ret; } return ret; } return -1; } else if (ios->type == INCHI_IOSTREAM_FILE) { /* output to file */ int ret=0, ret2=0; va_list argList; if (ios->f) { my_va_start( argList, lpszFormat ); ret = vfprintf( ios->f, lpszFormat, argList ); va_end( argList ); } else { my_va_start( argList, lpszFormat ); ret2 = vfprintf( stdout, lpszFormat, argList ); va_end( argList ); } return ret? ret : ret2; } /* no output */ return 0; }
int process_single_input( int argc, char *argv[ ] ) /**************************************************/ { /**************************************/ #endif /* #if ( BUILD_WITH_AMI == 1 ) */ /**************************************/ /* if not in AMI mode, main() starts here */ int bReleaseVersion = bRELEASE_VERSION; const int nStrLen = INCHI_SEGM_BUFLEN; int nRet = 0, nRet1; int i, k; long num_err, num_output, num_inp; /* long rcPict[4] = {0,0,0,0}; */ unsigned long ulDisplTime = 0; /* infinite, milliseconds */ unsigned long ulTotalProcessingTime = 0; char szTitle[MAX_SDF_HEADER+MAX_SDF_VALUE+256]; char szSdfDataValue[MAX_SDF_VALUE+1]; char *pStr = NULL; INPUT_PARMS inp_parms; INPUT_PARMS *ip = &inp_parms; STRUCT_DATA struct_data; STRUCT_DATA *sd = &struct_data; ORIG_ATOM_DATA OrigAtData; /* 0=> disconnected, 1=> original */ ORIG_ATOM_DATA *orig_inp_data = &OrigAtData; ORIG_ATOM_DATA PrepAtData[2]; /* 0=> disconnected, 1=> original */ ORIG_ATOM_DATA *prep_inp_data = PrepAtData; PINChI2 *pINChI[INCHI_NUM]; PINChI_Aux2 *pINChI_Aux[INCHI_NUM]; INCHI_IOSTREAM outputstr, logstr, prbstr, instr; INCHI_IOSTREAM *pout=&outputstr, *plog = &logstr, *pprb = &prbstr, *inp_file = &instr; #ifdef TARGET_EXE_STANDALONE char ik_string[256]; /*^^^ Resulting InChIKey string */ int ik_ret=0; /*^^^ InChIKey-calc result code */ int xhash1, xhash2; char szXtra1[65], szXtra2[65]; int inchi_ios_type = INCHI_IOSTREAM_STRING; #else int inchi_ios_type = INCHI_IOSTREAM_FILE; #endif /* internal tests --- */ #ifndef TEST_FPTRS STRUCT_FPTRS *pStructPtrs = NULL; #else STRUCT_FPTRS struct_fptrs, *pStructPtrs =&struct_fptrs; /* INCHI_LIB debug only */ #endif #if ( defined(REPEAT_ALL) && REPEAT_ALL > 0 ) int num_repeat = REPEAT_ALL; #endif #if ( TRACE_MEMORY_LEAKS == 1 ) _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF); /* for execution outside the VC++ debugger uncomment one of the following two */ /*#define MY_REPORT_FILE _CRTDBG_FILE_STDERR */ /*#define MY_REPORT_FILE _CRTDBG_FILE_STDOUT */ #ifdef MY_REPORT_FILE _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_WARN, MY_REPORT_FILE ); _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_ERROR, MY_REPORT_FILE ); _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_ASSERT, MY_REPORT_FILE ); #else _CrtSetReportMode(_CRT_WARN | _CRT_ERROR, _CRTDBG_MODE_DEBUG); #endif /* turn on floating point exceptions */ { /* Get the default control word. */ int cw = _controlfp( 0,0 ); /* Set the exception masks OFF, turn exceptions on. */ /*cw &=~(EM_OVERFLOW|EM_UNDERFLOW|EM_INEXACT|EM_ZERODIVIDE|EM_DENORMAL);*/ cw &=~(EM_OVERFLOW|EM_UNDERFLOW|EM_ZERODIVIDE|EM_DENORMAL); /* Set the control word. */ _controlfp( cw, MCW_EM ); } #endif #if ( defined(REPEAT_ALL) && REPEAT_ALL > 0 ) repeat: inchi_ios_close(inp_file); inchi_ios_close(pout); inchi_ios_close(plog); inchi_ios_close(pprb); pStr = NULL; #endif /* --- internal tests */ sd->bUserQuit = 0; #if ( defined( _WIN32 ) && defined( _CONSOLE ) && !defined( COMPILE_ANSI_ONLY ) ) if ( SetConsoleCtrlHandler( MyHandlerRoutine, 1 ) ) ConsoleQuit = WasInterrupted; #endif num_inp = 0; num_err = 0; num_output = 0; inchi_ios_init(inp_file, INCHI_IOSTREAM_FILE, NULL); inchi_ios_init(pout, inchi_ios_type, NULL); inchi_ios_init(plog, inchi_ios_type, stdout); inchi_ios_init(pprb, inchi_ios_type, NULL); if ( argc == 1 || argc==2 && ( argv[1][0]==INCHI_OPTION_PREFX ) && (!strcmp(argv[1]+1, "?") || !stricmp(argv[1]+1, "help") ) ) { HelpCommandLineParms(plog); inchi_ios_flush(plog); return 0; } /* original input structure */ memset( orig_inp_data , 0, sizeof( *orig_inp_data ) ); memset( prep_inp_data , 0, 2*sizeof( *prep_inp_data ) ); memset( pINChI, 0, sizeof(pINChI ) ); memset( pINChI_Aux, 0, sizeof(pINChI_Aux) ); memset( szSdfDataValue , 0, sizeof( szSdfDataValue ) ); plog->f = stderr; if ( 0 > ReadCommandLineParms( argc, (const char **)argv, ip, szSdfDataValue, &ulDisplTime, bReleaseVersion, plog) ) /* explicitly cast to (const char **) to avoid a warning about "incompatible pointer type":*/ { goto exit_function; } if ( !OpenFiles( &(inp_file->f), &(pout->f), &(plog->f), &(pprb->f), ip ) ) { goto exit_function; } if ( ip->bNoStructLabels ) { ip->pSdfLabel = NULL; ip->pSdfValue = NULL; } else if ( ip->nInputType == INPUT_INCHI_XML || ip->nInputType == INPUT_INCHI_PLAIN || ip->nInputType == INPUT_CMLFILE || ip->nInputType == INPUT_INCHI ) { /* the input may contain both the header and the label of the structure */ if ( !ip->pSdfLabel ) ip->pSdfLabel = ip->szSdfDataHeader; if ( !ip->pSdfValue ) ip->pSdfValue = szSdfDataValue; } inchi_ios_eprint( plog, "The command line used:\n\""); for(k=0; k<argc-1; k++) inchi_ios_eprint( plog, "%-s ",argv[k]); inchi_ios_eprint( plog, "%-s\"\n", argv[argc-1]); PrintInputParms(plog,ip); inchi_ios_flush2(plog, stderr); if ( !( pStr = (char*) inchi_malloc(nStrLen) ) ) { inchi_ios_eprint( plog, "Cannot allocate output buffer. Terminating\n"); inchi_ios_flush2(plog, stderr); goto exit_function; } pStr[0] = '\0'; #if ( READ_INCHI_STRING == 1 ) if ( ip->nInputType == INPUT_INCHI ) { memset( sd, 0, sizeof(*sd) ); ReadWriteInChI( inp_file, pout, plog, ip, sd, NULL, NULL, NULL, 0, NULL); inchi_ios_flush2(plog, stderr); ulTotalProcessingTime = sd->ulStructTime; num_inp = sd->fPtrStart; num_err = sd->fPtrEnd; goto exit_function; } #endif ulTotalProcessingTime = 0; if ( pStructPtrs ) { memset ( pStructPtrs, 0, sizeof(pStructPtrs[0]) ); /* debug: set CML reading sequence pStructPtrs->fptr = (INCHI_FPTR *)inchi_calloc(16, sizeof(INCHI_FPTR)); for ( i = 0; i < 15; i ++ ) pStructPtrs->fptr[i] = 15-i; pStructPtrs->cur_fptr = 7; pStructPtrs->len_fptr = 16; pStructPtrs->max_fptr = 14; */ } /**********************************************************************************************/ /* Main cycle : read input structures and create their INChI */ /**********************************************************************************************/ while ( !sd->bUserQuit && !bInterrupted ) { if ( ip->last_struct_number && num_inp >= ip->last_struct_number ) { nRet = _IS_EOF; /* simulate end of file */ goto exit_function; } /* read one structure from input and display optionally it */ nRet = GetOneStructure( sd, ip, szTitle, inp_file, plog, pout, pprb, orig_inp_data, &num_inp, pStr, nStrLen, pStructPtrs ); inchi_ios_flush2(plog, stderr); if ( pStructPtrs ) pStructPtrs->cur_fptr ++; if ( sd->bUserQuit ) break; switch ( nRet ) { case _IS_FATAL: num_err ++; case _IS_EOF: goto exit_function; case _IS_ERROR: num_err ++; case _IS_SKIP: continue; } /* create INChI for each connected component of the structure and optionally display them */ /* output INChI for the whole structure */ nRet1 = ProcessOneStructure( sd, ip, szTitle, pINChI, pINChI_Aux, inp_file, plog, pout, pprb, orig_inp_data, prep_inp_data, num_inp, pStr, nStrLen, 0 /* save_opt_bits */); inchi_ios_flush2(plog, stderr); #ifdef TARGET_EXE_STANDALONE /* correctly treat tabbed output with InChIKey */ if ( ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT ) if ( ip->bCalcInChIHash != INCHIHASH_NONE ) if (pout->s.pStr) if (pout->s.nUsedLength>0) if (pout->s.pStr[pout->s.nUsedLength-1]=='\n') /* replace LF with TAB */ pout->s.pStr[pout->s.nUsedLength-1] = '\t'; #endif /* free INChI memory */ FreeAllINChIArrays( pINChI, pINChI_Aux, sd->num_components ); /* free structure data */ FreeOrigAtData( orig_inp_data ); FreeOrigAtData( prep_inp_data ); FreeOrigAtData( prep_inp_data+1 ); ulTotalProcessingTime += sd->ulStructTime; nRet = inchi_max(nRet, nRet1); switch ( nRet ) { case _IS_FATAL: num_err ++; goto exit_function; case _IS_ERROR: num_err ++; continue; } #ifdef TARGET_EXE_STANDALONE if ( ip->bCalcInChIHash != INCHIHASH_NONE ) { char *buf = NULL; size_t slen = pout->s.nUsedLength; extract_inchi_substring(&buf, pout->s.pStr, slen); if (NULL==buf) { ik_ret = INCHIKEY_NOT_ENOUGH_MEMORY; } else { xhash1 = xhash2 = 0; if ( ( ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1 ) || ( ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2 ) ) xhash1 = 1; if ( ( ip->bCalcInChIHash == INCHIHASH_KEY_XTRA2 ) || ( ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2 ) ) xhash2 = 1; ik_ret = GetINCHIKeyFromINCHI(buf, xhash1, xhash2, ik_string, szXtra1, szXtra2); inchi_free(buf); } if (ik_ret==INCHIKEY_OK) { /* NB: correctly treat tabbed output with InChIKey & hash extensions */ char csep = '\n'; #ifdef TARGET_EXE_STANDALONE if ( ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT ) csep = '\t'; #endif inchi_ios_print(pout, "InChIKey=%-s",ik_string); if ( xhash1 ) inchi_ios_print(pout, "%cXHash1=%-s",csep,szXtra1); if ( xhash2 ) inchi_ios_print(pout, "%cXHash2=%-s",csep,szXtra2); inchi_ios_print(pout, "\n"); } else { inchi_ios_print(plog, "Warning (Could not compute InChIKey: ", num_inp); switch(ik_ret) { case INCHIKEY_UNKNOWN_ERROR: inchi_ios_print(plog, "unresolved error)"); break; case INCHIKEY_EMPTY_INPUT: inchi_ios_print(plog, "got an empty string)"); break; case INCHIKEY_INVALID_INCHI_PREFIX: case INCHIKEY_INVALID_INCHI: case INCHIKEY_INVALID_STD_INCHI: inchi_ios_print(plog, "got non-InChI string)"); break; case INCHIKEY_NOT_ENOUGH_MEMORY: inchi_ios_print(plog, "not enough memory to treat the string)"); break; default:inchi_ios_print(plog, "internal program error)"); break; } inchi_ios_print(plog, " structure #%-lu.\n", num_inp); if ( ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT ) inchi_ios_print(pout, "\n"); } inchi_ios_flush(pout); inchi_ios_flush2(plog, stderr); } else inchi_ios_flush(pout); #endif /* --- debug only --- if ( pStructPtrs->cur_fptr > 5 ) { pStructPtrs->cur_fptr = 5; } */ } /* end of main cycle - while ( !sd->bUserQuit && !bInterrupted ) */ exit_function: if ( (ip->bINChIOutputOptions & INCHI_OUT_XML) && sd->bXmlStructStarted > 0 ) { if ( !OutputINChIXmlStructEndTag( pout, pStr, nStrLen, 1 ) ) { inchi_ios_eprint( plog, "Cannot create end xml tag for structure #%ld.%s%s%s%s Terminating.\n", num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) ); inchi_ios_flush2(plog, stderr); sd->bXmlStructStarted = -1; /* do not repeat same message */ } } if ( (ip->bINChIOutputOptions & INCHI_OUT_XML) && ip->bXmlStarted ) { OutputINChIXmlRootEndTag( pout ); inchi_ios_flush(pout); ip->bXmlStarted = 0; } /* avoid memory leaks in case of fatal error */ if ( pStructPtrs && pStructPtrs->fptr ) { inchi_free( pStructPtrs->fptr ); } /* free INChI memory */ FreeAllINChIArrays( pINChI, pINChI_Aux, sd->num_components ); /* free structure data */ FreeOrigAtData( orig_inp_data ); FreeOrigAtData( prep_inp_data ); FreeOrigAtData( prep_inp_data+1 ); #if ( ADD_CMLPP == 1 ) /* BILLY 8/6/04 */ /* free CML memory */ FreeCml (); FreeCmlDoc( 1 ); #endif /* close output(s) */ inchi_ios_close(inp_file); inchi_ios_close(pout); inchi_ios_close(pprb); { int hours, minutes, seconds, mseconds; SplitTime( ulTotalProcessingTime, &hours, &minutes, &seconds, &mseconds ); inchi_ios_eprint( plog, "Finished processing %ld structure%s: %ld error%s, processing time %d:%02d:%02d.%02d\n", num_inp, num_inp==1?"":"s", num_err, num_err==1?"":"s", hours, minutes, seconds,mseconds/10); inchi_ios_flush2(plog, stderr); } inchi_ios_close(plog); if ( pStr ) inchi_free( pStr ); /* frees */ for ( i = 0; i < MAX_NUM_PATHS; i ++ ) { if ( ip->path[i] ) { free( (void*) ip->path[i] ); /* cast deliberately discards 'const' qualifier */ ip->path[i] = NULL; } } SetBitFree( ); /* internal tests --- */ #if ( defined(REPEAT_ALL) && REPEAT_ALL > 0 ) if ( num_repeat-- > 0 ) goto repeat; #endif /* --- internal tests */ #if ( bRELEASE_VERSION != 1 && defined(_DEBUG) ) if ( inp_file->f && inp_file->f != stdin ) { user_quit("Press Enter to exit ?", ulDisplTime); } #endif #if ( ( BUILD_WITH_AMI==1 ) && defined( _WIN32 ) && defined( _CONSOLE ) && !defined( COMPILE_ANSI_ONLY ) ) if ( bInterrupted ) return CTRL_STOP_EVENT; #endif return 0; }