rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,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
+