示例#1
0
char *_strdup( const char *string )
{
    char *p = NULL;
    if ( string ) {
        size_t length = strlen( string );
        p = (char *)inchi_malloc( length + 1 );
        if ( p ) {
            strcpy( p, string );
        }
    }
    return p;
}
示例#2
0
int BreakAllTies( int num_atoms, int num_max, AT_RANK **pRankStack,
                     NEIGH_LIST *NeighList, AT_RANK *nTempRank, CANON_STAT *pCS)
{
    int i, nRet = -1, nNumRanks=1 /* value does not matter*/;
    
    AT_RANK *nPrevRank       = *pRankStack ++;
    AT_RANK *nPrevAtomNumber = *pRankStack ++;

    AT_RANK *nNewRank        = NULL;
    AT_RANK *nNewAtomNumber  = NULL;
        
    if ( !pRankStack[0] ) {
        pRankStack[0] = (AT_RANK *) inchi_malloc(num_max*sizeof(*nNewRank));
    }
    if ( !pRankStack[1] ) {
        pRankStack[1] = (AT_RANK *) inchi_malloc(num_max*sizeof(*nNewAtomNumber));
    }
    if ( !pRankStack[0] || !pRankStack[1] )
        return CT_OUT_OF_RAM;  /*   <BRKPT> */
    nNewRank       = pRankStack[0];
    nNewAtomNumber = pRankStack[1];

    if ( nNewRank && nNewAtomNumber ) {
        memcpy( nNewAtomNumber, nPrevAtomNumber, num_atoms*sizeof(nNewAtomNumber[0]));
        memcpy( nNewRank, nPrevRank, num_atoms*sizeof(nNewRank[0]));
     
        for ( i = 1, nRet=0; i < num_atoms; i ++ ) { /*  12-12-2001: replaced Prev... with New... */
            if ( nNewRank[(int)nNewAtomNumber[i-1]] == nNewRank[(int)nNewAtomNumber[i]] ) {
                nNewRank[nNewAtomNumber[i-1]] = (AT_RANK)i;
                nNumRanks = DifferentiateRanks2( num_atoms, NeighList,
                                                 nNumRanks, nNewRank, nTempRank,
                                                 nNewAtomNumber, &pCS->lNumNeighListIter, 1 );
                pCS->lNumBreakTies ++;
                nRet ++;
            }
        }
    }
    return nRet;
}
示例#3
0
/***********************************************************************************
 * 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;
}
示例#4
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;
}
示例#5
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;
}