rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }