Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <limits.h>
8 : : #include <math.h>
9 : : #include <float.h>
10 : : #include <string.h>
11 : : #include <ctype.h>
12 : :
13 : : #include "mode.h"
14 : :
15 : : #include "ichierr.h"
16 : : #include "extr_ct.h"
17 : : #include "ichi_io.h"
18 : :
19 : : #include "inchi_api.h"
20 : : #include "readinch.h"
21 : :
22 : : #include "bcf_s.h"
23 : :
24 : : #define NO_ATOM (-1) /* non-existent (central) atom */
25 : :
26 : :
27 : : #ifndef AB_MAX_WELL_DEFINED_PARITY
28 : : #define AB_MAX_WELL_DEFINED_PARITY inchi_max(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* 1, 2 => well defined parities, uncluding 'unknown' */
29 : : #endif
30 : :
31 : : #ifndef AB_MIN_WELL_DEFINED_PARITY
32 : : #define AB_MIN_WELL_DEFINED_PARITY inchi_min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) */
33 : : #endif
34 : :
35 : :
36 : : #if ( defined(TARGET_API_LIB) || defined(TARGET_EXE_USING_API) )
37 : :
38 : : #ifndef AB_PARITY_UNKN
39 : : #define AB_PARITY_UNKN 3 /* 3 => user marked as unknown parity */
40 : : #endif
41 : : #ifndef AB_PARITY_UNDF
42 : : #define AB_PARITY_UNDF 4 /* 4 => parity cannot be defined because of symmetry or not well defined geometry */
43 : : #endif
44 : :
45 : : #define ATOM_PARITY_WELL_DEF(X) (AB_MIN_WELL_DEFINED_PARITY <= (X) && (X) <= AB_MAX_WELL_DEFINED_PARITY)
46 : :
47 : : #define SB_PARITY_FLAG 0x38 /* disconnected structure has undef. parity */
48 : :
49 : : #define SB_PARITY_SHFT 3
50 : :
51 : : #define SB_PARITY_MASK 0x07
52 : :
53 : : #define SB_PARITY_1(X) (X & SB_PARITY_MASK) /* refers to connected structure */
54 : :
55 : : #define SB_PARITY_2(X) (((X) >> SB_PARITY_SHFT) & SB_PARITY_MASK) /* refers to connected structure */
56 : :
57 : :
58 : :
59 : : #endif /* #if ( defined(TARGET_API_LIB) || defined(TARGET_EXE_USING_API) ) */
60 : :
61 : :
62 : : #if ( defined( TARGET_LIB_FOR_WINCHI ) || defined(TARGET_EXE_STANDALONE) )
63 : : int Extract0DParities( inp_ATOM *at,
64 : : int nNumAtoms,
65 : : inchi_Stereo0D *stereo0D,
66 : : int num_stereo0D,
67 : : char *pStrErr,
68 : : int *err,
69 : : int vABParityUnknown );
70 : : #endif
71 : :
72 : :
73 : : void find_and_interpret_structure_header( char *szLine,
74 : : char *pSdfLabel,
75 : : char *pSdfValue,
76 : : unsigned long *Id,
77 : : int hlen,
78 : : ReadINCHI_CtlData *ir );
79 : :
80 : :
81 : :
82 : : /****************************************************************************/
83 : 0 : inchi_Stereo0D * CreateInchi_Stereo0D( int num_stereo0D )
84 : : {
85 : 0 : return (inchi_Stereo0D*) inchi_calloc( num_stereo0D, sizeof( inchi_Stereo0D ) );
86 : : }
87 : :
88 : :
89 : : /****************************************************************************/
90 : 0 : void FreeInchi_Stereo0D( inchi_Stereo0D **stereo0D )
91 : : {
92 [ # # # # ]: 0 : if (stereo0D && *stereo0D)
93 : : {
94 [ # # ]: 0 : inchi_free( *stereo0D );
95 : 0 : *stereo0D = NULL;
96 : : }
97 : 0 : }
98 : :
99 : :
100 : : /****************************************************************************/
101 : 0 : int Extract0DParities( inp_ATOM *at,
102 : : int nNumAtoms,
103 : : inchi_Stereo0D *stereo0D,
104 : : int num_stereo0D,
105 : : char *pStrErr,
106 : : int *err,
107 : : int vABParityUnknown )
108 : : {
109 : :
110 : : /*
111 : : vABParityUnknown holds actual value of an internal constant signifying
112 : : unknown parity: either the same as for undefined parity (default==standard)
113 : : or a specific one (non-std; requested by SLUUD switch).
114 : : */
115 [ # # # # ]: 0 : if (stereo0D && num_stereo0D > 0)
116 : : {
117 : : int i0D, a2, k, k_prev, type, j, j1, j2, len, parity, parityNM;
118 : : int sb_ord_from_i1, sb_ord_from_i2, sn_ord_from_i1, sn_ord_from_i2;
119 : : AT_NUMB i1n, i2n, i1, i2;
120 : :
121 [ # # ]: 0 : for (i0D = 0; i0D < num_stereo0D; i0D++)
122 : : {
123 : 0 : parity = ( stereo0D[i0D].parity & SB_PARITY_MASK );
124 : 0 : parityNM = ( stereo0D[i0D].parity & SB_PARITY_FLAG ) >> SB_PARITY_SHFT;
125 : :
126 [ # # # # ]: 0 : if (parity == INCHI_PARITY_NONE ||
127 [ # # # # ]: 0 : (parity != INCHI_PARITY_ODD && parity != INCHI_PARITY_EVEN &&
128 [ # # ]: 0 : parity != INCHI_PARITY_UNKNOWN && parity != INCHI_PARITY_UNDEFINED)) /* djb-rwth: addressing LLVM warning */
129 : 0 : {
130 : : char szTemp[16];
131 : 0 : sprintf(szTemp, "#%d", i0D + 1);
132 : 0 : TREAT_ERR( *err, 0, "Wrong 0D stereo descriptor(s):" );
133 : 0 : TREAT_ERR( *err, 0, szTemp );
134 : 0 : continue; /* warning */
135 : : }
136 : :
137 : 0 : type = stereo0D[i0D].type;
138 : 0 : a2 = stereo0D[i0D].central_atom; /* central atom or -1 */
139 : 0 : j = -1;
140 : : /* djb-rwth: removing redundant code */
141 : 0 : sb_ord_from_i1 = sb_ord_from_i2 = sn_ord_from_i1 = sn_ord_from_i2 = -1;
142 : 0 : i1n = i2n = i1 = i2 = MAX_ATOMS + 1;
143 : :
144 [ # # # # ]: 0 : if (( type == INCHI_StereoType_Tetrahedral ||
145 [ # # ]: 0 : ((type == INCHI_StereoType_Allene ) &&
146 [ # # # # ]: 0 : 0 <= a2 && a2 < nNumAtoms)) ||
147 [ # # ]: 0 : (type == INCHI_StereoType_DoubleBond &&
148 : : a2 == NO_ATOM)) /* djb-rwth: addressing LLVM warning */
149 : : {
150 : : /* test the quadruplet */
151 [ # # ]: 0 : for (j = 0, k_prev = -1; j < 4; j++, k_prev = k)
152 : : {
153 : 0 : k = stereo0D[i0D].neighbor[j];
154 [ # # # # : 0 : if (k < 0 || k >= nNumAtoms || k_prev == k)
# # ]
155 : : break;
156 : : /* tetrahedral atom connectivity test */
157 [ # # # # ]: 0 : if (type == INCHI_StereoType_Tetrahedral &&
158 [ # # ]: 0 : k != a2 &&
159 : 0 : !is_in_the_list( at[a2].neighbor, (AT_NUMB) k, at[a2].valence ))
160 : : {
161 : 0 : break;
162 : : }
163 : : /* Double bond, Cumulene and allene are tested in the next if() */
164 : : }
165 : : }
166 : :
167 : : /* Find in the adjacency lists the double bond neighbor that leads to the opposite atom */
168 [ # # # # : 0 : if (j == 4 && ( type == INCHI_StereoType_Allene ||
# # ]
169 : : type == INCHI_StereoType_DoubleBond ))
170 : : {
171 : 0 : AT_NUMB *p1 = NULL, *p2 = NULL, *q1 = NULL, *q2 = NULL;
172 : 0 : i1n = (AT_NUMB) stereo0D[i0D].neighbor[0];
173 : 0 : i1 = (AT_NUMB) stereo0D[i0D].neighbor[1];
174 : 0 : i2 = (AT_NUMB) stereo0D[i0D].neighbor[2];
175 : 0 : i2n = (AT_NUMB) stereo0D[i0D].neighbor[3];
176 : :
177 : : /* find q1 and q2 */
178 [ # # # # ]: 0 : if (!( q1 = is_in_the_list( at[i1].neighbor, i1n, at[i1].valence ) ) ||
179 : 0 : !( q2 = is_in_the_list( at[i2].neighbor, i2n, at[i2].valence ) ))
180 : : {
181 : 0 : j = -2; /* error flag */
182 : : }
183 : : else
184 : : {
185 : : /* allene or cumulene; follow double bonds from i1 to i2 */
186 [ # # ]: 0 : if (!( p1 = is_in_the_list( at[i1].neighbor, i2, at[i1].valence ) ))
187 : : {
188 : : /* at[i1] and at[i2] are not connected: can be only allene or cumulene */
189 : :
190 : : AT_NUMB prev, cur, next;
191 : : int num_dbond, i, next_ord, half_len;
192 : :
193 : 0 : cur = next = i1;
194 : 0 : len = half_len = 0;
195 [ # # ]: 0 : while (len < 20)
196 : : {
197 : : /* arbitrary very high upper limit to prevent infinite loop */
198 : 0 : prev = cur;
199 : 0 : cur = next;
200 : :
201 [ # # ]: 0 : for (i = 0, num_dbond = 0; i < at[cur].valence; i++)
202 : : {
203 : : /* follow double bond path && avoid going back */
204 [ # # ]: 0 : if (at[cur].bond_type[i] == BOND_TYPE_DOUBLE &&
205 [ # # ]: 0 : prev != at[cur].neighbor[i])
206 : : {
207 : 0 : next = at[cur].neighbor[i];
208 : 0 : next_ord = i;
209 : 0 : num_dbond++;
210 : : }
211 : : }
212 : :
213 [ # # # # ]: 0 : if (num_dbond == 1 && next != i1)
214 : : {
215 : 0 : len++;
216 [ # # ]: 0 : if (len == 1)
217 : 0 : sb_ord_from_i1 = next_ord;
218 : :
219 [ # # # # ]: 0 : if (type == INCHI_StereoType_Allene && next == (AT_NUMB) a2)
220 : 0 : half_len = len;
221 : : }
222 : : else
223 : : break;
224 : : }
225 : :
226 [ # # # # : 0 : if (cur == i2 && prev != cur && 0 == num_dbond && len > 1 &&
# # # # #
# ]
227 [ # # ]: 0 : ( p2 = is_in_the_list( at[i2].neighbor, prev, at[i2].valence ) ) &&
228 [ # # ]: 0 : ( type != INCHI_StereoType_Allene || len == 2 * half_len ))
229 : : {
230 : 0 : sb_ord_from_i2 = p2 - at[i2].neighbor;
231 : 0 : sn_ord_from_i1 = q1 - at[i1].neighbor;
232 : 0 : sn_ord_from_i2 = q2 - at[i2].neighbor;
233 : : }
234 : : else
235 : : {
236 : 0 : j = -5; /* error flag */
237 : : }
238 : : }
239 : : else
240 : : {
241 : : /* allene must have been already processed, otherwise error */
242 [ # # ]: 0 : if (type == INCHI_StereoType_Allene)
243 : : {
244 : : /* error: atoms #1 and #2 of allene are connected */
245 : 0 : j = -3; /* error flag */
246 : : }
247 : : else
248 : : {
249 : : /* double bond only; the bond type is not checked because at the end
250 : : of the normalization it may happen to be alternating */
251 [ # # # # ]: 0 : if (type == INCHI_StereoType_DoubleBond &&
252 : 0 : ( p2 = is_in_the_list( at[i2].neighbor, i1, at[i2].valence ) ))
253 : : {
254 : 0 : sb_ord_from_i1 = p1 - at[i1].neighbor;
255 : 0 : sb_ord_from_i2 = p2 - at[i2].neighbor;
256 : 0 : sn_ord_from_i1 = q1 - at[i1].neighbor;
257 : 0 : sn_ord_from_i2 = q2 - at[i2].neighbor;
258 : : }
259 : : else
260 : : {
261 : 0 : j = -4; /* error flag */
262 : : }
263 : : }
264 : : }
265 : : }
266 : : }
267 : :
268 [ # # ]: 0 : if (j != 4)
269 : 0 : {
270 : : char szTemp[16];
271 : 0 : sprintf(szTemp, "#%d", i0D + 1);
272 : 0 : TREAT_ERR( *err, 0, "Wrong 0D stereo descriptor(s):" );
273 : 0 : TREAT_ERR( *err, 0, szTemp );
274 : 0 : continue; /* error */
275 : : }
276 : :
277 [ # # # # ]: 0 : switch (type)
278 : : {
279 : 0 : case INCHI_StereoType_None:
280 : 0 : continue;
281 : 0 : case INCHI_StereoType_DoubleBond:
282 : : case INCHI_StereoType_Allene:
283 [ # # # # ]: 0 : for (j1 = 0; j1 < MAX_NUM_STEREO_BONDS && at[i1].sb_parity[j1]; j1++)
284 : : {
285 : : ;
286 : : }
287 [ # # # # ]: 0 : for (j2 = 0; j2 < MAX_NUM_STEREO_BONDS && at[i2].sb_parity[j2]; j2++)
288 : : {
289 : : ;
290 : : }
291 [ # # # # : 0 : if (j1 < MAX_NUM_STEREO_BONDS && j2 < MAX_NUM_STEREO_BONDS &&
# # ]
292 [ # # # # ]: 0 : sb_ord_from_i1 >= 0 && sb_ord_from_i2 >= 0 &&
293 [ # # ]: 0 : sn_ord_from_i1 >= 0 && sn_ord_from_i2 >= 0)
294 : : {
295 [ # # # # ]: 0 : switch (parity)
296 : : {
297 : 0 : case INCHI_PARITY_ODD:
298 : 0 : at[i1].sb_parity[j1] = AB_PARITY_ODD;
299 : 0 : at[i2].sb_parity[j2] = AB_PARITY_EVEN;
300 : 0 : break;
301 : 0 : case INCHI_PARITY_EVEN:
302 : 0 : at[i1].sb_parity[j1] = AB_PARITY_ODD;
303 : 0 : at[i2].sb_parity[j2] = AB_PARITY_ODD;
304 : 0 : break;
305 : 0 : case INCHI_PARITY_UNDEFINED:
306 : 0 : at[i1].sb_parity[j1] = AB_PARITY_UNDF;
307 : 0 : at[i2].sb_parity[j2] = AB_PARITY_UNDF;
308 : 0 : break;
309 : 0 : default:
310 [ # # ]: 0 : if (parity == INCHI_PARITY_UNKNOWN)
311 : : {
312 : 0 : at[i1].sb_parity[j1] = vABParityUnknown;
313 : 0 : at[i2].sb_parity[j2] = vABParityUnknown;
314 : : }
315 : : else
316 : : {
317 : 0 : at[i1].sb_parity[j1] = AB_PARITY_NONE;
318 : 0 : at[i2].sb_parity[j2] = AB_PARITY_NONE;
319 : : }
320 : 0 : break;
321 : : }
322 [ # # # # ]: 0 : switch (parityNM)
323 : : {
324 : 0 : case INCHI_PARITY_ODD:
325 : 0 : at[i1].sb_parity[j1] |= AB_PARITY_ODD << SB_PARITY_SHFT;
326 : 0 : at[i2].sb_parity[j2] |= AB_PARITY_EVEN << SB_PARITY_SHFT;
327 : 0 : break;
328 : 0 : case INCHI_PARITY_EVEN:
329 : 0 : at[i1].sb_parity[j1] |= AB_PARITY_ODD << SB_PARITY_SHFT;
330 : 0 : at[i2].sb_parity[j2] |= AB_PARITY_ODD << SB_PARITY_SHFT;
331 : 0 : break;
332 : 0 : case INCHI_PARITY_UNDEFINED:
333 : 0 : at[i1].sb_parity[j1] |= AB_PARITY_UNDF << SB_PARITY_SHFT;
334 : 0 : at[i2].sb_parity[j2] |= AB_PARITY_UNDF << SB_PARITY_SHFT;
335 : 0 : break;
336 : 0 : default:
337 [ # # ]: 0 : if (parityNM == INCHI_PARITY_UNKNOWN)
338 : : {
339 : 0 : at[i1].sb_parity[j1] |= vABParityUnknown << SB_PARITY_SHFT;
340 : 0 : at[i2].sb_parity[j2] |= vABParityUnknown << SB_PARITY_SHFT;
341 : : }
342 : 0 : break;
343 : : }
344 : 0 : at[i1].sb_ord[j1] = sb_ord_from_i1;
345 : 0 : at[i1].sn_ord[j1] = sn_ord_from_i1;
346 : 0 : at[i1].sn_orig_at_num[j1] = at[i1n].orig_at_number;
347 : :
348 : 0 : at[i2].sb_ord[j2] = sb_ord_from_i2;
349 : 0 : at[i2].sn_ord[j2] = sn_ord_from_i2;
350 : 0 : at[i2].sn_orig_at_num[j2] = at[i2n].orig_at_number;
351 : : }
352 : 0 : break;
353 : 0 : case INCHI_StereoType_Tetrahedral:
354 [ # # # # ]: 0 : switch (parity)
355 : : {
356 : 0 : case INCHI_PARITY_ODD:
357 : 0 : at[a2].p_parity = AB_PARITY_ODD;
358 : 0 : break;
359 : 0 : case INCHI_PARITY_EVEN:
360 : 0 : at[a2].p_parity = AB_PARITY_EVEN;
361 : 0 : break;
362 : 0 : case INCHI_PARITY_UNDEFINED:
363 : 0 : at[a2].p_parity = AB_PARITY_UNDF;
364 : 0 : break;
365 : 0 : default:
366 [ # # ]: 0 : if (parity == INCHI_PARITY_UNKNOWN)
367 : : {
368 : 0 : at[a2].p_parity = vABParityUnknown;
369 : 0 : break;
370 : : }
371 : : else
372 : : {
373 : 0 : continue;
374 : : }
375 : : }
376 [ # # ]: 0 : for (j = 0; j < 4; j++)
377 : : {
378 : 0 : k = stereo0D[i0D].neighbor[j];
379 : 0 : at[a2].p_orig_at_num[j] = at[k].orig_at_number;
380 : : }
381 : 0 : break;
382 : :
383 : 0 : default:
384 : 0 : break;
385 : : }
386 : : }
387 : : /* take care of Unknown stereobonds: */
388 : : /* copy their Unknown stereo descriptors to at->bond_stereo (2005-03-01) */
389 : : /* Note: to this stage, unk/undef set to what was requested */
390 : : /*( through vABParityUnknown ) (2009-12-12) */
391 : 0 : FixUnkn0DStereoBonds( at, nNumAtoms );
392 : : #ifdef TARGET_API_LIB
393 : :
394 [ # # ]: 0 : if ((k = ReconcileAllCmlBondParities( at, nNumAtoms, 0 ))) /* djb-rwth: addressing LLVM warning */
395 : : {
396 : : char szErrCode[16];
397 : 0 : sprintf( szErrCode, "%d", k );
398 : 0 : AddErrorMessage( pStrErr, "0D Parities Reconciliation failed:" );
399 : 0 : AddErrorMessage( pStrErr, szErrCode );
400 : : }
401 : :
402 : : #endif
403 : : }
404 : :
405 : 0 : return 0;
406 : : }
407 : :
408 : :
409 : : /****************************************************************************/
410 : 0 : char* FindToken( INCHI_IOSTREAM *inp_file,
411 : : int *bTooLongLine,
412 : : const char *sToken,
413 : : int lToken,
414 : : char *szLine,
415 : : int nLenLine,
416 : : char *p,
417 : : int *res )
418 : : {
419 : : char *q;
420 : : int res2;
421 : :
422 [ # # ]: 0 : while (!( q = strstr( p, sToken ) ))
423 : : {
424 [ # # # # ]: 0 : if (( q = strrchr( p, '/' ) ) && ( q + lToken > szLine + *res ))
425 : : {
426 : 0 : *res -= q - szLine; /* res = the length of the szLine to be left in */
427 : 0 : memmove(szLine, q, (long long)*res + 1); /* djb-rwth: cast operator added */
428 : : }
429 : : else
430 : : {
431 : 0 : *res = 0;
432 : : }
433 : :
434 : 0 : res2 = inchi_ios_getsTab1( szLine + *res, nLenLine - *res - 1,
435 : : inp_file, bTooLongLine );
436 : :
437 [ # # # # ]: 0 : if (!*bTooLongLine || 0 > res2)
438 : : {
439 : : /* the line is over or end of file */
440 : 0 : return NULL;
441 : : }
442 : : else
443 : : {
444 : 0 : *res += res2;
445 : 0 : p = szLine;
446 : : }
447 : : }
448 : :
449 : 0 : return q + lToken;
450 : : }
451 : :
452 : :
453 : : /****************************************************************************/
454 : 0 : char *LoadLine( INCHI_IOSTREAM *inp_file,
455 : : int *bTooLongLine,
456 : : int *bItemIsOver,
457 : : char **s,
458 : : char *szLine,
459 : : int nLenLine,
460 : : int nMinLen2Load,
461 : : char *p,
462 : : int *res )
463 : : {
464 : :
465 : 0 : int pos = p - szLine, res2;
466 : :
467 [ # # # # ]: 0 : if (!*bItemIsOver && nLenLine - ( *res - pos ) > nMinLen2Load)
468 : : {
469 : : /* load the next portion if possible */
470 : :
471 [ # # ]: 0 : if (pos)
472 : : {
473 : 0 : *res -= pos;
474 : 0 : memmove(szLine, p, (long long)*res + 1); /* djb-rwth: cast operator added */
475 : 0 : p = szLine;
476 [ # # ]: 0 : if (*s)
477 : : {
478 : 0 : *s -= pos;
479 : : }
480 : :
481 : : /* djb-rwth: removing redundant code */
482 : : }
483 : :
484 : 0 : res2 = inchi_ios_getsTab1( szLine + *res,
485 : 0 : nLenLine - *res - 1,
486 : : inp_file, bTooLongLine );
487 : :
488 [ # # ]: 0 : if (res2 > 0)
489 : : {
490 [ # # # # ]: 0 : *bItemIsOver = ( ( *s = strchr( p + *res, '/' ) ) || !*bTooLongLine );
491 : 0 : *res += res2;
492 : : }
493 : : else
494 : : {
495 : 0 : *bItemIsOver = 1;
496 : : }
497 : : }
498 : :
499 : 0 : return p;
500 : : }
501 : :
502 : :
503 : : /*****************************************************************************/
504 : : #define AT_BONDS_VAL(AT,I) AT[I].chem_bonds_valence
505 : : #define ISOLATED_ATOM 15
506 : : #define NUM_ISO_Hk(AT,I,K) AT[I].num_iso_H[K]
507 : : #define inchi_NUMH2(AT,N) NUMH(AT,N)
508 : : #define AT_NUM_BONDS(AT) (AT).valence
509 : : #define IS_METAL_ATOM(AT,I) is_el_a_metal( AT[I].el_number )
510 : :
511 : :
512 : : /****************************************************************************/
513 : : char szLine_i2i[INCHI_LINE_LEN]; /* djb-rwth: placed as a global variable to avoid function buffer issues */
514 : 0 : int InchiToInpAtom( INCHI_IOSTREAM *inp_file,
515 : : MOL_COORD **szCoord,
516 : : int bDoNotAddH,
517 : : int vABParityUnknown,
518 : : INPUT_TYPE nInputType,
519 : : inp_ATOM **at,
520 : : int max_num_at,
521 : : int *num_dimensions,
522 : : int *num_bonds,
523 : : char *pSdfLabel,
524 : : char *pSdfValue,
525 : : unsigned long *Id,
526 : : INCHI_MODE *pInpAtomFlags,
527 : : int *err,
528 : : char *pStrErr )
529 : : {
530 : 0 : int num_atoms = 0, bItemIsOver; /* djb-rwth: removing redundant variables */
531 : : int i, k, k2, res, bond_type, bond_stereo1, bond_stereo2, bond_char, neigh, bond_parity, bond_parityNM;
532 : : /* djb-rwth: removing redundant variables */
533 : : char *p, *q, *s, parity;
534 : 0 : int b2D = 0, b3D = 0, b23D, nNumBonds = 0, bNonZeroXYZ, bNonMetal;
535 : 0 : int len_stereo0D = 0, max_len_stereo0D = 0;
536 : 0 : inp_ATOM *atom = NULL;
537 : 0 : MOL_COORD *pszCoord = NULL;
538 : 0 : INCHI_MODE InpAtomFlags = 0; /* 0 or FLAG_INP_AT_NONCHIRAL or FLAG_INP_AT_CHIRAL */
539 : 0 : inchi_Stereo0D *atom_stereo0D = NULL;
540 : : static const char szIsoH[] = "hdt";
541 : : /* plain tags */
542 : : static const char sStructHdrPln[] = "Structure:";
543 : : static char sStructHdrPlnAuxStart[64] = ""; /*"$1.1Beta/";*/
544 : : static int lenStructHdrPlnAuxStart = 0;
545 : : static const char sStructHdrPlnRevAt[] = "/rA:";
546 : : static const char sStructHdrPlnRevBn[] = "/rB:";
547 : : static const char sStructHdrPlnRevXYZ[] = "/rC:";
548 : : const char *sToken;
549 : : int lToken, len, hlen;
550 : :
551 : : ReadINCHI_CtlData ir;
552 : :
553 [ # # ]: 0 : if (!lenStructHdrPlnAuxStart)
554 : : {
555 : 0 : lenStructHdrPlnAuxStart = sprintf(sStructHdrPlnAuxStart, "AuxInfo=");
556 : : }
557 : :
558 [ # # ]: 0 : if (at)
559 : : {
560 [ # # # # ]: 0 : if (*at && max_num_at)
561 : 0 : memset(*at, 0, max_num_at * sizeof(**at)); /* djb-rwth: memset_s C11/Annex K variant? */
562 [ # # # # ]: 0 : if (szCoord && *szCoord)
563 : : {
564 [ # # ]: 0 : inchi_free(*szCoord);
565 : 0 : *szCoord = NULL;
566 : : }
567 : : }
568 : : /* djb-rwth: removing redundant code */
569 : :
570 : 0 : ir.bHeaderRead = ir.bErrorMsg = ir.bRestoreInfo = 0;
571 : 0 : *num_dimensions = *num_bonds = 0;
572 : :
573 : :
574 [ # # ]: 0 : if (nInputType != INPUT_INCHI_PLAIN)
575 : : {
576 : 0 : return num_atoms;
577 : : }
578 : :
579 : :
580 : : /*
581 : : Extract reversibility info from plain text INChI format
582 : : */
583 : :
584 : 0 : ir.bHeaderRead = 0; /* djb-rwth: removing redundant code */
585 [ # # ]: 0 : while (0 < (res = inchi_ios_getsTab(szLine_i2i, sizeof(szLine_i2i) - 1, inp_file, &ir.bTooLongLine)))
586 : : {
587 : :
588 [ # # ]: 0 : if (!ir.bTooLongLine &&
589 [ # # ]: 0 : (hlen = sizeof(sStructHdrPln) - 1, !memcmp(szLine_i2i, sStructHdrPln, hlen)))
590 : :
591 : : {
592 : 0 : num_atoms = 0;
593 : 0 : find_and_interpret_structure_header(szLine_i2i, pSdfLabel, pSdfValue,
594 : : Id, hlen, &ir);
595 : : }
596 : :
597 [ # # ]: 0 : else if (!memcmp(szLine_i2i, sStructHdrPlnAuxStart, lenStructHdrPlnAuxStart))
598 : : {
599 : : /* Reject to deal with polymers for now */
600 [ # # ]: 0 : if (strstr(szLine_i2i, "/Z:"))
601 : : {
602 : 0 : *err = INCHI_INP_ERROR_ERR;
603 : 0 : num_atoms = INCHI_INP_ERROR_RET;
604 : 0 : TREAT_ERR(*err, 0, "Reading polymer AuxInfo is not supported yet");
605 : 0 : goto bypass_end_of_INChI_plain;
606 : : }
607 : :
608 : : /* Found the header of the AuxInfo, read AuxInfo head of the line */
609 [ # # ]: 0 : if (!ir.bHeaderRead)
610 : : {
611 : 0 : ir.ulongID = 0LU;
612 [ # # ]: 0 : if (Id)
613 : : {
614 : 0 : *Id = ir.ulongID;
615 : : }
616 [ # # ]: 0 : if (pSdfLabel)
617 : : {
618 : 0 : pSdfLabel[0] = '\0';
619 : : }
620 [ # # ]: 0 : if (pSdfValue)
621 : : {
622 : 0 : pSdfValue[0] = '\0';
623 : : }
624 : : }
625 : :
626 : 0 : ir.bHeaderRead = 0;
627 : :
628 : : /* Check for empty "AuxInfo=ver//" */
629 : 0 : p = strchr(szLine_i2i + lenStructHdrPlnAuxStart, '/');
630 : :
631 [ # # # # : 0 : if (p && p[1] == '/' && (!p[2] || '\n' == p[2]))
# # # # ]
632 : : {
633 : 0 : goto bypass_end_of_INChI_plain;
634 : : }
635 : :
636 : : /*
637 : : Search for atoms block (plain)
638 : : */
639 : :
640 : 0 : p = szLine_i2i;
641 : 0 : sToken = sStructHdrPlnRevAt;
642 : 0 : lToken = sizeof(sStructHdrPlnRevAt) - 1;
643 : :
644 : : /* Search for sToken in the line; load next segments of the line if sToken has not found */
645 : :
646 : 0 : p = FindToken(inp_file, &ir.bTooLongLine, sToken, lToken,
647 : : szLine_i2i, sizeof(szLine_i2i), p, &res);
648 : :
649 [ # # ]: 0 : if (!p)
650 : : {
651 : 0 : *err = INCHI_INP_ERROR_ERR;
652 : 0 : num_atoms = INCHI_INP_ERROR_RET;
653 : 0 : TREAT_ERR(*err, 0, "Missing atom data");
654 : 0 : goto bypass_end_of_INChI_plain;
655 : : }
656 : : else
657 : : {
658 : : /* atoms block started */
659 : 0 : i = 0;
660 : : /* djb-rwth: removing redundant code */
661 [ # # # # ]: 0 : bItemIsOver = (s = strchr(p, '/')) || !ir.bTooLongLine;
662 : : while (1)
663 : : {
664 : :
665 : 0 : p = LoadLine(inp_file, &ir.bTooLongLine, &bItemIsOver, &s,
666 : : szLine_i2i, sizeof(szLine_i2i), INCHI_LINE_ADD, p, &res);
667 : :
668 [ # # ]: 0 : if (!i)
669 : : {
670 : : /* allocate atom */
671 : 0 : num_atoms = strtol(p, &q, 10);
672 : :
673 [ # # # # : 0 : if (!num_atoms || !q || !*q)
# # ]
674 : : {
675 : 0 : num_atoms = 0; /* no atom data */
676 : 0 : goto bypass_end_of_INChI_plain;
677 : : }
678 : 0 : p = q;
679 : :
680 : : /* Molfile chirality flag */
681 [ # # # ]: 0 : switch (*p)
682 : : {
683 : 0 : case 'c':
684 : 0 : InpAtomFlags |= FLAG_INP_AT_CHIRAL;
685 : 0 : p++;
686 : 0 : break;
687 : 0 : case 'n':
688 : 0 : InpAtomFlags |= FLAG_INP_AT_NONCHIRAL;
689 : 0 : p++;
690 : 0 : break;
691 : : }
692 : :
693 [ # # # # ]: 0 : if (at && *at)
694 : : {
695 [ # # ]: 0 : if (num_atoms > max_num_at)
696 : : {
697 [ # # ]: 0 : inchi_free(*at);
698 : 0 : *at = NULL;
699 : : }
700 : : else
701 : : {
702 : 0 : memset(*at, 0, max_num_at * sizeof(**at)); /* djb-rwth: memset_s C11/Annex K variant? */
703 : 0 : atom = *at;
704 : : }
705 : : }
706 : :
707 [ # # # # ]: 0 : if (!at || !*at)
708 : : {
709 : :
710 : 0 : atom = CreateInpAtom(num_atoms + 1);
711 : :
712 [ # # ]: 0 : if (!atom)
713 : : {
714 : 0 : num_atoms = INCHI_INP_FATAL_RET; /* was -1; error */
715 : 0 : *err = INCHI_INP_FATAL_ERR;
716 : 0 : TREAT_ERR(*err, 0, "Out of RAM");
717 : 0 : goto bypass_end_of_INChI_plain;
718 : : }
719 : : }
720 : :
721 : : {
722 : 0 : max_len_stereo0D = num_atoms + 1;
723 : :
724 : 0 : atom_stereo0D = CreateInchi_Stereo0D(max_len_stereo0D);
725 : :
726 [ # # ]: 0 : if (!atom_stereo0D)
727 : : {
728 : 0 : num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
729 : 0 : *err = INCHI_INP_FATAL_ERR;
730 : 0 : TREAT_ERR(*err, 0, "Out of RAM");
731 : 0 : goto bypass_end_of_INChI_plain;
732 : : }
733 : : }
734 : : }
735 : :
736 : : /* element, first char */
737 [ # # # # : 0 : if (!isalpha(UCINT * p) || !isupper(UCINT * p) || i >= num_atoms)
# # ]
738 : : {
739 : : break; /* end of atoms block */
740 : : }
741 : :
742 : 0 : atom[i].elname[0] = *p++;
743 : :
744 : : /* element, second char */
745 [ # # # # ]: 0 : if (isalpha(UCINT * p) && islower(UCINT * p))
746 : : {
747 : 0 : atom[i].elname[1] = *p++;
748 : : }
749 : :
750 : 0 : atom[i].el_number = get_periodic_table_number(atom[i].elname);
751 : :
752 : : /* bonds' valence + number of non-isotopic H */
753 [ # # ]: 0 : if (isdigit(UCINT * p))
754 : : {
755 : 0 : AT_BONDS_VAL(atom, i) = (char)strtol(p, &q, 10);
756 [ # # ]: 0 : if (!AT_BONDS_VAL(atom, i))
757 : 0 : AT_BONDS_VAL(atom, i) = ISOLATED_ATOM; /* same convention as in MOLfile, found zero bonds valence */
758 : 0 : p = q;
759 : : }
760 : :
761 : : /* charge */
762 [ # # # # ]: 0 : atom[i].charge = (*p == '+') ? 1 : (*p == '-') ? -1 : 0;
763 [ # # ]: 0 : if (atom[i].charge)
764 : : {
765 : 0 : p++;
766 [ # # ]: 0 : if (isdigit(UCINT * p))
767 : : {
768 : 0 : atom[i].charge *= (S_CHAR)(strtol(p, &q, 10) & CHAR_MASK);
769 : 0 : p = q;
770 : : }
771 : : }
772 : :
773 : : /* radical */
774 [ # # ]: 0 : if (*p == '.')
775 : : {
776 : 0 : p++;
777 [ # # ]: 0 : if (isdigit(UCINT * p))
778 : : {
779 : 0 : atom[i].radical = (S_CHAR)strtol(p, &q, 10);
780 : 0 : p = q;
781 : : }
782 : : }
783 : :
784 : : /* isotopic mass */
785 [ # # ]: 0 : if (*p == 'i')
786 : : {
787 : 0 : p++;
788 [ # # ]: 0 : if (isdigit(UCINT * p))
789 : : {
790 : 0 : int mw = strtol(p, &q, 10);
791 : 0 : p = q;
792 : 0 : mw -= get_atomic_mass_from_elnum(atom[i].el_number);
793 [ # # ]: 0 : if (mw >= 0)
794 : 0 : mw++;
795 : 0 : atom[i].iso_atw_diff = mw;
796 : : }
797 : : }
798 : :
799 : : /* parity */
800 [ # # # # : 0 : switch (*p)
# ]
801 : : {
802 : 0 : case 'o':
803 : 0 : parity = INCHI_PARITY_ODD;
804 : 0 : p++;
805 : 0 : break;
806 : 0 : case 'e':
807 : 0 : parity = INCHI_PARITY_EVEN;
808 : 0 : p++;
809 : 0 : break;
810 : 0 : case 'u':
811 : 0 : parity = INCHI_PARITY_UNKNOWN;
812 : 0 : p++;
813 : 0 : break;
814 : 0 : case '?':
815 : 0 : parity = INCHI_PARITY_UNDEFINED;
816 : 0 : p++;
817 : 0 : break;
818 : 0 : default:
819 : 0 : parity = 0;
820 : 0 : break;
821 : : }
822 : :
823 [ # # ]: 0 : if (parity)
824 : : {
825 : 0 : atom_stereo0D[len_stereo0D].central_atom = i;
826 : 0 : atom_stereo0D[len_stereo0D].parity = parity;
827 : 0 : atom_stereo0D[len_stereo0D].type = INCHI_StereoType_Tetrahedral;
828 : 0 : len_stereo0D++;
829 : : }
830 : :
831 : : /* isotopic h, d, t */
832 [ # # ]: 0 : for (k = 0; k < NUM_H_ISOTOPES; k++)
833 : : {
834 [ # # ]: 0 : if (*p == szIsoH[k])
835 : : {
836 : 0 : NUM_ISO_Hk(atom, i, k) = 1;
837 : 0 : p++;
838 [ # # ]: 0 : if (isdigit(UCINT * p))
839 : : {
840 : 0 : NUM_ISO_Hk(atom, i, k) = (char)strtol(p, &q, 10);
841 : 0 : p = q;
842 : : }
843 : : }
844 : : }
845 : :
846 : 0 : i++;
847 : : }
848 : :
849 [ # # # # : 0 : if (!bItemIsOver || i != num_atoms || (s && p != s)) /* djb-rwth: addressing LLVM warning */
# # # # ]
850 : : {
851 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
852 : 0 : *err = INCHI_INP_ERROR_ERR;
853 : 0 : TREAT_ERR(*err, 0, "Wrong number of atoms");
854 : 0 : goto bypass_end_of_INChI_plain;
855 : : }
856 : : }
857 : :
858 : : /*
859 : : Search for bonds block (plain) and read it
860 : : */
861 : :
862 : : /*p = szLine;*/
863 : 0 : sToken = sStructHdrPlnRevBn;
864 : 0 : lToken = sizeof(sStructHdrPlnRevBn) - 1;
865 : :
866 : : /* Search for sToken in the line; load next segments of the line if sToken has not found */
867 : 0 : p = FindToken(inp_file, &ir.bTooLongLine, sToken, lToken, szLine_i2i, sizeof(szLine_i2i), p, &res);
868 : :
869 [ # # ]: 0 : if (!p)
870 : : {
871 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
872 : 0 : *err = INCHI_INP_ERROR_ERR;
873 : 0 : TREAT_ERR(*err, 0, "Missing bonds data");
874 : 0 : goto bypass_end_of_INChI_plain;
875 : : }
876 : : else
877 : : {
878 : : /* bonds block started */
879 : :
880 : 0 : i = 1;
881 : :
882 : : /* djb-rwth: removing redundant code */
883 : :
884 [ # # # # ]: 0 : bItemIsOver = (s = strchr(p, '/')) || !ir.bTooLongLine;
885 : :
886 [ # # ]: 0 : if (1 == num_atoms)
887 : : {
888 : : /* needed because the next '/' may be still out of szLine */
889 : :
890 : 0 : p = LoadLine(inp_file, &ir.bTooLongLine, &bItemIsOver, &s,
891 : : szLine_i2i, sizeof(szLine_i2i), INCHI_LINE_ADD, p, &res);
892 : : }
893 : :
894 [ # # ]: 0 : while (i < num_atoms)
895 : : {
896 : :
897 : 0 : p = LoadLine(inp_file, &ir.bTooLongLine, &bItemIsOver, &s,
898 : : szLine_i2i, sizeof(szLine_i2i), INCHI_LINE_ADD, p, &res);
899 : :
900 [ # # # # : 0 : if (i >= num_atoms || (s && p >= s)) /* djb-rwth: addressing LLVM warning */
# # ]
901 : : {
902 : : break; /* end of bonds (plain) */
903 : : }
904 : :
905 : : /* bond, first char */
906 [ # # ]: 0 : if (*p == ';')
907 : : {
908 : 0 : p++;
909 : 0 : i++;
910 : 0 : continue;
911 : : }
912 : :
913 [ # # ]: 0 : if (!isalpha(UCINT * p))
914 : : {
915 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
916 : 0 : *err = INCHI_INP_ERROR_ERR;
917 : 0 : TREAT_ERR(*err, 0, "Wrong bonds data");
918 : 0 : goto bypass_end_of_INChI_plain;
919 : : }
920 : :
921 : 0 : bond_char = *p++;
922 : :
923 : : /* bond parity */
924 [ # # # # : 0 : switch (*p)
# ]
925 : : {
926 : 0 : case '-':
927 : 0 : bond_parity = INCHI_PARITY_ODD;
928 : 0 : p++;
929 : 0 : break;
930 : 0 : case '+':
931 : 0 : bond_parity = INCHI_PARITY_EVEN;
932 : 0 : p++;
933 : 0 : break;
934 : 0 : case 'u':
935 : 0 : bond_parity = INCHI_PARITY_UNKNOWN;
936 : 0 : p++;
937 : 0 : break;
938 : 0 : case '?':
939 : 0 : bond_parity = INCHI_PARITY_UNDEFINED;
940 : 0 : p++;
941 : 0 : break;
942 : 0 : default:
943 : 0 : bond_parity = 0;
944 : 0 : break;
945 : : }
946 : :
947 [ # # ]: 0 : if (bond_parity)
948 : : {
949 [ # # # # : 0 : switch (*p)
# ]
950 : : {
951 : 0 : case '-':
952 : 0 : bond_parityNM = INCHI_PARITY_ODD;
953 : 0 : p++;
954 : 0 : break;
955 : 0 : case '+':
956 : 0 : bond_parityNM = INCHI_PARITY_EVEN;
957 : 0 : p++;
958 : 0 : break;
959 : 0 : case 'u':
960 : 0 : bond_parityNM = INCHI_PARITY_UNKNOWN;
961 : 0 : p++;
962 : 0 : break;
963 : 0 : case '?':
964 : 0 : bond_parityNM = INCHI_PARITY_UNDEFINED;
965 : 0 : p++;
966 : 0 : break;
967 : 0 : default:
968 : 0 : bond_parityNM = 0;
969 : 0 : break;
970 : : }
971 : : }
972 : : else
973 : : {
974 : 0 : bond_parityNM = 0;
975 : : }
976 : :
977 : : /* neighbor of the current atom */
978 [ # # ]: 0 : if (!isdigit(UCINT * p))
979 : : {
980 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
981 : 0 : *err = INCHI_INP_ERROR_ERR;
982 : 0 : TREAT_ERR(*err, 0, "Wrong bonds data");
983 : 0 : goto bypass_end_of_INChI_plain;
984 : : }
985 : :
986 : 0 : neigh = (int)strtol(p, &q, 10) - 1;
987 : :
988 : : #if ( FIX_CURE53_ISSUE_HEAP_BUFFER_OVERFLOW_INCHITOINPATOM==1 )
989 [ # # # # : 0 : if (i >= num_atoms || neigh >= num_atoms || neigh < 0)
# # ]
990 : : {
991 : : #else
992 : : if (i >= num_atoms || neigh >= num_atoms) {
993 : : #endif
994 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
995 : 0 : *err = INCHI_INP_ERROR_ERR;
996 : 0 : TREAT_ERR(*err, 0, "Bond to nonexistent atom");
997 : 0 : goto bypass_end_of_INChI_plain;
998 : : }
999 : :
1000 : 0 : p = q;
1001 : 0 : bond_stereo1 = bond_stereo2 = 0;
1002 : :
1003 : : /* bond type & 2D stereo */
1004 [ # # # # : 0 : switch (bond_char)
# # # # #
# # # ]
1005 : : {
1006 : 0 : case 'v':
1007 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1008 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1EITHER;
1009 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2EITHER;
1010 : 0 : break;
1011 : 0 : case 'V':
1012 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1013 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2EITHER;
1014 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1EITHER;
1015 : 0 : break;
1016 : 0 : case 'w':
1017 : 0 : bond_type = INCHI_BOND_TYPE_DOUBLE;
1018 : 0 : bond_stereo1 =
1019 : 0 : bond_stereo2 = INCHI_BOND_STEREO_DOUBLE_EITHER;
1020 : 0 : break;
1021 : 0 : case 's':
1022 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1023 : 0 : break;
1024 : 0 : case 'd':
1025 : 0 : bond_type = INCHI_BOND_TYPE_DOUBLE;
1026 : 0 : break;
1027 : 0 : case 't':
1028 : 0 : bond_type = INCHI_BOND_TYPE_TRIPLE;
1029 : 0 : break;
1030 : 0 : case 'a':
1031 : 0 : bond_type = INCHI_BOND_TYPE_ALTERN;
1032 : 0 : break;
1033 : 0 : case 'p':
1034 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1035 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1UP;
1036 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2UP;
1037 : 0 : break;
1038 : 0 : case 'P':
1039 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1040 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2UP;
1041 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1UP;
1042 : 0 : break;
1043 : 0 : case 'n':
1044 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1045 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_1DOWN;
1046 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_2DOWN;
1047 : 0 : break;
1048 : 0 : case 'N':
1049 : 0 : bond_type = INCHI_BOND_TYPE_SINGLE;
1050 : 0 : bond_stereo1 = INCHI_BOND_STEREO_SINGLE_2DOWN;
1051 : 0 : bond_stereo2 = INCHI_BOND_STEREO_SINGLE_1DOWN;
1052 : 0 : break;
1053 : 0 : default:
1054 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
1055 : 0 : *err = INCHI_INP_ERROR_ERR;
1056 : 0 : TREAT_ERR(*err, 0, "Wrong bond type");
1057 : 0 : goto bypass_end_of_INChI_plain;
1058 : : }
1059 : :
1060 : 0 : k = AT_NUM_BONDS(atom[i])++; /* AT_NUM_BONDS(AT) ==> (AT).valence */
1061 : :
1062 : 0 : atom[i].bond_type[k] = bond_type;
1063 : 0 : atom[i].bond_stereo[k] = bond_stereo1;
1064 : 0 : atom[i].neighbor[k] = (AT_NUMB)neigh;
1065 : :
1066 : 0 : k2 = AT_NUM_BONDS(atom[neigh])++; /* AT_NUM_BONDS(AT) ==> (AT).valence */
1067 : 0 : atom[neigh].bond_type[k2] = bond_type;
1068 : 0 : atom[neigh].bond_stereo[k2] = bond_stereo2;
1069 : 0 : atom[neigh].neighbor[k2] = (AT_NUMB)i;
1070 : :
1071 : 0 : bond_parity |= (bond_parityNM << SB_PARITY_SHFT);
1072 : :
1073 [ # # ]: 0 : if (bond_parity)
1074 : : {
1075 [ # # ]: 0 : if (max_len_stereo0D <= len_stereo0D)
1076 : : {
1077 : : /* realloc atom_Stereo0D */
1078 : :
1079 : 0 : inchi_Stereo0D* new_atom_stereo0D = CreateInchi_Stereo0D(max_len_stereo0D + num_atoms);
1080 : :
1081 [ # # ]: 0 : if (!new_atom_stereo0D)
1082 : : {
1083 : 0 : num_atoms = INCHI_INP_FATAL_RET; /* fatal error: cannot allocate */
1084 : 0 : *err = INCHI_INP_FATAL_ERR;
1085 : 0 : TREAT_ERR(*err, 0, "Out of RAM");
1086 : 0 : goto bypass_end_of_INChI_plain;
1087 : : }
1088 : :
1089 : 0 : memcpy(new_atom_stereo0D, atom_stereo0D, len_stereo0D * sizeof(*atom_stereo0D));
1090 : 0 : FreeInchi_Stereo0D(&atom_stereo0D);
1091 : 0 : atom_stereo0D = new_atom_stereo0D;
1092 : 0 : max_len_stereo0D += num_atoms;
1093 : : }
1094 : :
1095 : : /* (a) i may be allene endpoint and neigh = allene middle point or
1096 : : (b) i may be allene middle point and neigh = allene endpoint
1097 : : !!!!! CURRENTLY ONLY (b) IS ALLOWED !!!!!
1098 : : */
1099 : :
1100 : 0 : atom_stereo0D[len_stereo0D].neighbor[1] = neigh; /* neigh < i */
1101 : 0 : atom_stereo0D[len_stereo0D].neighbor[2] = i;
1102 : 0 : atom_stereo0D[len_stereo0D].parity = bond_parity;
1103 : 0 : atom_stereo0D[len_stereo0D].type = INCHI_StereoType_DoubleBond; /* incl allenes & cumulenes */
1104 : 0 : len_stereo0D++;
1105 : : }
1106 : : }
1107 : :
1108 [ # # # # : 0 : if (!bItemIsOver || i != num_atoms || (s && p != s)) /* djb-rwth: addressing LLVM warning */
# # # # ]
1109 : : {
1110 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
1111 : 0 : *err = INCHI_INP_ERROR_ERR;
1112 : 0 : TREAT_ERR(*err, 0, "Wrong number of bonds");
1113 : 0 : goto bypass_end_of_INChI_plain;
1114 : : }
1115 : : }
1116 : :
1117 : : /*
1118 : : Search for coordinates block (plain)
1119 : : */
1120 : :
1121 : : /*p = szLine;*/
1122 : 0 : sToken = sStructHdrPlnRevXYZ;
1123 : 0 : lToken = sizeof(sStructHdrPlnRevXYZ) - 1;
1124 : :
1125 : : /* search for sToken in the line; load next segments of the line if sToken has not found */
1126 : 0 : p = FindToken(inp_file, &ir.bTooLongLine, sToken, lToken, szLine_i2i, sizeof(szLine_i2i), p, &res);
1127 : :
1128 [ # # ]: 0 : if (!p)
1129 : : {
1130 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
1131 : 0 : *err = INCHI_INP_ERROR_ERR;
1132 : 0 : TREAT_ERR(*err, 0, "Missing atom coordinates data");
1133 : 0 : goto bypass_end_of_INChI_plain;
1134 : : }
1135 : : else
1136 : : {
1137 : : /* Coordinates block started */
1138 [ # # ]: 0 : if ((pszCoord = (MOL_COORD*)inchi_malloc(inchi_max(num_atoms, 1) * sizeof(MOL_COORD)))) /* djb-rwth: addressing LLVM warning */
1139 : : {
1140 : 0 : memset(pszCoord, ' ', inchi_max(num_atoms, 1) * sizeof(MOL_COORD)); /* djb-rwth: memset_s C11/Annex K variant? */
1141 : : }
1142 : : else
1143 : : {
1144 : 0 : num_atoms = INCHI_INP_FATAL_RET; /* allocation error */
1145 : 0 : *err = INCHI_INP_FATAL_ERR;
1146 : 0 : TREAT_ERR(*err, 0, "Out of RAM");
1147 : 0 : goto bypass_end_of_INChI_plain;
1148 : : }
1149 : :
1150 : 0 : i = 0;
1151 : : /* djb-rwth: removing redundant code */
1152 [ # # # # ]: 0 : bItemIsOver = (s = strchr(p, '/')) || !ir.bTooLongLine;
1153 : :
1154 [ # # ]: 0 : while (i < num_atoms)
1155 : : {
1156 : :
1157 : 0 : p = LoadLine(inp_file, &ir.bTooLongLine, &bItemIsOver, &s,
1158 : : szLine_i2i, sizeof(szLine_i2i), INCHI_LINE_ADD, p, &res);
1159 : :
1160 [ # # # # : 0 : if (i >= num_atoms || (s && p >= s)) /* djb-rwth: addressing LLVM warning */
# # ]
1161 : : {
1162 : : break; /* end of bonds (plain) */
1163 : : }
1164 : :
1165 : : /* coord, first char */
1166 [ # # ]: 0 : if (*p == ';')
1167 : : {
1168 [ # # ]: 0 : for (k = 0; k < NUM_COORD; k++)
1169 : : {
1170 : 0 : pszCoord[i][LEN_COORD * k + 4] = '0';
1171 : : }
1172 : 0 : p++;
1173 : 0 : i++;
1174 : 0 : continue;
1175 : : }
1176 : :
1177 [ # # ]: 0 : for (k = 0; k < 3; k++)
1178 : : {
1179 : : double xyz;
1180 : 0 : bNonZeroXYZ = 0;
1181 [ # # ]: 0 : if (*p == ';')
1182 : : {
1183 : 0 : pszCoord[i][LEN_COORD * k + 4] = '0';
1184 : 0 : xyz = 0.0;
1185 : : }
1186 : : else
1187 : : {
1188 [ # # ]: 0 : if (*p == ',')
1189 : : {
1190 : : /* empty */
1191 : 0 : pszCoord[i][LEN_COORD * k + 4] = '0';
1192 : 0 : xyz = 0.0;
1193 : 0 : p++;
1194 : : }
1195 : : else
1196 : : {
1197 : 0 : xyz = strtod(p, &q);
1198 : 0 : bNonZeroXYZ = fabs(xyz) > MIN_BOND_LENGTH;
1199 [ # # ]: 0 : if (q != NULL)
1200 : : {
1201 : 0 : memcpy(pszCoord[i] + LEN_COORD * (long long)k, p, q - p); /* djb-rwth: cast operator added */
1202 [ # # ]: 0 : if (*q == ',')
1203 : 0 : q++;
1204 : 0 : p = q;
1205 : : }
1206 : : else
1207 : 0 : pszCoord[i][LEN_COORD * k + 4] = '0';
1208 : : }
1209 : : }
1210 : :
1211 [ # # # # ]: 0 : switch (k)
1212 : : {
1213 : 0 : case 0:
1214 : 0 : atom[i].x = xyz;
1215 : 0 : b2D |= bNonZeroXYZ;
1216 : 0 : break;
1217 : 0 : case 1:
1218 : 0 : atom[i].y = xyz;
1219 : 0 : b2D |= bNonZeroXYZ;
1220 : 0 : break;
1221 : 0 : case 2:
1222 : 0 : b3D |= bNonZeroXYZ;
1223 : 0 : atom[i].z = xyz;
1224 : 0 : break;
1225 : : }
1226 : : }
1227 : :
1228 [ # # ]: 0 : if (*p == ';')
1229 : : {
1230 : 0 : p++; /* end of this triple of coordinates */
1231 : 0 : i++;
1232 : : }
1233 : : else
1234 : : {
1235 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error in input data: atoms, bonds & coord must be present together */
1236 : 0 : *err = INCHI_INP_ERROR_ERR;
1237 : 0 : TREAT_ERR(*err, 0, "Wrong atom coordinates data");
1238 : 0 : goto bypass_end_of_INChI_plain;
1239 : : }
1240 : : }
1241 : :
1242 [ # # # # : 0 : if (!bItemIsOver || (s && p != s) || i != num_atoms) /* djb-rwth: addressing LLVM warning */
# # # # ]
1243 : : {
1244 : 0 : num_atoms = INCHI_INP_ERROR_RET; /* error */
1245 : 0 : *err = INCHI_INP_ERROR_ERR;
1246 : 0 : TREAT_ERR(*err, 0, "Wrong number of coordinates");
1247 : 0 : goto bypass_end_of_INChI_plain;
1248 : : }
1249 : : } /* end of coordinates */
1250 : :
1251 : : /*
1252 : : Set special valences and implicit H (xml)
1253 : : */
1254 : :
1255 : 0 : b23D = b2D | b3D;
1256 : : /* djb-rwth: removing redundant code */
1257 [ # # ]: 0 : if (at)
1258 : : {
1259 [ # # ]: 0 : if (!*at)
1260 : : {
1261 : : int a1, a2, n1, n2, valence;
1262 : : int chem_bonds_valence;
1263 : 0 : int nX = 0, nY = 0, nZ = 0, nXYZ;
1264 : 0 : *at = atom;
1265 : :
1266 : : /* special valences */
1267 : :
1268 [ # # ]: 0 : for (bNonMetal = 0; bNonMetal < 1; bNonMetal++)
1269 : : {
1270 [ # # ]: 0 : for (a1 = 0; a1 < num_atoms; a1++)
1271 : : {
1272 : : int num_bond_type[MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE + 1];
1273 : 0 : int bHasMetalNeighbor = 0;
1274 : :
1275 : 0 : memset(num_bond_type, 0, sizeof(num_bond_type)); /* djb-rwth: memset_s C11/Annex K variant? */
1276 : :
1277 : 0 : valence = AT_BONDS_VAL(atom, a1); /* save atom valence if available */
1278 : 0 : AT_BONDS_VAL(atom, a1) = 0;
1279 : :
1280 : 0 : atom[a1].orig_at_number = a1 + 1;
1281 : :
1282 : 0 : nX = nY = nZ = 0;
1283 : :
1284 [ # # ]: 0 : for (n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1++) /*AT_NUM_BONDS(AT) ==> (AT).valence */
1285 : : {
1286 : 0 : bond_type = atom[a1].bond_type[n1] - MIN_INPUT_BOND_TYPE;
1287 [ # # # # ]: 0 : if (bond_type < 0 || bond_type > MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE)
1288 : : {
1289 : 0 : bond_type = 0;
1290 : 0 : TREAT_ERR(*err, 0, "Unknown bond type in InChI aux assigned as a single bond");
1291 : : }
1292 : :
1293 : 0 : num_bond_type[bond_type] ++;
1294 : 0 : nNumBonds++;
1295 [ # # ]: 0 : if (b23D)
1296 : : {
1297 : 0 : neigh = atom[a1].neighbor[n1];
1298 : 0 : nX |= (fabs(atom[a1].x - atom[neigh].x) > MIN_BOND_LENGTH);
1299 : 0 : nY |= (fabs(atom[a1].y - atom[neigh].y) > MIN_BOND_LENGTH);
1300 : 0 : nZ |= (fabs(atom[a1].z - atom[neigh].z) > MIN_BOND_LENGTH);
1301 : : }
1302 : : }
1303 : :
1304 : 0 : chem_bonds_valence = 0;
1305 [ # # # # ]: 0 : for (n1 = 0; MIN_INPUT_BOND_TYPE + n1 <= 3 && MIN_INPUT_BOND_TYPE + n1 <= MAX_INPUT_BOND_TYPE; n1++)
1306 : : {
1307 : 0 : chem_bonds_valence += (MIN_INPUT_BOND_TYPE + n1) * num_bond_type[n1];
1308 : : }
1309 : :
1310 : 0 : if (MIN_INPUT_BOND_TYPE <= INCHI_BOND_TYPE_ALTERN && INCHI_BOND_TYPE_ALTERN <= MAX_INPUT_BOND_TYPE &&
1311 [ # # ]: 0 : (n2 = num_bond_type[INCHI_BOND_TYPE_ALTERN - MIN_INPUT_BOND_TYPE]))
1312 : : {
1313 : : /* accept input aromatic bonds for now */
1314 [ # # # ]: 0 : switch (n2)
1315 : : {
1316 : 0 : case 2:
1317 : 0 : chem_bonds_valence += 3; /* =A- */
1318 : 0 : break;
1319 : :
1320 : 0 : case 3:
1321 : 0 : chem_bonds_valence += 4; /* =A< */
1322 : 0 : break;
1323 : :
1324 : 0 : default:
1325 : : /* if 1 or >= 4 aromatic bonds then replace such bonds with single bonds */
1326 [ # # ]: 0 : for (n1 = 0; n1 < AT_NUM_BONDS(atom[a1]); n1++) /* AT_NUM_BONDS(AT) ==> (AT).valence */
1327 : : {
1328 [ # # ]: 0 : if (atom[a1].bond_type[n1] == INCHI_BOND_TYPE_ALTERN)
1329 : : {
1330 : : AT_NUMB* p1;
1331 : 0 : a2 = atom[a1].neighbor[n1];
1332 : 0 : p1 = is_in_the_list(atom[a2].neighbor, (AT_NUMB)a1, AT_NUM_BONDS(atom[a2])); /*AT_NUM_BONDS(AT) ==> (AT).valence*/
1333 [ # # ]: 0 : if (p1)
1334 : : {
1335 : 0 : atom[a1].bond_type[n1] =
1336 : 0 : atom[a2].bond_type[p1 - atom[a2].neighbor] = INCHI_BOND_TYPE_SINGLE;
1337 : : }
1338 : : else
1339 : : {
1340 : 0 : *err = -2; /* Program error */
1341 : 0 : TREAT_ERR(*err, 0, "Program error interpreting InChI aux");
1342 : 0 : num_atoms = INCHI_INP_FATAL_RET;
1343 : 0 : goto bypass_end_of_INChI_plain; /* no structure */
1344 : : }
1345 : : }
1346 : : }
1347 : :
1348 : 0 : chem_bonds_valence += n2;
1349 : 0 : *err |= 32; /* Unrecognized aromatic bond(s) replaced with single */
1350 : 0 : TREAT_ERR(*err, 0, "Atom has 1 or more than 3 aromatic bonds");
1351 : 0 : break;
1352 : : }
1353 : : }
1354 : :
1355 : : /* added 2006-07-19 to process aromatic bonds same way as from molfile */
1356 [ # # # # ]: 0 : if (n2 && !valence)
1357 : 0 : {
1358 : 0 : int num_H = NUMH(atom, a1); /* only isotopic */
1359 : 0 : int chem_valence = chem_bonds_valence;
1360 : : int bUnusualValenceArom =
1361 : 0 : detect_unusual_el_valence((int)atom[a1].el_number, atom[a1].charge,
1362 : 0 : atom[a1].radical, chem_valence,
1363 : 0 : num_H, atom[a1].valence);
1364 : : int bUnusualValenceNoArom =
1365 : 0 : detect_unusual_el_valence((int)atom[a1].el_number, atom[a1].charge,
1366 : 0 : atom[a1].radical, chem_valence - 1,
1367 : 0 : num_H, atom[a1].valence);
1368 : :
1369 : : #if ( CHECK_AROMBOND2ALT == 1 )
1370 [ # # # # : 0 : if (bUnusualValenceArom && !bUnusualValenceNoArom && 0 == nBondsValToMetal(atom, a1))
# # ]
1371 : : #else
1372 : : if (bUnusualValenceArom && !bUnusualValenceNoArom)
1373 : : #endif
1374 : :
1375 : : {
1376 : : /* typically NH in 5-member aromatic ring */
1377 : 0 : chem_bonds_valence--;
1378 : : }
1379 : : }
1380 [ # # # # ]: 0 : else if (n2 && valence)
1381 : : {
1382 : : /* atom has aromatic bonds AND the chemical valence is known */
1383 : 0 : int num_H = NUMH(atom, a1);
1384 : 0 : int chem_valence = chem_bonds_valence + num_H;
1385 [ # # ]: 0 : if (valence == chem_valence - 1)
1386 : : {
1387 : : /* typically NH in 5-member aromatic ring */
1388 : 0 : chem_bonds_valence--;
1389 : : }
1390 : : }
1391 : :
1392 : 0 : atom[a1].chem_bonds_valence = chem_bonds_valence;
1393 : :
1394 : 0 : atom[a1].num_H = get_num_H(atom[a1].elname,
1395 : 0 : atom[a1].num_H,
1396 : 0 : atom[a1].num_iso_H,
1397 : 0 : atom[a1].charge,
1398 : 0 : atom[a1].radical,
1399 : 0 : atom[a1].chem_bonds_valence,
1400 : : valence,
1401 : : 0,
1402 : : bDoNotAddH,
1403 : : bHasMetalNeighbor);
1404 : : }
1405 : : }
1406 : :
1407 : 0 : nNumBonds /= 2;
1408 : :
1409 [ # # # # ]: 0 : if (b23D && nNumBonds)
1410 : : {
1411 : 0 : nXYZ = nX + nY + nZ;
1412 : 0 : b2D = (nXYZ > 0);
1413 : 0 : b3D = (nXYZ == 3);
1414 [ # # # # ]: 0 : *num_dimensions = b3D ? 3 : b2D ? 2 : 0;
1415 : 0 : *num_bonds = nNumBonds;
1416 : : }
1417 : :
1418 : : /*======= 0D parities =================================*/
1419 : :
1420 [ # # ]: 0 : for (i = 0; i < len_stereo0D; i++)
1421 : : {
1422 : : AT_NUMB* p1, * p2;
1423 : 0 : int sb_ord_from_a1 = -1, sb_ord_from_a2 = -1, bEnd1 = 0, bEnd2 = 0;
1424 : :
1425 [ # # # ]: 0 : switch (atom_stereo0D[i].type)
1426 : : {
1427 : :
1428 : 0 : case INCHI_StereoType_Tetrahedral:
1429 : 0 : a1 = atom_stereo0D[i].central_atom;
1430 [ # # # # : 0 : if (atom_stereo0D[i].parity && (AT_NUM_BONDS(atom[a1]) == 3 || AT_NUM_BONDS(atom[a1]) == 4))
# # ]
1431 : : {
1432 : 0 : int ii, kk = 0;
1433 [ # # ]: 0 : if (AT_NUM_BONDS(atom[a1]) == 3)
1434 : 0 : atom_stereo0D[i].neighbor[kk++] = a1;
1435 [ # # ]: 0 : for (ii = 0; ii < AT_NUM_BONDS(atom[a1]); ii++)
1436 : 0 : atom_stereo0D[i].neighbor[kk++] = atom[a1].neighbor[ii];
1437 : : }
1438 : :
1439 : 0 : break;
1440 : :
1441 : 0 : case INCHI_StereoType_DoubleBond:
1442 : : #define MAX_CHAIN_LEN 20
1443 : 0 : a1 = atom_stereo0D[i].neighbor[1];
1444 : 0 : a2 = atom_stereo0D[i].neighbor[2];
1445 : 0 : p1 = is_in_the_list(atom[a1].neighbor, (AT_NUMB)a2, AT_NUM_BONDS(atom[a1]));
1446 : 0 : p2 = is_in_the_list(atom[a2].neighbor, (AT_NUMB)a1, AT_NUM_BONDS(atom[a2]));
1447 [ # # # # ]: 0 : if (!p1 || !p2)
1448 : : {
1449 : 0 : atom_stereo0D[i].type = INCHI_StereoType_None;
1450 : 0 : atom_stereo0D[i].central_atom = NO_ATOM;
1451 : 0 : atom_stereo0D[i].neighbor[0] =
1452 : 0 : atom_stereo0D[i].neighbor[3] = -1;
1453 : 0 : *err |= 64; /* Error in cumulene stereo */
1454 : 0 : TREAT_ERR(*err, 0, "0D stereobond not recognized");
1455 : 0 : break;
1456 : : }
1457 : :
1458 : : /* streobond, allene, or cumulene */
1459 : :
1460 : 0 : sb_ord_from_a1 = p1 - atom[a1].neighbor;
1461 : 0 : sb_ord_from_a2 = p2 - atom[a2].neighbor;
1462 : :
1463 [ # # ]: 0 : if (AT_NUM_BONDS(atom[a1]) == 2 &&
1464 [ # # ]: 0 : atom[a1].bond_type[0] + atom[a1].bond_type[1] == 2 * INCHI_BOND_TYPE_DOUBLE &&
1465 [ # # ]: 0 : 0 == inchi_NUMH2(atom, a1) &&
1466 [ # # ]: 0 : (AT_NUM_BONDS(atom[a2]) != 2 ||
1467 [ # # ]: 0 : atom[a2].bond_type[0] + atom[a2].bond_type[1] != 2 * INCHI_BOND_TYPE_DOUBLE))
1468 : : {
1469 : 0 : bEnd2 = 1; /* a2 is the end-atom, a1 is middle atom */
1470 : : }
1471 : :
1472 [ # # ]: 0 : if (AT_NUM_BONDS(atom[a2]) == 2 &&
1473 [ # # ]: 0 : atom[a2].bond_type[0] + atom[a2].bond_type[1] == 2 * INCHI_BOND_TYPE_DOUBLE &&
1474 [ # # ]: 0 : 0 == inchi_NUMH2(atom, a2) &&
1475 [ # # ]: 0 : (AT_NUM_BONDS(atom[a1]) != 2 ||
1476 [ # # ]: 0 : atom[a1].bond_type[0] + atom[a1].bond_type[1] != 2 * INCHI_BOND_TYPE_DOUBLE))
1477 : : {
1478 : 0 : bEnd1 = 1; /* a1 is the end-atom, a2 is middle atom */
1479 : : }
1480 : :
1481 [ # # ]: 0 : if (bEnd2 + bEnd1 == 1)
1482 : : {
1483 : : /* allene or cumulene */
1484 : :
1485 : : AT_NUMB chain[MAX_CHAIN_LEN + 1], prev, cur, next;
1486 : :
1487 [ # # # # ]: 0 : if (bEnd2 && !bEnd1)
1488 : : {
1489 : 0 : cur = a1;
1490 : 0 : a1 = a2;
1491 : 0 : a2 = cur;
1492 : 0 : sb_ord_from_a1 = sb_ord_from_a2;
1493 : : }
1494 : :
1495 : 0 : sb_ord_from_a2 = -1;
1496 : 0 : cur = a1;
1497 : 0 : next = a2;
1498 : 0 : len = 0;
1499 : 0 : chain[len++] = cur;
1500 : 0 : chain[len++] = next;
1501 : :
1502 [ # # ]: 0 : while (len < MAX_CHAIN_LEN)
1503 : : {
1504 : : /* arbitrary very high upper limit to prevent infinite loop */
1505 : :
1506 : 0 : prev = cur;
1507 : 0 : cur = next;
1508 : : /* follow double bond path && avoid going back */
1509 [ # # ]: 0 : if (AT_NUM_BONDS(atom[cur]) == 2 &&
1510 [ # # ]: 0 : atom[cur].bond_type[0] + atom[cur].bond_type[1] == 2 * INCHI_BOND_TYPE_DOUBLE &&
1511 [ # # ]: 0 : 0 == inchi_NUMH2(atom, cur))
1512 : : {
1513 : 0 : next = atom[cur].neighbor[atom[cur].neighbor[0] == prev];
1514 : 0 : chain[len++] = next;
1515 : : }
1516 : : else
1517 : : {
1518 : : break;
1519 : : }
1520 : : }
1521 [ # # # # ]: 0 : if (len > 2 &&
1522 : 0 : (p2 = is_in_the_list(atom[cur].neighbor, (AT_NUMB)prev, AT_NUM_BONDS(atom[cur]))))
1523 : : {
1524 : 0 : sb_ord_from_a2 = p2 - atom[cur].neighbor;
1525 : 0 : a2 = cur;
1526 : : /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
1527 : 0 : atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[sb_ord_from_a1 == 0];
1528 : 0 : atom_stereo0D[i].neighbor[1] = a1;
1529 : 0 : atom_stereo0D[i].neighbor[2] = a2;
1530 : 0 : atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[sb_ord_from_a2 == 0];
1531 : :
1532 [ # # ]: 0 : if (len % 2)
1533 : : {
1534 : 0 : atom_stereo0D[i].central_atom = chain[len / 2];
1535 : 0 : atom_stereo0D[i].type = INCHI_StereoType_Allene;
1536 : : }
1537 : : else
1538 : : {
1539 : 0 : atom_stereo0D[i].central_atom = NO_ATOM;
1540 : : }
1541 : : }
1542 : : else
1543 : : {
1544 : : /* error */
1545 : 0 : atom_stereo0D[i].type = INCHI_StereoType_None;
1546 : 0 : atom_stereo0D[i].central_atom = NO_ATOM;
1547 : 0 : atom_stereo0D[i].neighbor[0] =
1548 : 0 : atom_stereo0D[i].neighbor[3] = -1;
1549 : 0 : *err |= 64; /* Error in cumulene stereo */
1550 : 0 : TREAT_ERR(*err, 0, "Cumulene stereo not recognized (0D)");
1551 : : }
1552 : : #undef MAX_CHAIN_LEN
1553 : : }
1554 : : else
1555 : : {
1556 : : /****** a normal possibly stereogenic bond -- not an allene or cumulene *******/
1557 : : /* by design we need to pick up the first non-stereo-bond-neighbor as "sn"-atom */
1558 : 0 : sb_ord_from_a1 = p1 - atom[a1].neighbor;
1559 : 0 : sb_ord_from_a2 = p2 - atom[a2].neighbor;
1560 : 0 : atom_stereo0D[i].neighbor[0] = atom[a1].neighbor[p1 == atom[a1].neighbor];
1561 : 0 : atom_stereo0D[i].neighbor[3] = atom[a2].neighbor[p2 == atom[a2].neighbor];
1562 : 0 : atom_stereo0D[i].central_atom = NO_ATOM;
1563 : : }
1564 : :
1565 [ # # # # ]: 0 : if (atom_stereo0D[i].type != INCHI_StereoType_None &&
1566 [ # # ]: 0 : sb_ord_from_a1 >= 0 && sb_ord_from_a2 >= 0 &&
1567 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF(SB_PARITY_2(atom_stereo0D[i].parity)))
1568 : : {
1569 : : /* Detected well-defined disconnected stereo
1570 : : * locate first non-metal neighbors */
1571 : :
1572 : : int a, j, /* k,*/ sb_ord, cur_neigh, min_neigh; /* djb-rwth: removing redundant variables */
1573 : :
1574 [ # # ]: 0 : for (k = 0; k < 2; k++)
1575 : : {
1576 [ # # ]: 0 : a = k ? atom_stereo0D[i].neighbor[2] : atom_stereo0D[i].neighbor[1];
1577 [ # # ]: 0 : sb_ord = k ? sb_ord_from_a2 : sb_ord_from_a1;
1578 : 0 : min_neigh = num_atoms;
1579 [ # # ]: 0 : for (j = 0; j < AT_NUM_BONDS(atom[a]); j++) /* djb-rwth: removing redundant code */
1580 : : {
1581 : 0 : cur_neigh = atom[a].neighbor[j];
1582 [ # # # # ]: 0 : if (j != sb_ord && !IS_METAL_ATOM(atom, cur_neigh))
1583 : : {
1584 : 0 : min_neigh = inchi_min(cur_neigh, min_neigh);
1585 : : }
1586 : : }
1587 [ # # ]: 0 : if (min_neigh < num_atoms)
1588 : : {
1589 [ # # ]: 0 : atom_stereo0D[i].neighbor[k ? 3 : 0] = min_neigh;
1590 : : }
1591 : : else
1592 : : {
1593 : 0 : TREAT_ERR(*err, 0, "Cannot find non-metal stereobond neighor (0D)");
1594 : : }
1595 : : }
1596 : : }
1597 : :
1598 : 0 : break;
1599 : : }
1600 : : }
1601 : : /* end of 0D parities extraction */
1602 : : /*exit_cycle:;*/
1603 : : }
1604 : :
1605 : : /* Transfer atom_stereo0D[] to atom[] */
1606 [ # # ]: 0 : if (len_stereo0D)
1607 : : {
1608 : 0 : Extract0DParities(atom, num_atoms, atom_stereo0D, len_stereo0D,
1609 : : pStrErr, err, vABParityUnknown);
1610 : : }
1611 : :
1612 [ # # ]: 0 : if (pInpAtomFlags)
1613 : : {
1614 : : /* save chirality flag */
1615 : 0 : *pInpAtomFlags |= InpAtomFlags;
1616 : : }
1617 : : }
1618 [ # # ]: 0 : else if (atom)
1619 : : {
1620 [ # # ]: 0 : inchi_free(atom);
1621 : 0 : atom = NULL;
1622 : : }
1623 : :
1624 : : #if ( FIX_READ_AUX_MEM_LEAK == 1 )
1625 : : /* 2005-08-04 avoid memory leak */
1626 [ # # ]: 0 : if (atom_stereo0D) /* && !(stereo0D && *stereo0D == atom_stereo0D) ) */
1627 : : {
1628 : 0 : FreeInchi_Stereo0D(&atom_stereo0D);
1629 : : }
1630 : : #endif
1631 : :
1632 [ # # ]: 0 : if (szCoord)
1633 : : {
1634 : 0 : *szCoord = pszCoord;
1635 : 0 : pszCoord = NULL;
1636 : : }
1637 [ # # ]: 0 : else if (pszCoord)
1638 : : {
1639 [ # # ]: 0 : inchi_free(pszCoord);
1640 : 0 : pszCoord = NULL;
1641 : : }
1642 : :
1643 : 0 : goto bypass_end_of_INChI_plain;
1644 : : /*return num_atoms;*/
1645 : : }
1646 : : } /* while ( 0 < (res = inchi_ios_getsTab( szLine, sizeof(szLine)-1, inp_file, &ir.bTooLongLine ) ) ) */
1647 : :
1648 : : /* End of structure reading cycle */
1649 [ # # ]: 0 : if (atom_stereo0D)
1650 : 0 : FreeInchi_Stereo0D(&atom_stereo0D);
1651 [ # # ]: 0 : if (res <= 0)
1652 : : {
1653 [ # # ]: 0 : if (*err == INCHI_INP_ERROR_ERR)
1654 : : {
1655 : 0 : return num_atoms;
1656 : : }
1657 : 0 : *err = INCHI_INP_EOF_ERR;
1658 : :
1659 : 0 : return INCHI_INP_EOF_RET; /* no more data */
1660 : : }
1661 : :
1662 : 0 : bypass_end_of_INChI_plain:
1663 : : /* Cleanup */
1664 [ # # # # ]: 0 : if (num_atoms == INCHI_INP_ERROR_RET || num_atoms == INCHI_INP_FATAL_RET)
1665 : : {
1666 [ # # ]: 0 : if (atom_stereo0D) /* djb-rwth: avoiding memory leak */
1667 : : {
1668 : 0 : FreeInchi_Stereo0D(&atom_stereo0D);
1669 : : }
1670 : :
1671 [ # # ]: 0 : if (atom) /* djb-rwth: fixing coverity ID #499615 */
1672 : : {
1673 [ # # ]: 0 : inchi_free(atom);
1674 : : }
1675 : :
1676 [ # # ]: 0 : if (pszCoord) /* djb-rwth: fixing coverity ID #499571 */
1677 : : {
1678 [ # # ]: 0 : inchi_free(pszCoord);
1679 : : }
1680 : : }
1681 : :
1682 [ # # # # ]: 0 : while (ir.bTooLongLine &&
1683 : 0 : 0 < inchi_ios_getsTab1(szLine_i2i, sizeof(szLine_i2i) - 1, inp_file, &ir.bTooLongLine))
1684 : : {
1685 : : ;
1686 : : }
1687 : :
1688 : 0 : return num_atoms;
1689 : :
1690 : : #undef AT_NUM_BONDS
1691 : : #undef AT_NUMB
1692 : : #undef is_in_the_list
1693 : : #undef inchi_NUMH2
1694 : :
1695 : : #undef MoreParms
1696 : : #undef INPUT_FILE
1697 : : #undef CreateInpAtom
1698 : : #undef AT_BONDS_VAL
1699 : : #undef ISOLATED_ATOM
1700 : : #undef NUM_ISO_Hk
1701 : : #undef IS_METAL_ATOM
1702 : : }
1703 : :
1704 : :
1705 : :
1706 : : /****************************************************************************/
1707 : 0 : void find_and_interpret_structure_header( char *szLine,
1708 : : char *pSdfLabel,
1709 : : char *pSdfValue,
1710 : : unsigned long *Id,
1711 : : int hlen,
1712 : : ReadINCHI_CtlData *ir )
1713 : : {
1714 : : int len;
1715 : : char *p, *q;
1716 : : static const char sStructHdrPlnNoLblVal[] = " is missing";
1717 : :
1718 : :
1719 : 0 : p = szLine + hlen;
1720 : 0 : ir->ulongID = 0LU;
1721 : :
1722 : : /* structure number */
1723 : 0 : ir->ulongID = strtoul( p, &q, 10 );
1724 [ # # # # : 0 : if (q && q[0] == '.' && q[1] == ' ')
# # ]
1725 : : {
1726 : 0 : p = q + 2;
1727 : : }
1728 : 0 : p = p + strspn( p, " \n\r" );
1729 : :
1730 [ # # ]: 0 : if (pSdfLabel)
1731 : : {
1732 : 0 : pSdfLabel[0] = '\0';
1733 : : }
1734 [ # # ]: 0 : if (pSdfValue)
1735 : : {
1736 : 0 : pSdfValue[0] = '\0';
1737 : : }
1738 : :
1739 [ # # ]: 0 : if (*p)
1740 : : {
1741 : : /* has label name */
1742 : :
1743 : : /*p ++;*/
1744 [ # # ]: 0 : if ((q = strchr( p, '=' ))) /* djb-rwth: addressing LLVM warning */
1745 : : {
1746 : :
1747 : : /* '=' separates label name from the value */
1748 : 0 : len = inchi_min( q - p + 1, MAX_SDF_HEADER - 1 );
1749 : :
1750 [ # # ]: 0 : if (pSdfLabel)
1751 : : {
1752 : 0 : mystrncpy( pSdfLabel, p, len );
1753 : 0 : lrtrim( pSdfLabel, &len );
1754 : : }
1755 : :
1756 : 0 : p = q + 1;
1757 : 0 : q = p + (int) strlen( p );
1758 : :
1759 [ # # ]: 0 : if (q - p > 0)
1760 : : {
1761 : 0 : len = inchi_min( q - p + 1, MAX_SDF_VALUE - 1 );
1762 [ # # ]: 0 : if (pSdfValue)
1763 : : {
1764 : 0 : mystrncpy( pSdfValue, p, len );
1765 : : }
1766 : : /* djb-rwth: removing redundant code */
1767 : : }
1768 : : }
1769 [ # # ]: 0 : else if ((q = strstr( p, sStructHdrPlnNoLblVal ))) /* djb-rwth: addressing LLVM warning */
1770 : : {
1771 : 0 : len = inchi_min( q - p + 1, MAX_SDF_HEADER - 1 );
1772 [ # # ]: 0 : if (pSdfLabel)
1773 : : {
1774 : 0 : mystrncpy( pSdfLabel, p, len );
1775 : : }
1776 : : /* djb-rwth: removing redundant code */
1777 : : }
1778 : : }
1779 : :
1780 [ # # ]: 0 : if (Id)
1781 : : {
1782 : 0 : *Id = ir->ulongID;
1783 : : }
1784 : :
1785 : 0 : ir->bHeaderRead = 1;
1786 : 0 : ir->bErrorMsg = ir->bRestoreInfo = 0;
1787 : :
1788 : 0 : return;
1789 : : }
|