~ubuntu-branches/debian/stretch/openbabel/stretch

« back to all changes in this revision

Viewing changes to src/formats/inchi103/ichimake.c

  • Committer: Package Import Robot
  • Author(s): Daniel Leidert
  • Date: 2013-05-22 19:08:27 UTC
  • mfrom: (1.1.11) (7.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20130522190827-72q0fnx5y2nm3bc0
Tags: 2.3.2+dfsg-1
* New upstream release.
* debian/control: Dropped DM-Upload-Allowed field.
  (Standards-Version): Bumped to 3.9.4.
* debian/copyright: Massive update.
* debian/upstream: Author name update.
* debian/get-orig-source.sh: Remove the windows-*/ directory too.
* debian/openbabel.install: Removed roundtrip manpage.
* debian/openbabel-gui.install: Fixed manpage name.
* debian/openbabel-gui.links: Removed unused file.
* debian/rules: Enable OpenMP. Disable tests on `nocheck'.
* debian/patches/gaussformat_nosym.patch: Dropped. Applied upstream.
* debian/patches/moldenformat_coordonly.patch: Ditto.
* debian/patches/obspectrophore_man.patch: Ditto.
* debian/patches/fix_ftbfs.patch: Added.
  - Fix several FTBFS issues in upstream build system.
* debian/patches/series: Adjusted.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * International Chemical Identifier (InChI)
3
 
 * Version 1
4
 
 * Software version 1.03
5
 
 * May 9, 2010
6
 
 *
7
 
 * Originally developed at NIST
8
 
 * Modifications and additions by IUPAC and the InChI Trust
9
 
 *
10
 
 * The InChI library and programs are free software developed under the
11
 
 * auspices of the International Union of Pure and Applied Chemistry (IUPAC);
12
 
 * you can redistribute this software and/or modify it under the terms of 
13
 
 * the GNU Lesser General Public License as published by the Free Software 
14
 
 * Foundation:
15
 
 * http://www.opensource.org/licenses/lgpl-2.1.php
16
 
 */
17
 
 
18
 
 
19
 
#include <stdio.h>
20
 
#include <stdlib.h>
21
 
#include <string.h>
22
 
#include <ctype.h>
23
 
 
24
 
 
25
 
#include "mode.h"
26
 
 
27
 
#if( TEST_RENUMB_ATOMS == 1 )
28
 
#include "ichitime.h"
29
 
#endif
30
 
#include "inpdef.h"
31
 
#include "ichi.h"
32
 
#include "strutil.h"
33
 
#include "util.h"
34
 
#include "extr_ct.h"
35
 
#include "ichitaut.h"
36
 
#include "ichinorm.h"
37
 
#include "ichicant.h"
38
 
#include "ichicano.h"
39
 
#include "ichicomn.h"
40
 
 
41
 
#include "ichicomp.h"
42
 
#include "ichimain.h"
43
 
#include "ichimake.h"
44
 
#include "ichister.h"
45
 
#include "ichi_io.h"
46
 
 
47
 
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at );
48
 
int GetElementAndCount( const char **f, char *szEl, int *count );
49
 
int CompareHillFormulas( const char *f1, const char *f2 );
50
 
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 );
51
 
int CompareReversedStereoINChI( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */);
52
 
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
53
 
                            AT_NUMB *nOrigAtNosInCanonOrd, int num_at );
54
 
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
55
 
                        INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
56
 
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
57
 
                           AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
58
 
                           INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
59
 
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
60
 
                        int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers);
61
 
 
62
 
int CheckCanonNumberingCorrectness(
63
 
                 int num_atoms, int num_at_tg,
64
 
                 sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
65
 
                 char *pStrErrStruct );
66
 
 
67
 
static int CompareDfsDescendants4CT( const void *a1, const void *a2 );
68
 
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo );
69
 
 
70
 
 
71
 
#if( TEST_RENUMB_ATOMS == 1 || READ_INCHI_STRING == 1 ) /*  { */
72
 
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 );
73
 
#endif
74
 
 
75
 
#if( READ_INCHI_STRING == 1 ) /*  { */
76
 
/*************************************************************************************/
77
 
 
78
 
int CompareReversedStereoINChI2( INChI_Stereo *s1, INChI_Stereo *s2, ICR *picr);
79
 
 
80
 
#endif
81
 
/**********************************************************************************************/
82
 
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at )
83
 
{
84
 
    int i, j, val;
85
 
    memset( at, 0, sizeof(at[0])*num_inp_at );
86
 
    for ( i = 0; i < num_inp_at; i ++ ) {
87
 
        strncpy( at[i].elname, inp_at[i].elname, sizeof(at[0].elname) );
88
 
        at[i].el_number = (U_CHAR)get_periodic_table_number( at[i].elname );
89
 
        val = at[i].valence = inp_at[i].valence;
90
 
        for ( j = 0; j < val; j ++ ) {
91
 
            at[i].neighbor[j]  = inp_at[i].neighbor[j];
92
 
            at[i].bond_type[j] = inp_at[i].bond_type[j];
93
 
        }
94
 
        at[i].chem_bonds_valence = inp_at[i].chem_bonds_valence;
95
 
        at[i].orig_at_number     = inp_at[i].orig_at_number;
96
 
        at[i].orig_compt_at_numb= inp_at[i].orig_compt_at_numb;
97
 
        at[i].endpoint           = inp_at[i].endpoint;
98
 
        at[i].iso_atw_diff       = inp_at[i].iso_atw_diff;
99
 
        at[i].num_H              = inp_at[i].num_H;
100
 
        at[i].cFlags             = inp_at[i].cFlags;
101
 
        for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
102
 
            at[i].num_iso_H[j]       = inp_at[i].num_iso_H[j];
103
 
        }
104
 
        at[i].charge             = inp_at[i].charge;
105
 
        at[i].radical            = inp_at[i].radical;
106
 
 
107
 
#if( FIND_RING_SYSTEMS == 1 )
108
 
        at[i].nBlockSystem       = inp_at[i].nBlockSystem;
109
 
        at[i].bCutVertex         = inp_at[i].bCutVertex;
110
 
        at[i].nRingSystem        = inp_at[i].nRingSystem;
111
 
        at[i].nNumAtInRingSystem = inp_at[i].nNumAtInRingSystem;
112
 
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
113
 
        at[i].nDistanceFromTerminal = inp_at[i].nDistanceFromTerminal;
114
 
#endif
115
 
#endif
116
 
 
117
 
/*
118
 
        at[i].x                  = inp_at[i].x;
119
 
        at[i].y                  = inp_at[i].y;
120
 
        at[i].z                  = inp_at[i].z;
121
 
*/
122
 
    }
123
 
    return 0;
124
 
}
125
 
/**********************************************************************************************/
126
 
int GetElementAndCount( const char **f, char *szEl, int *count )
127
 
{
128
 
    const char *p = *f;
129
 
    char       *q;
130
 
    int   i = 0;
131
 
    if ( *p ) {
132
 
        if ( isupper( UCINT *p ) ) {
133
 
            szEl[i++] = *p++;
134
 
            if ( *p && islower( UCINT *p ) ) {
135
 
                szEl[i++] = *p++;
136
 
            }
137
 
            szEl[i] = '\0';
138
 
            if ( 1 == i && szEl[0] == 'C' ) {
139
 
                szEl[0] = 'A'; /*  less than any element: */
140
 
                               /*  carbon-containing compounds should be first */
141
 
            }
142
 
            if ( *p && isdigit( UCINT *p ) ) {
143
 
                *count = strtol( p, &q, 10 );
144
 
                p = q;
145
 
            } else {
146
 
                *count = 1;
147
 
            }
148
 
            *f = p; /*  next element; */
149
 
            return 1;
150
 
        }
151
 
        return -1; /*  not a chemical formula */
152
 
    }
153
 
    strcpy( szEl, "Zz" ); /*  zero termination 'element' is larger than any other element */
154
 
    *count = 9999;        /*  zero termination 'element count' is larger than any other count */
155
 
    return 0;
156
 
}
157
 
/**********************************************************************************************
158
 
 
159
 
   E1 < E2 if strcmp( E1, E2) < 0  OR E2 is empty and E1 is not
160
 
   n1 < n2 if value n1 > n2
161
 
 
162
 
   Sorting order:
163
 
 
164
 
   C10H22N
165
 
   C10H22
166
 
   C2
167
 
   Ag2Cl2
168
 
   Ag2Cl
169
 
   Ag2F2
170
 
   Ag2
171
 
   AgCl
172
 
   AgF
173
 
   F6S
174
 
   F2S
175
 
 
176
 
**********************************************************************************************/
177
 
int CompareHillFormulas( const char *f1, const char *f2 )
178
 
{
179
 
    char szEl1[4], szEl2[4];
180
 
    int  count1, count2, ret1, ret2, ret;
181
 
 
182
 
    do {
183
 
        ret1 = GetElementAndCount( &f1, szEl1, &count1 );
184
 
        ret2 = GetElementAndCount( &f2, szEl2, &count2 );
185
 
        if ( 0 <= ret1 && 0 <= ret2 ) {
186
 
            if ( ret = strcmp( szEl1, szEl2 ) ) {
187
 
                return ret; /*  lexicographic order, string termination > any character */
188
 
            }
189
 
            if ( ret = count2 - count1 ) {
190
 
                return ret; /*  inverse atom count order */
191
 
            }
192
 
        } else {
193
 
            return 0; /*  program error <BRKPT> */
194
 
        }
195
 
 
196
 
    } while ( 0 < ret1 && 0 < ret2 );
197
 
 
198
 
    return 0;
199
 
}
200
 
/**********************************************************************************************/
201
 
int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 )
202
 
{
203
 
    char szEl1[4], szEl2[4];
204
 
    int  count1, count2, ret1, ret2, ret;
205
 
 
206
 
    do {
207
 
        ret1 = GetElementAndCount( &f1, szEl1, &count1 );
208
 
        if ( 0 < ret1 && szEl1[0] == 'H' && !szEl1[1] ) {
209
 
            *num_H1 += count1;
210
 
            ret1 = GetElementAndCount( &f1, szEl1, &count1 );
211
 
        }
212
 
        ret2 = GetElementAndCount( &f2, szEl2, &count2 );
213
 
        if ( 0 < ret2 && szEl2[0] == 'H' && !szEl2[1] ) {
214
 
            *num_H2 += count2;
215
 
            ret2 = GetElementAndCount( &f2, szEl2, &count2 );
216
 
        }
217
 
        if ( 0 <= ret1 && 0 <= ret2 ) {
218
 
            if ( ret = strcmp( szEl1, szEl2 ) ) {
219
 
                return ret; /*  lexicographic order, string termination > any character */
220
 
            }
221
 
            if ( ret = count2 - count1 ) {
222
 
                return ret; /*  inverse atom count order */
223
 
            }
224
 
        } else {
225
 
            return 0; /*  program error <BRKPT> */
226
 
        }
227
 
 
228
 
    } while ( 0 < ret1 && 0 < ret2 );
229
 
 
230
 
    return 0;
231
 
}
232
 
 
233
 
/**************************************************************/
234
 
int CompareTautNonIsoPartOfINChI( const INChI *i1, const INChI *i2 )
235
 
{
236
 
    int len1, len2, ret, i;
237
 
 
238
 
    len1 = i1->lenTautomer > 0 && i1->nTautomer[0]? i1->lenTautomer:0;
239
 
    len2 = i2->lenTautomer > 0 && i2->nTautomer[0]? i2->lenTautomer:0;
240
 
    if ( ret  = len2 - len1 ) {
241
 
        return ret;
242
 
    }
243
 
    for ( i = 0; i < len1; i ++ ) {
244
 
        if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
245
 
            return ret;
246
 
    }
247
 
    return 0;
248
 
}
249
 
 
250
 
/**********************************************************************************************/
251
 
/*  sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2               */
252
 
/**********************************************************************************************/
253
 
int CompINChITautVsNonTaut(const INCHI_SORT *p1, const INCHI_SORT *p2, int bCompareIsotopic)
254
 
{
255
 
    int ret, num, i, num_H1, num_H2;
256
 
    
257
 
    const INChI *i1  = NULL; /* Mobile-H layers in Mobile-H sorting order */
258
 
    const INChI *i2  = NULL; /* Fixed-H  layers in Fixed-H  sorting order */
259
 
    
260
 
    int   n1;               /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
261
 
    
262
 
    /* INChI_Stereo *Stereo1, *Stereo2; */
263
 
 
264
 
    n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
265
 
 
266
 
    i1  = p1->pINChI[n1];
267
 
    i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
268
 
           p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
269
 
 
270
 
 
271
 
    /* non-deleted-non-empty < deleted < empty */
272
 
    if ( i1 && !i2 )
273
 
        return 0;   /* non-empty is the smallest (first) */
274
 
    if ( !i1 && i2 )
275
 
        return 0;
276
 
    if ( !i1 && !i2 )
277
 
        return 0;
278
 
    if ( i1->bDeleted )
279
 
        return 1;    /* deleted is the largest (last) among non-empty */
280
 
    if ( i2->bDeleted )
281
 
        return -1;
282
 
 
283
 
    if ( i1->nNumberOfAtoms > 0 && !i2->nNumberOfAtoms )
284
 
        return 0;
285
 
 
286
 
    i2 = i2;
287
 
 
288
 
    num_H1 = num_H2 = 0;
289
 
    
290
 
    /* do not compare terminal H */
291
 
    if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
292
 
        return ret;  /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
293
 
    }
294
 
 
295
 
    /*********************************************************
296
 
            compare non-isotopic non-tautomeric part
297
 
     *********************************************************/
298
 
 
299
 
    /* compare number of atoms (excluding terminal H) */
300
 
    if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
301
 
        return ret; /*  more atoms first */
302
 
    
303
 
    /*  compare elements  (excluding terminal H) */
304
 
    num = i1->nNumberOfAtoms;
305
 
    for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
306
 
        if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
307
 
            return ret; /* greater periodic number first */
308
 
    }
309
 
    /**********************************************************
310
 
        compare connection tables
311
 
    ***********************************************************/
312
 
    if ( ret = i2->lenConnTable - i1->lenConnTable )
313
 
        return ret; /* longer connection table first */
314
 
    num = i2->lenConnTable; 
315
 
    for ( i = 0; i < num; i ++ ) {
316
 
        if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
317
 
            return ret; /* greater connection table first */
318
 
    }
319
 
    /*********************************************************
320
 
      compare compare total number of H (inverse: H3 < H2 )
321
 
    **********************************************************/
322
 
    if ( ret = num_H2 - num_H1 )
323
 
        return ret;
324
 
    /*********************************************************
325
 
      compare non-tautomeric num_H: N < NH3 < NH2 < NH
326
 
    **********************************************************/
327
 
    num = i1->nNumberOfAtoms;
328
 
    for ( i = 0; i < num; i ++ ) {
329
 
        if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
330
 
            return !i2->nNum_H[i]?  1 :  /* no H first */
331
 
                   !i1->nNum_H[i]? -1 :
332
 
                   (int)i2->nNum_H[i] - (int)i1->nNum_H[i];
333
 
        }
334
 
    }
335
 
    /*********************************************************
336
 
         compare non-isotopic tautomeric part
337
 
     *********************************************************/
338
 
    if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
339
 
        return ret;
340
 
    }
341
 
    /*
342
 
    if ( ret = i2->lenTautomer - i1->lenTautomer )
343
 
        return ret;
344
 
    num = inchi_min( i2->lenTautomer, i1->lenTautomer );
345
 
    for ( i = 0; i < num; i ++ ) {
346
 
        if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
347
 
            return ret;
348
 
    }
349
 
    */
350
 
    /*********************************************************
351
 
     *                                                       *
352
 
     *  at this point both components are either tautomeric  *
353
 
     *  or non-tautomeric                                    *
354
 
     *                                                       *
355
 
     *********************************************************/
356
 
 
357
 
    /*********************************************************
358
 
       non-tautomeric "fixed H" specific
359
 
     *********************************************************/
360
 
    if ( /*TAUT_NON == bTaut &&*/ (i2 && i2->nNum_H_fixed ) ) {
361
 
        /* first, compare non-tautomeric chem. formulas -- they may be different */
362
 
        /* secondly, compare fixed-H distribution */
363
 
        if ( i2->nNum_H_fixed ) {
364
 
            num = i2->nNumberOfAtoms;
365
 
            for ( i = 0; i < num; i ++ ) {
366
 
                if ( i2->nNum_H_fixed[i] != 0 ) {
367
 
                    return 1;
368
 
                }
369
 
            }
370
 
        }
371
 
    }
372
 
    /*********************************************************
373
 
        compare non-isotopic stereo
374
 
     *********************************************************/
375
 
    ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
376
 
    if ( ret ) {
377
 
        return ret;
378
 
    }
379
 
    /*******************************************************
380
 
        do not switch back to tautomeric i1, i2
381
 
     *******************************************************/
382
 
    /* -- how to switch back --
383
 
    if ( i1t ) {
384
 
        i1  = i1t;
385
 
        i1t = NULL;
386
 
    }
387
 
    if ( i2t ) {
388
 
        i2  = i2t;
389
 
        i2t = NULL;
390
 
    }
391
 
    */
392
 
    /******************************************************
393
 
         compare isotopic non-tautomeric part
394
 
     ******************************************************/
395
 
    if ( bCompareIsotopic ) {
396
 
        if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
397
 
            return ret;
398
 
        num = i1->nNumberOfIsotopicAtoms;
399
 
        /*  compare isotopic atoms */
400
 
        for ( i = 0; i < num; i ++ ) {
401
 
            if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
402
 
                return ret;
403
 
            if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
404
 
                return ret;
405
 
        }
406
 
        /* compare isotopic H */
407
 
        /* if tautomeric comparison mode then here are compared only non-tautomeric H */
408
 
        for ( i = 0; i < num; i ++ ) {
409
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
410
 
                return ret;
411
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
412
 
                return ret;
413
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
414
 
                return ret;
415
 
        }
416
 
        /*****************************************************
417
 
             compare isotopic tautomeric part
418
 
         *****************************************************/
419
 
        if ( ret = i2->nNumberOfIsotopicTGroups || i1->nNumberOfIsotopicTGroups )
420
 
            return ret;
421
 
        /*
422
 
        num = i1->nNumberOfIsotopicTGroups;
423
 
        for ( i = 0; i < num; i ++ ) {
424
 
            if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
425
 
                return ret;
426
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
427
 
                return ret;
428
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
429
 
                return ret;
430
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
431
 
                return ret;
432
 
        }
433
 
        */
434
 
        /****************************************************
435
 
            compare isotopic stereo
436
 
         ****************************************************/
437
 
        ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
438
 
        if ( ret ) {
439
 
            return ret;
440
 
        }
441
 
 
442
 
    }
443
 
 
444
 
 
445
 
    /**********************************************************
446
 
        compare charges: non-charged first, then in order of
447
 
        ascending charges (negative first) 
448
 
    ***********************************************************/
449
 
    if ( i2->nTotalCharge && i1->nTotalCharge ) {
450
 
        /*  both are charged; smaller charges first */
451
 
        ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
452
 
        return ret;
453
 
    }
454
 
    if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
455
 
        /*  only one is charged; uncharged first */
456
 
        return ret;
457
 
    }
458
 
    /* stable sort */
459
 
    /*ret = p1->ord_number - p2->ord_number;*/
460
 
 
461
 
    return ret;
462
 
}
463
 
 
464
 
/*************************** stereo ***********************************************************/
465
 
typedef enum tagSp3StereoTypeTmp {
466
 
    SP3_NONE = 0,  /* no sp3 stereo: no /t, /m, /s segments */
467
 
    /* /t is present: */
468
 
    SP3_ONLY = 1,  /* no /s or /m segment: inversion leaves the structure unchanged */
469
 
    SP3_ABS  = 2,  /* abs stereo: both /m and /s are present */
470
 
    SP3_REL  = 4,  /* rel stereo: /s is present, /m is not */
471
 
    SP3_RAC  = 8,  /* racemic stereo: /s is presen, /m is nott */
472
 
    SP3_TYPE = (SP3_ABS|SP3_REL|SP3_RAC),          /* bitmap for checking the presence of /m */
473
 
    SP3_ANY  = (SP3_ABS|SP3_REL|SP3_RAC|SP3_ONLY)  /* bitmap for checking the presence of /t */
474
 
} SP3_TYPE_TMP;
475
 
 
476
 
/**********************************************************************************************/
477
 
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo )
478
 
{
479
 
    int nRet = SP3_NONE;
480
 
    if ( pINChI && !pINChI->bDeleted && Stereo && 0 < Stereo->nNumberOfStereoCenters ) {
481
 
        if ( 0 != Stereo->nCompInv2Abs ) {
482
 
            if ( pINChI->nFlags & INCHI_FLAG_REL_STEREO ) {
483
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
484
 
                if ( 1 <  Stereo->nNumberOfStereoCenters ) {
485
 
                    nRet = SP3_REL;
486
 
                }
487
 
#else
488
 
                nRet = SP3_REL;
489
 
#endif
490
 
            } else
491
 
            if ( pINChI->nFlags & INCHI_FLAG_RAC_STEREO ) {
492
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
493
 
                if ( 1 <  Stereo->nNumberOfStereoCenters ) {
494
 
                    nRet = SP3_REL;
495
 
                }
496
 
#else
497
 
                nRet = SP3_RAC;
498
 
#endif
499
 
            } else {
500
 
                nRet = SP3_ABS;
501
 
            }
502
 
        } else
503
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
504
 
        if ( !(( pINChI->nFlags & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO) ) && 1 == Stereo->nNumberOfStereoCenters) )
505
 
#endif
506
 
        {
507
 
            nRet = SP3_ONLY; /*  SP3_NONE if relative stereo and 1 stereocenter */
508
 
        }
509
 
    }
510
 
    return nRet;
511
 
}
512
 
 
513
 
/* char sDifSegs[DIFL_LENGTH][DIFS_LENGTH]; */
514
 
 
515
 
/**********************************************************************************************/
516
 
/*  sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2               */
517
 
/**********************************************************************************************/
518
 
int CompINChILayers(const INCHI_SORT *p1, const INCHI_SORT *p2, 
519
 
                    char sDifSegs[][DIFS_LENGTH], int bFixTranspChargeBug )
520
 
{
521
 
    int ret = 0, num, i, num_H1, num_H2;
522
 
    
523
 
    const INChI *i1  = NULL; /* Mobile-H layers in Mobile-H sorting order */
524
 
    const INChI *i2  = NULL; /* Fixed-H  layers in Fixed-H  sorting order */
525
 
    
526
 
    int   n1;               /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
527
 
    
528
 
    INChI_Stereo *Stereo1, *Stereo2;
529
 
    INChI_Stereo *IsoStereo1, *IsoStereo2;
530
 
    int bRelRac[DIFL_LENGTH];
531
 
    char *psDifSegs;
532
 
 
533
 
    n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
534
 
 
535
 
    i1  = p1->pINChI[n1];
536
 
    i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
537
 
           p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
538
 
 
539
 
    num_H1 = num_H2 = 0;
540
 
    memset( bRelRac, DIFV_BOTH_EMPTY, sizeof(bRelRac) );
541
 
    /*=====================*/
542
 
    /*====     /f    ======*/
543
 
    /*=====================*/
544
 
    if ( i1 && !i1->bDeleted && i1->szHillFormula && i1->szHillFormula[0] ) {
545
 
        sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
546
 
        if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
547
 
            if ( !CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) &&
548
 
                  num_H1 == num_H2 ) {
549
 
                sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_EQL2PRECED;
550
 
            } else {
551
 
                sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
552
 
            }
553
 
        } else {
554
 
            sDifSegs[DIFL_F][DIFS_f_FORMULA] |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
555
 
        }
556
 
    } else {
557
 
        sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
558
 
        if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
559
 
            sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
560
 
        } else {
561
 
            sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
562
 
        }
563
 
    }
564
 
    /*=====================*/
565
 
    /*====     /c    ======*/
566
 
    /*=====================*/
567
 
    if ( i1 && !i1->bDeleted && i1->lenConnTable > 1 ) {
568
 
        sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
569
 
    } else {
570
 
        sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
571
 
    }
572
 
    /*=====================*/
573
 
    /*====     /h    ======*/
574
 
    /*=====================*/
575
 
    /* M: H atoms */
576
 
    if ( i1 && !i1->bDeleted ) {
577
 
        num_H1 = (i1->lenTautomer > 0 && i1->nTautomer && i1->nTautomer[0])? 1 : 0; /* number of t-groups */
578
 
        if ( !num_H1 && i1->nNum_H ) {
579
 
            for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) { /* immobile H */
580
 
                if ( i1->nNum_H[i] ) {
581
 
                    num_H1 = 1;
582
 
                    break;
583
 
                }
584
 
            }
585
 
        }
586
 
        sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= num_H1? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
587
 
    } else {
588
 
        sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
589
 
    }
590
 
    /* F: fixed mobile H */
591
 
    if ( i2 && !i2->bDeleted && i2->nNum_H_fixed ) {
592
 
        num_H2 = 0;
593
 
        if ( i1 && !i1->bDeleted ) {
594
 
            for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
595
 
                if ( i2->nNum_H_fixed[i] ) {
596
 
                    num_H2 = 1;
597
 
                    break;
598
 
                }
599
 
            }
600
 
        }
601
 
        sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= num_H2? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
602
 
    } else {
603
 
        sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
604
 
    }
605
 
    /* MI: exchangable isotopic H: see OutputINChI1(), num_iso_H[] */
606
 
 
607
 
    /*=====================*/
608
 
    /*====     /q    ======*/
609
 
    /*=====================*/
610
 
    psDifSegs = &sDifSegs[DIFL_F][DIFS_q_CHARGE];
611
 
    if ( i1 && !i1->bDeleted ) {
612
 
        if ( i1->nTotalCharge ) {
613
 
            sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
614
 
        } else {
615
 
            sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
616
 
        }
617
 
        if ( i2 && !i2->bDeleted ) {
618
 
            if ( i1->nTotalCharge ) {
619
 
                if ( i1->nTotalCharge == i2->nTotalCharge ) {
620
 
                    *psDifSegs |= DIFV_EQL2PRECED;
621
 
                } else
622
 
                if ( i2->nTotalCharge ) {
623
 
                    *psDifSegs |= DIFV_NEQ2PRECED;
624
 
                } else {
625
 
                    *psDifSegs |= DIFV_IS_EMPTY;
626
 
                }
627
 
            } else {
628
 
                if ( i2->nTotalCharge ) {
629
 
                    *psDifSegs |= DIFV_NEQ2PRECED;
630
 
                } else {
631
 
                    *psDifSegs |= DIFV_BOTH_EMPTY;
632
 
                }
633
 
            }
634
 
        } else
635
 
        if ( !i2 ) {
636
 
            if (bFixTranspChargeBug==1) 
637
 
            {
638
 
            /* bug explanation:
639
 
 
640
 
            component #1 is tautomeric, component #2 is not
641
 
            Mobile-H(#2) > Mobile-H(#1)
642
 
            Fixed-H(#2) = Mobile-H(#2) < Fixed-H(#1)
643
 
 
644
 
            Layer       first_charge   second_charge
645
 
 
646
 
            Mobile-H    0    (comp#1)  -1 (comp#2)
647
 
            Fixed-H     none (comp#2)  -1 (comp#1)
648
 
 
649
 
            v1.01 charge compared decided that charge layers are same and omitted Fixed-H /q layer
650
 
 
651
 
            Solution: when component permutation is detected AND fixed-H component does not exist,
652
 
            compare Mobile-H charge [0 (comp#1) in the example] to the charge of Mobile-H [-1 (comp#2)]
653
 
            of the component that has none Fixed-H charge
654
 
            */
655
 
 
656
 
            /* Fixed-H i2 is empty because Fixed-H struct is same as Mobile-H */
657
 
                if ( p1->ord_number != p2->ord_number && /* component order in Fixed-H is different from Mobile-H */
658
 
                     n1 == TAUT_YES && p2->pINChI[TAUT_YES] && !p2->pINChI[TAUT_YES]->bDeleted &&
659
 
                    p2->pINChI[TAUT_YES]->nNumberOfAtoms ) {
660
 
                    int i2_nTotalCharge = p2->pINChI[TAUT_YES]->nTotalCharge;
661
 
 
662
 
                    if ( i1->nTotalCharge ) {
663
 
                        if ( i1->nTotalCharge == i2_nTotalCharge ) {
664
 
                            *psDifSegs |= DIFV_EQL2PRECED;
665
 
                        } else
666
 
                        if ( i2_nTotalCharge ) {
667
 
                            *psDifSegs |= DIFV_NEQ2PRECED;
668
 
                        } else {
669
 
                            *psDifSegs |= DIFV_IS_EMPTY;
670
 
                        }
671
 
                    } else {
672
 
                        if ( i2_nTotalCharge ) {
673
 
                            *psDifSegs |= DIFV_NEQ2PRECED;
674
 
                        } else {
675
 
                            *psDifSegs |= DIFV_BOTH_EMPTY;
676
 
                        }
677
 
                    }
678
 
                } else {
679
 
                    *psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
680
 
                }
681
 
            } 
682
 
            else /* if (bFixTranspChargeBug==1) */
683
 
            {
684
 
                *psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
685
 
            } 
686
 
        } 
687
 
 
688
 
        else /* if ( !i2 ) { */
689
 
        {
690
 
            /* i2 && i2->bDeleted */
691
 
            *psDifSegs |= i1->nTotalCharge? DIFV_IS_EMPTY : DIFV_BOTH_EMPTY;
692
 
        }
693
 
 
694
 
    } else {
695
 
        sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
696
 
        if ( i2 && !i2->bDeleted ) {
697
 
            if ( i2->nTotalCharge ) {
698
 
                sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
699
 
            } else {
700
 
                sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
701
 
            }
702
 
        }
703
 
    }
704
 
    /*************** stereo *****************/
705
 
    if ( i1 && !i1->bDeleted ) {
706
 
        Stereo1    = i1->Stereo;
707
 
        IsoStereo1 = i1->StereoIsotopic;
708
 
    } else {
709
 
        Stereo1    = NULL;
710
 
        IsoStereo1 = NULL;
711
 
    }
712
 
    if ( i2 && !i2->bDeleted ) {
713
 
        Stereo2    = i2->Stereo;
714
 
        IsoStereo2 = i2->StereoIsotopic;
715
 
    } else {
716
 
        Stereo2    = NULL;
717
 
        IsoStereo2 = NULL;
718
 
    }
719
 
    /*=====================*/
720
 
    /*====     /b    ======*/
721
 
    /*=====================*/
722
 
    /* M double bond stereo */
723
 
    psDifSegs = &sDifSegs[DIFL_M][DIFS_b_SBONDS];
724
 
    if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
725
 
        *psDifSegs |= DIFV_NEQ2PRECED;
726
 
    } else {
727
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
728
 
    }
729
 
    /* F double bond stereo */
730
 
    psDifSegs = &sDifSegs[DIFL_F][DIFS_b_SBONDS];
731
 
    if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
732
 
        if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
733
 
            if ( Eql_INChI_Stereo( Stereo1, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
734
 
                *psDifSegs |= DIFV_EQL2PRECED;
735
 
            } else {
736
 
                *psDifSegs |= DIFV_NEQ2PRECED;
737
 
            }
738
 
        } else {
739
 
            *psDifSegs |= DIFV_NEQ2PRECED;
740
 
        }
741
 
    } else {
742
 
        if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
743
 
            *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
744
 
        } else {
745
 
            *psDifSegs |= DIFV_BOTH_EMPTY;
746
 
        }
747
 
    }
748
 
    /* MI double bond stereo */
749
 
    psDifSegs = &sDifSegs[DIFL_MI][DIFS_b_SBONDS];
750
 
    if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds ) {
751
 
        if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP2, Stereo1, EQL_SP2, 0 ) ) {
752
 
            *psDifSegs |= DIFV_EQL2PRECED;
753
 
        } else {
754
 
            *psDifSegs |= DIFV_NEQ2PRECED;
755
 
        }
756
 
    } else {
757
 
        if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
758
 
            *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
759
 
        } else {
760
 
            *psDifSegs |= DIFV_BOTH_EMPTY;
761
 
        }
762
 
    }
763
 
    /* FI double bond stereo */
764
 
    psDifSegs = &sDifSegs[DIFL_FI][DIFS_b_SBONDS];
765
 
    if ( IsoStereo2 && IsoStereo2->nNumberOfStereoBonds ) {
766
 
        if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
767
 
            *psDifSegs |= DIFV_EQL2PRECED;
768
 
        } else {
769
 
            if ( !(Stereo1 && Stereo1->nNumberOfStereoBonds) &&
770
 
                 !(Stereo2 && Stereo2->nNumberOfStereoBonds) &&
771
 
                 Eql_INChI_Stereo( IsoStereo2, EQL_SP2, IsoStereo1, EQL_SP2, 0 ) ) {
772
 
                *psDifSegs |= DIFV_FI_EQ_MI;
773
 
            } else {
774
 
                *psDifSegs |= DIFV_NEQ2PRECED;
775
 
            }
776
 
        }
777
 
    } else {
778
 
        /* the solution table for FI stereo,
779
 
           in case of FI stereo is empty
780
 
           E = segment is empty, NE = not empty
781
 
           +==============================+
782
 
           | M   | MI  | F   |  result    |
783
 
           +=====+=====+=====+============+
784
 
           | E   | E   | E   | both empty |
785
 
           +-----+-----+-----+------------+
786
 
           | NE  | E   | E   | both empty |
787
 
           +-----+-----+-----+------------+
788
 
           | E   | NE  | E   | is empty   |
789
 
           +-----+-----+-----+------------+
790
 
           | NE  | NE  | E   | both empty |
791
 
           +-----+-----+-----+------------+
792
 
           | E   | E   | NE  | is empty   |
793
 
           +-----+-----+-----+------------+
794
 
           | NE  | E   | NE  | is empty   |
795
 
           +-----+-----+-----+------------+
796
 
           | E   | NE  | NE  | is empty   |
797
 
           +-----+-----+-----+------------+
798
 
           | NE  | NE  | ME  | is empty   |
799
 
           +==============================+
800
 
        */
801
 
        if ( Stereo2    && Stereo2->nNumberOfStereoBonds ) {
802
 
            *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
803
 
        } else
804
 
        if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds &&
805
 
             !(Stereo1 && Stereo1->nNumberOfStereoBonds)
806
 
            ) {
807
 
            *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
808
 
        } else {
809
 
            *psDifSegs |= DIFV_BOTH_EMPTY;
810
 
        }
811
 
    }
812
 
    /*==================================*/
813
 
    /*====     /t, /m, /s for M   ======*/
814
 
    /*==================================*/
815
 
    /* M sp3 stereo */
816
 
 
817
 
 
818
 
    bRelRac[DIFL_M ] = GetSp3RelRacAbs( i1, Stereo1 );       /* Mobile-H */
819
 
    bRelRac[DIFL_MI] = GetSp3RelRacAbs( i1, IsoStereo1 );
820
 
    bRelRac[DIFL_F ] = GetSp3RelRacAbs( i2, Stereo2 );       /* Fixed-H */
821
 
    bRelRac[DIFL_FI] = GetSp3RelRacAbs( i2, IsoStereo2 );
822
 
    if ( SP3_NONE != bRelRac[DIFL_M] ) {
823
 
        sDifSegs[DIFL_M][DIFS_t_SATOMS] |= (bRelRac[DIFL_M] & SP3_ANY)?  DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
824
 
        sDifSegs[DIFL_M][DIFS_m_SP3INV] |= (bRelRac[DIFL_M] & SP3_ABS)?  DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
825
 
        sDifSegs[DIFL_M][DIFS_s_STYPE]  |= (bRelRac[DIFL_M] & SP3_TYPE)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
826
 
    } else {
827
 
        sDifSegs[DIFL_M][DIFS_t_SATOMS] |= DIFV_BOTH_EMPTY;
828
 
        sDifSegs[DIFL_M][DIFS_m_SP3INV] |= DIFV_BOTH_EMPTY;
829
 
        sDifSegs[DIFL_M][DIFS_s_STYPE]  |= DIFV_BOTH_EMPTY;
830
 
    }
831
 
    /*=====================*/
832
 
    /*====     /t    ======*/
833
 
    /*=====================*/
834
 
    /* F sp3 stereo */
835
 
    psDifSegs = &sDifSegs[DIFL_F][DIFS_t_SATOMS];
836
 
    if ( SP3_ANY & bRelRac[DIFL_F] ) {
837
 
        if ( Eql_INChI_Stereo( Stereo2, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
838
 
            *psDifSegs |= DIFV_EQL2PRECED;
839
 
        } else {
840
 
            *psDifSegs |= DIFV_NEQ2PRECED;
841
 
        }
842
 
    } else
843
 
    if ( SP3_ANY & bRelRac[DIFL_M] ) {
844
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
845
 
    } else {
846
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
847
 
    }
848
 
    /* MI sp3 stereo */
849
 
    psDifSegs = &sDifSegs[DIFL_MI][DIFS_t_SATOMS];
850
 
    if ( SP3_ANY & bRelRac[DIFL_MI] ) {
851
 
        if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
852
 
            *psDifSegs |= DIFV_EQL2PRECED;
853
 
        } else {
854
 
            *psDifSegs |= DIFV_NEQ2PRECED;
855
 
        }
856
 
    } else
857
 
    if ( SP3_ANY & bRelRac[DIFL_M] ) {
858
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
859
 
    } else {
860
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
861
 
    }
862
 
    /* FI sp3 stereo */
863
 
    psDifSegs = &sDifSegs[DIFL_FI][DIFS_t_SATOMS];
864
 
    if ( SP3_ANY & bRelRac[DIFL_FI] ) {
865
 
        if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP3, Stereo2, EQL_SP3, 0 ) ) {
866
 
            *psDifSegs |= DIFV_EQL2PRECED;
867
 
        } else
868
 
        if ( !(SP3_ANY & bRelRac[DIFL_M]) &&
869
 
             !(SP3_ANY & bRelRac[DIFL_F]) &&
870
 
             Eql_INChI_Stereo( IsoStereo2, EQL_SP3, IsoStereo1, EQL_SP3, 0 ) ) {
871
 
            *psDifSegs |= DIFV_FI_EQ_MI;
872
 
        } else {
873
 
            *psDifSegs |= DIFV_NEQ2PRECED;
874
 
        }
875
 
    } else /* similar to /b */
876
 
    if ( (SP3_ANY & bRelRac[DIFL_F]) ) {
877
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
878
 
    } else
879
 
    if ( (SP3_ANY & bRelRac[DIFL_MI]) && !(SP3_ANY & bRelRac[DIFL_M]) ) {
880
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
881
 
    } else {
882
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
883
 
    }
884
 
    /*=====================*/
885
 
    /*====     /m    ======*/
886
 
    /*=====================*/
887
 
    /* F sp3 abs stereo inversion */
888
 
    psDifSegs = &sDifSegs[DIFL_F][DIFS_m_SP3INV];
889
 
    if ( bRelRac[DIFL_F] & SP3_ABS ) {
890
 
        /* the order of || operands below is critically important: || is not a commutative operation */
891
 
        if ( !(bRelRac[DIFL_M] & SP3_ABS) || Stereo2->nCompInv2Abs != Stereo1->nCompInv2Abs ) {
892
 
            *psDifSegs |= DIFV_NEQ2PRECED;
893
 
        } else {
894
 
            *psDifSegs |= DIFV_EQL2PRECED;
895
 
        }
896
 
    } else
897
 
    if ( bRelRac[DIFL_M] & SP3_ABS ) {
898
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
899
 
    } else {
900
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
901
 
    }
902
 
    /* MI sp3 abs stereo inversion */
903
 
    psDifSegs = &sDifSegs[DIFL_MI][DIFS_m_SP3INV];
904
 
    if ( SP3_ABS & bRelRac[DIFL_MI] ) {
905
 
        if ( (SP3_ABS & bRelRac[DIFL_M]) && IsoStereo1->nCompInv2Abs == Stereo1->nCompInv2Abs ) {
906
 
            *psDifSegs |= DIFV_EQL2PRECED;
907
 
        } else {
908
 
            *psDifSegs |= DIFV_NEQ2PRECED;
909
 
        }
910
 
    } else
911
 
    if ( SP3_ABS & bRelRac[DIFL_M] ) {
912
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
913
 
    } else {
914
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
915
 
    }
916
 
    /* FI sp3 abs stereo inversion */
917
 
    psDifSegs = &sDifSegs[DIFL_FI][DIFS_m_SP3INV];
918
 
    if ( SP3_ABS & bRelRac[DIFL_FI] ) {
919
 
        if ( (SP3_ABS & bRelRac[DIFL_F]) && IsoStereo2->nCompInv2Abs == Stereo2->nCompInv2Abs ) {
920
 
            *psDifSegs |= DIFV_EQL2PRECED;
921
 
        } else
922
 
        if ( !(SP3_ABS & bRelRac[DIFL_M]) &&
923
 
             !(SP3_ABS & bRelRac[DIFL_F]) &&
924
 
             (SP3_ABS & bRelRac[DIFL_MI]) && /* make sure IsoStereo1 != NULL */
925
 
             IsoStereo2->nCompInv2Abs == IsoStereo1->nCompInv2Abs ) {
926
 
            *psDifSegs |= DIFV_FI_EQ_MI;
927
 
        } else {
928
 
            *psDifSegs |= DIFV_NEQ2PRECED;
929
 
        }
930
 
    } else /* similar to /b */
931
 
    /* the order of || operands below is critically important: || is no a commutative operation */
932
 
    if ( (SP3_ABS & bRelRac[DIFL_F]) ) {
933
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
934
 
    } else
935
 
    if ( (SP3_ABS & bRelRac[DIFL_MI]) && !(SP3_ABS & bRelRac[DIFL_M]) ) {
936
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
937
 
    } else {
938
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
939
 
    }
940
 
    /*=====================*/
941
 
    /*====     /s    ======*/
942
 
    /*=====================*/
943
 
    /* F sp3 stereo type */
944
 
    psDifSegs = &sDifSegs[DIFL_F][DIFS_s_STYPE];
945
 
    if ( bRelRac[DIFL_F] & SP3_TYPE ) {
946
 
        if ( (bRelRac[DIFL_F] & SP3_TYPE) == (bRelRac[DIFL_M] & SP3_TYPE) ) {
947
 
            *psDifSegs |= DIFV_EQL2PRECED;
948
 
        } else {
949
 
            *psDifSegs |= DIFV_NEQ2PRECED;
950
 
        }
951
 
    } else
952
 
    if ( bRelRac[DIFL_M] & SP3_TYPE ) {
953
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
954
 
    } else {
955
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
956
 
    }
957
 
    /* MI sp3 stereo type */
958
 
    psDifSegs = &sDifSegs[DIFL_MI][DIFS_s_STYPE];
959
 
    if ( SP3_TYPE & bRelRac[DIFL_MI] ) {
960
 
        if ( (SP3_TYPE & bRelRac[DIFL_MI]) == (SP3_TYPE & bRelRac[DIFL_M]) ) {
961
 
            *psDifSegs |= DIFV_EQL2PRECED;
962
 
        } else {
963
 
            *psDifSegs |= DIFV_NEQ2PRECED;
964
 
        }
965
 
    } else
966
 
    if ( SP3_TYPE & bRelRac[DIFL_M] ) {
967
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
968
 
    } else {
969
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
970
 
    }
971
 
    /* FI sp3 stereo type */
972
 
    psDifSegs = &sDifSegs[DIFL_FI][DIFS_s_STYPE];
973
 
    if ( SP3_TYPE & bRelRac[DIFL_FI] ) {
974
 
        if ( (SP3_TYPE & bRelRac[DIFL_FI]) == (SP3_TYPE & bRelRac[DIFL_F]) ) {
975
 
            *psDifSegs |= DIFV_EQL2PRECED;
976
 
        } else
977
 
        if ( !(SP3_TYPE & bRelRac[DIFL_M]) &&
978
 
             !(SP3_TYPE & bRelRac[DIFL_F]) &&
979
 
             (SP3_TYPE & bRelRac[DIFL_MI]) ) {
980
 
            *psDifSegs |= DIFV_FI_EQ_MI;
981
 
        } else {
982
 
            *psDifSegs |= DIFV_NEQ2PRECED;
983
 
        }
984
 
    } else /* similar to /b */
985
 
    /* the order of || operands below is critically important: || is not a commutative operation */
986
 
    if ( (SP3_TYPE & bRelRac[DIFL_F]) ) {
987
 
        *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
988
 
    } else
989
 
    if ( (SP3_TYPE & bRelRac[DIFL_MI]) && !(SP3_TYPE & bRelRac[DIFL_M]) ) {
990
 
        *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
991
 
    } else {
992
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
993
 
    }
994
 
    /*=====================*/
995
 
    /*====     /o    ======*/
996
 
    /*=====================*/
997
 
    if ( p1 && p2 && p1->ord_number != p2->ord_number ) {
998
 
        sDifSegs[DIFL_F][DIFS_o_TRANSP] |= DIFV_NEQ2PRECED;
999
 
    }
1000
 
    /*=====================*/
1001
 
    /*====     /i    ======*/
1002
 
    /*=====================*/
1003
 
    /* M isotopic atoms */
1004
 
    psDifSegs = &sDifSegs[DIFL_MI][DIFS_i_IATOMS];
1005
 
    if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1006
 
        *psDifSegs |= DIFV_NEQ2PRECED;
1007
 
    } else {
1008
 
        *psDifSegs |= DIFV_BOTH_EMPTY;
1009
 
    }
1010
 
    /* F isotopic atoms */
1011
 
    psDifSegs = &sDifSegs[DIFL_FI][DIFS_i_IATOMS];
1012
 
    if ( i2 && !i2->bDeleted ) {
1013
 
        if ( i2->nNumberOfIsotopicAtoms || i2->nNumberOfIsotopicTGroups ) {
1014
 
            if ( !i1 || i1->bDeleted ||
1015
 
                 i2->nNumberOfIsotopicAtoms   != i1->nNumberOfIsotopicAtoms ||
1016
 
                 i2->nNumberOfIsotopicTGroups != i1->nNumberOfIsotopicTGroups ) {
1017
 
                *psDifSegs |= DIFV_NEQ2PRECED;
1018
 
            } else {
1019
 
                int diff;
1020
 
                num  = i1->nNumberOfIsotopicAtoms;
1021
 
                diff = 0;
1022
 
                for ( i = 0; i < num; i ++ ) {
1023
 
                    /* compare isotopic atoms */
1024
 
                    if ( diff = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
1025
 
                        break;
1026
 
                    if ( diff = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
1027
 
                        break;
1028
 
                    /* compare isotopic H */
1029
 
                    if ( diff = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
1030
 
                        break;
1031
 
                    if ( diff = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
1032
 
                        break;
1033
 
                    if ( diff = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
1034
 
                        break;
1035
 
                }
1036
 
                if ( !diff ) {
1037
 
                    num = i1->nNumberOfIsotopicTGroups;
1038
 
                    for ( i = 0; i < num; i ++ ) {
1039
 
                        if ( diff = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
1040
 
                            break;
1041
 
                        if ( diff = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
1042
 
                            break;
1043
 
                        if ( diff = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
1044
 
                            return diff;
1045
 
                        if ( diff = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
1046
 
                            break;
1047
 
                    }
1048
 
                }
1049
 
                *psDifSegs |= diff? DIFV_NEQ2PRECED : DIFV_FI_EQ_MI;
1050
 
 
1051
 
            }
1052
 
        } else
1053
 
        if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1054
 
            *psDifSegs |= DIFV_IS_EMPTY;
1055
 
        }
1056
 
    } else
1057
 
    if ( !i2 ) {
1058
 
        if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
1059
 
            *psDifSegs |= DIFV_EQL2PRECED;
1060
 
        } else {
1061
 
            *psDifSegs |= DIFV_BOTH_EMPTY;
1062
 
        }
1063
 
    }
1064
 
 
1065
 
    return ret;
1066
 
}
1067
 
/**********************************************************************************************/
1068
 
int INChI_SegmentAction( char cDifSegs )
1069
 
{
1070
 
    if ( !(cDifSegs & DIFV_OUTPUT_OMIT_F) ) {
1071
 
        return INCHI_SEGM_OMIT;
1072
 
    }
1073
 
    if ( (cDifSegs & DIFV_OUTPUT_EMPTY_T) && !(cDifSegs & DIFV_OUTPUT_EMPTY_F) ) {
1074
 
        return INCHI_SEGM_EMPTY;
1075
 
    }
1076
 
    if ( (cDifSegs & DIFV_OUTPUT_FILL_T) ) {
1077
 
        return INCHI_SEGM_FILL;
1078
 
    }
1079
 
    return INCHI_SEGM_OMIT; /* the control flow shoul never reach this point */
1080
 
}
1081
 
/**********************************************************************************************/
1082
 
int MarkUnusedAndEmptyLayers( char sDifSegs[][DIFS_LENGTH] )
1083
 
{
1084
 
    /****************************************************
1085
 
     1. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1086
 
        and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1087
 
        and there is NO succeeding non-empty layer then mark the 1st element
1088
 
        of the layer DIFV_BOTH_EMPTY; this layerr will be omitted.
1089
 
     
1090
 
     2. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1091
 
        and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1092
 
        and there IS a succeeding non-empty layer then mark the 1st element
1093
 
        of the layer DIFV_IS_EMPTY and all other elements DIFV_BOTH_EMPTY;
1094
 
        only the first empty segment of this layerr will be output.
1095
 
 
1096
 
     3. If NOT all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1097
 
        and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1098
 
        and the 1st element of the layer is DIFV_BOTH_EMPTY then mark it
1099
 
        DIFV_IS_EMPTY; it will be output as empty (except M layer).
1100
 
     */
1101
 
 
1102
 
    int i, nLayer, sBits, nFirstSegm;
1103
 
#define nFirstFmlSegm   DIFS_f_FORMULA
1104
 
#define nFirstIsoSegm   DIFS_i_IATOMS
1105
 
     /* FI */
1106
 
    nLayer = DIFL_FI;
1107
 
    nFirstSegm = nFirstIsoSegm;
1108
 
    sBits  = 0;
1109
 
    for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1110
 
        sBits |= sDifSegs[nLayer][i];
1111
 
    }
1112
 
    if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1113
 
        /* Omit the FI layer */
1114
 
        memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1115
 
    } else
1116
 
    if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1117
 
         !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1118
 
        sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1119
 
    }
1120
 
 
1121
 
    /* MI */
1122
 
    nLayer = DIFL_MI;
1123
 
    nFirstSegm = nFirstIsoSegm;
1124
 
    sBits  = 0;
1125
 
    for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1126
 
        sBits |= sDifSegs[nLayer][i];
1127
 
    }
1128
 
    if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1129
 
        /* Omit the MI layer */
1130
 
        memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1131
 
    } else
1132
 
    if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1133
 
         !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1134
 
        sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1135
 
    }
1136
 
 
1137
 
    /* F */
1138
 
    nLayer = DIFL_F;
1139
 
    nFirstSegm = nFirstFmlSegm;
1140
 
    sBits  = 0;
1141
 
    for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1142
 
        sBits |= sDifSegs[nLayer][i];
1143
 
    }
1144
 
    if ( !(sBits & DIFV_OUTPUT_OMIT_F) &&
1145
 
         sDifSegs[DIFL_FI][nFirstIsoSegm] == DIFV_BOTH_EMPTY ) {
1146
 
        /* Omit the F layer: no non-iotopic and no isotopic segments */
1147
 
        memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1148
 
    } else
1149
 
    /* do not omit fixed-H layer */
1150
 
    if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1151
 
         !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1152
 
        sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1153
 
    }
1154
 
     
1155
 
    /* M -- leave as it is */
1156
 
    return 0;
1157
 
#undef nFirstFmlSegm
1158
 
#undef nFirstIsoSegm
1159
 
}
1160
 
/*********************************************************************************************/
1161
 
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 )
1162
 
{
1163
 
    int i, num, ret;
1164
 
    if ( Stereo2 && Stereo1 ) {
1165
 
        /*  compare stereogenic bonds */
1166
 
        num = inchi_min( Stereo2->nNumberOfStereoBonds, Stereo1->nNumberOfStereoBonds );
1167
 
        for ( i = 0; i < num; i ++ ) {
1168
 
            if ( ret = (int)Stereo2->nBondAtom1[i] - (int)Stereo1->nBondAtom1[i] )
1169
 
                return ret;
1170
 
            if ( ret = (int)Stereo2->nBondAtom2[i] - (int)Stereo1->nBondAtom2[i] )
1171
 
                return ret;
1172
 
            if ( ret = (int)Stereo2->b_parity[i] - (int)Stereo1->b_parity[i] )
1173
 
                return ret;
1174
 
        }
1175
 
        if ( ret = (int)Stereo2->nNumberOfStereoBonds - (int)Stereo1->nNumberOfStereoBonds )
1176
 
            return ret;
1177
 
        /*  compare stereogenic atoms */
1178
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1179
 
        if ( ((nFlags1 | nFlags2) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) ) &&
1180
 
             1 == Stereo2->nNumberOfStereoCenters &&
1181
 
             1 == Stereo1->nNumberOfStereoCenters ) {
1182
 
            ; /*  do not compare single stereocenters in case of relative stereo */
1183
 
        } else
1184
 
#endif
1185
 
        {
1186
 
            num = inchi_min( Stereo2->nNumberOfStereoCenters, Stereo1->nNumberOfStereoCenters );
1187
 
            for ( i = 0; i < num; i ++ ) {
1188
 
                if ( ret = (int)Stereo2->nNumber[i] - (int)Stereo1->nNumber[i] )
1189
 
                    return ret;
1190
 
                if ( ret = (int)Stereo2->t_parity[i] - (int)Stereo1->t_parity[i] )
1191
 
                    return ret;
1192
 
            }
1193
 
            if ( ret = (int)Stereo2->nNumberOfStereoCenters - (int)Stereo1->nNumberOfStereoCenters )
1194
 
                return ret;
1195
 
            /*  compare stereo-abs-is-inverted flags  for non-relative, non-racemic */
1196
 
            if ( !((nFlags1 | nFlags2) & (INCHI_FLAG_RAC_STEREO | INCHI_FLAG_REL_STEREO)) ) {
1197
 
                if ( ret = (Stereo2->nCompInv2Abs < 0) - (Stereo1->nCompInv2Abs < 0) ) {
1198
 
                    return ret;
1199
 
                }
1200
 
            }
1201
 
        }
1202
 
    } else
1203
 
    if ( Stereo2 && ( Stereo2->nNumberOfStereoBonds > 0 ||
1204
 
                      Stereo2->nNumberOfStereoCenters > 0
1205
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1206
 
                      && /*  do not compare single stereocenters in case of relative stereo */
1207
 
                      !((nFlags2 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1208
 
                       1 == Stereo2->nNumberOfStereoCenters
1209
 
                       )
1210
 
#endif
1211
 
       ) ) {
1212
 
        return 1;
1213
 
    }else
1214
 
    if ( Stereo1 && ( Stereo1->nNumberOfStereoBonds > 0 || 
1215
 
                      Stereo1->nNumberOfStereoCenters > 0
1216
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
1217
 
                      && /*  do not compare single stereocenters in case of relative stereo */
1218
 
                      !((nFlags1 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1219
 
                       1 == Stereo1->nNumberOfStereoCenters
1220
 
                       )
1221
 
#endif
1222
 
       ) ) {
1223
 
        return -1;
1224
 
    }
1225
 
    return 0;
1226
 
}
1227
 
/**********************************************************************************************/
1228
 
/*  sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2               */
1229
 
/**********************************************************************************************/
1230
 
int CompINChI2(const INCHI_SORT *p1, const INCHI_SORT *p2, int bTaut, int bCompareIsotopic)
1231
 
{
1232
 
    int ret, num, i, num_H1, num_H2;
1233
 
    
1234
 
    const INChI *i1  = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1235
 
    const INChI *i2  = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1236
 
    
1237
 
    int   n1;               /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
1238
 
    int   n2;               /* TAUT_YES if tautomeric i2 exists, otherwise TAUT_NON */
1239
 
    
1240
 
    const INChI *i1n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1241
 
    const INChI *i2n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1242
 
 
1243
 
    /*const INChI *i1t = NULL;*/ /* temp for i1 if both tautomeric AND non-tautomeric exist */
1244
 
    /*const INChI *i2t = NULL;*/ /* temp for i2 if both tautomeric AND non-tautomeric exist */
1245
 
 
1246
 
 
1247
 
    /* INChI_Stereo *Stereo1, *Stereo2; */
1248
 
 
1249
 
    n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1250
 
    n2 = ( p2->pINChI[TAUT_YES] && p2->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1251
 
 
1252
 
    i1  = p1->pINChI[n1];
1253
 
    i1n = (n1 == TAUT_YES && p1->pINChI[TAUT_NON] &&
1254
 
           p1->pINChI[TAUT_NON]->nNumberOfAtoms)? p1->pINChI[TAUT_NON] : (const INChI *)NULL;
1255
 
 
1256
 
    i2  = p2->pINChI[n2];
1257
 
    i2n = (n2 == TAUT_YES && p2->pINChI[TAUT_NON] &&
1258
 
          p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
1259
 
 
1260
 
    /* non-deleted-non-empty < deleted < empty */
1261
 
    if ( i1 && !i2 )
1262
 
        return -1;   /* non-empty is the smallest (first) */
1263
 
    if ( !i1 && i2 )
1264
 
        return 1;
1265
 
    if ( !i1 && !i2 )
1266
 
        return 0;
1267
 
    if ( i1->bDeleted && !i2->bDeleted )
1268
 
        return 1;    /* deleted is the largest (last) among non-empty */
1269
 
    if ( !i1->bDeleted && i2->bDeleted )
1270
 
        return -1;
1271
 
 
1272
 
    num_H1 = num_H2 = 0;
1273
 
    
1274
 
    /* do not compare terminal H */
1275
 
    if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
1276
 
        return ret;  /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
1277
 
    }
1278
 
 
1279
 
    /*********************************************************
1280
 
            compare non-isotopic non-tautomeric part
1281
 
     *********************************************************/
1282
 
 
1283
 
    /* compare number of atoms (excluding terminal H) */
1284
 
    if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
1285
 
        return ret; /*  more atoms first */
1286
 
    
1287
 
    /*  compare elements  (excluding terminal H) */
1288
 
    num = i1->nNumberOfAtoms;
1289
 
    for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
1290
 
        if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
1291
 
            return ret; /* greater periodic number first */
1292
 
    }
1293
 
    /**********************************************************
1294
 
        compare connection tables
1295
 
    ***********************************************************/
1296
 
    if ( ret = i2->lenConnTable - i1->lenConnTable )
1297
 
        return ret; /* longer connection table first */
1298
 
    num = i2->lenConnTable; 
1299
 
    for ( i = 0; i < num; i ++ ) {
1300
 
        if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
1301
 
            return ret; /* greater connection table first */
1302
 
    }
1303
 
    /*********************************************************
1304
 
      compare compare total number of H (inverse: H3 < H2 )
1305
 
    **********************************************************/
1306
 
    if ( ret = num_H2 - num_H1 )
1307
 
        return ret;
1308
 
    /*********************************************************
1309
 
      compare non-tautomeric num_H: N < NH3 < NH2 < NH
1310
 
    **********************************************************/
1311
 
    num = i1->nNumberOfAtoms;
1312
 
    for ( i = 0; i < num; i ++ ) {
1313
 
        if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
1314
 
            return !i2->nNum_H[i]?  1 :  /* no H first */
1315
 
                   !i1->nNum_H[i]? -1 :
1316
 
                   (int)i2->nNum_H[i] - (int)i1->nNum_H[i];
1317
 
        }
1318
 
    }
1319
 
    /*********************************************************
1320
 
         compare non-isotopic tautomeric part
1321
 
     *********************************************************/
1322
 
    if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
1323
 
        return ret;
1324
 
    }
1325
 
    /*
1326
 
    if ( ret = i2->lenTautomer - i1->lenTautomer )
1327
 
        return ret;
1328
 
    num = inchi_min( i2->lenTautomer, i1->lenTautomer );
1329
 
    for ( i = 0; i < num; i ++ ) {
1330
 
        if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
1331
 
            return ret;
1332
 
    }
1333
 
    */
1334
 
    /*********************************************************
1335
 
     *                                                       *
1336
 
     *  at this point both components are either tautomeric  *
1337
 
     *  or non-tautomeric                                    *
1338
 
     *                                                       *
1339
 
     *********************************************************/
1340
 
 
1341
 
    /*********************************************************
1342
 
       non-tautomeric "fixed H" specific
1343
 
     *********************************************************/
1344
 
    if ( TAUT_NON == bTaut && (i1n && i1n->nNum_H_fixed || i2n && i2n->nNum_H_fixed) ) {
1345
 
        /* first, compare non-tautomeric chem. formulas -- they may be different */
1346
 
        const char *f1 = (i1n /*&& i1n->nNum_H_fixed*/)? i1n->szHillFormula : i1->szHillFormula;
1347
 
        const char *f2 = (i2n /*&& i2n->nNum_H_fixed*/)? i2n->szHillFormula : i2->szHillFormula;
1348
 
        if ( f1 && f2 &&(ret = CompareHillFormulas( f1, f2 ))) {
1349
 
            return ret;
1350
 
        }
1351
 
        /* secondly, compare fixed-H distribution */
1352
 
        if ( i1n && i1n->nNum_H_fixed && i2n && i2n->nNum_H_fixed ) {
1353
 
            num = inchi_min( i1n->nNumberOfAtoms, i2n->nNumberOfAtoms);
1354
 
            for ( i = 0; i < num; i ++ ) {
1355
 
                if ( i2n->nNum_H_fixed[i] != i1n->nNum_H_fixed[i] ) {
1356
 
                    return !i2n->nNum_H_fixed[i]?  1 : /* no fixed H first */
1357
 
                           !i1n->nNum_H_fixed[i]? -1 :
1358
 
                           (int)i2n->nNum_H_fixed[i] - (int)i1n->nNum_H_fixed[i];
1359
 
                }
1360
 
            }
1361
 
            if ( ret = (int)i2n->nNumberOfAtoms - (int)i1n->nNumberOfAtoms ) {
1362
 
                return ret; /* should not happen <BRKPT> */
1363
 
            }
1364
 
        } else
1365
 
        if ( i1n && i1n->nNum_H_fixed ) {
1366
 
            num = i1n->nNumberOfAtoms;
1367
 
            for ( i = 0; i < num; i ++ ) {  /* added 2004-05-04 */
1368
 
                if ( i1n->nNum_H_fixed[i] ) {
1369
 
                    return -1; /* i1n->nNum_H_fixed[i] > 0? -1:1;*/
1370
 
                }
1371
 
            }
1372
 
            /* p1 is tautomeric, p2 is not tautomeric; this must have been detected earlier */
1373
 
            /*return -1;*/ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1374
 
        } else {
1375
 
            num = i2n->nNumberOfAtoms;
1376
 
            for ( i = 0; i < num; i ++ ) {  /* added 2004-05-04 */
1377
 
                if ( i2n->nNum_H_fixed[i] ) {
1378
 
                    return 1; /* i2n->nNum_H_fixed[i] > 0? 1:-1;*/
1379
 
                }
1380
 
            }
1381
 
            /* p2 is tautomeric, p1 is not tautomeric; this must have been detected earlier */
1382
 
            /*return 1; */ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1383
 
        }
1384
 
    }
1385
 
    
1386
 
    /*************************************************************************
1387
 
              if requested non-tautomeric comparison then
1388
 
              prepare to compare non-taut non-isotopic stereo, etc. 
1389
 
     *************************************************************************/
1390
 
    if ( TAUT_NON == bTaut ) {
1391
 
        if ( i1n ) {
1392
 
            /*i1t = i1;*/
1393
 
            i1  = i1n;
1394
 
        }
1395
 
        if ( i2n ) {
1396
 
            /*i2t = i2;*/
1397
 
            i2  = i2n;
1398
 
        }
1399
 
    }
1400
 
 
1401
 
    /*********************************************************
1402
 
        compare non-isotopic stereo
1403
 
     *********************************************************/
1404
 
    ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
1405
 
    if ( ret ) {
1406
 
        return ret;
1407
 
    }
1408
 
    /*******************************************************
1409
 
        do not switch back to tautomeric i1, i2
1410
 
     *******************************************************/
1411
 
    /* -- how to switch back --
1412
 
    if ( i1t ) {
1413
 
        i1  = i1t;
1414
 
        i1t = NULL;
1415
 
    }
1416
 
    if ( i2t ) {
1417
 
        i2  = i2t;
1418
 
        i2t = NULL;
1419
 
    }
1420
 
    */
1421
 
    /******************************************************
1422
 
         compare isotopic non-tautomeric part
1423
 
     ******************************************************/
1424
 
    if ( bCompareIsotopic ) {
1425
 
        if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
1426
 
            return ret;
1427
 
        num = i1->nNumberOfIsotopicAtoms;
1428
 
        /*  compare isotopic atoms */
1429
 
        for ( i = 0; i < num; i ++ ) {
1430
 
            if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
1431
 
                return ret;
1432
 
            if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
1433
 
                return ret;
1434
 
        }
1435
 
        /* compare isotopic H */
1436
 
        /* if tautomeric comparison mode then here are compared only non-tautomeric H */
1437
 
        for ( i = 0; i < num; i ++ ) {
1438
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
1439
 
                return ret;
1440
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
1441
 
                return ret;
1442
 
            if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
1443
 
                return ret;
1444
 
        }
1445
 
        /*****************************************************
1446
 
             compare isotopic tautomeric part
1447
 
         *****************************************************/
1448
 
        if ( ret = i2->nNumberOfIsotopicTGroups - i1->nNumberOfIsotopicTGroups )
1449
 
            return ret;
1450
 
        num = i1->nNumberOfIsotopicTGroups;
1451
 
        for ( i = 0; i < num; i ++ ) {
1452
 
            if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
1453
 
                return ret;
1454
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
1455
 
                return ret;
1456
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
1457
 
                return ret;
1458
 
            if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
1459
 
                return ret;
1460
 
        }
1461
 
    
1462
 
        /****************************************************
1463
 
            compare isotopic stereo
1464
 
         ****************************************************/
1465
 
        ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
1466
 
        if ( ret ) {
1467
 
            return ret;
1468
 
        }
1469
 
    }
1470
 
 
1471
 
    /**********************************************************
1472
 
        compare charges: non-charged first, then in order of
1473
 
        ascending charges (negative first) 
1474
 
    ***********************************************************/
1475
 
    if ( i2->nTotalCharge && i1->nTotalCharge ) {
1476
 
        /*  both are charged; smaller charges first */
1477
 
        ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
1478
 
        return ret;
1479
 
    }
1480
 
    if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
1481
 
        /*  only one is charged; uncharged first */
1482
 
        return ret;
1483
 
    }
1484
 
    /* stable sort */
1485
 
    /*ret = p1->ord_number - p2->ord_number;*/
1486
 
 
1487
 
    return ret;
1488
 
}
1489
 
/***********************************************************************/
1490
 
int CompINChINonTaut2(const void *p1, const void *p2)
1491
 
{
1492
 
    int ret;
1493
 
    ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1494
 
#if( CANON_FIXH_TRANS == 1 )
1495
 
    if ( !ret ) {
1496
 
        /* to obtain canonical transposition 2004-05-10 */
1497
 
        ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1498
 
    }
1499
 
#endif
1500
 
    if ( !ret ) {
1501
 
        /* stable sort */
1502
 
        ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1503
 
    }
1504
 
    return ret;
1505
 
}
1506
 
/***********************************************************************/
1507
 
int CompINChITaut2(const void *p1, const void *p2)
1508
 
{
1509
 
    int ret;
1510
 
    ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1511
 
#if( CANON_FIXH_TRANS == 1 )
1512
 
    if ( !ret ) {
1513
 
        /* to obtain canonical transposition 2004-05-10 */
1514
 
        ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1515
 
    }
1516
 
#endif
1517
 
    if ( !ret ) {
1518
 
        /* stable sort */
1519
 
        ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1520
 
    }
1521
 
    return ret;
1522
 
}
1523
 
/**********************************************************************************************/
1524
 
/*  strrev from K&R is not in ANSI-compatible C library */
1525
 
void mystrrev( char *p )
1526
 
{
1527
 
    char c, *q = p;
1528
 
    while( *q++ )
1529
 
        ;
1530
 
    q -= 2; /*  pointer to the last character */
1531
 
    while ( p < q ) {
1532
 
        c    = *q;  /*  swap */
1533
 
        *q-- = *p;
1534
 
        *p++ = c;
1535
 
    }
1536
 
}
1537
 
/*****************************************************************************************/
1538
 
/*                Find DFS order for CT(canon. numbers and Hs) output                    */
1539
 
/*****************************************************************************************/
1540
 
 
1541
 
static AT_NUMB   *gDfs4CT_nDfsNumber;
1542
 
static AT_NUMB   *gDfs4CT_nNumDescendants;
1543
 
static int        gDfs4CT_nCurrentAtom;
1544
 
 
1545
 
/**********************************************************************************************/
1546
 
static int CompareDfsDescendants4CT( const void *a1, const void *a2 )
1547
 
{
1548
 
    int neigh1 = (int)*(const AT_RANK*)a1;
1549
 
    int neigh2 = (int)*(const AT_RANK*)a2;
1550
 
    if ( neigh1 > MAX_ATOMS ) {
1551
 
        if ( neigh2 > MAX_ATOMS ) {
1552
 
            return 0;
1553
 
        }
1554
 
        return 1;
1555
 
    } else
1556
 
    if ( neigh2 > MAX_ATOMS ) {
1557
 
        return -1;
1558
 
    } else {
1559
 
        AT_RANK nCurDfsNumber = gDfs4CT_nDfsNumber[gDfs4CT_nCurrentAtom];
1560
 
        int nDesc1 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh1]?
1561
 
                         0 : (int)gDfs4CT_nNumDescendants[neigh1];
1562
 
        int nDesc2 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh2]?
1563
 
                         0 : (int)gDfs4CT_nNumDescendants[neigh2];
1564
 
        int ret;
1565
 
        if ( ret = nDesc1 - nDesc2 ) {
1566
 
            return ret;
1567
 
        }
1568
 
        return  (int)neigh1 - (int)neigh2; /*  canon. numbers difference */
1569
 
    }
1570
 
}
1571
 
/**********************************************************************************************/
1572
 
/*  sp_ATOM *at, AT_RANK *nRank, int num_atoms */
1573
 
AT_NUMB *GetDfsOrder4CT( AT_NUMB *LinearCT, int nLenCT, S_CHAR *nNum_H, int num_atoms, int nCtMode )
1574
 
{
1575
 
    AT_NUMB    *nStackAtom = NULL;
1576
 
    int         nTopStackAtom=-1;
1577
 
    AT_NUMB    *nNumDescendants = NULL; /*  number of descendants incl. closures and the atom itself */
1578
 
    AT_NUMB    *nDfsNumber = NULL;
1579
 
    S_CHAR     *cNeighNumb = NULL;
1580
 
    NEIGH_LIST *nl = NULL;
1581
 
    AT_NUMB     nDfs;
1582
 
    int         i, j, u, k, start, num_rings, nTotOutputStringLen;
1583
 
    AT_NUMB    *nOutputString = NULL, cDelim;
1584
 
    int         bCtPredecessors = (nCtMode & CT_MODE_PREDECESSORS);
1585
 
 
1586
 
    /* int nNumStartChildren; */
1587
 
 
1588
 
 
1589
 
    /*  allocate arrays */
1590
 
    nStackAtom      = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
1591
 
    nNumDescendants = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nNumDescendants[0]));
1592
 
    nDfsNumber      = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
1593
 
    cNeighNumb      = (S_CHAR  *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
1594
 
    nl              = CreateNeighListFromLinearCT( LinearCT, nLenCT, num_atoms );
1595
 
    /*  check allocation */
1596
 
    if ( !nStackAtom || !nNumDescendants || !nDfsNumber || !cNeighNumb || !nl ) {
1597
 
        /* ret = CT_OUT_OF_RAM; */ /*  program error */ /*   <BRKPT> */
1598
 
        goto exit_function;
1599
 
    }
1600
 
    if ( bCtPredecessors ) {
1601
 
        start = 0;
1602
 
    } else {
1603
 
        /*  find DFS start vertex (atom) */
1604
 
        for ( i = 1, start = 0; i < num_atoms; i ++ ) {
1605
 
            if ( nl[i][0] <  nl[start][0] ) { /*  index = nRank-1 */
1606
 
                start = i;
1607
 
            }
1608
 
        }
1609
 
    }
1610
 
    /*
1611
 
      vertex information:
1612
 
        1. Number of (forward edges) + (back edges, first visit -- ring closures): nl[i][0]
1613
 
        2. Number of vertices traversed from this vertex, including the vertex:    nNumDescendants[i]
1614
 
        3. Each edge information:
1615
 
           a. forward edge (0) or back edge (1) indicator: nDfsNumber[i] > nDfsNumber[neigh]
1616
 
           b. neighbor at another end of the edge neigh = nl[i][k+1], k < i
1617
 
 
1618
 
        Total per edge: 2 + 2*(number of edges)
1619
 
    */
1620
 
 
1621
 
    /* DFS initiation */
1622
 
    u               = start; /* start atom */
1623
 
    nDfs            = 0;
1624
 
    nTopStackAtom   =-1;
1625
 
    memset( nDfsNumber,      0, num_atoms*sizeof(nDfsNumber[0]));
1626
 
    memset( nNumDescendants, 0, num_atoms*sizeof(nNumDescendants[0]));
1627
 
    memset( cNeighNumb,      0, num_atoms*sizeof(cNeighNumb[0]));
1628
 
    /*  push the start atom on the stack */
1629
 
    nDfsNumber[u] = ++nDfs;
1630
 
    if ( bCtPredecessors ) {
1631
 
        nNumDescendants[u] = 0; /* atom #1 has no predecessor */
1632
 
    } else {
1633
 
        nNumDescendants[u] = 1; /* count itself as a descendant */
1634
 
    }
1635
 
    nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1636
 
    /* nNumStartChildren = 0; */
1637
 
    num_rings = 0;
1638
 
 
1639
 
    /* DFS */
1640
 
    
1641
 
    do {
1642
 
        /* advance */
1643
 
        while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i]+1,  (int)nl[i][0] >= j )
1644
 
        /*while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) )*/
1645
 
        /* replaced due to missing sequence point; undefined behavior, pointed by Geoffrey Hutchison */
1646
 
        {
1647
 
            cNeighNumb[i] ++;
1648
 
            u = (int)nl[i][j]; /*  jth neighbor of the vertex i */
1649
 
            if ( !nDfsNumber[u] ) {
1650
 
                /* tree edge, 1st visit -- advance */
1651
 
                /* put unexplored vertex u on the stack for further examination */
1652
 
                nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1653
 
                nDfsNumber[u] = ++nDfs;
1654
 
                if ( bCtPredecessors ) {
1655
 
                    nNumDescendants[u] = i+1; /* predecessor's rank */
1656
 
                } else {
1657
 
                    nNumDescendants[u] ++; /* count atom u as its descendant */
1658
 
                }
1659
 
            } else
1660
 
            if ( nTopStackAtom && u != (int)nStackAtom[nTopStackAtom-1] &&
1661
 
                 /* back edge: u is not a predecessor of i */
1662
 
                 nDfsNumber[u] < nDfsNumber[i] ) {
1663
 
                /* Back edge, 1st visit: u is an ancestor of i (ring closure) */
1664
 
                if ( !bCtPredecessors ) {
1665
 
                    nNumDescendants[i] ++; /* count closures as descendants */
1666
 
                }
1667
 
                num_rings ++;          /* count ring closures */
1668
 
            } else {
1669
 
                nl[i][j] = MAX_ATOMS+1; /* back edge, 2nd visit: mark as deleted */
1670
 
            }
1671
 
        }
1672
 
        cNeighNumb[i] = 0; /* all neighbors of the ith atom have been
1673
 
                              traversed; resore the neighbor counter */
1674
 
        /* back up */
1675
 
        if ( !bCtPredecessors && nTopStackAtom /* that is, i != start */) {
1676
 
            u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
1677
 
            nNumDescendants[u] += nNumDescendants[i]; /* add descendants */
1678
 
        }
1679
 
    } while ( --nTopStackAtom >= 0 );
1680
 
 
1681
 
    /* Sort the neighbors in ascending order so that:
1682
 
       primary key   = number of descendants in the DFS tree; closure neighbor is 0
1683
 
       secondary key = canonical number (here vertex number = canonical number - 1)
1684
 
     */
1685
 
 
1686
 
    /* set static globals for the sorting: */
1687
 
    gDfs4CT_nDfsNumber      = nDfsNumber;     
1688
 
    gDfs4CT_nNumDescendants = nNumDescendants;
1689
 
    gDfs4CT_nCurrentAtom    = -1;   
1690
 
 
1691
 
    /* sorting; deleted will be the last neighbors */
1692
 
    for ( i = 0; i < num_atoms; i ++ ) {
1693
 
        if ( nl[i][0] > 1 ) {
1694
 
            gDfs4CT_nCurrentAtom = i;
1695
 
            insertions_sort( &nl[i][1], nl[i][0], sizeof(nl[i][1]), CompareDfsDescendants4CT );
1696
 
        }
1697
 
        /* reduce number of neighbors to exclude deleted */
1698
 
        for ( k = 0; k < nl[i][0] && nl[i][k+1] <= MAX_ATOMS; k ++ )
1699
 
            ;
1700
 
        nl[i][0] = k;
1701
 
    }
1702
 
 
1703
 
    nTotOutputStringLen = 3*(num_atoms+num_rings+1); /*  last 3 elements are a 'zero termination' */
1704
 
 
1705
 
    if ( bCtPredecessors ) {
1706
 
        if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1707
 
            cDelim = '-';
1708
 
            for ( u = 0, k = -3 ; u < num_atoms; u ++ ) {
1709
 
                k += 3;
1710
 
                if ( k+6 > nTotOutputStringLen ) {
1711
 
                    goto exit_error;  /* program error */
1712
 
                }
1713
 
                nOutputString[k]   = nNumDescendants[u]? nNumDescendants[u] : MAX_ATOMS+1;
1714
 
                nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1715
 
                nOutputString[k+2] = k? ',' : '\0';
1716
 
                for ( j = 1; j <= nl[u][0] && nDfsNumber[u] > nDfsNumber[i=nl[u][j]]; j ++ ) {
1717
 
                    /* closures */
1718
 
                    k += 3;
1719
 
                    if ( k+6 > nTotOutputStringLen ) {
1720
 
                        goto exit_error;  /* program error */
1721
 
                    }
1722
 
                    nOutputString[k]   = i+1;  /* closure */
1723
 
                    nOutputString[k+1] = 0;
1724
 
                    nOutputString[k+2] = cDelim;
1725
 
                }
1726
 
            }
1727
 
        }
1728
 
    } else {
1729
 
        if ( nNumDescendants ) {  /* do not need anymore */
1730
 
            inchi_free( nNumDescendants );
1731
 
            nNumDescendants = NULL;
1732
 
        }
1733
 
        /* 
1734
 
            the output string contains:
1735
 
              (num_atoms) atoms for the DFS (spanning) tree
1736
 
              (num_atoms-1) delimiters for the DFS (spanning) tree
1737
 
              1 character for each atom that has 1 terminal hydrogen atoms
1738
 
              2 characters  for each atom that has 2-9 terminal hydrogen atoms
1739
 
              3 characters  for each atom that has 10-99 terminal hydrogen atoms, etc.
1740
 
              (num_rings) atoms for the ring closures
1741
 
              (num_rings) delimiters for the ring closures
1742
 
        */
1743
 
 
1744
 
        if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1745
 
            u               = start; /*  start atom */
1746
 
            nTopStackAtom   =-1;
1747
 
            memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
1748
 
            /*  push the start atom on the stack */
1749
 
            nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1750
 
            /*  output the starting atom */
1751
 
            k = 0;
1752
 
            nOutputString[k]   = u+1;
1753
 
            nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1754
 
            nOutputString[k+2] = '\0';
1755
 
 
1756
 
            do {
1757
 
                /* advance */
1758
 
                while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i]+1,  (int)nl[i][0] >= j )
1759
 
                /*while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) )*/
1760
 
                /* replaced due to missing sequence point; undefined behavior, reported by Geoffrey Hutchison */
1761
 
                {
1762
 
                    k += 3;
1763
 
                    if ( k+6 > nTotOutputStringLen ) {
1764
 
                        goto exit_error;  /* program error */
1765
 
                    }
1766
 
                    cNeighNumb[i] ++;
1767
 
                    u = (int)nl[i][j]; /* neighbor */
1768
 
 
1769
 
                    /* output neighbor's canonical number */
1770
 
                    nOutputString[k] = u+1;
1771
 
 
1772
 
                    if ( nDfsNumber[u] > nDfsNumber[i] ) {
1773
 
                        /* tree edge, 1st visit -- advance */
1774
 
                        /* put 'unexplored' vertex u on the stack */
1775
 
                        nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1776
 
 
1777
 
                        /* output neighbor's number of H */
1778
 
                        nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1779
 
                    } else {
1780
 
                        nOutputString[k+1] = 0;
1781
 
                    }
1782
 
                    /* output a delimiter preceding the neighbor */
1783
 
                    if ( 1 < nl[i][0] ) {
1784
 
                        if ( j == 1 ) {
1785
 
                            cDelim = '(';
1786
 
                        } else
1787
 
                        if (  j == nl[i][0] ) {
1788
 
                            cDelim = ')';
1789
 
                        } else {
1790
 
                            cDelim = ',';
1791
 
                        }
1792
 
                    } else {
1793
 
                        cDelim = '-';
1794
 
                    }
1795
 
                    nOutputString[k+2] = cDelim;
1796
 
                }
1797
 
                cNeighNumb[i] = 0;
1798
 
 
1799
 
                /* back up: nothing else to do */
1800
 
            } while ( --nTopStackAtom >= 0 );
1801
 
        }
1802
 
    }
1803
 
    goto exit_function;
1804
 
 
1805
 
exit_error:
1806
 
    if ( nOutputString ) {
1807
 
        inchi_free( nOutputString );
1808
 
        nOutputString = NULL;
1809
 
    }
1810
 
 
1811
 
exit_function:
1812
 
    if ( nStackAtom )
1813
 
        inchi_free( nStackAtom );
1814
 
    if ( nNumDescendants )
1815
 
        inchi_free( nNumDescendants );
1816
 
    if ( nDfsNumber )
1817
 
        inchi_free( nDfsNumber );
1818
 
    if ( cNeighNumb )
1819
 
        inchi_free( cNeighNumb );
1820
 
    if ( nl )
1821
 
        FreeNeighList( nl );
1822
 
    return nOutputString;
1823
 
}
1824
 
/**********************************************************************************************/
1825
 
int GetInpStructErrorType( INPUT_PARMS *ip, int err, char *pStrErrStruct, int num_inp_atoms )
1826
 
{
1827
 
    if ( err && err == 9 )
1828
 
        return _IS_ERROR; /*  sdfile bypassed to $$$$ */
1829
 
    if ( err && err < 30 )
1830
 
        return _IS_FATAL;
1831
 
    if ( num_inp_atoms <= 0 || err ) {
1832
 
        if ( 98 == err && 0 == num_inp_atoms && ip->bAllowEmptyStructure )
1833
 
            return _IS_WARNING;
1834
 
        return _IS_ERROR;
1835
 
    }
1836
 
    if ( pStrErrStruct[0] )
1837
 
        return _IS_WARNING;
1838
 
    return _IS_OKAY;
1839
 
}
1840
 
/**********************************************************************************************/
1841
 
int ProcessStructError( INCHI_IOSTREAM *output_file, INCHI_IOSTREAM *log_file, /*int err,*/ 
1842
 
                        char *pStrErrStruct, int nErrorType,
1843
 
                        int *bXmlStructStarted, long num_inp, INPUT_PARMS *ip, char *pStr, int nStrLen )
1844
 
{
1845
 
    int b_ok;
1846
 
#ifdef INCHI_LIB
1847
 
    int bPlainText = (ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT) &&
1848
 
                     (ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
1849
 
                    !(ip->bINChIOutputOptions & INCHI_OUT_XML);
1850
 
#else
1851
 
    int bPlainText = 0;
1852
 
#endif
1853
 
    if ( !bPlainText && *bXmlStructStarted <= 0 ) {
1854
 
        return nErrorType;
1855
 
    }
1856
 
    /*  Fatal error, Error, Warning */
1857
 
    if ( nErrorType ) {
1858
 
        if ( bPlainText ) {
1859
 
            if ( !(b_ok=OutputINChIPlainError( output_file, pStr, nStrLen, pStrErrStruct, nErrorType ) ) ) {
1860
 
                inchi_ios_eprint( log_file, "Cannot create message for error (structure #%ld.%s%s%s%s) Terminating.\n",
1861
 
                                                            num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1862
 
            } else {
1863
 
                inchi_ios_print( output_file, "\n" ); /* add a blank line after the WINCHI Window message */
1864
 
            }
1865
 
        } else {
1866
 
            if ( !(b_ok=OutputINChIXmlError( output_file, pStr, nStrLen, 2, /*err,*/ pStrErrStruct, nErrorType ) ) ) {
1867
 
                inchi_ios_eprint( log_file, "Cannot create xml tag for error (structure #%ld.%s%s%s%s) Terminating.\n",
1868
 
                                                            num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1869
 
            }
1870
 
            if ( !b_ok || nErrorType == _IS_FATAL || nErrorType == _IS_ERROR ) {
1871
 
                /*  close current structure output */
1872
 
                if ( !OutputINChIXmlStructEndTag( output_file, pStr, nStrLen, 1 ) ) {
1873
 
                    inchi_ios_eprint( log_file, "Cannot create end xml tag for structure #%ld.%s%s%s%s Terminating.\n", num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1874
 
                    *bXmlStructStarted = -1;
1875
 
                    b_ok = 0;
1876
 
                } else {
1877
 
                    *bXmlStructStarted = 0;
1878
 
                }
1879
 
            }
1880
 
        }
1881
 
        return b_ok? nErrorType : _IS_FATAL;
1882
 
    }
1883
 
    return nErrorType;
1884
 
    
1885
 
}
1886
 
 
1887
 
#if( TEST_RENUMB_ATOMS == 1 ) /*  { */
1888
 
/***************************************************************************************/
1889
 
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 )
1890
 
{
1891
 
    if ( s1 == NULL && s2 == NULL )
1892
 
        return 0;
1893
 
    if ( (s1 == NULL) ^ (s2 == NULL) )
1894
 
        return 20;
1895
 
 
1896
 
    if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
1897
 
        return 21;
1898
 
    if ( s1->nNumberOfStereoCenters > 0 ) {
1899
 
        if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1900
 
            return 22;
1901
 
        if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1902
 
            return 23;
1903
 
        if ( s1->nNumberInv && s2->nNumberInv ) {
1904
 
            if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1905
 
                return 28;
1906
 
            if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1907
 
                return 29;
1908
 
            if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
1909
 
                 s1->bTrivialInv  != s2->bTrivialInv ) {
1910
 
                return 30;
1911
 
            }
1912
 
        } else
1913
 
        if ( s1->nNumberInv || s2->nNumberInv ) {
1914
 
            return 31;
1915
 
        }
1916
 
    }
1917
 
    if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
1918
 
        return 24;
1919
 
    if ( s1->nNumberOfStereoBonds > 0 ) {
1920
 
        if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
1921
 
            return 25;
1922
 
        if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
1923
 
            return 26;
1924
 
        if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
1925
 
            return 27;
1926
 
    }
1927
 
    return 0;
1928
 
}
1929
 
/***************************************************************************************/
1930
 
int CompareINChI( INChI *i1, INChI *i2, INChI_Aux *a1, INChI_Aux *a2 )
1931
 
{
1932
 
    int ret;
1933
 
    if ( i1 == NULL && i2 == NULL )
1934
 
        return 0;
1935
 
    if ( (i1 == NULL) ^ (i2 == NULL) )
1936
 
        return 1;
1937
 
    
1938
 
    if ( i1->nErrorCode == i2->nErrorCode ) {
1939
 
        if ( i1->nErrorCode )
1940
 
            return 0;
1941
 
    } else {
1942
 
        return 2;
1943
 
    }
1944
 
    
1945
 
    if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
1946
 
        return 3;
1947
 
    if ( i1->nNumberOfAtoms > 0 ) {
1948
 
        if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
1949
 
            return 4;
1950
 
        if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) )
1951
 
            return 5;
1952
 
        if ( i1->nNum_H_fixed && i2->nNum_H_fixed && 
1953
 
             memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
1954
 
            return 6;
1955
 
        }
1956
 
        if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
1957
 
            return 7;
1958
 
    }
1959
 
 
1960
 
    if ( i1->lenConnTable != i2->lenConnTable )
1961
 
        return 8;
1962
 
    if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
1963
 
        return 9;
1964
 
 
1965
 
    if ( i1->lenTautomer != i2->lenTautomer )
1966
 
        return 10;
1967
 
    if ( i1->lenTautomer > 0 && memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
1968
 
        return 11;
1969
 
 
1970
 
    if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
1971
 
        return 12;
1972
 
    if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
1973
 
        return 13;
1974
 
 
1975
 
    if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
1976
 
        return 14;
1977
 
    if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
1978
 
        return 15;
1979
 
    if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
1980
 
        return 16;
1981
 
    if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
1982
 
        return 17;
1983
 
    if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
1984
 
        if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
1985
 
             memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
1986
 
                    sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
1987
 
            return 18;
1988
 
    } else
1989
 
    if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
1990
 
        return 19;
1991
 
    }
1992
 
    /* ret = 20..31 */
1993
 
    if ( ret = CompareStereoINChI( i1->Stereo, i2->Stereo ) )
1994
 
        return ret;
1995
 
    /* ret = 40..51 */
1996
 
    if ( ret = CompareStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) )
1997
 
        return ret+20;
1998
 
 
1999
 
    return 0;
2000
 
}
2001
 
#endif /*  } TEST_RENUMB_ATOMS == 1 */
2002
 
#if( READ_INCHI_STRING == 1 ) /*  { */
2003
 
/*************************************************************************************/
2004
 
int CompareReversedStereoINChI( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */)
2005
 
{
2006
 
    if ( s1 == NULL && s2 == NULL )
2007
 
        return 0;
2008
 
    if ( (s1 == NULL) ^ (s2 == NULL) ) {
2009
 
        INChI_Stereo *s = s1? s1 : s2;
2010
 
        if ( s->nNumberOfStereoCenters || s->nNumberOfStereoBonds ) {
2011
 
            return 20; /* Diff: Missing Stereo */
2012
 
        } else {
2013
 
            return 0;
2014
 
        }
2015
 
    }
2016
 
 
2017
 
    if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
2018
 
        return 21;      /* Diff: Number of sp3 stereocenters */
2019
 
    if ( s1->nNumberOfStereoCenters > 0 ) {
2020
 
        if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
2021
 
            return 22;  /* Diff: sp3 stereocenter locations */
2022
 
        if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
2023
 
            return 23;  /* Diff: sp3 stereocenter parities */
2024
 
        if ( s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs )
2025
 
            return 24;  /* Diff: sp3 inversion */
2026
 
        /*
2027
 
        if ( s1->nNumberInv && s2->nNumberInv ) {
2028
 
            if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
2029
 
                return 25;
2030
 
            if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
2031
 
                return 26;
2032
 
            if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
2033
 
                 s1->bTrivialInv  != s2->bTrivialInv ) {
2034
 
                return 27;
2035
 
            }
2036
 
        } else
2037
 
        if ( s1->nNumberInv || s2->nNumberInv ) {
2038
 
            return 28;
2039
 
        }
2040
 
        */
2041
 
    }
2042
 
    if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
2043
 
        return 25;      /* Diff: Number of stereobonds */
2044
 
    if ( s1->nNumberOfStereoBonds > 0 ) {
2045
 
        if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
2046
 
            return 26; /* Diff: Stereobond 1st atom locations */
2047
 
        if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
2048
 
            return 27; /* Diff: Stereobond 2nd atom locations */
2049
 
        if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
2050
 
            return 28; /* Diff: Stereobond parities */
2051
 
    }
2052
 
    return 0;
2053
 
}
2054
 
/*************************************************************************************/
2055
 
int CompareReversedStereoINChI2( INChI_Stereo *s1/* InChI from reversed struct */, INChI_Stereo *s2 /* input InChI */, ICR *picr)
2056
 
{
2057
 
    int ret = 0;
2058
 
    int j1, j2, num_eq, num_dif, num_extra_undf, num_miss_undf, num_in1_only, num_in2_only;
2059
 
    int bAddSb = !(picr->num_sb_undef_in1_only + picr->num_sb_in1_only + picr->num_sb_in2_only);
2060
 
    int bAddSc = !(picr->num_sc_undef_in1_only + picr->num_sc_in1_only + picr->num_sc_in2_only);
2061
 
    
2062
 
    int nNumSc1 = s1? s1->nNumberOfStereoCenters : 0;
2063
 
    int nNumSc2 = s2? s2->nNumberOfStereoCenters : 0;
2064
 
    int nNumSb1 = s1? s1->nNumberOfStereoBonds   : 0;
2065
 
    int nNumSb2 = s2? s2->nNumberOfStereoBonds   : 0;
2066
 
    
2067
 
    if ( (nNumSc1 || nNumSc1) &&
2068
 
         ( nNumSc1 != nNumSc2 ||
2069
 
           memcmp( s1->nNumber,  s2->nNumber,  nNumSc1*sizeof(s1->nNumber[0] ) ) ||
2070
 
           memcmp( s1->t_parity, s2->t_parity, nNumSc1*sizeof(s1->t_parity[0]) ) ) ) {
2071
 
 
2072
 
        num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
2073
 
        for ( j1 = j2 = 0; j1 < nNumSc1 && j2 < nNumSc2; ) {
2074
 
            if ( s1->nNumber[j1] ==  s2->nNumber[j2] ) {
2075
 
                if ( s1->t_parity[j1] == s2->t_parity[j2] ) {
2076
 
                    num_eq ++;
2077
 
                } else {
2078
 
                    num_dif ++;
2079
 
                }
2080
 
                j1 ++;
2081
 
                j2 ++;
2082
 
            } else
2083
 
            if ( s1->nNumber[j1] < s2->nNumber[j2] ) {
2084
 
                num_in1_only ++;
2085
 
                if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2086
 
                    num_extra_undf ++;
2087
 
                }
2088
 
                if ( bAddSc ) {
2089
 
                    if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
2090
 
                        picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
2091
 
                    if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2092
 
                        if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
2093
 
                            picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
2094
 
                    }
2095
 
                }
2096
 
                j1 ++;
2097
 
            } else {
2098
 
                num_in2_only ++;
2099
 
                if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2100
 
                    num_miss_undf ++;
2101
 
                }
2102
 
                if ( bAddSc ) {
2103
 
                    if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
2104
 
                        picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
2105
 
                    if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2106
 
                        if ( picr->num_sc_undef_in2_only < ICR_MAX_SC_UNDF )
2107
 
                            picr->sc_undef_in2_only[picr->num_sc_undef_in2_only ++] = j1;
2108
 
                    }
2109
 
                }
2110
 
                j2 ++;
2111
 
            }
2112
 
        }
2113
 
        while ( j1 < nNumSc1 ) {
2114
 
            if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2115
 
                num_extra_undf ++;
2116
 
            }
2117
 
            num_in1_only ++;
2118
 
            if ( bAddSc ) {
2119
 
                if ( picr->num_sc_in1_only < ICR_MAX_SC_IN1_ONLY )
2120
 
                    picr->sc_in1_only[picr->num_sc_in1_only ++] = j1;
2121
 
                if ( s1->t_parity[j1] == AB_PARITY_UNDF ) {
2122
 
                    if ( picr->num_sc_undef_in1_only < ICR_MAX_SC_UNDF )
2123
 
                        picr->sc_undef_in1_only[picr->num_sc_undef_in1_only ++] = j1;
2124
 
                }
2125
 
            }
2126
 
            j1 ++;
2127
 
        }
2128
 
        while ( j2 < nNumSc2 ) {
2129
 
            if ( s2->t_parity[j2] == AB_PARITY_UNDF ) {
2130
 
                num_miss_undf ++;
2131
 
            }
2132
 
            num_in2_only ++;
2133
 
            if ( bAddSc ) {
2134
 
                if ( picr->num_sc_in2_only < ICR_MAX_SC_IN2_ONLY )
2135
 
                    picr->sc_in2_only[picr->num_sc_in2_only ++] = j2;
2136
 
            }
2137
 
            j2 ++;
2138
 
        }
2139
 
        if ( num_dif ) {
2140
 
            ret |= IDIF_SC_PARITY; 
2141
 
        }
2142
 
        if ( num_in1_only ) {
2143
 
            if ( num_extra_undf ) {
2144
 
                ret |= IDIF_SC_EXTRA_UNDF;
2145
 
            }
2146
 
            if ( num_in1_only != num_extra_undf ) {
2147
 
                ret |= IDIF_SC_EXTRA;
2148
 
            }
2149
 
        }
2150
 
        if ( num_in2_only ) {
2151
 
            if ( num_miss_undf ) {
2152
 
                ret |= IDIF_SC_MISS_UNDF;
2153
 
            }
2154
 
            if ( num_in2_only != num_miss_undf ) {
2155
 
                ret |= IDIF_SC_MISS;
2156
 
            }
2157
 
        }
2158
 
    }
2159
 
    if ( s1 && s2 && s1->nCompInv2Abs != s2->nCompInv2Abs && s1->nCompInv2Abs && s2->nCompInv2Abs ) {
2160
 
        ret |= IDIF_SC_INV;
2161
 
    }
2162
 
 
2163
 
    if ( (nNumSb1 || nNumSb2 ) &&
2164
 
         (nNumSb1 != nNumSb2 ||
2165
 
          memcmp( s1->nBondAtom1, s2->nBondAtom1, nNumSb1*sizeof(s1->nBondAtom1[0]) ) ||
2166
 
          memcmp( s1->nBondAtom2, s2->nBondAtom2, nNumSb1*sizeof(s1->nBondAtom2[0]) ) ||
2167
 
          memcmp( s1->b_parity,   s2->b_parity,   nNumSb1*sizeof(s1->b_parity[0]) ) ) ) {
2168
 
 
2169
 
        num_eq = num_dif = num_extra_undf = num_miss_undf = num_in1_only = num_in2_only = 0;
2170
 
        for ( j1 = j2 = 0; j1 < nNumSb1 && j2 < nNumSb2; ) {
2171
 
            if ( s1->nBondAtom1[j1] ==  s2->nBondAtom1[j2] &&
2172
 
                 s1->nBondAtom2[j1] ==  s2->nBondAtom2[j2] ) {
2173
 
                if ( s1->b_parity[j1] == s2->b_parity[j2] ) {
2174
 
                    num_eq ++;
2175
 
                } else {
2176
 
                    num_dif ++;
2177
 
                }
2178
 
                j1 ++;
2179
 
                j2 ++;
2180
 
            } else
2181
 
            if ( s1->nBondAtom1[j1] <  s2->nBondAtom1[j2] ||
2182
 
                 s1->nBondAtom1[j1] == s2->nBondAtom1[j2] && s1->nBondAtom2[j1] <  s2->nBondAtom2[j2]) {
2183
 
                num_in1_only ++;
2184
 
                if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2185
 
                    num_extra_undf ++;
2186
 
                }
2187
 
                if ( bAddSb ) {
2188
 
                    if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
2189
 
                        picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
2190
 
                    if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2191
 
                        if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
2192
 
                            picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
2193
 
                    }
2194
 
                }
2195
 
                j1 ++;
2196
 
            } else {
2197
 
                num_in2_only ++;
2198
 
                if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2199
 
                    num_miss_undf ++;
2200
 
                }
2201
 
                if ( bAddSb ) {
2202
 
                    if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
2203
 
                        picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
2204
 
                    if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2205
 
                        if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
2206
 
                            picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
2207
 
                    }
2208
 
                }
2209
 
                j2 ++;
2210
 
            }
2211
 
        }
2212
 
        while ( j1 < nNumSb1 ) {
2213
 
            num_in1_only ++;
2214
 
            if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2215
 
                num_extra_undf ++;
2216
 
            }
2217
 
            if ( bAddSb ) {
2218
 
                if ( picr->num_sb_in1_only < ICR_MAX_SB_IN1_ONLY )
2219
 
                    picr->sb_in1_only[picr->num_sb_in1_only ++] = j1;
2220
 
                if ( s1->b_parity[j1] == AB_PARITY_UNDF ) {
2221
 
                    if ( picr->num_sb_undef_in1_only < ICR_MAX_SB_UNDF )
2222
 
                        picr->sb_undef_in1_only[picr->num_sb_undef_in1_only ++] = j1;
2223
 
                }
2224
 
            }
2225
 
            j1 ++;
2226
 
        }
2227
 
        while ( j2 < nNumSb2 ) {
2228
 
            num_in2_only ++;
2229
 
            if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2230
 
                num_miss_undf ++;
2231
 
            }
2232
 
            if ( bAddSb ) {
2233
 
                if ( picr->num_sb_in2_only < ICR_MAX_SB_IN2_ONLY )
2234
 
                    picr->sb_in2_only[picr->num_sb_in2_only ++] = j2;
2235
 
                if ( s2->b_parity[j2] == AB_PARITY_UNDF ) {
2236
 
                    if ( picr->num_sb_undef_in2_only < ICR_MAX_SB_UNDF )
2237
 
                        picr->sb_undef_in2_only[picr->num_sb_undef_in2_only ++] = j1;
2238
 
                }
2239
 
            }
2240
 
            j2 ++;
2241
 
        }
2242
 
        if ( num_dif ) {
2243
 
            ret |= IDIF_SB_PARITY; 
2244
 
        }
2245
 
        if ( num_in1_only ) {
2246
 
            if ( num_extra_undf ) {
2247
 
                ret |= IDIF_SB_EXTRA_UNDF;
2248
 
            }
2249
 
            if ( num_in1_only != num_extra_undf ) {
2250
 
                ret |= IDIF_SB_EXTRA;
2251
 
            }
2252
 
        }
2253
 
        if ( num_in2_only ) {
2254
 
            if ( num_miss_undf ) {
2255
 
                ret |= IDIF_SB_MISS_UNDF;
2256
 
            }
2257
 
            if ( num_in2_only != num_miss_undf ) {
2258
 
                ret |= IDIF_SB_MISS;
2259
 
            }
2260
 
        }
2261
 
    }
2262
 
 
2263
 
    return ret;
2264
 
}
2265
 
/*************************************************************************************/
2266
 
int CompareReversedINChI( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */, INChI_Aux *a1, INChI_Aux *a2 )
2267
 
{
2268
 
    int ret;
2269
 
    if ( i1 == NULL && i2 == NULL )
2270
 
        return 0;
2271
 
    if ( (i1 == NULL) ^ (i2 == NULL) )
2272
 
        return 1; /* Diff: Missing InChI */
2273
 
    
2274
 
    if ( i1->nErrorCode == i2->nErrorCode ) {
2275
 
        if ( i1->nErrorCode )
2276
 
            return 0;
2277
 
    } else {
2278
 
        return 2; /* Diff: Error codes */
2279
 
    }
2280
 
    if ( i1->bDeleted != i2->bDeleted ) {
2281
 
        return 1; /* Diff: Missing InChI */
2282
 
    }
2283
 
    if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
2284
 
        return 3;  /* Diff: Num. atoms */
2285
 
    if ( i1->nNumberOfAtoms > 0 ) {
2286
 
        if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
2287
 
            return 4; /* Diff: Elements */
2288
 
        if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
2289
 
            return 7; /* Diff: Hill Formulas */
2290
 
        if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
2291
 
            if ( i1->lenConnTable > 1 || i2->lenConnTable > 1 ) {
2292
 
                return 5; /* Diff: H Locations (mobile H present) */
2293
 
            } else {
2294
 
                return 6; /* Diff: H Locations (no mobile H) */
2295
 
            }
2296
 
        }
2297
 
        /* fixed H */
2298
 
        if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
2299
 
            int bHasFixedH1 = 0, bHasFixedH2 = 0, i, j1, j2;
2300
 
            if ( i1->nNum_H_fixed ) {
2301
 
                for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2302
 
                    if ( i1->nNum_H_fixed[i] ) {
2303
 
                        bHasFixedH1 ++;
2304
 
                    }
2305
 
                }
2306
 
            }
2307
 
            if ( i2->nNum_H_fixed ) {
2308
 
                for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
2309
 
                    if ( i2->nNum_H_fixed[i] ) {
2310
 
                        bHasFixedH2 ++;
2311
 
                    }
2312
 
                }
2313
 
            }
2314
 
            /* count the differences */
2315
 
            j1 = j2 = 0;
2316
 
            if ( bHasFixedH1 && !bHasFixedH2 ) {
2317
 
                for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2318
 
                    if ( i1->nNum_H_fixed[i] > 0 ) {
2319
 
                        j1 ++;
2320
 
                    } else
2321
 
                    if ( i1->nNum_H_fixed[i] < 0 ) {
2322
 
                        j2 ++;
2323
 
                    }
2324
 
                }
2325
 
 
2326
 
                return 18; /* Diff: Extra Fixed-H */
2327
 
            } else
2328
 
            if ( !bHasFixedH1 && bHasFixedH2 ) {
2329
 
                for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2330
 
                    if ( 0 > i2->nNum_H_fixed[i] ) {
2331
 
                        j1 ++;
2332
 
                    } else
2333
 
                    if ( 0 < i2->nNum_H_fixed[i] ) {
2334
 
                        j2 ++;
2335
 
                    }
2336
 
                }
2337
 
                return 19; /* Diff: Missed Fixed-H */
2338
 
            } else
2339
 
            if ( bHasFixedH1 && bHasFixedH2 &&
2340
 
                 memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
2341
 
                for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2342
 
                    if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
2343
 
                        j1 ++;
2344
 
                    } else
2345
 
                    if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
2346
 
                        j2 ++;
2347
 
                    }
2348
 
                }
2349
 
            }
2350
 
            ret = (j1 && j2)? 20 : j1? 18 : j2? 19 : 0;
2351
 
            if ( ret ) {
2352
 
                return ret; /* 20 => Diff: NotEql Fixed-H */
2353
 
                            /* 19 => Diff: Missed Fixed-H (i1 has less) */
2354
 
                            /* 18 => Diff: Extra Fixed-H  (i1 has more) */
2355
 
            }
2356
 
        }
2357
 
    }
2358
 
 
2359
 
    if ( i1->lenConnTable != i2->lenConnTable )
2360
 
        return 8; /* Diff: Connections length */
2361
 
    if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
2362
 
        return 9; /* Diff: Connections */
2363
 
    /* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2364
 
    if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) )
2365
 
        return 10; /* Diff: Mobile groups length */ /* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2366
 
    if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2367
 
         memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
2368
 
        return 11; /* Diff: Mobile groups */
2369
 
 
2370
 
    if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
2371
 
        return 12; /* Diff: Isotopic atoms number */
2372
 
    if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2373
 
        return 13; /* Diff: Isotopic atoms */
2374
 
    if ( i1->nTotalCharge != i2->nTotalCharge )
2375
 
        return 14; /* Diff: Charge */
2376
 
/*
2377
 
    if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
2378
 
        return 14;
2379
 
    if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
2380
 
        return 15;
2381
 
*/
2382
 
    if ( a1 && a2 ) {
2383
 
        if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
2384
 
            return 16; /* Diff: Number of removed protons */
2385
 
        if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
2386
 
            return 17; /* Diff: Removed isotopic H */
2387
 
    }
2388
 
/*
2389
 
    if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2390
 
        if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2391
 
             memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2392
 
                    sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2393
 
            return 18;
2394
 
    } else
2395
 
    if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2396
 
        return 19;
2397
 
    }
2398
 
*/
2399
 
    /* ret = 20..31 => 40..51 */
2400
 
    if ( ret = CompareReversedStereoINChI( i1->Stereo, i2->Stereo ) )
2401
 
        return ret+20;
2402
 
    /* ret = 40..51 => 60..71 */
2403
 
 
2404
 
    if ( !i2->StereoIsotopic && i2->Stereo && i1->StereoIsotopic &&
2405
 
         0 < (i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters) &&
2406
 
         0 == CompareReversedStereoINChI( i1->StereoIsotopic, i2->Stereo ) ) {
2407
 
        /* InChI from reversed structure does not contain fully duplicated isotopic stereo */
2408
 
        ;
2409
 
    } else
2410
 
 
2411
 
    if ( ret = CompareReversedStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) ) {
2412
 
        return ret+40;
2413
 
    }
2414
 
 
2415
 
    return 0;
2416
 
}
2417
 
 
2418
 
/*******************************************************************************/
2419
 
int CompareIcr( ICR *picr1, ICR *picr2, INCHI_MODE *pin1, INCHI_MODE *pin2, INCHI_MODE mask )
2420
 
{
2421
 
    int nNumExtraBits1 = 0, nNumExtraBits2 = 0, bit1, bit2;
2422
 
    INCHI_MODE Flg1=picr1->flags, Flg2 = picr2->flags, cur_bit = 1, in1, in2;
2423
 
    int i, ret;
2424
 
 
2425
 
    /* compare flags */
2426
 
    in1 = in2 = 0;
2427
 
    for ( i = 0; Flg1 || Flg2; i ++, Flg1 >>= 1, Flg2 >>= 1, cur_bit <<= 1 ) {
2428
 
        if ( !(mask & cur_bit) ) {
2429
 
            continue;
2430
 
        }
2431
 
        bit1 = Flg1 & 1;
2432
 
        bit2 = Flg2 & 1;
2433
 
        if ( bit1 && !bit2 ) {
2434
 
            in1 |= 1 << i;
2435
 
            nNumExtraBits1 ++;
2436
 
        } else
2437
 
        if ( !bit1 && bit2 ) {
2438
 
            in2 |= 1 << i;
2439
 
            nNumExtraBits2 ++;
2440
 
        }
2441
 
    }
2442
 
    if ( nNumExtraBits1 && !nNumExtraBits2 ) {
2443
 
        ret = 1;
2444
 
    } else
2445
 
    if ( !nNumExtraBits1 && nNumExtraBits2 ) {
2446
 
        ret = -1;
2447
 
    } else
2448
 
    if ( !in1 && !in2 ) {
2449
 
        ret = 0;
2450
 
    } else {
2451
 
        ret = 2; /* compare produced undefined results */
2452
 
    }
2453
 
    if ( pin1 ) *pin1 = in1;
2454
 
    if ( pin2 ) *pin2 = in2;
2455
 
    /* more detailed compare not implemented */
2456
 
    return ret;
2457
 
}
2458
 
 
2459
 
/*********************************************************************************************************/
2460
 
INCHI_MODE CompareReversedINChI2( INChI *i1 /* InChI from reversed struct */, INChI *i2 /* input InChI */,
2461
 
                                  INChI_Aux *a1, INChI_Aux *a2, ICR *picr, int *err )
2462
 
{
2463
 
    INCHI_MODE ret = 0;
2464
 
    INChI_Stereo *Stereo1=NULL, *Stereo2=NULL;
2465
 
    int  n1, n2, m, j, j1, j2, ret2, num_H1, num_H2;
2466
 
    
2467
 
    *err = 0;
2468
 
 
2469
 
    memset( picr, 0, sizeof(*picr) );
2470
 
 
2471
 
    if ( i1 == NULL && i2 == NULL )
2472
 
        return 0;
2473
 
    if ( (i1 == NULL) ^ (i2 == NULL) ) {
2474
 
        ret |= IDIF_PROBLEM; /* one InChI exists while another doesn't */
2475
 
        goto exit_function;
2476
 
    }
2477
 
    
2478
 
    if ( i1->nErrorCode == i2->nErrorCode ) {
2479
 
        if ( i1->nErrorCode ) {
2480
 
            ret |= IDIF_PROBLEM; /* both InChI have same error codes */
2481
 
            goto exit_function;
2482
 
        }
2483
 
    } else {
2484
 
        ret |= IDIF_PROBLEM; /* at least one InChI has an error code */
2485
 
        goto exit_function;
2486
 
    }
2487
 
    
2488
 
    if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms ) {
2489
 
        ret |= IDIF_NUM_AT;
2490
 
        goto exit_function;
2491
 
    }
2492
 
    if ( i1->nNumberOfAtoms > 0 ) {
2493
 
        if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) ) {
2494
 
            ret |= IDIF_ATOMS;
2495
 
            goto exit_function;
2496
 
        }
2497
 
        /* IDIF_NON_TAUT_H,  IDIF_MORE_FH, IDIF_LESS_FH */
2498
 
        if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) ) {
2499
 
            ret |= IDIF_POSITION_H;
2500
 
            for ( j1 = 0; j1 < i1->nNumberOfAtoms; j1 ++ ) {
2501
 
                if ( i1->nNum_H[j1] != i2->nNum_H[j1] && picr->num_diff_pos_H < ICR_MAX_DIFF_FIXED_H ) {
2502
 
                    picr->diff_pos_H_at[picr->num_diff_pos_H] = j1;
2503
 
                    picr->diff_pos_H_nH[picr->num_diff_pos_H] = i1->nNum_H[j1] - i2->nNum_H[j1];
2504
 
                    picr->num_diff_pos_H ++;
2505
 
                }
2506
 
            }
2507
 
        }
2508
 
        /* fixed H */
2509
 
        if ( i1->nNum_H_fixed || i2->nNum_H_fixed ) {
2510
 
            int bHasFixedH1 = 0, bHasFixedH2 = 0, i;
2511
 
            if ( i1->nNum_H_fixed ) {
2512
 
                for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
2513
 
                    if ( i1->nNum_H_fixed[i] ) {
2514
 
                        bHasFixedH1 ++;
2515
 
                    }
2516
 
                }
2517
 
            }
2518
 
            if ( i2->nNum_H_fixed ) {
2519
 
                for ( i = 0; i < i2->nNumberOfAtoms; i ++ ) {
2520
 
                    if ( i2->nNum_H_fixed[i] ) {
2521
 
                        bHasFixedH2 ++;
2522
 
                    }
2523
 
                }
2524
 
            }
2525
 
            if ( bHasFixedH1 && !bHasFixedH2 ) {
2526
 
                for ( i = j = 0; i < i1->nNumberOfAtoms; i ++ ) {
2527
 
                    if ( i1->nNum_H_fixed[i] ) {
2528
 
                        if ( j < ICR_MAX_DIFF_FIXED_H ) {
2529
 
                            picr->fixed_H_at1_more[j] = i;
2530
 
                            picr->fixed_H_nH1_more[j] = i1->nNum_H_fixed[i];
2531
 
                            j ++;
2532
 
                        }
2533
 
                    }
2534
 
                }
2535
 
                picr->num_fixed_H1_more = j;
2536
 
                ret |= IDIF_MORE_FH; /* Extra Fixed-H */
2537
 
            } else
2538
 
            if ( !bHasFixedH1 && bHasFixedH2 ) {
2539
 
                for ( i = j = 0; i < i2->nNumberOfAtoms; i ++ ) {
2540
 
                    if ( i2->nNum_H_fixed[i] ) {
2541
 
                        if ( j < ICR_MAX_DIFF_FIXED_H ) {
2542
 
                            picr->fixed_H_at2_more[j] = i;
2543
 
                            picr->fixed_H_nH2_more[j] = i2->nNum_H_fixed[i];
2544
 
                            j ++;
2545
 
                        }
2546
 
                    }
2547
 
                }
2548
 
                picr->num_fixed_H2_more = j;
2549
 
                ret |= IDIF_LESS_FH; /* Missed Fixed-H */
2550
 
            } else
2551
 
            if ( bHasFixedH1 && bHasFixedH2 &&
2552
 
                 memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
2553
 
                for ( i = j1 = j2 = 0; i < i1->nNumberOfAtoms; i ++ ) {
2554
 
                    if ( i1->nNum_H_fixed[i] > i2->nNum_H_fixed[i] ) {
2555
 
                        if ( j1 < ICR_MAX_DIFF_FIXED_H ) {
2556
 
                            picr->fixed_H_at1_more[j1] = i;
2557
 
                            picr->fixed_H_nH1_more[j1] = i1->nNum_H_fixed[i] - i2->nNum_H_fixed[i];
2558
 
                            j1 ++;
2559
 
                        }
2560
 
                    } else
2561
 
                    if ( i1->nNum_H_fixed[i] < i2->nNum_H_fixed[i] ) {
2562
 
                        if ( j2 < ICR_MAX_DIFF_FIXED_H ) {
2563
 
                            picr->fixed_H_at2_more[j2] = i;
2564
 
                            picr->fixed_H_nH2_more[j2] = i2->nNum_H_fixed[i] - i1->nNum_H_fixed[i];
2565
 
                            j2 ++;
2566
 
                        }
2567
 
                    }
2568
 
                }
2569
 
                ret |= (j1? IDIF_MORE_FH:0) | (j2? IDIF_LESS_FH:0);
2570
 
                picr->num_fixed_H1_more = j1;
2571
 
                picr->num_fixed_H2_more = j2;
2572
 
            }
2573
 
        }
2574
 
    }
2575
 
    /* compare formulas and H */
2576
 
    num_H1 = 0;
2577
 
    num_H2 = 0;
2578
 
    ret2 = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 );
2579
 
    picr->tot_num_H1 = num_H1;
2580
 
    picr->tot_num_H2 = num_H2;
2581
 
    if ( ret2 ) {
2582
 
        ret |= IDIF_NUM_EL;
2583
 
        goto exit_function;
2584
 
    }
2585
 
    if ( num_H1 > num_H2 ) {
2586
 
        ret |= IDIF_MORE_H;
2587
 
    }
2588
 
    if ( num_H1 < num_H2 ) {
2589
 
        ret |= IDIF_LESS_H;
2590
 
    }
2591
 
 
2592
 
    if ( i1->lenConnTable != i2->lenConnTable ) {
2593
 
        ret |= IDIF_CON_LEN;
2594
 
        goto exit_function;
2595
 
    } else
2596
 
    if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) ) {
2597
 
        ret |= IDIF_CON_TBL;
2598
 
        goto exit_function;
2599
 
    }
2600
 
    /* output special cases: different number of t-groups, different sizes of t-groups, different endpoints */
2601
 
    /* in isotopic or deprotonated cases i1->lenTautomer == 1 && i1->nTautomer[0] = 0 */
2602
 
/*
2603
 
    if ( i1->lenTautomer != i2->lenTautomer && (i1->lenTautomer > 1 || i2->lenTautomer > 1) ) {
2604
 
        ret |=  IDIF_TAUT_LEN; 
2605
 
    }
2606
 
*/
2607
 
    /* compare number of t-groups */
2608
 
    n1 = i1->lenTautomer? i1->nTautomer[0] : 0;
2609
 
    n2 = i2->lenTautomer? i2->nTautomer[0] : 0;
2610
 
    if ( !n1 && n2 ) {
2611
 
        ret |= IDIF_NO_TAUT;
2612
 
    } else
2613
 
    if ( n1 && !n2 ) {
2614
 
        ret |= IDIF_WRONG_TAUT;
2615
 
    } else
2616
 
    if ( n1 == 1 && n2 > 1 ) {
2617
 
        ret |= IDIF_SINGLE_TG;
2618
 
    } else
2619
 
    if ( n1 > 1 && n2 == 1 ) {
2620
 
        ret |= IDIF_MULTIPLE_TG;
2621
 
    } else
2622
 
    if ( n1 != n2 ) {
2623
 
        ret |= IDIF_NUM_TG;
2624
 
    }
2625
 
    if ( n1 || n2 ) {
2626
 
        /* number of endpoints */
2627
 
        int num1 = 0, num2 = 0, num_M1=0, num_M2=0;
2628
 
        int len, num_eq, num_in1_only, num_in2_only;
2629
 
        AT_NUMB *pe1 = (AT_NUMB *)inchi_malloc( (i1->lenTautomer+1) * sizeof(pe1[0]) );
2630
 
        AT_NUMB *pe2 = (AT_NUMB *)inchi_malloc( (i2->lenTautomer+1) * sizeof(pe2[0]) );
2631
 
        num_H1 = num_H2=0;
2632
 
        /* collect endpoints, H, (-) */
2633
 
        if ( !pe1 || !pe2 ) {
2634
 
            if ( pe1 ) inchi_free( pe1 );
2635
 
            if ( pe2 ) inchi_free( pe2 );
2636
 
            *err = -1; /* allocation error */
2637
 
            goto exit_function;
2638
 
        }
2639
 
        for ( m = 1; m < i1->lenTautomer; m += len ) {
2640
 
            len = i1->nTautomer[m ++];
2641
 
            num_H1 += i1->nTautomer[m];
2642
 
            num_M1 += i1->nTautomer[m+1];
2643
 
            for ( j = 2; j < len; j ++ ) {
2644
 
                pe1[num1 ++] = i1->nTautomer[m + j];
2645
 
            }
2646
 
        }
2647
 
        for ( m = 1; m < i2->lenTautomer; m += len ) {
2648
 
            len = i2->nTautomer[m ++];
2649
 
            num_H2 += i2->nTautomer[m];
2650
 
            num_M2 += i2->nTautomer[m+1];
2651
 
            for ( j = 2; j < len; j ++ ) {
2652
 
                pe2[num2 ++] = i2->nTautomer[m + j];
2653
 
            }
2654
 
        }
2655
 
        picr->num_taut_H1 = num_H1;
2656
 
        picr->num_taut_H2 = num_H2;
2657
 
        picr->num_taut_M1 = num_M1;
2658
 
        picr->num_taut_M2 = num_M2;
2659
 
        /* sort endpoints */
2660
 
        insertions_sort_AT_RANK( pe1, num1 );
2661
 
        insertions_sort_AT_RANK( pe2, num2 );
2662
 
        /* compare */
2663
 
        /*
2664
 
        if ( num1 < num2 ) {
2665
 
            ret |= IDIF_LESS_TG_ENDP;
2666
 
        } else
2667
 
        if ( num1 > num2 ) {
2668
 
            ret |= IDIF_MORE_TG_ENDP;
2669
 
        }
2670
 
        */
2671
 
        /* compare all */
2672
 
        num_eq = num_in1_only = num_in2_only = 0;
2673
 
        for ( j1 = j2 = 0; j1 < num1 && j2 < num2; ) {
2674
 
            if( pe1[j1] == pe2[j2] ) {
2675
 
                j1 ++;
2676
 
                j2 ++;
2677
 
                num_eq ++;
2678
 
            } else
2679
 
            if ( pe1[j1] < pe2[j2] ) { /* BC: fixed, was pe2[j1] 2006-03-27 */
2680
 
                if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2681
 
                    picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2682
 
                }
2683
 
                j1 ++;
2684
 
                num_in1_only ++;
2685
 
            } else {
2686
 
                if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2687
 
                    picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2688
 
                }
2689
 
                j2 ++;
2690
 
                num_in2_only ++;
2691
 
            }
2692
 
        }
2693
 
        while ( j1 < num1 ) {
2694
 
            if ( picr->num_endp_in1_only < ICR_MAX_ENDP_IN1_ONLY ) {
2695
 
                picr->endp_in1_only[picr->num_endp_in1_only ++] = pe1[j1];
2696
 
            }
2697
 
            j1 ++;
2698
 
            num_in1_only ++;
2699
 
        }
2700
 
        while ( j2 < num2 ) {
2701
 
            if ( picr->num_endp_in2_only < ICR_MAX_ENDP_IN2_ONLY ) {
2702
 
                picr->endp_in2_only[picr->num_endp_in2_only ++] = pe2[j2];
2703
 
            }
2704
 
            j2 ++;
2705
 
            num_in2_only ++;
2706
 
        }
2707
 
        if ( num_in1_only ) {
2708
 
            ret |= IDIF_EXTRA_TG_ENDP;
2709
 
        }
2710
 
        if ( num_in2_only ) {
2711
 
            ret |= IDIF_MISS_TG_ENDP;
2712
 
        }
2713
 
        if ( !num_in1_only && !num_in2_only && num_eq ) {
2714
 
           ; /* same t-groups endpoints */
2715
 
        } else {
2716
 
           ret |= IDIF_DIFF_TG_ENDP;
2717
 
        }
2718
 
        inchi_free( pe1 );
2719
 
        inchi_free( pe2 );
2720
 
 
2721
 
    }
2722
 
 
2723
 
    if ( (i1->lenTautomer > 1 && i2->lenTautomer > 1) &&
2724
 
         ( i1->lenTautomer != i2->lenTautomer ||
2725
 
         memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) ) )
2726
 
        ret |= IDIF_TG;
2727
 
 
2728
 
    if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms ) {
2729
 
        ret |= IDIF_NUM_ISO_AT;
2730
 
    } else
2731
 
    if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
2732
 
        ret |= IDIF_ISO_AT;
2733
 
    if ( i1->nTotalCharge != i2->nTotalCharge )
2734
 
        ret |= IDIF_CHARGE;
2735
 
    if ( a1 && a1->nNumRemovedProtons && (!a2 || a2->nNumRemovedProtons != a1->nNumRemovedProtons) ) {
2736
 
        ret |= IDIF_REM_PROT;
2737
 
    }
2738
 
    if ( a1 && (!a2 || 
2739
 
         a2->nNumRemovedIsotopicH[0] != a1->nNumRemovedIsotopicH[0] ||
2740
 
         a2->nNumRemovedIsotopicH[1] != a1->nNumRemovedIsotopicH[1] ||
2741
 
         a2->nNumRemovedIsotopicH[2] != a1->nNumRemovedIsotopicH[2]) ) {
2742
 
        ret |= IDIF_REM_ISO_H;
2743
 
    }
2744
 
 
2745
 
/*
2746
 
    if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
2747
 
        if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
2748
 
             memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
2749
 
                    sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
2750
 
            return 18;
2751
 
    } else
2752
 
    if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
2753
 
        return 19;
2754
 
    }
2755
 
*/
2756
 
    if ( i1->StereoIsotopic &&
2757
 
         i1->StereoIsotopic->nNumberOfStereoBonds + i1->StereoIsotopic->nNumberOfStereoCenters ) {
2758
 
        Stereo1 = i1->StereoIsotopic;
2759
 
    } else {
2760
 
        Stereo1 = i1->Stereo;
2761
 
    }
2762
 
    if ( i2->StereoIsotopic &&
2763
 
         i2->StereoIsotopic->nNumberOfStereoBonds + i2->StereoIsotopic->nNumberOfStereoCenters ) {
2764
 
        Stereo2 = i2->StereoIsotopic;
2765
 
    } else {
2766
 
        Stereo2 = i2->Stereo;
2767
 
    }
2768
 
    ret |= CompareReversedStereoINChI2( Stereo1, Stereo2, picr );
2769
 
 
2770
 
exit_function:
2771
 
 
2772
 
    picr->flags = ret;
2773
 
 
2774
 
    return ret;
2775
 
}
2776
 
#endif  /* } READ_INCHI_STRING */
2777
 
/***************************************************************************************/
2778
 
int  Create_INChI( INChI **ppINChI, INChI_Aux **ppINChI_Aux, ORIG_ATOM_DATA *orig_inp_data, /* not used */
2779
 
                  inp_ATOM *inp_at, INP_ATOM_DATA *out_norm_data[2],
2780
 
                  int num_inp_at, INCHI_MODE nUserMode,
2781
 
                  INCHI_MODE *pbTautFlags, INCHI_MODE *pbTautFlagsDone,
2782
 
                  struct tagInchiTime *ulMaxTime, T_GROUP_INFO *ti_out, char *pStrErrStruct)
2783
 
{
2784
 
/*
2785
 
#define NON_TAUT 0
2786
 
#define TAUT     1    
2787
 
*/
2788
 
    sp_ATOM  *at[TAUT_NUM]; /* at[0]=>non-tautomeric, at[1]=>tautomeric */
2789
 
    /* inp_ATOM *out_norm_taut_at, *out_norm_nontaut_at; */
2790
 
    int                       i, n1, n2, num_atoms, num_at_tg, num_removed_H, num_removed_H_taut=0, ret=0, ret2=0;
2791
 
    INCHI_MODE                 nMode=0;
2792
 
    T_GROUP_INFO              vt_group_info;
2793
 
    T_GROUP_INFO              vt_group_info_orig;
2794
 
    T_GROUP_INFO * /*const*/  t_group_info        = &vt_group_info;                
2795
 
    T_GROUP_INFO * /*const*/  t_group_info_orig   = &vt_group_info_orig;
2796
 
    
2797
 
    CANON_STAT  CS, CS2;
2798
 
    CANON_STAT *pCS  = &CS;
2799
 
    CANON_STAT *pCS2 = &CS2;  /*  save all allocations to avoid memory leaks in case Canon_INChI() removes the pointer */
2800
 
    
2801
 
    ATOM_SIZES  s[TAUT_NUM];
2802
 
 
2803
 
    BCN Bcn;
2804
 
    BCN *pBCN = &Bcn;
2805
 
 
2806
 
    int bHasIsotopicAtoms  = 0;
2807
 
    int bMayHaveStereo     = 0;
2808
 
    int num_taut_at        = 0;
2809
 
 
2810
 
    inp_ATOM *out_at = NULL; /*, *norm_at_fixed_bonds[TAUT_NUM]; */ /*  = {out_norm_nontaut_at, out_norm_taut_at} ; */
2811
 
    INChI     *pINChI=NULL;      /* added initialization 2006-03 */
2812
 
    INChI_Aux *pINChI_Aux=NULL;  /* added initialization 2006-03 */
2813
 
    int        bPointedEdgeStereo = ((TG_FLAG_POINTED_EDGE_STEREO & *pbTautFlags)? PES_BIT_POINT_EDGE_STEREO:0)
2814
 
                                  | ((TG_FLAG_PHOSPHINE_STEREO    & *pbTautFlags)? PES_BIT_PHOSPHINE_STEREO :0)
2815
 
                                  | ((TG_FLAG_ARSINE_STEREO       & *pbTautFlags)? PES_BIT_ARSINE_STEREO    :0)
2816
 
                                  | ((TG_FLAG_FIX_SP3_BUG         & *pbTautFlags)? PES_BIT_FIX_SP3_BUG      :0);
2817
 
    INCHI_MODE bTautFlags         = (*pbTautFlags     & (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) );
2818
 
    INCHI_MODE bTautFlagsDone     = (*pbTautFlagsDone /*& (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) */);
2819
 
#if( bRELEASE_VERSION == 0 )
2820
 
    int bExtract = 0; /*  EXTR_HAS_ATOM_WITH_DEFINED_PARITY; */
2821
 
#endif
2822
 
 
2823
 
/*^^^ */
2824
 
    int bFixIsoFixedH = 0;
2825
 
    int bFixTermHChrg = 0;
2826
 
 
2827
 
#if( TEST_RENUMB_ATOMS == 1 )
2828
 
    long ulNormTime=0;
2829
 
    long ulCanonTime=0, ulCanonTime2=0;
2830
 
 
2831
 
    inchiTime ulNormTimeStart;
2832
 
    inchiTime ulCanonTimeStart;
2833
 
 
2834
 
    InchiTimeGet( &ulNormTimeStart );
2835
 
#endif
2836
 
 
2837
 
    /* vABParityUnknown holds actual value of an internal constant signifying       */
2838
 
    /* unknown parity: either the same as for undefined parity (default==standard)  */
2839
 
    /*  or a specific one (non-std; requested by SLUUD switch).                     */
2840
 
    int vABParityUnknown = AB_PARITY_UNDF;
2841
 
    if ( 0 != ( nUserMode & REQ_MODE_DIFF_UU_STEREO) ) 
2842
 
    {
2843
 
        /* Make labels for unknown and undefined stereo different */
2844
 
        vABParityUnknown = AB_PARITY_UNKN;
2845
 
    }
2846
 
 
2847
 
    
2848
 
 
2849
 
/*^^^ */
2850
 
#if( FIX_ISO_FIXEDH_BUG == 1 )
2851
 
    if (TG_FLAG_FIX_ISO_FIXEDH_BUG & *pbTautFlags)
2852
 
        bFixIsoFixedH = 1;
2853
 
#endif
2854
 
#if( FIX_TERM_H_CHRG_BUG == 1 )
2855
 
    if (TG_FLAG_FIX_TERM_H_CHRG_BUG & *pbTautFlags)
2856
 
        bFixTermHChrg = 1;
2857
 
#endif
2858
 
/*^^^ */
2859
 
 
2860
 
    memset( s, 0, sizeof(s) );
2861
 
    if ( pBCN ) {
2862
 
        memset( pBCN, 0, sizeof( pBCN[0] ) );
2863
 
    }
2864
 
    memset( t_group_info, 0, sizeof(*t_group_info) );
2865
 
    memset( t_group_info_orig, 0, sizeof(*t_group_info_orig) );
2866
 
    /*norm_at[TAUT_NON] = out_norm_data[TAUT_NON]->at; *//* output normalized non-tautomeric component */
2867
 
    /*norm_at[TAUT_YES] = out_norm_data[TAUT_YES]->at; *//* output normalized tautomeric component */
2868
 
    /*norm_at_fixed_bonds[TAUT_NON] = NULL;*/
2869
 
    /*norm_at_fixed_bonds[TAUT_YES] = out_norm_data[TAUT_YES]->at_fixed_bonds;*/
2870
 
    for ( i = 0; i < TAUT_NUM; i ++ ) {
2871
 
        if ( out_norm_data[i]->at ) {
2872
 
            if ( !(at[i] = (sp_ATOM  *)inchi_malloc( num_inp_at * sizeof(*at[0]) ) ) ) {
2873
 
                ret = -1;
2874
 
            }
2875
 
        } else {
2876
 
            at[i] = NULL;
2877
 
        }
2878
 
    }
2879
 
    if ( !out_norm_data[TAUT_NON]->at && !out_norm_data[TAUT_YES]->at || !inp_at || ret ) {
2880
 
        ret = -1;
2881
 
        goto exit_function;
2882
 
    }
2883
 
    /* the first struct to process: tautomeric if exists else non-tautomeric */
2884
 
    out_at = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES]->at : out_norm_data[TAUT_NON]->at;
2885
 
    /* copy the input structure to be normalized to the buffer for the normalization data */
2886
 
    memcpy( out_at, inp_at, num_inp_at*sizeof(out_at[0]) );
2887
 
 
2888
 
    /*  tautomeric groups setting */
2889
 
    t_group_info->bIgnoreIsotopic = 0;   /*  include tautomeric group isotopic info in MarkTautomerGroups() */
2890
 
    t_group_info->bTautFlags      = *pbTautFlags;
2891
 
    t_group_info->bTautFlagsDone  = *pbTautFlagsDone;
2892
 
 
2893
 
    /*  Preprocess the structure; here THE NUMBER OF ATOMS MAY BE REDUCED */
2894
 
    /*  ??? Ambiguity: H-D may become HD or DH (that is, H+implicit D or D+implicit H) */
2895
 
    if ( TG_FLAG_H_ALREADY_REMOVED & bTautFlags ) {
2896
 
        INP_ATOM_DATA *out_norm_data1 = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES] :
2897
 
                                        out_norm_data[TAUT_NON]->at? out_norm_data[TAUT_NON] : NULL;
2898
 
        if ( out_norm_data1 ) {
2899
 
            num_at_tg     =
2900
 
            num_atoms     = out_norm_data1->num_at - out_norm_data1->num_removed_H;
2901
 
            num_removed_H = out_norm_data1->num_removed_H;
2902
 
            t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
2903
 
        } else {
2904
 
            ret = -1;
2905
 
            goto exit_function;
2906
 
        }
2907
 
    } else {
2908
 
        num_at_tg =
2909
 
        num_atoms = remove_terminal_HDT( num_inp_at, out_at, bFixTermHChrg );
2910
 
        num_removed_H = num_inp_at - num_atoms;
2911
 
        t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
2912
 
        add_DT_to_num_H( num_atoms, out_at );
2913
 
    }
2914
 
    /*fix_odd_things( num_atoms, out_at );*/
2915
 
#if( FIND_RING_SYSTEMS == 1 )
2916
 
    MarkRingSystemsInp( out_at, num_atoms, 0 );
2917
 
#endif
2918
 
    /*  duplicate the preprocessed structure so that all supplied out_norm_data[]->at buffers are filled */
2919
 
    if ( out_at != out_norm_data[TAUT_YES]->at && out_norm_data[TAUT_YES]->at ) {
2920
 
        memcpy( out_norm_data[TAUT_YES]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2921
 
    }
2922
 
    if ( out_norm_data[TAUT_YES]->at_fixed_bonds && out_norm_data[TAUT_YES]->at ) {
2923
 
        memcpy( out_norm_data[TAUT_YES]->at_fixed_bonds, out_at, num_inp_at*sizeof(out_at[0]) );
2924
 
    }
2925
 
    if ( out_at != out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_NON]->at ) {
2926
 
        memcpy( out_norm_data[TAUT_NON]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2927
 
    }
2928
 
 
2929
 
    /*******************************************************************************
2930
 
     * ??? not true ??? duplicate inp_at and keep inp_at[] unchanged after terminal hydrogens removal
2931
 
     * set stereo parities in taut_at[], non_taut_at[]
2932
 
     * obtain max. lenghts of the name stereo parts
2933
 
     * Ignore absence/presence of isotopic stereo for now
2934
 
     * mark isotopic atoms
2935
 
     *******************************************************************************/
2936
 
    if ( out_norm_data[TAUT_YES]->at && at[TAUT_YES] ) {
2937
 
        /* final normalization of possibly tautomeric structure */
2938
 
        ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_YES]->at, out_norm_data[TAUT_YES]->at_fixed_bonds, num_atoms,
2939
 
                                               t_group_info, NULL, NULL );
2940
 
        if ( ret < 0 ) {
2941
 
            goto exit_function;/*  out of RAM or other normalization problem */
2942
 
        }
2943
 
        num_taut_at = ret; /* number of atoms without removed H? */
2944
 
        num_removed_H_taut = t_group_info->tni.nNumRemovedExplicitH;
2945
 
        out_norm_data[TAUT_YES]->num_at              = num_atoms + num_removed_H_taut; /* protons might have been removed */
2946
 
        out_norm_data[TAUT_YES]->num_removed_H       = num_removed_H_taut;
2947
 
        out_norm_data[TAUT_YES]->nNumRemovedProtons += t_group_info->tni.nNumRemovedProtons;
2948
 
        for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
2949
 
            out_norm_data[TAUT_YES]->nNumRemovedProtonsIsotopic[i] += t_group_info->tni.nNumRemovedProtonsIsotopic[i] /*+ t_group_info->num_iso_H[i]*/;
2950
 
            out_norm_data[TAUT_YES]->num_iso_H[i]                  += t_group_info->num_iso_H[i];
2951
 
        }
2952
 
        /* mark deleted isolated tautomeric H(+) */
2953
 
        if ( num_taut_at == 1 && out_norm_data[TAUT_YES]->at[0].at_type == ATT_PROTON &&
2954
 
             t_group_info && t_group_info->tni.nNumRemovedProtons == 1 ) {
2955
 
            out_norm_data[TAUT_YES]->bDeleted = 1;
2956
 
            FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2957
 
        } else
2958
 
        if ( (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT) &&
2959
 
             out_norm_data[TAUT_YES]->at_fixed_bonds) {
2960
 
             out_norm_data[TAUT_YES]->bTautPreprocessed = 1;
2961
 
        }
2962
 
        /*
2963
 
        if ( !(t_group_info->tni.bNormalizationFlags & (FLAG_NORM_CONSIDER_TAUT & ~FLAG_PROTON_SINGLE_REMOVED)) &&
2964
 
             out_norm_data[TAUT_YES]->at_fixed_bonds) {
2965
 
             FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2966
 
        }
2967
 
        */
2968
 
        /*out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;*/
2969
 
        out_norm_data[TAUT_YES]->bTautFlags     = *pbTautFlags     = t_group_info->bTautFlags;
2970
 
        out_norm_data[TAUT_YES]->bTautFlagsDone = *pbTautFlagsDone = t_group_info->bTautFlagsDone;
2971
 
        out_norm_data[TAUT_YES]->bNormalizationFlags = t_group_info->tni.bNormalizationFlags;
2972
 
        /* create internal sp_ATOM at[] out of out_norm_data[]->at */
2973
 
        inp2spATOM( out_norm_data[TAUT_YES]->at, num_inp_at, at[TAUT_YES] );
2974
 
        /* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
2975
 
        ret = set_stereo_parity( out_norm_data[TAUT_YES]->at, at[TAUT_YES], num_taut_at, num_removed_H_taut,
2976
 
                                 &s[TAUT_YES].nMaxNumStereoAtoms, &s[TAUT_YES].nMaxNumStereoBonds, nUserMode,
2977
 
                                 bPointedEdgeStereo, vABParityUnknown );
2978
 
#if( bRELEASE_VERSION == 0 )
2979
 
        if ( 0 < ret ) {
2980
 
            bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
2981
 
        }
2982
 
        if ( t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT ) {
2983
 
            bExtract |= EXTR_TAUT_TREATMENT_CHARGES;
2984
 
        }
2985
 
#endif
2986
 
        if ( RETURNED_ERROR( ret ) ) {
2987
 
            goto exit_function; /*  stereo bond error */
2988
 
        }
2989
 
        s[TAUT_YES].bMayHaveStereo    = (s[TAUT_YES].nMaxNumStereoAtoms || s[TAUT_YES].nMaxNumStereoBonds);
2990
 
        /* 
2991
 
         * mark isotopic atoms and atoms that have non-tautomeric
2992
 
         * isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
2993
 
         */
2994
 
        s[TAUT_YES].num_isotopic_atoms = set_atom_iso_sort_keys( num_taut_at, at[TAUT_YES], t_group_info,
2995
 
                                                          &s[TAUT_YES].bHasIsotopicTautGroups );
2996
 
        /**************************************************************************
2997
 
         *  prepare tautomeric (if no tautomerism found then prepare non-tautomeric)
2998
 
         *  structure for canonicalizaton:
2999
 
         **************************************************************************
3000
 
         *   remove t-groups that have no H,
3001
 
         *   remove charges from t-groups if requested
3002
 
         *   renumber t-groups and find final t_group_info->num_t_groups
3003
 
         *   add to t-groups lists of endpoints tgroup->nEndpointAtomNumber[]
3004
 
         *   calculate length of the t-group part of the connection table
3005
 
         **************************************************************************/
3006
 
        s[TAUT_YES].nLenLinearCTTautomer = CountTautomerGroups( at[TAUT_YES], num_taut_at, t_group_info );
3007
 
        if ( RETURNED_ERROR(s[TAUT_YES].nLenLinearCTTautomer) ) { /* added error treatment 9-11-2003 */
3008
 
            ret = s[TAUT_YES].nLenLinearCTTautomer;
3009
 
            goto exit_function;
3010
 
            /*  error has happened; no breakpoint here
3011
 
            s[TAUT_YES].nLenLinearCTTautomer = 0;
3012
 
            */
3013
 
        } else
3014
 
        if ( s[TAUT_YES].nLenLinearCTTautomer > 0 ) {
3015
 
            num_at_tg = num_taut_at+t_group_info->num_t_groups;
3016
 
            /*  ??? -not true- create t_group_info_orig for multiple calls with atom renumbering */
3017
 
            make_a_copy_of_t_group_info( t_group_info_orig /* dest*/, t_group_info /* source*/ );
3018
 
            /*  mark isotopic tautomer groups: calculate t_group->iWeight */
3019
 
            s[TAUT_YES].nLenLinearCTIsotopicTautomer=set_tautomer_iso_sort_keys( t_group_info );
3020
 
            if ( s[TAUT_YES].nLenLinearCTIsotopicTautomer < 0 ) {
3021
 
                /* ??? -error cannot happen- error has happened; no breakpoint here */
3022
 
                s[TAUT_YES].nLenLinearCTIsotopicTautomer = 0;
3023
 
            }
3024
 
            out_norm_data[TAUT_YES]->bTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
3025
 
        }
3026
 
        /*  new variable: s[TAUT_YES].nLenCT introduced 7-22-2002 */
3027
 
        GetCanonLengths( num_taut_at, at[TAUT_YES], &s[TAUT_YES], t_group_info );
3028
 
    }
3029
 
    if ( out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at && at[TAUT_NON] && !s[TAUT_YES].nLenLinearCTTautomer ) {
3030
 
        /* the structure is non-tautomeric: use tautomeric treatment results only for it */
3031
 
        inchi_free( at[TAUT_NON] );
3032
 
        at[TAUT_NON] = NULL;
3033
 
    } else
3034
 
    if ( !out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at &&
3035
 
         !at[TAUT_NON] && at[TAUT_YES] && !s[TAUT_YES].nLenLinearCTTautomer ) {
3036
 
        /* requested tautomeric; found non-tautomeric; it is located in out_norm_data[TAUT_YES]->at */
3037
 
        out_norm_data[TAUT_YES]->bTautomeric = 0;
3038
 
    } else
3039
 
    if ( out_norm_data[TAUT_NON]->at && at[TAUT_NON] ) {
3040
 
        /* the structure needs non-tautomeric treatment: final normalization of non-tautomeric structure */
3041
 
        ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_NON]->at, NULL, num_atoms, NULL, &bTautFlags, &bTautFlagsDone );
3042
 
        if ( ret < 0 ) {
3043
 
            goto exit_function;  /*  out of RAM or other normalization problem */
3044
 
        }
3045
 
        out_norm_data[TAUT_NON]->num_at        = num_atoms + num_removed_H;
3046
 
        out_norm_data[TAUT_NON]->num_removed_H = num_removed_H;
3047
 
        out_norm_data[TAUT_NON]->bTautFlags     = *pbTautFlags;
3048
 
        out_norm_data[TAUT_NON]->bTautFlagsDone = *pbTautFlagsDone;
3049
 
        out_norm_data[TAUT_NON]->bNormalizationFlags = 0;
3050
 
        /* create internal sp_ATOM at[] out of out_norm_data[]->at */
3051
 
        inp2spATOM( out_norm_data[TAUT_NON]->at, num_inp_at, at[TAUT_NON] );
3052
 
        /* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
3053
 
        ret = set_stereo_parity( out_norm_data[TAUT_NON]->at, at[TAUT_NON], num_atoms, num_removed_H,
3054
 
                                 &s[TAUT_NON].nMaxNumStereoAtoms, &s[TAUT_NON].nMaxNumStereoBonds, nUserMode,
3055
 
                                 bPointedEdgeStereo, vABParityUnknown );
3056
 
#if( bRELEASE_VERSION == 0 )
3057
 
        if ( 0 < ret ) {
3058
 
            bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
3059
 
        }
3060
 
#endif
3061
 
        if ( RETURNED_ERROR( ret ) ) {
3062
 
            goto exit_function; /*  stereo bond error */
3063
 
        }
3064
 
        s[TAUT_NON].bMayHaveStereo = (s[TAUT_NON].nMaxNumStereoAtoms || s[TAUT_NON].nMaxNumStereoBonds);
3065
 
        /* 
3066
 
         * mark isotopic atoms and atoms that have non-tautomeric
3067
 
         * isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
3068
 
         */
3069
 
        s[TAUT_NON].num_isotopic_atoms = set_atom_iso_sort_keys( num_atoms, at[TAUT_NON], NULL, NULL );
3070
 
        GetCanonLengths( num_atoms, at[TAUT_NON], &s[TAUT_NON], NULL);
3071
 
        out_norm_data[TAUT_NON]->bTautomeric = 0;
3072
 
    }
3073
 
 
3074
 
    /**********************************************************/
3075
 
    /*  common */
3076
 
    bMayHaveStereo        = s[TAUT_YES].bMayHaveStereo || s[TAUT_NON].bMayHaveStereo;
3077
 
    bHasIsotopicAtoms     = s[TAUT_NON].num_isotopic_atoms > 0 || s[TAUT_NON].bHasIsotopicTautGroups > 0 ||
3078
 
                            s[TAUT_YES].num_isotopic_atoms > 0 || s[TAUT_YES].bHasIsotopicTautGroups > 0 ;
3079
 
/*^^^ */
3080
 
    if (bFixIsoFixedH)  /* 2008-03-21 DT */
3081
 
        bHasIsotopicAtoms     = bHasIsotopicAtoms   || 
3082
 
                                s[TAUT_YES].nLenLinearCTTautomer > 0 && t_group_info &&
3083
 
                                (0 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[0] ||
3084
 
                                 1 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[1] ||
3085
 
                                 2 < NUM_H_ISOTOPES && t_group_info->tni.nNumRemovedProtonsIsotopic[2]) ;
3086
 
/*^^^ */
3087
 
    bHasIsotopicAtoms   =   bHasIsotopicAtoms || 
3088
 
                            s[TAUT_YES].nLenIsotopicEndpoints > 1 && t_group_info &&
3089
 
                            (t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE));
3090
 
 
3091
 
    /*  default mode */
3092
 
    if ( !(nUserMode & REQ_MODE_DEFAULT) ) {
3093
 
        /*  default */
3094
 
        nUserMode |= REQ_MODE_DEFAULT;
3095
 
    }
3096
 
    
3097
 
    /*  adjust the mode to the reality */
3098
 
    if ( ( nUserMode & REQ_MODE_ISO ) && !bHasIsotopicAtoms ) {
3099
 
        nUserMode ^= REQ_MODE_ISO;
3100
 
        nUserMode |= REQ_MODE_NON_ISO;  /*  at least one is needed */
3101
 
    }
3102
 
    if ( (nUserMode & REQ_MODE_STEREO) && ( nUserMode & REQ_MODE_ISO ) ) {
3103
 
        nUserMode |= REQ_MODE_ISO_STEREO;
3104
 
    }
3105
 
    if ( (nUserMode & REQ_MODE_STEREO) && !( nUserMode & REQ_MODE_NON_ISO ) ) {
3106
 
        nUserMode ^= REQ_MODE_STEREO;
3107
 
    }
3108
 
    if ( !bMayHaveStereo ) {
3109
 
        if ( nUserMode & REQ_MODE_STEREO )
3110
 
            nUserMode ^= REQ_MODE_STEREO;
3111
 
        if ( nUserMode & REQ_MODE_ISO_STEREO )
3112
 
            nUserMode ^= REQ_MODE_ISO_STEREO;
3113
 
    }
3114
 
 
3115
 
    if ( (nUserMode & REQ_MODE_BASIC) && (!out_norm_data[TAUT_NON]->at || !ppINChI[TAUT_NON] || !ppINChI_Aux[TAUT_NON] || !at[TAUT_NON]) ) {
3116
 
        nUserMode ^= REQ_MODE_BASIC;
3117
 
    }
3118
 
    if ( (nUserMode & REQ_MODE_TAUT) && (!out_norm_data[TAUT_YES]->at || !ppINChI[TAUT_YES] || !ppINChI_Aux[TAUT_YES] || !at[TAUT_YES]) ) {
3119
 
        nUserMode ^= REQ_MODE_TAUT;
3120
 
    }
3121
 
        
3122
 
 
3123
 
    switch ((int)nUserMode & (REQ_MODE_BASIC | REQ_MODE_TAUT)) {
3124
 
    case REQ_MODE_BASIC:
3125
 
        n1 = TAUT_NON;
3126
 
        n2 = TAUT_NON;
3127
 
        break;
3128
 
    case REQ_MODE_TAUT:
3129
 
        n1 = TAUT_YES;
3130
 
        n2 = TAUT_YES;
3131
 
        break;
3132
 
    case (REQ_MODE_BASIC | REQ_MODE_TAUT):
3133
 
        n1 = TAUT_NON;
3134
 
        n2 = TAUT_YES;
3135
 
        break;
3136
 
    default:
3137
 
        ret = -3;
3138
 
        goto exit_function; /*  program error: inconsistent nUserMode or missing taut/non-taut allocation */ /*   <BRKPT> */
3139
 
    }
3140
 
#if( TEST_RENUMB_ATOMS == 1 )
3141
 
    ulNormTime = InchiTimeElapsed( &ulNormTimeStart);
3142
 
#endif
3143
 
    /************************************************************
3144
 
     *                                                          *
3145
 
     *       Obtain all non-stereo canonical numberings         *
3146
 
     *                                                          *
3147
 
     ************************************************************/
3148
 
#if( TEST_RENUMB_ATOMS == 1 )
3149
 
        InchiTimeGet( &ulCanonTimeStart );
3150
 
#endif
3151
 
    if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3152
 
        /* added for special non-isotopic test mode 2004-10-04 */
3153
 
        if ( t_group_info ) {
3154
 
            t_group_info->bIgnoreIsotopic = 1;
3155
 
            if ( t_group_info->nIsotopicEndpointAtomNumber ) {
3156
 
                t_group_info->nIsotopicEndpointAtomNumber[0] = inchi_min(1, t_group_info->nIsotopicEndpointAtomNumber[0]);
3157
 
            }
3158
 
            memset( t_group_info->num_iso_H, 0, sizeof(t_group_info->num_iso_H) );
3159
 
            memset ( t_group_info->tni.nNumRemovedProtonsIsotopic, 0, sizeof(t_group_info->tni.nNumRemovedProtonsIsotopic));
3160
 
            t_group_info->bTautFlagsDone &= ~(TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE);
3161
 
        }
3162
 
        for ( i = 0; i < TAUT_NUM; i ++ ) {
3163
 
            s[i].bHasIsotopicTautGroups = 0;
3164
 
            s[i].bIgnoreIsotopic = 1;
3165
 
            s[i].nLenIsotopic = 0;
3166
 
            s[i].nLenIsotopicEndpoints = 0;
3167
 
            s[i].nLenLinearCTIsotopicTautomer = 0;
3168
 
            s[i].num_isotopic_atoms = 0;
3169
 
        }
3170
 
        bHasIsotopicAtoms = 0;
3171
 
    }
3172
 
    ret = GetBaseCanonRanking( num_atoms, num_at_tg, at, t_group_info, s, pBCN, ulMaxTime, bFixIsoFixedH );
3173
 
#if( TEST_RENUMB_ATOMS == 1 )
3174
 
        ulCanonTime = InchiTimeElapsed( &ulCanonTimeStart );
3175
 
#endif
3176
 
    if ( ret < 0 ) {
3177
 
        goto exit_function; /*  program error */
3178
 
    }
3179
 
#if( bRELEASE_VERSION == 0 && FIND_CANON_NE_EQUITABLE == 1 )
3180
 
    /* Debug only: find whether canonical equivalence is different from equitable partition */
3181
 
    if ( bCanonIsFinerThanEquitablePartition( num_atoms, at[n1], pBCN->ftcn[TAUT_NON].nSymmRankCt ) ) {
3182
 
        bExtract |= EXTR_CANON_NE_EQUITABLE;
3183
 
    }
3184
 
#endif
3185
 
    /* added for special non-isotopic test mode 2004-10-04 */
3186
 
    if ( !pBCN->ftcn[n1].PartitionCt.Rank ) {
3187
 
        n1 = ALT_TAUT(n1);
3188
 
    }
3189
 
    if ( !pBCN->ftcn[n2].PartitionCt.Rank ) {
3190
 
        n2 = ALT_TAUT(n2);
3191
 
    }
3192
 
    if ( n1 > n2 ) {
3193
 
        ret = CT_TAUCOUNT_ERR;
3194
 
        goto exit_function; /*  program error */
3195
 
    }
3196
 
 
3197
 
    /************************************************************
3198
 
     *                                                          *
3199
 
     *       Obtain stereo canonical numberings                 *
3200
 
     *                                                          *
3201
 
     ************************************************************/
3202
 
 
3203
 
    for ( i = n2; i >= n1 && !RETURNED_ERROR( ret ); i -- ) {
3204
 
 
3205
 
        memset( pCS, 0, sizeof(*pCS) );
3206
 
 
3207
 
        switch( i ) {
3208
 
        case TAUT_NON: /*  non-tautomeric */
3209
 
            nMode  = 0;
3210
 
            nMode  = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
3211
 
            nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO))? CANON_MODE_ISO:0;
3212
 
            nMode |= (s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
3213
 
            nMode |= (bHasIsotopicAtoms && s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
3214
 
            nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO   )? CMODE_NOEQ_STEREO    : 0;
3215
 
            nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
3216
 
            nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS  : 0;
3217
 
            if ( (nMode & CANON_MODE_STEREO)     == CANON_MODE_STEREO ||
3218
 
                 (nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
3219
 
                nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
3220
 
                nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
3221
 
                nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU  )? CMODE_SC_IGN_ALL_UU  : 0;
3222
 
                nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU  )? CMODE_SB_IGN_ALL_UU  : 0;
3223
 
            }
3224
 
            if ( ret= AllocateCS( pCS, num_atoms, num_atoms, s[TAUT_NON].nLenCT, s[TAUT_NON].nLenCTAtOnly,
3225
 
                             s[TAUT_NON].nLenLinearCTStereoDble, s[TAUT_NON].nMaxNumStereoBonds,
3226
 
                             s[TAUT_NON].nLenLinearCTStereoCarb, s[TAUT_NON].nMaxNumStereoAtoms,
3227
 
                             0, 0, s[TAUT_NON].nLenIsotopic, nMode, pBCN ) ) {
3228
 
                goto exit_function;
3229
 
            }
3230
 
            *pCS2 = *pCS;
3231
 
            break;
3232
 
        case TAUT_YES: /*  tautomeric */
3233
 
            nMode  = 0;
3234
 
            nMode  = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
3235
 
            nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO) )? CANON_MODE_ISO:0;
3236
 
            nMode |= (s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
3237
 
            nMode |= (bHasIsotopicAtoms && s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
3238
 
            nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO   )? CMODE_NOEQ_STEREO    : 0;
3239
 
            nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
3240
 
            nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS  : 0;
3241
 
            if ( (nMode & CANON_MODE_STEREO)     == CANON_MODE_STEREO ||
3242
 
                 (nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
3243
 
                nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
3244
 
                nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
3245
 
                nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU  )? CMODE_SC_IGN_ALL_UU  : 0;
3246
 
                nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU  )? CMODE_SB_IGN_ALL_UU  : 0;
3247
 
            }
3248
 
            if ( ret= AllocateCS( pCS, num_atoms, num_at_tg, s[TAUT_YES].nLenCT, s[TAUT_YES].nLenCTAtOnly,
3249
 
                             s[TAUT_YES].nLenLinearCTStereoDble, s[TAUT_YES].nMaxNumStereoBonds,
3250
 
                             s[TAUT_YES].nLenLinearCTStereoCarb, s[TAUT_YES].nMaxNumStereoAtoms,
3251
 
                             s[TAUT_YES].nLenLinearCTTautomer, s[TAUT_YES].nLenLinearCTIsotopicTautomer,
3252
 
                             s[TAUT_YES].nLenIsotopic, nMode, pBCN ) ) {
3253
 
                goto exit_function;
3254
 
            }
3255
 
            *pCS2 = *pCS;
3256
 
            break;
3257
 
        }
3258
 
 
3259
 
    
3260
 
        /*^^^ 2009-12-05 */
3261
 
        nMode |= (nUserMode & REQ_MODE_DIFF_UU_STEREO)? REQ_MODE_DIFF_UU_STEREO : 0;
3262
 
        /*^^^ 2009-12-05 */
3263
 
 
3264
 
 
3265
 
        /*  settings */
3266
 
        pCS->lNumDecreasedCT               = -1;                             
3267
 
        pCS->bDoubleBondSquare             =  DOUBLE_BOND_NEIGH_LIST? 2:0;  /*  2 => special mode */
3268
 
        pCS->bIgnoreIsotopic               =  !((s[TAUT_NON].num_isotopic_atoms ||        
3269
 
                                                s[TAUT_YES].num_isotopic_atoms ||    
3270
 
                                                s[TAUT_YES].bHasIsotopicTautGroups) ||
3271
 
                                               (nUserMode & REQ_MODE_NON_ISO) ||
3272
 
                                               !(nUserMode & REQ_MODE_ISO));
3273
 
        
3274
 
        if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3275
 
            pCS->bIgnoreIsotopic = 1; /* 10-04-2004 */
3276
 
        }
3277
 
        
3278
 
        if ( i == TAUT_YES ) {  /* tautomeric */
3279
 
            pCS->t_group_info                  = t_group_info; /*  ??? make a copy or reuse ???  */
3280
 
            pCS->t_group_info->bIgnoreIsotopic = !(s[TAUT_YES].bHasIsotopicTautGroups ||
3281
 
                                                   (nUserMode & REQ_MODE_NON_ISO) ||
3282
 
                                                   !(nUserMode & REQ_MODE_ISO));
3283
 
            if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
3284
 
                pCS->t_group_info->bIgnoreIsotopic = 1; /* 10-04-2004 */
3285
 
            }
3286
 
        }
3287
 
        pCS->ulTimeOutTime  = pBCN->ulTimeOutTime;
3288
 
        /*=========== Obsolete Mode Bits (bit 0 is Least Significant Bit) ===========
3289
 
         *
3290
 
         *  Mode      Bits       Description                                
3291
 
         *   '0' c    0          Only one connection table canonicalization 
3292
 
         *   '1' C    1          Recalculate CT using fixed nSymmRank       
3293
 
         *   '2' i    1|2        Isotopic canonicalization (internal)       
3294
 
         *   '3' I    1|2|4      Isotopic canonicalization (output)
3295
 
         *   '4' s    1|8        Stereo canonicalization                    
3296
 
         *   '5' S    1|2|4|16   Stereo isotopic canonicalization           
3297
 
         *   '6' A    1|2|4|8|16 Output All
3298
 
         */
3299
 
#if( TEST_RENUMB_ATOMS == 1 )
3300
 
        InchiTimeGet( &ulCanonTimeStart );
3301
 
#endif
3302
 
        /***************************************
3303
 
           The last canonicalization step
3304
 
         ***************************************/
3305
 
        if ( pBCN ) {
3306
 
            /* USE_CANON2 == 1 */
3307
 
            pCS->NeighList  = NULL;
3308
 
            pCS->pBCN       = pBCN;
3309
 
            ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
3310
 
        } else {
3311
 
            /* old way */
3312
 
            pCS->NeighList  = CreateNeighList( num_atoms, i?num_at_tg:num_atoms, at[i], pCS->bDoubleBondSquare, pCS->t_group_info );
3313
 
            pCS->pBCN       = NULL;
3314
 
            ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
3315
 
        }
3316
 
 
3317
 
        pINChI     = ppINChI[i];      /* pointers to already allocated still empty InChI */
3318
 
        pINChI_Aux = ppINChI_Aux[i];
3319
 
        if ( ret <= 0 ) {
3320
 
            /***************************************/
3321
 
            /*  failure in Canon_INChI()            */
3322
 
            /***************************************/
3323
 
            pINChI->nErrorCode     = ret;
3324
 
            pINChI_Aux->nErrorCode = ret;
3325
 
        } else {
3326
 
            /***************************************/
3327
 
            /*  success Canon_INChI()               */
3328
 
            /*  save canonicalization results in   */
3329
 
            /*  pINChI and pINChI_Aux                */
3330
 
            /***************************************/
3331
 
            pINChI->nErrorCode     = 0;
3332
 
            pINChI_Aux->nErrorCode = 0;
3333
 
            pINChI->bDeleted = pINChI_Aux->bDeleted = out_norm_data[i]->bDeleted;
3334
 
            pINChI_Aux->nCanonFlags         = pCS->nCanonFlags;
3335
 
            pINChI_Aux->bTautFlags          = out_norm_data[i]->bTautFlags;
3336
 
            pINChI_Aux->bTautFlagsDone      = out_norm_data[i]->bTautFlagsDone;
3337
 
            pINChI_Aux->bNormalizationFlags = out_norm_data[i]->bNormalizationFlags;
3338
 
            /*  may return an error or a warning */
3339
 
            ret = FillOutINChI( pINChI, pINChI_Aux,
3340
 
                               num_atoms, i?num_at_tg:num_atoms,
3341
 
                               i?num_removed_H_taut:num_removed_H, at[i], 
3342
 
                               out_norm_data[i]->at, pCS, i, nUserMode, 
3343
 
                               pStrErrStruct );
3344
 
            if ( RETURNED_ERROR( ret ) ) {
3345
 
                /* failure in FillOutINChI() */
3346
 
                pINChI->nErrorCode      = ret;
3347
 
                pINChI_Aux->nErrorCode  = ret;
3348
 
            } else {
3349
 
                /****************************/
3350
 
                /* success in FillOutINChI() */
3351
 
                /****************************/
3352
 
#if( bRELEASE_VERSION == 0 )
3353
 
                if ( pINChI->Stereo &&
3354
 
                     (pINChI->Stereo->nCompInv2Abs && !pINChI->Stereo->bTrivialInv) ||
3355
 
                     pINChI->StereoIsotopic &&
3356
 
                     (pINChI->StereoIsotopic->nCompInv2Abs && !pINChI->StereoIsotopic->bTrivialInv) ) {
3357
 
                    bExtract |= EXTR_NON_TRIVIAL_STEREO;
3358
 
                }
3359
 
#endif
3360
 
                /* mark non-tautomeric representation as having another, tautomeric representation */
3361
 
                if ( pINChI_Aux && s[TAUT_YES].nLenLinearCTTautomer ) {
3362
 
                    pINChI_Aux->bIsTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
3363
 
                }
3364
 
#if( bRELEASE_VERSION == 0 )
3365
 
                pCS->bExtract   |= bExtract;
3366
 
                pINChI->bExtract |= pCS->bExtract;
3367
 
#endif
3368
 
                ret2 = CheckCanonNumberingCorrectness(
3369
 
                                num_atoms, i?num_at_tg:num_atoms,
3370
 
                                at[i], pCS, i, pStrErrStruct );
3371
 
                if ( ret2 ) {
3372
 
                    pINChI->nErrorCode      = ret2;
3373
 
                    pINChI_Aux->nErrorCode  = ret2;
3374
 
                    ret = ret2;
3375
 
                }
3376
 
            }
3377
 
        }
3378
 
#if( TEST_RENUMB_ATOMS == 1 )
3379
 
        ulCanonTime2 = InchiTimeElapsed( &ulCanonTimeStart );
3380
 
        pINChI_Aux->ulCanonTime = ulCanonTime+ulCanonTime2;
3381
 
        pINChI_Aux->ulNormTime  = ulNormTime;
3382
 
#endif
3383
 
        FreeNeighList( pCS->NeighList );
3384
 
        DeAllocateCS( pCS2 );
3385
 
 
3386
 
        pINChI = NULL;      /* avoid dangling pointers */
3387
 
        pINChI_Aux = NULL;  /* avoid dangling pointers */
3388
 
    }
3389
 
    if ( ret == 0 ) {
3390
 
        ret = num_atoms;
3391
 
    }
3392
 
    /*  treat the results later */
3393
 
 
3394
 
exit_function:
3395
 
    DeAllocBCN( pBCN );
3396
 
    if ( at[TAUT_YES] )
3397
 
        inchi_free( at[TAUT_YES] );
3398
 
    if ( at[TAUT_NON] )
3399
 
        inchi_free( at[TAUT_NON] );
3400
 
    if ( ti_out ) {
3401
 
        *ti_out = *t_group_info;
3402
 
    } else {
3403
 
        free_t_group_info( t_group_info );
3404
 
    }
3405
 
    free_t_group_info( t_group_info_orig );
3406
 
    return ret;
3407
 
}
3408
 
#ifndef INCHI_ANSI_ONLY /* { */
3409
 
/***************************************************************************************/
3410
 
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
3411
 
                            AT_NUMB *nOrigAtNosInCanonOrd, int num_at )
3412
 
{
3413
 
    AT_NUMB   *nCanonNbr, *nOrigAtNos, *nOrigAtNosOrd;
3414
 
    int          i, ret;
3415
 
 
3416
 
    ret = 0;
3417
 
 
3418
 
    nCanonNbr     = (AT_NUMB *)inchi_calloc( num_at, sizeof(nCanonNbr[0]) );
3419
 
    nOrigAtNos    = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNos[0]) );
3420
 
    nOrigAtNosOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNosOrd[0]) );
3421
 
 
3422
 
    if ( !nCanonNbr || !nOrigAtNos || !nAtomOrdNbr || !nOrigAtNosOrd ) {
3423
 
        ret = CT_OUT_OF_RAM;  /*   <BRKPT> */
3424
 
        goto exit_function;
3425
 
    }
3426
 
    for ( i = 0; i < num_at; i ++ ) {
3427
 
        nCanonNbr[i] = nAtomOrdNbr[i] = nOrigAtNosOrd[i] = (AT_NUMB)i;
3428
 
        nOrigAtNos[i] = norm_at[i].orig_at_number;
3429
 
    }
3430
 
    /*  get nCanonNbr[]: canon. numbers-1 in order of increasing original atom numbers */
3431
 
    pn_RankForSort = nOrigAtNosInCanonOrd;
3432
 
    qsort( nCanonNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
3433
 
    /*  get nOrigAtNosOrd[]: norm_atom ord. numbers the same order of increasing original atom numbers */
3434
 
    pn_RankForSort = nOrigAtNos;
3435
 
    qsort( nOrigAtNosOrd, num_at, sizeof(nOrigAtNosOrd[0]), CompRank ); 
3436
 
    /*  check whether the 2 sets of origiginal atom numbers have identical elements */
3437
 
    for ( i = 0; i < num_at; i ++ ) {
3438
 
        if ( nOrigAtNosInCanonOrd[nCanonNbr[i]] != nOrigAtNos[nOrigAtNosOrd[i]] ) {
3439
 
            ret = CT_RANKING_ERR;  /*   <BRKPT> */
3440
 
            goto exit_function;
3441
 
        }
3442
 
    }
3443
 
    for ( i = 0; i < num_at; i ++ ) {
3444
 
        nAtomOrdNbr[(int)nCanonNbr[i]] = nOrigAtNosOrd[i];
3445
 
    }
3446
 
 
3447
 
/*
3448
 
    pn_RankForSort = nCanonNbr;
3449
 
    qsort( nAtomOrdNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
3450
 
*/
3451
 
 
3452
 
exit_function:
3453
 
    if ( nCanonNbr )
3454
 
        inchi_free( nCanonNbr );
3455
 
    if ( nOrigAtNos )
3456
 
        inchi_free( nOrigAtNos );
3457
 
    if ( nOrigAtNosOrd )
3458
 
        inchi_free( nOrigAtNosOrd );
3459
 
    return ret;
3460
 
}
3461
 
/***************************************************************************************/
3462
 
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
3463
 
                        INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
3464
 
{
3465
 
    int          i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
3466
 
    int          next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
3467
 
    int          next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len;
3468
 
    int          num_iso_H[NUM_H_ISOTOPES];
3469
 
    char        *str;
3470
 
    AT_NUMB      g, e;
3471
 
    int          num_at           = pINChI->nNumberOfAtoms;
3472
 
    int          nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
3473
 
    AT_NUMB     *nOrigAtNosInCanonOrd;
3474
 
    INChI_Stereo *Stereo;
3475
 
    AT_NUMB     *nConstitEquNumbers;
3476
 
    AT_NUMB     *nConstitEquTGroupNumbers;
3477
 
    S_CHAR      *t_parity = NULL;
3478
 
    AT_NUMB     *nNumber = NULL;
3479
 
    int          bIncludeIsotopicH;
3480
 
 
3481
 
    AT_NUMB     *nNormAtNosInCanonOrd;
3482
 
    int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
3483
 
    int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
3484
 
    int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
3485
 
    int bRelRac= bRel || bRac;
3486
 
    int bDoDisplaySp3 = 1;
3487
 
 
3488
 
    inf_ATOM *inf_norm_at = inf_norm_at_data? inf_norm_at_data->at : NULL;
3489
 
 
3490
 
    ret = 0;
3491
 
    num_err = 0;
3492
 
 
3493
 
    if ( !inf_norm_at )
3494
 
        return ret;
3495
 
    /* prepare removeable protons and H info */
3496
 
    inf_norm_at_data->nNumRemovedProtons = pINChI_Aux->nNumRemovedProtons;
3497
 
    MakeRemovedProtonsString( pINChI_Aux->nNumRemovedProtons, pINChI_Aux->nNumRemovedIsotopicH, NULL, bIsotopic,
3498
 
                              inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
3499
 
    /* fill out info atom */
3500
 
    if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
3501
 
                        pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
3502
 
        bIsotopic = 0;
3503
 
    
3504
 
    Stereo                   = bIsotopic? pINChI->StereoIsotopic :
3505
 
                                          pINChI->Stereo;
3506
 
    bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0); 
3507
 
 
3508
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
3509
 
    if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3510
 
         (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3511
 
        bDoDisplaySp3 = 0;
3512
 
        if ( Stereo->nCompInv2Abs ) {
3513
 
            inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
3514
 
        }
3515
 
    }
3516
 
#endif    
3517
 
    /* flag has stereo */
3518
 
    if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
3519
 
        inf_norm_at_data->StereoFlags |= INF_STEREO;
3520
 
    }
3521
 
 
3522
 
    /*
3523
 
    if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3524
 
         (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3525
 
        bDoDisplaySp3 = 0;
3526
 
    }
3527
 
    */
3528
 
    if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
3529
 
        /* inversion changes stereo */
3530
 
        if ( bRel ) {
3531
 
            inf_norm_at_data->StereoFlags |= INF_STEREO_REL;
3532
 
        } else
3533
 
        if ( bRac ) {
3534
 
            inf_norm_at_data->StereoFlags |= INF_STEREO_RAC;
3535
 
        } else {
3536
 
            inf_norm_at_data->StereoFlags |= INF_STEREO_ABS;
3537
 
        }
3538
 
        if ( bRelRac ) {
3539
 
            inf_norm_at_data->StereoFlags |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
3540
 
        }
3541
 
    }
3542
 
    if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
3543
 
       /* display Inv stereo which is Absolute Stereo */
3544
 
        nNumber  = Stereo->nNumberInv;
3545
 
        t_parity = Stereo->t_parityInv;
3546
 
        nOrigAtNosInCanonOrd     = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
3547
 
                                              pINChI_Aux->nOrigAtNosInCanonOrdInv;
3548
 
    } else {
3549
 
       /* display Inv stereo which is Absolute Stereo */
3550
 
        if ( bDoDisplaySp3 ) {
3551
 
            nNumber  = Stereo->nNumber;
3552
 
            t_parity = Stereo->t_parity;
3553
 
        }
3554
 
        nOrigAtNosInCanonOrd     = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
3555
 
                                              pINChI_Aux->nOrigAtNosInCanonOrd;
3556
 
    }
3557
 
 
3558
 
    nConstitEquNumbers       = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
3559
 
                                          pINChI_Aux->nConstitEquNumbers;
3560
 
    nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
3561
 
                                          pINChI_Aux->nConstitEquTGroupNumbers;
3562
 
    memset( inf_norm_at, 0, init_num_at*sizeof(inf_norm_at[0]) );
3563
 
 
3564
 
    /*  obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
3565
 
    nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
3566
 
    if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
3567
 
        goto exit_function;
3568
 
    }
3569
 
    
3570
 
    /*  atom canonical and equivalence numbers > 0 */
3571
 
    for ( i = 0; i < num_at; i ++ ) {
3572
 
        j = (int)nNormAtNosInCanonOrd[i];
3573
 
        if ( j < 0 || j >= num_at )
3574
 
            continue;
3575
 
        inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
3576
 
        inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
3577
 
#ifdef DISPLAY_DEBUG_DATA
3578
 
        inf_norm_at[j].nDebugData = 0;
3579
 
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
3580
 
        inf_norm_at[j].nDebugData = norm_at[j].c_point;
3581
 
#endif
3582
 
#endif
3583
 
    }
3584
 
    /*  tautomeric groups */
3585
 
    if ( nNumberOfTGroups ) {
3586
 
        /*
3587
 
         :   start from 1: bypass number of t-groups
3588
 
         :   j is a counter within the current t-group
3589
 
         :   g is a tautomeric group canonical number
3590
 
         :   e is a tautomeric group equivalence
3591
 
         */
3592
 
        for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
3593
 
            n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /*  number of atoms in t-group */
3594
 
            e = nConstitEquTGroupNumbers[(int)g - 1];
3595
 
            /*  bypass number of hydrogen atoms, negative charges, ... */
3596
 
            for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
3597
 
                /*  scan canonical numbers of atoms within the atom t-group */
3598
 
                k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
3599
 
                inf_norm_at[k].nTautGroupCanonNbr = g;
3600
 
                inf_norm_at[k].nTautGroupEquNbr   = e;
3601
 
            }
3602
 
        }
3603
 
        if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
3604
 
            ret = CT_TAUCOUNT_ERR;  /*   <BRKPT> */
3605
 
            goto exit_function;
3606
 
        }
3607
 
    }
3608
 
    /* atoms that may exchange isotopic H */
3609
 
    if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
3610
 
        for ( i = 1; i < n; i ++ ) {
3611
 
            j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
3612
 
            k = (int)nNormAtNosInCanonOrd[j - 1];
3613
 
            if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
3614
 
                inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
3615
 
            }
3616
 
        }
3617
 
    }
3618
 
 
3619
 
#if( DISPLAY_RING_SYSTEMS == 1 )
3620
 
    /*  debug only */
3621
 
    for ( j = 0; j < num_at; j ++ ) {
3622
 
        inf_norm_at[j].nCanonNbr          = norm_at[j].nBlockSystem;
3623
 
        inf_norm_at[j].nCanonEquNbr       = norm_at[j].nRingSystem;
3624
 
#if( USE_DISTANCES_FOR_RANKING == 1 )
3625
 
        inf_norm_at[j].nTautGroupCanonNbr   = norm_at[j].nDistanceFromTerminal;
3626
 
        inf_norm_at[j].nTautGroupEquNbr     = norm_at[j].bCutVertex;
3627
 
#else
3628
 
        inf_norm_at[j].nTautGroupCanonNbr   = norm_at[j].bCutVertex;
3629
 
        inf_norm_at[j].nTautGroupEquNbr   = 0;
3630
 
#endif
3631
 
    }
3632
 
#endif
3633
 
 
3634
 
 
3635
 
 
3636
 
    /*  Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
3637
 
    len_str = sizeof(inf_norm_at[0].at_string);
3638
 
    for ( i = 0; i < init_num_at; i ++ ) {
3639
 
        str = inf_norm_at[i].at_string;
3640
 
        len = 0;
3641
 
        bIncludeIsotopicH = bIsotopic && !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT);
3642
 
        /*  isotopic mass */
3643
 
        atw = 0;
3644
 
        if ( norm_at[i].iso_atw_diff && bIsotopic ) {
3645
 
            if ( norm_at[i].at_type == ATT_PROTON ) {
3646
 
                ; /* do not set isotopic mass of a tautomeric proton */
3647
 
            } else
3648
 
            if ( norm_at[i].el_number == PERIODIC_NUMBER_H && norm_at[i].chem_bonds_valence == 1 &&
3649
 
                 !norm_at[i].charge && !norm_at[i].radical && !norm_at[i].num_H &&
3650
 
                 (inf_norm_at[j=(int)norm_at[i].neighbor[0]].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
3651
 
                ; /* do not set isotopic mass of an exchangeable proton */
3652
 
            } else {
3653
 
                atw = get_atw(norm_at[i].elname);
3654
 
                atw += (norm_at[i].iso_atw_diff>0)? norm_at[i].iso_atw_diff-1:norm_at[i].iso_atw_diff;
3655
 
                /*len += sprintf( str+len, "^%d", atw );*/
3656
 
            }
3657
 
        }
3658
 
        /*  element name */
3659
 
        if ( norm_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
3660
 
            len += sprintf( str+len, "%s", atw==2? "D" : "T" );
3661
 
        } else {
3662
 
            if ( atw ) {
3663
 
                len += sprintf( str+len, "^%d", atw );
3664
 
            }
3665
 
            len += sprintf( str+len, "%s", norm_at[i].elname );
3666
 
        }
3667
 
        /*  hydrogens */
3668
 
        /*  find number of previuosly removed terminal hydrogen atoms because these terminal H will be displayed */
3669
 
        for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3670
 
            num_iso_H[j] = norm_at[i].num_iso_H[j];
3671
 
        }
3672
 
        /* n = number of implicit H to display */
3673
 
        for ( j = num_at, n = (int)norm_at[i].num_H; j < init_num_at; j ++ ) {
3674
 
            /*  subtract number of removed terminal */
3675
 
            /*  H atoms from the total number of H atoms */
3676
 
            if ( i == (int)norm_at[j].neighbor[0] ) {
3677
 
                n -= 1; /* found explicit H => decrement number of implicit H */
3678
 
                m = (int)norm_at[j].iso_atw_diff-1;
3679
 
                if ( 0 <= m && m < NUM_H_ISOTOPES ) {
3680
 
                    /*  subtract number of removed terminal isotopic H */
3681
 
                    /*  atoms from the total number of isotopic H atoms */
3682
 
                    num_iso_H[m] -= 1;
3683
 
                }
3684
 
            }
3685
 
        }
3686
 
        /* at this point n = number of implicit H to display, 
3687
 
           num_iso_H[] contains number of implicit isotopic H among n */
3688
 
        if ( bIncludeIsotopicH ) {
3689
 
            /*  subtract number of isotopic H atoms from the total number of H atoms */
3690
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3691
 
                n -= num_iso_H[j];
3692
 
            }
3693
 
        }
3694
 
        /*  non-isotopic hydrogen atoms */
3695
 
        if ( n > 1 ) {
3696
 
            len += sprintf( str+len, "H%d", n );
3697
 
        } else
3698
 
        if ( n == 1 ) {
3699
 
            len += sprintf( str+len, "H" );
3700
 
        }
3701
 
        /*  isotopic hydrogen atoms */
3702
 
        if ( bIncludeIsotopicH ) {
3703
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3704
 
                if ( num_iso_H[j] ) {
3705
 
                    if ( j == 0 || j != 1 && j != 2 ) {
3706
 
                        len += sprintf( str+len, "^%dH", j+1 );
3707
 
                    } else {
3708
 
                        len += sprintf( str+len, j == 1? "D" : "T" );
3709
 
                    }
3710
 
                    if ( num_iso_H[j] != 1 ) {
3711
 
                        len += sprintf( str+len, "%d", (int)num_iso_H[j] );
3712
 
                    }
3713
 
                }
3714
 
            }
3715
 
        }
3716
 
        if ( norm_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
3717
 
            char *q;
3718
 
            if ( !str[2] ) {
3719
 
                str[1] = '2';  /* quick fix: replace HH with H2 */
3720
 
            } else
3721
 
            if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
3722
 
                len = 1 + sprintf( str+1, "%d", n+1 );
3723
 
            }
3724
 
        }
3725
 
        /*
3726
 
        if (  str[0] == 'H' && str[1] == 'H' && !str[2] ) {
3727
 
            str[1] = '2';
3728
 
        }
3729
 
        */
3730
 
        /*  charge */
3731
 
        if ( abs(norm_at[i].charge) > 1 )
3732
 
            len += sprintf( str+len, "%+d", norm_at[i].charge );
3733
 
        else
3734
 
        if ( abs(norm_at[i].charge) == 1 )
3735
 
            len += sprintf( str+len, "%s", norm_at[i].charge>0? "+" : "-" );
3736
 
        /*  radical */
3737
 
        if ( norm_at[i].radical )
3738
 
            len += sprintf( str+len, "%s", norm_at[i].radical==RADICAL_SINGLET? ":" :
3739
 
                                           norm_at[i].radical==RADICAL_DOUBLET? "." :
3740
 
                                           norm_at[i].radical==RADICAL_TRIPLET? ".." : "?");
3741
 
    }
3742
 
 
3743
 
    /*  stereogenic centers */
3744
 
    if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
3745
 
        for ( i = 0; i < num_stereo; i ++ ) {
3746
 
            j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
3747
 
            c = t_parity[i];
3748
 
            c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3749
 
            inf_norm_at[j].cStereoCenterParity = c;
3750
 
            str=inf_norm_at[j].at_string;
3751
 
            len = strlen(str);
3752
 
            if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3753
 
                str[len++] = '(';
3754
 
                str[len++] = inf_norm_at[j].cStereoCenterParity;
3755
 
                str[len++] = ')';
3756
 
                str[len] = '\0';
3757
 
                /*  mark ambuguous stereo center */
3758
 
                if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') &&  str[0] != '!' &&
3759
 
                     len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
3760
 
                    memmove( str+1, str, len+1 );
3761
 
                    str[0] = '!'; /* output the atom in red color */
3762
 
                }
3763
 
            }
3764
 
        }
3765
 
    }
3766
 
    
3767
 
    /*  stereogenic bonds */
3768
 
    /*  (cumulenes with odd number of double bonds are stereocenters, */
3769
 
    /*   and atom parity should be set) */
3770
 
    if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
3771
 
        for ( i = 0; i < num_stereo; i ++ ) {
3772
 
            int start_at, num_eql=0, bAmbiguousStereoBond = 0;
3773
 
            j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
3774
 
            k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
3775
 
            start_at = j;
3776
 
            c = Stereo->b_parity[i];
3777
 
                                
3778
 
            c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3779
 
 
3780
 
            /*  mark ambuguous stereo bond atom(s) */
3781
 
            if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
3782
 
                 (len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3783
 
                  str[0] != '!' ) {
3784
 
                memmove( str+1, str, len );
3785
 
                str[0] = '!'; /* output the atom in red color */
3786
 
                bAmbiguousStereoBond ++;
3787
 
            }
3788
 
            if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
3789
 
                 (len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3790
 
                  str[0] != '!' ) {
3791
 
                memmove( str+1, str, len );
3792
 
                str[0] = '!'; /* output the atom in red color */
3793
 
                bAmbiguousStereoBond ++;
3794
 
            }
3795
 
 
3796
 
            /*  find the opposite atom k. */
3797
 
            /*  Note: since it may be a cumulene, find the shortest(best) path */
3798
 
            /*  to atom number k to avoid confusion in case of, for example, */
3799
 
            /*  4-member aromatic rings. */
3800
 
            best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
3801
 
            for ( n = 0; n < norm_at[j].valence; n ++ ) {
3802
 
                if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
3803
 
                    /*  single bond cannot be stereogenic. */
3804
 
                    continue;
3805
 
                }
3806
 
                /* best_len = MAX_CUMULENE_LEN+1; */
3807
 
                len = 0; /*  number of bonds in cumulene - 1 */
3808
 
                next_atom[len]  = (int)norm_at[j].neighbor[n];
3809
 
                next_neigh[len] = n;
3810
 
                cur_atom = j;
3811
 
                while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
3812
 
                    next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0] == cur_atom);
3813
 
                    next_atom[len+1]  =  (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]];
3814
 
                    cur_atom = next_atom[len];
3815
 
                    len ++;
3816
 
                }
3817
 
                if ( next_atom[len] == k ) {
3818
 
                    if ( len < best_len ) {
3819
 
                        memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
3820
 
                        memcpy( best_next_atom,  next_atom,  sizeof(best_next_atom) );
3821
 
                        best_len = len;
3822
 
                        num_eql = 0;
3823
 
                        if ( len == 0 ) {
3824
 
                            break; /*  path length cannot be smaller than 1 */
3825
 
                        }
3826
 
                    } else
3827
 
                    if ( len == best_len ) {
3828
 
                        num_eql ++;
3829
 
                    }
3830
 
                }
3831
 
            }
3832
 
            if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
3833
 
                if ( num_eql ) {
3834
 
                    num_err ++;  /*  program error; no breakpoint here */
3835
 
                }
3836
 
                if ( best_len % 2 ) {
3837
 
                    /*  even number of bonds: chiral atom, draw parity on the cenrtal atom */
3838
 
                    j = best_next_atom[best_len/2];
3839
 
                    inf_norm_at[j].cStereoCenterParity = c;
3840
 
                    str=inf_norm_at[j].at_string;
3841
 
                    len = strlen(str);
3842
 
                    if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3843
 
                        str[len++] = '(';
3844
 
                        str[len++] = inf_norm_at[j].cStereoCenterParity;
3845
 
                        str[len++] = ')';
3846
 
                        str[len] = '\0';
3847
 
                    }
3848
 
                } else {
3849
 
                    /*  odd number of bonds: draw parity on the central bond */
3850
 
                    if ( best_len == 0 ) {
3851
 
                        /*  double bond */
3852
 
                        j = start_at;
3853
 
                        k = best_next_neigh[0];
3854
 
                    } else {
3855
 
                        /*  cumulene */
3856
 
                        best_len = best_len/2-1;
3857
 
                        j = best_next_atom[best_len];
3858
 
                        k = best_next_neigh[best_len+1]; /*  added +1 to display cumulene parity on the middle bond (6-24-2002) */
3859
 
                    }
3860
 
                    /*  mark "forward" bond */
3861
 
                    for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3862
 
                        ;
3863
 
                    if ( m < MAX_STEREO_BONDS ) {
3864
 
                        inf_norm_at[j].cStereoBondParity[m] = c;
3865
 
                        inf_norm_at[j].cStereoBondNumber[m] = k;
3866
 
                        inf_norm_at[j].cStereoBondWarning[m]   = bAmbiguousStereoBond;
3867
 
                    } else {
3868
 
                        num_err ++;  /*  program error; no breakpoint here */
3869
 
                    }
3870
 
                    /*  mark "backward" bond */
3871
 
                    n = norm_at[j].neighbor[k];
3872
 
                    for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]; k ++ )
3873
 
                        ;
3874
 
                    if ( k < norm_at[n].valence ) {
3875
 
                        j = n;
3876
 
                        for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3877
 
                            ;
3878
 
                        if ( m < MAX_STEREO_BONDS ) {
3879
 
                            inf_norm_at[j].cStereoBondParity[m] = c;
3880
 
                            inf_norm_at[j].cStereoBondNumber[m] = k;
3881
 
                            inf_norm_at[j].cStereoBondWarning[m]   = bAmbiguousStereoBond;
3882
 
                        } else {
3883
 
                            num_err ++;  /*  program error; no breakpoint here */
3884
 
                        }
3885
 
                    } else {
3886
 
                        num_err ++;  /*  program error; no breakpoint here */
3887
 
                    }
3888
 
                }
3889
 
            } else {
3890
 
                num_err ++;  /*  program error; no breakpoint here */
3891
 
            }
3892
 
        }
3893
 
    }
3894
 
 
3895
 
    for ( i = 0; i < init_num_at; i ++ ) {
3896
 
        /*  canonical numbers */
3897
 
        if ( inf_norm_at[i].nCanonNbr ) {
3898
 
            str = inf_norm_at[i].at_string;
3899
 
            len = strlen(str);
3900
 
            len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
3901
 
            if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
3902
 
                if ( inf_norm_at[i].nCanonEquNbr ) {
3903
 
                    len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
3904
 
                } else 
3905
 
                if ( len + 1 < len_str ) {
3906
 
                    len += 1;
3907
 
                    strcat( str, "/" );
3908
 
                }
3909
 
            }
3910
 
            /*  tautomeric groups */
3911
 
            if ( inf_norm_at[i].nTautGroupCanonNbr ) {
3912
 
                len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
3913
 
                if ( inf_norm_at[i].nTautGroupEquNbr ) {
3914
 
                    len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
3915
 
                }
3916
 
            }
3917
 
            if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
3918
 
                str[len++] = '/';
3919
 
                str[len++] = '*';
3920
 
                str[len]   = '\0';
3921
 
            }
3922
 
#ifdef DISPLAY_DEBUG_DATA
3923
 
            if ( inf_norm_at[i].nDebugData ) {
3924
 
                len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
3925
 
            }
3926
 
#endif
3927
 
        }
3928
 
    }
3929
 
 
3930
 
 
3931
 
exit_function:
3932
 
 
3933
 
    if ( nNormAtNosInCanonOrd )
3934
 
        inchi_free( nNormAtNosInCanonOrd );
3935
 
 
3936
 
 
3937
 
    return ret;
3938
 
}                              
3939
 
/***************************************************************************************/
3940
 
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
3941
 
                           AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
3942
 
                           INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
3943
 
{
3944
 
    int          i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
3945
 
    int          next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
3946
 
    int          next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len, bIncludeIsotopicH;
3947
 
    int          num_iso_H[NUM_H_ISOTOPES];
3948
 
    char        *str;
3949
 
    AT_NUMB      g, e;
3950
 
    int          num_at           = pINChI->nNumberOfAtoms;
3951
 
    int          num_H            = init_num_at - num_at; /* number of removed H */
3952
 
    int          nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
3953
 
    AT_NUMB     *nOrigAtNosInCanonOrd;
3954
 
    INChI_Stereo *Stereo;
3955
 
    AT_NUMB     *nConstitEquNumbers;
3956
 
    AT_NUMB     *nConstitEquTGroupNumbers;
3957
 
    S_CHAR      *t_parity = NULL;
3958
 
    AT_NUMB     *nNumber = NULL;
3959
 
 
3960
 
    AT_NUMB     *nNormAtNosInCanonOrd;
3961
 
    int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
3962
 
    int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
3963
 
    int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
3964
 
    int bRelRac= bRel || bRac;
3965
 
    int bDoDisplaySp3 = 1;
3966
 
 
3967
 
    inf_ATOM *inf_norm_at   = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset : NULL;
3968
 
    inp_ATOM *norm_at       = inp_norm_at? inp_norm_at + offset : NULL;
3969
 
    inf_ATOM *inf_norm_at_H = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset_H : NULL;
3970
 
    inp_ATOM *norm_at_H     = inp_norm_at? inp_norm_at + offset_H : NULL;
3971
 
 
3972
 
    ret = 0;
3973
 
    num_err = 0;
3974
 
 
3975
 
    if ( !inf_norm_at )
3976
 
        return ret;
3977
 
    /* -- already added in FillOutCompositeCanonInfAtom() --
3978
 
    if ( bIsotopic ) {
3979
 
        for ( i = 0, j = 0; i < NUM_H_ISOTOPES; i ++ ) {
3980
 
            if ( pINChI_Aux->nNumRemovedIsotopicH[i] ) {
3981
 
                inf_norm_at_data->num_iso_H[i] += pINChI_Aux->nNumRemovedIsotopicH[i];
3982
 
                inf_norm_at_data->num_removed_iso_H ++;
3983
 
            }
3984
 
        }
3985
 
    }
3986
 
    */
3987
 
 
3988
 
    if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
3989
 
                        pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
3990
 
        bIsotopic = 0;
3991
 
    
3992
 
    Stereo                   = bIsotopic? pINChI->StereoIsotopic :
3993
 
                                          pINChI->Stereo;
3994
 
    bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
3995
 
 
3996
 
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
3997
 
    if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3998
 
         (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3999
 
        bDoDisplaySp3 = 0;
4000
 
        if ( Stereo->nCompInv2Abs ) {
4001
 
            inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
4002
 
        }
4003
 
    }
4004
 
#endif    
4005
 
    /* flag has stereo */
4006
 
    if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
4007
 
        (*pStereoFlags) |= INF_STEREO;
4008
 
    }
4009
 
 
4010
 
    /*
4011
 
    if ( bDoDisplaySp3 && bRelRac && Stereo->nCompInv2Abs && Stereo->nNumberOfStereoCenters < 2 ) {
4012
 
        bDoDisplaySp3 = 0;
4013
 
    }
4014
 
    */
4015
 
    if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
4016
 
        /* inversion changes stereo */
4017
 
        if ( bRel ) {
4018
 
            (*pStereoFlags) |= INF_STEREO_REL;
4019
 
        } else
4020
 
        if ( bRac ) {
4021
 
            (*pStereoFlags) |= INF_STEREO_RAC;
4022
 
        } else {
4023
 
            (*pStereoFlags) |= INF_STEREO_ABS;
4024
 
        }
4025
 
        if ( bRelRac ) {
4026
 
            (*pStereoFlags) |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
4027
 
        }
4028
 
    }
4029
 
    if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
4030
 
       /* display Inv stereo which is Absolute Stereo */
4031
 
        nNumber  = Stereo->nNumberInv;
4032
 
        t_parity = Stereo->t_parityInv;
4033
 
        nOrigAtNosInCanonOrd     = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
4034
 
                                              pINChI_Aux->nOrigAtNosInCanonOrdInv;
4035
 
    } else {
4036
 
       /* display Output stereo which is Absolute Stereo */
4037
 
        if ( bDoDisplaySp3 ) {
4038
 
            nNumber  = Stereo->nNumber;
4039
 
            t_parity = Stereo->t_parity;
4040
 
        }
4041
 
        nOrigAtNosInCanonOrd     = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
4042
 
                                              pINChI_Aux->nOrigAtNosInCanonOrd;
4043
 
    }
4044
 
 
4045
 
    nConstitEquNumbers       = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
4046
 
                                          pINChI_Aux->nConstitEquNumbers;
4047
 
    nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
4048
 
                                          pINChI_Aux->nConstitEquTGroupNumbers;
4049
 
    memset( inf_norm_at,   0, num_at*sizeof(inf_norm_at[0]) );
4050
 
    if ( num_H > 0 ) {
4051
 
        memset( inf_norm_at_H, 0, num_H*sizeof(inf_norm_at[0]) );
4052
 
    }
4053
 
 
4054
 
    /*  obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
4055
 
    nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
4056
 
    if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
4057
 
        goto exit_function;
4058
 
    }
4059
 
    
4060
 
    /*  atom canonical and equivalence numbers > 0 */
4061
 
    for ( i = 0; i < num_at; i ++ ) {
4062
 
        j = (int)nNormAtNosInCanonOrd[i];
4063
 
        if ( j < 0 || j >= num_at )
4064
 
            continue;
4065
 
        inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
4066
 
        inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
4067
 
#ifdef DISPLAY_DEBUG_DATA
4068
 
        inf_norm_at[j].nDebugData = 0;
4069
 
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
4070
 
        inf_norm_at[j].nDebugData = norm_at[j].c_point;
4071
 
#endif
4072
 
#endif
4073
 
    }
4074
 
    /*  tautomeric groups */
4075
 
    if ( nNumberOfTGroups ) {
4076
 
        /*
4077
 
         :   start from 1: bypass number of t-groups
4078
 
         :   j is a counter within the current t-group
4079
 
         :   g is a tautomeric group canonical number
4080
 
         :   e is a tautomeric group equivalence
4081
 
         */
4082
 
        for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
4083
 
            n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /*  number of atoms in t-group */
4084
 
            e = nConstitEquTGroupNumbers[(int)g - 1];
4085
 
            /*  bypass number of hydrogen atoms, negative charges, ... */
4086
 
            for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
4087
 
                /*  scan canonical numbers of atoms within the atom t-group */
4088
 
                k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
4089
 
                inf_norm_at[k].nTautGroupCanonNbr = g;
4090
 
                inf_norm_at[k].nTautGroupEquNbr   = e;
4091
 
            }
4092
 
        }
4093
 
        if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
4094
 
            ret = CT_TAUCOUNT_ERR;  /*   <BRKPT> */
4095
 
            goto exit_function;
4096
 
        }
4097
 
    }
4098
 
    /* atoms that may exchange isotopic H */
4099
 
    if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
4100
 
        for ( i = 1; i < n; i ++ ) {
4101
 
            j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
4102
 
            k = (int)nNormAtNosInCanonOrd[j - 1];
4103
 
            if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
4104
 
                inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
4105
 
            }
4106
 
        }
4107
 
    }
4108
 
#if( DISPLAY_RING_SYSTEMS == 1 )
4109
 
    /*  debug only */
4110
 
    for ( j = 0; j < num_at; j ++ ) {
4111
 
        inf_norm_at[j].nCanonNbr          = norm_at[j].nBlockSystem;
4112
 
        inf_norm_at[j].nCanonEquNbr       = norm_at[j].nRingSystem;
4113
 
#if( USE_DISTANCES_FOR_RANKING == 1 )
4114
 
        inf_norm_at[j].nTautGroupCanonNbr   = norm_at[j].nDistanceFromTerminal;
4115
 
        inf_norm_at[j].nTautGroupEquNbr     = norm_at[j].bCutVertex;
4116
 
#else
4117
 
        inf_norm_at[j].nTautGroupCanonNbr   = norm_at[j].bCutVertex;
4118
 
        inf_norm_at[j].nTautGroupEquNbr   = 0;
4119
 
#endif
4120
 
    }
4121
 
#endif
4122
 
 
4123
 
 
4124
 
 
4125
 
    /*  Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
4126
 
    len_str = sizeof(inf_norm_at[0].at_string);
4127
 
    for ( i = 0; i < init_num_at; i ++ ) {
4128
 
        inf_ATOM *cur_inf_norm_at = (i < num_at)? inf_norm_at+i : inf_norm_at_H+i-num_at;
4129
 
        inp_ATOM *cur_norm_at     = (i < num_at)? norm_at    +i : norm_at_H    +i-num_at;
4130
 
        str = cur_inf_norm_at->at_string;
4131
 
        len = 0;
4132
 
        bIncludeIsotopicH = bIsotopic && (i >= num_at || !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT));
4133
 
        /*  isotopic mass */
4134
 
        atw = 0;
4135
 
        if ( cur_norm_at->iso_atw_diff && bIsotopic ) {
4136
 
            if ( cur_norm_at->at_type == ATT_PROTON ) {
4137
 
                ; /* do not set isotopic mass of a tautomeric proton */
4138
 
            } else
4139
 
            if ( num_at <= i && cur_norm_at->el_number == PERIODIC_NUMBER_H && cur_norm_at->chem_bonds_valence == 1 &&
4140
 
                 !cur_norm_at->charge && !cur_norm_at->radical && !cur_norm_at->num_H &&
4141
 
                 0 <= (j=(int)cur_norm_at->neighbor[0]-offset) && j < num_at &&
4142
 
                 (inf_norm_at[j].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
4143
 
                ; /* do not set isotopic mass of an exchangeable proton */
4144
 
            } else {
4145
 
                atw = get_atw(cur_norm_at->elname);
4146
 
                atw += (cur_norm_at->iso_atw_diff>0)? cur_norm_at->iso_atw_diff-1:cur_norm_at->iso_atw_diff;
4147
 
                /*len += sprintf( str+len, "^%d", atw );*/
4148
 
            }
4149
 
        }
4150
 
        /*  element name */
4151
 
        if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
4152
 
            len += sprintf( str+len, "%s", atw==2? "D" : "T" );
4153
 
        } else {
4154
 
            if ( atw ) {
4155
 
                len += sprintf( str+len, "^%d", atw );
4156
 
            }
4157
 
            len += sprintf( str+len, "%s", cur_norm_at->elname );
4158
 
        }
4159
 
        /*  hydrogens */
4160
 
        /*  find number of previuosly removed terminal hydrogen atoms */
4161
 
        for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4162
 
            num_iso_H[j] = cur_norm_at->num_iso_H[j];
4163
 
        }
4164
 
        for ( j = 0, n = (int)cur_norm_at->num_H; j < num_H; j ++ ) {
4165
 
            /*  subtract number of removed terminal */
4166
 
            /*  H atoms from the total number of H atoms */
4167
 
            if ( i == (int)norm_at_H[j].neighbor[0]-offset ) {
4168
 
                n -= 1;
4169
 
                m = (int)norm_at_H[j].iso_atw_diff-1;
4170
 
                if ( 0 <= m && m < NUM_H_ISOTOPES ) {
4171
 
                    /*  subtract number of removed terminal isotopic */
4172
 
                    /*  H atoms from the total number of isotopic H atoms */
4173
 
                    num_iso_H[m] -= 1;
4174
 
                }
4175
 
            }
4176
 
        }
4177
 
        if ( bIncludeIsotopicH ) {
4178
 
            /*  subtract number of isotopic H atoms from the total number of H atoms */
4179
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4180
 
                n -= num_iso_H[j];
4181
 
            }
4182
 
        }
4183
 
        /*  non-isotopic hydrogen atoms */
4184
 
        if ( n > 1 ) {
4185
 
            len += sprintf( str+len, "H%d", n );
4186
 
        } else
4187
 
        if ( n == 1 ) {
4188
 
            len += sprintf( str+len, "H" );
4189
 
        }
4190
 
        /*  isotopic hydrogen atoms */
4191
 
        if ( bIncludeIsotopicH ) {
4192
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4193
 
                if ( num_iso_H[j] ) {
4194
 
                    if ( j == 0 || j != 1 && j != 2 ) {
4195
 
                        len += sprintf( str+len, "^%dH", j+1 );
4196
 
                    } else {
4197
 
                        len += sprintf( str+len, j == 1? "D" : "T" );
4198
 
                    }
4199
 
                    if ( num_iso_H[j] != 1 ) {
4200
 
                        len += sprintf( str+len, "%d", (int)num_iso_H[j] );
4201
 
                    }
4202
 
                }
4203
 
            }
4204
 
        }
4205
 
        if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
4206
 
            char *q;
4207
 
            if ( !str[2] ) {
4208
 
                str[1] = '2';  /* quick fix: replace HH with H2 */
4209
 
            } else
4210
 
            if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
4211
 
                len = 1 + sprintf( str+1, "%d", n+1 );
4212
 
            }
4213
 
        }
4214
 
        /*  charge */
4215
 
        if ( abs(cur_norm_at->charge) > 1 )
4216
 
            len += sprintf( str+len, "%+d", cur_norm_at->charge );
4217
 
        else
4218
 
        if ( abs(cur_norm_at->charge) == 1 )
4219
 
            len += sprintf( str+len, "%s", cur_norm_at->charge>0? "+" : "-" );
4220
 
        /*  radical */
4221
 
        if ( cur_norm_at->radical )
4222
 
            len += sprintf( str+len, "%s", cur_norm_at->radical==RADICAL_SINGLET? ":" :
4223
 
                                           cur_norm_at->radical==RADICAL_DOUBLET? "." :
4224
 
                                           cur_norm_at->radical==RADICAL_TRIPLET? ".." : "?");
4225
 
    }
4226
 
 
4227
 
    /*  stereogenic centers */
4228
 
    if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
4229
 
        for ( i = 0; i < num_stereo; i ++ ) {
4230
 
            j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
4231
 
            c = t_parity[i];
4232
 
            c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
4233
 
            inf_norm_at[j].cStereoCenterParity = c;
4234
 
            str=inf_norm_at[j].at_string;
4235
 
            len = strlen(str);
4236
 
            if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
4237
 
                str[len++] = '(';
4238
 
                str[len++] = inf_norm_at[j].cStereoCenterParity;
4239
 
                str[len++] = ')';
4240
 
                str[len] = '\0';
4241
 
                /*  mark ambuguous stereo center */
4242
 
                if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') &&  str[0] != '!' &&
4243
 
                     len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
4244
 
                    memmove( str+1, str, len+1 );
4245
 
                    str[0] = '!'; /* output the atom in red color */
4246
 
                }
4247
 
            }
4248
 
        }
4249
 
    }
4250
 
    
4251
 
    /*  stereogenic bonds */
4252
 
    /*  (cumulenes with odd number of double bonds are stereocenters, */
4253
 
    /*   and atom parity should be set) */
4254
 
    if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
4255
 
        for ( i = 0; i < num_stereo; i ++ ) {
4256
 
            int start_at, num_eql=0, bAmbiguousStereoBond = 0;
4257
 
            j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
4258
 
            k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
4259
 
            start_at = j;
4260
 
            c = Stereo->b_parity[i];
4261
 
                                
4262
 
            c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
4263
 
 
4264
 
            /*  mark ambuguous stereo bond atom(s) */
4265
 
            if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
4266
 
                 (len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
4267
 
                  str[0] != '!' ) {
4268
 
                memmove( str+1, str, len );
4269
 
                str[0] = '!'; /* output the atom in red color */
4270
 
                bAmbiguousStereoBond ++;
4271
 
            }
4272
 
            if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
4273
 
                 (len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
4274
 
                  str[0] != '!' ) {
4275
 
                memmove( str+1, str, len );
4276
 
                str[0] = '!'; /* output the atom in red color */
4277
 
                bAmbiguousStereoBond ++;
4278
 
            }
4279
 
 
4280
 
            /*  find the opposite atom k. */
4281
 
            /*  Note: since it may be a cumulene, find the shortest(best) path */
4282
 
            /*  to atom number k to avoid confusion in case of, for example, */
4283
 
            /*  4-member aromatic rings. */
4284
 
            best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
4285
 
            for ( n = 0; n < norm_at[j].valence; n ++ ) {
4286
 
                if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
4287
 
                    /*  single bond cannot be stereogenic. */
4288
 
                    continue;
4289
 
                }
4290
 
                /* best_len = MAX_CUMULENE_LEN+1; */
4291
 
                len = 0; /*  number of bonds in cumulene - 1 */
4292
 
                next_atom[len]  = (int)norm_at[j].neighbor[n]-offset;
4293
 
                next_neigh[len] = n;
4294
 
                cur_atom = j;
4295
 
                while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
4296
 
                    next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0]-offset == cur_atom);
4297
 
                    next_atom[len+1]  =  (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]]-offset;
4298
 
                    cur_atom = next_atom[len];
4299
 
                    len ++;
4300
 
                }
4301
 
                if ( next_atom[len] == k ) {
4302
 
                    if ( len < best_len ) {
4303
 
                        memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
4304
 
                        memcpy( best_next_atom,  next_atom,  sizeof(best_next_atom) );
4305
 
                        best_len = len;
4306
 
                        num_eql = 0;
4307
 
                        if ( len == 0 ) {
4308
 
                            break; /*  path length cannot be smaller than 1 */
4309
 
                        }
4310
 
                    } else
4311
 
                    if ( len == best_len ) {
4312
 
                        num_eql ++;
4313
 
                    }
4314
 
                }
4315
 
            }
4316
 
            if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
4317
 
                if ( num_eql ) {
4318
 
                    num_err ++;  /*  program error; no breakpoint here */
4319
 
                }
4320
 
                if ( best_len % 2 ) {
4321
 
                    /*  even number of bonds: chiral atom, draw parity on the cenrtal atom */
4322
 
                    j = best_next_atom[best_len/2];
4323
 
                    inf_norm_at[j].cStereoCenterParity = c;
4324
 
                    str=inf_norm_at[j].at_string;
4325
 
                    len = strlen(str);
4326
 
                    if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
4327
 
                        str[len++] = '(';
4328
 
                        str[len++] = inf_norm_at[j].cStereoCenterParity;
4329
 
                        str[len++] = ')';
4330
 
                        str[len] = '\0';
4331
 
                    }
4332
 
                } else {
4333
 
                    /*  odd number of bonds: draw parity on the central bond */
4334
 
                    if ( best_len == 0 ) {
4335
 
                        /*  double bond */
4336
 
                        j = start_at;
4337
 
                        k = best_next_neigh[0];
4338
 
                    } else {
4339
 
                        /*  cumulene */
4340
 
                        best_len = best_len/2-1;
4341
 
                        j = best_next_atom[best_len];
4342
 
                        k = best_next_neigh[best_len+1]; /*  added +1 to display cumulene parity on the middle bond (6-24-2002) */
4343
 
                    }
4344
 
                    /*  mark "forward" bond */
4345
 
                    for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
4346
 
                        ;
4347
 
                    if ( m < MAX_STEREO_BONDS ) {
4348
 
                        inf_norm_at[j].cStereoBondParity[m] = c;
4349
 
                        inf_norm_at[j].cStereoBondNumber[m] = k;
4350
 
                        inf_norm_at[j].cStereoBondWarning[m]  = bAmbiguousStereoBond;
4351
 
                    } else {
4352
 
                        num_err ++;  /*  program error; no breakpoint here */
4353
 
                    }
4354
 
                    /*  mark "backward" bond */
4355
 
                    n = norm_at[j].neighbor[k]-offset;
4356
 
                    for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]-offset; k ++ )
4357
 
                        ;
4358
 
                    if ( k < norm_at[n].valence ) {
4359
 
                        j = n;
4360
 
                        for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
4361
 
                            ;
4362
 
                        if ( m < MAX_STEREO_BONDS ) {
4363
 
                            inf_norm_at[j].cStereoBondParity[m] = c;
4364
 
                            inf_norm_at[j].cStereoBondNumber[m] = k;
4365
 
                            inf_norm_at[j].cStereoBondWarning[m]   = bAmbiguousStereoBond;
4366
 
                        } else {
4367
 
                            num_err ++;  /*  program error; no breakpoint here */
4368
 
                        }
4369
 
                    } else {
4370
 
                        num_err ++;  /*  program error; no breakpoint here */
4371
 
                    }
4372
 
                }
4373
 
            } else {
4374
 
                num_err ++;  /*  program error; no breakpoint here */
4375
 
            }
4376
 
        }
4377
 
    }
4378
 
 
4379
 
    for ( i = 0; i < num_at; i ++ ) {
4380
 
        /*  canonical numbers */
4381
 
        if ( inf_norm_at[i].nCanonNbr ) {
4382
 
            str = inf_norm_at[i].at_string;
4383
 
            len = strlen(str);
4384
 
            len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
4385
 
            if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
4386
 
                if ( inf_norm_at[i].nCanonEquNbr ) {
4387
 
                    len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
4388
 
                } else 
4389
 
                if ( len + 1 < len_str ) {
4390
 
                    len += 1;
4391
 
                    strcat( str, "/" );
4392
 
                }
4393
 
            }
4394
 
            /*  tautomeric groups */
4395
 
            if ( inf_norm_at[i].nTautGroupCanonNbr ) {
4396
 
                len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
4397
 
                if ( inf_norm_at[i].nTautGroupEquNbr ) {
4398
 
                    len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
4399
 
                }
4400
 
            }
4401
 
            if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
4402
 
                str[len++] = '/';
4403
 
                str[len++] = '*';
4404
 
                str[len]   = '\0';
4405
 
            }
4406
 
#ifdef DISPLAY_DEBUG_DATA
4407
 
            if ( inf_norm_at[i].nDebugData ) {
4408
 
                len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
4409
 
            }
4410
 
#endif
4411
 
        }
4412
 
    }
4413
 
 
4414
 
 
4415
 
exit_function:
4416
 
 
4417
 
    if ( nNormAtNosInCanonOrd )
4418
 
        inchi_free( nNormAtNosInCanonOrd );
4419
 
 
4420
 
    return ret;
4421
 
}
4422
 
 
4423
 
/***************************************************************************************/
4424
 
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
4425
 
                        int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers)
4426
 
{
4427
 
    int          i, j, m, n, ret, len_str, len, atw;
4428
 
    int          num_iso_H[NUM_H_ISOTOPES];
4429
 
    char        *str;
4430
 
    int          num_at           = init_num_at - num_removed_H;
4431
 
    int (*MakeNumber)(char*, int, const char*, int) = MakeDecNumber;
4432
 
 
4433
 
    inf_ATOM *inf_at = inf_at_data? inf_at_data->at : NULL;
4434
 
 
4435
 
 
4436
 
    ret = 0;
4437
 
    
4438
 
 
4439
 
    if ( !inf_at )
4440
 
        return ret;
4441
 
 
4442
 
    memset( inf_at, 0, init_num_at*sizeof(inf_at[0]) );
4443
 
 
4444
 
    inf_at_data->nNumRemovedProtons = nNumRemovedProtons;
4445
 
    MakeRemovedProtonsString( nNumRemovedProtons, nNumRemovedProtonsIsotopic, NULL, bIsotopic, inf_at_data->szRemovedProtons, NULL );
4446
 
    /*  atom canonical and equivalence numbers > 0 */
4447
 
    for ( i = 0; i < num_at; i ++ ) {
4448
 
#if( DISPLAY_ORIG_AT_NUMBERS == 1 )
4449
 
        inf_at[i].nCanonNbr = inp_at[i].orig_at_number;
4450
 
#else
4451
 
        inf_at[i].nCanonNbr = (AT_NUMB)(i+1);
4452
 
#endif
4453
 
    }
4454
 
    /*  Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
4455
 
    len_str = sizeof(inf_at[0].at_string);
4456
 
    for ( i = 0; i < init_num_at; i ++ ) {
4457
 
        str = inf_at[i].at_string;
4458
 
        len = 0;
4459
 
        /*  isotopic mass */
4460
 
        atw = 0;
4461
 
        if ( inp_at[i].iso_atw_diff && bIsotopic ) {
4462
 
            atw = get_atw(inp_at[i].elname);
4463
 
            atw += (inp_at[i].iso_atw_diff>0)? inp_at[i].iso_atw_diff-1:inp_at[i].iso_atw_diff;
4464
 
            /*len += sprintf( str+len, "^%d", atw );*/
4465
 
        }
4466
 
        /*  element name */
4467
 
        if ( inp_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
4468
 
            len += sprintf( str+len, "%s", atw==2? "D" : "T" );
4469
 
        } else {
4470
 
            if ( atw ) {
4471
 
                len += sprintf( str+len, "^%d", atw );
4472
 
            }
4473
 
            len += sprintf( str+len, "%s", inp_at[i].elname );
4474
 
        }
4475
 
        /*  hydrogens */
4476
 
        /*  find number of previuosly removed terminal hydrogen atoms */
4477
 
        for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4478
 
            num_iso_H[j] = inp_at[i].num_iso_H[j];
4479
 
        }
4480
 
        for ( j = num_at, n = (int)inp_at[i].num_H; j < init_num_at; j ++ ) {
4481
 
            /*  subtract number of removed terminal */
4482
 
            /*  H atoms from the total number of H atoms */
4483
 
            if ( i == (int)inp_at[j].neighbor[0] ) {
4484
 
                n -= 1;
4485
 
                m = (int)inp_at[j].iso_atw_diff-1;
4486
 
                if ( 0 <= m && m < NUM_H_ISOTOPES ) {
4487
 
                    /*  subtract number of removed terminal isotopic */
4488
 
                    /*  H atoms from the total number of isotopic H atoms */
4489
 
                    num_iso_H[m] -= 1;
4490
 
                }
4491
 
            }
4492
 
        }
4493
 
        if ( bIsotopic && !bAdd_DT_to_num_H ) {
4494
 
            /*  subtract number of isotopic H atoms from the total number of H atoms */
4495
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4496
 
                n -= num_iso_H[j];
4497
 
            }
4498
 
        }
4499
 
        /*  non-isotopic hydrogen atoms */
4500
 
        if ( n > 1 ) {
4501
 
            len += sprintf( str+len, "H%d", n );
4502
 
        } else
4503
 
        if ( n == 1 ) {
4504
 
            len += sprintf( str+len, "H" ); /* fixed 12-21-2002: removed 3rd argument */
4505
 
        }
4506
 
        if ( bIsotopic ) {
4507
 
            /*  isotopic hydrogen atoms */
4508
 
            for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
4509
 
                if ( num_iso_H[j] ) {
4510
 
                    if ( j == 0 || j != 1 && j != 2 ) {
4511
 
                        len += sprintf( str+len, "^%dH", j+1 );
4512
 
                    } else {
4513
 
                        len += sprintf( str+len, j == 1? "D" : "T" );
4514
 
                    }
4515
 
                    if ( num_iso_H[j] != 1 ) {
4516
 
                        len += sprintf( str+len, "%d", (int)num_iso_H[j] );
4517
 
                    }
4518
 
                }
4519
 
            }
4520
 
        }
4521
 
        if ( inp_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
4522
 
            char *q;
4523
 
            if ( !str[2] ) {
4524
 
                str[1] = '2';  /* quick fix: replace HH with H2 */
4525
 
            } else
4526
 
            if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
4527
 
                len = 1 + sprintf( str+1, "%d", n+1 );
4528
 
            }
4529
 
        }
4530
 
        /*
4531
 
        if (  str[0] == 'H' && str[1] == 'H' && !str[2] ) {
4532
 
            str[1] = '2';
4533
 
        }
4534
 
        */
4535
 
        /*  charge */
4536
 
        if ( abs(inp_at[i].charge) > 1 )
4537
 
            len += sprintf( str+len, "%+d", inp_at[i].charge );
4538
 
        else
4539
 
        if ( abs(inp_at[i].charge) == 1 )
4540
 
            len += sprintf( str+len, "%s", inp_at[i].charge>0? "+" : "-" );
4541
 
        /*  radical */
4542
 
        if ( inp_at[i].radical )
4543
 
            len += sprintf( str+len, "%s", inp_at[i].radical==RADICAL_SINGLET? ":" :
4544
 
                                           inp_at[i].radical==RADICAL_DOUBLET? "." :
4545
 
                                           inp_at[i].radical==RADICAL_TRIPLET? ".." : "?");
4546
 
    }
4547
 
 
4548
 
    for ( i = 0; i < init_num_at; i ++ ) {
4549
 
        /*  canonical numbers */
4550
 
        if ( inf_at[i].nCanonNbr ) {
4551
 
            str = inf_at[i].at_string;
4552
 
            len = strlen(str);
4553
 
            len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonNbr );
4554
 
            if ( inf_at[i].nCanonEquNbr || inf_at[i].nTautGroupCanonNbr ) {
4555
 
                len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonEquNbr );
4556
 
            }
4557
 
            /*  tautomeric groups */
4558
 
            if ( inf_at[i].nTautGroupCanonNbr ) {
4559
 
                len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupCanonNbr );
4560
 
                if ( inf_at[i].nTautGroupEquNbr ) {
4561
 
                    len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupEquNbr );
4562
 
                }
4563
 
            }
4564
 
        }
4565
 
    }
4566
 
    ret = init_num_at;
4567
 
 
4568
 
    return ret;
4569
 
}
4570
 
/**********************************************************************************************/
4571
 
int FillOutInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int num_removed_H,
4572
 
                   int bAdd_DT_to_num_H, int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic,
4573
 
                   INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode )
4574
 
{
4575
 
    if ( norm_at && inf_norm_at_data && inf_norm_at_data->at ) {
4576
 
        if ( pINChI && pINChI_Aux ) {
4577
 
            return FillOutCanonInfAtom( norm_at, inf_norm_at_data, init_num_at, bIsotopic, pINChI,
4578
 
                                        pINChI_Aux, bAbcNumbers, nMode);
4579
 
        } else {
4580
 
            return FillOutInputInfAtom( norm_at, inf_norm_at_data, init_num_at, num_removed_H, bAdd_DT_to_num_H,
4581
 
                                        nNumRemovedProtons, nNumRemovedProtonsIsotopic, bIsotopic, bAbcNumbers);
4582
 
        }
4583
 
    }
4584
 
    return 0;
4585
 
}
4586
 
/***************************************************************************************/
4587
 
int FillOutCompositeCanonInfAtom(COMP_ATOM_DATA *composite_norm_data, INF_ATOM_DATA *inf_norm_at_data,
4588
 
                                 int bIsotopic, int bTautomeric,
4589
 
                                 PINChI2 *pINChI2, PINChI_Aux2 *pINChI_Aux2, int bAbcNumbers, INCHI_MODE nMode)
4590
 
{
4591
 
    int i, num_components, j, k, ret;
4592
 
    inp_ATOM *inp_norm_at;
4593
 
    INChI     *pINChI;
4594
 
    INChI_Aux *pINChI_Aux;
4595
 
    int      num_inp_at, num_at, num_H, offset, offset_H, next_offset, next_offset_H;
4596
 
 
4597
 
    if ( composite_norm_data && inf_norm_at_data && (bTautomeric == TAUT_INI || pINChI2 && pINChI_Aux2) ) {
4598
 
        composite_norm_data += bTautomeric;
4599
 
        inp_norm_at          = composite_norm_data->at;
4600
 
        num_components       = composite_norm_data->num_components;
4601
 
        offset   = 0;
4602
 
        offset_H = composite_norm_data->num_at - composite_norm_data->num_removed_H;
4603
 
        if ( bTautomeric == TAUT_INI ) {
4604
 
            ret = FillOutInputInfAtom( composite_norm_data->at, inf_norm_at_data, composite_norm_data->num_at,
4605
 
                                       composite_norm_data->num_removed_H, 0 /*bAdd_DT_to_num_H*/,
4606
 
                                       composite_norm_data->nNumRemovedProtons,
4607
 
                                       composite_norm_data->nNumRemovedProtonsIsotopic,
4608
 
                                       bIsotopic, bAbcNumbers);
4609
 
            return ret;
4610
 
        } else {
4611
 
            for ( i = 0; i < num_components; i ++ ) {
4612
 
                j = inchi_min(bTautomeric, TAUT_YES);
4613
 
                /* count isotopic H on removed atoms -- isolated H(+) cations */
4614
 
                inf_norm_at_data->nNumRemovedProtons += pINChI_Aux2[i][j]->nNumRemovedProtons;
4615
 
                if ( bIsotopic && bTautomeric == TAUT_YES ) {
4616
 
                    for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
4617
 
                        if ( pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k] ) {
4618
 
                            inf_norm_at_data->num_iso_H[k] += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
4619
 
                            inf_norm_at_data->num_removed_iso_H += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
4620
 
                        }
4621
 
                    }
4622
 
                }
4623
 
                /* ignore deleted components */
4624
 
                if ( pINChI2[i][j] && pINChI2[i][j]->bDeleted ) {
4625
 
                    continue;
4626
 
                }
4627
 
                if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
4628
 
                    j = ALT_TAUT(j);
4629
 
                    if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
4630
 
                        continue; /* error ??? */
4631
 
                    }
4632
 
                }
4633
 
                pINChI     = pINChI2[i][j];
4634
 
                pINChI_Aux = pINChI_Aux2[i][j];
4635
 
                next_offset   = composite_norm_data->nOffsetAtAndH[2*i];
4636
 
                next_offset_H = composite_norm_data->nOffsetAtAndH[2*i+1];
4637
 
                num_at   = next_offset - offset;
4638
 
                if ( num_at <= 0 )
4639
 
                    continue;
4640
 
                num_H    = next_offset_H - offset_H;
4641
 
                num_inp_at = num_at + num_H;
4642
 
                if ( num_at != pINChI->nNumberOfAtoms || num_at != pINChI_Aux->nNumberOfAtoms ) {
4643
 
                    return 0; /* error */
4644
 
                }
4645
 
                ret =  FillOutOneCanonInfAtom(inp_norm_at, inf_norm_at_data,
4646
 
                               inf_norm_at_data->pStereoFlags+i+1, num_inp_at,
4647
 
                               offset, offset_H, bIsotopic, pINChI, pINChI_Aux, bAbcNumbers, nMode);
4648
 
                if ( ret )
4649
 
                    return 0; /* error */
4650
 
 
4651
 
                inf_norm_at_data->StereoFlags |= inf_norm_at_data->pStereoFlags[i+1];
4652
 
                offset   = next_offset;
4653
 
                offset_H = next_offset_H;
4654
 
            }
4655
 
        }
4656
 
        MakeRemovedProtonsString( inf_norm_at_data->nNumRemovedProtons, inf_norm_at_data->num_iso_H, NULL, bIsotopic,
4657
 
                                  inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
4658
 
    }
4659
 
    return 1;
4660
 
}
4661
 
#endif /* } ifndef INCHI_ANSI_ONLY */
4662
 
/**********************************************************************************************/
4663
 
int CheckCanonNumberingCorrectness(int num_atoms, int num_at_tg,
4664
 
                 sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
4665
 
                 char *pStrErrStruct )
4666
 
{
4667
 
    int i, ret=0;
4668
 
    AT_NUMB *pCanonOrd=NULL;
4669
 
    int nErrorCode = 0;
4670
 
    AT_NUMB *pCanonRank; /* canonical ranks of the atoms or tautomeric groups */
4671
 
    AT_NUMB *pCanonRankAtoms=NULL;
4672
 
    
4673
 
    static int count=0; /* for debug only */
4674
 
    count ++;
4675
 
 
4676
 
    pCanonRankAtoms = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pCanonRankAtoms[0]) );
4677
 
    
4678
 
    /**********************************************************************************************
4679
 
     *
4680
 
     *  non-isotopic part
4681
 
     */
4682
 
    pCanonOrd            = pCS->nLenCanonOrdStereo > 0? pCS->nCanonOrdStereo :
4683
 
                           pCS->nLenCanonOrd       > 0? pCS->nCanonOrd : NULL;
4684
 
    pCanonRank           = pCanonRankAtoms;
4685
 
    if ( pCanonOrd && pCanonRank ) {
4686
 
        for ( i = 0; i < num_at_tg; i ++ ) {
4687
 
            pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
4688
 
        }
4689
 
        ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
4690
 
        if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
4691
 
            nErrorCode     |= WARN_FAILED_STEREO;
4692
 
        }
4693
 
 
4694
 
    } else {
4695
 
        nErrorCode  |= ERR_NO_CANON_RESULTS;
4696
 
        goto exit_function;
4697
 
    }
4698
 
    /**********************************************************************************************
4699
 
     *
4700
 
     *  isotopic part
4701
 
     */
4702
 
    pCanonOrd   = pCS->nLenCanonOrdIsotopicStereo > 0? pCS->nCanonOrdIsotopicStereo :
4703
 
                  pCS->nLenCanonOrdIsotopic       > 0? pCS->nCanonOrdIsotopic : NULL;
4704
 
    pCanonRank  = pCanonRankAtoms;
4705
 
 
4706
 
    if ( pCanonOrd && pCanonRank ) {
4707
 
        for ( i = 0; i < num_at_tg; i ++ ) {
4708
 
            pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
4709
 
        }
4710
 
        ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
4711
 
        if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
4712
 
            nErrorCode     |= (pCS->nLenCanonOrdIsotopicStereo? WARN_FAILED_ISOTOPIC_STEREO : WARN_FAILED_ISOTOPIC);
4713
 
        }
4714
 
 
4715
 
    }
4716
 
 
4717
 
exit_function:
4718
 
    if ( pCanonRankAtoms )
4719
 
        inchi_free( pCanonRankAtoms );
4720
 
 
4721
 
    if ( nErrorCode ) {
4722
 
        return CT_CANON_ERR;
4723
 
    }
4724
 
    return 0;
4725
 
}