rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,2786 @@
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
+ /*
11
+ The code in this #include file reads InChI AuxInfo
12
+ */
13
+
14
+ /****************************************************************************/
15
+ #define MIN_BOND_LENGTH (1.0e-6)
16
+ #define INCHI_LINE_LEN 512 /*1024*/ /*256*/
17
+ #define INCHI_LINE_ADD 384 /*128*/ /*64*/
18
+ /* Note: (INCHI_LINE_LEN - INCHI_LINE_ADD) > (length of the longest item: szCoord) = 33 */
19
+ /*****************************************************************************/
20
+
21
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
22
+
23
+ #define AB_MAX_WELL_DEFINED_PARITY inchi_max(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* 1, 2 => well defined parities, uncluding 'unknown' */
24
+ #define AB_MIN_WELL_DEFINED_PARITY inchi_min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) */
25
+ #define ATOM_PARITY_WELL_DEF(X) (AB_MIN_WELL_DEFINED_PARITY <= (X) && (X) <= AB_MAX_WELL_DEFINED_PARITY)
26
+
27
+ #define inchi_NUMH2(AT,CUR_AT) ((AT[CUR_AT].num_iso_H[0]>0?AT[CUR_AT].num_iso_H[0]:0) +AT[CUR_AT].num_iso_H[1]+AT[CUR_AT].num_iso_H[2]+AT[CUR_AT].num_iso_H[3])
28
+
29
+ #define SB_PARITY_FLAG 0x38 /* disconnected structure has undef. parity */
30
+ #define SB_PARITY_SHFT 3
31
+ #define SB_PARITY_MASK 0x07
32
+ #define SB_PARITY_1(X) (X & SB_PARITY_MASK) /* refers to connected structure */
33
+ #define SB_PARITY_2(X) (((X) >> SB_PARITY_SHFT) & SB_PARITY_MASK) /* refers to connected structure */
34
+
35
+
36
+ int str_fgetc( INCHI_FILE *f );
37
+ char *str_fgets( char *szLine, int len, INCHI_FILE *f );
38
+ int my_fgets( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine );
39
+
40
+ #endif
41
+
42
+
43
+ #ifdef INCHI_LIBRARY
44
+
45
+ void FreeInchi_Atom( inchi_Atom **at );
46
+ inchi_Atom *CreateInchi_Atom( int num_atoms );
47
+ void FreeInchi_Input( inchi_Input *inp_at_data );
48
+ S_SHORT *is_in_the_slist( S_SHORT *pathAtom, S_SHORT nNextAtom, int nPathLen );
49
+ int is_element_a_metal( char szEl[] );
50
+
51
+ char *str_fgetsTab( char *szLine, int len, INCHI_FILE *f );
52
+ int my_fgetsTab( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine );
53
+ int my_fgetsTab1( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine );
54
+
55
+ #endif
56
+
57
+ #ifndef INCHI_MAIN
58
+
59
+ void FreeInchi_Stereo0D( inchi_Stereo0D **stereo0D );
60
+ inchi_Stereo0D *CreateInchi_Stereo0D( int num_stereo0D );
61
+ int Extract0DParities( inp_ATOM *at, int nNumAtoms, inchi_Stereo0D *stereo0D,
62
+ int num_stereo0D, char *pStrErr, int *err );
63
+
64
+ #endif
65
+
66
+
67
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
68
+ /*******************************************************************/
69
+ int str_fgetc( INCHI_FILE *f )
70
+ {
71
+ #ifdef INCHI_LIBRARY
72
+ if ( f->nPtr < f->nUsedLength ) {
73
+ return (int)f->pStr[f->nPtr++];
74
+ }
75
+ return EOF;
76
+ #else
77
+ return fgetc( f );
78
+ #endif
79
+ }
80
+ /*******************************************************************/
81
+ char *str_fgets( char *szLine, int len, INCHI_FILE *f )
82
+ {
83
+ int length=0, c;
84
+ len --;
85
+ while ( length < len && EOF != (c = str_fgetc( f )) ) {
86
+ szLine[length++] = (char)c;
87
+ if ( c == '\n' )
88
+ break;
89
+ }
90
+ if ( !length && EOF == c ) {
91
+ return NULL;
92
+ }
93
+ szLine[length] = '\0';
94
+ return szLine;
95
+ }
96
+ /*******************************************************************/
97
+ int my_fgets( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine )
98
+ {
99
+ int length;
100
+ char *p;
101
+ do {
102
+ p = str_fgets( szLine, len-1, f );
103
+ if ( !p ) {
104
+ *bTooLongLine = 0;
105
+ return -1; /* end of file or cannot read */
106
+ }
107
+ szLine[len-1] = '\0';
108
+ /*
109
+ *bTooLongLine = !strchr( szLine, '\n' );
110
+ */
111
+ p = strchr( szLine, '\n' );
112
+ *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
113
+ LtrimRtrim( szLine, &length );
114
+ } while ( !length );
115
+ return length;
116
+ }
117
+
118
+ #endif
119
+
120
+
121
+ #ifdef INCHI_LIBRARY
122
+ /******************************************************************************************************/
123
+ void FreeInchi_Atom( inchi_Atom **at )
124
+ {
125
+ if ( at && *at ) {
126
+ inchi_free( *at );
127
+ *at = NULL;
128
+ }
129
+ }
130
+ /******************************************************************************************************/
131
+ inchi_Atom *CreateInchi_Atom( int num_atoms )
132
+ {
133
+ inchi_Atom *p = (inchi_Atom* ) inchi_calloc(num_atoms, sizeof(inchi_Atom) );
134
+ return p;
135
+ }
136
+ /******************************************************************************************************/
137
+ void FreeInchi_Input( inchi_Input *inp_at_data )
138
+ {
139
+ FreeInchi_Atom( &inp_at_data->atom );
140
+ FreeInchi_Stereo0D( &inp_at_data->stereo0D );
141
+ memset( inp_at_data, 0, sizeof(*inp_at_data) );
142
+ }
143
+ /*************************************************************************/
144
+ S_SHORT *is_in_the_slist( S_SHORT *pathAtom, S_SHORT nNextAtom, int nPathLen )
145
+ {
146
+ for ( ; nPathLen && *pathAtom != nNextAtom; nPathLen--, pathAtom++ )
147
+ ;
148
+ return nPathLen? pathAtom : NULL;
149
+ }
150
+ /************************************************/
151
+ int is_element_a_metal( char szEl[] )
152
+ {
153
+ static char szMetals[] = "K;V;Y;W;U;"
154
+ "Li;Be;Na;Mg;Al;Ca;Sc;Ti;Cr;Mn;Fe;Co;Ni;Cu;Zn;Ga;Rb;Sr;Zr;"
155
+ "Nb;Mo;Tc;Ru;Rh;Pd;Ag;Cd;In;Sn;Sb;Cs;Ba;La;Ce;Pr;Nd;Pm;Sm;"
156
+ "Eu;Gd;Tb;Dy;Ho;Er;Tm;Yb;Lu;Hf;Ta;Re;Os;Ir;Pt;Au;Hg;Tl;Pb;"
157
+ "Bi;Po;Fr;Ra;Ac;Th;Pa;Np;Pu;Am;Cm;Bk;Cf;Es;Fm;Md;No;Lr;Rf;";
158
+ int len = strlen(szEl);
159
+ char *p;
160
+
161
+ if ( 0 < len && len <= 2 &&
162
+ isalpha( UCINT szEl[0] ) && isupper( szEl[0] ) &&
163
+ (p = strstr(szMetals, szEl) ) && p[len] == ';' ) {
164
+
165
+ return 1; /*return AtType_Metal;*/
166
+ }
167
+ return 0;
168
+ }
169
+ /*******************************************************************/
170
+ /* read up to len or tab or LF; if empty read next until finds non-empty line */
171
+ /* remove leading and trailing white spaces; keep zero termination */
172
+ /*******************************************************************/
173
+ char *str_fgetsTab( char *szLine, int len, INCHI_FILE *f )
174
+ {
175
+ int length=0, c;
176
+ len --;
177
+ while ( length < len && EOF != (c = str_fgetc( f )) ) {
178
+ if ( c == '\t' )
179
+ c = '\n';
180
+ szLine[length++] = (char)c;
181
+ if ( c == '\n' )
182
+ break;
183
+ }
184
+ if ( !length && EOF == c ) {
185
+ return NULL;
186
+ }
187
+ szLine[length] = '\0';
188
+ return szLine;
189
+ }
190
+ /*******************************************************************/
191
+ /* read up to len or tab or LF; if empty read next until finds non-empty line */
192
+ /* remove leading and trailing white spaces; keep zero termination */
193
+ /*******************************************************************/
194
+ int my_fgetsTab( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine )
195
+ {
196
+ int length;
197
+ char *p;
198
+ do {
199
+ p = str_fgetsTab( szLine, len-1, f );
200
+ if ( !p ) {
201
+ *bTooLongLine = 0;
202
+ return -1; /* end of file or cannot read */
203
+ }
204
+ szLine[len-1] = '\0';
205
+ /*
206
+ *bTooLongLine = !strchr( szLine, '\n' );
207
+ */
208
+ p = strchr( szLine, '\n' );
209
+ *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
210
+ LtrimRtrim( szLine, &length );
211
+ } while ( !length );
212
+ return length;
213
+ }
214
+ /*******************************************************************/
215
+ int my_fgetsTab1( char *szLine, int len, INCHI_FILE *f, int *bTooLongLine )
216
+ {
217
+ int length;
218
+ char *p;
219
+ /*do {*/
220
+ p = str_fgetsTab( szLine, len-1, f );
221
+ if ( !p ) {
222
+ *bTooLongLine = 0;
223
+ return -1; /* end of file or cannot read */
224
+ }
225
+ szLine[len-1] = '\0';
226
+ /*
227
+ *bTooLongLine = !strchr( szLine, '\n' );
228
+ */
229
+ p = strchr( szLine, '\n' );
230
+ *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
231
+ LtrimRtrim( szLine, &length );
232
+ /*} while ( !length );*/
233
+ return length;
234
+ }
235
+
236
+ #endif
237
+
238
+
239
+ #ifndef INCHI_MAIN
240
+ /******************************************************************************************************/
241
+ inchi_Stereo0D *CreateInchi_Stereo0D( int num_stereo0D )
242
+ {
243
+ return (inchi_Stereo0D* ) inchi_calloc(num_stereo0D, sizeof(inchi_Stereo0D) );
244
+ }
245
+ /******************************************************************************************************/
246
+ void FreeInchi_Stereo0D( inchi_Stereo0D **stereo0D )
247
+ {
248
+ if ( stereo0D && *stereo0D ) {
249
+ inchi_free( *stereo0D );
250
+ *stereo0D = NULL;
251
+ }
252
+ }
253
+ #endif
254
+
255
+
256
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
257
+
258
+ #ifdef INCHI_LIBRARY
259
+ #define INChITo_Atom ll_INChIToInchi_Atom
260
+ #else
261
+ #define INChITo_Atom ee_INChIToIbChI_Atom
262
+ #define FindToken e_FindToken
263
+ #define LoadLine e_LoadLine
264
+ #endif
265
+
266
+ #define AT_NUM_BONDS(AT) (AT).num_bonds
267
+ #define ATOM_NUMBER AT_NUM
268
+ #define IN_NEIGH_LIST is_in_the_slist
269
+ #define INPUT_FILE INCHI_FILE
270
+ #define Create_Atom CreateInchi_Atom
271
+ #define AT_BONDS_VAL(AT,I) AT[I].num_iso_H[0]
272
+ #define ISOLATED_ATOM (-15)
273
+ #define NUM_ISO_Hk(AT,I,K) AT[I].num_iso_H[K+1]
274
+ #define IS_METAL_ATOM(AT,I) is_element_a_metal( AT[I].elname )
275
+
276
+ #else
277
+
278
+ #define inchi_Atom inp_ATOM
279
+ #define AT_NUM_BONDS(AT) (AT).valence
280
+ #define ATOM_NUMBER AT_NUMB
281
+ #define IN_NEIGH_LIST is_in_the_list
282
+ #define inchi_NUMH2(AT,N) NUMH(AT,N)
283
+ #define INChITo_Atom cc_INChIToInpAtom
284
+ #define INPUT_FILE FILE
285
+ #define Create_Atom CreateInpAtom
286
+ #define AT_BONDS_VAL(AT,I) AT[I].chem_bonds_valence
287
+ #define ISOLATED_ATOM 15
288
+ #define NUM_ISO_Hk(AT,I,K) AT[I].num_iso_H[K]
289
+ #define IS_METAL_ATOM(AT,I) is_el_a_metal( AT[I].el_number )
290
+
291
+ #endif
292
+
293
+ /*****************************************************************************/
294
+ /* local prototypes */
295
+ char *FindToken( INPUT_FILE *inp_molfile, int *bTooLongLine, const char *sToken, int lToken,
296
+ char *szLine, int nLenLine, char *p, int *res );
297
+ char *LoadLine( INPUT_FILE *inp_molfile, int *bTooLongLine, int *bItemIsOver, char **s,
298
+ char *szLine, int nLenLine, int nMinLen2Load, char *p, int *res );
299
+
300
+
301
+ int INChITo_Atom(INPUT_FILE *inp_molfile, MOL_COORD **szCoord,
302
+ inchi_Stereo0D **stereo0D, int *num_stereo0D,
303
+ int bDoNotAddH, INPUT_TYPE nInputType, inchi_Atom **at,
304
+ int max_num_at,
305
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
306
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr );
307
+
308
+
309
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
310
+ /*****************************************************************************/
311
+ int INChIToInchi_Atom ( INCHI_FILE *inp_molfile, inchi_Stereo0D **stereo0D, int *num_stereo0D,
312
+ int bDoNotAddH, INPUT_TYPE nInputType, inchi_Atom **at,
313
+ int max_num_at,
314
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
315
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr );
316
+
317
+ int INChIToInchi_Atom ( INCHI_FILE *inp_molfile, inchi_Stereo0D **stereo0D, int *num_stereo0D,
318
+ int bDoNotAddH, INPUT_TYPE nInputType, inchi_Atom **at,
319
+ int max_num_at,
320
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
321
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr )
322
+ {
323
+ return INChITo_Atom ( inp_molfile, NULL, stereo0D, num_stereo0D,
324
+ bDoNotAddH, nInputType, at, max_num_at,
325
+ num_dimensions, num_bonds, pSdfLabel, pSdfValue,
326
+ Id, pInpAtomFlags, err, pStrErr );
327
+ }
328
+
329
+ #else
330
+
331
+ /*****************************************************************************/
332
+ int INChIToInpAtom ( FILE *inp_molfile, MOL_COORD **szCoord,
333
+ int bDoNotAddH, INPUT_TYPE nInputType, inp_ATOM **at,
334
+ int max_num_at,
335
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
336
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr );
337
+
338
+ int INChIToInpAtom ( FILE *inp_molfile, MOL_COORD **szCoord,
339
+ int bDoNotAddH, INPUT_TYPE nInputType, inp_ATOM **at,
340
+ int max_num_at,
341
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
342
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr )
343
+ {
344
+ return INChITo_Atom ( inp_molfile, szCoord, NULL, NULL,
345
+ bDoNotAddH, nInputType, at, max_num_at,
346
+ num_dimensions, num_bonds, pSdfLabel, pSdfValue,
347
+ Id, pInpAtomFlags, err, pStrErr );
348
+ }
349
+
350
+ #endif
351
+
352
+ /*****************************************************************************/
353
+ char *FindToken( INPUT_FILE *inp_molfile, int *bTooLongLine, const char *sToken, int lToken,
354
+ char *szLine, int nLenLine, char *p, int *res )
355
+ {
356
+ char *q;
357
+ int res2;
358
+
359
+ while ( !(q = strstr( p, sToken ) ) ) {
360
+ if ( (q = strrchr( p, '/' )) && (q + lToken > szLine + *res) ) {
361
+ *res -= q - szLine; /* res = the length of the szLine to be left in */
362
+ memmove( szLine, q, *res + 1);
363
+ } else {
364
+ *res = 0;
365
+ }
366
+ if ( !*bTooLongLine ||
367
+ 0 > (res2 = my_fgetsTab1( szLine + *res, nLenLine - *res - 1,
368
+ inp_molfile, bTooLongLine ) ) ) {
369
+ /* the line is over or end of file */
370
+ return NULL;
371
+ } else {
372
+ *res += res2;
373
+ p = szLine;
374
+ }
375
+ }
376
+
377
+ return q + lToken;
378
+ }
379
+ /*****************************************************************************/
380
+ char *LoadLine( INPUT_FILE *inp_molfile, int *bTooLongLine, int *bItemIsOver, char **s,
381
+ char *szLine, int nLenLine, int nMinLen2Load, char *p, int *res )
382
+ {
383
+ int pos = p - szLine, res2;
384
+ if ( !*bItemIsOver && nLenLine - (*res - pos) > nMinLen2Load ) {
385
+ /* load the next portion if possible */
386
+ if ( pos ) {
387
+ *res -= pos;
388
+ memmove( szLine, p, *res+1 );
389
+ p = szLine;
390
+ if ( *s ) {
391
+ *s -= pos;
392
+ }
393
+ pos = 0;
394
+ }
395
+ res2 = my_fgetsTab1( szLine + *res, nLenLine - *res - 1, inp_molfile, bTooLongLine );
396
+ if ( res2 > 0 ) {
397
+ *bItemIsOver = ( (*s = strchr( p + *res, '/') ) || !*bTooLongLine );
398
+ *res += res2;
399
+ } else {
400
+ *bItemIsOver = 1;
401
+ }
402
+ }
403
+ return p;
404
+ }
405
+ /*****************************************************************************/
406
+ int INChITo_Atom(INPUT_FILE *inp_molfile, MOL_COORD **szCoord,
407
+ inchi_Stereo0D **stereo0D, int *num_stereo0D,
408
+ int bDoNotAddH, INPUT_TYPE nInputType, inchi_Atom **at,
409
+ int max_num_at,
410
+ int *num_dimensions, int *num_bonds, char *pSdfLabel, char *pSdfValue,
411
+ long *Id, INCHI_MODE *pInpAtomFlags, int *err, char *pStrErr )
412
+ {
413
+ int num_atoms = 0, bFindNext = 0, len, bHeaderRead, bItemIsOver, bErrorMsg, bRestoreInfo;
414
+ int bFatal = 0, num_struct = 0;
415
+ int i, k, k2, res, bond_type, bond_stereo1, bond_stereo2, bond_char, neigh, bond_parity, bond_parityNM;
416
+ int bTooLongLine, res2, bTooLongLine2, pos, hlen, hk;
417
+ long longID;
418
+ char szLine[INCHI_LINE_LEN], szNextLine[INCHI_LINE_ADD], *p, *q, *s, parity;
419
+ int b2D=0, b3D=0, b23D, nNumBonds = 0, bNonZeroXYZ, bNonMetal;
420
+ int len_stereo0D = 0, max_len_stereo0D = 0;
421
+ inchi_Stereo0D *atom_stereo0D = NULL;
422
+ inchi_Atom *atom = NULL;
423
+ MOL_COORD *pszCoord = NULL;
424
+ INCHI_MODE InpAtomFlags = 0; /* 0 or FLAG_INP_AT_NONCHIRAL or FLAG_INP_AT_CHIRAL */
425
+ static char szIsoH[] = "hdt";
426
+ /* plain tags */
427
+ static char sStructHdrPln[] = "Structure:";
428
+ static char sStructHdrPlnNoLblVal[] = " is missing";
429
+ static char sStructHdrPlnAuxStart[64] =""; /*"$1.1Beta/";*/
430
+ static int lenStructHdrPlnAuxStart = 0;
431
+ static char sStructHdrPlnRevAt[] = "/rA:";
432
+ static char sStructHdrPlnRevBn[] = "/rB:";
433
+ static char sStructHdrPlnRevXYZ[] = "/rC:";
434
+ char *sToken;
435
+ int lToken;
436
+ if ( !lenStructHdrPlnAuxStart ) {
437
+ lenStructHdrPlnAuxStart = sprintf( sStructHdrPlnAuxStart, "AuxInfo=" );
438
+ }
439
+
440
+ if ( at ) {
441
+ if ( *at && max_num_at ) {
442
+ memset( *at, 0, max_num_at * sizeof(**at) );
443
+ }
444
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
445
+ if ( stereo0D && num_stereo0D ) {
446
+ if ( *stereo0D && *num_stereo0D ) {
447
+ max_len_stereo0D = *num_stereo0D;
448
+ memset( *stereo0D, 0, max_len_stereo0D * sizeof( **stereo0D ));
449
+ } else {
450
+ max_len_stereo0D = 0;
451
+ }
452
+ }
453
+ #else
454
+ if ( szCoord && *szCoord ) {
455
+ inchi_free( *szCoord );
456
+ *szCoord = NULL;
457
+ }
458
+ #endif
459
+ } else {
460
+ bFindNext = 1;
461
+ }
462
+ bHeaderRead = bErrorMsg = bRestoreInfo = 0;
463
+ *num_dimensions = *num_bonds = 0;
464
+
465
+ /*************************************************************/
466
+ /* extract reversibility info from plain text INChI format */
467
+ /*************************************************************/
468
+ if ( nInputType == INPUT_INCHI_PLAIN ) {
469
+ bHeaderRead = hk = 0;
470
+ while ( 0 < (res = my_fgetsTab( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine ) ) ) {
471
+
472
+ /********************* find and interpret structure header ************/
473
+ if ( !bTooLongLine &&
474
+ (hlen=sizeof(sStructHdrPln)-1, !memcmp(szLine, sStructHdrPln, hlen)) ) {
475
+ p = szLine + hlen;
476
+ longID = 0;
477
+ num_atoms = 0;
478
+ /* structure number */
479
+ longID = strtol( p, &q, 10 );
480
+ if ( q && q[0] == '.' && q[1] == ' ' ) {
481
+ p = q+2;
482
+ }
483
+ p = p + strspn( p, " \n\r" );
484
+
485
+ if ( pSdfLabel ) {
486
+ pSdfLabel[0] = '\0';
487
+ }
488
+ if ( pSdfValue ) {
489
+ pSdfValue[0] = '\0';
490
+ }
491
+
492
+ if ( *p ) {
493
+ /* has label name */
494
+ /*p ++;*/
495
+ if ( q = strchr( p, '=' ) ) {
496
+ /* '=' separates label name from the value */
497
+ len = inchi_min( q-p+1, MAX_SDF_HEADER-1);
498
+ if ( pSdfLabel ) {
499
+ mystrncpy( pSdfLabel, p, len );
500
+ LtrimRtrim( pSdfLabel, &len );
501
+ }
502
+ p = q+1;
503
+ q = p + (int)strlen( p );
504
+ if ( q-p > 0 ) {
505
+ len = inchi_min( q-p+1, MAX_SDF_VALUE-1);
506
+ if ( pSdfValue ) {
507
+ mystrncpy( pSdfValue, p, len );
508
+ }
509
+ p = q;
510
+ }
511
+
512
+ } else
513
+ if ( q = strstr( p, sStructHdrPlnNoLblVal ) ) {
514
+ len = inchi_min( q-p+1, MAX_SDF_HEADER-1);
515
+ if ( pSdfLabel ) {
516
+ mystrncpy( pSdfLabel, p, len );
517
+ }
518
+ p = q+1;
519
+ }
520
+ }
521
+ if ( Id )
522
+ *Id = longID;
523
+
524
+ bHeaderRead = 1;
525
+ bErrorMsg = bRestoreInfo = 0;
526
+ } else
527
+ if ( !memcmp( szLine, sStructHdrPlnAuxStart, lenStructHdrPlnAuxStart) ) {
528
+ /* found the header of the AuxInfo, read AuxInfo head of the line */
529
+ if ( !bHeaderRead ) {
530
+ longID = 0;
531
+ if ( Id )
532
+ *Id = longID;
533
+ if ( pSdfLabel ) {
534
+ pSdfLabel[0] = '\0';
535
+ }
536
+ if ( pSdfValue ) {
537
+ pSdfValue[0] = '\0';
538
+ }
539
+ }
540
+ bHeaderRead = 0;
541
+ /* check for empty "AuxInfo=ver//" */
542
+ p = strchr( szLine + lenStructHdrPlnAuxStart, '/' );
543
+ if ( p && p[1] == '/' && (!p[2] || '\n' == p[2]) ) {
544
+ goto bypass_end_of_INChI_plain;
545
+ }
546
+ /***************** search for atoms block (plain) **********************/
547
+ p = szLine;
548
+ sToken = sStructHdrPlnRevAt;
549
+ lToken = sizeof(sStructHdrPlnRevAt)-1;
550
+ /* search for sToken in the line; load next segments of the line if sToken has not found */
551
+ p = FindToken( inp_molfile, &bTooLongLine, sToken, lToken,
552
+ szLine, sizeof(szLine), p, &res );
553
+ if ( !p ) {
554
+ *err = INCHI_INP_ERROR_ERR;
555
+ num_atoms = INCHI_INP_ERROR_RET;
556
+ MOLFILE_ERR_SET (*err, 0, "Missing atom data");
557
+ goto bypass_end_of_INChI_plain;
558
+ } else {
559
+ /* atoms block started */
560
+ i = 0;
561
+ res2 = bTooLongLine2 = -1;
562
+ bItemIsOver = (s = strchr( p, '/') ) || !bTooLongLine;
563
+ while ( 1 ) {
564
+ p = LoadLine( inp_molfile, &bTooLongLine, &bItemIsOver, &s,
565
+ szLine, sizeof(szLine), INCHI_LINE_ADD, p, &res );
566
+ if ( !i ) {
567
+ /* allocate atom */
568
+ num_atoms = strtol( p, &q, 10 );
569
+ if ( !num_atoms || !q || !*q ) {
570
+ num_atoms = 0; /* no atom data */
571
+ goto bypass_end_of_INChI_plain;
572
+ }
573
+ p = q;
574
+ /* Molfile chirality flag */
575
+ switch( *p ) {
576
+ case 'c':
577
+ InpAtomFlags |= FLAG_INP_AT_CHIRAL;
578
+ p ++;
579
+ break;
580
+ case 'n':
581
+ InpAtomFlags |= FLAG_INP_AT_NONCHIRAL;
582
+ p ++;
583
+ break;
584
+ }
585
+ if ( at && *at ) {
586
+ if ( num_atoms > max_num_at ) {
587
+ inchi_free( *at );
588
+ *at = NULL;
589
+ } else {
590
+ memset( *at, 0, max_num_at * sizeof( **at ) );
591
+ atom = *at;
592
+ }
593
+ }
594
+ if ( !at || !*at ) {
595
+ atom = Create_Atom( num_atoms+1 );
596
+ if ( !atom ) {
597
+ num_atoms = INCHI_INP_FATAL_RET; /* was -1; error */
598
+ *err = INCHI_INP_FATAL_ERR;
599
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
600
+ goto bypass_end_of_INChI_plain;
601
+ }
602
+ }
603
+ if ( stereo0D && *stereo0D ) {
604
+ if ( num_atoms > max_len_stereo0D ) {
605
+ FreeInchi_Stereo0D( stereo0D );
606
+ } else {
607
+ memset( *stereo0D, 0, max_len_stereo0D * sizeof( **stereo0D ) );
608
+ atom_stereo0D = *stereo0D;
609
+ }
610
+ }
611
+ if ( !stereo0D || !*stereo0D ) {
612
+ max_len_stereo0D = num_atoms+1;
613
+ atom_stereo0D = CreateInchi_Stereo0D( max_len_stereo0D );
614
+ if ( !atom_stereo0D ) {
615
+ num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
616
+ *err = INCHI_INP_FATAL_ERR;
617
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
618
+ goto bypass_end_of_INChI_plain;
619
+ }
620
+ }
621
+ }
622
+ /* element, first char */
623
+ if ( !isalpha( UCINT *p ) || !isupper( UCINT *p ) || i >= num_atoms ) {
624
+ break; /* end of atoms block */
625
+ }
626
+ atom[i].elname[0] = *p ++;
627
+ /* element, second char */
628
+ if ( isalpha( UCINT *p ) && islower( UCINT *p ) ) {
629
+ atom[i].elname[1] = *p ++;
630
+ }
631
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
632
+ #else
633
+ atom[i].el_number = get_periodic_table_number( atom[i].elname );
634
+ #endif
635
+ /* bonds' valence */
636
+ if ( isdigit( UCINT *p ) ) {
637
+ AT_BONDS_VAL(atom,i) = (char)strtol( p, &q, 10 );
638
+ if ( !AT_BONDS_VAL(atom,i) )
639
+ AT_BONDS_VAL(atom,i) = ISOLATED_ATOM; /* same convention as in MOLfile, found zero bonds valence */
640
+ p = q;
641
+ }
642
+ /* charge */
643
+ atom[i].charge = (*p == '+')? 1 : (*p == '-')? -1 : 0;
644
+ if ( atom[i].charge ) {
645
+ p ++;
646
+ if ( isdigit( UCINT *p ) ) {
647
+ atom[i].charge *= (S_CHAR)(strtol( p, &q, 10 ) & CHAR_MASK);
648
+ p = q;
649
+ }
650
+ }
651
+ /* radical */
652
+ if ( *p == '.' ) {
653
+ p ++;
654
+ if ( isdigit( UCINT *p ) ) {
655
+ atom[i].radical = (S_CHAR)strtol( p, &q, 10 );
656
+ p = q;
657
+ }
658
+ }
659
+ /* isotopic mass */
660
+ if ( *p == 'i' ) {
661
+ p ++;
662
+ if ( isdigit( UCINT *p ) ) {
663
+ int mw = strtol( p, &q, 10 );
664
+ p = q;
665
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
666
+ atom[i].isotopic_mass = mw;
667
+ #else
668
+ mw -= get_atw_from_elnum( atom[i].el_number );
669
+ if ( mw >= 0 )
670
+ mw ++;
671
+ atom[i].iso_atw_diff = mw;
672
+ #endif
673
+ }
674
+ }
675
+ /* parity */
676
+ switch( *p ) {
677
+ case 'o':
678
+ parity = INCHI_PARITY_ODD;
679
+ p ++;
680
+ break;
681
+ case 'e':
682
+ parity = INCHI_PARITY_EVEN;
683
+ p ++;
684
+ break;
685
+ case 'u':
686
+ parity = INCHI_PARITY_UNKNOWN;
687
+ p ++;
688
+ break;
689
+ case '?':
690
+ parity = INCHI_PARITY_UNDEFINED;
691
+ p ++;
692
+ break;
693
+ default:
694
+ parity = 0;
695
+ break;
696
+ }
697
+ if ( parity ) {
698
+ atom_stereo0D[len_stereo0D].central_atom = i;
699
+ atom_stereo0D[len_stereo0D].parity = parity;
700
+ atom_stereo0D[len_stereo0D].type = INCHI_StereoType_Tetrahedral;
701
+ len_stereo0D ++;
702
+ }
703
+ /* isotopic h, d, t */
704
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
705
+ if ( *p == szIsoH[k] ) {
706
+ NUM_ISO_Hk(atom,i,k) = 1;
707
+ p ++;
708
+ if ( isdigit( UCINT *p ) ) {
709
+ NUM_ISO_Hk(atom,i,k) = (char)strtol( p, &q, 10 );
710
+ p = q;
711
+ }
712
+ }
713
+ }
714
+ i ++;
715
+ }
716
+ if ( !bItemIsOver || i != num_atoms || s && p != s ) {
717
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
718
+ *err = INCHI_INP_ERROR_ERR;
719
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of atoms");
720
+ goto bypass_end_of_INChI_plain;
721
+ }
722
+ }
723
+ /***************** search for bonds block (plain) and read it *****************/
724
+ /*p = szLine;*/
725
+ sToken = sStructHdrPlnRevBn;
726
+ lToken = sizeof(sStructHdrPlnRevBn)-1;
727
+ /* search for sToken in the line; load next segments of the line if sToken has not found */
728
+ p = FindToken( inp_molfile, &bTooLongLine, sToken, lToken,
729
+ szLine, sizeof(szLine), p, &res );
730
+ if ( !p ) {
731
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
732
+ *err = INCHI_INP_ERROR_ERR;
733
+ MOLFILE_ERR_SET (*err, 0, "Missing bonds data");
734
+ goto bypass_end_of_INChI_plain;
735
+ } else {
736
+ /* bonds block started */
737
+ i = 1;
738
+ res2 = bTooLongLine2 = -1;
739
+ bItemIsOver = (s = strchr( p, '/') ) || !bTooLongLine;
740
+ if ( 1 == num_atoms ) {
741
+ /* needed because the next '/' may be still out of szLine */
742
+ p = LoadLine( inp_molfile, &bTooLongLine, &bItemIsOver, &s,
743
+ szLine, sizeof(szLine), INCHI_LINE_ADD, p, &res );
744
+ }
745
+ while ( i < num_atoms ) {
746
+ p = LoadLine( inp_molfile, &bTooLongLine, &bItemIsOver, &s,
747
+ szLine, sizeof(szLine), INCHI_LINE_ADD, p, &res );
748
+ if ( i >= num_atoms || s && p >= s ) {
749
+ break; /* end of bonds (plain) */
750
+ }
751
+ /* bond, first char */
752
+ if ( *p == ';' ) {
753
+ p ++;
754
+ i ++;
755
+ continue;
756
+ }
757
+ if ( !isalpha( UCINT *p ) ) {
758
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
759
+ *err = INCHI_INP_ERROR_ERR;
760
+ MOLFILE_ERR_SET (*err, 0, "Wrong bonds data");
761
+ goto bypass_end_of_INChI_plain;
762
+ }
763
+ bond_char = *p ++;
764
+ /* bond parity */
765
+ switch( *p ) {
766
+ case '-':
767
+ bond_parity = INCHI_PARITY_ODD;
768
+ p ++;
769
+ break;
770
+ case '+':
771
+ bond_parity = INCHI_PARITY_EVEN;
772
+ p ++;
773
+ break;
774
+ case 'u':
775
+ bond_parity = INCHI_PARITY_UNKNOWN;
776
+ p ++;
777
+ break;
778
+ case '?':
779
+ bond_parity = INCHI_PARITY_UNDEFINED;
780
+ p ++;
781
+ break;
782
+ default:
783
+ bond_parity = 0;
784
+ break;
785
+ }
786
+ if ( bond_parity ) {
787
+ switch( *p ) {
788
+ case '-':
789
+ bond_parityNM = INCHI_PARITY_ODD;
790
+ p ++;
791
+ break;
792
+ case '+':
793
+ bond_parityNM = INCHI_PARITY_EVEN;
794
+ p ++;
795
+ break;
796
+ case 'u':
797
+ bond_parityNM = INCHI_PARITY_UNKNOWN;
798
+ p ++;
799
+ break;
800
+ case '?':
801
+ bond_parityNM = INCHI_PARITY_UNDEFINED;
802
+ p ++;
803
+ break;
804
+ default:
805
+ bond_parityNM = 0;
806
+ break;
807
+ }
808
+ } else {
809
+ bond_parityNM = 0;
810
+ }
811
+
812
+ /* neighbor of the current atom */
813
+ if ( !isdigit( UCINT *p ) ) {
814
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
815
+ *err = INCHI_INP_ERROR_ERR;
816
+ MOLFILE_ERR_SET (*err, 0, "Wrong bonds data");
817
+ goto bypass_end_of_INChI_plain;
818
+ }
819
+ neigh = (int)strtol( p, &q, 10 )-1;
820
+
821
+ if ( i >= num_atoms || neigh >= num_atoms ) {
822
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
823
+ *err = INCHI_INP_ERROR_ERR;
824
+ MOLFILE_ERR_SET (*err, 0, "Bond to nonexistent atom");
825
+ goto bypass_end_of_INChI_plain;
826
+ }
827
+ p = q;
828
+ bond_stereo1 = bond_stereo2 = 0;
829
+
830
+ /* bond type & 2D stereo */
831
+ switch( bond_char ) {
832
+ case 'v':
833
+ bond_type = INCHI_BOND_TYPE_SINGLE;
834
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1EITHER;
835
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2EITHER;
836
+ break;
837
+ case 'V':
838
+ bond_type = INCHI_BOND_TYPE_SINGLE;
839
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2EITHER;
840
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1EITHER;
841
+ break;
842
+ case 'w':
843
+ bond_type = INCHI_BOND_TYPE_DOUBLE;
844
+ bond_stereo1 =
845
+ bond_stereo2 = INCHI_BOND_STEREO_DOUBLE_EITHER;
846
+ break;
847
+ case 's':
848
+ bond_type = INCHI_BOND_TYPE_SINGLE;
849
+ break;
850
+ case 'd':
851
+ bond_type = INCHI_BOND_TYPE_DOUBLE;
852
+ break;
853
+ case 't':
854
+ bond_type = INCHI_BOND_TYPE_TRIPLE;
855
+ break;
856
+ case 'a':
857
+ bond_type = INCHI_BOND_TYPE_ALTERN;
858
+ break;
859
+ case 'p':
860
+ bond_type = INCHI_BOND_TYPE_SINGLE;
861
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1UP;
862
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2UP;
863
+ break;
864
+ case 'P':
865
+ bond_type = INCHI_BOND_TYPE_SINGLE;
866
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2UP;
867
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1UP;
868
+ break;
869
+ case 'n':
870
+ bond_type = INCHI_BOND_TYPE_SINGLE;
871
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1DOWN;
872
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2DOWN;
873
+ break;
874
+ case 'N':
875
+ bond_type = INCHI_BOND_TYPE_SINGLE;
876
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2DOWN;
877
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1DOWN;
878
+ break;
879
+ default:
880
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
881
+ *err = INCHI_INP_ERROR_ERR;
882
+ MOLFILE_ERR_SET (*err, 0, "Wrong bond type");
883
+ goto bypass_end_of_INChI_plain;
884
+ }
885
+ k = AT_NUM_BONDS(atom[i]) ++;
886
+ atom[i].bond_type[k] = bond_type;
887
+ atom[i].bond_stereo[k] = bond_stereo1;
888
+ atom[i].neighbor[k] = (ATOM_NUMBER)neigh;
889
+ k2 = AT_NUM_BONDS(atom[neigh]) ++;
890
+ atom[neigh].bond_type[k2] = bond_type;
891
+ atom[neigh].bond_stereo[k2] = bond_stereo2;
892
+ atom[neigh].neighbor[k2] = (ATOM_NUMBER)i;
893
+ bond_parity |= (bond_parityNM << SB_PARITY_SHFT);
894
+
895
+ if ( bond_parity ) {
896
+ if ( max_len_stereo0D <= len_stereo0D ) {
897
+ /* realloc atom_Stereo0D */
898
+ inchi_Stereo0D *new_atom_stereo0D = CreateInchi_Stereo0D( max_len_stereo0D+num_atoms );
899
+ if ( !new_atom_stereo0D ) {
900
+ num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
901
+ *err = INCHI_INP_FATAL_ERR;
902
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
903
+ goto bypass_end_of_INChI_plain;
904
+ }
905
+ memcpy( new_atom_stereo0D, atom_stereo0D, len_stereo0D * sizeof(*atom_stereo0D) );
906
+ FreeInchi_Stereo0D( &atom_stereo0D );
907
+ atom_stereo0D = new_atom_stereo0D;
908
+ max_len_stereo0D += num_atoms;
909
+ }
910
+ /* (a) i may be allene endpoint and neigh = allene middle point or
911
+ (b) i may be allene middle point and neigh = allene endpoint
912
+ !!!!! CURRENTLY ONLY (b) IS ALLOWED !!!!!
913
+ */
914
+ atom_stereo0D[len_stereo0D].neighbor[1] = neigh; /* neigh < i */
915
+ atom_stereo0D[len_stereo0D].neighbor[2] = i;
916
+ atom_stereo0D[len_stereo0D].parity = bond_parity;
917
+ atom_stereo0D[len_stereo0D].type = INCHI_StereoType_DoubleBond; /* incl allenes & cumulenes */
918
+ len_stereo0D ++;
919
+ }
920
+ }
921
+ if ( !bItemIsOver || i != num_atoms || s && p != s ) {
922
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
923
+ *err = INCHI_INP_ERROR_ERR;
924
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of bonds");
925
+ goto bypass_end_of_INChI_plain;
926
+ }
927
+ }
928
+ /***************** search for coordinates block (plain) **********************/
929
+ /*p = szLine;*/
930
+ sToken = sStructHdrPlnRevXYZ;
931
+ lToken = sizeof(sStructHdrPlnRevXYZ)-1;
932
+ /* search for sToken in the line; load next segments of the line if sToken has not found */
933
+ p = FindToken( inp_molfile, &bTooLongLine, sToken, lToken,
934
+ szLine, sizeof(szLine), p, &res );
935
+ if ( !p ) {
936
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
937
+ *err = INCHI_INP_ERROR_ERR;
938
+ MOLFILE_ERR_SET (*err, 0, "Missing atom coordinates data");
939
+ goto bypass_end_of_INChI_plain;
940
+ } else {
941
+ /* coordinates block started */
942
+ if ( pszCoord = (MOL_COORD*)inchi_malloc(inchi_max(num_atoms,1) * sizeof(MOL_COORD)) ) {
943
+ memset( pszCoord, ' ', inchi_max(num_atoms,1) * sizeof(MOL_COORD));
944
+ } else {
945
+ num_atoms = INCHI_INP_FATAL_RET; /* allocation error */
946
+ *err = INCHI_INP_FATAL_ERR;
947
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
948
+ goto bypass_end_of_INChI_plain;
949
+ }
950
+ i = 0;
951
+ res2 = bTooLongLine2 = -1;
952
+ bItemIsOver = (s = strchr( p, '/') ) || !bTooLongLine;
953
+ while ( i < num_atoms ) {
954
+ p = LoadLine( inp_molfile, &bTooLongLine, &bItemIsOver, &s,
955
+ szLine, sizeof(szLine), INCHI_LINE_ADD, p, &res );
956
+ if ( i >= num_atoms || s && p >= s ) {
957
+ break; /* end of bonds (plain) */
958
+ }
959
+
960
+ /* coord, first char */
961
+ if ( *p == ';' ) {
962
+ for ( k = 0; k < NUM_COORD; k ++ ) {
963
+ pszCoord[i][LEN_COORD*k + 4] = '0';
964
+ }
965
+ p ++;
966
+ i ++;
967
+ continue;
968
+ }
969
+ for ( k = 0; k < 3; k ++ ) {
970
+ double xyz;
971
+ bNonZeroXYZ = 0;
972
+ if ( *p == ';' ) {
973
+ pszCoord[i][LEN_COORD*k + 4] = '0';
974
+ xyz = 0.0;
975
+ } else
976
+ if ( *p == ',' ) {
977
+ /* empty */
978
+ pszCoord[i][LEN_COORD*k + 4] = '0';
979
+ xyz = 0.0;
980
+ p ++;
981
+ } else {
982
+ xyz = strtod( p, &q );
983
+ bNonZeroXYZ = fabs(xyz) > MIN_BOND_LENGTH;
984
+ if ( q != NULL ) {
985
+ memcpy( pszCoord[i]+LEN_COORD*k, p, q-p );
986
+ if ( *q == ',' )
987
+ q ++;
988
+ p = q;
989
+ } else {
990
+ pszCoord[i][LEN_COORD*k + 4] = '0';
991
+ }
992
+ }
993
+ switch( k ) {
994
+ case 0:
995
+ atom[i].x = xyz;
996
+ b2D |= bNonZeroXYZ;
997
+ break;
998
+ case 1:
999
+ atom[i].y = xyz;
1000
+ b2D |= bNonZeroXYZ;
1001
+ break;
1002
+ case 2:
1003
+ b3D |= bNonZeroXYZ;
1004
+ atom[i].z = xyz;
1005
+ break;
1006
+ }
1007
+ }
1008
+ if ( *p == ';' ) {
1009
+ p ++; /* end of this triple of coordinates */
1010
+ i ++;
1011
+ } else {
1012
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data: atoms, bonds & coord must be present together */
1013
+ *err = INCHI_INP_ERROR_ERR;
1014
+ MOLFILE_ERR_SET (*err, 0, "Wrong atom coordinates data");
1015
+ goto bypass_end_of_INChI_plain;
1016
+ }
1017
+ }
1018
+ if ( !bItemIsOver || s && p != s || i != num_atoms ) {
1019
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
1020
+ *err = INCHI_INP_ERROR_ERR;
1021
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of coordinates");
1022
+ goto bypass_end_of_INChI_plain;
1023
+ }
1024
+ } /* end of coordinates */
1025
+ /* set special valences and implicit H (xml) */
1026
+ b23D = b2D | b3D;
1027
+ b2D = b3D = 0;
1028
+ if ( at ) {
1029
+ if ( !*at ) {
1030
+ int a1, a2, n1, n2, valence;
1031
+ int chem_bonds_valence;
1032
+ int nX=0, nY=0, nZ=0, nXYZ;
1033
+ *at = atom;
1034
+ /* special valences */
1035
+ for ( bNonMetal = 0; bNonMetal < 1; bNonMetal ++ ) {
1036
+ for ( a1 = 0; a1 < num_atoms; a1 ++ ) {
1037
+ int num_bond_type[MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE + 1];
1038
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1039
+ #else
1040
+ int bHasMetalNeighbor=0;
1041
+ #endif
1042
+ memset( num_bond_type, 0, sizeof(num_bond_type) );
1043
+
1044
+ valence = AT_BONDS_VAL(atom, a1); /* save atom valence if available */
1045
+ AT_BONDS_VAL(atom, a1) = 0;
1046
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1047
+ #else
1048
+ atom[a1].orig_at_number = a1+1;
1049
+ #endif
1050
+ nX = nY = nZ = 0;
1051
+ for ( n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1 ++ ) {
1052
+ bond_type = atom[a1].bond_type[n1] - MIN_INPUT_BOND_TYPE;
1053
+ if ( bond_type < 0 || bond_type > MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE ) {
1054
+ bond_type = 0;
1055
+ MOLFILE_ERR_SET (*err, 0, "Unknown bond type in InChI aux assigned as a single bond");
1056
+ }
1057
+
1058
+ num_bond_type[ bond_type ] ++;
1059
+ nNumBonds ++;
1060
+ if ( b23D ) {
1061
+ neigh = atom[a1].neighbor[n1];
1062
+ nX |= (fabs(atom[a1].x - atom[neigh].x) > MIN_BOND_LENGTH);
1063
+ nY |= (fabs(atom[a1].y - atom[neigh].y) > MIN_BOND_LENGTH);
1064
+ nZ |= (fabs(atom[a1].z - atom[neigh].z) > MIN_BOND_LENGTH);
1065
+ }
1066
+ }
1067
+ chem_bonds_valence = 0;
1068
+ for ( n1 = 0; MIN_INPUT_BOND_TYPE + n1 <= 3 && MIN_INPUT_BOND_TYPE + n1 <= MAX_INPUT_BOND_TYPE; n1 ++ ) {
1069
+ chem_bonds_valence += (MIN_INPUT_BOND_TYPE + n1) * num_bond_type[n1];
1070
+ }
1071
+ if ( MIN_INPUT_BOND_TYPE <= INCHI_BOND_TYPE_ALTERN && INCHI_BOND_TYPE_ALTERN <= MAX_INPUT_BOND_TYPE &&
1072
+ ( n2 = num_bond_type[INCHI_BOND_TYPE_ALTERN-MIN_INPUT_BOND_TYPE] ) ) {
1073
+ /* accept input aromatic bonds for now */
1074
+ switch ( n2 ) {
1075
+ case 2:
1076
+ chem_bonds_valence += 3; /* =A- */
1077
+ break;
1078
+ case 3:
1079
+ chem_bonds_valence += 4; /* =A< */
1080
+ break;
1081
+ default:
1082
+ /* if 1 or >= 4 aromatic bonds then replace such bonds with single bonds */
1083
+ for ( n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1 ++ ) {
1084
+ if ( atom[a1].bond_type[n1] == INCHI_BOND_TYPE_ALTERN ) {
1085
+ ATOM_NUMBER *p1;
1086
+ a2 = atom[a1].neighbor[n1];
1087
+ p1 = IN_NEIGH_LIST( atom[a2].neighbor, (ATOM_NUMBER)a1, AT_NUM_BONDS(atom[a2]) );
1088
+ if ( p1 ) {
1089
+ atom[a1].bond_type[n1] =
1090
+ atom[a2].bond_type[p1-atom[a2].neighbor] = INCHI_BOND_TYPE_SINGLE;
1091
+ } else {
1092
+ *err = -2; /* Program error */
1093
+ MOLFILE_ERR_SET (*err, 0, "Program error interpreting InChI aux");
1094
+ num_atoms = 0;
1095
+ goto bypass_end_of_INChI_plain; /* no structure */
1096
+ }
1097
+ }
1098
+ }
1099
+ chem_bonds_valence += n2;
1100
+ *err |= 32; /* Unrecognized aromatic bond(s) replaced with single */
1101
+ MOLFILE_ERR_SET (*err, 0, "Atom has more than 3 aromatic bonds");
1102
+ break;
1103
+ }
1104
+ }
1105
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1106
+ /*************************************************************************************
1107
+ *
1108
+ * Set number of hydrogen atoms
1109
+ */
1110
+ {
1111
+ int num_iso_H;
1112
+ num_iso_H = atom[a1].num_iso_H[1] + atom[a1].num_iso_H[2] + atom[a1].num_iso_H[3];
1113
+ if ( valence == ISOLATED_ATOM ) {
1114
+ atom[a1].num_iso_H[0] = 0;
1115
+ } else
1116
+ if ( valence && valence >= chem_bonds_valence ) {
1117
+ atom[a1].num_iso_H[0] = valence - chem_bonds_valence;
1118
+ } else
1119
+ if ( valence || bDoNotAddH ) {
1120
+ atom[a1].num_iso_H[0] = 0;
1121
+ } else
1122
+ if ( !bDoNotAddH ) {
1123
+ atom[a1].num_iso_H[0] = -1; /* auto add H */
1124
+ }
1125
+ }
1126
+ #else
1127
+ atom[a1].chem_bonds_valence = chem_bonds_valence;
1128
+ atom[a1].num_H = get_num_H( atom[a1].elname, atom[a1].num_H, atom[a1].num_iso_H, atom[a1].charge, atom[a1].radical,
1129
+ atom[a1].chem_bonds_valence,
1130
+ valence,
1131
+ 0, bDoNotAddH, bHasMetalNeighbor );
1132
+ #endif
1133
+ }
1134
+ }
1135
+ nNumBonds /= 2;
1136
+ if ( b23D && nNumBonds ) {
1137
+ nXYZ = nX+nY+nZ;
1138
+ b2D = (nXYZ > 0);
1139
+ b3D = (nXYZ == 3);
1140
+ *num_dimensions = b3D? 3 : b2D? 2 : 0;
1141
+ *num_bonds = nNumBonds;
1142
+ }
1143
+ /*======= 0D parities =================================*/
1144
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1145
+ if ( len_stereo0D > 0 && atom_stereo0D && stereo0D ) {
1146
+ *stereo0D = atom_stereo0D;
1147
+ *num_stereo0D = len_stereo0D;
1148
+ } else {
1149
+ FreeInchi_Stereo0D( &atom_stereo0D );
1150
+ *num_stereo0D = len_stereo0D = 0;
1151
+ }
1152
+ #endif
1153
+ for ( i = 0; i < len_stereo0D; i ++ ) {
1154
+ ATOM_NUMBER *p1, *p2;
1155
+ int sb_ord_from_a1 = -1, sb_ord_from_a2 = -1, bEnd1 = 0, bEnd2 = 0;
1156
+ switch( atom_stereo0D[i].type ) {
1157
+
1158
+ case INCHI_StereoType_Tetrahedral:
1159
+ a1 = atom_stereo0D[i].central_atom;
1160
+ if ( atom_stereo0D[i].parity && (AT_NUM_BONDS(atom[a1]) == 3 || AT_NUM_BONDS(atom[a1]) == 4) ) {
1161
+ int ii, kk = 0;
1162
+ if ( AT_NUM_BONDS(atom[a1]) == 3 ) {
1163
+ atom_stereo0D[i].neighbor[kk++] = a1;
1164
+ }
1165
+ for ( ii = 0; ii < AT_NUM_BONDS(atom[a1]); ii ++ ) {
1166
+ atom_stereo0D[i].neighbor[kk++] = atom[a1].neighbor[ii];
1167
+ }
1168
+ }
1169
+
1170
+ break;
1171
+
1172
+ case INCHI_StereoType_DoubleBond:
1173
+ #define MAX_CHAIN_LEN 20
1174
+ a1 = atom_stereo0D[i].neighbor[1];
1175
+ a2 = atom_stereo0D[i].neighbor[2];
1176
+ p1 = IN_NEIGH_LIST( atom[a1].neighbor, (ATOM_NUMBER)a2, AT_NUM_BONDS(atom[a1]) );
1177
+ p2 = IN_NEIGH_LIST( atom[a2].neighbor, (ATOM_NUMBER)a1, AT_NUM_BONDS(atom[a2]) );
1178
+ if ( !p1 || !p2 ) {
1179
+ atom_stereo0D[i].type = INCHI_StereoType_None;
1180
+ atom_stereo0D[i].central_atom = NO_ATOM;
1181
+ atom_stereo0D[i].neighbor[0] =
1182
+ atom_stereo0D[i].neighbor[4] = -1;
1183
+ *err |= 64; /* Error in cumulene stereo */
1184
+ MOLFILE_ERR_SET (*err, 0, "0D stereobond not recognized");
1185
+ break;
1186
+ }
1187
+ /* streobond, allene, or cumulene */
1188
+
1189
+ sb_ord_from_a1 = p1 - atom[a1].neighbor;
1190
+ sb_ord_from_a2 = p2 - atom[a2].neighbor;
1191
+
1192
+ if ( AT_NUM_BONDS(atom[a1]) == 2 &&
1193
+ atom[a1].bond_type[0] + atom[a1].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
1194
+ 0 == inchi_NUMH2(atom, a1) &&
1195
+ (AT_NUM_BONDS(atom[a2]) != 2 ||
1196
+ atom[a2].bond_type[0] + atom[a2].bond_type[1] != 2*INCHI_BOND_TYPE_DOUBLE ) ) {
1197
+ bEnd2 = 1; /* a2 is the end-atom, a1 is middle atom */
1198
+ }
1199
+ if ( AT_NUM_BONDS(atom[a2]) == 2 &&
1200
+ atom[a2].bond_type[0] + atom[a2].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
1201
+ 0 == inchi_NUMH2(atom, a2) &&
1202
+ (AT_NUM_BONDS(atom[a1]) != 2 ||
1203
+ atom[a1].bond_type[0] + atom[a1].bond_type[1] != 2*INCHI_BOND_TYPE_DOUBLE ) ) {
1204
+ bEnd1 = 1; /* a1 is the end-atom, a2 is middle atom */
1205
+ }
1206
+
1207
+ if ( bEnd2 + bEnd1 == 1 ) {
1208
+ /* allene or cumulene */
1209
+ ATOM_NUMBER chain[MAX_CHAIN_LEN+1], prev, cur, next;
1210
+ if ( bEnd2 && !bEnd1 ) {
1211
+ cur = a1;
1212
+ a1 = a2;
1213
+ a2 = cur;
1214
+ sb_ord_from_a1 = sb_ord_from_a2;
1215
+ }
1216
+ sb_ord_from_a2 = -1;
1217
+ cur = a1;
1218
+ next = a2;
1219
+ len = 0;
1220
+ chain[len++] = cur;
1221
+ chain[len++] = next;
1222
+ while ( len < MAX_CHAIN_LEN ) { /* arbitrary very high upper limit to prevent infinite loop */
1223
+ prev = cur;
1224
+ cur = next;
1225
+ /* follow double bond path && avoid going back */
1226
+ if ( AT_NUM_BONDS(atom[cur]) == 2 &&
1227
+ atom[cur].bond_type[0]+atom[cur].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
1228
+ 0 == inchi_NUMH2(atom, cur) ) {
1229
+ next = atom[cur].neighbor[atom[cur].neighbor[0] == prev];
1230
+ chain[len++] = next;
1231
+ } else {
1232
+ break;
1233
+ }
1234
+ }
1235
+ if ( len > 2 &&
1236
+ (p2 = IN_NEIGH_LIST( atom[cur].neighbor, (ATOM_NUMBER)prev, AT_NUM_BONDS(atom[cur]))) ) {
1237
+ sb_ord_from_a2 = p2 - atom[cur].neighbor;
1238
+ a2 = cur;
1239
+ /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
1240
+ atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[sb_ord_from_a1 == 0];
1241
+ atom_stereo0D[i].neighbor[1] = a1;
1242
+ atom_stereo0D[i].neighbor[2] = a2;
1243
+ atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[sb_ord_from_a2 == 0];
1244
+ if ( len % 2 ) {
1245
+ atom_stereo0D[i].central_atom = chain[len/2];
1246
+ atom_stereo0D[i].type = INCHI_StereoType_Allene;
1247
+ } else {
1248
+ atom_stereo0D[i].central_atom = NO_ATOM;
1249
+ }
1250
+ } else {
1251
+ /* error */
1252
+ atom_stereo0D[i].type = INCHI_StereoType_None;
1253
+ atom_stereo0D[i].central_atom = NO_ATOM;
1254
+ atom_stereo0D[i].neighbor[0] =
1255
+ atom_stereo0D[i].neighbor[4] = -1;
1256
+ *err |= 64; /* Error in cumulene stereo */
1257
+ MOLFILE_ERR_SET (*err, 0, "Cumulene stereo not recognized (0D)");
1258
+
1259
+ }
1260
+ #undef MAX_CHAIN_LEN
1261
+ } else {
1262
+ /****** a normal possibly stereogenic bond -- not an allene or cumulene *******/
1263
+ /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
1264
+ sb_ord_from_a1 = p1 - atom[a1].neighbor;
1265
+ sb_ord_from_a2 = p2 - atom[a2].neighbor;
1266
+ atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[p1 == atom[a1].neighbor];
1267
+ atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[p2 == atom[a2].neighbor];
1268
+ atom_stereo0D[i].central_atom = NO_ATOM;
1269
+ }
1270
+ if ( atom_stereo0D[i].type != INCHI_StereoType_None &&
1271
+ sb_ord_from_a1 >= 0 && sb_ord_from_a2 >= 0 &&
1272
+ ATOM_PARITY_WELL_DEF( SB_PARITY_2(atom_stereo0D[i].parity) ) ) {
1273
+ /* Detected well-defined disconnected stereo
1274
+ * locate first non-metal neighbors */
1275
+ int a, n, j, /* k,*/ sb_ord, cur_neigh, min_neigh;
1276
+ for ( k = 0; k < 2; k ++ ) {
1277
+ a = k? atom_stereo0D[i].neighbor[2] : atom_stereo0D[i].neighbor[1];
1278
+ sb_ord = k? sb_ord_from_a2 : sb_ord_from_a1;
1279
+ min_neigh = num_atoms;
1280
+ for ( n = j = 0; j < AT_NUM_BONDS(atom[a]); j ++ ) {
1281
+ cur_neigh = atom[a].neighbor[j];
1282
+ if ( j != sb_ord && !IS_METAL_ATOM(atom, cur_neigh) ) {
1283
+ min_neigh = inchi_min( cur_neigh, min_neigh );
1284
+ }
1285
+ }
1286
+ if ( min_neigh < num_atoms ) {
1287
+ atom_stereo0D[i].neighbor[k?3:0] = min_neigh;
1288
+ } else {
1289
+ MOLFILE_ERR_SET (*err, 0, "Cannot find non-metal stereobond neighor (0D)");
1290
+ }
1291
+ }
1292
+ }
1293
+
1294
+ break;
1295
+ }
1296
+ }
1297
+ /* end of 0D parities extraction */
1298
+ /*exit_cycle:;*/
1299
+ }
1300
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1301
+ #else
1302
+ /* transfer atom_stereo0D[] to atom[] */
1303
+ if ( len_stereo0D ) {
1304
+ Extract0DParities( atom, num_atoms, atom_stereo0D, len_stereo0D, pStrErr, err );
1305
+ }
1306
+ #endif
1307
+ if ( pInpAtomFlags ) {
1308
+ /* save chirality flag */
1309
+ *pInpAtomFlags |= InpAtomFlags;
1310
+ }
1311
+ } else
1312
+ if ( atom ) {
1313
+ inchi_free( atom );
1314
+ atom = NULL;
1315
+ }
1316
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1317
+ #else
1318
+ if ( szCoord ) {
1319
+ *szCoord = pszCoord;
1320
+ pszCoord = NULL;
1321
+ } else
1322
+ #endif
1323
+ if ( pszCoord ) {
1324
+ inchi_free( pszCoord );
1325
+ pszCoord = NULL;
1326
+ }
1327
+ goto bypass_end_of_INChI_plain;
1328
+ /*return num_atoms;*/
1329
+ }
1330
+ }
1331
+ if ( atom_stereo0D ) {
1332
+ FreeInchi_Stereo0D( &atom_stereo0D );
1333
+ }
1334
+ /* end of struct. reading cycle */
1335
+ if ( res <= 0 ) {
1336
+ if ( *err == INCHI_INP_ERROR_ERR ) {
1337
+ return num_atoms;
1338
+ }
1339
+ *err = INCHI_INP_EOF_ERR;
1340
+ return INCHI_INP_EOF_RET; /* no more data */
1341
+ }
1342
+ bypass_end_of_INChI_plain:
1343
+ /* cleanup */
1344
+ if ( num_atoms == INCHI_INP_ERROR_RET && atom_stereo0D ) {
1345
+ if ( stereo0D && *stereo0D == atom_stereo0D ) {
1346
+ *stereo0D = NULL;
1347
+ *num_stereo0D = 0;
1348
+ }
1349
+ FreeInchi_Stereo0D( &atom_stereo0D );
1350
+ }
1351
+ while ( bTooLongLine &&
1352
+ 0 < my_fgetsTab1( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine ) ) {
1353
+ ;
1354
+ }
1355
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1356
+ /* cleanup */
1357
+ if ( !*at ) {
1358
+ if ( atom ) {
1359
+ inchi_free( atom );
1360
+ atom = NULL;
1361
+ }
1362
+ if ( pszCoord ) {
1363
+ inchi_free( pszCoord );
1364
+ pszCoord = NULL;
1365
+ }
1366
+ }
1367
+ #endif
1368
+
1369
+ return num_atoms;
1370
+ }
1371
+
1372
+ /***********************************************************/
1373
+ /* extract reversibility info from xml text INChI format */
1374
+ /* */
1375
+ /* OBSOLETE CODE because InChI output in XML */
1376
+ /* does not exist anymore. Unsupported. */
1377
+ /* */
1378
+ /***********************************************************/
1379
+ if ( nInputType == INPUT_INCHI_XML ) {
1380
+ /* xml tags */
1381
+ static char sStructHdrXml[] = "<structure";
1382
+ static char sStructHdrXmlEnd[] = "</structure";
1383
+ static char sStructHdrXmlNumber[] = "number=\"";
1384
+ static char sStructHdrXmlIdName[] = "id.name=\"";
1385
+ static char sStructHdrXmlIdValue[] = "id.value=\"";
1386
+ static char sStructMsgXmlErr[] = "<message type=\"error (no InChI)\" value=\"";
1387
+ static char sStructMsgXmlErrFatal[] = "<message type=\"fatal (aborted)\" value=\"";
1388
+ static char sStructRevXmlRevHdr[] = "<reversibility>";
1389
+ static char sStructRevXmlRevAt[] = "<atoms>";
1390
+ static char sStructRevXmlRevAtEnd[] = "</atoms>";
1391
+ static char sStructRevXmlRevBn[] = "<bonds>";
1392
+ static char sStructRevXmlRevBnEnd[] = "</bonds>";
1393
+ static char sStructRevXmlRevXYZ[] = "<xyz>";
1394
+ static char sStructRevXmlRevXYZEnd[]= "</xyz>";
1395
+ static char sStructAuxXml[] = "<identifier.auxiliary-info";
1396
+ static char sStructAuxXmlEnd[] = "</identifier.auxiliary-info";
1397
+ int bInTheAuxInfo = 0;
1398
+
1399
+ while ( 0 < (res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine ) ) ) {
1400
+
1401
+ /********************* find and interpret structure header ************/
1402
+ if ( !memcmp(szLine, sStructHdrXml, sizeof(sStructHdrXml)-1) ) {
1403
+ num_struct = 1;
1404
+ p = szLine + sizeof(sStructHdrXml)-1;
1405
+ longID = 0;
1406
+ num_atoms = 0;
1407
+ /* structure number */
1408
+ if ( q = strstr( p, sStructHdrXmlNumber ) ) {
1409
+ p = q + sizeof(sStructHdrXmlNumber)-1;
1410
+ longID = strtol( p, &q, 10);
1411
+ if ( q && *q == '\"' )
1412
+ p = q+1;
1413
+ }
1414
+ if ( pSdfLabel ) {
1415
+ pSdfLabel[0] = '\0';
1416
+ }
1417
+ if ( pSdfValue ) {
1418
+ pSdfValue[0] = '\0';
1419
+ }
1420
+ /* pSdfLabel */
1421
+ if ( q = strstr( p, sStructHdrXmlIdName ) ) {
1422
+ p = q + sizeof(sStructHdrXmlIdName)-1;
1423
+ q = strchr( p, '\"' );
1424
+ if ( q ) {
1425
+ len = inchi_min( q-p+1, MAX_SDF_HEADER-1);
1426
+ if ( pSdfLabel ) {
1427
+ mystrncpy( pSdfLabel, p, len );
1428
+ }
1429
+ p = q+1;
1430
+ }
1431
+ }
1432
+ /* pSdfValue */
1433
+ if ( q = strstr( p, sStructHdrXmlIdValue ) ) {
1434
+ p = q + sizeof(sStructHdrXmlIdValue)-1;
1435
+ q = strchr( p, '\"' );
1436
+ if ( q ) {
1437
+ len = inchi_min( q-p+1, MAX_SDF_VALUE-1);
1438
+ if ( pSdfValue ) {
1439
+ mystrncpy( pSdfValue, p, len );
1440
+ }
1441
+ p = q+1;
1442
+ }
1443
+ }
1444
+ if ( Id )
1445
+ *Id = longID;
1446
+ bHeaderRead = 1;
1447
+ bErrorMsg = bRestoreInfo = 0;
1448
+ } else
1449
+ if ( bHeaderRead && (bFatal=0, len=sizeof(sStructMsgXmlErr)-1, !memcmp(szLine, sStructMsgXmlErr, len)) ||
1450
+ bHeaderRead && (len=sizeof(sStructMsgXmlErrFatal)-1, !memcmp(szLine, sStructMsgXmlErrFatal, len))&&(bFatal=1)) {
1451
+ p = szLine+len;
1452
+ q = strchr( p, '\"' );
1453
+ if ( q && !bFindNext ) {
1454
+ int c;
1455
+ bErrorMsg = 1;
1456
+ pStrErr[0] = '\0';
1457
+ c = *q;
1458
+ *q = '\0';
1459
+ MOLFILE_ERR_SET (*err, 0, p);
1460
+ *q = c;
1461
+ }
1462
+ *err = bFatal? INCHI_INP_FATAL_ERR : INCHI_INP_ERROR_ERR;
1463
+ num_atoms = bFatal? INCHI_INP_FATAL_RET : INCHI_INP_ERROR_RET;
1464
+ goto bypass_end_of_INChI;
1465
+ } else
1466
+ if ( bHeaderRead && !memcmp(szLine, sStructAuxXml, sizeof(sStructAuxXml)-1) ) {
1467
+ bInTheAuxInfo = 1;
1468
+ } else
1469
+ if ( bHeaderRead && !memcmp(szLine, sStructAuxXmlEnd, sizeof(sStructAuxXmlEnd)-1) ) {
1470
+ *err = INCHI_INP_ERROR_ERR;
1471
+ num_atoms = INCHI_INP_ERROR_RET;
1472
+ MOLFILE_ERR_SET (*err, 0, "Missing reversibility info" );
1473
+ goto bypass_end_of_INChI; /* reversibility info not found */
1474
+ } else
1475
+ if ( bHeaderRead && bInTheAuxInfo && !memcmp(szLine, sStructRevXmlRevHdr, sizeof(sStructRevXmlRevHdr)-1) ) {
1476
+ /*********************** atoms xml ***************************/
1477
+ num_struct = 1;
1478
+ res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine );
1479
+ if ( res <= 0 ) {
1480
+ num_atoms = INCHI_INP_EOF_RET; /* no data, probably end of file */
1481
+ *err = INCHI_INP_EOF_ERR;
1482
+ goto bypass_end_of_INChI;
1483
+ }
1484
+ if ( memcmp(szLine, sStructRevXmlRevAt, sizeof(sStructRevXmlRevAt)-1) ) {
1485
+ bHeaderRead = 0; /* invalid reversibility info; look for another header */
1486
+ continue;
1487
+ }
1488
+ /* read (the head of) the atoms line */
1489
+ res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine );
1490
+ if ( res <= 0 ) {
1491
+ num_atoms = INCHI_INP_EOF_RET; /* no data */
1492
+ *err = INCHI_INP_EOF_ERR;
1493
+ goto bypass_end_of_INChI;
1494
+ }
1495
+ p = szLine;
1496
+ num_atoms = strtol( p, &q, 10 );
1497
+ if ( !num_atoms || !q || !*q ) {
1498
+ num_atoms = INCHI_INP_EOF_RET; /* no atom data */
1499
+ *err = INCHI_INP_EOF_ERR;
1500
+ goto bypass_end_of_INChI;
1501
+ }
1502
+ p = q;
1503
+ /* Molfile chirality flag */
1504
+ switch( *p ) {
1505
+ case 'c':
1506
+ InpAtomFlags |= FLAG_INP_AT_CHIRAL;
1507
+ p ++;
1508
+ break;
1509
+ case 'n':
1510
+ InpAtomFlags |= FLAG_INP_AT_NONCHIRAL;
1511
+ p ++;
1512
+ break;
1513
+ }
1514
+ if ( at && *at ) {
1515
+ if ( num_atoms > max_num_at ) {
1516
+ inchi_free( *at );
1517
+ *at = NULL;
1518
+ } else {
1519
+ memset( *at, 0, max_num_at * sizeof( **at ) );
1520
+ atom = *at;
1521
+ }
1522
+ }
1523
+ if ( !at || !*at ) {
1524
+ atom = Create_Atom( num_atoms+1 );
1525
+ if ( !atom ) {
1526
+ num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
1527
+ *err = INCHI_INP_FATAL_ERR;
1528
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
1529
+ goto bypass_end_of_INChI;
1530
+ }
1531
+ }
1532
+ if ( stereo0D && *stereo0D ) {
1533
+ if ( num_atoms > max_len_stereo0D ) {
1534
+ FreeInchi_Stereo0D( stereo0D );
1535
+ } else {
1536
+ memset( *stereo0D, 0, max_len_stereo0D * sizeof( **stereo0D ) );
1537
+ atom_stereo0D = *stereo0D;
1538
+ }
1539
+ }
1540
+ if ( !stereo0D || !*stereo0D ) {
1541
+ max_len_stereo0D = num_atoms+1;
1542
+ atom_stereo0D = CreateInchi_Stereo0D( max_len_stereo0D );
1543
+ if ( !atom_stereo0D ) {
1544
+ num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
1545
+ *err = INCHI_INP_FATAL_ERR;
1546
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
1547
+ goto bypass_end_of_INChI;
1548
+ }
1549
+ }
1550
+
1551
+ i = 0;
1552
+ bItemIsOver = 0;
1553
+ res2 = bTooLongLine2 = -1;
1554
+
1555
+ /* read all atoms xml */
1556
+ while ( i < num_atoms ) {
1557
+ pos = p - szLine;
1558
+ if ( !bItemIsOver && (int)sizeof(szLine)-res + pos > (int)sizeof(szNextLine) ) {
1559
+ /* load next line if possible */
1560
+ res2 = my_fgets( szNextLine, sizeof(szNextLine)-1, inp_molfile, &bTooLongLine2 );
1561
+ if ( res2 > 0 && memcmp(szNextLine, sStructRevXmlRevAtEnd, sizeof(sStructRevXmlRevAtEnd)-1) ) {
1562
+ if ( pos ) {
1563
+ res -= pos; /* number of chars left to process in szLine */
1564
+ memmove( szLine, p, res*sizeof(szLine[0]) ); /* move them to the start of the line */
1565
+ }
1566
+ memcpy( szLine+res, szNextLine, (res2+1)*sizeof(szNextLine[0]) );
1567
+ res += res2;
1568
+ szLine[res] = '\0';
1569
+ bTooLongLine = bTooLongLine2;
1570
+ p = szLine;
1571
+ } else {
1572
+ bItemIsOver = 1;
1573
+ }
1574
+ }
1575
+ /* element, first char */
1576
+ if ( !isalpha( UCINT *p ) || !isupper( UCINT *p ) || i >= num_atoms ) {
1577
+ bHeaderRead = 0; /* wrong atom data */
1578
+ num_atoms = INCHI_INP_ERROR_RET; /* was 0, error */
1579
+ *err = INCHI_INP_ERROR_ERR; /* 40 */
1580
+ MOLFILE_ERR_SET (*err, 0, "Wrong atoms data");
1581
+ goto bypass_end_of_INChI;
1582
+ }
1583
+ atom[i].elname[0] = *p ++;
1584
+ /* element, second char */
1585
+ if ( isalpha( UCINT *p ) && islower( UCINT *p ) ) {
1586
+ atom[i].elname[1] = *p ++;
1587
+ }
1588
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1589
+ #else
1590
+ atom[i].el_number = get_periodic_table_number( atom[i].elname );
1591
+ #endif
1592
+ /* bonds' valence */
1593
+ if ( isdigit( UCINT *p ) ) {
1594
+ AT_BONDS_VAL(atom,i) = (char)strtol( p, &q, 10 );
1595
+ if ( !AT_BONDS_VAL(atom,i) )
1596
+ AT_BONDS_VAL(atom,i) = ISOLATED_ATOM; /* same convention as in MOLfile, found zero bonds valence */
1597
+ p = q;
1598
+ }
1599
+ /* charge */
1600
+ atom[i].charge = (*p == '+')? 1 : (*p == '-')? -1 : 0;
1601
+ if ( atom[i].charge ) {
1602
+ p ++;
1603
+ if ( isdigit( UCINT *p ) ) {
1604
+ atom[i].charge *= (S_CHAR)(strtol( p, &q, 10 ) & CHAR_MASK);
1605
+ p = q;
1606
+ }
1607
+ }
1608
+ /* radical */
1609
+ if ( *p == '.' ) {
1610
+ p ++;
1611
+ if ( isdigit( UCINT *p ) ) {
1612
+ atom[i].radical = (S_CHAR)strtol( p, &q, 10 );
1613
+ p = q;
1614
+ }
1615
+ }
1616
+ /* isotopic mass */
1617
+ if ( *p == 'i' ) {
1618
+ p ++;
1619
+ if ( isdigit( UCINT *p ) ) {
1620
+ int mw = strtol( p, &q, 10 );
1621
+ p = q;
1622
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
1623
+ atom[i].isotopic_mass = mw;
1624
+ #else
1625
+ mw -= get_atw_from_elnum( atom[i].el_number );
1626
+ if ( mw >= 0 )
1627
+ mw ++;
1628
+ atom[i].iso_atw_diff = mw;
1629
+ #endif
1630
+ }
1631
+ }
1632
+ /* parity */
1633
+ switch( *p ) {
1634
+ case 'o':
1635
+ parity = INCHI_PARITY_ODD;
1636
+ p ++;
1637
+ break;
1638
+ case 'e':
1639
+ parity = INCHI_PARITY_EVEN;
1640
+ p ++;
1641
+ break;
1642
+ case 'u':
1643
+ parity = INCHI_PARITY_UNKNOWN;
1644
+ p ++;
1645
+ break;
1646
+ case '?':
1647
+ parity = INCHI_PARITY_UNDEFINED;
1648
+ p ++;
1649
+ break;
1650
+ default:
1651
+ parity = 0;
1652
+ break;
1653
+ }
1654
+ if ( parity ) {
1655
+ atom_stereo0D[len_stereo0D].central_atom = i;
1656
+ atom_stereo0D[len_stereo0D].parity = parity;
1657
+ atom_stereo0D[len_stereo0D].type = INCHI_StereoType_Tetrahedral;
1658
+ len_stereo0D ++;
1659
+ }
1660
+ /* isotopic h, d, t */
1661
+ for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
1662
+ if ( *p == szIsoH[k] ) {
1663
+ NUM_ISO_Hk(atom,i,k) = 1;
1664
+ p ++;
1665
+ if ( isdigit( UCINT *p ) ) {
1666
+ NUM_ISO_Hk(atom,i,k) = (char)strtol( p, &q, 10 );
1667
+ p = q;
1668
+ }
1669
+ }
1670
+ }
1671
+ i ++;
1672
+ }
1673
+ if ( !bItemIsOver || p - szLine != res || i != num_atoms ) {
1674
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
1675
+ *err = INCHI_INP_ERROR_ERR;
1676
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of atoms");
1677
+ goto bypass_end_of_INChI;
1678
+ }
1679
+ /********************** bonds xml ****************************/
1680
+ res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine );
1681
+ if ( res <= 0 ) {
1682
+ num_atoms = 0; /* no data */
1683
+ goto bypass_end_of_INChI;
1684
+ }
1685
+ if ( memcmp(szLine, sStructRevXmlRevBn, sizeof(sStructRevXmlRevBn)-1) ) {
1686
+ bHeaderRead = 0; /* invalid reversibility info; look for another header */
1687
+ continue;
1688
+ }
1689
+ /* read (the head of) the xml bonds line */
1690
+ res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine );
1691
+ if ( res <= 0 ) {
1692
+ num_atoms = INCHI_INP_ERROR_RET; /* was 0; error: no data -- eof? */
1693
+ *err = INCHI_INP_ERROR_ERR;
1694
+ goto bypass_end_of_INChI;
1695
+ }
1696
+ i = 1;
1697
+ bItemIsOver = 0;
1698
+ res2 = bTooLongLine2 = -1;
1699
+ p = szLine;
1700
+ if ( !memcmp(szLine, sStructRevXmlRevBnEnd, sizeof(sStructRevXmlRevBnEnd)-1) ) {
1701
+ /* empty bonds section */
1702
+ res = 0;
1703
+ bItemIsOver = 1;
1704
+ }
1705
+ /* read all bonds (xml), starting from atom 1 (not 0) */
1706
+ while ( i < num_atoms ) {
1707
+ pos = p - szLine;
1708
+ if ( !bItemIsOver && (int)sizeof(szLine)-res + pos > (int)sizeof(szNextLine) ) {
1709
+ /* load next line if possible */
1710
+ res2 = my_fgets( szNextLine, sizeof(szNextLine)-1, inp_molfile, &bTooLongLine2 );
1711
+ if ( res2 > 0 && memcmp(szNextLine, sStructRevXmlRevBnEnd, sizeof(sStructRevXmlRevBnEnd)-1) ) {
1712
+ if ( pos ) {
1713
+ res -= pos; /* number of chars left to process in szLine */
1714
+ memmove( szLine, p, res*sizeof(szLine[0]) ); /* move them to the start of the line */
1715
+ }
1716
+ memcpy( szLine+res, szNextLine, (res2+1)*sizeof(szNextLine[0]) );
1717
+ res += res2;
1718
+ szLine[res] = '\0';
1719
+ bTooLongLine = bTooLongLine2;
1720
+ p = szLine;
1721
+ } else {
1722
+ bItemIsOver = 1;
1723
+ }
1724
+ }
1725
+ if ( i >= num_atoms ) {
1726
+ break;
1727
+ }
1728
+ /* bond, first char */
1729
+ if ( *p == ';' ) {
1730
+ p ++;
1731
+ i ++;
1732
+ continue;
1733
+ }
1734
+ if ( !isalpha( UCINT *p ) ) {
1735
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data */
1736
+ *err = INCHI_INP_ERROR_ERR;
1737
+ MOLFILE_ERR_SET (*err, 0, "Wrong bonds data");
1738
+ goto bypass_end_of_INChI;
1739
+ }
1740
+ bond_char = *p ++;
1741
+ /* bond parity */
1742
+ switch( *p ) {
1743
+ case '-':
1744
+ bond_parity = INCHI_PARITY_ODD;
1745
+ p ++;
1746
+ break;
1747
+ case '+':
1748
+ bond_parity = INCHI_PARITY_EVEN;
1749
+ p ++;
1750
+ break;
1751
+ case 'u':
1752
+ bond_parity = INCHI_PARITY_UNKNOWN;
1753
+ p ++;
1754
+ break;
1755
+ case '?':
1756
+ bond_parity = INCHI_PARITY_UNDEFINED;
1757
+ p ++;
1758
+ break;
1759
+ default:
1760
+ bond_parity = 0;
1761
+ break;
1762
+ }
1763
+ if ( bond_parity ) {
1764
+ switch( *p ) {
1765
+ case '-':
1766
+ bond_parityNM = INCHI_PARITY_ODD;
1767
+ p ++;
1768
+ break;
1769
+ case '+':
1770
+ bond_parityNM = INCHI_PARITY_EVEN;
1771
+ p ++;
1772
+ break;
1773
+ case 'u':
1774
+ bond_parityNM = INCHI_PARITY_UNKNOWN;
1775
+ p ++;
1776
+ break;
1777
+ case '?':
1778
+ bond_parityNM = INCHI_PARITY_UNDEFINED;
1779
+ p ++;
1780
+ break;
1781
+ default:
1782
+ bond_parityNM = 0;
1783
+ break;
1784
+ }
1785
+ } else {
1786
+ bond_parityNM = 0;
1787
+ }
1788
+
1789
+ /* neighbor of the current atom */
1790
+ if ( !isdigit( UCINT *p ) ) {
1791
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data */
1792
+ *err = INCHI_INP_ERROR_ERR;
1793
+ MOLFILE_ERR_SET (*err, 0, "Wrong bonds data");
1794
+ goto bypass_end_of_INChI;
1795
+ }
1796
+ neigh = (int)strtol( p, &q, 10 )-1;
1797
+
1798
+ if ( i >= num_atoms || neigh >= num_atoms ) {
1799
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data */
1800
+ *err = INCHI_INP_ERROR_ERR;
1801
+ MOLFILE_ERR_SET (*err, 0, "Bond to nonexistent atom");
1802
+ goto bypass_end_of_INChI;
1803
+ }
1804
+ p = q;
1805
+ bond_stereo1 = bond_stereo2 = 0;
1806
+
1807
+ /* bond type & 2D stereo */
1808
+ switch( bond_char ) {
1809
+ case 'v':
1810
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1811
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1EITHER;
1812
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2EITHER;
1813
+ break;
1814
+ case 'V':
1815
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1816
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2EITHER;
1817
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1EITHER;
1818
+ break;
1819
+ case 'w':
1820
+ bond_type = INCHI_BOND_TYPE_DOUBLE;
1821
+ bond_stereo1 =
1822
+ bond_stereo2 = INCHI_BOND_STEREO_DOUBLE_EITHER;
1823
+ break;
1824
+ case 's':
1825
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1826
+ break;
1827
+ case 'd':
1828
+ bond_type = INCHI_BOND_TYPE_DOUBLE;
1829
+ break;
1830
+ case 't':
1831
+ bond_type = INCHI_BOND_TYPE_TRIPLE;
1832
+ break;
1833
+ case 'a':
1834
+ bond_type = INCHI_BOND_TYPE_ALTERN;
1835
+ break;
1836
+ case 'p':
1837
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1838
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1UP;
1839
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2UP;
1840
+ break;
1841
+ case 'P':
1842
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1843
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2UP;
1844
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1UP;
1845
+ break;
1846
+ case 'n':
1847
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1848
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1DOWN;
1849
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2DOWN;
1850
+ break;
1851
+ case 'N':
1852
+ bond_type = INCHI_BOND_TYPE_SINGLE;
1853
+ bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2DOWN;
1854
+ bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1DOWN;
1855
+ break;
1856
+ default:
1857
+ num_atoms = INCHI_INP_ERROR_RET; /* error */
1858
+ *err = INCHI_INP_ERROR_ERR;
1859
+ MOLFILE_ERR_SET (*err, 0, "Wrong bond type");
1860
+ goto bypass_end_of_INChI;
1861
+ }
1862
+ k = AT_NUM_BONDS(atom[i]) ++;
1863
+ atom[i].bond_type[k] = bond_type;
1864
+ atom[i].bond_stereo[k] = bond_stereo1;
1865
+ atom[i].neighbor[k] = (ATOM_NUMBER)neigh;
1866
+ k2 = AT_NUM_BONDS(atom[neigh]) ++;
1867
+ atom[neigh].bond_type[k2] = bond_type;
1868
+ atom[neigh].bond_stereo[k2] = bond_stereo2;
1869
+ atom[neigh].neighbor[k2] = (ATOM_NUMBER)i;
1870
+ bond_parity |= (bond_parityNM << SB_PARITY_SHFT);
1871
+
1872
+ if ( bond_parity ) {
1873
+ if ( max_len_stereo0D <= len_stereo0D ) {
1874
+ /* realloc atom_Stereo0D */
1875
+ inchi_Stereo0D *new_atom_stereo0D = CreateInchi_Stereo0D( max_len_stereo0D+num_atoms );
1876
+ if ( !new_atom_stereo0D ) {
1877
+ num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
1878
+ *err = INCHI_INP_FATAL_ERR;
1879
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
1880
+ goto bypass_end_of_INChI;
1881
+ }
1882
+ memcpy( new_atom_stereo0D, atom_stereo0D, len_stereo0D * sizeof(*atom_stereo0D) );
1883
+ FreeInchi_Stereo0D( &atom_stereo0D );
1884
+ atom_stereo0D = new_atom_stereo0D;
1885
+ max_len_stereo0D += num_atoms;
1886
+ }
1887
+ /* (a) i may be allene endpoint and neigh = allene middle point or
1888
+ (b) i may be allene middle point and neigh = allene endpoint
1889
+ !!!!! CURRENTLY ONLY (b) IS ALLOWED !!!!!
1890
+ */
1891
+ atom_stereo0D[len_stereo0D].neighbor[1] = neigh; /* neigh < i */
1892
+ atom_stereo0D[len_stereo0D].neighbor[2] = i;
1893
+ atom_stereo0D[len_stereo0D].parity = bond_parity;
1894
+ atom_stereo0D[len_stereo0D].type = INCHI_StereoType_DoubleBond; /* incl allenes & cumulenes */
1895
+ len_stereo0D ++;
1896
+ }
1897
+ }
1898
+ if ( !bItemIsOver || p - szLine != res || i != num_atoms ) {
1899
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data */
1900
+ *err = INCHI_INP_ERROR_ERR;
1901
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of bonds");
1902
+ goto bypass_end_of_INChI;
1903
+ }
1904
+ /********************** coordinates xml ****************************/
1905
+ if ( pszCoord = (MOL_COORD*)inchi_malloc(inchi_max(num_atoms,1) * sizeof(MOL_COORD)) ) {
1906
+ memset( pszCoord, ' ', inchi_max(num_atoms,1) * sizeof(MOL_COORD));
1907
+ res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine );
1908
+ if ( res <= 0 ||
1909
+ /* compare the header */
1910
+ memcmp(szLine, sStructRevXmlRevXYZ, sizeof(sStructRevXmlRevXYZ)-1) ||
1911
+ /* read (the head of) the coordinates (xml) line */
1912
+ 0 >= (res = my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine ))) {
1913
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data: atoms, bonds & coord must be present together */
1914
+ *err = INCHI_INP_ERROR_ERR;
1915
+ MOLFILE_ERR_SET (*err, 0, "Missing atom coordinates data");
1916
+ goto bypass_end_of_INChI;
1917
+ }
1918
+ i = 0;
1919
+ bItemIsOver = 0;
1920
+ res2 = bTooLongLine2 = -1;
1921
+ p = szLine;
1922
+ if ( !memcmp(szLine, sStructRevXmlRevXYZEnd, sizeof(sStructRevXmlRevXYZEnd)-1) ) {
1923
+ /* empty bonds section */
1924
+ res = 0;
1925
+ bItemIsOver = 1;
1926
+ }
1927
+ /* read all coordinates (xml), starting from atom 1 (not 0) */
1928
+ while ( i < num_atoms ) {
1929
+ pos = p - szLine;
1930
+ if ( !bItemIsOver && (int)sizeof(szLine)-res + pos > (int)sizeof(szNextLine) ) {
1931
+ /* load next line if possible */
1932
+ res2 = my_fgets( szNextLine, sizeof(szNextLine)-1, inp_molfile, &bTooLongLine2 );
1933
+ if ( res2 > 0 && memcmp(szNextLine, sStructRevXmlRevXYZEnd, sizeof(sStructRevXmlRevXYZEnd)-1) ) {
1934
+ if ( pos ) {
1935
+ res -= pos; /* number of chars left to process in szLine */
1936
+ memmove( szLine, p, res*sizeof(szLine[0]) ); /* move them to the start of the line */
1937
+ }
1938
+ memcpy( szLine+res, szNextLine, (res2+1)*sizeof(szNextLine[0]) );
1939
+ res += res2;
1940
+ szLine[res] = '\0';
1941
+ bTooLongLine = bTooLongLine2;
1942
+ p = szLine;
1943
+ } else {
1944
+ bItemIsOver = 1;
1945
+ }
1946
+ }
1947
+ /* coord, first char */
1948
+ if ( *p == ';' ) {
1949
+ for ( k = 0; k < NUM_COORD; k ++ ) {
1950
+ pszCoord[i][LEN_COORD*k + 4] = '0';
1951
+ }
1952
+ p ++;
1953
+ i ++;
1954
+ continue;
1955
+ }
1956
+ for ( k = 0; k < 3; k ++ ) {
1957
+ double xyz;
1958
+ bNonZeroXYZ = 0;
1959
+ if ( *p == ';' ) {
1960
+ pszCoord[i][LEN_COORD*k + 4] = '0';
1961
+ xyz = 0.0;
1962
+ } else
1963
+ if ( *p == ',' ) {
1964
+ /* empty */
1965
+ pszCoord[i][LEN_COORD*k + 4] = '0';
1966
+ xyz = 0.0;
1967
+ p ++;
1968
+ } else {
1969
+ xyz = strtod( p, &q );
1970
+ bNonZeroXYZ = fabs(xyz) > MIN_BOND_LENGTH;
1971
+ if ( q != NULL ) {
1972
+ memcpy( pszCoord[i]+LEN_COORD*k, p, q-p );
1973
+ if ( *q == ',' )
1974
+ q ++;
1975
+ p = q;
1976
+ } else {
1977
+ pszCoord[i][LEN_COORD*k + 4] = '0';
1978
+ }
1979
+ }
1980
+ switch( k ) {
1981
+ case 0:
1982
+ atom[i].x = xyz;
1983
+ b2D |= bNonZeroXYZ;
1984
+ break;
1985
+ case 1:
1986
+ atom[i].y = xyz;
1987
+ b2D |= bNonZeroXYZ;
1988
+ break;
1989
+ case 2:
1990
+ b3D |= bNonZeroXYZ;
1991
+ atom[i].z = xyz;
1992
+ break;
1993
+ }
1994
+ }
1995
+ if ( *p == ';' ) {
1996
+ p ++; /* end of this triple of coordinates */
1997
+ i ++;
1998
+ } else {
1999
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data: atoms, bonds & coord must be present together */
2000
+ *err = INCHI_INP_ERROR_ERR;
2001
+ MOLFILE_ERR_SET (*err, 0, "Wrong atom coordinates data");
2002
+ goto bypass_end_of_INChI;
2003
+ }
2004
+ }
2005
+ if ( !bItemIsOver || p - szLine != res || i != num_atoms ) {
2006
+ num_atoms = INCHI_INP_ERROR_RET; /* error in input data: atoms, bonds & coord must be present together */
2007
+ *err = INCHI_INP_ERROR_ERR;
2008
+ MOLFILE_ERR_SET (*err, 0, "Wrong number of coordinates");
2009
+ goto bypass_end_of_INChI;
2010
+ }
2011
+ } else { /* allocation failed */
2012
+ num_atoms = INCHI_INP_FATAL_RET;
2013
+ *err = INCHI_INP_FATAL_ERR;
2014
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
2015
+ goto bypass_end_of_INChI;
2016
+ }
2017
+ /* set special valences and implicit H (xml) */
2018
+ b23D = b2D | b3D;
2019
+ b2D = b3D = 0;
2020
+ if ( at ) {
2021
+ if ( !*at ) {
2022
+ int a1, a2, n1, n2, valence;
2023
+ int chem_bonds_valence;
2024
+ int nX=0, nY=0, nZ=0, nXYZ;
2025
+ *at = atom;
2026
+ /* special valences */
2027
+ for ( bNonMetal = 0; bNonMetal < 1 /*2*/; bNonMetal ++ ) {
2028
+ for ( a1 = 0; a1 < num_atoms; a1 ++ ) {
2029
+ int num_bond_type[MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE + 1];
2030
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2031
+ #else
2032
+ int bHasMetalNeighbor=0;
2033
+ #endif
2034
+ memset( num_bond_type, 0, sizeof(num_bond_type) );
2035
+
2036
+ valence = AT_BONDS_VAL(atom, a1); /* save atom valence if available */
2037
+ AT_BONDS_VAL(atom, a1) = 0;
2038
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2039
+ #else
2040
+ atom[a1].orig_at_number = a1+1;
2041
+ #endif
2042
+ nX = nY = nZ = 0;
2043
+ for ( n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1 ++ ) {
2044
+ bond_type = atom[a1].bond_type[n1] - MIN_INPUT_BOND_TYPE;
2045
+ if ( bond_type < 0 || bond_type > MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE ) {
2046
+ bond_type = 0; /* cannot happen */
2047
+ MOLFILE_ERR_SET (*err, 0, "Unknown bond type in InChI aux assigned as a single bond");
2048
+ }
2049
+
2050
+ num_bond_type[ bond_type ] ++;
2051
+ nNumBonds ++;
2052
+ if ( b23D ) {
2053
+ neigh = atom[a1].neighbor[n1];
2054
+ nX |= (fabs(atom[a1].x - atom[neigh].x) > MIN_BOND_LENGTH);
2055
+ nY |= (fabs(atom[a1].y - atom[neigh].y) > MIN_BOND_LENGTH);
2056
+ nZ |= (fabs(atom[a1].z - atom[neigh].z) > MIN_BOND_LENGTH);
2057
+ }
2058
+ }
2059
+ chem_bonds_valence = 0;
2060
+ for ( n1 = 0; MIN_INPUT_BOND_TYPE + n1 <= 3 && MIN_INPUT_BOND_TYPE + n1 <= MAX_INPUT_BOND_TYPE; n1 ++ ) {
2061
+ chem_bonds_valence += (MIN_INPUT_BOND_TYPE + n1) * num_bond_type[n1];
2062
+ }
2063
+ if ( MIN_INPUT_BOND_TYPE <= INCHI_BOND_TYPE_ALTERN && INCHI_BOND_TYPE_ALTERN <= MAX_INPUT_BOND_TYPE &&
2064
+ ( n2 = num_bond_type[INCHI_BOND_TYPE_ALTERN-MIN_INPUT_BOND_TYPE] ) ) {
2065
+ /* accept input aromatic bonds for now */
2066
+ switch ( n2 ) {
2067
+ case 2:
2068
+ chem_bonds_valence += 3; /* =A- */
2069
+ break;
2070
+ case 3:
2071
+ chem_bonds_valence += 4; /* =A< */
2072
+ break;
2073
+ default:
2074
+ /* if 1 or >= 4 aromatic bonds then replace such bonds with single bonds */
2075
+ for ( n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1 ++ ) {
2076
+ if ( atom[a1].bond_type[n1] == INCHI_BOND_TYPE_ALTERN ) {
2077
+ ATOM_NUMBER *p1;
2078
+ a2 = atom[a1].neighbor[n1];
2079
+ p1 = IN_NEIGH_LIST( atom[a2].neighbor, (ATOM_NUMBER)a1, AT_NUM_BONDS(atom[a2]) );
2080
+ if ( p1 ) {
2081
+ atom[a1].bond_type[n1] =
2082
+ atom[a2].bond_type[p1-atom[a2].neighbor] = INCHI_BOND_TYPE_SINGLE;
2083
+ } else {
2084
+ *err = -2; /* Program error */
2085
+ MOLFILE_ERR_SET (*err, 0, "Program error interpreting InChI aux");
2086
+ num_atoms = 0;
2087
+ goto bypass_end_of_INChI; /* no structure */
2088
+ }
2089
+ }
2090
+ }
2091
+ chem_bonds_valence += n2;
2092
+ *err |= 32; /* Unrecognized aromatic bond(s) replaced with single */
2093
+ MOLFILE_ERR_SET (*err, 0, "Atom has more than 3 aromatic bonds");
2094
+ break;
2095
+ }
2096
+ }
2097
+
2098
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2099
+ /*************************************************************************************
2100
+ *
2101
+ * Set number of hydrogen atoms
2102
+ */
2103
+ {
2104
+ int num_iso_H;
2105
+ num_iso_H = atom[a1].num_iso_H[1] + atom[a1].num_iso_H[2] + atom[a1].num_iso_H[3];
2106
+ if ( valence == ISOLATED_ATOM ) {
2107
+ atom[a1].num_iso_H[0] = 0;
2108
+ } else
2109
+ if ( valence && valence >= chem_bonds_valence ) {
2110
+ atom[a1].num_iso_H[0] = valence - chem_bonds_valence;
2111
+ } else
2112
+ if ( valence || bDoNotAddH ) {
2113
+ atom[a1].num_iso_H[0] = 0;
2114
+ } else
2115
+ if ( !bDoNotAddH ) {
2116
+ atom[a1].num_iso_H[0] = -1; /* auto add H */
2117
+ }
2118
+ }
2119
+ #else
2120
+ atom[a1].chem_bonds_valence = chem_bonds_valence;
2121
+ atom[a1].num_H = get_num_H( atom[a1].elname, atom[a1].num_H, atom[a1].num_iso_H, atom[a1].charge, atom[a1].radical,
2122
+ atom[a1].chem_bonds_valence,
2123
+ valence,
2124
+ 0, bDoNotAddH, bHasMetalNeighbor );
2125
+ #endif
2126
+ }
2127
+ }
2128
+ nNumBonds /= 2;
2129
+ if ( b23D && nNumBonds ) {
2130
+ nXYZ = nX+nY+nZ;
2131
+ b2D = (nXYZ > 0);
2132
+ b3D = (nXYZ == 3);
2133
+ *num_dimensions = b3D? 3 : b2D? 2 : 0;
2134
+ *num_bonds = nNumBonds;
2135
+ }
2136
+ /*======= 0D parities =================================*/
2137
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2138
+ if ( len_stereo0D > 0 && atom_stereo0D && stereo0D ) {
2139
+ *stereo0D = atom_stereo0D;
2140
+ *num_stereo0D = len_stereo0D;
2141
+ } else {
2142
+ FreeInchi_Stereo0D( &atom_stereo0D );
2143
+ *num_stereo0D = len_stereo0D = 0;
2144
+ }
2145
+ #endif
2146
+ for ( i = 0; i < len_stereo0D; i ++ ) {
2147
+ ATOM_NUMBER *p1, *p2;
2148
+ int sb_ord_from_a1 = -1, sb_ord_from_a2 = -1, bEnd1 = 0, bEnd2 = 0;
2149
+ switch( atom_stereo0D[i].type ) {
2150
+
2151
+ case INCHI_StereoType_Tetrahedral:
2152
+ a1 = atom_stereo0D[i].central_atom;
2153
+ if ( atom_stereo0D[i].parity && (AT_NUM_BONDS(atom[a1]) == 3 || AT_NUM_BONDS(atom[a1]) == 4) ) {
2154
+ int ii, kk = 0;
2155
+ if ( AT_NUM_BONDS(atom[a1]) == 3 ) {
2156
+ atom_stereo0D[i].neighbor[kk++] = a1;
2157
+ }
2158
+ for ( ii = 0; ii < AT_NUM_BONDS(atom[a1]); ii ++ ) {
2159
+ atom_stereo0D[i].neighbor[kk++] = atom[a1].neighbor[ii];
2160
+ }
2161
+ }
2162
+
2163
+ break;
2164
+
2165
+ case INCHI_StereoType_DoubleBond:
2166
+ #define MAX_CHAIN_LEN 20
2167
+ a1 = atom_stereo0D[i].neighbor[1];
2168
+ a2 = atom_stereo0D[i].neighbor[2];
2169
+ p1 = IN_NEIGH_LIST( atom[a1].neighbor, (ATOM_NUMBER)a2, AT_NUM_BONDS(atom[a1]) );
2170
+ p2 = IN_NEIGH_LIST( atom[a2].neighbor, (ATOM_NUMBER)a1, AT_NUM_BONDS(atom[a2]) );
2171
+ if ( !p1 || !p2 ) {
2172
+ atom_stereo0D[i].type = INCHI_StereoType_None;
2173
+ atom_stereo0D[i].central_atom = NO_ATOM;
2174
+ atom_stereo0D[i].neighbor[0] =
2175
+ atom_stereo0D[i].neighbor[4] = -1;
2176
+ *err |= 64; /* Error in cumulene stereo */
2177
+ MOLFILE_ERR_SET (*err, 0, "0D stereobond not recognized");
2178
+ break;
2179
+ }
2180
+ /* streobond, allene, or cumulene */
2181
+
2182
+ sb_ord_from_a1 = p1 - atom[a1].neighbor;
2183
+ sb_ord_from_a2 = p2 - atom[a2].neighbor;
2184
+
2185
+ if ( AT_NUM_BONDS(atom[a1]) == 2 &&
2186
+ atom[a1].bond_type[0] + atom[a1].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
2187
+ 0 == inchi_NUMH2(atom, a1) &&
2188
+ (AT_NUM_BONDS(atom[a2]) != 2 ||
2189
+ atom[a2].bond_type[0] + atom[a2].bond_type[1] != 2*INCHI_BOND_TYPE_DOUBLE ) ) {
2190
+ bEnd2 = 1; /* a2 is the end-atom, a1 is middle atom */
2191
+ }
2192
+ if ( AT_NUM_BONDS(atom[a2]) == 2 &&
2193
+ atom[a2].bond_type[0] + atom[a2].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
2194
+ 0 == inchi_NUMH2(atom, a2) &&
2195
+ (AT_NUM_BONDS(atom[a1]) != 2 ||
2196
+ atom[a1].bond_type[0] + atom[a1].bond_type[1] != 2*INCHI_BOND_TYPE_DOUBLE ) ) {
2197
+ bEnd1 = 1; /* a1 is the end-atom, a2 is middle atom */
2198
+ }
2199
+
2200
+ if ( bEnd2 + bEnd1 == 1 ) {
2201
+ /* allene or cumulene */
2202
+ ATOM_NUMBER chain[MAX_CHAIN_LEN+1], prev, cur, next;
2203
+ if ( bEnd2 && !bEnd1 ) {
2204
+ cur = a1;
2205
+ a1 = a2;
2206
+ a2 = cur;
2207
+ sb_ord_from_a1 = sb_ord_from_a2;
2208
+ }
2209
+ sb_ord_from_a2 = -1;
2210
+ cur = a1;
2211
+ next = a2;
2212
+ len = 0;
2213
+ chain[len++] = cur;
2214
+ chain[len++] = next;
2215
+ while ( len < MAX_CHAIN_LEN ) { /* arbitrary very high upper limit to prevent infinite loop */
2216
+ prev = cur;
2217
+ cur = next;
2218
+ /* follow double bond path && avoid going back */
2219
+ if ( AT_NUM_BONDS(atom[cur]) == 2 &&
2220
+ atom[cur].bond_type[0]+atom[cur].bond_type[1] == 2*INCHI_BOND_TYPE_DOUBLE &&
2221
+ 0 == inchi_NUMH2(atom, cur) ) {
2222
+ next = atom[cur].neighbor[atom[cur].neighbor[0] == prev];
2223
+ chain[len++] = next;
2224
+ } else {
2225
+ break;
2226
+ }
2227
+ }
2228
+ if ( len > 2 &&
2229
+ (p2 = IN_NEIGH_LIST( atom[cur].neighbor, (ATOM_NUMBER)prev, AT_NUM_BONDS(atom[cur]))) ) {
2230
+ sb_ord_from_a2 = p2 - atom[cur].neighbor;
2231
+ a2 = cur;
2232
+ /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
2233
+ atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[sb_ord_from_a1 == 0];
2234
+ atom_stereo0D[i].neighbor[1] = a1;
2235
+ atom_stereo0D[i].neighbor[2] = a2;
2236
+ atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[sb_ord_from_a2 == 0];
2237
+ if ( len % 2 ) {
2238
+ atom_stereo0D[i].central_atom = chain[len/2];
2239
+ atom_stereo0D[i].type = INCHI_StereoType_Allene;
2240
+ } else {
2241
+ atom_stereo0D[i].central_atom = NO_ATOM;
2242
+ }
2243
+ } else {
2244
+ /* error */
2245
+ atom_stereo0D[i].type = INCHI_StereoType_None;
2246
+ atom_stereo0D[i].central_atom = NO_ATOM;
2247
+ atom_stereo0D[i].neighbor[0] =
2248
+ atom_stereo0D[i].neighbor[4] = -1;
2249
+ *err |= 64; /* Error in cumulene stereo */
2250
+ MOLFILE_ERR_SET (*err, 0, "Cumulene stereo not recognized (0D)");
2251
+
2252
+ }
2253
+ #undef MAX_CHAIN_LEN
2254
+ } else {
2255
+ /****** a normal possibly stereogenic bond -- not an allene or cumulene *******/
2256
+ /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
2257
+ sb_ord_from_a1 = p1 - atom[a1].neighbor;
2258
+ sb_ord_from_a2 = p2 - atom[a2].neighbor;
2259
+ atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[p1 == atom[a1].neighbor];
2260
+ atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[p2 == atom[a2].neighbor];
2261
+ atom_stereo0D[i].central_atom = NO_ATOM;
2262
+ }
2263
+ if ( atom_stereo0D[i].type != INCHI_StereoType_None &&
2264
+ sb_ord_from_a1 >= 0 && sb_ord_from_a2 >= 0 &&
2265
+ ATOM_PARITY_WELL_DEF( SB_PARITY_2(atom_stereo0D[i].parity) ) ) {
2266
+ /* Detected well-defined disconnected stereo
2267
+ * locate first non-metal neighbors */
2268
+ int a, n, j, /* k,*/ sb_ord, cur_neigh, min_neigh;
2269
+ for ( k = 0; k < 2; k ++ ) {
2270
+ a = k? atom_stereo0D[i].neighbor[2] : atom_stereo0D[i].neighbor[1];
2271
+ sb_ord = k? sb_ord_from_a2 : sb_ord_from_a1;
2272
+ min_neigh = num_atoms;
2273
+ for ( n = j = 0; j < AT_NUM_BONDS(atom[a]); j ++ ) {
2274
+ cur_neigh = atom[a].neighbor[j];
2275
+ if ( j != sb_ord && !IS_METAL_ATOM(atom, cur_neigh) ) {
2276
+ min_neigh = inchi_min( cur_neigh, min_neigh );
2277
+ }
2278
+ }
2279
+ if ( min_neigh < num_atoms ) {
2280
+ atom_stereo0D[i].neighbor[k?3:0] = min_neigh;
2281
+ } else {
2282
+ MOLFILE_ERR_SET (*err, 0, "Cannot find non-metal stereobond neighor (0D)");
2283
+ }
2284
+ }
2285
+ }
2286
+
2287
+ break;
2288
+ }
2289
+ }
2290
+ /* end of 0D parities extraction */
2291
+ /*exit_cycle:;*/
2292
+ }
2293
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2294
+ #else
2295
+ /* transfer atom_stereo0D[] to atom[] */
2296
+ if ( len_stereo0D ) {
2297
+ Extract0DParities( atom, num_atoms, atom_stereo0D, len_stereo0D, pStrErr, err );
2298
+ }
2299
+ #endif
2300
+ if ( pInpAtomFlags ) {
2301
+ /* save chirality flag */
2302
+ *pInpAtomFlags |= InpAtomFlags;
2303
+ }
2304
+ } else
2305
+ if ( atom ) {
2306
+ inchi_free( atom );
2307
+ atom = NULL;
2308
+ }
2309
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2310
+ #else
2311
+ if ( szCoord ) {
2312
+ *szCoord = pszCoord;
2313
+ pszCoord = NULL;
2314
+ } else
2315
+ #endif
2316
+ if ( pszCoord ) {
2317
+ inchi_free( pszCoord );
2318
+ }
2319
+ goto bypass_end_of_INChI;
2320
+ /*return num_atoms;*/
2321
+ }
2322
+ }
2323
+ if ( atom_stereo0D ) {
2324
+ FreeInchi_Stereo0D( &atom_stereo0D );
2325
+ }
2326
+ /* end of struct. reading cycle, code never used? */
2327
+ if ( res <= 0 ) {
2328
+ if ( *err == INCHI_INP_ERROR_ERR ) {
2329
+ return num_atoms;
2330
+ }
2331
+ *err = INCHI_INP_EOF_ERR;
2332
+ return INCHI_INP_EOF_RET; /* no more data */
2333
+ }
2334
+ bypass_end_of_INChI:
2335
+ /* cleanup */
2336
+ if ( num_atoms == INCHI_INP_ERROR_RET && atom_stereo0D ) {
2337
+ if ( stereo0D && *stereo0D == atom_stereo0D ) {
2338
+ *stereo0D = NULL;
2339
+ *num_stereo0D = 0;
2340
+ }
2341
+ FreeInchi_Stereo0D( &atom_stereo0D );
2342
+ }
2343
+ if ( !memcmp(szLine, sStructHdrXmlEnd, sizeof(sStructHdrXmlEnd)-1) )
2344
+ num_struct --;
2345
+ if ( !memcmp(szLine, sStructHdrXml, sizeof(sStructHdrXml)-1) )
2346
+ num_struct ++;
2347
+
2348
+ while ( num_struct > 0 && 0 < my_fgets( szLine, sizeof(szLine)-1, inp_molfile, &bTooLongLine ) ) {
2349
+ if ( !memcmp(szLine, sStructHdrXmlEnd, sizeof(sStructHdrXmlEnd)-1) )
2350
+ num_struct --;
2351
+ else
2352
+ if ( !memcmp(szLine, sStructHdrXml, sizeof(sStructHdrXml)-1) )
2353
+ num_struct ++;
2354
+ }
2355
+ return num_atoms;
2356
+
2357
+ }
2358
+
2359
+ return num_atoms;
2360
+
2361
+ #undef AT_NUM_BONDS
2362
+ #undef ATOM_NUMBER
2363
+ #undef IN_NEIGH_LIST
2364
+ #undef inchi_NUMH2
2365
+
2366
+ #if( defined(INCHI_LIBRARY) || defined(INCHI_MAIN) )
2367
+ #else
2368
+ #undef inchi_Atom
2369
+ #endif
2370
+
2371
+ #undef AT_NUM_BONDS
2372
+ #undef ATOM_NUMBER
2373
+ #undef IN_NEIGH_LIST
2374
+ #undef inchi_NUMH2
2375
+ #undef INChITo_Atom
2376
+ #undef MoreParms
2377
+ #undef INPUT_FILE
2378
+ #undef Create_Atom
2379
+ #undef AT_BONDS_VAL
2380
+ #undef ISOLATED_ATOM
2381
+ #undef NUM_ISO_Hk
2382
+ #undef IS_METAL_ATOM
2383
+
2384
+
2385
+ }
2386
+ #ifdef INCHI_MAIN
2387
+
2388
+ /**********************************************************************************/
2389
+ int INChIToInchi_Input( INCHI_FILE *inp_molfile, inchi_Input *orig_at_data, int bMergeAllInputStructures,
2390
+ int bDoNotAddH, INPUT_TYPE nInputType,
2391
+ char *pSdfLabel, char *pSdfValue, long *lSdfId, INCHI_MODE *pInpAtomFlags,
2392
+ int *err, char *pStrErr )
2393
+ {
2394
+ /* inp_ATOM *at = NULL; */
2395
+ int num_dimensions_new;
2396
+ int num_inp_bonds_new;
2397
+ int num_inp_atoms_new;
2398
+ int num_inp_0D_new;
2399
+ inchi_Atom *at_new = NULL;
2400
+ inchi_Atom *at_old = NULL;
2401
+ inchi_Stereo0D *stereo0D_new = NULL;
2402
+ inchi_Stereo0D *stereo0D_old = NULL;
2403
+ int nNumAtoms = 0, nNumStereo0D = 0;
2404
+ MOL_COORD *szCoordNew = NULL;
2405
+ MOL_COORD *szCoordOld = NULL;
2406
+ int i, j;
2407
+
2408
+ if ( pStrErr ) {
2409
+ pStrErr[0] = '\0';
2410
+ }
2411
+
2412
+ /*FreeOrigAtData( orig_at_data );*/
2413
+ if ( lSdfId )
2414
+ *lSdfId = 0;
2415
+ do {
2416
+
2417
+ at_old = orig_at_data? orig_at_data->atom : NULL; /* save pointer to the previous allocation */
2418
+ stereo0D_old = orig_at_data? orig_at_data->stereo0D : NULL;
2419
+ szCoordOld = NULL;
2420
+ num_inp_atoms_new =
2421
+ INChIToInchi_Atom( inp_molfile, orig_at_data? &stereo0D_new:NULL, &num_inp_0D_new,
2422
+ bDoNotAddH, nInputType, orig_at_data? &at_new:NULL, MAX_ATOMS,
2423
+ &num_dimensions_new, &num_inp_bonds_new,
2424
+ pSdfLabel, pSdfValue, lSdfId, pInpAtomFlags, err, pStrErr );
2425
+ if ( num_inp_atoms_new <= 0 && !*err ) {
2426
+ MOLFILE_ERR_SET (*err, 0, "Empty structure");
2427
+ *err = 98;
2428
+ } else
2429
+ if ( orig_at_data && !num_inp_atoms_new && 10 < *err && *err < 20 && orig_at_data->num_atoms > 0 && bMergeAllInputStructures ) {
2430
+ *err = 0; /* end of file */
2431
+ break;
2432
+ } else
2433
+ if ( num_inp_atoms_new > 0 && orig_at_data ) {
2434
+ /* merge pOrigDataTmp + orig_at_data => pOrigDataTmp; */
2435
+ nNumAtoms = num_inp_atoms_new + orig_at_data->num_atoms;
2436
+ nNumStereo0D = num_inp_0D_new + orig_at_data->num_stereo0D;
2437
+ if ( nNumAtoms >= MAX_ATOMS ) {
2438
+ MOLFILE_ERR_SET (*err, 0, "Too many atoms");
2439
+ *err = 70;
2440
+ orig_at_data->num_atoms = -1;
2441
+ } else
2442
+ if ( !at_old ) {
2443
+ /* the first structure */
2444
+ orig_at_data->atom = at_new; at_new = NULL;
2445
+ orig_at_data->num_atoms = num_inp_atoms_new; num_inp_atoms_new = 0;
2446
+ orig_at_data->stereo0D = stereo0D_new; stereo0D_new = NULL;
2447
+ orig_at_data->num_stereo0D = num_inp_0D_new; num_inp_0D_new = 0;
2448
+ } else
2449
+ if ( orig_at_data->atom = CreateInchi_Atom( nNumAtoms ) ) {
2450
+ /* switch at_new <--> orig_at_data->at; */
2451
+ if ( orig_at_data->num_atoms ) {
2452
+ memcpy( orig_at_data->atom, at_old, orig_at_data->num_atoms * sizeof(orig_at_data->atom[0]) );
2453
+ /* adjust numbering in the newly read structure */
2454
+ for ( i = 0; i < num_inp_atoms_new; i ++ ) {
2455
+ for ( j = 0; j < at_new[i].num_bonds; j ++ ) {
2456
+ at_new[i].neighbor[j] += orig_at_data->num_atoms;
2457
+ }
2458
+ }
2459
+ }
2460
+ FreeInchi_Atom( &at_old );
2461
+ /* copy newly read structure */
2462
+ memcpy( orig_at_data->atom + orig_at_data->num_atoms,
2463
+ at_new,
2464
+ num_inp_atoms_new * sizeof(orig_at_data->atom[0]) );
2465
+ /* cpy newly read 0D stereo */
2466
+ if ( num_inp_0D_new > 0 && stereo0D_new ) {
2467
+ if ( orig_at_data->stereo0D = CreateInchi_Stereo0D( nNumStereo0D ) ) {
2468
+ memcpy( orig_at_data->stereo0D, stereo0D_old, orig_at_data->num_stereo0D * sizeof(orig_at_data->stereo0D[0]) );
2469
+ /* adjust numbering in the newly read structure */
2470
+ for ( i = 0; i < num_inp_0D_new; i ++ ) {
2471
+ if ( stereo0D_new[i].central_atom >= 0 ) {
2472
+ stereo0D_new[i].central_atom += orig_at_data->num_atoms;
2473
+ }
2474
+ for ( j = 0; j < 4; j ++ ) {
2475
+ stereo0D_new[i].neighbor[j] += orig_at_data->num_atoms;
2476
+ }
2477
+ }
2478
+ FreeInchi_Stereo0D( &stereo0D_old );
2479
+ memcpy( orig_at_data->stereo0D+orig_at_data->num_stereo0D,
2480
+ stereo0D_new,
2481
+ num_inp_0D_new * sizeof(orig_at_data->stereo0D[0]) );
2482
+ } else {
2483
+ num_inp_0D_new = 0;
2484
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
2485
+ *err = -1;
2486
+ }
2487
+ } else {
2488
+ num_inp_0D_new = 0;
2489
+ }
2490
+ /* update lengths */
2491
+ orig_at_data->num_atoms += num_inp_atoms_new;
2492
+ orig_at_data->num_stereo0D += num_inp_0D_new;
2493
+ } else {
2494
+ MOLFILE_ERR_SET (*err, 0, "Out of RAM");
2495
+ *err = -1;
2496
+ }
2497
+ } else
2498
+ if ( num_inp_atoms_new > 0 ) {
2499
+ nNumAtoms += num_inp_atoms_new;
2500
+ }
2501
+ FreeInchi_Atom( &at_new );
2502
+ num_inp_atoms_new = 0;
2503
+ FreeInchi_Stereo0D( &stereo0D_new );
2504
+ num_inp_0D_new = 0;
2505
+
2506
+ } while ( !*err && bMergeAllInputStructures );
2507
+ /*
2508
+ if ( !*err ) {
2509
+ orig_at_data->num_components =
2510
+ MarkDisconnectedComponents( orig_at_data );
2511
+ if ( orig_at_data->num_components == 0 ) {
2512
+ MOLFILE_ERR_SET (*err, 0, "No components found");
2513
+ *err = 99;
2514
+ }
2515
+ if ( orig_at_data->num_components < 0 ) {
2516
+ MOLFILE_ERR_SET (*err, 0, "Too many components");
2517
+ *err = 99;
2518
+ }
2519
+ }
2520
+ */
2521
+ if ( szCoordNew ) {
2522
+ inchi_free( szCoordNew );
2523
+ }
2524
+ if ( at_new ) {
2525
+ inchi_free( at_new );
2526
+ }
2527
+ /*
2528
+ if ( !*err ) {
2529
+ if ( ReconcileAllCmlBondParities( orig_at_data->atom, orig_at_data->num_atoms ) ) {
2530
+ MOLFILE_ERR_SET (*err, 0, "Cannot reconcile stereobond parities");
2531
+ if (!orig_at_data->num_atoms) {
2532
+ *err = 1;
2533
+ }
2534
+ }
2535
+ }
2536
+ */
2537
+ if ( *err ) {
2538
+ FreeInchi_Input( orig_at_data );
2539
+ }
2540
+ if ( *err && !(10 < *err && *err < 20) && pStrErr && !pStrErr[0] ) {
2541
+ MOLFILE_ERR_SET (*err, 0, "Unknown error"); /* <BRKPT> */
2542
+ }
2543
+ return orig_at_data? orig_at_data->num_atoms : nNumAtoms;
2544
+ }
2545
+
2546
+ #endif
2547
+
2548
+ #ifndef INCHI_MAIN
2549
+ #undef AB_MAX_WELL_DEFINED_PARITY
2550
+ #undef AB_MIN_WELL_DEFINED_PARITY
2551
+ #include "extr_ct.h"
2552
+ /****************************************************************************************/
2553
+ int Extract0DParities( inp_ATOM *at, int nNumAtoms, inchi_Stereo0D *stereo0D,
2554
+ int num_stereo0D, char *pStrErr, int *err )
2555
+ {
2556
+ if ( stereo0D && num_stereo0D > 0 ) {
2557
+ int i0D, a2, k, k_prev, type, j, j1, j2, len, parity, parityNM;
2558
+ int sb_ord_from_i1, sb_ord_from_i2, sn_ord_from_i1, sn_ord_from_i2;
2559
+ AT_NUMB i1n, i2n, i1, i2;
2560
+ for ( i0D = 0; i0D < num_stereo0D; i0D ++ ) {
2561
+ parity = (stereo0D[i0D].parity & SB_PARITY_MASK);
2562
+ parityNM = (stereo0D[i0D].parity & SB_PARITY_FLAG) >> SB_PARITY_SHFT;
2563
+ if ( parity == INCHI_PARITY_NONE ||
2564
+ parity != INCHI_PARITY_ODD && parity != INCHI_PARITY_EVEN &&
2565
+ parity != INCHI_PARITY_UNKNOWN && parity != INCHI_PARITY_UNDEFINED ) {
2566
+ char szTemp[16];
2567
+ sprintf( szTemp, "#%d", i0D+1 );
2568
+ MOLFILE_ERR_SET (*err, 0, "Wrong 0D stereo descriptor(s):");
2569
+ MOLFILE_ERR_SET (*err, 0, szTemp);
2570
+ continue; /* warning */
2571
+ }
2572
+ type = stereo0D[i0D].type;
2573
+ a2 = stereo0D[i0D].central_atom; /* central atom or -1 */
2574
+ j = -1;
2575
+ len = 0;
2576
+ sb_ord_from_i1 = sb_ord_from_i2 = sn_ord_from_i1 = sn_ord_from_i2 = -1;
2577
+ i1n = i2n = i1 = i2 = MAX_ATOMS+1;
2578
+
2579
+ if ( (type == INCHI_StereoType_Tetrahedral ||
2580
+ type == INCHI_StereoType_Allene ) &&
2581
+ 0 <= a2 && a2 < nNumAtoms ||
2582
+ type == INCHI_StereoType_DoubleBond &&
2583
+ a2 == NO_ATOM) {
2584
+ /* test the quadruplet */
2585
+ for ( j = 0, k_prev = -1; j < 4; j ++, k_prev = k ) {
2586
+ k = stereo0D[i0D].neighbor[j];
2587
+ if ( k < 0 || k >= nNumAtoms || k_prev == k )
2588
+ break;
2589
+ /* tetrahedral atom connectivity test */
2590
+ if ( type == INCHI_StereoType_Tetrahedral &&
2591
+ k != a2 &&
2592
+ !is_in_the_list( at[a2].neighbor, (AT_NUMB)k, at[a2].valence) ) {
2593
+ break;
2594
+ }
2595
+ /* Double bond, Cumulene and allene are tested in the next if() */
2596
+ }
2597
+ }
2598
+ /* find in the adjacency lists the double bond neighbor that leads to the opposite atom */
2599
+ if ( j == 4 && (type == INCHI_StereoType_Allene ||
2600
+ type == INCHI_StereoType_DoubleBond) ) {
2601
+ AT_NUMB *p1 = NULL, *p2 = NULL, *q1 = NULL, *q2 = NULL;
2602
+ i1n = (AT_NUMB)stereo0D[i0D].neighbor[0];
2603
+ i1 = (AT_NUMB)stereo0D[i0D].neighbor[1];
2604
+ i2 = (AT_NUMB)stereo0D[i0D].neighbor[2];
2605
+ i2n = (AT_NUMB)stereo0D[i0D].neighbor[3];
2606
+ /* find q1 and q2 */
2607
+ if ( !(q1 = is_in_the_list( at[i1].neighbor, i1n, at[i1].valence)) ||
2608
+ !(q2 = is_in_the_list( at[i2].neighbor, i2n, at[i2].valence)) ) {
2609
+ j = -2; /* error flag */
2610
+ } else
2611
+ /* allene or cumulene; follow double bonds from i1 to i2 */
2612
+ if ( !(p1 = is_in_the_list( at[i1].neighbor, i2, at[i1].valence)) ) {
2613
+ /* at[i1] and at[i2] are not connected: can be only allene or cumulene */
2614
+ AT_NUMB prev, cur, next;
2615
+ int num_dbond, i, next_ord, half_len;
2616
+
2617
+ cur = next = i1;
2618
+ len = half_len = 0;
2619
+ while ( len < 20 ) { /* arbitrary very high upper limit to prevent infinite loop */
2620
+ prev = cur;
2621
+ cur = next;
2622
+ for ( i = 0, num_dbond = 0; i < at[cur].valence; i ++ ) {
2623
+ /* follow double bond path && avoid going back */
2624
+ if ( at[cur].bond_type[i] == BOND_TYPE_DOUBLE &&
2625
+ prev != at[cur].neighbor[i] ) {
2626
+ next = at[cur].neighbor[i];
2627
+ next_ord = i;
2628
+ num_dbond ++;
2629
+ }
2630
+ }
2631
+ if ( num_dbond == 1 && next != i1 ) {
2632
+ len ++;
2633
+ if ( len == 1 ) {
2634
+ sb_ord_from_i1 = next_ord;
2635
+ }
2636
+ if ( type == INCHI_StereoType_Allene && next == (AT_NUMB)a2 ) {
2637
+ half_len = len;
2638
+ }
2639
+ } else {
2640
+ break;
2641
+ }
2642
+ }
2643
+ if ( cur == i2 && prev != cur && 0 == num_dbond && len > 1 &&
2644
+ (p2 = is_in_the_list( at[i2].neighbor, prev, at[i2].valence)) &&
2645
+ (type != INCHI_StereoType_Allene || len == 2*half_len )) {
2646
+ sb_ord_from_i2 = p2 - at[i2].neighbor;
2647
+ sn_ord_from_i1 = q1 - at[i1].neighbor;
2648
+ sn_ord_from_i2 = q2 - at[i2].neighbor;
2649
+ } else {
2650
+ j = -5; /* error flag */
2651
+ }
2652
+ } else
2653
+ /* allene must have been already processed, otherwise error */
2654
+ if ( type == INCHI_StereoType_Allene ) {
2655
+ /* error: atoms #1 and #2 of allene are connected */
2656
+ j = -3; /* error flag */
2657
+ } else
2658
+ /* double bond only; the bond type is not checked because at the end
2659
+ of the normalization it may happen to be alternating */
2660
+ if ( type == INCHI_StereoType_DoubleBond &&
2661
+ (p2 = is_in_the_list( at[i2].neighbor, i1, at[i2].valence) ) ) {
2662
+ sb_ord_from_i1 = p1 - at[i1].neighbor;
2663
+ sb_ord_from_i2 = p2 - at[i2].neighbor;
2664
+ sn_ord_from_i1 = q1 - at[i1].neighbor;
2665
+ sn_ord_from_i2 = q2 - at[i2].neighbor;
2666
+ } else {
2667
+ j = -4; /* error flag */
2668
+ }
2669
+ }
2670
+ if ( j != 4 ) {
2671
+ char szTemp[16];
2672
+ sprintf( szTemp, "#%d", i0D+1 );
2673
+ MOLFILE_ERR_SET (*err, 0, "Wrong 0D stereo descriptor(s):");
2674
+ MOLFILE_ERR_SET (*err, 0, szTemp);
2675
+ continue; /* error */
2676
+ }
2677
+
2678
+ switch ( type ) {
2679
+ case INCHI_StereoType_None:
2680
+ continue;
2681
+ case INCHI_StereoType_DoubleBond:
2682
+ case INCHI_StereoType_Allene:
2683
+ for ( j1 = 0; j1 < MAX_NUM_STEREO_BONDS && at[i1].sb_parity[j1]; j1 ++ )
2684
+ ;
2685
+ for ( j2 = 0; j2 < MAX_NUM_STEREO_BONDS && at[i2].sb_parity[j2]; j2 ++ )
2686
+ ;
2687
+ if ( j1 < MAX_NUM_STEREO_BONDS && j2 < MAX_NUM_STEREO_BONDS &&
2688
+ sb_ord_from_i1 >= 0 && sb_ord_from_i2 >= 0 &&
2689
+ sn_ord_from_i1 >= 0 && sn_ord_from_i2 >= 0) {
2690
+
2691
+ switch( parity ) {
2692
+ case INCHI_PARITY_ODD:
2693
+ at[i1].sb_parity[j1] = AB_PARITY_ODD;
2694
+ at[i2].sb_parity[j2] = AB_PARITY_EVEN;
2695
+ break;
2696
+ case INCHI_PARITY_EVEN:
2697
+ at[i1].sb_parity[j1] = AB_PARITY_ODD;
2698
+ at[i2].sb_parity[j2] = AB_PARITY_ODD;
2699
+ break;
2700
+ case INCHI_PARITY_UNKNOWN:
2701
+ at[i1].sb_parity[j1] = AB_PARITY_UNKN;
2702
+ at[i2].sb_parity[j2] = AB_PARITY_UNKN;
2703
+ break;
2704
+ case INCHI_PARITY_UNDEFINED:
2705
+ at[i1].sb_parity[j1] = AB_PARITY_UNDF;
2706
+ at[i2].sb_parity[j2] = AB_PARITY_UNDF;
2707
+ break;
2708
+ default:
2709
+ at[i1].sb_parity[j1] = AB_PARITY_NONE;
2710
+ at[i2].sb_parity[j2] = AB_PARITY_NONE;
2711
+ }
2712
+
2713
+ switch( parityNM ) {
2714
+ case INCHI_PARITY_ODD:
2715
+ at[i1].sb_parity[j1] |= AB_PARITY_ODD << SB_PARITY_SHFT;
2716
+ at[i2].sb_parity[j2] |= AB_PARITY_EVEN << SB_PARITY_SHFT;
2717
+ break;
2718
+ case INCHI_PARITY_EVEN:
2719
+ at[i1].sb_parity[j1] |= AB_PARITY_ODD << SB_PARITY_SHFT;
2720
+ at[i2].sb_parity[j2] |= AB_PARITY_ODD << SB_PARITY_SHFT;
2721
+ break;
2722
+ case INCHI_PARITY_UNKNOWN:
2723
+ at[i1].sb_parity[j1] |= AB_PARITY_UNKN << SB_PARITY_SHFT;
2724
+ at[i2].sb_parity[j2] |= AB_PARITY_UNKN << SB_PARITY_SHFT;
2725
+ break;
2726
+ case INCHI_PARITY_UNDEFINED:
2727
+ at[i1].sb_parity[j1] |= AB_PARITY_UNDF << SB_PARITY_SHFT;
2728
+ at[i2].sb_parity[j2] |= AB_PARITY_UNDF << SB_PARITY_SHFT;
2729
+ break;
2730
+ default:
2731
+ break;
2732
+ }
2733
+
2734
+ at[i1].sb_ord[j1] = sb_ord_from_i1;
2735
+ at[i1].sn_ord[j1] = sn_ord_from_i1;
2736
+ at[i1].sn_orig_at_num[j1] = at[i1n].orig_at_number;
2737
+
2738
+ at[i2].sb_ord[j2] = sb_ord_from_i2;
2739
+ at[i2].sn_ord[j2] = sn_ord_from_i2;
2740
+ at[i2].sn_orig_at_num[j2] = at[i2n].orig_at_number;
2741
+ }
2742
+ break;
2743
+ case INCHI_StereoType_Tetrahedral:
2744
+ switch( parity ) {
2745
+ case INCHI_PARITY_ODD:
2746
+ at[a2].p_parity = AB_PARITY_ODD;
2747
+ break;
2748
+ case INCHI_PARITY_EVEN:
2749
+ at[a2].p_parity = AB_PARITY_EVEN;
2750
+ break;
2751
+ case INCHI_PARITY_UNKNOWN:
2752
+ at[a2].p_parity = AB_PARITY_UNKN;
2753
+ break;
2754
+ case INCHI_PARITY_UNDEFINED:
2755
+ at[a2].p_parity = AB_PARITY_UNDF;
2756
+ break;
2757
+ default:
2758
+ continue;
2759
+ }
2760
+ for ( j = 0; j < 4; j ++ ) {
2761
+ k = stereo0D[i0D].neighbor[j];
2762
+ at[a2].p_orig_at_num[j] = at[k].orig_at_number;
2763
+ }
2764
+ break;
2765
+ default:
2766
+ break;
2767
+ }
2768
+ }
2769
+
2770
+ #ifdef INCHI_LIBRARY
2771
+
2772
+ if ( k = ReconcileAllCmlBondParities( at, nNumAtoms, 0 ) ) {
2773
+ char szErrCode[16];
2774
+ sprintf( szErrCode, "%d", k);
2775
+ AddMOLfileError( pStrErr, "0D Parities Reconciliation failed:" );
2776
+ AddMOLfileError( pStrErr, szErrCode );
2777
+ }
2778
+
2779
+ #endif
2780
+
2781
+ }
2782
+ return 0;
2783
+ }
2784
+
2785
+ #endif
2786
+