rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,3812 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+ #include <ctype.h>
14
+
15
+ #include "mode.h"
16
+
17
+ #if( TEST_RENUMB_ATOMS == 1 )
18
+ #include "ichitime.h"
19
+ #endif
20
+ #include "inpdef.h"
21
+ #include "ichi.h"
22
+ #include "strutil.h"
23
+ #include "util.h"
24
+ #include "extr_ct.h"
25
+ #include "ichitaut.h"
26
+ #include "ichinorm.h"
27
+ #include "ichicant.h"
28
+ #include "ichicano.h"
29
+ #include "ichicomn.h"
30
+
31
+ #include "ichicomp.h"
32
+ #include "ichimain.h"
33
+ #include "ichimake.h"
34
+ #include "ichister.h"
35
+
36
+ int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at );
37
+ int GetElementAndCount( const char **f, char *szEl, int *count );
38
+ int CompareHillFormulas( const char *f1, const char *f2 );
39
+ int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 );
40
+ int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 );
41
+ int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
42
+ AT_NUMB *nOrigAtNosInCanonOrd, int num_at );
43
+ int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
44
+ INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
45
+ int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
46
+ AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
47
+ INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
48
+ int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
49
+ int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers);
50
+
51
+ int CheckCanonNumberingCorrectness(
52
+ int num_atoms, int num_at_tg,
53
+ sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
54
+ char *pStrErrStruct );
55
+
56
+ static int CompareDfsDescendants4CT( const void *a1, const void *a2 );
57
+ int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo );
58
+
59
+
60
+ #if( TEST_RENUMB_ATOMS == 1 ) /* { */
61
+ int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 );
62
+ #endif
63
+
64
+ /**********************************************************************************************/
65
+ int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at )
66
+ {
67
+ int i, j, val;
68
+ memset( at, 0, sizeof(at[0])*num_inp_at );
69
+ for ( i = 0; i < num_inp_at; i ++ ) {
70
+ strncpy( at[i].elname, inp_at[i].elname, sizeof(at[0].elname) );
71
+ at[i].el_number = (U_CHAR)get_periodic_table_number( at[i].elname );
72
+ val = at[i].valence = inp_at[i].valence;
73
+ for ( j = 0; j < val; j ++ ) {
74
+ at[i].neighbor[j] = inp_at[i].neighbor[j];
75
+ at[i].bond_type[j] = inp_at[i].bond_type[j];
76
+ }
77
+ at[i].chem_bonds_valence = inp_at[i].chem_bonds_valence;
78
+ at[i].orig_at_number = inp_at[i].orig_at_number;
79
+ at[i].orig_compt_at_numb= inp_at[i].orig_compt_at_numb;
80
+ at[i].endpoint = inp_at[i].endpoint;
81
+ at[i].iso_atw_diff = inp_at[i].iso_atw_diff;
82
+ at[i].num_H = inp_at[i].num_H;
83
+ at[i].cFlags = inp_at[i].cFlags;
84
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
85
+ at[i].num_iso_H[j] = inp_at[i].num_iso_H[j];
86
+ }
87
+ at[i].charge = inp_at[i].charge;
88
+ at[i].radical = inp_at[i].radical;
89
+
90
+ #if( FIND_RING_SYSTEMS == 1 )
91
+ at[i].nBlockSystem = inp_at[i].nBlockSystem;
92
+ at[i].bCutVertex = inp_at[i].bCutVertex;
93
+ at[i].nRingSystem = inp_at[i].nRingSystem;
94
+ at[i].nNumAtInRingSystem = inp_at[i].nNumAtInRingSystem;
95
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
96
+ at[i].nDistanceFromTerminal = inp_at[i].nDistanceFromTerminal;
97
+ #endif
98
+ #endif
99
+
100
+ /*
101
+ at[i].x = inp_at[i].x;
102
+ at[i].y = inp_at[i].y;
103
+ at[i].z = inp_at[i].z;
104
+ */
105
+ }
106
+ return 0;
107
+ }
108
+ /**********************************************************************************************/
109
+ int GetElementAndCount( const char **f, char *szEl, int *count )
110
+ {
111
+ const char *p = *f;
112
+ char *q;
113
+ int i = 0;
114
+ if ( *p ) {
115
+ if ( isupper( UCINT *p ) ) {
116
+ szEl[i++] = *p++;
117
+ if ( *p && islower( UCINT *p ) ) {
118
+ szEl[i++] = *p++;
119
+ }
120
+ szEl[i] = '\0';
121
+ if ( 1 == i && szEl[0] == 'C' ) {
122
+ szEl[0] = 'A'; /* less than any element: */
123
+ /* carbon-containing compounds should be first */
124
+ }
125
+ if ( *p && isdigit( UCINT *p ) ) {
126
+ *count = strtol( p, &q, 10 );
127
+ p = q;
128
+ } else {
129
+ *count = 1;
130
+ }
131
+ *f = p; /* next element; */
132
+ return 1;
133
+ }
134
+ return -1; /* not a chemical formula */
135
+ }
136
+ strcpy( szEl, "Zz" ); /* zero termination 'element' is larger than any other element */
137
+ *count = 9999; /* zero termination 'element count' is larger than any other count */
138
+ return 0;
139
+ }
140
+ /**********************************************************************************************
141
+
142
+ E1 < E2 if strcmp( E1, E2) < 0 OR E2 is empty and E1 is not
143
+ n1 < n2 if value n1 > n2
144
+
145
+ Sorting order:
146
+
147
+ C10H22N
148
+ C10H22
149
+ C2
150
+ Ag2Cl2
151
+ Ag2Cl
152
+ Ag2F2
153
+ Ag2
154
+ AgCl
155
+ AgF
156
+ F6S
157
+ F2S
158
+
159
+ **********************************************************************************************/
160
+ int CompareHillFormulas( const char *f1, const char *f2 )
161
+ {
162
+ char szEl1[4], szEl2[4];
163
+ int count1, count2, ret1, ret2, ret;
164
+
165
+ do {
166
+ ret1 = GetElementAndCount( &f1, szEl1, &count1 );
167
+ ret2 = GetElementAndCount( &f2, szEl2, &count2 );
168
+ if ( 0 <= ret1 && 0 <= ret2 ) {
169
+ if ( ret = strcmp( szEl1, szEl2 ) ) {
170
+ return ret; /* lexicographic order, string termination > any character */
171
+ }
172
+ if ( ret = count2 - count1 ) {
173
+ return ret; /* inverse atom count order */
174
+ }
175
+ } else {
176
+ return 0; /* program error <BRKPT> */
177
+ }
178
+
179
+ } while ( 0 < ret1 && 0 < ret2 );
180
+
181
+ return 0;
182
+ }
183
+ /**********************************************************************************************/
184
+ int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 )
185
+ {
186
+ char szEl1[4], szEl2[4];
187
+ int count1, count2, ret1, ret2, ret;
188
+
189
+ do {
190
+ ret1 = GetElementAndCount( &f1, szEl1, &count1 );
191
+ if ( 0 < ret1 && szEl1[0] == 'H' && !szEl1[1] ) {
192
+ *num_H1 += count1;
193
+ ret1 = GetElementAndCount( &f1, szEl1, &count1 );
194
+ }
195
+ ret2 = GetElementAndCount( &f2, szEl2, &count2 );
196
+ if ( 0 < ret2 && szEl2[0] == 'H' && !szEl2[1] ) {
197
+ *num_H2 += count2;
198
+ ret2 = GetElementAndCount( &f2, szEl2, &count2 );
199
+ }
200
+ if ( 0 <= ret1 && 0 <= ret2 ) {
201
+ if ( ret = strcmp( szEl1, szEl2 ) ) {
202
+ return ret; /* lexicographic order, string termination > any character */
203
+ }
204
+ if ( ret = count2 - count1 ) {
205
+ return ret; /* inverse atom count order */
206
+ }
207
+ } else {
208
+ return 0; /* program error <BRKPT> */
209
+ }
210
+
211
+ } while ( 0 < ret1 && 0 < ret2 );
212
+
213
+ return 0;
214
+ }
215
+
216
+ /**************************************************************/
217
+ int CompareTautNonIsoPartOfINChI( const INChI *i1, const INChI *i2 )
218
+ {
219
+ int len1, len2, ret, i;
220
+
221
+ len1 = i1->lenTautomer > 0 && i1->nTautomer[0]? i1->lenTautomer:0;
222
+ len2 = i2->lenTautomer > 0 && i2->nTautomer[0]? i2->lenTautomer:0;
223
+ if ( ret = len2 - len1 ) {
224
+ return ret;
225
+ }
226
+ for ( i = 0; i < len1; i ++ ) {
227
+ if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
228
+ return ret;
229
+ }
230
+ return 0;
231
+ }
232
+
233
+ /**********************************************************************************************/
234
+ /* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
235
+ /**********************************************************************************************/
236
+ int CompINChITautVsNonTaut(const INCHI_SORT *p1, const INCHI_SORT *p2, int bCompareIsotopic)
237
+ {
238
+ int ret, num, i, num_H1, num_H2;
239
+
240
+ const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
241
+ const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
242
+
243
+ int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
244
+
245
+ /* INChI_Stereo *Stereo1, *Stereo2; */
246
+
247
+ n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
248
+
249
+ i1 = p1->pINChI[n1];
250
+ i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
251
+ p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
252
+
253
+
254
+ /* non-deleted-non-empty < deleted < empty */
255
+ if ( i1 && !i2 )
256
+ return 0; /* non-empty is the smallest (first) */
257
+ if ( !i1 && i2 )
258
+ return 0;
259
+ if ( !i1 && !i2 )
260
+ return 0;
261
+ if ( i1->bDeleted )
262
+ return 1; /* deleted is the largest (last) among non-empty */
263
+ if ( i2->bDeleted )
264
+ return -1;
265
+
266
+ if ( i1->nNumberOfAtoms > 0 && !i2->nNumberOfAtoms )
267
+ return 0;
268
+
269
+ i2 = i2;
270
+
271
+ num_H1 = num_H2 = 0;
272
+
273
+ /* do not compare terminal H */
274
+ if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
275
+ return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
276
+ }
277
+
278
+ /*********************************************************
279
+ compare non-isotopic non-tautomeric part
280
+ *********************************************************/
281
+
282
+ /* compare number of atoms (excluding terminal H) */
283
+ if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
284
+ return ret; /* more atoms first */
285
+
286
+ /* compare elements (excluding terminal H) */
287
+ num = i1->nNumberOfAtoms;
288
+ for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
289
+ if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
290
+ return ret; /* greater periodic number first */
291
+ }
292
+ /**********************************************************
293
+ compare connection tables
294
+ ***********************************************************/
295
+ if ( ret = i2->lenConnTable - i1->lenConnTable )
296
+ return ret; /* longer connection table first */
297
+ num = i2->lenConnTable;
298
+ for ( i = 0; i < num; i ++ ) {
299
+ if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
300
+ return ret; /* greater connection table first */
301
+ }
302
+ /*********************************************************
303
+ compare compare total number of H (inverse: H3 < H2 )
304
+ **********************************************************/
305
+ if ( ret = num_H2 - num_H1 )
306
+ return ret;
307
+ /*********************************************************
308
+ compare non-tautomeric num_H: N < NH3 < NH2 < NH
309
+ **********************************************************/
310
+ num = i1->nNumberOfAtoms;
311
+ for ( i = 0; i < num; i ++ ) {
312
+ if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
313
+ return !i2->nNum_H[i]? 1 : /* no H first */
314
+ !i1->nNum_H[i]? -1 :
315
+ (int)i2->nNum_H[i] - (int)i1->nNum_H[i];
316
+ }
317
+ }
318
+ /*********************************************************
319
+ compare non-isotopic tautomeric part
320
+ *********************************************************/
321
+ if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
322
+ return ret;
323
+ }
324
+ /*
325
+ if ( ret = i2->lenTautomer - i1->lenTautomer )
326
+ return ret;
327
+ num = inchi_min( i2->lenTautomer, i1->lenTautomer );
328
+ for ( i = 0; i < num; i ++ ) {
329
+ if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
330
+ return ret;
331
+ }
332
+ */
333
+ /*********************************************************
334
+ * *
335
+ * at this point both components are either tautomeric *
336
+ * or non-tautomeric *
337
+ * *
338
+ *********************************************************/
339
+
340
+ /*********************************************************
341
+ non-tautomeric "fixed H" specific
342
+ *********************************************************/
343
+ if ( /*TAUT_NON == bTaut &&*/ (i2 && i2->nNum_H_fixed ) ) {
344
+ /* first, compare non-tautomeric chem. formulas -- they may be different */
345
+ /* secondly, compare fixed-H distribution */
346
+ if ( i2->nNum_H_fixed ) {
347
+ num = i2->nNumberOfAtoms;
348
+ for ( i = 0; i < num; i ++ ) {
349
+ if ( i2->nNum_H_fixed[i] != 0 ) {
350
+ return 1;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ /*********************************************************
356
+ compare non-isotopic stereo
357
+ *********************************************************/
358
+ ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
359
+ if ( ret ) {
360
+ return ret;
361
+ }
362
+ /*******************************************************
363
+ do not switch back to tautomeric i1, i2
364
+ *******************************************************/
365
+ /* -- how to switch back --
366
+ if ( i1t ) {
367
+ i1 = i1t;
368
+ i1t = NULL;
369
+ }
370
+ if ( i2t ) {
371
+ i2 = i2t;
372
+ i2t = NULL;
373
+ }
374
+ */
375
+ /******************************************************
376
+ compare isotopic non-tautomeric part
377
+ ******************************************************/
378
+ if ( bCompareIsotopic ) {
379
+ if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
380
+ return ret;
381
+ num = i1->nNumberOfIsotopicAtoms;
382
+ /* compare isotopic atoms */
383
+ for ( i = 0; i < num; i ++ ) {
384
+ if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
385
+ return ret;
386
+ if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
387
+ return ret;
388
+ }
389
+ /* compare isotopic H */
390
+ /* if tautomeric comparison mode then here are compared only non-tautomeric H */
391
+ for ( i = 0; i < num; i ++ ) {
392
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
393
+ return ret;
394
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
395
+ return ret;
396
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
397
+ return ret;
398
+ }
399
+ /*****************************************************
400
+ compare isotopic tautomeric part
401
+ *****************************************************/
402
+ if ( ret = i2->nNumberOfIsotopicTGroups || i1->nNumberOfIsotopicTGroups )
403
+ return ret;
404
+ /*
405
+ num = i1->nNumberOfIsotopicTGroups;
406
+ for ( i = 0; i < num; i ++ ) {
407
+ if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
408
+ return ret;
409
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
410
+ return ret;
411
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
412
+ return ret;
413
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
414
+ return ret;
415
+ }
416
+ */
417
+ /****************************************************
418
+ compare isotopic stereo
419
+ ****************************************************/
420
+ ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
421
+ if ( ret ) {
422
+ return ret;
423
+ }
424
+
425
+ }
426
+
427
+
428
+ /**********************************************************
429
+ compare charges: non-charged first, then in order of
430
+ ascending charges (negative first)
431
+ ***********************************************************/
432
+ if ( i2->nTotalCharge && i1->nTotalCharge ) {
433
+ /* both are charged; smaller charges first */
434
+ ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
435
+ return ret;
436
+ }
437
+ if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
438
+ /* only one is charged; uncharged first */
439
+ return ret;
440
+ }
441
+ /* stable sort */
442
+ /*ret = p1->ord_number - p2->ord_number;*/
443
+
444
+ return ret;
445
+ }
446
+
447
+ /*************************** stereo ***********************************************************/
448
+ typedef enum tagSp3StereoTypeTmp {
449
+ SP3_NONE = 0, /* no sp3 stereo: no /t, /m, /s segments */
450
+ /* /t is present: */
451
+ SP3_ONLY = 1, /* no /s or /m segment: inversion leaves the structure unchanged */
452
+ SP3_ABS = 2, /* abs stereo: both /m and /s are present */
453
+ SP3_REL = 4, /* rel stereo: /s is present, /m is not */
454
+ SP3_RAC = 8, /* racemic stereo: /s is presen, /m is nott */
455
+ SP3_TYPE = (SP3_ABS|SP3_REL|SP3_RAC), /* bitmap for checking the presence of /m */
456
+ SP3_ANY = (SP3_ABS|SP3_REL|SP3_RAC|SP3_ONLY) /* bitmap for checking the presence of /t */
457
+ } SP3_TYPE_TMP;
458
+
459
+ /**********************************************************************************************/
460
+ int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo )
461
+ {
462
+ int nRet = SP3_NONE;
463
+ if ( pINChI && !pINChI->bDeleted && Stereo && 0 < Stereo->nNumberOfStereoCenters ) {
464
+ if ( 0 != Stereo->nCompInv2Abs ) {
465
+ if ( pINChI->nFlags & INCHI_FLAG_REL_STEREO ) {
466
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
467
+ if ( 1 < Stereo->nNumberOfStereoCenters ) {
468
+ nRet = SP3_REL;
469
+ }
470
+ #else
471
+ nRet = SP3_REL;
472
+ #endif
473
+ } else
474
+ if ( pINChI->nFlags & INCHI_FLAG_RAC_STEREO ) {
475
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
476
+ if ( 1 < Stereo->nNumberOfStereoCenters ) {
477
+ nRet = SP3_REL;
478
+ }
479
+ #else
480
+ nRet = SP3_RAC;
481
+ #endif
482
+ } else {
483
+ nRet = SP3_ABS;
484
+ }
485
+ } else
486
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
487
+ if ( !(( pINChI->nFlags & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO) ) && 1 == Stereo->nNumberOfStereoCenters) )
488
+ #endif
489
+ {
490
+ nRet = SP3_ONLY; /* SP3_NONE if relative stereo and 1 stereocenter */
491
+ }
492
+ }
493
+ return nRet;
494
+ }
495
+
496
+ /* char sDifSegs[DIFL_LENGTH][DIFS_LENGTH]; */
497
+
498
+ /**********************************************************************************************/
499
+ /* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
500
+ /**********************************************************************************************/
501
+ int CompINChILayers(const INCHI_SORT *p1, const INCHI_SORT *p2, char sDifSegs[][DIFS_LENGTH] )
502
+ {
503
+ int ret = 0, num, i, num_H1, num_H2;
504
+
505
+ const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
506
+ const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
507
+
508
+ int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
509
+
510
+ INChI_Stereo *Stereo1, *Stereo2;
511
+ INChI_Stereo *IsoStereo1, *IsoStereo2;
512
+ int bRelRac[DIFL_LENGTH];
513
+ char *psDifSegs;
514
+
515
+ n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
516
+
517
+ i1 = p1->pINChI[n1];
518
+ i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
519
+ p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
520
+
521
+ num_H1 = num_H2 = 0;
522
+ memset( bRelRac, DIFV_BOTH_EMPTY, sizeof(bRelRac) );
523
+ /*=====================*/
524
+ /*==== /f ======*/
525
+ /*=====================*/
526
+ if ( i1 && !i1->bDeleted && i1->szHillFormula && i1->szHillFormula[0] ) {
527
+ sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
528
+ if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
529
+ if ( !CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) &&
530
+ num_H1 == num_H2 ) {
531
+ sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_EQL2PRECED;
532
+ } else {
533
+ sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
534
+ }
535
+ } else {
536
+ sDifSegs[DIFL_F][DIFS_f_FORMULA] |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
537
+ }
538
+ } else {
539
+ sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
540
+ if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
541
+ sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
542
+ } else {
543
+ sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
544
+ }
545
+ }
546
+ /*=====================*/
547
+ /*==== /c ======*/
548
+ /*=====================*/
549
+ if ( i1 && !i1->bDeleted && i1->lenConnTable > 1 ) {
550
+ sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
551
+ } else {
552
+ sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
553
+ }
554
+ /*=====================*/
555
+ /*==== /h ======*/
556
+ /*=====================*/
557
+ /* M: H atoms */
558
+ if ( i1 && !i1->bDeleted ) {
559
+ num_H1 = (i1->lenTautomer > 0 && i1->nTautomer && i1->nTautomer[0])? 1 : 0; /* number of t-groups */
560
+ if ( !num_H1 && i1->nNum_H ) {
561
+ for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) { /* immobile H */
562
+ if ( i1->nNum_H[i] ) {
563
+ num_H1 = 1;
564
+ break;
565
+ }
566
+ }
567
+ }
568
+ sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= num_H1? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
569
+ } else {
570
+ sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
571
+ }
572
+ /* F: fixed mobile H */
573
+ if ( i2 && !i2->bDeleted && i2->nNum_H_fixed ) {
574
+ num_H2 = 0;
575
+ if ( i1 && !i1->bDeleted ) {
576
+ for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
577
+ if ( i2->nNum_H_fixed[i] ) {
578
+ num_H2 = 1;
579
+ break;
580
+ }
581
+ }
582
+ }
583
+ sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= num_H2? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
584
+ } else {
585
+ sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
586
+ }
587
+ /* MI: exchangable isotopic H: see OutputINChI1(), num_iso_H[] */
588
+
589
+ /*=====================*/
590
+ /*==== /q ======*/
591
+ /*=====================*/
592
+ psDifSegs = &sDifSegs[DIFL_F][DIFS_q_CHARGE];
593
+ if ( i1 && !i1->bDeleted ) {
594
+ if ( i1->nTotalCharge ) {
595
+ sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
596
+ } else {
597
+ sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
598
+ }
599
+ if ( i2 && !i2->bDeleted ) {
600
+ if ( i1->nTotalCharge ) {
601
+ if ( i1->nTotalCharge == i2->nTotalCharge ) {
602
+ *psDifSegs |= DIFV_EQL2PRECED;
603
+ } else
604
+ if ( i2->nTotalCharge ) {
605
+ *psDifSegs |= DIFV_NEQ2PRECED;
606
+ } else {
607
+ *psDifSegs |= DIFV_IS_EMPTY;
608
+ }
609
+ } else {
610
+ if ( i2->nTotalCharge ) {
611
+ *psDifSegs |= DIFV_NEQ2PRECED;
612
+ } else {
613
+ *psDifSegs |= DIFV_BOTH_EMPTY;
614
+ }
615
+ }
616
+ } else
617
+ if ( !i2 ) {
618
+ *psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
619
+ } else {
620
+ /* i2 && i2->bDeleted */
621
+ *psDifSegs |= i1->nTotalCharge? DIFV_IS_EMPTY : DIFV_BOTH_EMPTY;
622
+ }
623
+ } else {
624
+ sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
625
+ if ( i2 && !i2->bDeleted ) {
626
+ if ( i2->nTotalCharge ) {
627
+ sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
628
+ } else {
629
+ sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
630
+ }
631
+ }
632
+ }
633
+ /*************** stereo *****************/
634
+ if ( i1 && !i1->bDeleted ) {
635
+ Stereo1 = i1->Stereo;
636
+ IsoStereo1 = i1->StereoIsotopic;
637
+ } else {
638
+ Stereo1 = NULL;
639
+ IsoStereo1 = NULL;
640
+ }
641
+ if ( i2 && !i2->bDeleted ) {
642
+ Stereo2 = i2->Stereo;
643
+ IsoStereo2 = i2->StereoIsotopic;
644
+ } else {
645
+ Stereo2 = NULL;
646
+ IsoStereo2 = NULL;
647
+ }
648
+ /*=====================*/
649
+ /*==== /b ======*/
650
+ /*=====================*/
651
+ /* M double bond stereo */
652
+ psDifSegs = &sDifSegs[DIFL_M][DIFS_b_SBONDS];
653
+ if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
654
+ *psDifSegs |= DIFV_NEQ2PRECED;
655
+ } else {
656
+ *psDifSegs |= DIFV_BOTH_EMPTY;
657
+ }
658
+ /* F double bond stereo */
659
+ psDifSegs = &sDifSegs[DIFL_F][DIFS_b_SBONDS];
660
+ if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
661
+ if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
662
+ if ( Eql_INChI_Stereo( Stereo1, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
663
+ *psDifSegs |= DIFV_EQL2PRECED;
664
+ } else {
665
+ *psDifSegs |= DIFV_NEQ2PRECED;
666
+ }
667
+ } else {
668
+ *psDifSegs |= DIFV_NEQ2PRECED;
669
+ }
670
+ } else {
671
+ if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
672
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
673
+ } else {
674
+ *psDifSegs |= DIFV_BOTH_EMPTY;
675
+ }
676
+ }
677
+ /* MI double bond stereo */
678
+ psDifSegs = &sDifSegs[DIFL_MI][DIFS_b_SBONDS];
679
+ if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds ) {
680
+ if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP2, Stereo1, EQL_SP2, 0 ) ) {
681
+ *psDifSegs |= DIFV_EQL2PRECED;
682
+ } else {
683
+ *psDifSegs |= DIFV_NEQ2PRECED;
684
+ }
685
+ } else {
686
+ if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
687
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
688
+ } else {
689
+ *psDifSegs |= DIFV_BOTH_EMPTY;
690
+ }
691
+ }
692
+ /* FI double bond stereo */
693
+ psDifSegs = &sDifSegs[DIFL_FI][DIFS_b_SBONDS];
694
+ if ( IsoStereo2 && IsoStereo2->nNumberOfStereoBonds ) {
695
+ if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
696
+ *psDifSegs |= DIFV_EQL2PRECED;
697
+ } else {
698
+ if ( !(Stereo1 && Stereo1->nNumberOfStereoBonds) &&
699
+ !(Stereo2 && Stereo2->nNumberOfStereoBonds) &&
700
+ Eql_INChI_Stereo( IsoStereo2, EQL_SP2, IsoStereo1, EQL_SP2, 0 ) ) {
701
+ *psDifSegs |= DIFV_FI_EQ_MI;
702
+ } else {
703
+ *psDifSegs |= DIFV_NEQ2PRECED;
704
+ }
705
+ }
706
+ } else {
707
+ /* the solution table for FI stereo,
708
+ in case of FI stereo is empty
709
+ E = segment is empty, NE = not empty
710
+ +==============================+
711
+ | M | MI | F | result |
712
+ +=====+=====+=====+============+
713
+ | E | E | E | both empty |
714
+ +-----+-----+-----+------------+
715
+ | NE | E | E | both empty |
716
+ +-----+-----+-----+------------+
717
+ | E | NE | E | is empty |
718
+ +-----+-----+-----+------------+
719
+ | NE | NE | E | both empty |
720
+ +-----+-----+-----+------------+
721
+ | E | E | NE | is empty |
722
+ +-----+-----+-----+------------+
723
+ | NE | E | NE | is empty |
724
+ +-----+-----+-----+------------+
725
+ | E | NE | NE | is empty |
726
+ +-----+-----+-----+------------+
727
+ | NE | NE | ME | is empty |
728
+ +==============================+
729
+ */
730
+ if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
731
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
732
+ } else
733
+ if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds &&
734
+ !(Stereo1 && Stereo1->nNumberOfStereoBonds)
735
+ ) {
736
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
737
+ } else {
738
+ *psDifSegs |= DIFV_BOTH_EMPTY;
739
+ }
740
+ }
741
+ /*==================================*/
742
+ /*==== /t, /m, /s for M ======*/
743
+ /*==================================*/
744
+ /* M sp3 stereo */
745
+ bRelRac[DIFL_M ] = GetSp3RelRacAbs( i1, Stereo1 );
746
+ bRelRac[DIFL_MI] = GetSp3RelRacAbs( i1, IsoStereo1 );
747
+ bRelRac[DIFL_F ] = GetSp3RelRacAbs( i2, Stereo2 );
748
+ bRelRac[DIFL_FI] = GetSp3RelRacAbs( i2, IsoStereo2 );
749
+ if ( SP3_NONE != bRelRac[DIFL_M] ) {
750
+ sDifSegs[DIFL_M][DIFS_t_SATOMS] |= (bRelRac[DIFL_M] & SP3_ANY)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
751
+ sDifSegs[DIFL_M][DIFS_m_SP3INV] |= (bRelRac[DIFL_M] & SP3_ABS)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
752
+ sDifSegs[DIFL_M][DIFS_s_STYPE] |= (bRelRac[DIFL_M] & SP3_TYPE)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
753
+ } else {
754
+ sDifSegs[DIFL_M][DIFS_t_SATOMS] |= DIFV_BOTH_EMPTY;
755
+ sDifSegs[DIFL_M][DIFS_m_SP3INV] |= DIFV_BOTH_EMPTY;
756
+ sDifSegs[DIFL_M][DIFS_s_STYPE] |= DIFV_BOTH_EMPTY;
757
+ }
758
+ /*=====================*/
759
+ /*==== /t ======*/
760
+ /*=====================*/
761
+ /* F sp3 stereo */
762
+ psDifSegs = &sDifSegs[DIFL_F][DIFS_t_SATOMS];
763
+ if ( SP3_ANY & bRelRac[DIFL_F] ) {
764
+ if ( Eql_INChI_Stereo( Stereo2, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
765
+ *psDifSegs |= DIFV_EQL2PRECED;
766
+ } else {
767
+ *psDifSegs |= DIFV_NEQ2PRECED;
768
+ }
769
+ } else
770
+ if ( SP3_ANY & bRelRac[DIFL_M] ) {
771
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
772
+ } else {
773
+ *psDifSegs |= DIFV_BOTH_EMPTY;
774
+ }
775
+ /* MI sp3 stereo */
776
+ psDifSegs = &sDifSegs[DIFL_MI][DIFS_t_SATOMS];
777
+ if ( SP3_ANY & bRelRac[DIFL_MI] ) {
778
+ if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
779
+ *psDifSegs |= DIFV_EQL2PRECED;
780
+ } else {
781
+ *psDifSegs |= DIFV_NEQ2PRECED;
782
+ }
783
+ } else
784
+ if ( SP3_ANY & bRelRac[DIFL_M] ) {
785
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
786
+ } else {
787
+ *psDifSegs |= DIFV_BOTH_EMPTY;
788
+ }
789
+ /* FI sp3 stereo */
790
+ psDifSegs = &sDifSegs[DIFL_FI][DIFS_t_SATOMS];
791
+ if ( SP3_ANY & bRelRac[DIFL_FI] ) {
792
+ if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP3, Stereo2, EQL_SP3, 0 ) ) {
793
+ *psDifSegs |= DIFV_EQL2PRECED;
794
+ } else
795
+ if ( !(SP3_ANY & bRelRac[DIFL_M]) &&
796
+ !(SP3_ANY & bRelRac[DIFL_F]) &&
797
+ Eql_INChI_Stereo( IsoStereo2, EQL_SP3, IsoStereo1, EQL_SP3, 0 ) ) {
798
+ *psDifSegs |= DIFV_FI_EQ_MI;
799
+ } else {
800
+ *psDifSegs |= DIFV_NEQ2PRECED;
801
+ }
802
+ } else /* similar to /b */
803
+ if ( (SP3_ANY & bRelRac[DIFL_F]) ) {
804
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
805
+ } else
806
+ if ( (SP3_ANY & bRelRac[DIFL_MI]) && !(SP3_ANY & bRelRac[DIFL_M]) ) {
807
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
808
+ } else {
809
+ *psDifSegs |= DIFV_BOTH_EMPTY;
810
+ }
811
+ /*=====================*/
812
+ /*==== /m ======*/
813
+ /*=====================*/
814
+ /* F sp3 abs stereo inversion */
815
+ psDifSegs = &sDifSegs[DIFL_F][DIFS_m_SP3INV];
816
+ if ( bRelRac[DIFL_F] & SP3_ABS ) {
817
+ /* the order of || operands below is critically important: || is not a commutative operation */
818
+ if ( !(bRelRac[DIFL_M] & SP3_ABS) || Stereo2->nCompInv2Abs != Stereo1->nCompInv2Abs ) {
819
+ *psDifSegs |= DIFV_NEQ2PRECED;
820
+ } else {
821
+ *psDifSegs |= DIFV_EQL2PRECED;
822
+ }
823
+ } else
824
+ if ( bRelRac[DIFL_M] & SP3_ABS ) {
825
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
826
+ } else {
827
+ *psDifSegs |= DIFV_BOTH_EMPTY;
828
+ }
829
+ /* MI sp3 abs stereo inversion */
830
+ psDifSegs = &sDifSegs[DIFL_MI][DIFS_m_SP3INV];
831
+ if ( SP3_ABS & bRelRac[DIFL_MI] ) {
832
+ if ( (SP3_ABS & bRelRac[DIFL_M]) && IsoStereo1->nCompInv2Abs == Stereo1->nCompInv2Abs ) {
833
+ *psDifSegs |= DIFV_EQL2PRECED;
834
+ } else {
835
+ *psDifSegs |= DIFV_NEQ2PRECED;
836
+ }
837
+ } else
838
+ if ( SP3_ABS & bRelRac[DIFL_M] ) {
839
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
840
+ } else {
841
+ *psDifSegs |= DIFV_BOTH_EMPTY;
842
+ }
843
+ /* FI sp3 abs stereo inversion */
844
+ psDifSegs = &sDifSegs[DIFL_FI][DIFS_m_SP3INV];
845
+ if ( SP3_ABS & bRelRac[DIFL_FI] ) {
846
+ if ( (SP3_ABS & bRelRac[DIFL_F]) && IsoStereo2->nCompInv2Abs == Stereo2->nCompInv2Abs ) {
847
+ *psDifSegs |= DIFV_EQL2PRECED;
848
+ } else
849
+ if ( !(SP3_ABS & bRelRac[DIFL_M]) &&
850
+ !(SP3_ABS & bRelRac[DIFL_F]) &&
851
+ (SP3_ABS & bRelRac[DIFL_MI]) && /* make sure IsoStereo1 != NULL */
852
+ IsoStereo2->nCompInv2Abs == IsoStereo1->nCompInv2Abs ) {
853
+ *psDifSegs |= DIFV_FI_EQ_MI;
854
+ } else {
855
+ *psDifSegs |= DIFV_NEQ2PRECED;
856
+ }
857
+ } else /* similar to /b */
858
+ /* the order of || operands below is critically important: || is no a commutative operation */
859
+ if ( (SP3_ABS & bRelRac[DIFL_F]) ) {
860
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
861
+ } else
862
+ if ( (SP3_ABS & bRelRac[DIFL_MI]) && !(SP3_ABS & bRelRac[DIFL_M]) ) {
863
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
864
+ } else {
865
+ *psDifSegs |= DIFV_BOTH_EMPTY;
866
+ }
867
+ /*=====================*/
868
+ /*==== /s ======*/
869
+ /*=====================*/
870
+ /* F sp3 stereo type */
871
+ psDifSegs = &sDifSegs[DIFL_F][DIFS_s_STYPE];
872
+ if ( bRelRac[DIFL_F] & SP3_TYPE ) {
873
+ if ( (bRelRac[DIFL_F] & SP3_TYPE) == (bRelRac[DIFL_M] & SP3_TYPE) ) {
874
+ *psDifSegs |= DIFV_EQL2PRECED;
875
+ } else {
876
+ *psDifSegs |= DIFV_NEQ2PRECED;
877
+ }
878
+ } else
879
+ if ( bRelRac[DIFL_M] & SP3_TYPE ) {
880
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
881
+ } else {
882
+ *psDifSegs |= DIFV_BOTH_EMPTY;
883
+ }
884
+ /* MI sp3 stereo type */
885
+ psDifSegs = &sDifSegs[DIFL_MI][DIFS_s_STYPE];
886
+ if ( SP3_TYPE & bRelRac[DIFL_MI] ) {
887
+ if ( (SP3_TYPE & bRelRac[DIFL_MI]) == (SP3_TYPE & bRelRac[DIFL_M]) ) {
888
+ *psDifSegs |= DIFV_EQL2PRECED;
889
+ } else {
890
+ *psDifSegs |= DIFV_NEQ2PRECED;
891
+ }
892
+ } else
893
+ if ( SP3_TYPE & bRelRac[DIFL_M] ) {
894
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
895
+ } else {
896
+ *psDifSegs |= DIFV_BOTH_EMPTY;
897
+ }
898
+ /* FI sp3 stereo type */
899
+ psDifSegs = &sDifSegs[DIFL_FI][DIFS_s_STYPE];
900
+ if ( SP3_TYPE & bRelRac[DIFL_FI] ) {
901
+ if ( (SP3_TYPE & bRelRac[DIFL_FI]) == (SP3_TYPE & bRelRac[DIFL_F]) ) {
902
+ *psDifSegs |= DIFV_EQL2PRECED;
903
+ } else
904
+ if ( !(SP3_TYPE & bRelRac[DIFL_M]) &&
905
+ !(SP3_TYPE & bRelRac[DIFL_F]) &&
906
+ (SP3_TYPE & bRelRac[DIFL_MI]) ) {
907
+ *psDifSegs |= DIFV_FI_EQ_MI;
908
+ } else {
909
+ *psDifSegs |= DIFV_NEQ2PRECED;
910
+ }
911
+ } else /* similar to /b */
912
+ /* the order of || operands below is critically important: || is not a commutative operation */
913
+ if ( (SP3_TYPE & bRelRac[DIFL_F]) ) {
914
+ *psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
915
+ } else
916
+ if ( (SP3_TYPE & bRelRac[DIFL_MI]) && !(SP3_TYPE & bRelRac[DIFL_M]) ) {
917
+ *psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
918
+ } else {
919
+ *psDifSegs |= DIFV_BOTH_EMPTY;
920
+ }
921
+ /*=====================*/
922
+ /*==== /o ======*/
923
+ /*=====================*/
924
+ if ( p1 && p2 && p1->ord_number != p2->ord_number ) {
925
+ sDifSegs[DIFL_F][DIFS_o_TRANSP] |= DIFV_NEQ2PRECED;
926
+ }
927
+ /*=====================*/
928
+ /*==== /i ======*/
929
+ /*=====================*/
930
+ /* M isotopic atoms */
931
+ psDifSegs = &sDifSegs[DIFL_MI][DIFS_i_IATOMS];
932
+ if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
933
+ *psDifSegs |= DIFV_NEQ2PRECED;
934
+ } else {
935
+ *psDifSegs |= DIFV_BOTH_EMPTY;
936
+ }
937
+ /* F isotopic atoms */
938
+ psDifSegs = &sDifSegs[DIFL_FI][DIFS_i_IATOMS];
939
+ if ( i2 && !i2->bDeleted ) {
940
+ if ( i2->nNumberOfIsotopicAtoms || i2->nNumberOfIsotopicTGroups ) {
941
+ if ( !i1 || i1->bDeleted ||
942
+ i2->nNumberOfIsotopicAtoms != i1->nNumberOfIsotopicAtoms ||
943
+ i2->nNumberOfIsotopicTGroups != i1->nNumberOfIsotopicTGroups ) {
944
+ *psDifSegs |= DIFV_NEQ2PRECED;
945
+ } else {
946
+ int diff;
947
+ num = i1->nNumberOfIsotopicAtoms;
948
+ diff = 0;
949
+ for ( i = 0; i < num; i ++ ) {
950
+ /* compare isotopic atoms */
951
+ if ( diff = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
952
+ break;
953
+ if ( diff = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
954
+ break;
955
+ /* compare isotopic H */
956
+ if ( diff = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
957
+ break;
958
+ if ( diff = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
959
+ break;
960
+ if ( diff = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
961
+ break;
962
+ }
963
+ if ( !diff ) {
964
+ num = i1->nNumberOfIsotopicTGroups;
965
+ for ( i = 0; i < num; i ++ ) {
966
+ if ( diff = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
967
+ break;
968
+ if ( diff = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
969
+ break;
970
+ if ( diff = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
971
+ return diff;
972
+ if ( diff = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
973
+ break;
974
+ }
975
+ }
976
+ *psDifSegs |= diff? DIFV_NEQ2PRECED : DIFV_FI_EQ_MI;
977
+
978
+ }
979
+ } else
980
+ if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
981
+ *psDifSegs |= DIFV_IS_EMPTY;
982
+ }
983
+ } else
984
+ if ( !i2 ) {
985
+ if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
986
+ *psDifSegs |= DIFV_EQL2PRECED;
987
+ } else {
988
+ *psDifSegs |= DIFV_BOTH_EMPTY;
989
+ }
990
+ }
991
+
992
+ return ret;
993
+ }
994
+ /**********************************************************************************************/
995
+ int INChI_SegmentAction( char cDifSegs )
996
+ {
997
+ if ( !(cDifSegs & DIFV_OUTPUT_OMIT_F) ) {
998
+ return INCHI_SEGM_OMIT;
999
+ }
1000
+ if ( (cDifSegs & DIFV_OUTPUT_EMPTY_T) && !(cDifSegs & DIFV_OUTPUT_EMPTY_F) ) {
1001
+ return INCHI_SEGM_EMPTY;
1002
+ }
1003
+ if ( (cDifSegs & DIFV_OUTPUT_FILL_T) ) {
1004
+ return INCHI_SEGM_FILL;
1005
+ }
1006
+ return INCHI_SEGM_OMIT; /* the control flow shoul never reach this point */
1007
+ }
1008
+ /**********************************************************************************************/
1009
+ int MarkUnusedAndEmptyLayers( char sDifSegs[][DIFS_LENGTH] )
1010
+ {
1011
+ /****************************************************
1012
+ 1. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1013
+ and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1014
+ and there is NO succeeding non-empty layer then mark the 1st element
1015
+ of the layer DIFV_BOTH_EMPTY; this layerr will be omitted.
1016
+
1017
+ 2. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1018
+ and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1019
+ and there IS a succeeding non-empty layer then mark the 1st element
1020
+ of the layer DIFV_IS_EMPTY and all other elements DIFV_BOTH_EMPTY;
1021
+ only the first empty segment of this layerr will be output.
1022
+
1023
+ 3. If NOT all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
1024
+ and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
1025
+ and the 1st element of the layer is DIFV_BOTH_EMPTY then mark it
1026
+ DIFV_IS_EMPTY; it will be output as empty (except M layer).
1027
+ */
1028
+
1029
+ int i, nLayer, sBits, nFirstSegm;
1030
+ #define nFirstFmlSegm DIFS_f_FORMULA
1031
+ #define nFirstIsoSegm DIFS_i_IATOMS
1032
+ /* FI */
1033
+ nLayer = DIFL_FI;
1034
+ nFirstSegm = nFirstIsoSegm;
1035
+ sBits = 0;
1036
+ for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1037
+ sBits |= sDifSegs[nLayer][i];
1038
+ }
1039
+ if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1040
+ /* Omit the FI layer */
1041
+ memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1042
+ } else
1043
+ if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1044
+ !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1045
+ sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1046
+ }
1047
+
1048
+ /* MI */
1049
+ nLayer = DIFL_MI;
1050
+ nFirstSegm = nFirstIsoSegm;
1051
+ sBits = 0;
1052
+ for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1053
+ sBits |= sDifSegs[nLayer][i];
1054
+ }
1055
+ if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
1056
+ /* Omit the MI layer */
1057
+ memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1058
+ } else
1059
+ if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1060
+ !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1061
+ sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1062
+ }
1063
+
1064
+ /* F */
1065
+ nLayer = DIFL_F;
1066
+ nFirstSegm = nFirstFmlSegm;
1067
+ sBits = 0;
1068
+ for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
1069
+ sBits |= sDifSegs[nLayer][i];
1070
+ }
1071
+ if ( !(sBits & DIFV_OUTPUT_OMIT_F) &&
1072
+ sDifSegs[DIFL_FI][nFirstIsoSegm] == DIFV_BOTH_EMPTY ) {
1073
+ /* Omit the F layer: no non-iotopic and no isotopic segments */
1074
+ memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
1075
+ } else
1076
+ /* do not omit fixed-H layer */
1077
+ if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
1078
+ !(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
1079
+ sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
1080
+ }
1081
+
1082
+ /* M -- leave as it is */
1083
+ return 0;
1084
+ #undef nFirstFmlSegm
1085
+ #undef nFirstIsoSegm
1086
+ }
1087
+ /*********************************************************************************************/
1088
+ int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 )
1089
+ {
1090
+ int i, num, ret;
1091
+ if ( Stereo2 && Stereo1 ) {
1092
+ /* compare stereogenic bonds */
1093
+ num = inchi_min( Stereo2->nNumberOfStereoBonds, Stereo1->nNumberOfStereoBonds );
1094
+ for ( i = 0; i < num; i ++ ) {
1095
+ if ( ret = (int)Stereo2->nBondAtom1[i] - (int)Stereo1->nBondAtom1[i] )
1096
+ return ret;
1097
+ if ( ret = (int)Stereo2->nBondAtom2[i] - (int)Stereo1->nBondAtom2[i] )
1098
+ return ret;
1099
+ if ( ret = (int)Stereo2->b_parity[i] - (int)Stereo1->b_parity[i] )
1100
+ return ret;
1101
+ }
1102
+ if ( ret = (int)Stereo2->nNumberOfStereoBonds - (int)Stereo1->nNumberOfStereoBonds )
1103
+ return ret;
1104
+ /* compare stereogenic atoms */
1105
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1106
+ if ( ((nFlags1 | nFlags2) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) ) &&
1107
+ 1 == Stereo2->nNumberOfStereoCenters &&
1108
+ 1 == Stereo1->nNumberOfStereoCenters ) {
1109
+ ; /* do not compare single stereocenters in case of relative stereo */
1110
+ } else
1111
+ #endif
1112
+ {
1113
+ num = inchi_min( Stereo2->nNumberOfStereoCenters, Stereo1->nNumberOfStereoCenters );
1114
+ for ( i = 0; i < num; i ++ ) {
1115
+ if ( ret = (int)Stereo2->nNumber[i] - (int)Stereo1->nNumber[i] )
1116
+ return ret;
1117
+ if ( ret = (int)Stereo2->t_parity[i] - (int)Stereo1->t_parity[i] )
1118
+ return ret;
1119
+ }
1120
+ if ( ret = (int)Stereo2->nNumberOfStereoCenters - (int)Stereo1->nNumberOfStereoCenters )
1121
+ return ret;
1122
+ /* compare stereo-abs-is-inverted flags for non-relative, non-racemic */
1123
+ if ( !((nFlags1 | nFlags2) & (INCHI_FLAG_RAC_STEREO | INCHI_FLAG_REL_STEREO)) ) {
1124
+ if ( ret = (Stereo2->nCompInv2Abs < 0) - (Stereo1->nCompInv2Abs < 0) ) {
1125
+ return ret;
1126
+ }
1127
+ }
1128
+ }
1129
+ } else
1130
+ if ( Stereo2 && ( Stereo2->nNumberOfStereoBonds > 0 ||
1131
+ Stereo2->nNumberOfStereoCenters > 0
1132
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1133
+ && /* do not compare single stereocenters in case of relative stereo */
1134
+ !((nFlags2 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1135
+ 1 == Stereo2->nNumberOfStereoCenters
1136
+ )
1137
+ #endif
1138
+ ) ) {
1139
+ return 1;
1140
+ }else
1141
+ if ( Stereo1 && ( Stereo1->nNumberOfStereoBonds > 0 ||
1142
+ Stereo1->nNumberOfStereoCenters > 0
1143
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
1144
+ && /* do not compare single stereocenters in case of relative stereo */
1145
+ !((nFlags1 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
1146
+ 1 == Stereo1->nNumberOfStereoCenters
1147
+ )
1148
+ #endif
1149
+ ) ) {
1150
+ return -1;
1151
+ }
1152
+ return 0;
1153
+ }
1154
+ /**********************************************************************************************/
1155
+ /* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
1156
+ /**********************************************************************************************/
1157
+ int CompINChI2(const INCHI_SORT *p1, const INCHI_SORT *p2, int bTaut, int bCompareIsotopic)
1158
+ {
1159
+ int ret, num, i, num_H1, num_H2;
1160
+
1161
+ const INChI *i1 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1162
+ const INChI *i2 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
1163
+
1164
+ int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
1165
+ int n2; /* TAUT_YES if tautomeric i2 exists, otherwise TAUT_NON */
1166
+
1167
+ const INChI *i1n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1168
+ const INChI *i2n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
1169
+
1170
+ /*const INChI *i1t = NULL;*/ /* temp for i1 if both tautomeric AND non-tautomeric exist */
1171
+ /*const INChI *i2t = NULL;*/ /* temp for i2 if both tautomeric AND non-tautomeric exist */
1172
+
1173
+
1174
+ /* INChI_Stereo *Stereo1, *Stereo2; */
1175
+
1176
+ n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1177
+ n2 = ( p2->pINChI[TAUT_YES] && p2->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
1178
+
1179
+ i1 = p1->pINChI[n1];
1180
+ i1n = (n1 == TAUT_YES && p1->pINChI[TAUT_NON] &&
1181
+ p1->pINChI[TAUT_NON]->nNumberOfAtoms)? p1->pINChI[TAUT_NON] : (const INChI *)NULL;
1182
+
1183
+ i2 = p2->pINChI[n2];
1184
+ i2n = (n2 == TAUT_YES && p2->pINChI[TAUT_NON] &&
1185
+ p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
1186
+
1187
+ /* non-deleted-non-empty < deleted < empty */
1188
+ if ( i1 && !i2 )
1189
+ return -1; /* non-empty is the smallest (first) */
1190
+ if ( !i1 && i2 )
1191
+ return 1;
1192
+ if ( !i1 && !i2 )
1193
+ return 0;
1194
+ if ( i1->bDeleted && !i2->bDeleted )
1195
+ return 1; /* deleted is the largest (last) among non-empty */
1196
+ if ( !i1->bDeleted && i2->bDeleted )
1197
+ return -1;
1198
+
1199
+ num_H1 = num_H2 = 0;
1200
+
1201
+ /* do not compare terminal H */
1202
+ if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
1203
+ return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
1204
+ }
1205
+
1206
+ /*********************************************************
1207
+ compare non-isotopic non-tautomeric part
1208
+ *********************************************************/
1209
+
1210
+ /* compare number of atoms (excluding terminal H) */
1211
+ if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
1212
+ return ret; /* more atoms first */
1213
+
1214
+ /* compare elements (excluding terminal H) */
1215
+ num = i1->nNumberOfAtoms;
1216
+ for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
1217
+ if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
1218
+ return ret; /* greater periodic number first */
1219
+ }
1220
+ /**********************************************************
1221
+ compare connection tables
1222
+ ***********************************************************/
1223
+ if ( ret = i2->lenConnTable - i1->lenConnTable )
1224
+ return ret; /* longer connection table first */
1225
+ num = i2->lenConnTable;
1226
+ for ( i = 0; i < num; i ++ ) {
1227
+ if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
1228
+ return ret; /* greater connection table first */
1229
+ }
1230
+ /*********************************************************
1231
+ compare compare total number of H (inverse: H3 < H2 )
1232
+ **********************************************************/
1233
+ if ( ret = num_H2 - num_H1 )
1234
+ return ret;
1235
+ /*********************************************************
1236
+ compare non-tautomeric num_H: N < NH3 < NH2 < NH
1237
+ **********************************************************/
1238
+ num = i1->nNumberOfAtoms;
1239
+ for ( i = 0; i < num; i ++ ) {
1240
+ if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
1241
+ return !i2->nNum_H[i]? 1 : /* no H first */
1242
+ !i1->nNum_H[i]? -1 :
1243
+ (int)i2->nNum_H[i] - (int)i1->nNum_H[i];
1244
+ }
1245
+ }
1246
+ /*********************************************************
1247
+ compare non-isotopic tautomeric part
1248
+ *********************************************************/
1249
+ if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
1250
+ return ret;
1251
+ }
1252
+ /*
1253
+ if ( ret = i2->lenTautomer - i1->lenTautomer )
1254
+ return ret;
1255
+ num = inchi_min( i2->lenTautomer, i1->lenTautomer );
1256
+ for ( i = 0; i < num; i ++ ) {
1257
+ if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
1258
+ return ret;
1259
+ }
1260
+ */
1261
+ /*********************************************************
1262
+ * *
1263
+ * at this point both components are either tautomeric *
1264
+ * or non-tautomeric *
1265
+ * *
1266
+ *********************************************************/
1267
+
1268
+ /*********************************************************
1269
+ non-tautomeric "fixed H" specific
1270
+ *********************************************************/
1271
+ if ( TAUT_NON == bTaut && (i1n && i1n->nNum_H_fixed || i2n && i2n->nNum_H_fixed) ) {
1272
+ /* first, compare non-tautomeric chem. formulas -- they may be different */
1273
+ const char *f1 = (i1n /*&& i1n->nNum_H_fixed*/)? i1n->szHillFormula : i1->szHillFormula;
1274
+ const char *f2 = (i2n /*&& i2n->nNum_H_fixed*/)? i2n->szHillFormula : i2->szHillFormula;
1275
+ if ( f1 && f2 &&(ret = CompareHillFormulas( f1, f2 ))) {
1276
+ return ret;
1277
+ }
1278
+ /* secondly, compare fixed-H distribution */
1279
+ if ( i1n && i1n->nNum_H_fixed && i2n && i2n->nNum_H_fixed ) {
1280
+ num = inchi_min( i1n->nNumberOfAtoms, i2n->nNumberOfAtoms);
1281
+ for ( i = 0; i < num; i ++ ) {
1282
+ if ( i2n->nNum_H_fixed[i] != i1n->nNum_H_fixed[i] ) {
1283
+ return !i2n->nNum_H_fixed[i]? 1 : /* no fixed H first */
1284
+ !i1n->nNum_H_fixed[i]? -1 :
1285
+ (int)i2n->nNum_H_fixed[i] - (int)i1n->nNum_H_fixed[i];
1286
+ }
1287
+ }
1288
+ if ( ret = (int)i2n->nNumberOfAtoms - (int)i1n->nNumberOfAtoms ) {
1289
+ return ret; /* should not happen <BRKPT> */
1290
+ }
1291
+ } else
1292
+ if ( i1n && i1n->nNum_H_fixed ) {
1293
+ num = i1n->nNumberOfAtoms;
1294
+ for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
1295
+ if ( i1n->nNum_H_fixed[i] ) {
1296
+ return -1; /* i1n->nNum_H_fixed[i] > 0? -1:1;*/
1297
+ }
1298
+ }
1299
+ /* p1 is tautomeric, p2 is not tautomeric; this must have been detected earlier */
1300
+ /*return -1;*/ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1301
+ } else {
1302
+ num = i2n->nNumberOfAtoms;
1303
+ for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
1304
+ if ( i2n->nNum_H_fixed[i] ) {
1305
+ return 1; /* i2n->nNum_H_fixed[i] > 0? 1:-1;*/
1306
+ }
1307
+ }
1308
+ /* p2 is tautomeric, p1 is not tautomeric; this must have been detected earlier */
1309
+ /*return 1; */ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
1310
+ }
1311
+ }
1312
+
1313
+ /*************************************************************************
1314
+ if requested non-tautomeric comparison then
1315
+ prepare to compare non-taut non-isotopic stereo, etc.
1316
+ *************************************************************************/
1317
+ if ( TAUT_NON == bTaut ) {
1318
+ if ( i1n ) {
1319
+ /*i1t = i1;*/
1320
+ i1 = i1n;
1321
+ }
1322
+ if ( i2n ) {
1323
+ /*i2t = i2;*/
1324
+ i2 = i2n;
1325
+ }
1326
+ }
1327
+
1328
+ /*********************************************************
1329
+ compare non-isotopic stereo
1330
+ *********************************************************/
1331
+ ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
1332
+ if ( ret ) {
1333
+ return ret;
1334
+ }
1335
+ /*******************************************************
1336
+ do not switch back to tautomeric i1, i2
1337
+ *******************************************************/
1338
+ /* -- how to switch back --
1339
+ if ( i1t ) {
1340
+ i1 = i1t;
1341
+ i1t = NULL;
1342
+ }
1343
+ if ( i2t ) {
1344
+ i2 = i2t;
1345
+ i2t = NULL;
1346
+ }
1347
+ */
1348
+ /******************************************************
1349
+ compare isotopic non-tautomeric part
1350
+ ******************************************************/
1351
+ if ( bCompareIsotopic ) {
1352
+ if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
1353
+ return ret;
1354
+ num = i1->nNumberOfIsotopicAtoms;
1355
+ /* compare isotopic atoms */
1356
+ for ( i = 0; i < num; i ++ ) {
1357
+ if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
1358
+ return ret;
1359
+ if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
1360
+ return ret;
1361
+ }
1362
+ /* compare isotopic H */
1363
+ /* if tautomeric comparison mode then here are compared only non-tautomeric H */
1364
+ for ( i = 0; i < num; i ++ ) {
1365
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
1366
+ return ret;
1367
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
1368
+ return ret;
1369
+ if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
1370
+ return ret;
1371
+ }
1372
+ /*****************************************************
1373
+ compare isotopic tautomeric part
1374
+ *****************************************************/
1375
+ if ( ret = i2->nNumberOfIsotopicTGroups - i1->nNumberOfIsotopicTGroups )
1376
+ return ret;
1377
+ num = i1->nNumberOfIsotopicTGroups;
1378
+ for ( i = 0; i < num; i ++ ) {
1379
+ if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
1380
+ return ret;
1381
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
1382
+ return ret;
1383
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
1384
+ return ret;
1385
+ if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
1386
+ return ret;
1387
+ }
1388
+
1389
+ /****************************************************
1390
+ compare isotopic stereo
1391
+ ****************************************************/
1392
+ ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
1393
+ if ( ret ) {
1394
+ return ret;
1395
+ }
1396
+ }
1397
+
1398
+ /**********************************************************
1399
+ compare charges: non-charged first, then in order of
1400
+ ascending charges (negative first)
1401
+ ***********************************************************/
1402
+ if ( i2->nTotalCharge && i1->nTotalCharge ) {
1403
+ /* both are charged; smaller charges first */
1404
+ ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
1405
+ return ret;
1406
+ }
1407
+ if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
1408
+ /* only one is charged; uncharged first */
1409
+ return ret;
1410
+ }
1411
+ /* stable sort */
1412
+ /*ret = p1->ord_number - p2->ord_number;*/
1413
+
1414
+ return ret;
1415
+ }
1416
+ /***********************************************************************/
1417
+ int CompINChINonTaut2(const void *p1, const void *p2)
1418
+ {
1419
+ int ret;
1420
+ ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1421
+ #if( CANON_FIXH_TRANS == 1 )
1422
+ if ( !ret ) {
1423
+ /* to obtain canonical transposition 2004-05-10 */
1424
+ ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1425
+ }
1426
+ #endif
1427
+ if ( !ret ) {
1428
+ /* stable sort */
1429
+ ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1430
+ }
1431
+ return ret;
1432
+ }
1433
+ /***********************************************************************/
1434
+ int CompINChITaut2(const void *p1, const void *p2)
1435
+ {
1436
+ int ret;
1437
+ ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
1438
+ #if( CANON_FIXH_TRANS == 1 )
1439
+ if ( !ret ) {
1440
+ /* to obtain canonical transposition 2004-05-10 */
1441
+ ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
1442
+ }
1443
+ #endif
1444
+ if ( !ret ) {
1445
+ /* stable sort */
1446
+ ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
1447
+ }
1448
+ return ret;
1449
+ }
1450
+ /**********************************************************************************************/
1451
+ /* strrev from K&R is not in ANSI-compatible C library */
1452
+ void mystrrev( char *p )
1453
+ {
1454
+ char c, *q = p;
1455
+ while( *q++ )
1456
+ ;
1457
+ q -= 2; /* pointer to the last character */
1458
+ while ( p < q ) {
1459
+ c = *q; /* swap */
1460
+ *q-- = *p;
1461
+ *p++ = c;
1462
+ }
1463
+ }
1464
+ /*****************************************************************************************/
1465
+ /* Find DFS order for CT(canon. numbers and Hs) output */
1466
+ /*****************************************************************************************/
1467
+
1468
+ static AT_NUMB *gDfs4CT_nDfsNumber;
1469
+ static AT_NUMB *gDfs4CT_nNumDescendants;
1470
+ static int gDfs4CT_nCurrentAtom;
1471
+
1472
+ /**********************************************************************************************/
1473
+ static int CompareDfsDescendants4CT( const void *a1, const void *a2 )
1474
+ {
1475
+ int neigh1 = (int)*(const AT_RANK*)a1;
1476
+ int neigh2 = (int)*(const AT_RANK*)a2;
1477
+ if ( neigh1 > MAX_ATOMS ) {
1478
+ if ( neigh2 > MAX_ATOMS ) {
1479
+ return 0;
1480
+ }
1481
+ return 1;
1482
+ } else
1483
+ if ( neigh2 > MAX_ATOMS ) {
1484
+ return -1;
1485
+ } else {
1486
+ AT_RANK nCurDfsNumber = gDfs4CT_nDfsNumber[gDfs4CT_nCurrentAtom];
1487
+ int nDesc1 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh1]?
1488
+ 0 : (int)gDfs4CT_nNumDescendants[neigh1];
1489
+ int nDesc2 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh2]?
1490
+ 0 : (int)gDfs4CT_nNumDescendants[neigh2];
1491
+ int ret;
1492
+ if ( ret = nDesc1 - nDesc2 ) {
1493
+ return ret;
1494
+ }
1495
+ return (int)neigh1 - (int)neigh2; /* canon. numbers difference */
1496
+ }
1497
+ }
1498
+ /**********************************************************************************************/
1499
+ /* sp_ATOM *at, AT_RANK *nRank, int num_atoms */
1500
+ AT_NUMB *GetDfsOrder4CT( AT_NUMB *LinearCT, int nLenCT, S_CHAR *nNum_H, int num_atoms, int nCtMode )
1501
+ {
1502
+ AT_NUMB *nStackAtom = NULL;
1503
+ int nTopStackAtom=-1;
1504
+ AT_NUMB *nNumDescendants = NULL; /* number of descendants incl. closures and the atom itself */
1505
+ AT_NUMB *nDfsNumber = NULL;
1506
+ S_CHAR *cNeighNumb = NULL;
1507
+ NEIGH_LIST *nl = NULL;
1508
+ AT_NUMB nDfs;
1509
+ int i, j, u, k, start, num_rings, nTotOutputStringLen;
1510
+ AT_NUMB *nOutputString = NULL, cDelim;
1511
+ int bCtPredecessors = (nCtMode & CT_MODE_PREDECESSORS);
1512
+
1513
+ /* int nNumStartChildren; */
1514
+
1515
+
1516
+ /* allocate arrays */
1517
+ nStackAtom = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
1518
+ nNumDescendants = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nNumDescendants[0]));
1519
+ nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
1520
+ cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
1521
+ nl = CreateNeighListFromLinearCT( LinearCT, nLenCT, num_atoms );
1522
+ /* check allocation */
1523
+ if ( !nStackAtom || !nNumDescendants || !nDfsNumber || !cNeighNumb || !nl ) {
1524
+ /* ret = CT_OUT_OF_RAM; */ /* program error */ /* <BRKPT> */
1525
+ goto exit_function;
1526
+ }
1527
+ if ( bCtPredecessors ) {
1528
+ start = 0;
1529
+ } else {
1530
+ /* find DFS start vertex (atom) */
1531
+ for ( i = 1, start = 0; i < num_atoms; i ++ ) {
1532
+ if ( nl[i][0] < nl[start][0] ) { /* index = nRank-1 */
1533
+ start = i;
1534
+ }
1535
+ }
1536
+ }
1537
+ /*
1538
+ vertex information:
1539
+ 1. Number of (forward edges) + (back edges, first visit -- ring closures): nl[i][0]
1540
+ 2. Number of vertices traversed from this vertex, including the vertex: nNumDescendants[i]
1541
+ 3. Each edge information:
1542
+ a. forward edge (0) or back edge (1) indicator: nDfsNumber[i] > nDfsNumber[neigh]
1543
+ b. neighbor at another end of the edge neigh = nl[i][k+1], k < i
1544
+
1545
+ Total per edge: 2 + 2*(number of edges)
1546
+ */
1547
+
1548
+ /* DFS initiation */
1549
+ u = start; /* start atom */
1550
+ nDfs = 0;
1551
+ nTopStackAtom =-1;
1552
+ memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
1553
+ memset( nNumDescendants, 0, num_atoms*sizeof(nNumDescendants[0]));
1554
+ memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
1555
+ /* push the start atom on the stack */
1556
+ nDfsNumber[u] = ++nDfs;
1557
+ if ( bCtPredecessors ) {
1558
+ nNumDescendants[u] = 0; /* atom #1 has no predecessor */
1559
+ } else {
1560
+ nNumDescendants[u] = 1; /* count itself as a descendant */
1561
+ }
1562
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1563
+ /* nNumStartChildren = 0; */
1564
+ num_rings = 0;
1565
+
1566
+ /* DFS */
1567
+
1568
+ do {
1569
+ /* advance */
1570
+ while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) ) {
1571
+ cNeighNumb[i] ++;
1572
+ u = (int)nl[i][j]; /* jth neighbor of the vertex i */
1573
+ if ( !nDfsNumber[u] ) {
1574
+ /* tree edge, 1st visit -- advance */
1575
+ /* put unexplored vertex u on the stack for further examination */
1576
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1577
+ nDfsNumber[u] = ++nDfs;
1578
+ if ( bCtPredecessors ) {
1579
+ nNumDescendants[u] = i+1; /* predecessor's rank */
1580
+ } else {
1581
+ nNumDescendants[u] ++; /* count atom u as its descendant */
1582
+ }
1583
+ } else
1584
+ if ( nTopStackAtom && u != (int)nStackAtom[nTopStackAtom-1] &&
1585
+ /* back edge: u is not a predecessor of i */
1586
+ nDfsNumber[u] < nDfsNumber[i] ) {
1587
+ /* Back edge, 1st visit: u is an ancestor of i (ring closure) */
1588
+ if ( !bCtPredecessors ) {
1589
+ nNumDescendants[i] ++; /* count closures as descendants */
1590
+ }
1591
+ num_rings ++; /* count ring closures */
1592
+ } else {
1593
+ nl[i][j] = MAX_ATOMS+1; /* back edge, 2nd visit: mark as deleted */
1594
+ }
1595
+ }
1596
+ cNeighNumb[i] = 0; /* all neighbors of the ith atom have been
1597
+ traversed; resore the neighbor counter */
1598
+ /* back up */
1599
+ if ( !bCtPredecessors && nTopStackAtom /* that is, i != start */) {
1600
+ u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
1601
+ nNumDescendants[u] += nNumDescendants[i]; /* add descendants */
1602
+ }
1603
+ } while ( --nTopStackAtom >= 0 );
1604
+
1605
+ /* Sort the neighbors in ascending order so that:
1606
+ primary key = number of descendants in the DFS tree; closure neighbor is 0
1607
+ secondary key = canonical number (here vertex number = canonical number - 1)
1608
+ */
1609
+
1610
+ /* set static globals for the sorting: */
1611
+ gDfs4CT_nDfsNumber = nDfsNumber;
1612
+ gDfs4CT_nNumDescendants = nNumDescendants;
1613
+ gDfs4CT_nCurrentAtom = -1;
1614
+
1615
+ /* sorting; deleted will be the last neighbors */
1616
+ for ( i = 0; i < num_atoms; i ++ ) {
1617
+ if ( nl[i][0] > 1 ) {
1618
+ gDfs4CT_nCurrentAtom = i;
1619
+ insertions_sort( &nl[i][1], nl[i][0], sizeof(nl[i][1]), CompareDfsDescendants4CT );
1620
+ }
1621
+ /* reduce number of neighbors to exclude deleted */
1622
+ for ( k = 0; k < nl[i][0] && nl[i][k+1] <= MAX_ATOMS; k ++ )
1623
+ ;
1624
+ nl[i][0] = k;
1625
+ }
1626
+
1627
+ nTotOutputStringLen = 3*(num_atoms+num_rings+1); /* last 3 elements are a 'zero termination' */
1628
+
1629
+ if ( bCtPredecessors ) {
1630
+ if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1631
+ cDelim = '-';
1632
+ for ( u = 0, k = -3 ; u < num_atoms; u ++ ) {
1633
+ k += 3;
1634
+ if ( k+6 > nTotOutputStringLen ) {
1635
+ goto exit_error; /* program error */
1636
+ }
1637
+ nOutputString[k] = nNumDescendants[u]? nNumDescendants[u] : MAX_ATOMS+1;
1638
+ nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1639
+ nOutputString[k+2] = k? ',' : '\0';
1640
+ for ( j = 1; j <= nl[u][0] && nDfsNumber[u] > nDfsNumber[i=nl[u][j]]; j ++ ) {
1641
+ /* closures */
1642
+ k += 3;
1643
+ if ( k+6 > nTotOutputStringLen ) {
1644
+ goto exit_error; /* program error */
1645
+ }
1646
+ nOutputString[k] = i+1; /* closure */
1647
+ nOutputString[k+1] = 0;
1648
+ nOutputString[k+2] = cDelim;
1649
+ }
1650
+ }
1651
+ }
1652
+ } else {
1653
+ if ( nNumDescendants ) { /* do not need anymore */
1654
+ inchi_free( nNumDescendants );
1655
+ nNumDescendants = NULL;
1656
+ }
1657
+ /*
1658
+ the output string contains:
1659
+ (num_atoms) atoms for the DFS (spanning) tree
1660
+ (num_atoms-1) delimiters for the DFS (spanning) tree
1661
+ 1 character for each atom that has 1 terminal hydrogen atoms
1662
+ 2 characters for each atom that has 2-9 terminal hydrogen atoms
1663
+ 3 characters for each atom that has 10-99 terminal hydrogen atoms, etc.
1664
+ (num_rings) atoms for the ring closures
1665
+ (num_rings) delimiters for the ring closures
1666
+ */
1667
+
1668
+ if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
1669
+ u = start; /* start atom */
1670
+ nTopStackAtom =-1;
1671
+ memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
1672
+ /* push the start atom on the stack */
1673
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1674
+ /* output the starting atom */
1675
+ k = 0;
1676
+ nOutputString[k] = u+1;
1677
+ nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1678
+ nOutputString[k+2] = '\0';
1679
+
1680
+ do {
1681
+ /* advance */
1682
+ while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) ) {
1683
+ k += 3;
1684
+ if ( k+6 > nTotOutputStringLen ) {
1685
+ goto exit_error; /* program error */
1686
+ }
1687
+ cNeighNumb[i] ++;
1688
+ u = (int)nl[i][j]; /* neighbor */
1689
+
1690
+ /* output neighbor's canonical number */
1691
+ nOutputString[k] = u+1;
1692
+
1693
+ if ( nDfsNumber[u] > nDfsNumber[i] ) {
1694
+ /* tree edge, 1st visit -- advance */
1695
+ /* put 'unexplored' vertex u on the stack */
1696
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
1697
+
1698
+ /* output neighbor's number of H */
1699
+ nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
1700
+ } else {
1701
+ nOutputString[k+1] = 0;
1702
+ }
1703
+ /* output a delimiter preceding the neighbor */
1704
+ if ( 1 < nl[i][0] ) {
1705
+ if ( j == 1 ) {
1706
+ cDelim = '(';
1707
+ } else
1708
+ if ( j == nl[i][0] ) {
1709
+ cDelim = ')';
1710
+ } else {
1711
+ cDelim = ',';
1712
+ }
1713
+ } else {
1714
+ cDelim = '-';
1715
+ }
1716
+ nOutputString[k+2] = cDelim;
1717
+ }
1718
+ cNeighNumb[i] = 0;
1719
+
1720
+ /* back up: nothing else to do */
1721
+ } while ( --nTopStackAtom >= 0 );
1722
+ }
1723
+ }
1724
+ goto exit_function;
1725
+
1726
+ exit_error:
1727
+ if ( nOutputString ) {
1728
+ inchi_free( nOutputString );
1729
+ nOutputString = NULL;
1730
+ }
1731
+
1732
+ exit_function:
1733
+ if ( nStackAtom )
1734
+ inchi_free( nStackAtom );
1735
+ if ( nNumDescendants )
1736
+ inchi_free( nNumDescendants );
1737
+ if ( nDfsNumber )
1738
+ inchi_free( nDfsNumber );
1739
+ if ( cNeighNumb )
1740
+ inchi_free( cNeighNumb );
1741
+ if ( nl )
1742
+ FreeNeighList( nl );
1743
+ return nOutputString;
1744
+ }
1745
+ /**********************************************************************************************/
1746
+ int GetInpStructErrorType( INPUT_PARMS *ip, int err, char *pStrErrStruct, int num_inp_atoms )
1747
+ {
1748
+ if ( err && err == 9 )
1749
+ return _IS_ERROR; /* sdfile bypassed to $$$$ */
1750
+ if ( err && err < 30 )
1751
+ return _IS_FATAL;
1752
+ if ( num_inp_atoms <= 0 || err ) {
1753
+ if ( 98 == err && 0 == num_inp_atoms && ip->bAllowEmptyStructure )
1754
+ return _IS_WARNING;
1755
+ return _IS_ERROR;
1756
+ }
1757
+ if ( pStrErrStruct[0] )
1758
+ return _IS_WARNING;
1759
+ return _IS_OKAY;
1760
+ }
1761
+ /**********************************************************************************************/
1762
+ int ProcessStructError( INCHI_FILE *output_file, INCHI_FILE *log_file, /*int err,*/ char *pStrErrStruct, int nErrorType,
1763
+ int *bXmlStructStarted, int num_inp, INPUT_PARMS *ip, char *pStr, int nStrLen )
1764
+ {
1765
+ int b_ok;
1766
+ #ifdef INCHI_LIB
1767
+ int bPlainText = (ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT) &&
1768
+ (ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
1769
+ !(ip->bINChIOutputOptions & INCHI_OUT_XML);
1770
+ #else
1771
+ int bPlainText = 0;
1772
+ #endif
1773
+ if ( !bPlainText && *bXmlStructStarted <= 0 ) {
1774
+ return nErrorType;
1775
+ }
1776
+ /* Fatal error, Error, Warning */
1777
+ if ( nErrorType ) {
1778
+ if ( bPlainText ) {
1779
+ if ( !(b_ok=OutputINChIPlainError( output_file, pStr, nStrLen, pStrErrStruct, nErrorType ) ) ) {
1780
+ my_fprintf( log_file, "Cannot create message for error (structure #%d.%s%s%s%s) Terminating.\n",
1781
+ num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1782
+ } else {
1783
+ inchi_print( output_file, "\n" ); /* add a blank line after the WINCHI Window message */
1784
+ }
1785
+ } else {
1786
+ if ( !(b_ok=OutputINChIXmlError( output_file, pStr, nStrLen, 2, /*err,*/ pStrErrStruct, nErrorType ) ) ) {
1787
+ my_fprintf( log_file, "Cannot create xml tag for error (structure #%d.%s%s%s%s) Terminating.\n",
1788
+ num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1789
+ }
1790
+ if ( !b_ok || nErrorType == _IS_FATAL || nErrorType == _IS_ERROR ) {
1791
+ /* close current structure output */
1792
+ if ( !OutputINChIXmlStructEndTag( output_file, pStr, nStrLen, 1 ) ) {
1793
+ my_fprintf( log_file, "Cannot create end xml tag for structure #%d.%s%s%s%s Terminating.\n", num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
1794
+ *bXmlStructStarted = -1;
1795
+ b_ok = 0;
1796
+ } else {
1797
+ *bXmlStructStarted = 0;
1798
+ }
1799
+ }
1800
+ }
1801
+ return b_ok? nErrorType : _IS_FATAL;
1802
+ }
1803
+ return nErrorType;
1804
+
1805
+ }
1806
+
1807
+ #if( TEST_RENUMB_ATOMS == 1 ) /* { */
1808
+ /***************************************************************************************/
1809
+ int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 )
1810
+ {
1811
+ if ( s1 == NULL && s2 == NULL )
1812
+ return 0;
1813
+ if ( (s1 == NULL) ^ (s2 == NULL) )
1814
+ return 20;
1815
+
1816
+ if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
1817
+ return 21;
1818
+ if ( s1->nNumberOfStereoCenters > 0 ) {
1819
+ if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1820
+ return 22;
1821
+ if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1822
+ return 23;
1823
+ if ( s1->nNumberInv && s2->nNumberInv ) {
1824
+ if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
1825
+ return 28;
1826
+ if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
1827
+ return 29;
1828
+ if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
1829
+ s1->bTrivialInv != s2->bTrivialInv ) {
1830
+ return 30;
1831
+ }
1832
+ } else
1833
+ if ( s1->nNumberInv || s2->nNumberInv ) {
1834
+ return 31;
1835
+ }
1836
+ }
1837
+ if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
1838
+ return 24;
1839
+ if ( s1->nNumberOfStereoBonds > 0 ) {
1840
+ if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
1841
+ return 25;
1842
+ if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
1843
+ return 26;
1844
+ if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
1845
+ return 27;
1846
+ }
1847
+ return 0;
1848
+ }
1849
+ /***************************************************************************************/
1850
+ int CompareINChI( INChI *i1, INChI *i2, INChI_Aux *a1, INChI_Aux *a2 )
1851
+ {
1852
+ int ret;
1853
+ if ( i1 == NULL && i2 == NULL )
1854
+ return 0;
1855
+ if ( (i1 == NULL) ^ (i2 == NULL) )
1856
+ return 1;
1857
+
1858
+ if ( i1->nErrorCode == i2->nErrorCode ) {
1859
+ if ( i1->nErrorCode )
1860
+ return 0;
1861
+ } else {
1862
+ return 2;
1863
+ }
1864
+
1865
+ if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
1866
+ return 3;
1867
+ if ( i1->nNumberOfAtoms > 0 ) {
1868
+ if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
1869
+ return 4;
1870
+ if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) )
1871
+ return 5;
1872
+ if ( i1->nNum_H_fixed && i2->nNum_H_fixed &&
1873
+ memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
1874
+ return 6;
1875
+ }
1876
+ if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
1877
+ return 7;
1878
+ }
1879
+
1880
+ if ( i1->lenConnTable != i2->lenConnTable )
1881
+ return 8;
1882
+ if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
1883
+ return 9;
1884
+
1885
+ if ( i1->lenTautomer != i2->lenTautomer )
1886
+ return 10;
1887
+ if ( i1->lenTautomer > 0 && memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
1888
+ return 11;
1889
+
1890
+ if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
1891
+ return 12;
1892
+ if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
1893
+ return 13;
1894
+
1895
+ if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
1896
+ return 14;
1897
+ if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
1898
+ return 15;
1899
+ if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
1900
+ return 16;
1901
+ if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
1902
+ return 17;
1903
+ if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
1904
+ if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
1905
+ memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
1906
+ sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
1907
+ return 18;
1908
+ } else
1909
+ if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
1910
+ return 19;
1911
+ }
1912
+ /* ret = 20..31 */
1913
+ if ( ret = CompareStereoINChI( i1->Stereo, i2->Stereo ) )
1914
+ return ret;
1915
+ /* ret = 40..51 */
1916
+ if ( ret = CompareStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) )
1917
+ return ret+20;
1918
+
1919
+ return 0;
1920
+ }
1921
+ #endif /* } TEST_RENUMB_ATOMS == 1 */
1922
+ /***************************************************************************************/
1923
+ int Create_INChI( INChI **ppINChI, INChI_Aux **ppINChI_Aux, ORIG_ATOM_DATA *orig_inp_data,
1924
+ inp_ATOM *inp_at, INP_ATOM_DATA *out_norm_data[2],
1925
+ int num_inp_at, INCHI_MODE nUserMode,
1926
+ INCHI_MODE *pbTautFlags, INCHI_MODE *pbTautFlagsDone,
1927
+ struct tagInchiTime *ulMaxTime, char *pStrErrStruct)
1928
+ {
1929
+ /*
1930
+ #define NON_TAUT 0
1931
+ #define TAUT 1
1932
+ */
1933
+ sp_ATOM *at[TAUT_NUM]; /* at[0]=>non-tautomeric, at[1]=>tautomeric */
1934
+ /* inp_ATOM *out_norm_taut_at, *out_norm_nontaut_at; */
1935
+ int i, n1, n2, num_atoms, num_at_tg, num_removed_H, num_removed_H_taut=0, ret=0, ret2=0;
1936
+ INCHI_MODE nMode=0;
1937
+ T_GROUP_INFO vt_group_info;
1938
+ T_GROUP_INFO vt_group_info_orig;
1939
+ T_GROUP_INFO * /*const*/ t_group_info = &vt_group_info;
1940
+ T_GROUP_INFO * /*const*/ t_group_info_orig = &vt_group_info_orig;
1941
+
1942
+ CANON_STAT CS, CS2;
1943
+ CANON_STAT *pCS = &CS;
1944
+ CANON_STAT *pCS2 = &CS2; /* save all allocations to avoid memory leaks in case Canon_INChI() removes the pointer */
1945
+
1946
+ ATOM_SIZES s[TAUT_NUM];
1947
+
1948
+ BCN Bcn;
1949
+ BCN *pBCN = &Bcn;
1950
+
1951
+ int bHasIsotopicAtoms = 0;
1952
+ int bMayHaveStereo = 0;
1953
+ int num_taut_at = 0;
1954
+
1955
+ inp_ATOM *out_at = NULL; /*, *norm_at_fixed_bonds[TAUT_NUM]; *//* = {out_norm_nontaut_at, out_norm_taut_at} ; */
1956
+ INChI *pINChI;
1957
+ INChI_Aux *pINChI_Aux;
1958
+ int bPointedEdgeStereo = (0 != (TG_FLAG_POINTED_EDGE_STEREO & *pbTautFlags));
1959
+ INCHI_MODE bTautFlags = (*pbTautFlags & (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) );
1960
+ INCHI_MODE bTautFlagsDone = (*pbTautFlagsDone /*& (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) */);
1961
+ #if( bRELEASE_VERSION == 0 )
1962
+ int bExtract = 0; /* EXTR_HAS_ATOM_WITH_DEFINED_PARITY; */
1963
+ #endif
1964
+ #if( TEST_RENUMB_ATOMS == 1 )
1965
+ long ulNormTime=0;
1966
+ long ulCanonTime=0, ulCanonTime2=0;
1967
+
1968
+ inchiTime ulNormTimeStart;
1969
+ inchiTime ulCanonTimeStart;
1970
+
1971
+ InchiTimeGet( &ulNormTimeStart );
1972
+ #endif
1973
+
1974
+ memset( s, 0, sizeof(s) );
1975
+ if ( pBCN ) {
1976
+ memset( pBCN, 0, sizeof( pBCN[0] ) );
1977
+ }
1978
+ memset( t_group_info, 0, sizeof(*t_group_info) );
1979
+ memset( t_group_info_orig, 0, sizeof(*t_group_info_orig) );
1980
+ /*norm_at[TAUT_NON] = out_norm_data[TAUT_NON]->at; *//* output normalized non-tautomeric component */
1981
+ /*norm_at[TAUT_YES] = out_norm_data[TAUT_YES]->at; *//* output normalized tautomeric component */
1982
+ /*norm_at_fixed_bonds[TAUT_NON] = NULL;*/
1983
+ /*norm_at_fixed_bonds[TAUT_YES] = out_norm_data[TAUT_YES]->at_fixed_bonds;*/
1984
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
1985
+ if ( out_norm_data[i]->at ) {
1986
+ if ( !(at[i] = (sp_ATOM *)inchi_malloc( num_inp_at * sizeof(*at[0]) ) ) ) {
1987
+ ret = -1;
1988
+ }
1989
+ } else {
1990
+ at[i] = NULL;
1991
+ }
1992
+ }
1993
+ if ( !out_norm_data[TAUT_NON]->at && !out_norm_data[TAUT_YES]->at || !inp_at || ret ) {
1994
+ ret = -1;
1995
+ goto exit_function;
1996
+ }
1997
+ /* the first struct to process: tautomeric if exists else non-tautomeric */
1998
+ out_at = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES]->at : out_norm_data[TAUT_NON]->at;
1999
+ /* copy the input structure to be normalized to the buffer for the normalization data */
2000
+ memcpy( out_at, inp_at, num_inp_at*sizeof(out_at[0]) );
2001
+
2002
+ /* tautomeric groups setting */
2003
+ t_group_info->bIgnoreIsotopic = 0; /* include tautomeric group isotopic info in MarkTautomerGroups() */
2004
+ t_group_info->bTautFlags = *pbTautFlags;
2005
+ t_group_info->bTautFlagsDone = *pbTautFlagsDone;
2006
+
2007
+ /* Preprocess the structure; here THE NUMBER OF ATOMS MAY BE REDUCED */
2008
+ /* ??? Ambiguity: H-D may become HD or DH (that is, H+implicit D or D+implicit H) */
2009
+ num_at_tg =
2010
+ num_atoms = remove_terminal_HDT( num_inp_at, out_at );
2011
+ num_removed_H = num_inp_at - num_atoms;
2012
+ t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
2013
+ add_DT_to_num_H( num_atoms, out_at );
2014
+ /*fix_odd_things( num_atoms, out_at );*/
2015
+ #if( FIND_RING_SYSTEMS == 1 )
2016
+ MarkRingSystemsInp( out_at, num_atoms );
2017
+ #endif
2018
+ /* duplicate the preprocessed structure so that all supplied out_norm_data[]->at buffers are filled */
2019
+ if ( out_at != out_norm_data[TAUT_YES]->at && out_norm_data[TAUT_YES]->at ) {
2020
+ memcpy( out_norm_data[TAUT_YES]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2021
+ }
2022
+ if ( out_norm_data[TAUT_YES]->at_fixed_bonds && out_norm_data[TAUT_YES]->at ) {
2023
+ memcpy( out_norm_data[TAUT_YES]->at_fixed_bonds, out_at, num_inp_at*sizeof(out_at[0]) );
2024
+ }
2025
+ if ( out_at != out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_NON]->at ) {
2026
+ memcpy( out_norm_data[TAUT_NON]->at, out_at, num_inp_at*sizeof(out_at[0]) );
2027
+ }
2028
+
2029
+ /*******************************************************************************
2030
+ * ??? not true ??? duplicate inp_at and keep inp_at[] unchanged after terminal hydrogens removal
2031
+ * set stereo parities in taut_at[], non_taut_at[]
2032
+ * obtain max. lenghts of the name stereo parts
2033
+ * Ignore absence/presence of isotopic stereo for now
2034
+ * mark isotopic atoms
2035
+ *******************************************************************************/
2036
+ if ( out_norm_data[TAUT_YES]->at && at[TAUT_YES] ) {
2037
+ /* final normalization of possibly tautomeric structure */
2038
+ ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_YES]->at, out_norm_data[TAUT_YES]->at_fixed_bonds, num_atoms,
2039
+ t_group_info, NULL, NULL );
2040
+ if ( ret < 0 ) {
2041
+ goto exit_function;/* out of RAM or other normalization problem */
2042
+ }
2043
+ num_taut_at = ret; /* number of atoms without removed H? */
2044
+ num_removed_H_taut = t_group_info->tni.nNumRemovedExplicitH;
2045
+ out_norm_data[TAUT_YES]->num_at = num_atoms + num_removed_H_taut; /* protons might have been removed */
2046
+ out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;
2047
+ out_norm_data[TAUT_YES]->nNumRemovedProtons += t_group_info->tni.nNumRemovedProtons;
2048
+ for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
2049
+ out_norm_data[TAUT_YES]->nNumRemovedProtonsIsotopic[i] += t_group_info->tni.nNumRemovedProtonsIsotopic[i] /*+ t_group_info->num_iso_H[i]*/;
2050
+ out_norm_data[TAUT_YES]->num_iso_H[i] += t_group_info->num_iso_H[i];
2051
+ }
2052
+ /* mark deleted isolated tautomeric H(+) */
2053
+ if ( num_taut_at == 1 && out_norm_data[TAUT_YES]->at[0].at_type == ATT_PROTON &&
2054
+ t_group_info && t_group_info->tni.nNumRemovedProtons == 1 ) {
2055
+ out_norm_data[TAUT_YES]->bDeleted = 1;
2056
+ FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2057
+ } else
2058
+ if ( (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT) &&
2059
+ out_norm_data[TAUT_YES]->at_fixed_bonds) {
2060
+ out_norm_data[TAUT_YES]->bTautPreprocessed = 1;
2061
+ }
2062
+ /*
2063
+ if ( !(t_group_info->tni.bNormalizationFlags & (FLAG_NORM_CONSIDER_TAUT & ~FLAG_PROTON_SINGLE_REMOVED)) &&
2064
+ out_norm_data[TAUT_YES]->at_fixed_bonds) {
2065
+ FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
2066
+ }
2067
+ */
2068
+ /*out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;*/
2069
+ out_norm_data[TAUT_YES]->bTautFlags = *pbTautFlags = t_group_info->bTautFlags;
2070
+ out_norm_data[TAUT_YES]->bTautFlagsDone = *pbTautFlagsDone = t_group_info->bTautFlagsDone;
2071
+ out_norm_data[TAUT_YES]->bNormalizationFlags = t_group_info->tni.bNormalizationFlags;
2072
+ /* create internal sp_ATOM at[] out of out_norm_data[]->at */
2073
+ inp2spATOM( out_norm_data[TAUT_YES]->at, num_inp_at, at[TAUT_YES] );
2074
+ /* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
2075
+ ret = set_stereo_parity( out_norm_data[TAUT_YES]->at, at[TAUT_YES], num_taut_at, num_removed_H_taut,
2076
+ &s[TAUT_YES].nMaxNumStereoAtoms, &s[TAUT_YES].nMaxNumStereoBonds, nUserMode,
2077
+ bPointedEdgeStereo );
2078
+ #if( bRELEASE_VERSION == 0 )
2079
+ if ( 0 < ret ) {
2080
+ bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
2081
+ }
2082
+ if ( t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT ) {
2083
+ bExtract |= EXTR_TAUT_TREATMENT_CHARGES;
2084
+ }
2085
+ #endif
2086
+ if ( RETURNED_ERROR( ret ) ) {
2087
+ goto exit_function; /* stereo bond error */
2088
+ }
2089
+ s[TAUT_YES].bMayHaveStereo = (s[TAUT_YES].nMaxNumStereoAtoms || s[TAUT_YES].nMaxNumStereoBonds);
2090
+ /*
2091
+ * mark isotopic atoms and atoms that have non-tautomeric
2092
+ * isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
2093
+ */
2094
+ s[TAUT_YES].num_isotopic_atoms = set_atom_iso_sort_keys( num_taut_at, at[TAUT_YES], t_group_info,
2095
+ &s[TAUT_YES].bHasIsotopicTautGroups );
2096
+ /**************************************************************************
2097
+ * prepare tautomeric (if no tautomerism found then prepare non-tautomeric)
2098
+ * structure for canonicalizaton:
2099
+ **************************************************************************
2100
+ * remove t-groups that have no H,
2101
+ * remove charges from t-groups if requested
2102
+ * renumber t-groups and find final t_group_info->num_t_groups
2103
+ * add to t-groups lists of endpoints tgroup->nEndpointAtomNumber[]
2104
+ * calculate length of the t-group part of the connection table
2105
+ **************************************************************************/
2106
+ s[TAUT_YES].nLenLinearCTTautomer = CountTautomerGroups( at[TAUT_YES], num_taut_at, t_group_info );
2107
+ if ( RETURNED_ERROR(s[TAUT_YES].nLenLinearCTTautomer) ) { /* added error treatment 9-11-2003 */
2108
+ ret = s[TAUT_YES].nLenLinearCTTautomer;
2109
+ goto exit_function;
2110
+ /* error has happened; no breakpoint here
2111
+ s[TAUT_YES].nLenLinearCTTautomer = 0;
2112
+ */
2113
+ } else
2114
+ if ( s[TAUT_YES].nLenLinearCTTautomer > 0 ) {
2115
+ num_at_tg = num_taut_at+t_group_info->num_t_groups;
2116
+ /* ??? -not true- create t_group_info_orig for multiple calls with atom renumbering */
2117
+ make_a_copy_of_t_group_info( t_group_info_orig, t_group_info );
2118
+ /* mark isotopic tautomer groups: calculate t_group->iWeight */
2119
+ s[TAUT_YES].nLenLinearCTIsotopicTautomer=set_tautomer_iso_sort_keys( t_group_info );
2120
+ if ( s[TAUT_YES].nLenLinearCTIsotopicTautomer < 0 ) {
2121
+ /* ??? -error cannot happen- error has happened; no breakpoint here */
2122
+ s[TAUT_YES].nLenLinearCTIsotopicTautomer = 0;
2123
+ }
2124
+ out_norm_data[TAUT_YES]->bTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
2125
+ }
2126
+ /* new variable: s[TAUT_YES].nLenCT introduced 7-22-2002 */
2127
+ GetCanonLengths( num_taut_at, at[TAUT_YES], &s[TAUT_YES], t_group_info );
2128
+ }
2129
+ if ( out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at && at[TAUT_NON] && !s[TAUT_YES].nLenLinearCTTautomer ) {
2130
+ /* the structure is non-tautomeric: use tautomeric treatment results only for it */
2131
+ inchi_free( at[TAUT_NON] );
2132
+ at[TAUT_NON] = NULL;
2133
+ } else
2134
+ if ( !out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at &&
2135
+ !at[TAUT_NON] && at[TAUT_YES] && !s[TAUT_YES].nLenLinearCTTautomer ) {
2136
+ /* requested tautomeric; found non-tautomeric; it is located in out_norm_data[TAUT_YES]->at */
2137
+ out_norm_data[TAUT_YES]->bTautomeric = 0;
2138
+ } else
2139
+ if ( out_norm_data[TAUT_NON]->at && at[TAUT_NON] ) {
2140
+ /* the structure needs non-tautomeric treatment: final normalization of non-tautomeric structure */
2141
+ ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_NON]->at, NULL, num_atoms, NULL, &bTautFlags, &bTautFlagsDone );
2142
+ if ( ret < 0 ) {
2143
+ goto exit_function; /* out of RAM or other normalization problem */
2144
+ }
2145
+ out_norm_data[TAUT_NON]->num_at = num_atoms + num_removed_H;
2146
+ out_norm_data[TAUT_NON]->num_removed_H = num_removed_H;
2147
+ out_norm_data[TAUT_NON]->bTautFlags = *pbTautFlags;
2148
+ out_norm_data[TAUT_NON]->bTautFlagsDone = *pbTautFlagsDone;
2149
+ out_norm_data[TAUT_NON]->bNormalizationFlags = 0;
2150
+ /* create internal sp_ATOM at[] out of out_norm_data[]->at */
2151
+ inp2spATOM( out_norm_data[TAUT_NON]->at, num_inp_at, at[TAUT_NON] );
2152
+ /* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
2153
+ ret = set_stereo_parity( out_norm_data[TAUT_NON]->at, at[TAUT_NON], num_atoms, num_removed_H,
2154
+ &s[TAUT_NON].nMaxNumStereoAtoms, &s[TAUT_NON].nMaxNumStereoBonds, nUserMode,
2155
+ bPointedEdgeStereo );
2156
+ #if( bRELEASE_VERSION == 0 )
2157
+ if ( 0 < ret ) {
2158
+ bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
2159
+ }
2160
+ #endif
2161
+ if ( RETURNED_ERROR( ret ) ) {
2162
+ goto exit_function; /* stereo bond error */
2163
+ }
2164
+ s[TAUT_NON].bMayHaveStereo = (s[TAUT_NON].nMaxNumStereoAtoms || s[TAUT_NON].nMaxNumStereoBonds);
2165
+ /*
2166
+ * mark isotopic atoms and atoms that have non-tautomeric
2167
+ * isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
2168
+ */
2169
+ s[TAUT_NON].num_isotopic_atoms = set_atom_iso_sort_keys( num_atoms, at[TAUT_NON], NULL, NULL );
2170
+ GetCanonLengths( num_atoms, at[TAUT_NON], &s[TAUT_NON], NULL);
2171
+ out_norm_data[TAUT_NON]->bTautomeric = 0;
2172
+ }
2173
+
2174
+ /**********************************************************/
2175
+ /* common */
2176
+ bMayHaveStereo = s[TAUT_YES].bMayHaveStereo || s[TAUT_NON].bMayHaveStereo;
2177
+ bHasIsotopicAtoms = s[TAUT_NON].num_isotopic_atoms > 0 || s[TAUT_NON].bHasIsotopicTautGroups > 0 ||
2178
+ s[TAUT_YES].num_isotopic_atoms > 0 || s[TAUT_YES].bHasIsotopicTautGroups > 0 ||
2179
+ s[TAUT_YES].nLenIsotopicEndpoints > 1 && t_group_info &&
2180
+ (t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE));
2181
+
2182
+ /* default mode */
2183
+ if ( !(nUserMode & REQ_MODE_DEFAULT) ) {
2184
+ /* default */
2185
+ nUserMode |= REQ_MODE_DEFAULT;
2186
+ }
2187
+
2188
+ /* adjust the mode to the reality */
2189
+ if ( ( nUserMode & REQ_MODE_ISO ) && !bHasIsotopicAtoms ) {
2190
+ nUserMode ^= REQ_MODE_ISO;
2191
+ nUserMode |= REQ_MODE_NON_ISO; /* at least one is needed */
2192
+ }
2193
+ if ( (nUserMode & REQ_MODE_STEREO) && ( nUserMode & REQ_MODE_ISO ) ) {
2194
+ nUserMode |= REQ_MODE_ISO_STEREO;
2195
+ }
2196
+ if ( (nUserMode & REQ_MODE_STEREO) && !( nUserMode & REQ_MODE_NON_ISO ) ) {
2197
+ nUserMode ^= REQ_MODE_STEREO;
2198
+ }
2199
+ if ( !bMayHaveStereo ) {
2200
+ if ( nUserMode & REQ_MODE_STEREO )
2201
+ nUserMode ^= REQ_MODE_STEREO;
2202
+ if ( nUserMode & REQ_MODE_ISO_STEREO )
2203
+ nUserMode ^= REQ_MODE_ISO_STEREO;
2204
+ }
2205
+
2206
+ if ( (nUserMode & REQ_MODE_BASIC) && (!out_norm_data[TAUT_NON]->at || !ppINChI[TAUT_NON] || !ppINChI_Aux[TAUT_NON] || !at[TAUT_NON]) ) {
2207
+ nUserMode ^= REQ_MODE_BASIC;
2208
+ }
2209
+ if ( (nUserMode & REQ_MODE_TAUT) && (!out_norm_data[TAUT_YES]->at || !ppINChI[TAUT_YES] || !ppINChI_Aux[TAUT_YES] || !at[TAUT_YES]) ) {
2210
+ nUserMode ^= REQ_MODE_TAUT;
2211
+ }
2212
+
2213
+
2214
+ switch ((int)nUserMode & (REQ_MODE_BASIC | REQ_MODE_TAUT)) {
2215
+ case REQ_MODE_BASIC:
2216
+ n1 = TAUT_NON;
2217
+ n2 = TAUT_NON;
2218
+ break;
2219
+ case REQ_MODE_TAUT:
2220
+ n1 = TAUT_YES;
2221
+ n2 = TAUT_YES;
2222
+ break;
2223
+ case (REQ_MODE_BASIC | REQ_MODE_TAUT):
2224
+ n1 = TAUT_NON;
2225
+ n2 = TAUT_YES;
2226
+ break;
2227
+ default:
2228
+ ret = -3;
2229
+ goto exit_function; /* program error: inconsistent nUserMode or missing taut/non-taut allocation */ /* <BRKPT> */
2230
+ }
2231
+ #if( TEST_RENUMB_ATOMS == 1 )
2232
+ ulNormTime = InchiTimeElapsed( &ulNormTimeStart);
2233
+ #endif
2234
+ /************************************************************
2235
+ * *
2236
+ * Obtain all non-stereo canonical numberings *
2237
+ * *
2238
+ ************************************************************/
2239
+ #if( TEST_RENUMB_ATOMS == 1 )
2240
+ InchiTimeGet( &ulCanonTimeStart );
2241
+ #endif
2242
+ if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
2243
+ /* added for special non-isotopic test mode 2004-10-04 */
2244
+ if ( t_group_info ) {
2245
+ t_group_info->bIgnoreIsotopic = 1;
2246
+ if ( t_group_info->nIsotopicEndpointAtomNumber ) {
2247
+ t_group_info->nIsotopicEndpointAtomNumber[0] = inchi_min(1, t_group_info->nIsotopicEndpointAtomNumber[0]);
2248
+ }
2249
+ memset( t_group_info->num_iso_H, 0, sizeof(t_group_info->num_iso_H) );
2250
+ memset ( t_group_info->tni.nNumRemovedProtonsIsotopic, 0, sizeof(t_group_info->tni.nNumRemovedProtonsIsotopic));
2251
+ t_group_info->bTautFlagsDone &= ~(TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE);
2252
+ }
2253
+ for ( i = 0; i < TAUT_NUM; i ++ ) {
2254
+ s[i].bHasIsotopicTautGroups = 0;
2255
+ s[i].bIgnoreIsotopic = 1;
2256
+ s[i].nLenIsotopic = 0;
2257
+ s[i].nLenIsotopicEndpoints = 0;
2258
+ s[i].nLenLinearCTIsotopicTautomer = 0;
2259
+ s[i].num_isotopic_atoms = 0;
2260
+ }
2261
+ bHasIsotopicAtoms = 0;
2262
+ }
2263
+ ret = GetBaseCanonRanking( num_atoms, num_at_tg, at, t_group_info, s, pBCN, ulMaxTime );
2264
+ #if( TEST_RENUMB_ATOMS == 1 )
2265
+ ulCanonTime = InchiTimeElapsed( &ulCanonTimeStart );
2266
+ #endif
2267
+ if ( ret < 0 ) {
2268
+ goto exit_function; /* program error */
2269
+ }
2270
+ #if( bRELEASE_VERSION == 0 && FIND_CANON_NE_EQUITABLE == 1 )
2271
+ /* Debug only: find whether canonical equivalence is different from equitable partition */
2272
+ if ( bCanonIsFinerThanEquitablePartition( num_atoms, at[n1], pBCN->ftcn[TAUT_NON].nSymmRankCt ) ) {
2273
+ bExtract |= EXTR_CANON_NE_EQUITABLE;
2274
+ }
2275
+ #endif
2276
+ /* added for special non-isotopic test mode 2004-10-04 */
2277
+ if ( !pBCN->ftcn[n1].PartitionCt.Rank ) {
2278
+ n1 = ALT_TAUT(n1);
2279
+ }
2280
+ if ( !pBCN->ftcn[n2].PartitionCt.Rank ) {
2281
+ n2 = ALT_TAUT(n2);
2282
+ }
2283
+ if ( n1 > n2 ) {
2284
+ ret = CT_TAUCOUNT_ERR;
2285
+ goto exit_function; /* program error */
2286
+ }
2287
+
2288
+ /************************************************************
2289
+ * *
2290
+ * Obtain stereo canonical numberings *
2291
+ * *
2292
+ ************************************************************/
2293
+
2294
+ for ( i = n2; i >= n1 && !RETURNED_ERROR( ret ); i -- ) {
2295
+
2296
+ memset( pCS, 0, sizeof(*pCS) );
2297
+
2298
+ switch( i ) {
2299
+ case TAUT_NON: /* non-tautomeric */
2300
+ nMode = 0;
2301
+ nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
2302
+ nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO))? CANON_MODE_ISO:0;
2303
+ nMode |= (s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
2304
+ nMode |= (bHasIsotopicAtoms && s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
2305
+ nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
2306
+ nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
2307
+ nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
2308
+ if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
2309
+ (nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
2310
+ nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
2311
+ nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
2312
+ nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
2313
+ nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
2314
+ }
2315
+ if ( ret= AllocateCS( pCS, num_atoms, num_atoms, s[TAUT_NON].nLenCT, s[TAUT_NON].nLenCTAtOnly,
2316
+ s[TAUT_NON].nLenLinearCTStereoDble, s[TAUT_NON].nMaxNumStereoBonds,
2317
+ s[TAUT_NON].nLenLinearCTStereoCarb, s[TAUT_NON].nMaxNumStereoAtoms,
2318
+ 0, 0, s[TAUT_NON].nLenIsotopic, nMode, pBCN ) ) {
2319
+ goto exit_function;
2320
+ }
2321
+ *pCS2 = *pCS;
2322
+ break;
2323
+ case TAUT_YES: /* tautomeric */
2324
+ nMode = 0;
2325
+ nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
2326
+ nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO) )? CANON_MODE_ISO:0;
2327
+ nMode |= (s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
2328
+ nMode |= (bHasIsotopicAtoms && s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
2329
+ nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
2330
+ nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
2331
+ nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
2332
+ if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
2333
+ (nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
2334
+ nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
2335
+ nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
2336
+ nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
2337
+ nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
2338
+ }
2339
+ if ( ret= AllocateCS( pCS, num_atoms, num_at_tg, s[TAUT_YES].nLenCT, s[TAUT_YES].nLenCTAtOnly,
2340
+ s[TAUT_YES].nLenLinearCTStereoDble, s[TAUT_YES].nMaxNumStereoBonds,
2341
+ s[TAUT_YES].nLenLinearCTStereoCarb, s[TAUT_YES].nMaxNumStereoAtoms,
2342
+ s[TAUT_YES].nLenLinearCTTautomer, s[TAUT_YES].nLenLinearCTIsotopicTautomer,
2343
+ s[TAUT_YES].nLenIsotopic, nMode, pBCN ) ) {
2344
+ goto exit_function;
2345
+ }
2346
+ *pCS2 = *pCS;
2347
+ break;
2348
+ }
2349
+
2350
+
2351
+ /* settings */
2352
+ pCS->lNumDecreasedCT = -1;
2353
+ pCS->bDoubleBondSquare = DOUBLE_BOND_NEIGH_LIST? 2:0; /* 2 => special mode */
2354
+ pCS->bIgnoreIsotopic = !((s[TAUT_NON].num_isotopic_atoms ||
2355
+ s[TAUT_YES].num_isotopic_atoms ||
2356
+ s[TAUT_YES].bHasIsotopicTautGroups) ||
2357
+ (nUserMode & REQ_MODE_NON_ISO) ||
2358
+ !(nUserMode & REQ_MODE_ISO));
2359
+
2360
+ if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
2361
+ pCS->bIgnoreIsotopic = 1; /* 10-04-2004 */
2362
+ }
2363
+
2364
+ if ( i == TAUT_YES ) { /* tautomeric */
2365
+ pCS->t_group_info = t_group_info; /* ??? make a copy or reuse ??? */
2366
+ pCS->t_group_info->bIgnoreIsotopic = !(s[TAUT_YES].bHasIsotopicTautGroups ||
2367
+ (nUserMode & REQ_MODE_NON_ISO) ||
2368
+ !(nUserMode & REQ_MODE_ISO));
2369
+ if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
2370
+ pCS->t_group_info->bIgnoreIsotopic = 1; /* 10-04-2004 */
2371
+ }
2372
+ }
2373
+ pCS->ulTimeOutTime = pBCN->ulTimeOutTime;
2374
+ /*=========== Obsolete Mode Bits (bit 0 is Least Significant Bit) ===========
2375
+ *
2376
+ * Mode Bits Description
2377
+ * '0' c 0 Only one connection table canonicalization
2378
+ * '1' C 1 Recalculate CT using fixed nSymmRank
2379
+ * '2' i 1|2 Isotopic canonicalization (internal)
2380
+ * '3' I 1|2|4 Isotopic canonicalization (output)
2381
+ * '4' s 1|8 Stereo canonicalization
2382
+ * '5' S 1|2|4|16 Stereo isotopic canonicalization
2383
+ * '6' A 1|2|4|8|16 Output All
2384
+ */
2385
+ #if( TEST_RENUMB_ATOMS == 1 )
2386
+ InchiTimeGet( &ulCanonTimeStart );
2387
+ #endif
2388
+ /***************************************
2389
+ The last canonicalization step
2390
+ ***************************************/
2391
+ if ( pBCN ) {
2392
+ /* USE_CANON2 == 1 */
2393
+ pCS->NeighList = NULL;
2394
+ pCS->pBCN = pBCN;
2395
+ ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
2396
+ } else {
2397
+ /* old way */
2398
+ pCS->NeighList = CreateNeighList( num_atoms, i?num_at_tg:num_atoms, at[i], pCS->bDoubleBondSquare, pCS->t_group_info );
2399
+ pCS->pBCN = NULL;
2400
+ ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
2401
+ }
2402
+
2403
+ pINChI = ppINChI[i];
2404
+ pINChI_Aux = ppINChI_Aux[i];
2405
+ if ( ret <= 0 ) {
2406
+ /***************************************/
2407
+ /* failure in Canon_INChI() */
2408
+ /***************************************/
2409
+ pINChI->nErrorCode = ret;
2410
+ pINChI_Aux->nErrorCode = ret;
2411
+ } else {
2412
+ /***************************************/
2413
+ /* success Canon_INChI() */
2414
+ /* save canonicalization results in */
2415
+ /* pINChI and pINChI_Aux */
2416
+ /***************************************/
2417
+ pINChI->nErrorCode = 0;
2418
+ pINChI_Aux->nErrorCode = 0;
2419
+ pINChI->bDeleted = pINChI_Aux->bDeleted = out_norm_data[i]->bDeleted;
2420
+ pINChI_Aux->nCanonFlags = pCS->nCanonFlags;
2421
+ pINChI_Aux->bTautFlags = out_norm_data[i]->bTautFlags;
2422
+ pINChI_Aux->bTautFlagsDone = out_norm_data[i]->bTautFlagsDone;
2423
+ pINChI_Aux->bNormalizationFlags = out_norm_data[i]->bNormalizationFlags;
2424
+ /* may return an error or a warning */
2425
+ ret = FillOutINChI( pINChI, pINChI_Aux,
2426
+ num_atoms, i?num_at_tg:num_atoms,
2427
+ i?num_removed_H_taut:num_removed_H, at[i], out_norm_data[i]->at, pCS, i, nUserMode, pStrErrStruct );
2428
+ if ( RETURNED_ERROR( ret ) ) {
2429
+ /* failure in FillOutINChI() */
2430
+ pINChI->nErrorCode = ret;
2431
+ pINChI_Aux->nErrorCode = ret;
2432
+ } else {
2433
+ /****************************/
2434
+ /* success in FillOutINChI() */
2435
+ /****************************/
2436
+ #if( bRELEASE_VERSION == 0 )
2437
+ if ( pINChI->Stereo &&
2438
+ (pINChI->Stereo->nCompInv2Abs && !pINChI->Stereo->bTrivialInv) ||
2439
+ pINChI->StereoIsotopic &&
2440
+ (pINChI->StereoIsotopic->nCompInv2Abs && !pINChI->StereoIsotopic->bTrivialInv) ) {
2441
+ bExtract |= EXTR_NON_TRIVIAL_STEREO;
2442
+ }
2443
+ #endif
2444
+ /* mark non-tautomeric representation as having another, tautomeric representation */
2445
+ if ( pINChI_Aux && s[TAUT_YES].nLenLinearCTTautomer ) {
2446
+ pINChI_Aux->bIsTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
2447
+ }
2448
+ #if( bRELEASE_VERSION == 0 )
2449
+ pCS->bExtract |= bExtract;
2450
+ pINChI->bExtract |= pCS->bExtract;
2451
+ #endif
2452
+ ret2 = CheckCanonNumberingCorrectness(
2453
+ num_atoms, i?num_at_tg:num_atoms,
2454
+ at[i], pCS, i, pStrErrStruct );
2455
+ if ( ret2 ) {
2456
+ pINChI->nErrorCode = ret2;
2457
+ pINChI_Aux->nErrorCode = ret2;
2458
+ ret = ret2;
2459
+ }
2460
+ }
2461
+ }
2462
+ #if( TEST_RENUMB_ATOMS == 1 )
2463
+ ulCanonTime2 = InchiTimeElapsed( &ulCanonTimeStart );
2464
+ pINChI_Aux->ulCanonTime = ulCanonTime+ulCanonTime2;
2465
+ pINChI_Aux->ulNormTime = ulNormTime;
2466
+ #endif
2467
+ FreeNeighList( pCS->NeighList );
2468
+ DeAllocateCS( pCS2 );
2469
+ }
2470
+ if ( ret == 0 ) {
2471
+ ret = num_atoms;
2472
+ }
2473
+ /* treat the results later */
2474
+
2475
+ exit_function:
2476
+ DeAllocBCN( pBCN );
2477
+ if ( at[TAUT_YES] )
2478
+ inchi_free( at[TAUT_YES] );
2479
+ if ( at[TAUT_NON] )
2480
+ inchi_free( at[TAUT_NON] );
2481
+ free_t_group_info( t_group_info );
2482
+ free_t_group_info( t_group_info_orig );
2483
+ return ret;
2484
+ }
2485
+ #ifndef INCHI_ANSI_ONLY /* { */
2486
+ /***************************************************************************************/
2487
+ int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
2488
+ AT_NUMB *nOrigAtNosInCanonOrd, int num_at )
2489
+ {
2490
+ AT_NUMB *nCanonNbr, *nOrigAtNos, *nOrigAtNosOrd;
2491
+ int i, ret;
2492
+
2493
+ ret = 0;
2494
+
2495
+ nCanonNbr = (AT_NUMB *)inchi_calloc( num_at, sizeof(nCanonNbr[0]) );
2496
+ nOrigAtNos = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNos[0]) );
2497
+ nOrigAtNosOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNosOrd[0]) );
2498
+
2499
+ if ( !nCanonNbr || !nOrigAtNos || !nAtomOrdNbr || !nOrigAtNosOrd ) {
2500
+ ret = CT_OUT_OF_RAM; /* <BRKPT> */
2501
+ goto exit_function;
2502
+ }
2503
+ for ( i = 0; i < num_at; i ++ ) {
2504
+ nCanonNbr[i] = nAtomOrdNbr[i] = nOrigAtNosOrd[i] = (AT_NUMB)i;
2505
+ nOrigAtNos[i] = norm_at[i].orig_at_number;
2506
+ }
2507
+ /* get nCanonNbr[]: canon. numbers-1 in order of increasing original atom numbers */
2508
+ pn_RankForSort = nOrigAtNosInCanonOrd;
2509
+ qsort( nCanonNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
2510
+ /* get nOrigAtNosOrd[]: norm_atom ord. numbers the same order of increasing original atom numbers */
2511
+ pn_RankForSort = nOrigAtNos;
2512
+ qsort( nOrigAtNosOrd, num_at, sizeof(nOrigAtNosOrd[0]), CompRank );
2513
+ /* check whether the 2 sets of origiginal atom numbers have identical elements */
2514
+ for ( i = 0; i < num_at; i ++ ) {
2515
+ if ( nOrigAtNosInCanonOrd[nCanonNbr[i]] != nOrigAtNos[nOrigAtNosOrd[i]] ) {
2516
+ ret = CT_RANKING_ERR; /* <BRKPT> */
2517
+ goto exit_function;
2518
+ }
2519
+ }
2520
+ for ( i = 0; i < num_at; i ++ ) {
2521
+ nAtomOrdNbr[(int)nCanonNbr[i]] = nOrigAtNosOrd[i];
2522
+ }
2523
+
2524
+ /*
2525
+ pn_RankForSort = nCanonNbr;
2526
+ qsort( nAtomOrdNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
2527
+ */
2528
+
2529
+ exit_function:
2530
+ if ( nCanonNbr )
2531
+ inchi_free( nCanonNbr );
2532
+ if ( nOrigAtNos )
2533
+ inchi_free( nOrigAtNos );
2534
+ if ( nOrigAtNosOrd )
2535
+ inchi_free( nOrigAtNosOrd );
2536
+ return ret;
2537
+ }
2538
+ /***************************************************************************************/
2539
+ int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
2540
+ INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
2541
+ {
2542
+ int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
2543
+ int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
2544
+ int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len;
2545
+ int num_iso_H[NUM_H_ISOTOPES];
2546
+ char *str;
2547
+ AT_NUMB g, e;
2548
+ int num_at = pINChI->nNumberOfAtoms;
2549
+ int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
2550
+ AT_NUMB *nOrigAtNosInCanonOrd;
2551
+ INChI_Stereo *Stereo;
2552
+ AT_NUMB *nConstitEquNumbers;
2553
+ AT_NUMB *nConstitEquTGroupNumbers;
2554
+ S_CHAR *t_parity = NULL;
2555
+ AT_NUMB *nNumber = NULL;
2556
+ int bIncludeIsotopicH;
2557
+
2558
+ AT_NUMB *nNormAtNosInCanonOrd;
2559
+ int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
2560
+ int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
2561
+ int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
2562
+ int bRelRac= bRel || bRac;
2563
+ int bDoDisplaySp3 = 1;
2564
+
2565
+ inf_ATOM *inf_norm_at = inf_norm_at_data? inf_norm_at_data->at : NULL;
2566
+
2567
+ ret = 0;
2568
+ num_err = 0;
2569
+
2570
+ if ( !inf_norm_at )
2571
+ return ret;
2572
+ /* prepare removeable protons and H info */
2573
+ inf_norm_at_data->nNumRemovedProtons = pINChI_Aux->nNumRemovedProtons;
2574
+ MakeRemovedProtonsString( pINChI_Aux->nNumRemovedProtons, pINChI_Aux->nNumRemovedIsotopicH, NULL, bIsotopic,
2575
+ inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
2576
+ /* fill out info atom */
2577
+ if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
2578
+ pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
2579
+ bIsotopic = 0;
2580
+
2581
+ Stereo = bIsotopic? pINChI->StereoIsotopic :
2582
+ pINChI->Stereo;
2583
+ bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
2584
+
2585
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
2586
+ if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
2587
+ (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
2588
+ bDoDisplaySp3 = 0;
2589
+ if ( Stereo->nCompInv2Abs ) {
2590
+ inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
2591
+ }
2592
+ }
2593
+ #endif
2594
+ /* flag has stereo */
2595
+ if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
2596
+ inf_norm_at_data->StereoFlags |= INF_STEREO;
2597
+ }
2598
+
2599
+ /*
2600
+ if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
2601
+ (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
2602
+ bDoDisplaySp3 = 0;
2603
+ }
2604
+ */
2605
+ if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
2606
+ /* inversion changes stereo */
2607
+ if ( bRel ) {
2608
+ inf_norm_at_data->StereoFlags |= INF_STEREO_REL;
2609
+ } else
2610
+ if ( bRac ) {
2611
+ inf_norm_at_data->StereoFlags |= INF_STEREO_RAC;
2612
+ } else {
2613
+ inf_norm_at_data->StereoFlags |= INF_STEREO_ABS;
2614
+ }
2615
+ if ( bRelRac ) {
2616
+ inf_norm_at_data->StereoFlags |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
2617
+ }
2618
+ }
2619
+ if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
2620
+ /* display Inv stereo which is Absolute Stereo */
2621
+ nNumber = Stereo->nNumberInv;
2622
+ t_parity = Stereo->t_parityInv;
2623
+ nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
2624
+ pINChI_Aux->nOrigAtNosInCanonOrdInv;
2625
+ } else {
2626
+ /* display Inv stereo which is Absolute Stereo */
2627
+ if ( bDoDisplaySp3 ) {
2628
+ nNumber = Stereo->nNumber;
2629
+ t_parity = Stereo->t_parity;
2630
+ }
2631
+ nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
2632
+ pINChI_Aux->nOrigAtNosInCanonOrd;
2633
+ }
2634
+
2635
+ nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
2636
+ pINChI_Aux->nConstitEquNumbers;
2637
+ nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
2638
+ pINChI_Aux->nConstitEquTGroupNumbers;
2639
+ memset( inf_norm_at, 0, init_num_at*sizeof(inf_norm_at[0]) );
2640
+
2641
+ /* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
2642
+ nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
2643
+ if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
2644
+ goto exit_function;
2645
+ }
2646
+
2647
+ /* atom canonical and equivalence numbers > 0 */
2648
+ for ( i = 0; i < num_at; i ++ ) {
2649
+ j = (int)nNormAtNosInCanonOrd[i];
2650
+ if ( j < 0 || j >= num_at )
2651
+ continue;
2652
+ inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
2653
+ inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
2654
+ #ifdef DISPLAY_DEBUG_DATA
2655
+ inf_norm_at[j].nDebugData = 0;
2656
+ #if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
2657
+ inf_norm_at[j].nDebugData = norm_at[j].c_point;
2658
+ #endif
2659
+ #endif
2660
+ }
2661
+ /* tautomeric groups */
2662
+ if ( nNumberOfTGroups ) {
2663
+ /*
2664
+ : start from 1: bypass number of t-groups
2665
+ : j is a counter within the current t-group
2666
+ : g is a tautomeric group canonical number
2667
+ : e is a tautomeric group equivalence
2668
+ */
2669
+ for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
2670
+ n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
2671
+ e = nConstitEquTGroupNumbers[(int)g - 1];
2672
+ /* bypass number of hydrogen atoms, negative charges, ... */
2673
+ for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
2674
+ /* scan canonical numbers of atoms within the atom t-group */
2675
+ k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
2676
+ inf_norm_at[k].nTautGroupCanonNbr = g;
2677
+ inf_norm_at[k].nTautGroupEquNbr = e;
2678
+ }
2679
+ }
2680
+ if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
2681
+ ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
2682
+ goto exit_function;
2683
+ }
2684
+ }
2685
+ /* atoms that may exchange isotopic H */
2686
+ if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
2687
+ for ( i = 1; i < n; i ++ ) {
2688
+ j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
2689
+ k = (int)nNormAtNosInCanonOrd[j - 1];
2690
+ if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
2691
+ inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
2692
+ }
2693
+ }
2694
+ }
2695
+
2696
+ #if( DISPLAY_RING_SYSTEMS == 1 )
2697
+ /* debug only */
2698
+ for ( j = 0; j < num_at; j ++ ) {
2699
+ inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
2700
+ inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
2701
+ #if( USE_DISTANCES_FOR_RANKING == 1 )
2702
+ inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
2703
+ inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
2704
+ #else
2705
+ inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
2706
+ inf_norm_at[j].nTautGroupEquNbr = 0;
2707
+ #endif
2708
+ }
2709
+ #endif
2710
+
2711
+
2712
+
2713
+ /* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
2714
+ len_str = sizeof(inf_norm_at[0].at_string);
2715
+ for ( i = 0; i < init_num_at; i ++ ) {
2716
+ str = inf_norm_at[i].at_string;
2717
+ len = 0;
2718
+ bIncludeIsotopicH = bIsotopic && !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT);
2719
+ /* isotopic mass */
2720
+ atw = 0;
2721
+ if ( norm_at[i].iso_atw_diff && bIsotopic ) {
2722
+ if ( norm_at[i].at_type == ATT_PROTON ) {
2723
+ ; /* do not set isotopic mass of a tautomeric proton */
2724
+ } else
2725
+ if ( norm_at[i].el_number == PERIODIC_NUMBER_H && norm_at[i].chem_bonds_valence == 1 &&
2726
+ !norm_at[i].charge && !norm_at[i].radical && !norm_at[i].num_H &&
2727
+ (inf_norm_at[j=(int)norm_at[i].neighbor[0]].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
2728
+ ; /* do not set isotopic mass of an exchangeable proton */
2729
+ } else {
2730
+ atw = get_atw(norm_at[i].elname);
2731
+ atw += (norm_at[i].iso_atw_diff>0)? norm_at[i].iso_atw_diff-1:norm_at[i].iso_atw_diff;
2732
+ /*len += sprintf( str+len, "^%d", atw );*/
2733
+ }
2734
+ }
2735
+ /* element name */
2736
+ if ( norm_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
2737
+ len += sprintf( str+len, "%s", atw==2? "D" : "T" );
2738
+ } else {
2739
+ if ( atw ) {
2740
+ len += sprintf( str+len, "^%d", atw );
2741
+ }
2742
+ len += sprintf( str+len, "%s", norm_at[i].elname );
2743
+ }
2744
+ /* hydrogens */
2745
+ /* find number of previuosly removed terminal hydrogen atoms because these terminal H will be displayed */
2746
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
2747
+ num_iso_H[j] = norm_at[i].num_iso_H[j];
2748
+ }
2749
+ /* n = number of implicit H to display */
2750
+ for ( j = num_at, n = (int)norm_at[i].num_H; j < init_num_at; j ++ ) {
2751
+ /* subtract number of removed terminal */
2752
+ /* H atoms from the total number of H atoms */
2753
+ if ( i == (int)norm_at[j].neighbor[0] ) {
2754
+ n -= 1; /* found explicit H => decrement number of implicit H */
2755
+ m = (int)norm_at[j].iso_atw_diff-1;
2756
+ if ( 0 <= m && m < NUM_H_ISOTOPES ) {
2757
+ /* subtract number of removed terminal isotopic H */
2758
+ /* atoms from the total number of isotopic H atoms */
2759
+ num_iso_H[m] -= 1;
2760
+ }
2761
+ }
2762
+ }
2763
+ /* at this point n = number of implicit H to display,
2764
+ num_iso_H[] contains number of implicit isotopic H among n */
2765
+ if ( bIncludeIsotopicH ) {
2766
+ /* subtract number of isotopic H atoms from the total number of H atoms */
2767
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
2768
+ n -= num_iso_H[j];
2769
+ }
2770
+ }
2771
+ /* non-isotopic hydrogen atoms */
2772
+ if ( n > 1 ) {
2773
+ len += sprintf( str+len, "H%d", n );
2774
+ } else
2775
+ if ( n == 1 ) {
2776
+ len += sprintf( str+len, "H" );
2777
+ }
2778
+ /* isotopic hydrogen atoms */
2779
+ if ( bIncludeIsotopicH ) {
2780
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
2781
+ if ( num_iso_H[j] ) {
2782
+ if ( j == 0 || j != 1 && j != 2 ) {
2783
+ len += sprintf( str+len, "^%dH", j+1 );
2784
+ } else {
2785
+ len += sprintf( str+len, j == 1? "D" : "T" );
2786
+ }
2787
+ if ( num_iso_H[j] != 1 ) {
2788
+ len += sprintf( str+len, "%d", (int)num_iso_H[j] );
2789
+ }
2790
+ }
2791
+ }
2792
+ }
2793
+ if ( norm_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
2794
+ char *q;
2795
+ if ( !str[2] ) {
2796
+ str[1] = '2'; /* quick fix: replace HH with H2 */
2797
+ } else
2798
+ if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
2799
+ len = 1 + sprintf( str+1, "%d", n+1 );
2800
+ }
2801
+ }
2802
+ /*
2803
+ if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
2804
+ str[1] = '2';
2805
+ }
2806
+ */
2807
+ /* charge */
2808
+ if ( abs(norm_at[i].charge) > 1 )
2809
+ len += sprintf( str+len, "%+d", norm_at[i].charge );
2810
+ else
2811
+ if ( abs(norm_at[i].charge) == 1 )
2812
+ len += sprintf( str+len, "%s", norm_at[i].charge>0? "+" : "-" );
2813
+ /* radical */
2814
+ if ( norm_at[i].radical )
2815
+ len += sprintf( str+len, "%s", norm_at[i].radical==RADICAL_SINGLET? ":" :
2816
+ norm_at[i].radical==RADICAL_DOUBLET? "." :
2817
+ norm_at[i].radical==RADICAL_TRIPLET? ".." : "?");
2818
+ }
2819
+
2820
+ /* stereogenic centers */
2821
+ if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
2822
+ for ( i = 0; i < num_stereo; i ++ ) {
2823
+ j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
2824
+ c = t_parity[i];
2825
+ c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
2826
+ inf_norm_at[j].cStereoCenterParity = c;
2827
+ str=inf_norm_at[j].at_string;
2828
+ len = strlen(str);
2829
+ if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
2830
+ str[len++] = '(';
2831
+ str[len++] = inf_norm_at[j].cStereoCenterParity;
2832
+ str[len++] = ')';
2833
+ str[len] = '\0';
2834
+ /* mark ambuguous stereo center */
2835
+ if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
2836
+ len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
2837
+ memmove( str+1, str, len+1 );
2838
+ str[0] = '!'; /* output the atom in red color */
2839
+ }
2840
+ }
2841
+ }
2842
+ }
2843
+
2844
+ /* stereogenic bonds */
2845
+ /* (cumulenes with odd number of double bonds are stereocenters, */
2846
+ /* and atom parity should be set) */
2847
+ if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
2848
+ for ( i = 0; i < num_stereo; i ++ ) {
2849
+ int start_at, num_eql=0, bAmbiguousStereoBond = 0;
2850
+ j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
2851
+ k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
2852
+ start_at = j;
2853
+ c = Stereo->b_parity[i];
2854
+
2855
+ c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
2856
+
2857
+ /* mark ambuguous stereo bond atom(s) */
2858
+ if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
2859
+ (len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
2860
+ str[0] != '!' ) {
2861
+ memmove( str+1, str, len );
2862
+ str[0] = '!'; /* output the atom in red color */
2863
+ bAmbiguousStereoBond ++;
2864
+ }
2865
+ if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
2866
+ (len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
2867
+ str[0] != '!' ) {
2868
+ memmove( str+1, str, len );
2869
+ str[0] = '!'; /* output the atom in red color */
2870
+ bAmbiguousStereoBond ++;
2871
+ }
2872
+
2873
+ /* find the opposite atom k. */
2874
+ /* Note: since it may be a cumulene, find the shortest(best) path */
2875
+ /* to atom number k to avoid confusion in case of, for example, */
2876
+ /* 4-member aromatic rings. */
2877
+ best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
2878
+ for ( n = 0; n < norm_at[j].valence; n ++ ) {
2879
+ if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
2880
+ /* single bond cannot be stereogenic. */
2881
+ continue;
2882
+ }
2883
+ /* best_len = MAX_CUMULENE_LEN+1; */
2884
+ len = 0; /* number of bonds in cumulene - 1 */
2885
+ next_atom[len] = (int)norm_at[j].neighbor[n];
2886
+ next_neigh[len] = n;
2887
+ cur_atom = j;
2888
+ while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
2889
+ next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0] == cur_atom);
2890
+ next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]];
2891
+ cur_atom = next_atom[len];
2892
+ len ++;
2893
+ }
2894
+ if ( next_atom[len] == k ) {
2895
+ if ( len < best_len ) {
2896
+ memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
2897
+ memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
2898
+ best_len = len;
2899
+ num_eql = 0;
2900
+ if ( len == 0 ) {
2901
+ break; /* path length cannot be smaller than 1 */
2902
+ }
2903
+ } else
2904
+ if ( len == best_len ) {
2905
+ num_eql ++;
2906
+ }
2907
+ }
2908
+ }
2909
+ if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
2910
+ if ( num_eql ) {
2911
+ num_err ++; /* program error; no breakpoint here */
2912
+ }
2913
+ if ( best_len % 2 ) {
2914
+ /* even number of bonds: chiral atom, draw parity on the cenrtal atom */
2915
+ j = best_next_atom[best_len/2];
2916
+ inf_norm_at[j].cStereoCenterParity = c;
2917
+ str=inf_norm_at[j].at_string;
2918
+ len = strlen(str);
2919
+ if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
2920
+ str[len++] = '(';
2921
+ str[len++] = inf_norm_at[j].cStereoCenterParity;
2922
+ str[len++] = ')';
2923
+ str[len] = '\0';
2924
+ }
2925
+ } else {
2926
+ /* odd number of bonds: draw parity on the central bond */
2927
+ if ( best_len == 0 ) {
2928
+ /* double bond */
2929
+ j = start_at;
2930
+ k = best_next_neigh[0];
2931
+ } else {
2932
+ /* cumulene */
2933
+ best_len = best_len/2-1;
2934
+ j = best_next_atom[best_len];
2935
+ k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
2936
+ }
2937
+ /* mark "forward" bond */
2938
+ for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
2939
+ ;
2940
+ if ( m < MAX_STEREO_BONDS ) {
2941
+ inf_norm_at[j].cStereoBondParity[m] = c;
2942
+ inf_norm_at[j].cStereoBondNumber[m] = k;
2943
+ inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
2944
+ } else {
2945
+ num_err ++; /* program error; no breakpoint here */
2946
+ }
2947
+ /* mark "backward" bond */
2948
+ n = norm_at[j].neighbor[k];
2949
+ for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]; k ++ )
2950
+ ;
2951
+ if ( k < norm_at[n].valence ) {
2952
+ j = n;
2953
+ for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
2954
+ ;
2955
+ if ( m < MAX_STEREO_BONDS ) {
2956
+ inf_norm_at[j].cStereoBondParity[m] = c;
2957
+ inf_norm_at[j].cStereoBondNumber[m] = k;
2958
+ inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
2959
+ } else {
2960
+ num_err ++; /* program error; no breakpoint here */
2961
+ }
2962
+ } else {
2963
+ num_err ++; /* program error; no breakpoint here */
2964
+ }
2965
+ }
2966
+ } else {
2967
+ num_err ++; /* program error; no breakpoint here */
2968
+ }
2969
+ }
2970
+ }
2971
+
2972
+ for ( i = 0; i < init_num_at; i ++ ) {
2973
+ /* canonical numbers */
2974
+ if ( inf_norm_at[i].nCanonNbr ) {
2975
+ str = inf_norm_at[i].at_string;
2976
+ len = strlen(str);
2977
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
2978
+ if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
2979
+ if ( inf_norm_at[i].nCanonEquNbr ) {
2980
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
2981
+ } else
2982
+ if ( len + 1 < len_str ) {
2983
+ len += 1;
2984
+ strcat( str, "/" );
2985
+ }
2986
+ }
2987
+ /* tautomeric groups */
2988
+ if ( inf_norm_at[i].nTautGroupCanonNbr ) {
2989
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
2990
+ if ( inf_norm_at[i].nTautGroupEquNbr ) {
2991
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
2992
+ }
2993
+ }
2994
+ if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
2995
+ str[len++] = '/';
2996
+ str[len++] = '*';
2997
+ str[len] = '\0';
2998
+ }
2999
+ #ifdef DISPLAY_DEBUG_DATA
3000
+ if ( inf_norm_at[i].nDebugData ) {
3001
+ len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
3002
+ }
3003
+ #endif
3004
+ }
3005
+ }
3006
+
3007
+
3008
+ exit_function:
3009
+
3010
+ if ( nNormAtNosInCanonOrd )
3011
+ inchi_free( nNormAtNosInCanonOrd );
3012
+
3013
+
3014
+ return ret;
3015
+ }
3016
+ /***************************************************************************************/
3017
+ int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
3018
+ AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
3019
+ INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
3020
+ {
3021
+ int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
3022
+ int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
3023
+ int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len, bIncludeIsotopicH;
3024
+ int num_iso_H[NUM_H_ISOTOPES];
3025
+ char *str;
3026
+ AT_NUMB g, e;
3027
+ int num_at = pINChI->nNumberOfAtoms;
3028
+ int num_H = init_num_at - num_at; /* number of removed H */
3029
+ int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
3030
+ AT_NUMB *nOrigAtNosInCanonOrd;
3031
+ INChI_Stereo *Stereo;
3032
+ AT_NUMB *nConstitEquNumbers;
3033
+ AT_NUMB *nConstitEquTGroupNumbers;
3034
+ S_CHAR *t_parity = NULL;
3035
+ AT_NUMB *nNumber = NULL;
3036
+
3037
+ AT_NUMB *nNormAtNosInCanonOrd;
3038
+ int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
3039
+ int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
3040
+ int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
3041
+ int bRelRac= bRel || bRac;
3042
+ int bDoDisplaySp3 = 1;
3043
+
3044
+ inf_ATOM *inf_norm_at = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset : NULL;
3045
+ inp_ATOM *norm_at = inp_norm_at? inp_norm_at + offset : NULL;
3046
+ inf_ATOM *inf_norm_at_H = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset_H : NULL;
3047
+ inp_ATOM *norm_at_H = inp_norm_at? inp_norm_at + offset_H : NULL;
3048
+
3049
+ ret = 0;
3050
+ num_err = 0;
3051
+
3052
+ if ( !inf_norm_at )
3053
+ return ret;
3054
+ /* -- already added in FillOutCompositeCanonInfAtom() --
3055
+ if ( bIsotopic ) {
3056
+ for ( i = 0, j = 0; i < NUM_H_ISOTOPES; i ++ ) {
3057
+ if ( pINChI_Aux->nNumRemovedIsotopicH[i] ) {
3058
+ inf_norm_at_data->num_iso_H[i] += pINChI_Aux->nNumRemovedIsotopicH[i];
3059
+ inf_norm_at_data->num_removed_iso_H ++;
3060
+ }
3061
+ }
3062
+ }
3063
+ */
3064
+
3065
+ if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
3066
+ pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
3067
+ bIsotopic = 0;
3068
+
3069
+ Stereo = bIsotopic? pINChI->StereoIsotopic :
3070
+ pINChI->Stereo;
3071
+ bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
3072
+
3073
+ #if( REL_RAC_STEREO_IGN_1_SC == 1 )
3074
+ if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
3075
+ (Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
3076
+ bDoDisplaySp3 = 0;
3077
+ if ( Stereo->nCompInv2Abs ) {
3078
+ inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
3079
+ }
3080
+ }
3081
+ #endif
3082
+ /* flag has stereo */
3083
+ if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
3084
+ (*pStereoFlags) |= INF_STEREO;
3085
+ }
3086
+
3087
+ /*
3088
+ if ( bDoDisplaySp3 && bRelRac && Stereo->nCompInv2Abs && Stereo->nNumberOfStereoCenters < 2 ) {
3089
+ bDoDisplaySp3 = 0;
3090
+ }
3091
+ */
3092
+ if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
3093
+ /* inversion changes stereo */
3094
+ if ( bRel ) {
3095
+ (*pStereoFlags) |= INF_STEREO_REL;
3096
+ } else
3097
+ if ( bRac ) {
3098
+ (*pStereoFlags) |= INF_STEREO_RAC;
3099
+ } else {
3100
+ (*pStereoFlags) |= INF_STEREO_ABS;
3101
+ }
3102
+ if ( bRelRac ) {
3103
+ (*pStereoFlags) |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
3104
+ }
3105
+ }
3106
+ if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
3107
+ /* display Inv stereo which is Absolute Stereo */
3108
+ nNumber = Stereo->nNumberInv;
3109
+ t_parity = Stereo->t_parityInv;
3110
+ nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
3111
+ pINChI_Aux->nOrigAtNosInCanonOrdInv;
3112
+ } else {
3113
+ /* display Output stereo which is Absolute Stereo */
3114
+ if ( bDoDisplaySp3 ) {
3115
+ nNumber = Stereo->nNumber;
3116
+ t_parity = Stereo->t_parity;
3117
+ }
3118
+ nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
3119
+ pINChI_Aux->nOrigAtNosInCanonOrd;
3120
+ }
3121
+
3122
+ nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
3123
+ pINChI_Aux->nConstitEquNumbers;
3124
+ nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
3125
+ pINChI_Aux->nConstitEquTGroupNumbers;
3126
+ memset( inf_norm_at, 0, num_at*sizeof(inf_norm_at[0]) );
3127
+ if ( num_H > 0 ) {
3128
+ memset( inf_norm_at_H, 0, num_H*sizeof(inf_norm_at[0]) );
3129
+ }
3130
+
3131
+ /* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
3132
+ nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
3133
+ if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
3134
+ goto exit_function;
3135
+ }
3136
+
3137
+ /* atom canonical and equivalence numbers > 0 */
3138
+ for ( i = 0; i < num_at; i ++ ) {
3139
+ j = (int)nNormAtNosInCanonOrd[i];
3140
+ if ( j < 0 || j >= num_at )
3141
+ continue;
3142
+ inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
3143
+ inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
3144
+ #ifdef DISPLAY_DEBUG_DATA
3145
+ inf_norm_at[j].nDebugData = 0;
3146
+ #if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
3147
+ inf_norm_at[j].nDebugData = norm_at[j].c_point;
3148
+ #endif
3149
+ #endif
3150
+ }
3151
+ /* tautomeric groups */
3152
+ if ( nNumberOfTGroups ) {
3153
+ /*
3154
+ : start from 1: bypass number of t-groups
3155
+ : j is a counter within the current t-group
3156
+ : g is a tautomeric group canonical number
3157
+ : e is a tautomeric group equivalence
3158
+ */
3159
+ for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
3160
+ n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
3161
+ e = nConstitEquTGroupNumbers[(int)g - 1];
3162
+ /* bypass number of hydrogen atoms, negative charges, ... */
3163
+ for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
3164
+ /* scan canonical numbers of atoms within the atom t-group */
3165
+ k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
3166
+ inf_norm_at[k].nTautGroupCanonNbr = g;
3167
+ inf_norm_at[k].nTautGroupEquNbr = e;
3168
+ }
3169
+ }
3170
+ if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
3171
+ ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
3172
+ goto exit_function;
3173
+ }
3174
+ }
3175
+ /* atoms that may exchange isotopic H */
3176
+ if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
3177
+ for ( i = 1; i < n; i ++ ) {
3178
+ j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
3179
+ k = (int)nNormAtNosInCanonOrd[j - 1];
3180
+ if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
3181
+ inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
3182
+ }
3183
+ }
3184
+ }
3185
+ #if( DISPLAY_RING_SYSTEMS == 1 )
3186
+ /* debug only */
3187
+ for ( j = 0; j < num_at; j ++ ) {
3188
+ inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
3189
+ inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
3190
+ #if( USE_DISTANCES_FOR_RANKING == 1 )
3191
+ inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
3192
+ inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
3193
+ #else
3194
+ inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
3195
+ inf_norm_at[j].nTautGroupEquNbr = 0;
3196
+ #endif
3197
+ }
3198
+ #endif
3199
+
3200
+
3201
+
3202
+ /* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
3203
+ len_str = sizeof(inf_norm_at[0].at_string);
3204
+ for ( i = 0; i < init_num_at; i ++ ) {
3205
+ inf_ATOM *cur_inf_norm_at = (i < num_at)? inf_norm_at+i : inf_norm_at_H+i-num_at;
3206
+ inp_ATOM *cur_norm_at = (i < num_at)? norm_at +i : norm_at_H +i-num_at;
3207
+ str = cur_inf_norm_at->at_string;
3208
+ len = 0;
3209
+ bIncludeIsotopicH = bIsotopic && (i >= num_at || !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT));
3210
+ /* isotopic mass */
3211
+ atw = 0;
3212
+ if ( cur_norm_at->iso_atw_diff && bIsotopic ) {
3213
+ if ( cur_norm_at->at_type == ATT_PROTON ) {
3214
+ ; /* do not set isotopic mass of a tautomeric proton */
3215
+ } else
3216
+ if ( num_at <= i && cur_norm_at->el_number == PERIODIC_NUMBER_H && cur_norm_at->chem_bonds_valence == 1 &&
3217
+ !cur_norm_at->charge && !cur_norm_at->radical && !cur_norm_at->num_H &&
3218
+ 0 <= (j=(int)cur_norm_at->neighbor[0]-offset) && j < num_at &&
3219
+ (inf_norm_at[j].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
3220
+ ; /* do not set isotopic mass of an exchangeable proton */
3221
+ } else {
3222
+ atw = get_atw(cur_norm_at->elname);
3223
+ atw += (cur_norm_at->iso_atw_diff>0)? cur_norm_at->iso_atw_diff-1:cur_norm_at->iso_atw_diff;
3224
+ /*len += sprintf( str+len, "^%d", atw );*/
3225
+ }
3226
+ }
3227
+ /* element name */
3228
+ if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
3229
+ len += sprintf( str+len, "%s", atw==2? "D" : "T" );
3230
+ } else {
3231
+ if ( atw ) {
3232
+ len += sprintf( str+len, "^%d", atw );
3233
+ }
3234
+ len += sprintf( str+len, "%s", cur_norm_at->elname );
3235
+ }
3236
+ /* hydrogens */
3237
+ /* find number of previuosly removed terminal hydrogen atoms */
3238
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3239
+ num_iso_H[j] = cur_norm_at->num_iso_H[j];
3240
+ }
3241
+ for ( j = 0, n = (int)cur_norm_at->num_H; j < num_H; j ++ ) {
3242
+ /* subtract number of removed terminal */
3243
+ /* H atoms from the total number of H atoms */
3244
+ if ( i == (int)norm_at_H[j].neighbor[0]-offset ) {
3245
+ n -= 1;
3246
+ m = (int)norm_at_H[j].iso_atw_diff-1;
3247
+ if ( 0 <= m && m < NUM_H_ISOTOPES ) {
3248
+ /* subtract number of removed terminal isotopic */
3249
+ /* H atoms from the total number of isotopic H atoms */
3250
+ num_iso_H[m] -= 1;
3251
+ }
3252
+ }
3253
+ }
3254
+ if ( bIncludeIsotopicH ) {
3255
+ /* subtract number of isotopic H atoms from the total number of H atoms */
3256
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3257
+ n -= num_iso_H[j];
3258
+ }
3259
+ }
3260
+ /* non-isotopic hydrogen atoms */
3261
+ if ( n > 1 ) {
3262
+ len += sprintf( str+len, "H%d", n );
3263
+ } else
3264
+ if ( n == 1 ) {
3265
+ len += sprintf( str+len, "H" );
3266
+ }
3267
+ /* isotopic hydrogen atoms */
3268
+ if ( bIncludeIsotopicH ) {
3269
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3270
+ if ( num_iso_H[j] ) {
3271
+ if ( j == 0 || j != 1 && j != 2 ) {
3272
+ len += sprintf( str+len, "^%dH", j+1 );
3273
+ } else {
3274
+ len += sprintf( str+len, j == 1? "D" : "T" );
3275
+ }
3276
+ if ( num_iso_H[j] != 1 ) {
3277
+ len += sprintf( str+len, "%d", (int)num_iso_H[j] );
3278
+ }
3279
+ }
3280
+ }
3281
+ }
3282
+ if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
3283
+ char *q;
3284
+ if ( !str[2] ) {
3285
+ str[1] = '2'; /* quick fix: replace HH with H2 */
3286
+ } else
3287
+ if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
3288
+ len = 1 + sprintf( str+1, "%d", n+1 );
3289
+ }
3290
+ }
3291
+ /* charge */
3292
+ if ( abs(cur_norm_at->charge) > 1 )
3293
+ len += sprintf( str+len, "%+d", cur_norm_at->charge );
3294
+ else
3295
+ if ( abs(cur_norm_at->charge) == 1 )
3296
+ len += sprintf( str+len, "%s", cur_norm_at->charge>0? "+" : "-" );
3297
+ /* radical */
3298
+ if ( cur_norm_at->radical )
3299
+ len += sprintf( str+len, "%s", cur_norm_at->radical==RADICAL_SINGLET? ":" :
3300
+ cur_norm_at->radical==RADICAL_DOUBLET? "." :
3301
+ cur_norm_at->radical==RADICAL_TRIPLET? ".." : "?");
3302
+ }
3303
+
3304
+ /* stereogenic centers */
3305
+ if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
3306
+ for ( i = 0; i < num_stereo; i ++ ) {
3307
+ j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
3308
+ c = t_parity[i];
3309
+ c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3310
+ inf_norm_at[j].cStereoCenterParity = c;
3311
+ str=inf_norm_at[j].at_string;
3312
+ len = strlen(str);
3313
+ if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3314
+ str[len++] = '(';
3315
+ str[len++] = inf_norm_at[j].cStereoCenterParity;
3316
+ str[len++] = ')';
3317
+ str[len] = '\0';
3318
+ /* mark ambuguous stereo center */
3319
+ if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
3320
+ len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
3321
+ memmove( str+1, str, len+1 );
3322
+ str[0] = '!'; /* output the atom in red color */
3323
+ }
3324
+ }
3325
+ }
3326
+ }
3327
+
3328
+ /* stereogenic bonds */
3329
+ /* (cumulenes with odd number of double bonds are stereocenters, */
3330
+ /* and atom parity should be set) */
3331
+ if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
3332
+ for ( i = 0; i < num_stereo; i ++ ) {
3333
+ int start_at, num_eql=0, bAmbiguousStereoBond = 0;
3334
+ j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
3335
+ k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
3336
+ start_at = j;
3337
+ c = Stereo->b_parity[i];
3338
+
3339
+ c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
3340
+
3341
+ /* mark ambuguous stereo bond atom(s) */
3342
+ if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
3343
+ (len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3344
+ str[0] != '!' ) {
3345
+ memmove( str+1, str, len );
3346
+ str[0] = '!'; /* output the atom in red color */
3347
+ bAmbiguousStereoBond ++;
3348
+ }
3349
+ if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
3350
+ (len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
3351
+ str[0] != '!' ) {
3352
+ memmove( str+1, str, len );
3353
+ str[0] = '!'; /* output the atom in red color */
3354
+ bAmbiguousStereoBond ++;
3355
+ }
3356
+
3357
+ /* find the opposite atom k. */
3358
+ /* Note: since it may be a cumulene, find the shortest(best) path */
3359
+ /* to atom number k to avoid confusion in case of, for example, */
3360
+ /* 4-member aromatic rings. */
3361
+ best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
3362
+ for ( n = 0; n < norm_at[j].valence; n ++ ) {
3363
+ if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
3364
+ /* single bond cannot be stereogenic. */
3365
+ continue;
3366
+ }
3367
+ /* best_len = MAX_CUMULENE_LEN+1; */
3368
+ len = 0; /* number of bonds in cumulene - 1 */
3369
+ next_atom[len] = (int)norm_at[j].neighbor[n]-offset;
3370
+ next_neigh[len] = n;
3371
+ cur_atom = j;
3372
+ while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
3373
+ next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0]-offset == cur_atom);
3374
+ next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]]-offset;
3375
+ cur_atom = next_atom[len];
3376
+ len ++;
3377
+ }
3378
+ if ( next_atom[len] == k ) {
3379
+ if ( len < best_len ) {
3380
+ memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
3381
+ memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
3382
+ best_len = len;
3383
+ num_eql = 0;
3384
+ if ( len == 0 ) {
3385
+ break; /* path length cannot be smaller than 1 */
3386
+ }
3387
+ } else
3388
+ if ( len == best_len ) {
3389
+ num_eql ++;
3390
+ }
3391
+ }
3392
+ }
3393
+ if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
3394
+ if ( num_eql ) {
3395
+ num_err ++; /* program error; no breakpoint here */
3396
+ }
3397
+ if ( best_len % 2 ) {
3398
+ /* even number of bonds: chiral atom, draw parity on the cenrtal atom */
3399
+ j = best_next_atom[best_len/2];
3400
+ inf_norm_at[j].cStereoCenterParity = c;
3401
+ str=inf_norm_at[j].at_string;
3402
+ len = strlen(str);
3403
+ if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
3404
+ str[len++] = '(';
3405
+ str[len++] = inf_norm_at[j].cStereoCenterParity;
3406
+ str[len++] = ')';
3407
+ str[len] = '\0';
3408
+ }
3409
+ } else {
3410
+ /* odd number of bonds: draw parity on the central bond */
3411
+ if ( best_len == 0 ) {
3412
+ /* double bond */
3413
+ j = start_at;
3414
+ k = best_next_neigh[0];
3415
+ } else {
3416
+ /* cumulene */
3417
+ best_len = best_len/2-1;
3418
+ j = best_next_atom[best_len];
3419
+ k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
3420
+ }
3421
+ /* mark "forward" bond */
3422
+ for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3423
+ ;
3424
+ if ( m < MAX_STEREO_BONDS ) {
3425
+ inf_norm_at[j].cStereoBondParity[m] = c;
3426
+ inf_norm_at[j].cStereoBondNumber[m] = k;
3427
+ inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
3428
+ } else {
3429
+ num_err ++; /* program error; no breakpoint here */
3430
+ }
3431
+ /* mark "backward" bond */
3432
+ n = norm_at[j].neighbor[k]-offset;
3433
+ for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]-offset; k ++ )
3434
+ ;
3435
+ if ( k < norm_at[n].valence ) {
3436
+ j = n;
3437
+ for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
3438
+ ;
3439
+ if ( m < MAX_STEREO_BONDS ) {
3440
+ inf_norm_at[j].cStereoBondParity[m] = c;
3441
+ inf_norm_at[j].cStereoBondNumber[m] = k;
3442
+ inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
3443
+ } else {
3444
+ num_err ++; /* program error; no breakpoint here */
3445
+ }
3446
+ } else {
3447
+ num_err ++; /* program error; no breakpoint here */
3448
+ }
3449
+ }
3450
+ } else {
3451
+ num_err ++; /* program error; no breakpoint here */
3452
+ }
3453
+ }
3454
+ }
3455
+
3456
+ for ( i = 0; i < num_at; i ++ ) {
3457
+ /* canonical numbers */
3458
+ if ( inf_norm_at[i].nCanonNbr ) {
3459
+ str = inf_norm_at[i].at_string;
3460
+ len = strlen(str);
3461
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
3462
+ if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
3463
+ if ( inf_norm_at[i].nCanonEquNbr ) {
3464
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
3465
+ } else
3466
+ if ( len + 1 < len_str ) {
3467
+ len += 1;
3468
+ strcat( str, "/" );
3469
+ }
3470
+ }
3471
+ /* tautomeric groups */
3472
+ if ( inf_norm_at[i].nTautGroupCanonNbr ) {
3473
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
3474
+ if ( inf_norm_at[i].nTautGroupEquNbr ) {
3475
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
3476
+ }
3477
+ }
3478
+ if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
3479
+ str[len++] = '/';
3480
+ str[len++] = '*';
3481
+ str[len] = '\0';
3482
+ }
3483
+ #ifdef DISPLAY_DEBUG_DATA
3484
+ if ( inf_norm_at[i].nDebugData ) {
3485
+ len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
3486
+ }
3487
+ #endif
3488
+ }
3489
+ }
3490
+
3491
+
3492
+ exit_function:
3493
+
3494
+ if ( nNormAtNosInCanonOrd )
3495
+ inchi_free( nNormAtNosInCanonOrd );
3496
+
3497
+ return ret;
3498
+ }
3499
+
3500
+ /***************************************************************************************/
3501
+ int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
3502
+ int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers)
3503
+ {
3504
+ int i, j, m, n, ret, len_str, len, atw;
3505
+ int num_iso_H[NUM_H_ISOTOPES];
3506
+ char *str;
3507
+ int num_at = init_num_at - num_removed_H;
3508
+ int (*MakeNumber)(char*, int, const char*, int) = MakeDecNumber;
3509
+
3510
+ inf_ATOM *inf_at = inf_at_data? inf_at_data->at : NULL;
3511
+
3512
+
3513
+ ret = 0;
3514
+
3515
+
3516
+ if ( !inf_at )
3517
+ return ret;
3518
+
3519
+ memset( inf_at, 0, init_num_at*sizeof(inf_at[0]) );
3520
+
3521
+ inf_at_data->nNumRemovedProtons = nNumRemovedProtons;
3522
+ MakeRemovedProtonsString( nNumRemovedProtons, nNumRemovedProtonsIsotopic, NULL, bIsotopic, inf_at_data->szRemovedProtons, NULL );
3523
+ /*
3524
+ if ( inf_at_data->nNumRemovedProtons ) {
3525
+ sprintf ( inf_at_data->szRemovedProtons, "Proton balance: %c %d H+",
3526
+ inf_at_data->nNumRemovedProtons>=0? '+':'-',
3527
+ abs(inf_at_data->nNumRemovedProtons) );
3528
+ } else {
3529
+ inf_at_data->szRemovedProtons[0] = '\0';
3530
+
3531
+ }
3532
+ */
3533
+ /* atom canonical and equivalence numbers > 0 */
3534
+ for ( i = 0; i < num_at; i ++ ) {
3535
+ #if( DISPLAY_ORIG_AT_NUMBERS == 1 )
3536
+ inf_at[i].nCanonNbr = inp_at[i].orig_at_number;
3537
+ #else
3538
+ inf_at[i].nCanonNbr = (AT_NUMB)(i+1);
3539
+ #endif
3540
+ }
3541
+ /* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
3542
+ len_str = sizeof(inf_at[0].at_string);
3543
+ for ( i = 0; i < init_num_at; i ++ ) {
3544
+ str = inf_at[i].at_string;
3545
+ len = 0;
3546
+ /* isotopic mass */
3547
+ atw = 0;
3548
+ if ( inp_at[i].iso_atw_diff && bIsotopic ) {
3549
+ atw = get_atw(inp_at[i].elname);
3550
+ atw += (inp_at[i].iso_atw_diff>0)? inp_at[i].iso_atw_diff-1:inp_at[i].iso_atw_diff;
3551
+ /*len += sprintf( str+len, "^%d", atw );*/
3552
+ }
3553
+ /* element name */
3554
+ if ( inp_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
3555
+ len += sprintf( str+len, "%s", atw==2? "D" : "T" );
3556
+ } else {
3557
+ if ( atw ) {
3558
+ len += sprintf( str+len, "^%d", atw );
3559
+ }
3560
+ len += sprintf( str+len, "%s", inp_at[i].elname );
3561
+ }
3562
+ /* hydrogens */
3563
+ /* find number of previuosly removed terminal hydrogen atoms */
3564
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3565
+ num_iso_H[j] = inp_at[i].num_iso_H[j];
3566
+ }
3567
+ for ( j = num_at, n = (int)inp_at[i].num_H; j < init_num_at; j ++ ) {
3568
+ /* subtract number of removed terminal */
3569
+ /* H atoms from the total number of H atoms */
3570
+ if ( i == (int)inp_at[j].neighbor[0] ) {
3571
+ n -= 1;
3572
+ m = (int)inp_at[j].iso_atw_diff-1;
3573
+ if ( 0 <= m && m < NUM_H_ISOTOPES ) {
3574
+ /* subtract number of removed terminal isotopic */
3575
+ /* H atoms from the total number of isotopic H atoms */
3576
+ num_iso_H[m] -= 1;
3577
+ }
3578
+ }
3579
+ }
3580
+ if ( bIsotopic ) {
3581
+ /* subtract number of isotopic H atoms from the total number of H atoms */
3582
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3583
+ n -= num_iso_H[j];
3584
+ }
3585
+ }
3586
+ /* non-isotopic hydrogen atoms */
3587
+ if ( n > 1 ) {
3588
+ len += sprintf( str+len, "H%d", n );
3589
+ } else
3590
+ if ( n == 1 ) {
3591
+ len += sprintf( str+len, "H" ); /* fixed 12-21-2002: removed 3rd argument */
3592
+ }
3593
+ if ( bIsotopic ) {
3594
+ /* isotopic hydrogen atoms */
3595
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
3596
+ if ( num_iso_H[j] ) {
3597
+ if ( j == 0 || j != 1 && j != 2 ) {
3598
+ len += sprintf( str+len, "^%dH", j+1 );
3599
+ } else {
3600
+ len += sprintf( str+len, j == 1? "D" : "T" );
3601
+ }
3602
+ if ( num_iso_H[j] != 1 ) {
3603
+ len += sprintf( str+len, "%d", (int)num_iso_H[j] );
3604
+ }
3605
+ }
3606
+ }
3607
+ }
3608
+ if ( inp_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
3609
+ char *q;
3610
+ if ( !str[2] ) {
3611
+ str[1] = '2'; /* quick fix: replace HH with H2 */
3612
+ } else
3613
+ if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
3614
+ len = 1 + sprintf( str+1, "%d", n+1 );
3615
+ }
3616
+ }
3617
+ /*
3618
+ if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
3619
+ str[1] = '2';
3620
+ }
3621
+ */
3622
+ /* charge */
3623
+ if ( abs(inp_at[i].charge) > 1 )
3624
+ len += sprintf( str+len, "%+d", inp_at[i].charge );
3625
+ else
3626
+ if ( abs(inp_at[i].charge) == 1 )
3627
+ len += sprintf( str+len, "%s", inp_at[i].charge>0? "+" : "-" );
3628
+ /* radical */
3629
+ if ( inp_at[i].radical )
3630
+ len += sprintf( str+len, "%s", inp_at[i].radical==RADICAL_SINGLET? ":" :
3631
+ inp_at[i].radical==RADICAL_DOUBLET? "." :
3632
+ inp_at[i].radical==RADICAL_TRIPLET? ".." : "?");
3633
+ }
3634
+
3635
+ for ( i = 0; i < init_num_at; i ++ ) {
3636
+ /* canonical numbers */
3637
+ if ( inf_at[i].nCanonNbr ) {
3638
+ str = inf_at[i].at_string;
3639
+ len = strlen(str);
3640
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonNbr );
3641
+ if ( inf_at[i].nCanonEquNbr || inf_at[i].nTautGroupCanonNbr ) {
3642
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonEquNbr );
3643
+ }
3644
+ /* tautomeric groups */
3645
+ if ( inf_at[i].nTautGroupCanonNbr ) {
3646
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupCanonNbr );
3647
+ if ( inf_at[i].nTautGroupEquNbr ) {
3648
+ len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupEquNbr );
3649
+ }
3650
+ }
3651
+ }
3652
+ }
3653
+ ret = init_num_at;
3654
+
3655
+ return ret;
3656
+ }
3657
+ /**********************************************************************************************/
3658
+ int FillOutInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int num_removed_H,
3659
+ int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic,
3660
+ INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode )
3661
+ {
3662
+ if ( norm_at && inf_norm_at_data && inf_norm_at_data->at ) {
3663
+ if ( pINChI && pINChI_Aux ) {
3664
+ return FillOutCanonInfAtom( norm_at, inf_norm_at_data, init_num_at, bIsotopic, pINChI,
3665
+ pINChI_Aux, bAbcNumbers, nMode);
3666
+ } else {
3667
+ return FillOutInputInfAtom( norm_at, inf_norm_at_data, init_num_at, num_removed_H,
3668
+ nNumRemovedProtons, nNumRemovedProtonsIsotopic, bIsotopic, bAbcNumbers);
3669
+ }
3670
+ }
3671
+ return 0;
3672
+ }
3673
+ /***************************************************************************************/
3674
+ int FillOutCompositeCanonInfAtom(COMP_ATOM_DATA *composite_norm_data, INF_ATOM_DATA *inf_norm_at_data,
3675
+ int bIsotopic, int bTautomeric,
3676
+ PINChI2 *pINChI2, PINChI_Aux2 *pINChI_Aux2, int bAbcNumbers, INCHI_MODE nMode)
3677
+ {
3678
+ int i, num_components, j, k, ret;
3679
+ inp_ATOM *inp_norm_at;
3680
+ INChI *pINChI;
3681
+ INChI_Aux *pINChI_Aux;
3682
+ int num_inp_at, num_at, num_H, offset, offset_H, next_offset, next_offset_H;
3683
+
3684
+ if ( composite_norm_data && inf_norm_at_data && (bTautomeric == TAUT_INI || pINChI2 && pINChI_Aux2) ) {
3685
+ composite_norm_data += bTautomeric;
3686
+ inp_norm_at = composite_norm_data->at;
3687
+ num_components = composite_norm_data->num_components;
3688
+ offset = 0;
3689
+ offset_H = composite_norm_data->num_at - composite_norm_data->num_removed_H;
3690
+ if ( bTautomeric == TAUT_INI ) {
3691
+ ret = FillOutInputInfAtom( composite_norm_data->at, inf_norm_at_data, composite_norm_data->num_at,
3692
+ composite_norm_data->num_removed_H,
3693
+ composite_norm_data->nNumRemovedProtons,
3694
+ composite_norm_data->nNumRemovedProtonsIsotopic,
3695
+ bIsotopic, bAbcNumbers);
3696
+ return ret;
3697
+ } else {
3698
+ for ( i = 0; i < num_components; i ++ ) {
3699
+ j = inchi_min(bTautomeric, TAUT_YES);
3700
+ /* count isotopic H on removed atoms -- isolated H(+) cations */
3701
+ inf_norm_at_data->nNumRemovedProtons += pINChI_Aux2[i][j]->nNumRemovedProtons;
3702
+ if ( bIsotopic && bTautomeric == TAUT_YES ) {
3703
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
3704
+ if ( pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k] ) {
3705
+ inf_norm_at_data->num_iso_H[k] += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
3706
+ inf_norm_at_data->num_removed_iso_H += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
3707
+ }
3708
+ }
3709
+ }
3710
+ /* ignore deleted components */
3711
+ if ( pINChI2[i][j] && pINChI2[i][j]->bDeleted ) {
3712
+ continue;
3713
+ }
3714
+ if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
3715
+ j = ALT_TAUT(j);
3716
+ if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
3717
+ continue; /* error ??? */
3718
+ }
3719
+ }
3720
+ pINChI = pINChI2[i][j];
3721
+ pINChI_Aux = pINChI_Aux2[i][j];
3722
+ next_offset = composite_norm_data->nOffsetAtAndH[2*i];
3723
+ next_offset_H = composite_norm_data->nOffsetAtAndH[2*i+1];
3724
+ num_at = next_offset - offset;
3725
+ if ( num_at <= 0 )
3726
+ continue;
3727
+ num_H = next_offset_H - offset_H;
3728
+ num_inp_at = num_at + num_H;
3729
+ if ( num_at != pINChI->nNumberOfAtoms || num_at != pINChI_Aux->nNumberOfAtoms ) {
3730
+ return 0; /* error */
3731
+ }
3732
+ ret = FillOutOneCanonInfAtom(inp_norm_at, inf_norm_at_data,
3733
+ inf_norm_at_data->pStereoFlags+i+1, num_inp_at,
3734
+ offset, offset_H, bIsotopic, pINChI, pINChI_Aux, bAbcNumbers, nMode);
3735
+ if ( ret )
3736
+ return 0; /* error */
3737
+
3738
+ inf_norm_at_data->StereoFlags |= inf_norm_at_data->pStereoFlags[i+1];
3739
+ offset = next_offset;
3740
+ offset_H = next_offset_H;
3741
+ }
3742
+ }
3743
+ MakeRemovedProtonsString( inf_norm_at_data->nNumRemovedProtons, inf_norm_at_data->num_iso_H, NULL, bIsotopic,
3744
+ inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
3745
+ }
3746
+ return 1;
3747
+ }
3748
+ #endif /* } ifndef INCHI_ANSI_ONLY */
3749
+ /**********************************************************************************************/
3750
+ int CheckCanonNumberingCorrectness(int num_atoms, int num_at_tg,
3751
+ sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
3752
+ char *pStrErrStruct )
3753
+ {
3754
+ int i, ret=0;
3755
+ AT_NUMB *pCanonOrd=NULL;
3756
+ int nErrorCode = 0;
3757
+ AT_NUMB *pCanonRank; /* canonical ranks of the atoms or tautomeric groups */
3758
+ AT_NUMB *pCanonRankAtoms=NULL;
3759
+
3760
+ static int count=0; /* for debug only */
3761
+ count ++;
3762
+
3763
+ pCanonRankAtoms = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pCanonRankAtoms[0]) );
3764
+
3765
+ /**********************************************************************************************
3766
+ *
3767
+ * non-isotopic part
3768
+ */
3769
+ pCanonOrd = pCS->nLenCanonOrdStereo > 0? pCS->nCanonOrdStereo :
3770
+ pCS->nLenCanonOrd > 0? pCS->nCanonOrd : NULL;
3771
+ pCanonRank = pCanonRankAtoms;
3772
+ if ( pCanonOrd && pCanonRank ) {
3773
+ for ( i = 0; i < num_at_tg; i ++ ) {
3774
+ pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
3775
+ }
3776
+ ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
3777
+ if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
3778
+ nErrorCode |= WARN_FAILED_STEREO;
3779
+ }
3780
+
3781
+ } else {
3782
+ nErrorCode |= ERR_NO_CANON_RESULTS;
3783
+ goto exit_function;
3784
+ }
3785
+ /**********************************************************************************************
3786
+ *
3787
+ * isotopic part
3788
+ */
3789
+ pCanonOrd = pCS->nLenCanonOrdIsotopicStereo > 0? pCS->nCanonOrdIsotopicStereo :
3790
+ pCS->nLenCanonOrdIsotopic > 0? pCS->nCanonOrdIsotopic : NULL;
3791
+ pCanonRank = pCanonRankAtoms;
3792
+
3793
+ if ( pCanonOrd && pCanonRank ) {
3794
+ for ( i = 0; i < num_at_tg; i ++ ) {
3795
+ pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
3796
+ }
3797
+ ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
3798
+ if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
3799
+ nErrorCode |= (pCS->nLenCanonOrdIsotopicStereo? WARN_FAILED_ISOTOPIC_STEREO : WARN_FAILED_ISOTOPIC);
3800
+ }
3801
+
3802
+ }
3803
+
3804
+ exit_function:
3805
+ if ( pCanonRankAtoms )
3806
+ inchi_free( pCanonRankAtoms );
3807
+
3808
+ if ( nErrorCode ) {
3809
+ return CT_CANON_ERR;
3810
+ }
3811
+ return 0;
3812
+ }