rino 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/aux2atom.h
ADDED
@@ -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
|
+
|