Beispiel #1
0
/*
    Read Molfile (throuh call to InChI native ReadMolfile() ) and pack the data into INCHIMOL
*/
void INCHI_DECL IXA_MOL_ReadMolfile( IXA_STATUS_HANDLE hStatus,
                                     IXA_MOL_HANDLE    hMolecule,
                                     const char*       pBytes)
{
    int err;
    char error_string[STR_ERR_LEN];
    MOL_FMT_DATA*    mol_data = NULL;
    MOL_FMT_CTAB     OnlyCtab;
    int i, n1;
    IXA_ATOMID    atom1;
    IXA_ATOMID    atom2;
    IXA_BONDID    bond;
    int           bond_count;
    IXA_BOND_TYPE bond_type;
    const char*   p_cursor;
    INCHI_IOSTREAM instr;
    INCHI_IOSTREAM *inp_file = &instr;
    S_CHAR orig_mass_diff;
    int mass_or_mass_diff;
    int inlen=0;


    /* Throw out any existing content in the IXA molecule object. */
    IXA_MOL_Clear(hStatus, hMolecule);

    /* Wrap input text into an INCHI_IOSTREAM_STRING to use    a     */
    /* general-purpose (Molfile->InChI internal data) reader    */
    inchi_ios_init(inp_file, INCHI_IOSTREAM_TYPE_STRING, NULL);
    inp_file->s.pStr = (char * ) pBytes;
    inlen = strlen( inp_file->s.pStr ) + 1;
    inp_file->s.nUsedLength = inlen;
    inp_file->s.nPtr = 0;
    inp_file->f = NULL;

    error_string[0] = '\0';

    /* Parse the MolFile and store its content in an internal data structure. It might be possible
       to eliminate the internal struct and read directly into the IXA molecule object but that
       would mean rewriting a lot of code and also mask the relationship between this MolFile
       reading function and those used in previous InChI code. */
    p_cursor = pBytes;
    mol_data = ReadMolfile( inp_file,
                            NULL,
                            &OnlyCtab,
                            0, /*NULL != szCoord,*/
                            1,
                            NULL, 0, NULL, NULL, NULL,
                            &err, error_string );

    /* uses "err" and "error_string" to report errors. Pick up any errors
       and write them to the status object. */
    if (!mol_data)
    {
        if (error_string[0])
        {
            STATUS_PushMessage(hStatus, IXA_STATUS_ERROR, error_string);
        }
        else
        {
            STATUS_PushMessage(hStatus, IXA_STATUS_ERROR, "No molfile data or failed to read");
        }
        goto exit_function;
    }
    else
    {
        if (error_string[0])
        {
            if ( !err)
                STATUS_PushMessage(hStatus, IXA_STATUS_WARNING, error_string);
        }
    }

    /* No need to do anything if the MolFile does not contain any atoms. */
    if (mol_data->ctab.n_atoms > 0)
    {
        /* Create the appropriate number of IXA atoms. Some atom properties can only be set
           once bonds have been created and bonds can only be created once all atoms are in
           place. Hence this rather lightweight loop that creates atoms but does not set
           their properties. */
        for (i = 0; i < mol_data->ctab.n_atoms; i++)
        {
            IXA_MOL_CreateAtom(hStatus, hMolecule);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
        }

        /* All atoms now exist so it is now possible to create bonds and set their properties. */
        for ( i = 0; i < mol_data->ctab.n_bonds; i ++ )
        {
            /* Create the bond. */
            atom1 = IXA_MOL_GetAtomId(hStatus, hMolecule, mol_data->ctab.bonds[i].atnum1-1);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            atom2 = IXA_MOL_GetAtomId(hStatus, hMolecule, mol_data->ctab.bonds[i].atnum2-1);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            bond = IXA_MOL_CreateBond(hStatus, hMolecule, atom1, atom2);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;

            /* Set bond order. */
            switch (mol_data->ctab.bonds[i].bond_type)
            {
                case 1:
                    IXA_MOL_SetBondType(hStatus, hMolecule, bond, IXA_BOND_TYPE_SINGLE);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case 2:
                    IXA_MOL_SetBondType(hStatus, hMolecule, bond, IXA_BOND_TYPE_DOUBLE);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case 3:
                    IXA_MOL_SetBondType(hStatus, hMolecule, bond, IXA_BOND_TYPE_TRIPLE);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case 4:
                    IXA_MOL_SetBondType(hStatus, hMolecule, bond, IXA_BOND_TYPE_AROMATIC);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                default:
                    STATUS_PushMessage(hStatus, IXA_STATUS_ERROR, "Bond type %d is not recognised", mol_data->ctab.bonds[i].bond_type);
                    goto exit_function;
            }

            /* Set bond wedge and double bond configuration. */
            switch (mol_data->ctab.bonds[i].bond_stereo)
            {
                case INPUT_STEREO_DBLE_EITHER:
                    IXA_MOL_SetDblBondConfig(hStatus, hMolecule, bond, IXA_DBLBOND_CONFIG_EITHER);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case INPUT_STEREO_SNGL_UP:
                    IXA_MOL_SetBondWedge(hStatus, hMolecule, bond, atom1, IXA_BOND_WEDGE_UP);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case INPUT_STEREO_SNGL_EITHER:
                    IXA_MOL_SetBondWedge(hStatus, hMolecule, bond, atom1, IXA_BOND_WEDGE_EITHER);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case INPUT_STEREO_SNGL_DOWN:
                    IXA_MOL_SetBondWedge(hStatus, hMolecule, bond, atom1, IXA_BOND_WEDGE_DOWN);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                case 0:
                    IXA_MOL_SetBondWedge(hStatus, hMolecule, bond, atom1, IXA_BOND_WEDGE_NONE);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    break;
                default:
                    STATUS_PushMessage(hStatus, IXA_STATUS_ERROR, "Stereo type %d is not recognised", mol_data->ctab.bonds[i].bond_stereo);
                    goto exit_function;
            }
        }

        /* Now that all bonds have been dealt with, set atom properties. */
        for (i = 0; i < mol_data->ctab.n_atoms; i++)
        {
            /* Most atom properties are easily dealt with. They might equally have been set
               when the atom was first created. */
            atom1 = IXA_MOL_GetAtomId(hStatus, hMolecule, i);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            IXA_MOL_SetAtomElement(hStatus, hMolecule, atom1, mol_data->ctab.atoms[i].symbol);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;

            /*    Fix 2016-02-18/03-04: conform GetINCHI() conventions, account for the most abundant isotope */
            orig_mass_diff = mol_data->ctab.atoms[i].mass_difference;
            if ( orig_mass_diff == 0 )
            {
                /* not isotopic */
                mass_or_mass_diff = 0;
            }
            else if ( orig_mass_diff == ZERO_ATW_DIFF )
            {
                /*    isotopic enrichment, special case:
                    isotope's integer mass is equal to the
                    rounded average mass from Periodic Table
                */
                mass_or_mass_diff = 0 + ISOTOPIC_SHIFT_FLAG;
            }
            else
            {
                /* isotopic mass, general case */
                mass_or_mass_diff = orig_mass_diff + ISOTOPIC_SHIFT_FLAG;
            }
            IXA_MOL_SetAtomMass( hStatus, hMolecule, atom1, mass_or_mass_diff );
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            IXA_MOL_SetAtomCharge(hStatus, hMolecule, atom1, mol_data->ctab.atoms[i].charge);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            IXA_MOL_SetAtomX(hStatus, hMolecule, atom1, mol_data->ctab.atoms[i].fx);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            IXA_MOL_SetAtomY(hStatus, hMolecule, atom1, mol_data->ctab.atoms[i].fy);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            IXA_MOL_SetAtomZ(hStatus, hMolecule, atom1, mol_data->ctab.atoms[i].fz);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
#if( SINGLET_IS_TRIPLET == 1 )
            if (mol_data->ctab.atoms[i].radical == 1)
            {
                IXA_MOL_SetAtomRadical(hStatus, hMolecule, atom1, IXA_ATOM_RADICAL_TRIPLET);
                if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            }
            else
#endif
            IXA_MOL_SetAtomRadical(hStatus, hMolecule, atom1, (IXA_ATOM_RADICAL) mol_data->ctab.atoms[i].radical);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;

            /* Implicit hydrogen count depends on an analysis of the bonds connected to the
               atom. This is the reason why bonds had to be created before atom properties
               could be set. */
            bond_count = IXA_MOL_GetAtomNumBonds(hStatus, hMolecule, atom1);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            if (mol_data->ctab.atoms[i].valence &&
                (mol_data->ctab.atoms[i].valence != 15 || (bond_count != 0)))
            {
                /* Molfile contains special valence => calculate number of H */
                int valence;
                int chem_bonds_valence = 0;
                int aromatic_count = 0;
                valence = mol_data->ctab.atoms[i].valence; /*  save atom valence if available */
                for ( n1 = 0; n1 < bond_count; n1 ++ )
                {
                    bond = IXA_MOL_GetAtomBond(hStatus, hMolecule, atom1, n1);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    bond_type = IXA_MOL_GetBondType(hStatus, hMolecule, bond);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                    switch (bond_type)
                    {
                        case INCHI_BOND_TYPE_SINGLE:
                            chem_bonds_valence += 1;
                            break;
                        case INCHI_BOND_TYPE_DOUBLE:
                            chem_bonds_valence += 2;
                            break;
                        case INCHI_BOND_TYPE_TRIPLE:
                            chem_bonds_valence += 3;
                            break;
                        case INCHI_BOND_TYPE_ALTERN:
                            chem_bonds_valence += 1;
                            aromatic_count++;
                            break;
                    }
                }
                switch (aromatic_count)
                {
                    case 0:
                        break;
                    case 2:
                    case 3:
                        chem_bonds_valence++;
                        break;
                    default:
                        STATUS_PushMessage(hStatus, IXA_STATUS_ERROR, "Atom cannot have %d aromatic bonds", aromatic_count);
                        goto exit_function;
                }
                if ( valence >= chem_bonds_valence )
                {
                    IXA_MOL_SetAtomHydrogens(hStatus, hMolecule, atom1, 0, valence - chem_bonds_valence);
                    if (IXA_STATUS_HasError(hStatus)) goto exit_function;
                }
            }
            else if ( mol_data->ctab.atoms[i].atom_aliased_flag )
            {
                IXA_MOL_SetAtomHydrogens(hStatus, hMolecule, atom1, 0, 0);
                if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            }
            else if ( mol_data->ctab.atoms[i].valence == 15 && (bond_count == 0))
            {
                IXA_MOL_SetAtomHydrogens(hStatus, hMolecule, atom1, 0, 0);
                if (IXA_STATUS_HasError(hStatus)) goto exit_function;
            }
            else
            {
                IXA_MOL_SetAtomHydrogens(hStatus, hMolecule, atom1, 0, -1);
            }
        }

        /* Chiral flag is a whole-molecule property not tied to any particular atom, bond
           or stereo centre. */
        if (mol_data->ctab.chiral_flag)
        {
            IXA_MOL_SetChiral(hStatus, hMolecule, IXA_TRUE);
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
        }

        if ( mol_data->ctab.sgroups.used || mol_data->ctab.v3000 )
        {
            /* Treat Molfile extended data (polymers; V300 features ) */
            IXA_MOL_SetExtMoldataByMolfileExtInput( hStatus, hMolecule, mol_data );
            if (IXA_STATUS_HasError(hStatus)) goto exit_function;
         }
    }

exit_function:
    FreeMolfileData( mol_data );
}
Beispiel #2
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;
}
Beispiel #3
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;
}