示例#1
0
int main( int argc, char *argv[ ] )
{
#define nStrLen 256
int bReleaseVersion = bRELEASE_VERSION;

char    szSdfDataValue[MAX_SDF_VALUE+1];
char    szInchiCmdLine[512];
char    pStrInchiId[nStrLen], pStrLogId[nStrLen];
const   char *p1, *p2;


int   retcode= 0, retcode1 = 0,  i, k, tot_len;
int   inp_index, out_index;
int   nStructNo;

long  lSdfId;
long num_inp, num_err, num_output;

INPUT_PARMS inp_parms, *ip = &inp_parms;
STRUCT_DATA struct_data, *sd = &struct_data;


INCHI_IOSTREAM outputstr, logstr, prbstr, instr;
INCHI_IOSTREAM *out_stream=&outputstr, *log_stream=&logstr, *prb_stream=&prbstr, *inp_stream=&instr;

inchi_Input inchi_inp,      *pInp   = &inchi_inp;
inchi_Output genout, *pResults = &genout;
INCHIGEN_DATA       inchi_gendata,      *pGenData   = &inchi_gendata;
INCHIGEN_HANDLE  HGen = NULL;

char *pinfo;
int len_mess=0, len_mess1, mshift=0, was_print = 0;
char ik_string[256];    /*^^^ Resulting InChIKey string */
int ik_ret=0;           /*^^^ InChIKey-calc result code */
int xhash1, xhash2;
char szXtra1[256], szXtra2[256];

unsigned long  ulDisplTime = 0;    /*  infinite, milliseconds */
time_t elapsed;
/*^^^ Post-1.02b - moved from below */
int bTabbed=0;



/*^^^ Set debug output */

#if (TRACE_MEMORY_LEAKS == 1)

    _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
    /* for execution outside of 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 */
#if ( !defined(__STDC__) || __STDC__ != 1 )
    {
        /* 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

#endif /* #if (TRACE_MEMORY_LEAKS == 1) */




/*^^^ Set Ctrl+C trap under Win32 + MS VC++ */

#if( defined( _WIN32 ) && defined( _CONSOLE ) && defined(_MSC_VER) && _MSC_VER >= 800 && defined(ADD_WIN_CTLC) && !(defined(__STDC__) && __STDC__ == 1))
    if ( SetConsoleCtrlHandler( MyHandlerRoutine, 1 ) )
    {
        ; /*ConsoleQuit = WasInterrupted*/;
    }
#endif



    num_inp    = 0;
    num_err    = 0;
    num_output = 0;

    elapsed = time(NULL);

    /*^^^ Set original input structure */
    memset(pInp, 0, sizeof(*pInp));
    memset(pResults, 0, sizeof(*pResults));
    memset(pGenData, 0, sizeof(*pGenData));
    memset(szSdfDataValue, 0, sizeof(szSdfDataValue));

    /*^^^  Initialize I/O streams as string buffers so that they may be filled within dll;
           also associate files with the streams and use inchi_ios_flush to flush buffer content */

    inchi_ios_init(log_stream, INCHI_IOSTREAM_TYPE_STRING, NULL);
    inchi_ios_init(inp_stream, INCHI_IOSTREAM_TYPE_STRING, NULL);
    inchi_ios_init(out_stream, INCHI_IOSTREAM_TYPE_STRING, NULL);
    inchi_ios_init(prb_stream, INCHI_IOSTREAM_TYPE_STRING, NULL);


    /*^^^ Check command line */
    if ( argc < 2 || argc==2 && ( argv[1][0]==INCHI_OPTION_PREFX ) &&
        (!strcmp(argv[1]+1, "?") || !e_inchi_stricmp(argv[1]+1, "help") ) )
    {
        /* e_HelpCommandLineParms(stdout); */
        e_HelpCommandLineParmsReduced(log_stream);
        log_stream->f = stderr;
        inchi_ios_flush(log_stream);
        return 0;
    }

    if ( 0 > e_ReadCommandLineParms( argc, (const char **)argv, ip, szSdfDataValue, &ulDisplTime, bReleaseVersion, log_stream ) )
                                    /*^^^ Explicitly cast to (const char **) to avoid a
                                          warning about "incompatible pointer type":*/
    {

        goto exit_function;
    }


    /*^^^ Open files associated with I/O streams. */
    if ( !e_OpenFiles( &(inp_stream->f), &(out_stream->f), &(log_stream->f), &(prb_stream->f), ip ) )
        goto exit_function;



    /*^^^ Create InChI generator object. */
#ifndef USE_STDINCHI_API
    HGen = INCHIGEN_Create();
#else
    HGen = STDINCHIGEN_Create();
#endif

    if (NULL==HGen)
    {
        /*^^^ Probably, out of RAM. Could do nothing. */
        inchi_fprintf( stderr, "Could not create InChI generator (out of RAM?)\n" );
        goto exit_function;
    }




    /*^^^ Set input labelling opts */
    if ( ip->bNoStructLabels )
    {
        ip->pSdfLabel = NULL;
        ip->pSdfValue = NULL;
    }
    else
    if ( ip->nInputType == INPUT_INCHI_PLAIN  ||
         ip->nInputType == INPUT_INCHI_XML    ||
         ip->nInputType == INPUT_CMLFILE      )
    {
        /* 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;
    }
    e_PrintInputParms( log_stream, ip );
    inchi_ios_flush2(log_stream,stdout);
    pStrInchiId[0] = '\0';




    /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                Main cycle:  read input structures and create their InChI
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

    out_index = 0;


    while (!e_bInterrupted)
    {

        int bHasTimeout = 0;
        if ( ip->last_struct_number && num_inp >= ip->last_struct_number )
        {
            retcode = _IS_EOF; /*  simulate end of file */
            goto exit_function;
        }

        /*^^^ Create command line */
        szInchiCmdLine[0] = '\0';
        for ( i = 1; i < argc; i ++ )
        {
            if ( argv[i] && INCHI_OPTION_PREFX == argv[i][0] && argv[i][1] )
            {
                /*^^^ Omit certain options */
                if ( !e_inchi_memicmp( argv[i]+1, "start:", 6) ||
                     !e_inchi_memicmp( argv[i]+1, "end:",   4) ||
                     !e_inchi_stricmp( argv[i]+1, "Tabbed" )
                     )
                {
                    continue;
                }

                if ( !e_inchi_stricmp( argv[i]+1, "Inchi2Inchi" ) )
                {
                    inchi_ios_eprint( log_stream, "\nOption Inchi2Inchi is not supported (use classic interface). \n"  );
                    goto exit_function;
                }
                else if ( !e_inchi_stricmp( argv[i]+1, "Inchi2Struct" ) )
                {
                    inchi_ios_eprint( log_stream, "\nOption Inchi2Struct is not supported (use classic interface). \n"  );
                    goto exit_function;
                }


                if ( !e_inchi_memicmp( argv[i]+1, "w", 1 ) && isdigit( UCINT argv[i][2] ) )
                {
                    bHasTimeout = 1;
                }
                /*^^^ Add option to szInchiCmdLine */
                if ( strlen(szInchiCmdLine)+strlen(argv[i]) + 4 < sizeof(szInchiCmdLine) )
                {
                    if ( szInchiCmdLine[0] )
                        strcat( szInchiCmdLine, " " );
                    k = ( !(k=strcspn( argv[i], " \t" )) || argv[i][k] ); /* k means enclose in "" */
                    if (k)
                        strcat( szInchiCmdLine, "\"" );
                    strcat( szInchiCmdLine, argv[i] );
                    if (k)
                        strcat( szInchiCmdLine, "\"" );
                } else
                {
                    inchi_fprintf( stderr, "Too many options. Option \"%s\" ignored\n", argv[i] );
                }
            }
        }
        if ( !bHasTimeout )
        {
            /*^^^ Add default timeout option -W60: 60 seconds */
            char szW60[] = " ?W60";
            szW60[1] = INCHI_OPTION_PREFX;
            if ( strlen(szInchiCmdLine) + strlen( szW60 ) < sizeof(szInchiCmdLine) )
                strcat( szInchiCmdLine, szW60 );
            else
                inchi_fprintf( stderr, "Too many options. Option \"%s\" ignored\n", szW60 );
        }
        /*^^^ End of command line deal */


        if ( ip->nInputType==INPUT_INCHI_PLAIN )
        {
            inchi_ios_eprint( log_stream, "\nRestoring InChI from AuxInfo is not supported (use classic interface). \n"  );
            goto exit_function;
        }


        /*^^^ Skip input cycle */
        while(!e_bInterrupted)
        {
            inp_index = out_index;


            /*^^^ Read one structure from input */
            e_FreeInchi_Input( pInp );



            retcode = e_ReadStructure( sd, ip, inp_stream, log_stream, out_stream, prb_stream, pInp, num_inp+1,
                          /* for CML:*/ inp_index, &out_index );

            inchi_ios_flush2(log_stream,stdout);

            if ( _IS_SKIP != retcode)
            {
                lSdfId    = ( ip->bGetSdfileId )? ip->lSdfId : 0; /* if requested then CAS r.n. otherwise struct. number*/
                nStructNo = ( ip->lMolfileNumber > 0 )? ip->lMolfileNumber : num_inp+1;
                e_MakeOutputHeader( ip->pSdfLabel, ip->pSdfValue, lSdfId, nStructNo, pStrInchiId, pStrLogId );
            }

            /* e_ReadStructure() outputs the error/warning messages, so we do not need to re-output them here */
            switch (retcode)
            {
            case _IS_FATAL:
                num_inp ++;
                num_err ++;
                goto exit_function;
            case _IS_EOF:
                inchi_ios_eprint( log_stream, "\rStructure %d could not be read: Detected end of file. \r", num_inp+1 );
                goto exit_function;
            case _IS_ERROR:
                num_inp ++;
                num_err ++;
                continue;
            case _IS_SKIP:
                num_inp ++;
                continue;
            }
            break;
        }
        if ( e_bInterrupted )
        {
            inchi_ios_eprint( log_stream, "\nStructure %d could not be read: User Quit.\n", num_inp+1 );
            inchi_ios_flush2(log_stream,stdout);
            num_err ++;
            goto exit_function;
        }


        /*^^^ Analyze the chiral flag */

        p1 = NULL;
#ifndef USE_STDINCHI_API
        if ( (ip->nMode & REQ_MODE_CHIR_FLG_STEREO) && (ip->nMode & REQ_MODE_STEREO) &&
             ( ip->bChiralFlag & (FLAG_SET_INP_AT_CHIRAL | FLAG_SET_INP_AT_NONCHIRAL) ) )
                ; /* cmd line has priority over the chiral flag in Molfile */

        else if ( sd->bChiralFlag & FLAG_INP_AT_CHIRAL )
            p1 =  e_GetChiralFlagString( 1 );  /* input file has chiral flag */

        else if ( (ip->nMode & REQ_MODE_CHIR_FLG_STEREO) && (ip->nMode & REQ_MODE_STEREO) ||
             (sd->bChiralFlag & FLAG_INP_AT_NONCHIRAL) )  /* fix 04/05/2005 D.T.*/
            /* chiral flag requested (/SUCF) or input has non-chiral flag */
            p1 =  e_GetChiralFlagString( 0 );

        if (p1)
        {
            if ( strlen(szInchiCmdLine) + strlen( p1 ) < sizeof(szInchiCmdLine) )
                strcat( szInchiCmdLine, p1 );
            else
                inchi_fprintf( stderr, "Too many options. Option \"%s\" ignored\n", p1 );
        }
#endif
        pInp->szOptions = szInchiCmdLine;


        /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        create INChI for each connected component of the structure and optionally
        display them; output INChI for the whole structure.
        Use compartmentalized library interface.
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

#ifdef CREATE_0D_PARITIES
        if ( !pInp->stereo0D && !pInp->num_stereo0D )
        {
            int bPointedEdgeStereo = (0 != (TG_FLAG_POINTED_EDGE_STEREO & ip->bTautFlags));
            set_0D_stereo_parities( pInp, bPointedEdgeStereo );
            Clear3D2Dstereo(pInp);
        }
#endif
#ifdef NEIGH_ONLY_ONCE
        e_RemoveRedundantNeighbors(pInp);
#endif

        len_mess = len_mess1 = 0;
        pinfo = (char*) &(pGenData->pStrErrStruct);
        was_print = 0;



        /*^^^ Set up */

#ifndef USE_STDINCHI_API
        retcode = INCHIGEN_Setup( HGen, pGenData, pInp );
#else
        retcode = STDINCHIGEN_Setup( HGen, pGenData, pInp );
#endif

        len_mess1 = strlen(pinfo);
        if (len_mess1 > len_mess)
        {
            mshift = len_mess?1:0;
            inchi_ios_eprint(log_stream, "*** %-s [Initialization] %-s\n", pStrLogId, pinfo+len_mess+mshift);
            inchi_ios_flush2(log_stream,stdout);
            len_mess = len_mess1;
            was_print = 1;
        }



        /*^^^ Normalization step */
        if ( (retcode == inchi_Ret_OKAY) || (retcode == inchi_Ret_WARNING) )
        {

#ifndef USE_STDINCHI_API
            retcode = INCHIGEN_DoNormalization(HGen, pGenData);
#else
            retcode = STDINCHIGEN_DoNormalization(HGen, pGenData);
#endif

            len_mess1 = strlen(pinfo);
            if (len_mess1 > len_mess)
            {
                mshift = len_mess?1:0;
                inchi_ios_eprint(log_stream, "*** %-s [Normalization] %-s\n", pStrLogId, pinfo+len_mess+mshift);
                inchi_ios_flush2(log_stream,stdout);
                len_mess = len_mess1;
                was_print = 1;
            }

#ifdef OUTPUT_NORMALIZATION_DATA
            {
                int ic, istruct, itaut, ia, ib, nc[2];
                NORM_ATOMS *inp_norm_data[TAUT_NUM]; /*  = { &NormAtomsNontaut, &NormAtomsTaut}; */
                NORM_ATOM *atom;
                nc[0] = pGenData->num_components[0];
                nc[1] = pGenData->num_components[1];
                inchi_ios_eprint(log_stream, "=== %-s Intermediate normalization data follow", pStrLogId);
                for (istruct=0; istruct<2; istruct++)
                {
                    /*^^^ Print results for 1) original/disconnected structure and
                                            2)reconnected structure */
                    if (nc[istruct]>0)
                    {
                        if (istruct==0)
                            inchi_ios_eprint(log_stream, "\n\tOriginal/disconnected structure: ");
                        else
                            inchi_ios_eprint(log_stream, "\n\tReconnected structure: ");
                        inchi_ios_eprint(log_stream, "%-d component(s)\n", nc[istruct]);
                        inchi_ios_eprint(log_stream, "\t===============================================\n");

                        for (ic=0; ic < nc[istruct]; ic++)
                        {
                            /* Print results for each component of the structure */
                            inp_norm_data[0] = &(pGenData->NormAtomsNontaut[istruct][ic]);
                            inp_norm_data[1] = &(pGenData->NormAtomsTaut[istruct][ic]);
                            for (itaut=0;itaut<2;itaut++)
                            {
                                /* Print results for 1) non-tautomeric and
                                                     2) tautomeric  version (if present)
                                                     of the component                   */
                                if (NULL!=inp_norm_data[itaut])
                                {

                                    if (inp_norm_data[itaut]->num_at>0)
                                    {
                                        if (itaut==0)
                                            inchi_ios_eprint(log_stream, "\tComponent %-d, non-tautomeric:", ic+1);
                                        else
                                            inchi_ios_eprint(log_stream, "\tComponent %-d, tautomeric:", ic+1);

                                        inchi_ios_eprint(log_stream, "\t%-d atom(s)\n", inp_norm_data[itaut]->num_at);

                                        for (ia=0; ia< inp_norm_data[itaut]->num_at; ia++)
                                        {
                                            /*^^^ Print data for each atom */
                                            if (inp_norm_data[itaut]->at != NULL)
                                            {
                                                atom = &( inp_norm_data[itaut]->at[ia] );
                                                if (NULL!=atom)
                                                {
                                                    /*^^^ Print: element, number, original number, no. of Hs,
                                                                 charge, coordination number, valence */
                                                    inchi_ios_eprint(log_stream, "\t\tatom %-s%-d (orig.%-s%-d) [H%-d] charge=%-+d  CN=%-d val=%-d ",
                                                        atom->elname, ia+1, atom->elname, atom->orig_at_number, atom->num_H, atom->charge,
                                                        atom->valence, atom->chem_bonds_valence);
                                                    if (atom->valence > 0)
                                                    {
                                                        /*^^^ Neighbors */
                                                        inchi_ios_eprint(log_stream, "nbrs { ");
                                                        for (ib=0; ib <atom->valence; ib++)
                                                        {
                                                            inchi_ios_eprint(log_stream, "%-d ", atom->neighbor[ib]+1);
                                                        }
                                                        inchi_ios_eprint(log_stream, "}");
                                                    }
                                                    /* Indicate if atom shares Hs with others */
                                                    if (atom->endpoint > 0)
                                                    {
                                                        inchi_ios_eprint(log_stream, "\n\t\t(in taut. group: %-d)", atom->endpoint);
                                                    }
                                                    inchi_ios_eprint(log_stream, "\n");
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            inchi_ios_flush(log_stream);
#endif
        }

        /*^^^ Canonicalization step */
        if ( (retcode == inchi_Ret_OKAY) || (retcode == inchi_Ret_WARNING) )
        {

#ifndef USE_STDINCHI_API
            retcode = INCHIGEN_DoCanonicalization( HGen, pGenData );
#else
            retcode = STDINCHIGEN_DoCanonicalization( HGen, pGenData );
#endif

            len_mess1 = strlen(pinfo);
            if (len_mess1 > len_mess)
            {
                mshift = len_mess?1:0;
                inchi_ios_eprint(log_stream, "*** %-s [Canonicalization] %-s\n", pStrLogId, pinfo+len_mess+mshift);
                inchi_ios_flush2(log_stream,stdout);
                len_mess = len_mess1;
                was_print = 1;
            }
        }

        /*^^^ Serialization (final) step */
        if ( (retcode == inchi_Ret_OKAY) || (retcode == inchi_Ret_WARNING) )
        {

#ifndef USE_STDINCHI_API
            retcode1 = INCHIGEN_DoSerialization(HGen, pGenData, pResults);
#else
            retcode1 = STDINCHIGEN_DoSerialization(HGen, pGenData, pResults);
#endif

            retcode = inchi_max(retcode , retcode1);


            len_mess1 = strlen(pinfo);
            if (len_mess1 > len_mess)
            {
                mshift = len_mess?1:0;
                inchi_ios_eprint(log_stream, "*** %-s [Serialization] %-s\n", pStrLogId, pinfo+len_mess+mshift);
                inchi_ios_flush2(log_stream,stdout);
                was_print = 1;
            }
        }

/*
        if (!was_print)
            inchi_ios_eprint(log_stream, "*** %-s        \r", pStrLogId);
*/


        /*^^^ Output err/warn */
        if ( pResults->szMessage && pResults->szMessage[0] )    { p1 = "; "; p2 = pResults->szMessage; }
        else                                            p1 = p2 = "";


        switch (retcode)
        {
        case inchi_Ret_UNKNOWN:
        case inchi_Ret_FATAL: /* fatal processing error -- typically, memory allocation error */
            num_inp ++;
            num_err ++;
            inchi_ios_eprint( log_stream, "Fatal Error (No INChI%s%s) %s\n", p1, p2, pStrLogId );
            inchi_ios_eprint( log_stream, "Log start:---------------------\n%s\nLog end--------------------\n", pResults->szLog? pResults->szLog : "Log is missing" );
            /*^^^ Free InChI library memories */
#ifndef USE_STDINCHI_API
            INCHIGEN_Reset(HGen, pGenData, pResults);
#else
            STDINCHIGEN_Reset(HGen, pGenData, pResults);
#endif
            goto exit_function;
        case inchi_Ret_EOF: /* typically, no input structure provided or help requested */
            /* output previous structure number and message */
            inchi_ios_eprint( log_stream, "End of file detected after structure %d\n", num_inp );
            goto exit_function;
        case inchi_Ret_ERROR:
            num_inp ++;
            num_err ++;
            inchi_ios_eprint( log_stream, "Error (No INChI%s%s) %s\n", p1, p2, pStrLogId );
            inchi_ios_flush2(log_stream,stdout);
            /*^^^ Free InChI library memories */
#ifndef USE_STDINCHI_API
            INCHIGEN_Reset(HGen, pGenData, pResults);
#else
            STDINCHIGEN_Reset(HGen, pGenData, pResults);
#endif
            continue;
        case inchi_Ret_SKIP:
            num_inp ++;
            inchi_ios_eprint( log_stream, "Skipped %s\n", pStrLogId );
            goto exit_function;
        case inchi_Ret_OKAY:
            break;
        case inchi_Ret_WARNING:
            /*^^^ Suppress warnings, we display them step by steps */
            /*^^^
            if ( p2 && p2[0] )
                inchi_ios_eprint( log_stream, "Warning (%s) %s\n", p2, pStrLogId );
            */
            break; /* ok */
        }

        num_inp ++;
        tot_len = 0;

        /*^^^ Post-1.02b - here from below */
        bTabbed  = 0 != ( ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT );

        if ( pResults->szInChI && pResults->szInChI[0] )
        {
            if (ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY )
            {
                /*^^^ output SDfile */
                char *start;
                unsigned len;
                int bAddLabel = 0;
                /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                output a SDfile. pResults->szInChI contains Molfile ending with "$$$$\n" line.
                Replace the 1st line with the structure number
                Replace the last line with the SDfile header, label, and new "$$$$\n" line
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/


                start = pResults->szInChI;

                /*^^^ 2. SDfile header and data: write zero to the 1st byte of
                         the last line "$$$$\n" to remove this line with purpose to relpace it */
                if ( ip->pSdfLabel && ip->pSdfLabel[0] && ip->pSdfValue && ip->pSdfValue[0] &&
                     (len = strlen(start)) && len > 5 && '$' == start[len-5] && '\n' == start[len-6] ) {
                    start[len-5] = '\0';
                    bAddLabel = 1;
                }

                /*^^^ 3. Output the whole Molfile */
                inchi_ios_print( out_stream, "%s", start );
                if ( bAddLabel )
                {
                    inchi_ios_print( out_stream, ">  <%s>\n%s\n\n$$$$\n", ip->pSdfLabel, ip->pSdfValue );
                }

                inchi_ios_flush(out_stream);
            } /* if (ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY ) */

            else

            {
                /*^^^ Print InChI */

                int bAuxInfo = !( ip->bINChIOutputOptions & INCHI_OUT_ONLY_AUX_INFO ) &&
                               pResults->szAuxInfo && pResults->szAuxInfo[0];

                /*^^^ Post-1.02b - correctly treat tabbed output with InChIKey */
                int bAuxOrKey = bAuxInfo || ( ip->bCalcInChIHash != INCHIHASH_NONE );

                const char *pLF  = "\n";
                const char *pTAB = bTabbed? "\t" : pLF;
                if ( !ip->bNoStructLabels )
                {
                    /* Print a previously created label string */
                    inchi_ios_print(out_stream, "%s%s", pStrInchiId, pTAB);
                }

                /*^^^ Print INChI Identifier */

                /*^^^ Post-1.02b */
                inchi_ios_print(out_stream, "%s%s", pResults->szInChI, bAuxOrKey? pTAB : pLF);
                /*^^^ Print INChI Aux Info */
                if ( bAuxInfo )
                    inchi_ios_print(out_stream, "%s%s",pResults->szAuxInfo, ip->bCalcInChIHash? pTAB : pLF);

                inchi_ios_flush(out_stream);
            }
        } /* if ( pResults->szInChI && pResults->szInChI[0] )  */


        /*^^^ Calculate InChIKey */
        if ( ip->bCalcInChIHash != INCHIHASH_NONE )
        {
            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(pResults->szInChI, xhash1, xhash2,
                                                  ik_string, szXtra1, szXtra2);
            if (ik_ret==INCHIKEY_OK)
            {
                /* NB: correctly treat tabbed output with InChIKey & hash extensions */
                char csep = '\n';
                if ( ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT )
                    csep = '\t';
                inchi_ios_print(out_stream, "InChIKey=%-s",ik_string);
                if ( xhash1 )
                    inchi_ios_print(out_stream, "%cXHash1=%-s",csep,szXtra1);
                if ( xhash2 )
                    inchi_ios_print(out_stream, "%cXHash2=%-s",csep,szXtra2);
                inchi_ios_print(out_stream, "\n");
            }
            else
            {
                /*^^^ Post-1.02b - add LF if output is tabbed and key generation failed */
                if (bTabbed)
                    inchi_ios_print(out_stream, "\n");

                inchi_ios_eprint(log_stream, "Warning: could not compute InChIKey for #%-d ",
                                         num_inp);
                switch(ik_ret)
                {
                case INCHIKEY_UNKNOWN_ERROR:
                        inchi_ios_eprint(log_stream, "(invalid key length requested)\n");
                        break;
                case INCHIKEY_EMPTY_INPUT:
                        inchi_ios_eprint(log_stream, "(got an empty string)\n");
                        break;
                case INCHIKEY_INVALID_INCHI_PREFIX:
                case INCHIKEY_INVALID_INCHI:
                case INCHIKEY_INVALID_STD_INCHI:
                        inchi_ios_eprint(log_stream, "(got non-InChI string)\n");
                        break;
                case INCHIKEY_NOT_ENOUGH_MEMORY:
                        inchi_ios_eprint(log_stream, "(not enough memory to treat the string)\n");
                        break;
                default:inchi_ios_eprint(log_stream, "(internal program error)\n");
                        break;
                }
            }
            inchi_ios_flush(out_stream);
            inchi_ios_flush2(log_stream,stdout);
        }



        /*^^^ Free InChI library memories */
#ifndef USE_STDINCHI_API
        INCHIGEN_Reset(HGen, pGenData, pResults);
#else
        STDINCHIGEN_Reset(HGen, pGenData, pResults);
#endif
    } /* while ( !e_bInterrupted ) */




    if (e_bInterrupted)
    {
        inchi_ios_eprint( log_stream, "\nStructure %d could not be processed: User Quit.\n", num_inp+1 );
        num_err ++;
        goto exit_function;
    }



/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
exit_function:

    inchi_ios_eprint( log_stream, "\nProcessed %ld structure%s, %ld error%s.\n",
                 num_inp, (num_inp==1)?"":"s", num_err, (num_err==1)?"":"s" );

    elapsed-= time(NULL);
    inchi_ios_eprint( log_stream,"\nElapsed time: %ld\"\n", -elapsed);

    inchi_ios_flush2(log_stream,stdout);



    /*^^^ Freeing/closing */
    e_FreeInchi_Input( pInp );

#ifndef USE_STDINCHI_API
    INCHIGEN_Destroy(HGen);
#else
    STDINCHIGEN_Destroy(HGen);
#endif

    for (i = 0; i<MAX_NUM_PATHS; i++)
    {
        if ( ip->path[i] )
        {
            e_inchi_free( (char*) ip->path[i] ); /*  cast deliberately discards 'const' qualifier */
            ip->path[i] = NULL;
        }
    }

    inchi_ios_close(inp_stream);
    inchi_ios_close(log_stream);
    inchi_ios_close(out_stream);
    inchi_ios_close(prb_stream);

    return 0;
}
示例#2
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;
}