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