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 <string.h>
42 : : #include <ctype.h>
43 : : #include <limits.h>
44 : : #include <locale.h>
45 : :
46 : : /* #define CHECK_WIN32_VC_HEAP */
47 : :
48 : : #include "mode.h"
49 : :
50 : : #if ( READ_INCHI_STRING == 1 )
51 : :
52 : : #include "ichierr.h"
53 : : #include "ichi.h"
54 : : #include "ichitime.h"
55 : : #include "ichidrp.h"
56 : : #include "inpdef.h"
57 : : #include "util.h"
58 : : #include "strutil.h"
59 : : #include "ichi_io.h"
60 : :
61 : : /* reverse InChI */
62 : : #include "ichimain.h"
63 : : #include "extr_ct.h"
64 : : #include "ichitaut.h"
65 : : #include "ichister.h"
66 : : #include "strutil.h"
67 : : #include "ichisize.h"
68 : : #include "ichiring.h"
69 : : #include "ichinorm.h"
70 : : #include "ichierr.h"
71 : : #include "ichicant.h"
72 : :
73 : : #include "ichirvrs.h"
74 : : #include "mol_fmt.h"
75 : :
76 : :
77 : : /* */
78 : : #if ( defined(TARGET_API_LIB) || defined(TARGET_EXE_STANDALONE) )
79 : : #include "inchi_api.h"
80 : : #endif
81 : : /* */
82 : :
83 : : #include "bcf_s.h"
84 : :
85 : : #define SEGM_LINE_ADD 128
86 : :
87 : : typedef struct tagOneLinkedBond
88 : : {
89 : : AT_NUMB neigh; /* canonical number of a neighbor */
90 : : AT_NUMB prev; /* position of the previous neighbor in the list */
91 : : } ONE_LINKED_BOND;
92 : :
93 : : typedef struct tagLinkedBonds
94 : : {
95 : : ONE_LINKED_BOND* pBond;
96 : : int len;
97 : : int len_alloc;
98 : : }LINKED_BONDS;
99 : : #define LINKED_BOND_ADD 128
100 : :
101 : : typedef enum tagModeProtonIsoExchgH
102 : : {
103 : : MODE_PIXH_UNDEFINED, /* 0 */
104 : : MODE_PIXH_ADD_TO_FIRST, /* 1 */
105 : : MODE_PIXH_ADD_TO_EACH, /* 2 */
106 : : MODE_PIXH_ADD_A_PIXH_COMPONENT, /* 3 */
107 : : MODE_PIXH_KEEP_TOTALS /* 4 */
108 : : } MODE_PIXH;
109 : :
110 : :
111 : : /* Local prototypes */
112 : : int InChILine2Data(INCHI_IOSTREAM* pInp,
113 : : SEGM_LINE* pLine,
114 : : char** pStr,
115 : : int* pState,
116 : : int* nErr,
117 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
118 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
119 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
120 : : int s[INCHI_NUM][TAUT_NUM][2],
121 : : int bReadCoord,
122 : : int bInchi2Struct,
123 : : INCHI_MODE nMode,
124 : : int* bStdFormat,
125 : : int* input_has_save_opt,
126 : : unsigned char* input_save_opt_bits,
127 : : OAD_Polymer** ppolymer,
128 : : OAD_V3000** pv3000);
129 : :
130 : : static int GetInChIFormulaNumH(INChI* pInChI, int* nNumH);
131 : : static int GetInChINumH(INChI* pInChI, int* nNumH);
132 : : static int GetInChIIsoH(INChI* pInChI, int nNumIsotopicH[NUM_H_ISOTOPES]);
133 : :
134 : : static int getInChIChar(INCHI_IOSTREAM* pInp);
135 : : static int AddInChIChar(INCHI_IOSTREAM* pInp, SEGM_LINE* Line, const char* pszToken);
136 : : static int AddLinkedBond(AT_NUMB at1, AT_NUMB at2, AT_NUMB num_at, LINKED_BONDS* pLB);
137 : : static int bInChIHasReconnectedMetal(INChI* pInChI);
138 : : static int SetProtonsAndXchgIsoH(int bInChI2Structure,
139 : : int bReqSplitOutputInChI,
140 : : int bReqProtonsForEachComponent,
141 : : int bReqNonTaut, int bReqStereo,
142 : : int num_components[INCHI_NUM],
143 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
144 : : InpInChI* OneInput);
145 : : #if ( FIX_DALKE_BUGS == 1 )
146 : : static int SetHillFormFromInChI(InpInChI* OneInput);
147 : : #endif
148 : :
149 : : static int nGetInChISegment(INCHI_IOSTREAM* pInp, SEGM_LINE* Line, const char* pszToken);
150 : :
151 : : static int CopySegment(INChI* pInChITo, INChI* pInChIFrom, int StereoType,
152 : : int bIsotopicTo, int bIsotopicFrom);
153 : : static int nFillOutProtonMobileH(INChI* pInChI);
154 : : static int nProtonCopyIsotopicInfo(INChI* pInChI_to, INChI* pInChI_from);
155 : : static int CopyAtomNumbers(INChI* pInChI_To, int bIsoTo, INChI* pInChI_From, int bIsoFrom);
156 : :
157 : : static int ParseSegmentFormula(const char* str, int bMobileH, INChI* pInpInChI[],
158 : : int nNumComponents[], int* na_total);
159 : : static int ParseSegmentConnections(const char* str, int bMobileH, INChI** pInpInChI,
160 : : int* pnNumComponents, int* pbAbc, int* nb_total);
161 : : static int ParseSegmentMobileH(const char* str, int bMobileH, INChI* pInpInChI[],
162 : : int pnNumComponents[], int* pbAbc);
163 : : static int ParseSegmentCharge(const char* str, int bMobileH, INChI* pInpInChI[],
164 : : int nNumComponents[]);
165 : : static int ParseSegmentProtons(const char* str, int bMobileH,
166 : : REM_PROTONS nNumProtons[], int nNumComponents[]);
167 : : static int ParseSegmentPolymer(const char* str, int bMobileH,
168 : : REM_PROTONS nNumProtons[], int nNumComponents[],
169 : : int na_total, int nb_total,
170 : : int bInchi2Struct,
171 : : OAD_Polymer** ppPolymer, OAD_V3000** ppV3000);
172 : : static int ParseSegmentSp2(const char* str, int bMobileH, INChI* pInpInChI[],
173 : : int nNumComponents[], int state, int* pbAbc);
174 : : static int ParseSegmentSp3(const char* str, int bMobileH, INChI* pInpInChI[],
175 : : int ppnNumComponents[], int state, int* pbAbc);
176 : : static int SegmentSp3CreateEmpty(const char* str, int bMobileH, INChI* pInpInChI[],
177 : : int nNumComponents, int state, int* pbAbc);
178 : : static int SegmentSp3StoreStereoCenters(int* pbAbc, const char* pStart, const char* pEnd,
179 : : int pInChI_iComponent_nNumberOfAtoms,
180 : : INChI_Stereo* PStereo_0);
181 : : static int SegmentSp3ProcessAbbreviation(int* mpy_component, int iComponent, int nNumComponents,
182 : : int val, const char* q, int state, int* pbAbc,
183 : : int bMobileH, int nCpyType,
184 : : INChI* pInChI, INChI* pInpInChI_ALT_TAUT_bMobileH);
185 : : static int SegmentSp3CopyMultiplierCovered(int mpy_component, int iComponent,
186 : : INChI* pInpInChI, int bIso, int nCpyType);
187 : : static int ParseSegmentSp3m(const char* str, int bMobileH, INChI* pInpInChI[],
188 : : int nNumComponents[], int state);
189 : : static int bIsSp3LayerNotEmpty(INChI* pInpInChI[], int bMobileH,
190 : : int bIso, int nNumComponents);
191 : : static int ParseSegmentSp3s(const char* str, int bMobileH, INChI* pInpInChI[],
192 : : int s[TAUT_NUM][2], int ppnNumComponents[], int state);
193 : : static int ParseSegmentIsoAtoms(const char* str, int bMobileH, INChI* pInpInChI[],
194 : : int nNumComponents[], int state, int* pbAbc);
195 : : static int ParseSegmentIsoExchgH(const char* str, int bMobileH,
196 : : REM_PROTONS nNumProtons[],
197 : : int nNumComponents[], int state, int* pbAbc);
198 : : static int ParseSegmentPerm(const char* str, int bMobileH, INChI* pInpInChI[],
199 : : int ppnNumComponents[], int state, int* pbAbc);
200 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
201 : : static int bIsoMayBeArranged(int bInchi2Struct, int iso_diff[NUM_H_ISOTOPES],
202 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
203 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM], int nNumComponents[INCHI_NUM][TAUT_NUM], int iINChI);
204 : : #endif
205 : :
206 : : static int ReadInChILine(INCHI_IOSTREAM* pInp,
207 : : SEGM_LINE* pLine,
208 : : char** pStr,
209 : : int* pState,
210 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
211 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
212 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
213 : : int s[INCHI_NUM][TAUT_NUM][2],
214 : : int* input_is_stdinchi,
215 : : int* input_has_save_opt,
216 : : unsigned char* input_save_opt_bits,
217 : : int bInchi2Struct,
218 : : OAD_Polymer** ppolymer,
219 : : OAD_V3000** pv3000);
220 : :
221 : : int ReadInChICoord(INCHI_IOSTREAM* pInp,
222 : : SEGM_LINE* pLine,
223 : : int* pState,
224 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
225 : : int nNumComponents[INCHI_NUM][TAUT_NUM]);
226 : :
227 : : static int OutputInChIAsRequested(struct tagCANON_GLOBALS* pCG,
228 : : INCHI_IOSTREAM* pOut,
229 : : INCHI_IOSTREAM* pLog,
230 : : ICHICONST INPUT_PARMS* ip_inp,
231 : : STRUCT_DATA* sd_inp,
232 : : InpInChI* OneInput,
233 : : int num_components[INCHI_NUM],
234 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
235 : : long num_inp,
236 : : unsigned char save_opt_bits);
237 : :
238 : : static int ParseAuxSegmentVersion(const char* str,
239 : : int bMobileH,
240 : : INChI* pInpInChI[],
241 : : int ppnNumComponents[],
242 : : int state);
243 : :
244 : : static int ParseAuxSegmentNumbers(const char* str,
245 : : int bMobileH,
246 : : INChI* pInpInChI[],
247 : : int ppnNumComponents[],
248 : : int state,
249 : : int* pbAbc);
250 : :
251 : : static int ParseAuxSegmentAtomEqu(const char* str,
252 : : int bMobileH,
253 : : INChI* pInpInChI[],
254 : : int ppnNumComponents[],
255 : : int state);
256 : :
257 : : static int ParseAuxSegmentGroupEqu(const char* str,
258 : : int bMobileH,
259 : : INChI* pInpInChI[],
260 : : int ppnNumComponents[],
261 : : int state);
262 : :
263 : : static int ParseAuxSegmentSp3Inv(const char* str,
264 : : int bMobileH,
265 : : INChI* pInpInChI[],
266 : : int ppnNumComponents[],
267 : : int state);
268 : :
269 : : static int ParseAuxSegmentSp3InvNumbers(const char* str,
270 : : int bMobileH,
271 : : INChI* pInpInChI[],
272 : : int ppnNumComponents[],
273 : : int state);
274 : :
275 : : static int ParseAuxSegmentReverseCRV(const char* str, int state);
276 : :
277 : : static int ParseAuxSegmentReverseAtoms(const char* str, int state);
278 : :
279 : : static int ParseAuxSegmentReverseBonds(const char* str, int state);
280 : :
281 : : static int ParseAuxSegmentReverseXYZ(const char* str,
282 : : XYZ_COORD** ppXYZ,
283 : : int state);
284 : :
285 : : static int AddAuxSegmentCoord(int nRet,
286 : : XYZ_COORD* pXYZ,
287 : : int nLenXYZ,
288 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
289 : : int nNumComponents[INCHI_NUM][TAUT_NUM]);
290 : :
291 : :
292 : : static void getInchiStateReadErr(int stat, char* szMsg);
293 : :
294 : : static const char* getInchiErrName(int nErr);
295 : :
296 : : static int extract_from_inchi_string(char* sinchi, InpInChI* OneInput);
297 : :
298 : : const char* ParseSegmentReadDelimitedNumbers(const char* str, const char* pEnd,
299 : : INT_ARRAY* numlist, char c_delim,
300 : : char c_stop, int* ret);
301 : :
302 : : #define SEG_END '/'
303 : : /* the following 2 definitions are used to allow tab-delimited InChI input - 2008-11-17 DT */
304 : : #define INCHI_INP_EOL(X) ((X)=='\n' || (X)=='\r' || (X)=='\t')
305 : : /*#define INCHI_TOKEN "/\n\r\t"*/
306 : : #define INCHI_TOKEN "/\n\r\t\\"
307 : :
308 : : typedef enum tagInChI_STATE
309 : : {
310 : : /* M */
311 : : IST_MOBILE_H_FORMULA, /* 0 */
312 : : IST_MOBILE_H_CONNECTIONS, /* 1 */
313 : : IST_MOBILE_H, /* 2 */
314 : : IST_MOBILE_H_CHARGE, /* 3 */
315 : : IST_MOBILE_H_PROTONS, /* 4 */
316 : : IST_MOBILE_H_SP2, /* 5 */
317 : : IST_MOBILE_H_SP3, /* 6 */
318 : : IST_MOBILE_H_SP3_M, /* 7 */
319 : : IST_MOBILE_H_SP3_S, /* 8 */
320 : :
321 : : /* Fork */
322 : : IST_MOBILE_H_ISO_LAYER_FORK, /* 9 */
323 : :
324 : : /* MI */
325 : : IST_MOBILE_H_ISO_ATOMS, /* 10 */
326 : : IST_MOBILE_H_ISO_EXCH_H, /* 11 */
327 : : IST_MOBILE_H_ISO_SP2, /* 12 */
328 : : IST_MOBILE_H_ISO_SP3, /* 13 */
329 : : IST_MOBILE_H_ISO_SP3_M, /* 14 */
330 : : IST_MOBILE_H_ISO_SP3_S, /* 15 */
331 : :
332 : : /* Fork */
333 : : IST_FIXED_H_LAYER_FORK, /* 16 */
334 : :
335 : : /* F */
336 : : IST_FIXED_H_FORMULA, /* 17 */
337 : : IST_FIXED_H, /* 18 */
338 : : IST_FIXED_H_CHARGE, /* 19 */
339 : : IST_FIXED_H_SP2, /* 20 */
340 : : IST_FIXED_H_SP3, /* 21 */
341 : : IST_FIXED_H_SP3_M, /* 22 */
342 : : IST_FIXED_H_SP3_S, /* 23 */
343 : : IST_FIXED_H_PERMUTATION, /* 24 */
344 : :
345 : : /* Fork */
346 : : IST_FIXED_H_ISO_LAYER_FORK, /* 25 */
347 : :
348 : : /* FI */
349 : : IST_FIXED_H_ISO_ATOMS, /* 26 */
350 : : IST_FIXED_H_ISO_LAYER, /* 27 */
351 : : IST_FIXED_H_ISO_SP2, /* 28 */
352 : : IST_FIXED_H_ISO_SP3, /* 29 */
353 : : IST_FIXED_H_ISO_SP3_M, /* 30 */
354 : : IST_FIXED_H_ISO_SP3_S, /* 31 */
355 : : IST_FIXED_H_ISO_PERMUTATION, /* 32 */
356 : :
357 : : /* Reconnected */
358 : : IST_RECONNECTED_LAYER_FORK, /* 33 */
359 : : IST_RECONNECTED_FORMULA, /* 34 */
360 : :
361 : : /* Other reading errors */
362 : : IST_MATERIAL_BALANCE_ERROR, /* 35 */
363 : :
364 : : /* */
365 : : IST_MOBILE_H_POLYMER, /* 36 */
366 : :
367 : : IST_END = -1
368 : : }INCHI_STATE;
369 : :
370 : :
371 : : #define IST_HAPPENED_IN_RECMET 100
372 : :
373 : :
374 : : typedef struct tagInchiReadErrMsg
375 : : {
376 : : int stat;
377 : : const char* msg;
378 : : } INCHI_READ_ERR_MSG;
379 : :
380 : : ICHICONST INCHI_READ_ERR_MSG irErrMsg[] =
381 : : {
382 : : /* M */
383 : : { IST_MOBILE_H_FORMULA, "MOBILE_H_FORMULA" },
384 : : { IST_MOBILE_H_CONNECTIONS, "MOBILE_H_CONNECTIONS" },
385 : : { IST_MOBILE_H, "MOBILE_H" },
386 : : { IST_MOBILE_H_CHARGE, "MOBILE_H_CHARGE" },
387 : : { IST_MOBILE_H_PROTONS, "MOBILE_H_PROTONS" },
388 : : { IST_MOBILE_H_SP2, "MOBILE_H_SP2" },
389 : : { IST_MOBILE_H_SP3, "MOBILE_H_SP3" },
390 : : { IST_MOBILE_H_SP3_M, "MOBILE_H_SP3_/m" },
391 : : { IST_MOBILE_H_SP3_S, "MOBILE_H_SP3_/s" },
392 : :
393 : : /* Fork */
394 : : { IST_MOBILE_H_ISO_LAYER_FORK, "MOBILE_H_ISO_LAYER_FORK" },
395 : :
396 : : /* MI */
397 : : { IST_MOBILE_H_ISO_ATOMS, "MOBILE_H_ISO_ATOMS" },
398 : : { IST_MOBILE_H_ISO_EXCH_H, "MOBILE_H_ISO_EXCH_H" },
399 : : { IST_MOBILE_H_ISO_SP2, "MOBILE_H_ISO_SP2" },
400 : : { IST_MOBILE_H_ISO_SP3, "MOBILE_H_ISO_SP3" },
401 : : { IST_MOBILE_H_ISO_SP3_M, "MOBILE_H_ISO_SP3_/m" },
402 : : { IST_MOBILE_H_ISO_SP3_S, "MOBILE_H_ISO_SP3_/s" },
403 : :
404 : : /* Fork */
405 : : { IST_FIXED_H_LAYER_FORK, "FIXED_H_LAYER_FORK" },
406 : :
407 : : /* F */
408 : : { IST_FIXED_H_FORMULA, "FIXED_H_FORMULA" },
409 : : { IST_FIXED_H, "FIXED_H" },
410 : : { IST_FIXED_H_CHARGE, "FIXED_H_CHARGE" },
411 : : { IST_FIXED_H_SP2, "FIXED_H_SP2" },
412 : : { IST_FIXED_H_SP3, "FIXED_H_SP3" },
413 : : { IST_FIXED_H_SP3_M, "FIXED_H_SP3_/m" },
414 : : { IST_FIXED_H_SP3_S, "FIXED_H_SP3_/s" },
415 : : { IST_FIXED_H_PERMUTATION, "FIXED_H_PERMUTATION" },
416 : :
417 : : /* Fork */
418 : : { IST_FIXED_H_ISO_LAYER_FORK, "FIXED_H_ISO_LAYER_FORK" },
419 : :
420 : : /* FI */
421 : : { IST_FIXED_H_ISO_ATOMS, "FIXED_H_ISO_ATOMS" },
422 : : { IST_FIXED_H_ISO_LAYER, "FIXED_H_ISO_LAYER" },
423 : : { IST_FIXED_H_ISO_SP2, "FIXED_H_ISO_SP2" },
424 : : { IST_FIXED_H_ISO_SP3, "FIXED_H_ISO_SP3" },
425 : : { IST_FIXED_H_ISO_SP3_M, "FIXED_H_ISO_SP3_m" },
426 : : { IST_FIXED_H_ISO_SP3_S, "FIXED_H_ISO_SP3_s" },
427 : : { IST_FIXED_H_ISO_PERMUTATION, "FIXED_H_ISO_PERMUTATION" },
428 : :
429 : : /* Reconnected */
430 : : { IST_RECONNECTED_LAYER_FORK, "RECONNECTED_LAYER_FORK" },
431 : : { IST_RECONNECTED_FORMULA, "RECONNECTED_FORMULA" },
432 : :
433 : : { IST_MATERIAL_BALANCE_ERROR, "MATERIAL_BALANCE" },
434 : :
435 : : { IST_MOBILE_H_POLYMER, "POLYMER_LAYER" },
436 : :
437 : : { IST_END, "Unknown Error" }
438 : : };
439 : :
440 : :
441 : :
442 : : typedef enum tagCopySegmentType
443 : : {
444 : : CPY_SP2,
445 : : CPY_SP3,
446 : : CPY_SP3_M,
447 : : CPY_SP3_S,
448 : : CPY_ISO_AT
449 : : } COPY_SEG_TYPE;
450 : :
451 : : #define NSTRLEN 524288
452 : : #define MAX_MSG_LEN 512
453 : : #define MAX_MSG_BUF_LEN 128
454 : :
455 : :
456 : : void PrepareSaveOptBits(INPUT_PARMS* ip,
457 : : INCHI_IOSTREAM* pLog,
458 : : const long num_inp,
459 : : const char* szCurHdr,
460 : : int input_has_save_opt,
461 : : unsigned char input_save_opt_bits,
462 : : unsigned char* save_opt_bits);
463 : :
464 : : void TreatErrorsInReadInChIString(int nReadStatus,
465 : : int nErr,
466 : : int pState,
467 : : INPUT_PARMS* ip,
468 : : INCHI_IOSTREAM* pOut,
469 : : INCHI_IOSTREAM* pLog,
470 : : long* num_inp,
471 : : long* num_errors,
472 : : long* num_processed,
473 : : char** pstrHdr,
474 : : char** pszCurHdr,
475 : : InpInChI* pOneInput);
476 : :
477 : : int ConvertInChI2Struct(ICHICONST INPUT_PARMS* ip_inp,
478 : : INPUT_PARMS* ip,
479 : : InpInChI* pOneInput,
480 : : inp_ATOM** at,
481 : : int* num_at,
482 : : OAD_Polymer** polymer,
483 : : OAD_V3000** v3000,
484 : : INCHI_IOSTREAM* pOut,
485 : : INCHI_IOSTREAM* pLog,
486 : : STRUCT_DATA* sd,
487 : : int num_components[INCHI_NUM],
488 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
489 : : char** pszCurHdr,
490 : : char* szMsg,
491 : : int nMsgLen,
492 : : char szMessage[MAX_MSG_LEN],
493 : : int nInitLenMessage,
494 : : int nMessageLen,
495 : : int input_is_stdinchi,
496 : : int bHasSomeReconnected,
497 : : int bHasSomeFixedH,
498 : : int bHasMetal,
499 : : int nModeFlagsStereo,
500 : : int bTautFlags,
501 : : int bReqNonTaut,
502 : : unsigned long WarningFlags[2][2],
503 : : long num_inp,
504 : : long* num_errors,
505 : : unsigned char save_opt_bits,
506 : : inchiTime* pulTStart,
507 : : long* ulProcessingTime,
508 : : struct tagINCHI_CLOCK* ic,
509 : : struct tagCANON_GLOBALS* pCG);
510 : :
511 : : int ConvertInChI2InChI(INPUT_PARMS* ip,
512 : : InpInChI* pOneInput,
513 : : INCHI_IOSTREAM* pOut,
514 : : INCHI_IOSTREAM* pLog,
515 : : STRUCT_DATA* sd,
516 : : int num_components[INCHI_NUM],
517 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
518 : : char** pszCurHdr,
519 : : long num_inp,
520 : : long* num_errors,
521 : : unsigned char save_opt_bits,
522 : : inchiTime* pulTStart,
523 : : long* ulProcessingTime,
524 : : struct tagINCHI_CLOCK* ic,
525 : : struct tagCANON_GLOBALS* pCG);
526 : :
527 : : int DetectAndExposePolymerInternals(INCHI_IOSTREAM* is);
528 : :
529 : : int DetectHiddenPolymerStuff(char* tmpstr, int tmpstrlen,
530 : : int* ninsert, int* insert_pos,
531 : : int insert_lead_offset, int* nstars);
532 : :
533 : :
534 : :
535 : : /****************************************************************************/
536 : 0 : void getInchiStateReadErr(int stat, char* szMsg)
537 : : /* const char *getInchiStateReadErr(int stat) */
538 : : {
539 : 0 : int i, bRecMet = 0;
540 : :
541 [ # # ]: 0 : if (stat >= IST_HAPPENED_IN_RECMET)
542 : : {
543 : 0 : bRecMet = 1;
544 : 0 : stat -= IST_HAPPENED_IN_RECMET;
545 : : }
546 [ # # # # ]: 0 : for (i = 0; 0 <= irErrMsg[i].stat && stat != irErrMsg[i].stat; i++)
547 : : {
548 : : ;
549 : : }
550 [ # # ]: 0 : sprintf(szMsg,
551 : : #if ( FIX_DALKE_BUGS == 1 )
552 : : "%s%.100s",
553 : : #else
554 : : "%s%s",
555 : : #endif
556 : 0 : irErrMsg[i].msg, bRecMet ? ", Reconnected layer" : "");
557 : :
558 : 0 : }
559 : :
560 : :
561 : : /****************************************************************************/
562 : 0 : const char* getInchiErrName(int nErr)
563 : : {
564 [ # # # # : 0 : switch (nErr)
# ]
565 : : {
566 : 0 : case RI_ERR_ALLOC:
567 : 0 : return "Allocation failed";
568 : 0 : case RI_ERR_PROGR:
569 : 0 : return "Program error";
570 : 0 : case RI_ERR_SYNTAX:
571 : 0 : return "Syntax error";
572 : 0 : case RI_ERR_EOL:
573 : 0 : return "End of line";
574 : : }
575 : 0 : return "Unknown error";
576 : : }
577 : :
578 : :
579 : : #if ( FIX_DALKE_BUGS == 1 )
580 : :
581 : :
582 : : /****************************************************************************/
583 : 0 : int SetHillFormFromInChI(InpInChI* OneInput)
584 : : {
585 : : int iINChI, iTaut, iComp, num_diff;
586 : : INChI* pINChI;
587 : : char* szHillFormulaOld;
588 [ # # ]: 0 : for (iINChI = 0, num_diff = 0; iINChI < INCHI_NUM; iINChI++)
589 : : {
590 [ # # ]: 0 : for (iTaut = TAUT_NON; iTaut < TAUT_NUM; iTaut++)
591 : : {
592 [ # # ]: 0 : for (iComp = 0; iComp < OneInput->nNumComponents[iINChI][iTaut]; iComp++)
593 : : {
594 : 0 : pINChI = &OneInput->pInpInChI[iINChI][iTaut][iComp];
595 [ # # # # : 0 : if (!pINChI->nNumberOfAtoms || pINChI->bDeleted || !pINChI->szHillFormula || !pINChI->szHillFormula[0])
# # # # ]
596 : : {
597 : 0 : continue;
598 : : }
599 : 0 : szHillFormulaOld = pINChI->szHillFormula;
600 : 0 : pINChI->szHillFormula = AllocateAndFillHillFormula(pINChI);
601 [ # # # # : 0 : num_diff += !pINChI->szHillFormula || !pINChI->szHillFormula[0] || strcmp(pINChI->szHillFormula, szHillFormulaOld);
# # ]
602 [ # # ]: 0 : inchi_free(szHillFormulaOld);
603 : : }
604 : : }
605 : : }
606 : :
607 : 0 : return num_diff;
608 : : }
609 : : #endif
610 : :
611 : :
612 : : /****************************************************************************
613 : : Main entry point
614 : : ****************************************************************************/
615 : 0 : int ReadWriteInChI(INCHI_CLOCK* ic,
616 : : struct tagCANON_GLOBALS* pCG,
617 : : INCHI_IOSTREAM* pInp,
618 : : INCHI_IOSTREAM* pOut,
619 : : INCHI_IOSTREAM* pLog,
620 : : INPUT_PARMS* ip_inp,
621 : : STRUCT_DATA* sd_inp,
622 : : /* the following are InChI library-specific parameters */
623 : : inp_ATOM** at,
624 : : int* num_at,
625 : : int* num_bonds,
626 : : OAD_Polymer** polymer,
627 : : OAD_V3000** v3000,
628 : : /* end of InChI library-specific parameters */
629 : : char* szMsg,
630 : : int nMsgLen,
631 : : unsigned long WarningFlags[2][2])
632 : : {
633 : : InpInChI OneInput;
634 : 0 : char* strHdr = NULL;
635 : 0 : char* szCurHdr = NULL;
636 : : int num_components[INCHI_NUM];
637 [ # # ]: 0 : int bReqNonTaut = (0 != ((ip_inp->nMode & REQ_MODE_BASIC) &&
638 [ # # ]: 0 : (ip_inp->nMode & REQ_MODE_TAUT)));
639 : : /*
640 : : int bReqRecmet = (0 != ((ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
641 : : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD)));
642 : : */
643 : 0 : int bReqStereo = (0 != (ip_inp->nMode & REQ_MODE_STEREO));
644 : 0 : int bHasSomeReconnected = 0, bHasSomeFixedH = 0, bHasMetal = 0;
645 : 0 : int nModeFlagsStereo = 0, bTautFlags = 0; /* InChI creation flags modifications derived from current InChI */
646 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM];
647 : :
648 : : NORM_CANON_FLAGS ncFlags;
649 : 0 : NORM_CANON_FLAGS* pncFlags = &ncFlags;
650 : : INPUT_PARMS ip_cur, * ip;
651 : : STRUCT_DATA sd_cur, * sd;
652 : :
653 : : int pState; /* djb-rwth: removing redundant variables */
654 : 0 : int bReqProtonsForEachComponent = 0;
655 : 0 : int bReqSplitOutputInChI = 0;
656 : : SEGM_LINE Line;
657 : 0 : SEGM_LINE* pLine = &Line;
658 : 0 : long ulProcessingTime = 0;
659 : : inchiTime ulTStart;
660 : 0 : long num_processed = 0, num_errors = 0;
661 : : int bPlainTabbedOutput; /* djb-rwth: ignoring LLVM warning: variable used */
662 : : const char* pTAB; /* djb-rwth: ignoring LLVM warning: variable used */
663 : :
664 : 0 : long num_inp = 0;
665 : :
666 : 0 : int read_inchi_ok = 0;
667 : 0 : int end_of_data_reached = 0;
668 : 0 : int treat_save_opt = 0;
669 : 0 : int input_is_stdinchi = 0;
670 : 0 : int input_has_save_opt = 0;
671 : 0 : unsigned char input_save_opt_bits = 0;
672 : 0 : unsigned char save_opt_bits = 0;
673 : :
674 : 0 : const int bInChI2Structure = 0 != (ip_inp->bReadInChIOptions & READ_INCHI_TO_STRUCTURE);
675 : 0 : const int bInChI2InChI = 0 != (ip_inp->bReadInChIOptions & READ_INCHI_OUTPUT_INCHI);
676 : 0 : const int bReadCoord = bInChI2Structure;
677 : :
678 : 0 : int nMessageLen = MAX_MSG_LEN;
679 : : char szMessage[MAX_MSG_LEN];
680 : : int nInitLenMessage;
681 : 0 : int invalid_opt = 0;
682 : : int j, nErr, iINChI;
683 : :
684 : 0 : int treat_mismatch_as_error = ip_inp->bINChIOutputOptions2 & INCHI_OUT_MISMATCH_AS_ERROR;
685 : 0 : int output_error_inchi = ip_inp->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR;
686 : :
687 : 0 : int ret = 0;
688 : 0 : int nReadStatus = RI_ERR_EOL;
689 : :
690 : 0 : INCHI_IOSTREAM* pRealOut = pOut;
691 : : /* temporary output buffer pTmpOut may be used */
692 : : /* locally instead of legal pOut to capture */
693 : : /* InChI string which may then be recognised */
694 : : /* as erratic (whence should not be finally */
695 : : /* printed) */
696 : : INCHI_IOSTREAM tmpoutputstr;
697 : 0 : INCHI_IOSTREAM* pTmpOut = &tmpoutputstr;
698 [ # # ]: 0 : if (bInChI2Structure)
699 : : {
700 : 0 : inchi_ios_init(pTmpOut, INCHI_IOS_TYPE_STRING, NULL);
701 [ # # ]: 0 : if (pTmpOut->s.pStr)
702 : 0 : pRealOut = pTmpOut;
703 : : }
704 : :
705 : : #ifdef GHI100_FIX
706 : : #if ((SPRINTF_FLAG != 1) && (SPRINTF_FLAG != 2))
707 : : setlocale(LC_ALL, "en-US"); /* djb-rwth: setting all locales to "en-US" */
708 : : #endif
709 : : #endif
710 : :
711 : 0 : memset(szMessage, 0, sizeof(szMessage)); /* djb-rwth: memset_s C11/Annex K variant? */
712 : 0 : memset(&OneInput, 0, sizeof(OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
713 : 0 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
714 [ # # ]: 0 : if (szMsg)
715 : 0 : szMsg[0] = '\0';
716 : :
717 : 0 : OneInput.polymer = NULL; /* v. 1.05 added */
718 : 0 : OneInput.v3000 = NULL;
719 : :
720 : :
721 : : /* Read input, InChI by InChI*/
722 [ # # ]: 0 : while (nReadStatus != RI_ERR_EOF)
723 : : {
724 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
725 : : {
726 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
727 : : {
728 [ # # ]: 0 : if (OneInput.nNumProtons[iINChI][j].pNumProtons)
729 : : {
730 [ # # ]: 0 : inchi_free(OneInput.nNumProtons[iINChI][j].pNumProtons);
731 : 0 : OneInput.nNumProtons[iINChI][j].pNumProtons = NULL;
732 : : }
733 : : }
734 : : }
735 : :
736 : 0 : memset(&OneInput, 0, sizeof(OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
737 : 0 : memset(pncFlags, 0, sizeof(*pncFlags)); /* djb-rwth: memset_s C11/Annex K variant? */
738 : : /* djb-rwth: removing redundant code */
739 : 0 : ip_cur = *ip_inp;
740 : 0 : ip = &ip_cur;
741 : 0 : sd_cur = *sd_inp;
742 : 0 : sd = &sd_cur;
743 : :
744 : 0 : bReqSplitOutputInChI =
745 : 0 : 0 != (ip->bReadInChIOptions & READ_INCHI_SPLIT_OUTPUT);
746 : 0 : bReqProtonsForEachComponent =
747 [ # # ]: 0 : bReqSplitOutputInChI &&
748 [ # # ]: 0 : 0 != (READ_INCHI_KEEP_BALANCE_P & ip->bReadInChIOptions);
749 : 0 : bPlainTabbedOutput =
750 : 0 : 0 != (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT);
751 : :
752 : 0 : pTAB =
753 : : #if ( defined(TARGET_API_LIB) || defined(TARGET_LIB_FOR_WINCHI) )
754 : : "\n";
755 : : #else
756 : : bPlainTabbedOutput ? "\t" : "\n";
757 : : #endif
758 : :
759 : :
760 [ # # ]: 0 : if (bInChI2Structure)
761 : : {
762 : 0 : bReqStereo = 1;
763 : 0 : bReqSplitOutputInChI = 1;
764 : 0 : bReqProtonsForEachComponent = bReqNonTaut;
765 : 0 : ip->bTautFlags |= (TG_FLAG_DISCONNECT_COORD | TG_FLAG_RECONNECT_COORD);
766 : 0 : ip->nMode |= (REQ_MODE_BASIC | REQ_MODE_TAUT | REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_ISO);
767 : : /* bReqRecmet = 1; */
768 : : #if ( bRELEASE_VERSION == 1 )
769 : 0 : bReqNonTaut = 1; /* bReqNonTaut=0 ignores Fixed-H layer in input InChI, for testing only */
770 : : #endif
771 : : /* polymer stuff added */
772 [ # # ]: 0 : if (pInp->type == INCHI_IOS_TYPE_STRING)
773 : : {
774 : : int res; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
775 : :
776 [ # # ]: 0 : if (ip_inp->lMolfileNumber)
777 : : /* get here from inchi-1 main emulation mode */
778 : 0 : num_inp = ip_inp->lMolfileNumber - 1;
779 : :
780 : 0 : res = DetectAndExposePolymerInternals(pInp); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
781 : : /* proceed silently for now, errs mist be uncovered further on conversion */
782 : : }
783 : : }
784 : :
785 : 0 : InchiTimeGet(&ulTStart);
786 : :
787 : : /* Read InChI string */
788 : 0 : nReadStatus = InChILine2Data(pInp, pLine, &strHdr, &pState, &nErr,
789 : : OneInput.pInpInChI, OneInput.nNumComponents,
790 : : OneInput.nNumProtons, OneInput.s,
791 : : bReadCoord, bInChI2Structure, ip_inp->nMode,
792 : : &input_is_stdinchi, &input_has_save_opt,
793 : : &input_save_opt_bits,
794 : : &OneInput.polymer, &OneInput.v3000);
795 : :
796 : 0 : ulProcessingTime += InchiTimeElapsed(ic, &ulTStart);
797 : :
798 : : #if 0
799 : : if (!bInChI2Structure && OneInput.polymer)
800 : : {
801 : : /* inchi2inchi for polymers: for now skip */
802 : : pState == IST_MOBILE_H_POLYMER;
803 : : nReadStatus = -2;
804 : : }
805 : : #endif
806 : :
807 : :
808 [ # # # # ]: 0 : end_of_data_reached = nReadStatus == RI_ERR_EOL || nReadStatus == RI_ERR_EOF;
809 : :
810 [ # # ]: 0 : if (!bInChI2Structure)
811 : : {
812 : : /* i2i, disable polymer related */
813 [ # # ]: 0 : if (OneInput.polymer)
814 : : {
815 : 0 : pState = IST_MOBILE_H_POLYMER;
816 : 0 : nErr = RI_ERR_PROGR;
817 : : }
818 : : }
819 : :
820 [ # # # # ]: 0 : read_inchi_ok = end_of_data_reached && !nErr;
821 : :
822 : : /* then uncommented... commented out 2020-07-10 (potentially dangerous change, needs testing (TODO: i2s for InChI=1// )*/
823 [ # # ]: 0 : read_inchi_ok = read_inchi_ok &&
824 [ # # ]: 0 : (OneInput.nNumComponents[INCHI_BAS][TAUT_YES] + OneInput.nNumComponents[INCHI_BAS][TAUT_NON]);
825 : :
826 : : #if ALLOW_EMPTY_INCHI_AS_INPUT!=1
827 : : /* no empty InChI allowed */
828 : : read_inchi_ok = read_inchi_ok &&
829 : : (OneInput.nNumComponents[INCHI_BAS][TAUT_YES] +
830 : : OneInput.nNumComponents[INCHI_BAS][TAUT_NON]);
831 : : #endif
832 : : #ifdef TARGET_EXE_STANDALONE
833 : : /* inchi-1: we currently disable conversion of polymeric InChI (inchi2struct)
834 : : to anything but SDF (would it be necessary in the future?) */
835 : : if (OneInput.polymer &&
836 : : bInChI2Structure &&
837 : : !(ip_inp->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
838 : : {
839 : : read_inchi_ok = 0;
840 : : nErr = RI_ERR_PROGR;
841 : : }
842 : : #endif
843 : :
844 [ # # ]: 0 : if (!read_inchi_ok)
845 : : {
846 : 0 : TreatErrorsInReadInChIString(nReadStatus, nErr, pState, ip_inp, pRealOut, pLog,
847 : : &num_inp, &num_errors, &num_processed,
848 : : &strHdr, &szCurHdr, &OneInput);
849 [ # # # # ]: 0 : if (nReadStatus == RI_ERR_SYNTAX || nReadStatus == RI_ERR_PROGR)
850 : : {
851 : 0 : ret = nReadStatus;
852 : : }
853 : : }
854 : : else
855 : : {
856 : : /* InChI has been successfully read */
857 : 0 : ret = 0;
858 : 0 : num_inp++;
859 : 0 : ip->lMolfileNumber = num_inp;
860 : 0 : bHasSomeReconnected = 0;
861 : 0 : bHasSomeFixedH = 0;
862 : :
863 [ # # ]: 0 : if (pRealOut == pTmpOut)
864 : : {
865 : 0 : inchi_ios_reset(pRealOut);
866 : : /*inchi_ios_close( pRealOut );
867 : : inchi_ios_init( pRealOut, INCHI_IOS_TYPE_STRING, NULL );*/
868 : : }
869 : : /* inchi_ios_print( pRealOut, ""); */
870 : :
871 : : /* Does not allow conversion non-standard->standard */
872 : : /* (force target to be non-standard also) */
873 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_STDINCHI)
874 : : {
875 [ # # ]: 0 : if (!input_is_stdinchi)
876 : : {
877 : : /* Input InChI is a non-standard one */
878 : 0 : ip->bINChIOutputOptions &= ~INCHI_OUT_STDINCHI;
879 : : /*
880 : : if (szCurHdr && szCurHdr[0])
881 : : inchi_ios_eprint( pLog, "Warning: forced conversion to non-standard InChI for non-std input, %s\n", szCurHdr );
882 : : else
883 : : inchi_ios_eprint( pLog, "Warning: forced conversion to non-standard InChI for non-std input, Structure %ld\n", num_inp );
884 : : */
885 : : }
886 : : }
887 : :
888 : :
889 : 0 : treat_save_opt = ip->bINChIOutputOptions & INCHI_OUT_SAVEOPT;
890 : :
891 [ # # ]: 0 : if (treat_save_opt)
892 : : {
893 : 0 : PrepareSaveOptBits(ip, pLog, num_inp, szCurHdr,
894 : : input_has_save_opt,
895 : : input_save_opt_bits,
896 : : &save_opt_bits);
897 : : }
898 : :
899 : : #ifndef TARGET_API_LIB
900 : : /*
901 : : inchi_ios_eprint(stderr, "%ld: %s\r", num_inp, strHdr? strHdr : "");
902 : : inchi_ios_eprint(pLog, "%ld: %s\n", num_inp, strHdr? strHdr : "");
903 : : */
904 : :
905 : : if (!ip->bNoStructLabels &&
906 : : !(bInChI2Structure && (ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
907 : : )
908 : : {
909 : : /* Added 2nd item: Do not output this extra line into the output SDfile. 2008-11-17 DCh */
910 : : if (strHdr && strstr(strHdr, "Structure:"))
911 : : {
912 : : inchi_ios_print(pRealOut, "%s%s", strHdr, pTAB); /* output header */
913 : : #if ( FIX_DALKE_BUGS == 1 )
914 : : #else
915 : : sprintf(szMessage, "%s (%ld)", strHdr ? strHdr : "", num_inp);
916 : : #endif
917 : : }
918 : : else
919 : : {
920 : : if (bInChI2Structure) inchi_ios_print(pRealOut, "Structure: %ld. (%s)%s",
921 : : num_inp, strHdr ? strHdr : "No struct name",
922 : : pTAB); /* output header */
923 : : #if ( FIX_DALKE_BUGS == 1 )
924 : : #else
925 : : sprintf(szMessage, "Structure: %ld. (%s)%s", num_inp, strHdr ? strHdr : "No struct name", pTAB);
926 : : #endif
927 : : }
928 : : if (strHdr && strHdr[0])
929 : : {
930 : : strncpy(ip->szSdfDataHeader, strHdr, sizeof(ip->szSdfDataHeader));
931 : : ip->szSdfDataHeader[sizeof(ip->szSdfDataHeader) - 1] = '\0';
932 : : ip->pSdfLabel = NULL;
933 : : ip->pSdfValue = ip->szSdfDataHeader;
934 : : }
935 : : else
936 : : {
937 : : ip->pSdfValue = NULL;
938 : : ip->szSdfDataHeader[0] = '\0';
939 : : }
940 : : }
941 : :
942 : : #if ( FIX_DALKE_BUGS == 1 )
943 : : sprintf(szMessage, "%ld: %.400s", num_inp, strHdr ? strHdr : "");
944 : : #else
945 : : sprintf(szMessage, "%ld: %s", num_inp, strHdr ? strHdr : "");
946 : : #endif
947 : : #endif
948 : :
949 : 0 : nInitLenMessage = (int)strlen(szMessage);
950 [ # # ]: 0 : if (strHdr)
951 : : {
952 : 0 : szCurHdr = strHdr;
953 : 0 : strHdr = NULL;
954 : : }
955 [ # # # # : 0 : if (szCurHdr && ip && ip->first_struct_number > 0)
# # ]
956 : : {
957 : : /* Check whether the structure should be skipped */
958 : : static const char szStruct[] = "Structure:";
959 : 0 : char* pStrNum = strstr(szCurHdr, szStruct);
960 : : long cur_struct_number;
961 [ # # ]: 0 : if (pStrNum)
962 : : {
963 : 0 : pStrNum += sizeof(szStruct) - 1; /* -1 takes care of the string terminal zero */
964 : 0 : cur_struct_number = inchi_strtol(pStrNum, NULL, 10);
965 [ # # ]: 0 : if (cur_struct_number)
966 : : {
967 : 0 : OneInput.num_inp = cur_struct_number;
968 : : }
969 : : /* Process request to bypass first several InChIs */
970 [ # # # # ]: 0 : if (cur_struct_number > 0 && cur_struct_number < ip->first_struct_number)
971 : : {
972 : :
973 : : #if ( !defined(TARGET_API_LIB) && !defined(TARGET_EXE_STANDALONE) )
974 : : inchi_fprintf(stderr, "Skipping %s\r", szMessage);
975 : : #endif
976 : 0 : FreeInpInChI(&OneInput);
977 [ # # ]: 0 : if (szCurHdr)
978 : : {
979 [ # # ]: 0 : inchi_free(szCurHdr);
980 : 0 : szCurHdr = NULL;
981 : : }
982 : : INCHI_HEAPCHK
983 : 0 : continue;
984 : : }
985 : : }
986 : : }
987 : :
988 : 0 : num_processed++;
989 : :
990 : : /* In case of splitting InChI into separate components */
991 : : /* decide whether to keep /p in each component or */
992 : : /* output /p and /i/h as a separate component */
993 : : /* Note: if InChI is not to be splitted DO NOT create */
994 : : /* a separate component for /p, /i/h: it would be a bug*/
995 : :
996 : 0 : InchiTimeGet(&ulTStart);
997 : :
998 : : INCHI_HEAPCHK
999 : :
1000 : 0 : ret = SetProtonsAndXchgIsoH(bInChI2Structure, bReqSplitOutputInChI,
1001 : : bReqProtonsForEachComponent, bReqNonTaut, bReqStereo,
1002 : : num_components, nModeProtonIsoExchgH, &OneInput);
1003 : : INCHI_HEAPCHK
1004 : :
1005 [ # # ]: 0 : if (ret < 0)
1006 : : {
1007 : 0 : num_errors++;
1008 : 0 : goto exit_error;
1009 : : }
1010 : :
1011 : 0 : sd->num_components[INCHI_BAS] = num_components[INCHI_BAS];
1012 : 0 : sd->num_components[INCHI_REC] = num_components[INCHI_REC];
1013 : :
1014 : : /* Do we have reconnected InChI ? */
1015 [ # # ]: 0 : if ((OneInput.nNumComponents[INCHI_REC][TAUT_YES] ||
1016 [ # # ]: 0 : OneInput.nNumComponents[INCHI_REC][TAUT_NON]) &&
1017 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
1018 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD)
1019 : : )
1020 : : {
1021 : : /* needed for InChI string output to include reconnected InChI */
1022 : 0 : sd->bTautFlagsDone[0] |= TG_FLAG_DISCONNECT_COORD_DONE;
1023 : 0 : bHasSomeReconnected = 1;
1024 : : }
1025 : :
1026 : : /* Do we have fixed H InChI ? */
1027 [ # # ]: 0 : if (bReqNonTaut &&
1028 : : /*OneInput.nNumComponents[bHasSomeReconnected?INCHI_REC:INCHI_BAS][TAUT_NON]*/
1029 [ # # ]: 0 : (OneInput.nNumComponents[INCHI_REC][TAUT_NON] ||
1030 [ # # ]: 0 : OneInput.nNumComponents[INCHI_BAS][TAUT_NON]))
1031 : : {
1032 : 0 : bHasSomeFixedH = 1;
1033 : : }
1034 : :
1035 : 0 : ulProcessingTime += InchiTimeElapsed(ic, &ulTStart);
1036 : :
1037 [ # # # # : 0 : invalid_opt = (!bInChI2Structure && !bInChI2InChI) ||
# # ]
1038 [ # # ]: 0 : (bInChI2Structure && bInChI2InChI);
1039 : :
1040 [ # # ]: 0 : if (invalid_opt)
1041 : : {
1042 : 0 : inchi_ios_eprint(pLog, "\nWrong command line options: expected Inch2Struct or Inchi2Inchi\n", num_inp);
1043 : 0 : break;
1044 : : }
1045 : :
1046 : : /* InChI --> Structure */
1047 [ # # ]: 0 : else if (bInChI2Structure)
1048 : : {
1049 : : char* result_string;
1050 : :
1051 [ # # # # ]: 0 : if (OneInput.polymer && OneInput.polymer->n)
1052 : : {
1053 : 0 : OneInput.valid_polymer = 1;
1054 : : }
1055 : :
1056 : 0 : ret = ConvertInChI2Struct(ip_inp, ip, &OneInput,
1057 : : at, num_at,
1058 : : polymer, v3000,
1059 : : pRealOut, pLog,
1060 : : sd, num_components, nModeProtonIsoExchgH,
1061 : : &szCurHdr, szMsg, nMsgLen, szMessage,
1062 : : nInitLenMessage, nMessageLen,
1063 : : input_is_stdinchi, bHasSomeReconnected,
1064 : : bHasSomeFixedH, bHasMetal,
1065 : : nModeFlagsStereo, bTautFlags, bReqNonTaut,
1066 : : WarningFlags, num_inp, &num_errors,
1067 : : save_opt_bits, &ulTStart, &ulProcessingTime,
1068 : : ic, pCG);
1069 : :
1070 : 0 : result_string = pRealOut->s.pStr;
1071 [ # # ]: 0 : if (ret == 0) /* no problems */
1072 : : {
1073 : : ;
1074 : : }
1075 [ # # ]: 0 : else if (ret > 0)
1076 : : {
1077 : : /* error */
1078 [ # # ]: 0 : if (output_error_inchi)
1079 : : {
1080 : : /* emit error string */
1081 : 0 : inchi_ios_eprint(pRealOut, "InChI creation Error!\n");
1082 : : }
1083 : : }
1084 [ # # ]: 0 : else if (ret < 0)
1085 : : {
1086 : : /* error or a mismatch possibly treated as error */
1087 [ # # ]: 0 : if (ret != RI_ERR_MISMATCH)
1088 : : {
1089 : 0 : goto exit_error;
1090 : : }
1091 : : else
1092 : : {
1093 [ # # ]: 0 : if (!treat_mismatch_as_error)
1094 : : {
1095 : : /* ignore mismatch, print InChI as usual */
1096 [ # # ]: 0 : if (result_string)
1097 : : {
1098 : 0 : inchi_ios_eprint(pRealOut, "%-s\n", result_string);
1099 : : }
1100 : : }
1101 : : else
1102 : : {
1103 : : /* concider mismatch an error */
1104 [ # # ]: 0 : if (!output_error_inchi)
1105 : : {
1106 : : ; /* print nothing for now*/
1107 : : }
1108 : : else
1109 : : {
1110 : : /* emit err string instead of InChI */
1111 [ # # ]: 0 : if (result_string)
1112 : : {
1113 : : /* try to preserve header if any */
1114 : 0 : char* pi = strstr(result_string, "InChI=");
1115 [ # # ]: 0 : if (pi)
1116 : : {
1117 : 0 : int np = pi - result_string;
1118 [ # # ]: 0 : if (np)
1119 : 0 : result_string[np - 1] = '\0';
1120 : 0 : inchi_ios_eprint(pRealOut, "%-s\n", result_string);
1121 : : }
1122 : : }
1123 : 0 : inchi_ios_eprint(pRealOut, "InChICreationError!\n"); /* emit err string */
1124 : : }
1125 : : }
1126 : 0 : FreeInpInChI(&OneInput);
1127 [ # # ]: 0 : if (strHdr)
1128 : : {
1129 [ # # ]: 0 : inchi_free(strHdr);
1130 : 0 : strHdr = NULL;
1131 : : }
1132 [ # # ]: 0 : if (szCurHdr)
1133 : : {
1134 [ # # ]: 0 : inchi_free(szCurHdr);
1135 : 0 : szCurHdr = NULL;
1136 : : }
1137 : : INCHI_HEAPCHK
1138 : 0 : continue;
1139 : : }
1140 : : }
1141 : : } /* ( bInChI2Structure ) */
1142 : :
1143 : :
1144 : : /* InChI --> InChI */
1145 [ # # ]: 0 : else if (bInChI2InChI)
1146 : : {
1147 : 0 : ret = ConvertInChI2InChI(ip, &OneInput, pRealOut, pLog, sd,
1148 : : num_components, nModeProtonIsoExchgH,
1149 : : &szCurHdr, num_inp, &num_errors,
1150 : : save_opt_bits, &ulTStart,
1151 : : &ulProcessingTime, ic, pCG);
1152 : : }
1153 : :
1154 [ # # ]: 0 : if (nReadStatus == RI_ERR_EOF)
1155 : : #if ( FIX_ONE_LINE_INCHI_INPUT_CONVERSION_ISSUE==1 && defined(TARGET_EXE_STANDALONE) && !defined(TARGET_API_LIB) )
1156 : : {
1157 : : inchi_ios_flush(pRealOut);
1158 : : inchi_ios_flush2(pLog, stderr);
1159 : : break;
1160 : : }
1161 : : #else
1162 : 0 : break;
1163 : : #endif
1164 : : } /* InChI has been successfully read */
1165 : :
1166 : :
1167 : : #ifdef TARGET_EXE_STANDALONE
1168 : : #ifndef TARGET_API_LIB
1169 : : inchi_ios_flush(pRealOut);
1170 : : inchi_ios_flush2(pLog, stderr);
1171 : : #endif
1172 : : #endif
1173 : : #ifdef TARGET_API_LIB
1174 : 0 : break; /* exit after the 1st structure */
1175 : : #endif
1176 : : } /* while */
1177 : :
1178 : 0 : exit_error:
1179 : 0 : FreeInpInChI(&OneInput);
1180 [ # # ]: 0 : if (strHdr)
1181 : : {
1182 [ # # ]: 0 : inchi_free(strHdr);
1183 : 0 : strHdr = NULL;
1184 : : }
1185 [ # # ]: 0 : if (pLine->str)
1186 : : {
1187 [ # # ]: 0 : inchi_free(pLine->str);
1188 : : }
1189 [ # # ]: 0 : if (szCurHdr)
1190 : : {
1191 [ # # ]: 0 : inchi_free(szCurHdr);
1192 : 0 : szCurHdr = NULL;
1193 : : }
1194 : :
1195 : : INCHI_HEAPCHK
1196 : :
1197 [ # # ]: 0 : if (sd_inp)
1198 : : {
1199 : 0 : sd_inp->ulStructTime = ulProcessingTime;
1200 : 0 : sd_inp->fPtrStart = num_processed;
1201 : 0 : sd_inp->fPtrEnd = num_errors;
1202 : : }
1203 [ # # ]: 0 : if (pRealOut == pTmpOut)
1204 : : {
1205 : 0 : inchi_ios_close(pTmpOut);
1206 : : }
1207 : :
1208 : 0 : return ret;
1209 : : }
1210 : :
1211 : :
1212 : : /****************************************************************************/
1213 : 0 : int OutputInChIAsRequested(struct tagCANON_GLOBALS* pCG,
1214 : : INCHI_IOSTREAM* pOut,
1215 : : INCHI_IOSTREAM* pLog,
1216 : : ICHICONST INPUT_PARMS* ip_inp,
1217 : : STRUCT_DATA* sd_inp,
1218 : : InpInChI* OneInput,
1219 : : int num_components[INCHI_NUM],
1220 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
1221 : : long num_inp,
1222 : : unsigned char save_opt_bits)
1223 : : {
1224 : 0 : int j, k, k1, k2, ret2 = 0, iINChI, iINChI1; /* djb-rwth: removing redundant variables */
1225 : : PINChI2* pINChI[INCHI_NUM], * newPTR1;
1226 : : PINChI_Aux2* pINChI_Aux[INCHI_NUM], * newPTR2;
1227 : : int bReqNonTaut;
1228 : : int bHasSomeReconnected;
1229 : :
1230 : : INPUT_PARMS ip_local;
1231 : : STRUCT_DATA sd_local;
1232 : 0 : INPUT_PARMS* ip = &ip_local;
1233 : 0 : STRUCT_DATA* sd = &sd_local;
1234 : : NORM_CANON_FLAGS ncFlags;
1235 : 0 : NORM_CANON_FLAGS* pncFlags = &ncFlags;
1236 : : int nRet1, bSortPrintINChIFlags;
1237 : : int bReqSplitOutputInChI;
1238 : : int nNumOutputComponents;
1239 : :
1240 : : INCHI_IOS_STRING temp_string_container;
1241 : 0 : INCHI_IOS_STRING* strbuf = &temp_string_container;
1242 : 0 : memset(strbuf, 0, sizeof(*strbuf)); /* djb-rwth: memset_s C11/Annex K variant? */
1243 : :
1244 [ # # ]: 0 : if (0 >= inchi_strbuf_init(strbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT))
1245 : : {
1246 : 0 : ret2 = RI_ERR_ALLOC;
1247 : 0 : goto exit_error;
1248 : : }
1249 : :
1250 : 0 : nRet1 = 0;
1251 : 0 : k1 = k2 = 0;
1252 : 0 : memset(pncFlags, 0, sizeof(*pncFlags)); /* djb-rwth: memset_s C11/Annex K variant? */
1253 : 0 : memset(pINChI, 0, sizeof(pINChI)); /* djb-rwth: memset_s C11/Annex K variant? */
1254 : 0 : memset(pINChI_Aux, 0, sizeof(pINChI_Aux)); /* djb-rwth: memset_s C11/Annex K variant? */
1255 : :
1256 : 0 : *ip = *ip_inp;
1257 : 0 : *sd = *sd_inp;
1258 : 0 : bHasSomeReconnected = 0;
1259 : 0 : bSortPrintINChIFlags = 0;
1260 : : /* djb-rwth: removing redundant code */
1261 : 0 : bReqNonTaut = (0 != (ip->nMode & REQ_MODE_BASIC));
1262 : 0 : bReqSplitOutputInChI = (0 != (ip->bReadInChIOptions & READ_INCHI_SPLIT_OUTPUT));
1263 : :
1264 : : INCHI_HEAPCHK
1265 : :
1266 [ # # ]: 0 : if (num_components[INCHI_BAS])
1267 : : {
1268 : : /* djb-rwth: MYREALLOC2( PINChI2, PINChI_Aux2, pINChI[INCHI_BAS], pINChI_Aux[INCHI_BAS], num_components[INCHI_BAS], (long long)num_components[INCHI_BAS], k1 ); has been replaced and the whole block rewritten to address memory leaks and reading from freed memory locations */
1269 : :
1270 : : do {
1271 : : if ((num_components[INCHI_BAS]) <= ((long long)num_components[INCHI_BAS]))
1272 : : {
1273 : 0 : newPTR1 = (PINChI2*)inchi_calloc(((long long)num_components[INCHI_BAS]) + 1, sizeof(PINChI2));
1274 : 0 : newPTR2 = (PINChI_Aux2*)inchi_calloc(((long long)num_components[INCHI_BAS]) + 1, sizeof(PINChI_Aux2));
1275 [ # # # # ]: 0 : if (newPTR1 && newPTR2) {
1276 [ # # # # ]: 0 : if ((pINChI[INCHI_BAS]) && (num_components[INCHI_BAS]) > 0)
1277 : 0 : memcpy(newPTR1, (pINChI[INCHI_BAS]), (num_components[INCHI_BAS]) * sizeof(PINChI2));
1278 [ # # # # ]: 0 : if ((pINChI_Aux[INCHI_BAS]) && (num_components[INCHI_BAS]) > 0)
1279 : 0 : memcpy(newPTR2, (pINChI_Aux[INCHI_BAS]), (num_components[INCHI_BAS]) * sizeof(PINChI_Aux2));
1280 [ # # ]: 0 : if (pINChI[INCHI_BAS])
1281 [ # # ]: 0 : inchi_free(pINChI[INCHI_BAS]);
1282 [ # # ]: 0 : if (pINChI_Aux[INCHI_BAS])
1283 [ # # ]: 0 : inchi_free(pINChI_Aux[INCHI_BAS]);
1284 : 0 : pINChI[INCHI_BAS] = newPTR1;
1285 : 0 : pINChI_Aux[INCHI_BAS] = newPTR2;
1286 : 0 : num_components[INCHI_BAS] = (long long)num_components[INCHI_BAS];
1287 : 0 : k1 = 0;
1288 : : }
1289 : : else
1290 : : {
1291 [ # # ]: 0 : inchi_free(newPTR1);
1292 [ # # ]: 0 : inchi_free(newPTR2);
1293 : 0 : k1 = 1;
1294 : : }
1295 : : }
1296 : : else { k1 = 0; }
1297 : : } while (0);
1298 : : }
1299 : :
1300 [ # # ]: 0 : if (num_components[INCHI_REC])
1301 : : {
1302 : : /* djb-rwth: MYREALLOC2( PINChI2, PINChI_Aux2, pINChI[INCHI_REC], pINChI_Aux[INCHI_REC], num_components[INCHI_REC], (long long)num_components[INCHI_REC], k2 ); has been replaced and the whole block rewritten to address memory leaks and reading from freed memory locations */
1303 : :
1304 : : do {
1305 : : if ((num_components[INCHI_REC]) <= ((long long)num_components[INCHI_REC]))
1306 : : {
1307 : 0 : newPTR1 = (PINChI2*)inchi_calloc(((long long)num_components[INCHI_REC]) + 1, sizeof(PINChI2));
1308 : 0 : newPTR2 = (PINChI_Aux2*)inchi_calloc(((long long)num_components[INCHI_REC]) + 1, sizeof(PINChI_Aux2));
1309 [ # # # # ]: 0 : if (newPTR1 && newPTR2) {
1310 [ # # # # ]: 0 : if ((pINChI[INCHI_REC]) && (num_components[INCHI_REC]) > 0)
1311 : 0 : memcpy(newPTR1, (pINChI[INCHI_REC]), (num_components[INCHI_REC]) * sizeof(PINChI2));
1312 [ # # # # ]: 0 : if ((pINChI_Aux[INCHI_REC]) && (num_components[INCHI_REC]) > 0)
1313 : 0 : memcpy(newPTR2, (pINChI_Aux[INCHI_REC]), (num_components[INCHI_REC]) * sizeof(PINChI_Aux2));
1314 [ # # ]: 0 : if (pINChI[INCHI_REC])
1315 [ # # ]: 0 : inchi_free(pINChI[INCHI_REC]);
1316 [ # # ]: 0 : if (pINChI_Aux[INCHI_REC])
1317 [ # # ]: 0 : inchi_free(pINChI_Aux[INCHI_REC]);
1318 : 0 : pINChI[INCHI_REC] = newPTR1;
1319 : 0 : pINChI_Aux[INCHI_REC] = newPTR2;
1320 : 0 : num_components[INCHI_REC] = (long long)num_components[INCHI_REC];
1321 : 0 : k2 = 0;
1322 : : }
1323 : : else
1324 : : {
1325 [ # # ]: 0 : inchi_free(newPTR1);
1326 [ # # ]: 0 : inchi_free(newPTR2);
1327 : 0 : k2 = 1;
1328 : : }
1329 : : }
1330 : : else { k2 = 0; }
1331 : : } while (0);
1332 : : }
1333 : :
1334 : :
1335 : : INCHI_HEAPCHK
1336 : :
1337 [ # # # # ]: 0 : if (k1 || k2 /*|| !pStr*/)
1338 : : {
1339 : : /* djb-rwth: avoiding memory leak */
1340 : 0 : free(pINChI[INCHI_BAS]);
1341 : 0 : free(pINChI_Aux[INCHI_BAS]);
1342 : 0 : free(pINChI[INCHI_REC]);
1343 : 0 : free(pINChI_Aux[INCHI_REC]);
1344 : 0 : ret2 = RI_ERR_ALLOC;
1345 : 0 : goto exit_error;
1346 : : }
1347 : :
1348 [ # # ]: 0 : if (num_components[INCHI_REC] &&
1349 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
1350 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD))
1351 : : {
1352 : 0 : sd->bTautFlagsDone[0] |= TG_FLAG_DISCONNECT_COORD_DONE;
1353 : 0 : bHasSomeReconnected = 1;
1354 : : }
1355 : :
1356 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1357 : : {
1358 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1359 : : {
1360 [ # # # # : 0 : if (bReqNonTaut || (j != TAUT_NON && OneInput->pInpInChI[iINChI][j])) /* djb-rwth: addressing LLVM warning */
# # ]
1361 : : {
1362 [ # # ]: 0 : for (k = 0; k < num_components[iINChI]; k++)
1363 : : {
1364 : : /* allocate InChI & AuxInfo */
1365 [ # # ]: 0 : if (!(pINChI[iINChI][k][j] = (INChI*)inchi_calloc(1, sizeof(INChI))))
1366 : : {
1367 : : /* djb-rwth: avoiding memory leak */
1368 : 0 : free(pINChI[INCHI_BAS]);
1369 : 0 : free(pINChI_Aux[INCHI_BAS]);
1370 : 0 : free(pINChI[INCHI_REC]);
1371 : 0 : free(pINChI_Aux[INCHI_REC]);
1372 : 0 : ret2 = RI_ERR_ALLOC;
1373 : 0 : goto exit_error;
1374 : : }
1375 [ # # ]: 0 : if (!(pINChI_Aux[iINChI][k][j] = (INChI_Aux*)inchi_calloc(1, sizeof(INChI_Aux))))
1376 : : {
1377 : : /* djb-rwth: avoiding memory leak */
1378 : 0 : free(pINChI[INCHI_BAS]);
1379 : 0 : free(pINChI_Aux[INCHI_BAS]);
1380 : 0 : free(pINChI[INCHI_REC]);
1381 : 0 : free(pINChI_Aux[INCHI_REC]);
1382 : 0 : ret2 = RI_ERR_ALLOC;
1383 : 0 : goto exit_error;
1384 : : }
1385 : : /* copy InChI & AuxInfo */
1386 [ # # ]: 0 : if (k < OneInput->nNumComponents[iINChI][j])
1387 : : {
1388 : :
1389 : : /* copy InChI */
1390 : 0 : *pINChI[iINChI][k][j] = OneInput->pInpInChI[iINChI][j][k];
1391 : 0 : memset(&OneInput->pInpInChI[iINChI][j][k], 0, sizeof(OneInput->pInpInChI[iINChI][j][k])); /* djb-rwth: memset_s C11/Annex K variant? */
1392 : : INCHI_HEAPCHK
1393 : : /* take care of protons in AuxInfo */
1394 : :
1395 [ # # # # ]: 0 : if (nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_EACH && j == TAUT_YES)
1396 : : {
1397 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedProtons =
1398 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons[k].nNumRemovedProtons;
1399 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
1400 : : {
1401 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedIsotopicH[k1] =
1402 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons[k].nNumRemovedIsotopicH[k1];
1403 : : }
1404 : : INCHI_HEAPCHK
1405 : : }
1406 [ # # # # ]: 0 : else if ((!k && nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_FIRST) ||
1407 [ # # ]: 0 : (k + 1 == OneInput->nNumComponents[iINChI][j] &&
1408 [ # # ]: 0 : nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_A_PIXH_COMPONENT)) /* djb-rwth: addressing LLVM warnings */
1409 : : {
1410 : : /* add protons and exchangeable isotopic H to the first component's AuxInfo */
1411 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedProtons = OneInput->nNumProtons[iINChI][j].nNumRemovedProtons;
1412 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
1413 : : {
1414 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedIsotopicH[k1] =
1415 : 0 : OneInput->nNumProtons[iINChI][j].nNumRemovedIsotopicH[k1];
1416 : : }
1417 : : INCHI_HEAPCHK
1418 : : }
1419 : : else
1420 : : {
1421 : 0 : pINChI_Aux[iINChI][k][j]->bDeleted = pINChI[iINChI][k][j]->bDeleted;
1422 : : }
1423 : :
1424 [ # # # # : 0 : if (j == TAUT_YES && pINChI[iINChI][k][j] && pINChI[iINChI][k][j]->nNumberOfAtoms &&
# # ]
1425 [ # # ]: 0 : !pINChI[iINChI][k][j]->nNum_H_fixed)
1426 : : {
1427 : : /* serializer crashes if it is not allocated */
1428 : 0 : pINChI[iINChI][k][j]->nNum_H_fixed = (S_CHAR*)inchi_calloc((long long)pINChI[iINChI][k][j]->nNumberOfAtoms + 1, sizeof(pINChI[0][0][0]->nNum_H_fixed[0])); /* djb-rwth: cast operator added */
1429 : : }
1430 : :
1431 [ # # # # ]: 0 : if (j == TAUT_YES && k < OneInput->nNumComponents[iINChI][TAUT_NON] &&
1432 [ # # # # ]: 0 : pINChI[iINChI][k][j] && pINChI[iINChI][k][j]->nNumberOfAtoms &&
1433 [ # # # # : 0 : pINChI[iINChI][k][TAUT_NON] && pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms &&
# # ]
1434 : 0 : !CompareReversedINChI(pINChI[iINChI][k][j], pINChI[iINChI][k][TAUT_NON], NULL, NULL))
1435 : : {
1436 : 0 : pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms = 0; /* eliminate non-taut equal to taut */
1437 : : }
1438 : : }
1439 : : else
1440 : : {
1441 : : /* extra component, usually it is a Mobile H component */
1442 : : /* corresponding to a free proton component in Fixed H */
1443 : 0 : pINChI[iINChI][k][j]->bDeleted = 1;
1444 : 0 : pINChI_Aux[iINChI][k][j]->bDeleted = 1;
1445 : : }
1446 : : } /* k */
1447 : : } /* if ( bReqNonTaut || j != TAUT_NON && OneInput->pInpInChI[iINChI][j] ) */
1448 : :
1449 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j])
1450 : : {
1451 : : INCHI_HEAPCHK
1452 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
1453 : 0 : OneInput->pInpInChI[iINChI][j] = NULL;
1454 : : }
1455 : : } /* j */
1456 : : } /* iINChI */
1457 : :
1458 [ # # ]: 0 : if (bReqSplitOutputInChI)
1459 : : {
1460 [ # # ]: 0 : if (bHasSomeReconnected)
1461 : : {
1462 : 0 : iINChI1 = INCHI_REC; /* only reconnected */
1463 : : /* djb-rwth: removing redundant code */
1464 : 0 : sd->num_components[INCHI_BAS] = sd->num_components[INCHI_REC];
1465 : : }
1466 : : else
1467 : : {
1468 : 0 : iINChI1 = 0; /* only disconnected */
1469 : : /* djb-rwth: removing redundant code */
1470 : : }
1471 : 0 : sd->num_components[INCHI_REC] = 0; /* treat reconnected as connected */
1472 : 0 : nNumOutputComponents = sd->num_components[INCHI_BAS];
1473 : : }
1474 : : else
1475 : : {
1476 : 0 : iINChI1 = 0;
1477 : : /* djb-rwth: removing redundant code */
1478 : 0 : nNumOutputComponents = 1;
1479 : : }
1480 : :
1481 [ # # # # : 0 : for (k1 = 0, k2 = (bReqSplitOutputInChI ? k1 + 1 : nNumOutputComponents); k1 < k2 && k1 < nNumOutputComponents; k1 = k2, k2++)
# # ]
1482 : : {
1483 : :
1484 [ # # ]: 0 : if (bReqSplitOutputInChI)
1485 : : {
1486 : 0 : sd->num_components[INCHI_BAS] = 1;
1487 : 0 : sd->num_components[INCHI_REC] = 0;
1488 : : /* additional data */
1489 : 0 : sd->num_non_taut[INCHI_BAS] =
1490 : 0 : sd->num_taut[INCHI_BAS] =
1491 : 0 : sd->num_non_taut[INCHI_REC] =
1492 : 0 : sd->num_taut[INCHI_REC] = 0;
1493 : 0 : iINChI = iINChI1;
1494 [ # # # # ]: 0 : for (j = 0; j < TAUT_NUM && sd->num_components[iINChI]; j++)
1495 : : {
1496 [ # # ]: 0 : for (k = k1; k < k2; k++)
1497 : : {
1498 : : /* find where the current processed structure is located */
1499 [ # # # # ]: 0 : int cur_is_in_non_taut = (pINChI[iINChI][k][TAUT_NON] && pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms > 0);
1500 [ # # # # ]: 0 : int cur_is_in_taut = (pINChI[iINChI][k][TAUT_YES] && pINChI[iINChI][k][TAUT_YES]->nNumberOfAtoms > 0);
1501 [ # # # # : 0 : int cur_is_non_taut = (cur_is_in_non_taut && 0 == pINChI[iINChI][k][TAUT_NON]->lenTautomer) ||
# # ]
1502 [ # # ]: 0 : (cur_is_in_taut && 0 == pINChI[iINChI][k][TAUT_YES]->lenTautomer); /* djb-rwth: addressing LLVM warnings */
1503 [ # # # # ]: 0 : int cur_is_taut = cur_is_in_taut && 0 < pINChI[iINChI][k][TAUT_YES]->lenTautomer;
1504 [ # # ]: 0 : if (cur_is_non_taut + cur_is_taut)
1505 : : {
1506 : : /* count tautomeric and non-tautomeric components of the structures */
1507 : : /*
1508 : : int j1 = cur_is_in_non_taut? TAUT_NON:TAUT_YES;
1509 : : int j2 = cur_is_in_taut? TAUT_YES:TAUT_NON;
1510 : : */
1511 : 0 : sd->num_non_taut[INCHI_BAS] += cur_is_non_taut;
1512 : 0 : sd->num_taut[INCHI_BAS] += cur_is_taut;
1513 : : }
1514 : : }
1515 : : }
1516 : : INCHI_HEAPCHK
1517 : : }
1518 : : else
1519 : : {
1520 : 0 : sd->num_components[INCHI_BAS] = inchi_max(OneInput->nNumComponents[INCHI_BAS][TAUT_YES],
1521 : : OneInput->nNumComponents[INCHI_BAS][TAUT_NON]);
1522 : 0 : sd->num_components[INCHI_REC] = inchi_max(OneInput->nNumComponents[INCHI_REC][TAUT_YES],
1523 : : OneInput->nNumComponents[INCHI_REC][TAUT_NON]);
1524 : : /* additional data needed for SortAndPrintINChI() */
1525 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1526 : : {
1527 : 0 : sd->num_non_taut[iINChI] =
1528 : 0 : sd->num_taut[iINChI] = 0;
1529 [ # # # # ]: 0 : for (j = 0; j < TAUT_NUM && sd->num_components[iINChI]; j++)
1530 : : {
1531 [ # # ]: 0 : for (k = k1; k < k2; k++)
1532 : : {
1533 : : /* find where the current processed structure is located */
1534 [ # # # # ]: 0 : int cur_is_in_non_taut = (pINChI[iINChI][k][TAUT_NON] && pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms > 0);
1535 [ # # # # ]: 0 : int cur_is_in_taut = (pINChI[iINChI][k][TAUT_YES] && pINChI[iINChI][k][TAUT_YES]->nNumberOfAtoms > 0);
1536 [ # # # # : 0 : int cur_is_non_taut = (cur_is_in_non_taut && 0 == pINChI[iINChI][k][TAUT_NON]->lenTautomer) ||
# # ]
1537 [ # # ]: 0 : (cur_is_in_taut && 0 == pINChI[iINChI][k][TAUT_YES]->lenTautomer); /* djb-rwth: addressing LLVM warnings */
1538 [ # # # # ]: 0 : int cur_is_taut = cur_is_in_taut && 0 < pINChI[iINChI][k][TAUT_YES]->lenTautomer;
1539 [ # # ]: 0 : if (cur_is_non_taut + cur_is_taut)
1540 : : {
1541 : : /* count tautomeric and non-tautomeric components of the structures */
1542 : : /*
1543 : : int j1 = cur_is_in_non_taut? TAUT_NON:TAUT_YES;
1544 : : int j2 = cur_is_in_taut? TAUT_YES:TAUT_NON;
1545 : : */
1546 : 0 : sd->num_non_taut[iINChI] += cur_is_non_taut;
1547 : 0 : sd->num_taut[iINChI] += cur_is_taut;
1548 : : }
1549 : : }
1550 : : }
1551 : : }
1552 : : INCHI_HEAPCHK
1553 : : }
1554 [ # # ]: 0 : if (bReqSplitOutputInChI)
1555 : : {
1556 : : /* output components one by one (for splitting input InChI into components) */
1557 : : PINChI2* pInChI_2[INCHI_NUM];
1558 : : PINChI_Aux2* pInChI_Aux_2[INCHI_NUM];
1559 : : INChI* pInChI_1[1][2];
1560 : : INChI_Aux* pInChI_Aux_1[1][2];
1561 : 0 : memset(pInChI_2, 0, sizeof(pInChI_2)); /* djb-rwth: memset_s C11/Annex K variant? */
1562 : 0 : memset(pInChI_Aux_2, 0, sizeof(pInChI_Aux_2)); /* djb-rwth: memset_s C11/Annex K variant? */
1563 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1564 : : {
1565 : 0 : pInChI_1[0][j] = pINChI[iINChI1][k1][j];
1566 : 0 : pInChI_Aux_1[0][j] = pINChI_Aux[iINChI1][k1][j];
1567 : : }
1568 : 0 : pInChI_2[INCHI_BAS] = pInChI_1;
1569 : 0 : pInChI_Aux_2[INCHI_BAS] = pInChI_Aux_1;
1570 : : /* make sure purely reconnected InChI is marked as ReChI, not InChI */
1571 [ # # # # ]: 0 : if (bHasSomeReconnected &&
1572 [ # # ]: 0 : (bInChIHasReconnectedMetal(pInChI_1[0][TAUT_YES]) ||
1573 : 0 : bInChIHasReconnectedMetal(pInChI_1[0][TAUT_NON])))
1574 : : {
1575 : 0 : bSortPrintINChIFlags = FLAG_SORT_PRINT_ReChI_PREFIX;
1576 : : }
1577 : : else
1578 : : {
1579 : 0 : bSortPrintINChIFlags = 0;
1580 : : }
1581 : : INCHI_HEAPCHK
1582 : 0 : nRet1 = SortAndPrintINChI(pCG, pOut, strbuf, pLog, ip,
1583 : : NULL /*orig_inp_data*/,
1584 : : NULL /*prep_inp_data*/,
1585 : : NULL /*composite_norm_data*/,
1586 : : NULL /*pOrigStruct*/,
1587 : 0 : sd->num_components, sd->num_non_taut,
1588 : 0 : sd->num_taut, sd->bTautFlags,
1589 : 0 : sd->bTautFlagsDone, pncFlags, num_inp,
1590 : : pInChI_2, pInChI_Aux_2,
1591 : : &bSortPrintINChIFlags, save_opt_bits);
1592 : : INCHI_HEAPCHK
1593 : : }
1594 : : else
1595 : : {
1596 : : INCHI_HEAPCHK
1597 : :
1598 : 0 : bSortPrintINChIFlags = 0;
1599 : 0 : nRet1 = SortAndPrintINChI(pCG, pOut, strbuf, pLog, ip,
1600 : : NULL /*orig_inp_data*/, NULL /*prep_inp_data*/,
1601 : : NULL /*composite_norm_data*/, NULL /*pOrigStruct*/,
1602 : 0 : sd->num_components, sd->num_non_taut, sd->num_taut,
1603 : 0 : sd->bTautFlags, sd->bTautFlagsDone, pncFlags, num_inp,
1604 : : pINChI, pINChI_Aux, &bSortPrintINChIFlags,
1605 : : save_opt_bits);
1606 : : INCHI_HEAPCHK
1607 : : }
1608 [ # # # # ]: 0 : if (nRet1 == _IS_FATAL || nRet1 == _IS_ERROR)
1609 : : {
1610 : : break;
1611 : : }
1612 : : }
1613 : :
1614 : : INCHI_HEAPCHK
1615 : 0 : FreeAllINChIArrays(pINChI, pINChI_Aux, num_components);
1616 : : INCHI_HEAPCHK
1617 : :
1618 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1619 : : {
1620 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1621 : : {
1622 [ # # ]: 0 : if (OneInput->nNumProtons[iINChI][j].pNumProtons)
1623 : : {
1624 [ # # ]: 0 : inchi_free(OneInput->nNumProtons[iINChI][j].pNumProtons);
1625 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons = NULL;
1626 : : }
1627 : : }
1628 : : }
1629 : :
1630 : : INCHI_HEAPCHK
1631 : :
1632 [ # # # # ]: 0 : if (nRet1 == _IS_FATAL || nRet1 == _IS_ERROR)
1633 : : {
1634 : 0 : ret2 = RI_ERR_PROGR;
1635 : : }
1636 : :
1637 : 0 : exit_error:
1638 : :
1639 : 0 : inchi_strbuf_close(strbuf);
1640 : :
1641 : 0 : return ret2;
1642 : : }
1643 : :
1644 : :
1645 : : /****************************************************************************/
1646 : 0 : int GetNumNeighborsFromInchi(INChI* pInChI, AT_NUMB nAtNumber)
1647 : : {
1648 : : int i, j, n_vertex, n_neigh, nNumNeigh, bTautAtom, nNumH, nTotNumNeigh, num_atoms;
1649 : : AT_NUMB taut_at_number;
1650 : 0 : nAtNumber -= 1;
1651 : 0 : nNumNeigh = 0; /* number of bonds */
1652 : 0 : bTautAtom = 0; /* 1 if atom belongs to a Mobile-H group */
1653 : 0 : nNumH = 0; /* number of terminal neighbors H */
1654 : 0 : num_atoms = 0; /* djb-rwth: initialisation with pInChI below */
1655 : :
1656 [ # # ]: 0 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
1657 : : {
1658 : 0 : num_atoms = pInChI->nNumberOfAtoms;
1659 : : /* from RestoreAtomConnectionsSetStereo() */
1660 : : /* Connection table structure:
1661 : : Vert(1) [, Neigh(11), Neigh(12),...], Vert(2) [, Neigh(2,1), Neigh(2,2),...] ...
1662 : : where Neigh(i,1) < Neigh(i,2) <... < Vert(i);
1663 : : Vert(i) < Vert(i+1)
1664 : : */
1665 [ # # ]: 0 : for (i = 1, n_vertex = pInChI->nConnTable[0] - 1; i < pInChI->lenConnTable; i++)
1666 : : {
1667 [ # # ]: 0 : if ((n_neigh = pInChI->nConnTable[i] - 1) < n_vertex)
1668 : : {
1669 : : /* vertex - neighbor connection */
1670 [ # # # # ]: 0 : nNumNeigh += (nAtNumber == n_vertex || nAtNumber == n_neigh);
1671 : : }
1672 : : else
1673 : : {/* n_neigh is the next vertex */
1674 [ # # ]: 0 : if ((n_vertex = n_neigh) >= num_atoms)
1675 : : {
1676 : 0 : return RI_ERR_PROGR;
1677 : : }
1678 : : }
1679 : : }
1680 : : }
1681 : :
1682 : :
1683 : : /* is atom tautomeric, from GetTgroupInfoFromInChI() */
1684 [ # # # # : 0 : if (pInChI && pInChI->lenTautomer > 1 && pInChI->nTautomer && pInChI->nTautomer[0] > 0)
# # # # ]
1685 : : {
1686 : : int itg, len_tg;
1687 : 0 : int tot_len_tg = pInChI->lenTautomer - T_GROUP_HDR_LEN * pInChI->nTautomer[0] - 1; /* number of endpoints */
1688 : 0 : j = 1; /* index in pInChI->nTautomer[] */
1689 : 0 : i = 0; /* index in ti->nEndpointAtomNumber[] */
1690 [ # # ]: 0 : for (itg = 0; itg < pInChI->nTautomer[0]; itg++)
1691 : : {
1692 : 0 : len_tg = pInChI->nTautomer[j]; /* t-group length not including pInChI->nTautomer[j] */
1693 : 0 : j += T_GROUP_HDR_LEN; /* skip t-group header */
1694 : 0 : len_tg -= T_GROUP_HDR_LEN - 1;
1695 [ # # ]: 0 : for (; 0 < len_tg--; j++, i++)
1696 : : {
1697 : 0 : taut_at_number = pInChI->nTautomer[j] - 1; /* Mobile-H group atom number */
1698 : 0 : bTautAtom += (taut_at_number == nAtNumber);
1699 : : }
1700 : : }
1701 [ # # ]: 0 : if (i != tot_len_tg)
1702 : : {
1703 : 0 : return RI_ERR_PROGR;
1704 : : }
1705 : : }
1706 : : /* count hydrogen neighbors */
1707 [ # # # # ]: 0 : if (pInChI && pInChI->nNum_H) /* djb-rwth: condition added for fixing a NULL pointer dereference */
1708 : : {
1709 : 0 : nNumH = pInChI->nNum_H[nAtNumber];
1710 : : }
1711 : : /* conclusion: if not tautomeric then return positive number, otherwise add 1000 */
1712 : 0 : nTotNumNeigh = nNumNeigh + nNumH;
1713 [ # # ]: 0 : if (bTautAtom)
1714 : : {
1715 : 0 : nTotNumNeigh += 1000;
1716 : : }
1717 : 0 : return nTotNumNeigh;
1718 : :
1719 : : }
1720 : :
1721 : :
1722 : : /****************************************************************************/
1723 : 0 : int CountStereoTypes(INChI* pInChI,
1724 : : int* num_known_SB,
1725 : : int* num_known_SC,
1726 : : int* num_unk_und_SB,
1727 : : int* num_unk_und_SC,
1728 : : int* num_SC_PIII,
1729 : : int* num_SC_AsIII)
1730 : : {
1731 : : INChI_Stereo* Stereo;
1732 : : int i, ret;
1733 : : AT_NUMB nAtNumber;
1734 : : U_CHAR el_number;
1735 : :
1736 [ # # # # ]: 0 : if (!pInChI->nNumberOfAtoms || pInChI->bDeleted)
1737 : : {
1738 : 0 : return 0; /* no InChI */
1739 : : }
1740 : 0 : Stereo = (pInChI->StereoIsotopic &&
1741 : 0 : (pInChI->StereoIsotopic->nNumberOfStereoBonds +
1742 [ # # # # ]: 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters)) ? pInChI->StereoIsotopic :
1743 : 0 : (pInChI->Stereo &&
1744 : 0 : (pInChI->Stereo->nNumberOfStereoBonds +
1745 [ # # # # ]: 0 : pInChI->Stereo->nNumberOfStereoCenters)) ? pInChI->Stereo : NULL;
1746 [ # # ]: 0 : if (!Stereo)
1747 : : {
1748 : 0 : return 1; /* No Stereo */
1749 : : }
1750 : :
1751 : : /* count SB and cumulenes */
1752 [ # # ]: 0 : for (i = 0; i < Stereo->nNumberOfStereoBonds; i++)
1753 : : {
1754 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(Stereo->b_parity[i]))
1755 : : {
1756 : 0 : (*num_known_SB)++;
1757 : : }
1758 : : else
1759 : : {
1760 : 0 : (*num_unk_und_SB)++;
1761 : : }
1762 : : }
1763 : : /* count SC and allenes */
1764 [ # # ]: 0 : for (i = 0; i < Stereo->nNumberOfStereoCenters; i++)
1765 : : {
1766 [ # # # # ]: 0 : if (!(nAtNumber = Stereo->nNumber[i]) || nAtNumber > pInChI->nNumberOfAtoms)
1767 : : {
1768 : 0 : return RI_ERR_PROGR; /* wrong data, should never happen */
1769 : : }
1770 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(Stereo->t_parity[i]))
1771 : : {
1772 : 0 : (*num_known_SC)++;
1773 : : }
1774 : : else
1775 : : {
1776 : 0 : (*num_unk_und_SC)++;
1777 : : }
1778 : 0 : el_number = pInChI->nAtom[nAtNumber - 1];
1779 [ # # # # ]: 0 : if (el_number != EL_NUMBER_P && el_number != EL_NUMBER_AS)
1780 : : {
1781 : 0 : continue;
1782 : : }
1783 : 0 : ret = GetNumNeighborsFromInchi(pInChI, nAtNumber);
1784 [ # # ]: 0 : if (ret < 0)
1785 : : {
1786 : 0 : return ret;
1787 : : }
1788 [ # # ]: 0 : if (3 == ret)
1789 : : {
1790 : 0 : *num_SC_PIII += (EL_NUMBER_P == el_number);
1791 : 0 : *num_SC_AsIII += (EL_NUMBER_AS == el_number);
1792 : : }
1793 : : }
1794 : :
1795 : 0 : return 2; /* Has Stereo */
1796 : : }
1797 : :
1798 : :
1799 : : /****************************************************************************/
1800 : 0 : int bInpInchiComponentExists(InpInChI* pOneInput,
1801 : : int iInChI,
1802 : : int bMobileH,
1803 : : int k)
1804 : : {
1805 [ # # # # : 0 : if ((INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
# # ]
1806 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1807 : : {
1808 : 0 : return 0;
1809 : : }
1810 : :
1811 : 0 : return (k < pOneInput->nNumComponents[iInChI][bMobileH] &&
1812 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH] &&
1813 [ # # # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].nNumberOfAtoms > 0 &&
1814 [ # # ]: 0 : !pOneInput->pInpInChI[iInChI][bMobileH][k].bDeleted);
1815 : : }
1816 : :
1817 : :
1818 : : /****************************************************************************/
1819 : 0 : int bInpInchiComponentDeleted(InpInChI* pOneInput,
1820 : : int iInChI,
1821 : : int bMobileH,
1822 : : int k)
1823 : : {
1824 [ # # # # : 0 : if ((INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
# # ]
1825 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1826 : : {
1827 : 0 : return 0;
1828 : : }
1829 : :
1830 : 0 : return (k < pOneInput->nNumComponents[iInChI][bMobileH] &&
1831 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH] &&
1832 [ # # # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].nNumberOfAtoms > 0 &&
1833 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].bDeleted);
1834 : : }
1835 : :
1836 : :
1837 : : /****************************************************************************/
1838 : 0 : int bRevInchiComponentExists(StrFromINChI* pStruct,
1839 : : int iInChI,
1840 : : int bMobileH,
1841 : : int k)
1842 : : {
1843 [ # # # # : 0 : if (!pStruct || /*!pStruct->at2 ||*/ !pStruct->num_atoms ||
# # ]
1844 [ # # # # ]: 0 : (INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
1845 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1846 : : {
1847 : 0 : return 0;
1848 : : }
1849 : :
1850 : 0 : return (k < pStruct->RevInChI.num_components[iInChI] &&
1851 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI] &&
1852 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH] &&
1853 [ # # # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->nNumberOfAtoms > 0 &&
1854 [ # # ]: 0 : !pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->bDeleted);
1855 : : }
1856 : :
1857 : :
1858 : : /****************************************************************************/
1859 : 0 : int bRevInchiComponentDeleted(StrFromINChI* pStruct,
1860 : : int iInChI,
1861 : : int bMobileH,
1862 : : int k)
1863 : : {
1864 [ # # # # : 0 : if (!pStruct || /*!pStruct->at2 ||*/ !pStruct->num_atoms ||
# # ]
1865 [ # # # # ]: 0 : (INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
1866 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1867 : : {
1868 : 0 : return 0;
1869 : : }
1870 : :
1871 : 0 : return (k < pStruct->RevInChI.num_components[iInChI] &&
1872 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI] &&
1873 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH] &&
1874 [ # # # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->nNumberOfAtoms > 0 &&
1875 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->bDeleted);
1876 : : }
1877 : :
1878 : :
1879 : : /****************************************************************************/
1880 : 0 : int DetectInpInchiCreationOptions(InpInChI* pOneInput,
1881 : : int* bHasReconnected,
1882 : : int* bHasMetal,
1883 : : int* bHasFixedH,
1884 : : int* nModeFlagsStereo,
1885 : : int* bTautFlagsStereo)
1886 : : {
1887 : 0 : int ret = 0, bHasStereo;
1888 : 0 : int nModeFlagsValue = 0, bTautFlagsValue; /* stereo flags */
1889 : : int iInChI, iMobileH, bIso, k, max_components, num_components;
1890 : : INChI* pInChI;
1891 : : int num_known_SB /*Stereo Bonds & Cumulenes >C==C==C==C< */;
1892 : : int num_known_SC /* Stereo Centers & Allenes >C=C=C< */;
1893 : : int num_unk_und_SB, num_unk_und_SC;
1894 : : int num_SC_PIII, num_SC_AsIII; /* has Phosphine or Arsine stereo center(s) */
1895 : :
1896 : 0 : *bHasReconnected = *bHasFixedH = *nModeFlagsStereo = *bTautFlagsStereo = 0;
1897 : 0 : nModeFlagsValue = bTautFlagsValue = bHasStereo = 0;
1898 : 0 : num_known_SB = num_known_SC = num_unk_und_SB = num_unk_und_SC = num_SC_PIII = num_SC_AsIII = 0;
1899 : 0 : *bHasMetal = 0;
1900 : :
1901 [ # # ]: 0 : for (iInChI = 0; iInChI < INCHI_NUM; iInChI++)
1902 : : {
1903 [ # # ]: 0 : for (iMobileH = 0; iMobileH < TAUT_NUM; iMobileH++)
1904 : : {
1905 [ # # # # ]: 0 : for (bIso = 1; !nModeFlagsValue && 0 <= bIso; bIso--)
1906 : : {
1907 [ # # # # ]: 0 : switch (pOneInput->s[iInChI][iMobileH][bIso])
1908 : : {
1909 : 0 : case 1: /* SABS */
1910 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO;
1911 : 0 : break;
1912 : 0 : case 2:
1913 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_RELATIVE_STEREO;
1914 : 0 : break;
1915 : 0 : case 3:
1916 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_RACEMIC_STEREO;
1917 : : }
1918 : : }
1919 : :
1920 : 0 : max_components = pOneInput->pInpInChI[iInChI][iMobileH] ?
1921 [ # # ]: 0 : pOneInput->nNumComponents[iInChI][iMobileH] : 0;
1922 : :
1923 [ # # ]: 0 : for (k = num_components = 0; k < max_components; k++)
1924 : : {
1925 : 0 : pInChI = pOneInput->pInpInChI[iInChI][iMobileH] + k;
1926 : 0 : ret = CountStereoTypes(pInChI,
1927 : : &num_known_SB, &num_known_SC,
1928 : : &num_unk_und_SB, &num_unk_und_SC,
1929 : : &num_SC_PIII, &num_SC_AsIII);
1930 [ # # ]: 0 : if (ret < 0)
1931 : : {
1932 : 0 : return ret; /* error */
1933 : : }
1934 : 0 : bHasStereo += (ret == 2);
1935 [ # # ]: 0 : if ((ret > 0))
1936 : : {
1937 : : /* ret == 0 => Empty InChI, 1=> No Stereo, 2=> Has Stereo */
1938 : 0 : num_components++;
1939 : 0 : *bHasReconnected |= (iInChI == INCHI_REC);
1940 : 0 : *bHasFixedH |= (iMobileH == TAUT_NON);
1941 : : }
1942 : 0 : *bHasMetal |= bInChIHasReconnectedMetal(pInChI);
1943 : : }
1944 : : }
1945 : : }
1946 : :
1947 [ # # # # ]: 0 : if ((nModeFlagsValue & REQ_MODE_RELATIVE_STEREO) && (nModeFlagsValue & REQ_MODE_RACEMIC_STEREO))
1948 : : {
1949 : 0 : return RI_ERR_SYNTAX;
1950 : : }
1951 [ # # # # ]: 0 : if (bHasStereo && !nModeFlagsValue) /* REQ_MODE_SB_IGN_ALL_UU | REQ_MODE_SC_IGN_ALL_UU*/
1952 : : {
1953 : : /* inversion does not change the stereo or no stereo at all */
1954 : 0 : nModeFlagsValue = REQ_MODE_STEREO | REQ_MODE_ISO_STEREO; /* Abs */
1955 : : }
1956 : :
1957 [ # # # # ]: 0 : if (!num_known_SB && num_unk_und_SB)
1958 : : {
1959 : : ; /* full SUU option or SB part of it */
1960 : : }
1961 : : else
1962 : : {
1963 : 0 : nModeFlagsValue |= REQ_MODE_SB_IGN_ALL_UU; /* ignore Unknown/Undefind SB if no well-defined SB exist */
1964 : : }
1965 : :
1966 [ # # # # ]: 0 : if (!num_known_SC && num_unk_und_SC)
1967 : : {
1968 : : ; /* full SUU option or SB part of it */
1969 : : }
1970 : : else
1971 : : {
1972 : 0 : nModeFlagsValue |= REQ_MODE_SC_IGN_ALL_UU; /* ignore Unknown/Undefind SC if no well-defined SB exist */
1973 : : }
1974 : : /* Phosphine and Arsine Stereo */
1975 [ # # ]: 0 : if (num_SC_PIII)
1976 : : {
1977 : 0 : bTautFlagsValue |= TG_FLAG_PHOSPHINE_STEREO;
1978 : : }
1979 : : /* Phosphine and Arsine Stereo */
1980 [ # # ]: 0 : if (num_SC_AsIII)
1981 : : {
1982 : 0 : bTautFlagsValue |= TG_FLAG_ARSINE_STEREO;
1983 : : }
1984 : :
1985 : 0 : *nModeFlagsStereo = nModeFlagsValue;
1986 : 0 : *bTautFlagsStereo = bTautFlagsValue;
1987 : :
1988 : 0 : return 0;
1989 : : }
1990 : :
1991 : :
1992 : : /****************************************************************************/
1993 : 0 : int bInChIHasReconnectedMetal(INChI* pInChI)
1994 : : {
1995 : : int i;
1996 [ # # # # : 0 : if (pInChI && !pInChI->bDeleted && pInChI->nNumberOfAtoms && pInChI->nAtom)
# # # # ]
1997 : : {
1998 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
1999 : : {
2000 [ # # ]: 0 : if (is_el_a_metal((int)pInChI->nAtom[i]))
2001 : : {
2002 [ # # # # : 0 : if (pInChI->nNumberOfAtoms > 1 || (pInChI->nNum_H && pInChI->nNum_H[0])) /* djb-rwth: addressing LLVM warning */
# # ]
2003 : : {
2004 : 0 : return 1;
2005 : : }
2006 : : }
2007 : : }
2008 : : }
2009 : :
2010 : 0 : return 0;
2011 : : }
2012 : :
2013 : :
2014 : : /****************************************************************************/
2015 : 0 : int SetProtonsAndXchgIsoH(int bInChI2Structure,
2016 : : int bReqSplitOutputInChI,
2017 : : int bReqProtonsForEachComponent,
2018 : : int bReqNonTaut,
2019 : : int bReqStereo,
2020 : : int num_components[INCHI_NUM],
2021 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
2022 : : InpInChI* OneInput)
2023 : : {
2024 : 0 : int j, k, k1, ret2 = 0, iINChI;
2025 : : int bAvailableProtonsForEachComponent, bAvailableProtonsTotal;
2026 : :
2027 : : INCHI_HEAPCHK
2028 : :
2029 : 0 : num_components[INCHI_BAS] = num_components[INCHI_REC] = 0;
2030 : :
2031 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
2032 : : {
2033 : 0 : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_UNDEFINED;
2034 : : /* are totals of /p and/or /i/h available ? */
2035 : 0 : bAvailableProtonsTotal = 0 != OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
2036 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
2037 : : {
2038 : 0 : bAvailableProtonsTotal |= 0 != OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[k1];
2039 : : }
2040 : : /* are /p and/or /i/h available for each component ? */
2041 : 0 : bAvailableProtonsForEachComponent = (NULL != OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2042 : :
2043 : : /* decision: add /p to each component, add total to the 1st, add total as one more component */
2044 : : /* In case of bInChI2Structure just keep totals if not available for each component */
2045 : :
2046 [ # # ]: 0 : if (bInChI2Structure)
2047 : : {
2048 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsForEachComponent ?
2049 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2050 : : MODE_PIXH_KEEP_TOTALS;
2051 : : }
2052 : : else
2053 : : {
2054 [ # # ]: 0 : if (!bReqSplitOutputInChI)
2055 : : {
2056 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsForEachComponent ?
2057 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2058 : : MODE_PIXH_ADD_TO_FIRST;
2059 : : }
2060 : : else
2061 : : {
2062 [ # # ]: 0 : if (!bAvailableProtonsForEachComponent)
2063 : : {
2064 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsTotal ?
2065 [ # # ]: 0 : MODE_PIXH_ADD_A_PIXH_COMPONENT :
2066 : : MODE_PIXH_ADD_TO_FIRST;
2067 : : }
2068 : : else
2069 : : {
2070 : : /* bAvailableProtonsForEachComponent && bReqSplitOutputInChI */
2071 [ # # ]: 0 : if (bReqProtonsForEachComponent)
2072 : : {
2073 : 0 : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_ADD_TO_EACH;
2074 : : }
2075 : : else
2076 : : {
2077 : 0 : nModeProtonIsoExchgH[iINChI] = bReqNonTaut ?
2078 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2079 : : MODE_PIXH_ADD_A_PIXH_COMPONENT;
2080 : : }
2081 : : }
2082 : : }
2083 : : }
2084 : :
2085 : : /* remove unneeded data: protons for each component */
2086 [ # # ]: 0 : if (bAvailableProtonsForEachComponent &&
2087 [ # # ]: 0 : nModeProtonIsoExchgH[iINChI] != MODE_PIXH_ADD_TO_EACH)
2088 : : {
2089 [ # # ]: 0 : inchi_free(OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2090 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons = NULL;
2091 : 0 : bAvailableProtonsForEachComponent = 0;
2092 : : }
2093 : : /* remove unneeded data: total protons all components */
2094 [ # # # # ]: 0 : if (bAvailableProtonsTotal && nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_EACH)
2095 : : {
2096 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons = 0;
2097 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
2098 : : {
2099 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[k1] = 0;
2100 : : }
2101 : : /* djb-rwth: removing redundant code */
2102 : : }
2103 : : /* remove unneeded data: Fixed-H InChI; no protons data exist for Fixed-H */
2104 [ # # # # ]: 0 : if (!bReqNonTaut && OneInput->nNumComponents[iINChI][TAUT_NON])
2105 : : {
2106 : 0 : j = TAUT_NON;
2107 [ # # ]: 0 : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2108 : : {
2109 : 0 : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2110 : : }
2111 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
2112 : 0 : OneInput->pInpInChI[iINChI][j] = NULL;
2113 : 0 : OneInput->nNumComponents[iINChI][j] = 0;
2114 : : }
2115 : : #ifdef NEVER
2116 : : /* remove unneeded data: Mobile-H InChI ????? */
2117 : : if (bReqNonTaut && OneInput->nNumComponents[iINChI][TAUT_NON])
2118 : : {
2119 : : j = TAUT_YES;
2120 : : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2121 : : {
2122 : : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2123 : : }
2124 : : inchi_free(OneInput->pInpInChI[iINChI][j]);
2125 : : OneInput->pInpInChI[iINChI][j] = NULL;
2126 : : OneInput->nNumComponents[iINChI][j] = 0;
2127 : : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_UNDEFINED;
2128 : : if (OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons)
2129 : : {
2130 : : inchi_free(OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2131 : : OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons = NULL;
2132 : : }
2133 : : }
2134 : : #endif
2135 : : /* add one more component containing only /p and /i/h */
2136 [ # # ]: 0 : if ((nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_A_PIXH_COMPONENT &&
2137 [ # # # # ]: 0 : OneInput->nNumComponents[iINChI][TAUT_YES]) ||
2138 : : /* always add one deleted component if no non-taut InChI is available */
2139 [ # # ]: 0 : (bInChI2Structure && !bAvailableProtonsForEachComponent &&
2140 [ # # ]: 0 : !OneInput->nNumComponents[iINChI][TAUT_NON] &&
2141 [ # # ]: 0 : OneInput->nNumComponents[iINChI][TAUT_YES])) /* djb-rwth: addressing LLVM warnings */
2142 : : {
2143 : 0 : int nPrevLen, nLen = 0;
2144 : 0 : j = TAUT_YES;
2145 : 0 : nPrevLen = OneInput->nNumComponents[iINChI][j];
2146 [ # # ]: 0 : for (k = 0; k < nPrevLen; k++)
2147 : : {
2148 : 0 : nLen += !OneInput->pInpInChI[iINChI][j][k].bDeleted;
2149 : : }
2150 [ # # ]: 0 : if (nLen == nPrevLen)
2151 : : {
2152 : : /* add one more component */
2153 : 0 : INChI* pInChI = (INChI*)inchi_calloc((long long)nLen + 1, sizeof(*pInChI)); /* djb-rwth: cast operator added */
2154 [ # # ]: 0 : if (!pInChI)
2155 : : {
2156 : 0 : ret2 = RI_ERR_ALLOC;
2157 : 0 : goto exit_error;
2158 : : }
2159 : 0 : memcpy(pInChI, OneInput->pInpInChI[iINChI][j], nLen * sizeof(*pInChI));
2160 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
2161 : 0 : OneInput->pInpInChI[iINChI][j] = pInChI;
2162 : : }
2163 : 0 : OneInput->nNumComponents[iINChI][j] = nLen + 1;
2164 : :
2165 [ # # ]: 0 : for (k = nLen; k < nPrevLen; k++)
2166 : : {
2167 : 0 : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2168 : 0 : memset(&OneInput->pInpInChI[iINChI][j][k], 0, sizeof(OneInput->pInpInChI[iINChI][j][k])); /* djb-rwth: memset_s C11/Annex K variant? */
2169 : : }
2170 : : /* mark the last component as a proton */
2171 [ # # ]: 0 : if (0 > (ret2 = nFillOutProtonMobileH(OneInput->pInpInChI[iINChI][j] + nLen)))
2172 : : {
2173 : 0 : goto exit_error;
2174 : : }
2175 : : }
2176 : : INCHI_HEAPCHK
2177 : :
2178 : : /* remove unneeded Stereo and/or Fixed H */
2179 [ # # ]: 0 : if (!bReqStereo)
2180 : : {
2181 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
2182 : : {
2183 [ # # ]: 0 : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2184 : : {
2185 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j][k].Stereo)
2186 : : {
2187 : 0 : Free_INChI_Stereo(OneInput->pInpInChI[iINChI][j][k].Stereo);
2188 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j][k].Stereo);
2189 : 0 : OneInput->pInpInChI[iINChI][j][k].Stereo = NULL;
2190 : : }
2191 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j][k].StereoIsotopic)
2192 : : {
2193 : 0 : Free_INChI_Stereo(OneInput->pInpInChI[iINChI][j][k].StereoIsotopic);
2194 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j][k].StereoIsotopic);
2195 : 0 : OneInput->pInpInChI[iINChI][j][k].StereoIsotopic = NULL;
2196 : : }
2197 : : INCHI_HEAPCHK
2198 : : }
2199 : : }
2200 : : }
2201 : :
2202 : : }
2203 : :
2204 : 0 : num_components[INCHI_BAS] = inchi_max(OneInput->nNumComponents[INCHI_BAS][TAUT_YES],
2205 : : OneInput->nNumComponents[INCHI_BAS][TAUT_NON]);
2206 : 0 : num_components[INCHI_REC] = inchi_max(OneInput->nNumComponents[INCHI_REC][TAUT_YES],
2207 : : OneInput->nNumComponents[INCHI_REC][TAUT_NON]);
2208 : :
2209 : 0 : exit_error:
2210 : 0 : return ret2;
2211 : : }
2212 : :
2213 : :
2214 : : /****************************************************************************/
2215 : 0 : int GetInChIFormulaNumH(INChI* pInChI, int* nNumH)
2216 : : { /* get number of H including bridging hydrogen atoms */
2217 : : const char* p, * q;
2218 : 0 : *nNumH = 0;
2219 [ # # ]: 0 : if (pInChI->szHillFormula)
2220 : : {
2221 [ # # ]: 0 : for (p = strchr(pInChI->szHillFormula, 'H'); p; p = strchr(p, 'H'))
2222 : : {
2223 : 0 : p++;
2224 [ # # ]: 0 : if (!islower(UCINT * p))
2225 : : {
2226 : : /* found hydrogen in the formula */
2227 [ # # ]: 0 : if (isdigit(UCINT * p))
2228 : : {
2229 : : #if ( CHECK_STRTOL_ATNUMB==1 )
2230 : 0 : int delta = (int)inchi_strtol(p, &q, 10);
2231 [ # # # # ]: 0 : if (delta > MAX_ATOMS || delta < 0)
2232 : : {
2233 : 0 : return RI_ERR_SYNTAX; /* syntax error */
2234 : : }
2235 : 0 : *nNumH += delta;
2236 : : #else
2237 : : * nNumH += (int)inchi_strtol(p, &q, 10);
2238 : : #endif
2239 : 0 : p = q;
2240 : : }
2241 : : else
2242 : : {
2243 : 0 : *nNumH += 1;
2244 : : }
2245 : : }
2246 : : }
2247 : : }
2248 : :
2249 : 0 : return 0;
2250 : : }
2251 : :
2252 : :
2253 : : /****************************************************************************/
2254 : 0 : int GetInChINumH(INChI* pInChI, int* nNumH)
2255 : : {
2256 : : int i, j, nNumTautGroups, iTautGroup, nTautGroupLen, lenTautomer;
2257 : 0 : *nNumH = 0;
2258 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
2259 : : {
2260 : 0 : *nNumH += (pInChI->nAtom[i] == EL_NUMBER_H); /* bridging H */
2261 : 0 : *nNumH += pInChI->nNum_H[i];
2262 : : }
2263 : : /* earlier nNum_H_fixed[] should have been added to pInChI->nNum_H[] */
2264 : : /*
2265 : : if ( pInChI->nNum_H_fixed ) {
2266 : : for ( i = 0; i < pInChI->nNumberOfAtoms; i ++ ) {
2267 : : *nNumH += pInChI->nNum_H_fixed[i];
2268 : : }
2269 : : }
2270 : : */
2271 [ # # # # ]: 0 : if (pInChI->lenTautomer > 3 && pInChI->nTautomer)
2272 : : {
2273 : 0 : lenTautomer = pInChI->lenTautomer;
2274 : 0 : j = 0;
2275 : 0 : nNumTautGroups = pInChI->nTautomer[j++];
2276 [ # # # # ]: 0 : for (iTautGroup = 0; j < lenTautomer && iTautGroup < nNumTautGroups; iTautGroup++, j += nTautGroupLen)
2277 : : {
2278 : 0 : nTautGroupLen = pInChI->nTautomer[j] + 1;
2279 : 0 : *nNumH += pInChI->nTautomer[j + 1];
2280 : : }
2281 [ # # # # ]: 0 : if (iTautGroup != nNumTautGroups || j != lenTautomer)
2282 : : {
2283 : 0 : return RI_ERR_PROGR;
2284 : : }
2285 : : }
2286 [ # # # # : 0 : if (pInChI->nNum_H_fixed && (pInChI->lenTautomer || pInChI->nTautomer))
# # ]
2287 : : {
2288 : 0 : return RI_ERR_PROGR;
2289 : : }
2290 : :
2291 : 0 : return 0;
2292 : : }
2293 : :
2294 : :
2295 : : /****************************************************************************/
2296 : 0 : int GetInChIIsoH(INChI* pInChI, int nNumIsotopicH[NUM_H_ISOTOPES])
2297 : : {
2298 : : int i;
2299 [ # # ]: 0 : for (i = 0; i < NUM_H_ISOTOPES; i++)
2300 : : {
2301 : 0 : nNumIsotopicH[i] = 0;
2302 : : }
2303 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfIsotopicAtoms; i++)
2304 : : {
2305 [ # # ]: 0 : if (pInChI->IsotopicAtom[i].nIsoDifference > 0 &&
2306 [ # # ]: 0 : pInChI->IsotopicAtom[i].nIsoDifference <= NUM_H_ISOTOPES)
2307 : : {
2308 [ # # ]: 0 : if (!pInChI->nAtom ||
2309 [ # # ]: 0 : !pInChI->IsotopicAtom[i].nAtomNumber ||
2310 [ # # ]: 0 : pInChI->IsotopicAtom[i].nAtomNumber > pInChI->nNumberOfAtoms)
2311 : : {
2312 : 0 : return RI_ERR_PROGR;
2313 : : }
2314 [ # # ]: 0 : if (pInChI->nAtom[pInChI->IsotopicAtom[i].nAtomNumber - 1] == (AT_NUMB)EL_NUMBER_H)
2315 : : {
2316 : : /* isotopic H in connection table */
2317 : 0 : nNumIsotopicH[pInChI->IsotopicAtom[i].nIsoDifference - 1]++;
2318 : : }
2319 : : }
2320 : 0 : nNumIsotopicH[0] += pInChI->IsotopicAtom[i].nNum_H;
2321 : 0 : nNumIsotopicH[1] += pInChI->IsotopicAtom[i].nNum_D;
2322 : 0 : nNumIsotopicH[2] += pInChI->IsotopicAtom[i].nNum_T;
2323 : : }
2324 : :
2325 : 0 : return 0;
2326 : : }
2327 : :
2328 : :
2329 : : /****************************************************************************/
2330 : : typedef struct tagNumElem
2331 : : {
2332 : : int num;
2333 : : /*
2334 : : int iso;
2335 : : */
2336 : : } NUM_ELEM;
2337 : :
2338 : :
2339 : : /****************************************************************************
2340 : : Read a single InChI input Line and convert to data
2341 : : ****************************************************************************/
2342 : 0 : int InChILine2Data(INCHI_IOSTREAM* pInp,
2343 : : SEGM_LINE* pLine,
2344 : : char** pStr,
2345 : : int* pState,
2346 : : int* nErr,
2347 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
2348 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
2349 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
2350 : : int s[INCHI_NUM][TAUT_NUM][2],
2351 : : int bReadCoord,
2352 : : int bInchi2Struct,
2353 : : INCHI_MODE nMode,
2354 : : int* bStdFormat,
2355 : : int* input_has_save_opt,
2356 : : unsigned char* input_save_opt_bits,
2357 : : OAD_Polymer** ppolymer,
2358 : : OAD_V3000** pv3000)
2359 : : {
2360 : 0 : int iINChI, i, j, k, m, len1, len2, ret2 = 0, retAux = 0, stateAux = 0; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2361 : : int ret, tot_charge[INCHI_NUM][TAUT_NUM];
2362 : : int i1, i2, i3;
2363 : : int kc;
2364 : : NUM_ELEM* num_elem[INCHI_NUM][TAUT_NUM];
2365 : :
2366 : :
2367 : : #if ( FIX_I2I_STEREOCONVERSION_BUG == 1 )
2368 : : /* (2008-03-06) 1=> Fix bug of i2i conversion SAbs-->(SRel||Srac) */
2369 : : /* (converter does not placed proper stereo to output) */
2370 : :
2371 : : /* set new stereo type as requested by conversion option */
2372 : 0 : int target_stereo_type = 1;
2373 [ # # ]: 0 : if (nMode & REQ_MODE_RELATIVE_STEREO)
2374 : : {
2375 : 0 : target_stereo_type = 2;
2376 : : }
2377 [ # # ]: 0 : else if (nMode & REQ_MODE_RACEMIC_STEREO)
2378 : : {
2379 : 0 : target_stereo_type = 3;
2380 : : }
2381 : : #endif
2382 : :
2383 : 0 : memset(num_elem, 0, sizeof(num_elem)); /* djb-rwth: memset_s C11/Annex K variant? */
2384 : :
2385 : 0 : ret = ReadInChILine(pInp, pLine, pStr, pState, pInpInChI,
2386 : : nNumComponents, nNumProtons, s, bStdFormat,
2387 : : input_has_save_opt, input_save_opt_bits,
2388 : : bInchi2Struct, ppolymer, pv3000);
2389 : :
2390 : : #if ( FIX_I2I_STEREOCONVERSION_BUG == 1 )
2391 : : /* modify stereo type for layers as requested */
2392 [ # # ]: 0 : if (target_stereo_type > 1)
2393 : : {
2394 [ # # ]: 0 : for (i1 = 0; i1 < INCHI_NUM; i1++)
2395 : : {
2396 [ # # ]: 0 : for (i2 = 0; i2 < TAUT_NUM; i2++)
2397 : : {
2398 [ # # ]: 0 : for (i3 = 0; i3 < 2; i3++)
2399 : : {
2400 [ # # ]: 0 : if (s[i1][i2][i3] != 0)
2401 : : {
2402 [ # # ]: 0 : if (target_stereo_type != 1)
2403 : : {
2404 : : /* do not allow conversion SRel=>SAbs, SRac=>SAbs */
2405 : 0 : s[i1][i2][i3] = target_stereo_type;
2406 : : }
2407 : : }
2408 : : }
2409 : : }
2410 : : }
2411 : : }
2412 : : #endif
2413 : :
2414 : 0 : * nErr = 0;
2415 : :
2416 [ # # ]: 0 : if ((ret == RI_ERR_EOL) &&
2417 : 0 : nNumComponents[INCHI_BAS][TAUT_YES]
2418 [ # # # # ]: 0 : + nNumComponents[INCHI_BAS][TAUT_NON] && bReadCoord)
2419 : : {
2420 : 0 : retAux = ReadInChICoord(pInp, pLine, &stateAux, pInpInChI, nNumComponents); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2421 : : }
2422 : :
2423 [ # # # # ]: 0 : if ((ret == RI_ERR_EOL || ret == RI_ERR_EOF) &&
2424 : 0 : nNumComponents[INCHI_BAS][TAUT_YES]
2425 [ # # ]: 0 : + nNumComponents[INCHI_BAS][TAUT_NON])
2426 : : {
2427 : : /* post-processing: add omitted layers */
2428 : 0 : *pState = IST_MATERIAL_BALANCE_ERROR;
2429 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
2430 : : {
2431 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
2432 : : {
2433 : : /* for Mobile/Fixed H (j) ... */
2434 : : int bIsotopic, bStereoType, bStereoTypeAlt;
2435 : 0 : int nMH2FH_AltInv = 0, nFH2iFH_AltInv = 0 /*, niMH2iFH_AltInv=0, nMH2iMH_AltInv=0*/;
2436 [ # # ]: 0 : int jAlt = ALT_TAUT(j);
2437 : 0 : INCHI_MODE nFlags = 0, nFlagsAlt = 0;
2438 : : /* get stereo type: ABS, REL, RAC, or nothing */
2439 : 0 : tot_charge[iINChI][j] = 0;
2440 [ # # ]: 0 : for (bIsotopic = bStereoType = bStereoTypeAlt = 0; bIsotopic < 2; bIsotopic++)
2441 : : {
2442 [ # # # # ]: 0 : if (!bStereoType || bStereoType < s[iINChI][j][bIsotopic])
2443 : : {
2444 : 0 : bStereoType = s[iINChI][j][bIsotopic];
2445 : : }
2446 [ # # # # ]: 0 : if (!bStereoTypeAlt || bStereoTypeAlt < s[iINChI][jAlt][bIsotopic])
2447 : : {
2448 : 0 : bStereoTypeAlt = s[iINChI][jAlt][bIsotopic];
2449 : : }
2450 [ # # # # ]: 0 : nFlags = bStereoType == 2 ? INCHI_FLAG_REL_STEREO : bStereoType == 3 ? INCHI_FLAG_RAC_STEREO : 0;
2451 [ # # # # ]: 0 : nFlagsAlt = bStereoTypeAlt == 2 ? INCHI_FLAG_REL_STEREO : bStereoTypeAlt == 3 ? INCHI_FLAG_RAC_STEREO : 0;
2452 : : }
2453 : : /* set stereo type to each component */
2454 : : /* add missing nNum_H and nConnTable */
2455 [ # # ]: 0 : if (nNumComponents[iINChI][j])
2456 : : {
2457 : 0 : num_elem[iINChI][j] = (NUM_ELEM*)inchi_calloc((long long)nElDataLen + 1, sizeof(num_elem[0][0][0])); /* djb-rwth: cast operator added */
2458 [ # # ]: 0 : if (!num_elem[iINChI][j])
2459 : : {
2460 : 0 : ret2 = RI_ERR_ALLOC;
2461 : 0 : goto exit_function;
2462 : : }
2463 : : }
2464 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
2465 : : {
2466 : : /* for each component k ... */
2467 [ # # ]: 0 : if (pInpInChI[iINChI][j])
2468 : : {
2469 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
2470 : 0 : INChI* pInChI_Alt = (k < nNumComponents[iINChI][jAlt] &&
2471 [ # # ]: 0 : pInpInChI[iINChI][jAlt] &&
2472 : : /*pInpInChI[iINChI][jAlt]->nNumberOfAtoms)? pInpInChI[iINChI][jAlt]:NULL;*/ /* 2007-09-25 DT */
2473 [ # # # # ]: 0 : pInpInChI[iINChI][jAlt][k].nNumberOfAtoms) ? &pInpInChI[iINChI][jAlt][k] : NULL;
2474 [ # # ]: 0 : if (nFlags)
2475 : : {
2476 : 0 : pInChI->nFlags |= nFlags;
2477 : : }
2478 : : else
2479 : : {
2480 [ # # # # : 0 : if (j == TAUT_NON && !nFlags && nFlagsAlt)
# # ]
2481 : : {
2482 : 0 : pInChI->nFlags |= nFlagsAlt;
2483 : : }
2484 : : }
2485 : : /**** add empty immobile H (nNum_H) if it is missing ****/
2486 [ # # ]: 0 : if (!pInChI->nNum_H &&
2487 [ # # ]: 0 : !(pInChI->nNum_H = (S_CHAR*)inchi_calloc((long long)pInChI->nNumberOfAtoms + 1, sizeof(pInChI->nNum_H[0])))) /* djb-rwth: cast operator added */
2488 : : {
2489 : 0 : ret2 = RI_ERR_ALLOC;
2490 : 0 : goto exit_function;
2491 : : }
2492 : : /**** add single atom nConnTable if it is missing ****/
2493 [ # # # # ]: 0 : if (!pInChI->nConnTable && pInpInChI[iINChI][TAUT_YES]) /* djb-rwth: fixing a NULL pointer dereference */
2494 : 0 : {
2495 : : AT_NUMB* pCT;
2496 : : int lenCT;
2497 [ # # # # ]: 0 : if (j == TAUT_NON && k < nNumComponents[iINChI][TAUT_YES] &&
2498 [ # # ]: 0 : (pCT = pInpInChI[iINChI][TAUT_YES][k].nConnTable) &&
2499 [ # # ]: 0 : (lenCT = pInpInChI[iINChI][TAUT_YES][k].lenConnTable) > 0)
2500 : : {
2501 [ # # ]: 0 : if (!(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)lenCT + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
2502 : : {
2503 : 0 : ret2 = RI_ERR_ALLOC;
2504 : 0 : goto exit_function;
2505 : : }
2506 : 0 : memcpy(pInChI->nConnTable, pCT, lenCT * sizeof(pInChI->nConnTable[0]));
2507 : 0 : pInChI->lenConnTable = lenCT;
2508 : : }
2509 : : else
2510 : : {
2511 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->nNumberOfAtoms > 1)
2512 : : {
2513 [ # # ]: 0 : *pState = IST_MOBILE_H_CONNECTIONS + (iINChI == INCHI_REC ? IST_HAPPENED_IN_RECMET : 0);
2514 : 0 : ret2 = RI_ERR_SYNTAX;
2515 : 0 : goto exit_function;
2516 : : }
2517 [ # # ]: 0 : if (!(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)pInChI->nNumberOfAtoms + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
2518 : : {
2519 : 0 : ret2 = RI_ERR_ALLOC;
2520 : 0 : goto exit_function;
2521 : : }
2522 : 0 : pInChI->lenConnTable = 1;
2523 : 0 : pInChI->nConnTable[0] = 1;
2524 : : }
2525 : : }
2526 : : else
2527 : : {
2528 [ # # # # : 0 : if (pInChI->nConnTable && !pInChI->lenConnTable && pInChI->nNumberOfAtoms == 1)
# # ]
2529 : : {
2530 : 0 : pInChI->nConnTable[0] = 1;
2531 : 0 : pInChI->lenConnTable = 1;
2532 : : }
2533 : : }
2534 : : /**** copy charge: Mobile H --> Fixed H; ****/
2535 [ # # ]: 0 : if (j == TAUT_NON)
2536 : : {
2537 : : /*
2538 : : if ( pInChI->nTotalCharge == NO_VALUE_INT )
2539 : : {
2540 : : pInChI->nTotalCharge = 0;
2541 : : }
2542 : : else
2543 : : */
2544 [ # # # # : 0 : if (!pInChI->nTotalCharge && k < nNumComponents[iINChI][TAUT_YES] && pInpInChI[iINChI][TAUT_YES]) /* djb-rwth: fixing a NULL pointer dereference */
# # ]
2545 : : {
2546 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_YES][k]; /* Mobile H InChI */
2547 [ # # # # ]: 0 : if (pAltInChI->nTotalCharge && pAltInChI->nTotalCharge != NO_VALUE_INT)
2548 : : {
2549 : 0 : pInChI->nTotalCharge = pAltInChI->nTotalCharge;
2550 : : }
2551 : : }
2552 : : }
2553 : : /***** Fixed H: add pInChI->nNum_H_fixed to pInChI->nNum_H ****/
2554 [ # # # # : 0 : if (j == TAUT_NON && pInChI->nNum_H && pInChI->nNum_H_fixed)
# # ]
2555 : : {
2556 [ # # ]: 0 : for (m = 0; m < pInChI->nNumberOfAtoms; m++)
2557 : : {
2558 : 0 : pInChI->nNum_H[m] += pInChI->nNum_H_fixed[m];
2559 : : }
2560 : : }
2561 : : /***** copy isotopic atoms: Mobile H --> Fixed H ******/
2562 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->nNumberOfIsotopicAtoms &&
2563 [ # # ]: 0 : k < nNumComponents[iINChI][TAUT_NON])
2564 : : {
2565 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_NON][k]; /* Fixed H InChI */
2566 : :
2567 [ # # ]: 0 : if (!pAltInChI->nNumberOfIsotopicAtoms)
2568 : : {
2569 : 0 : ret2 = CopySegment(pAltInChI, pInChI, CPY_ISO_AT, 0, 0);
2570 [ # # ]: 0 : if (ret2 < 0)
2571 : : {
2572 : 0 : goto exit_function;
2573 : : }
2574 : : }
2575 : : }
2576 : : /**** copy coordinates: Mobile H --> Fixed H ******/
2577 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->IsotopicTGroup &&
2578 [ # # ]: 0 : k < nNumComponents[iINChI][TAUT_NON])
2579 : : {
2580 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_NON][k]; /* Fixed H InChI */
2581 : :
2582 [ # # ]: 0 : if (!pAltInChI->IsotopicTGroup)
2583 : : {
2584 : 0 : XYZ_COORD* pxyz = (XYZ_COORD*)inchi_calloc(pInChI->nNumberOfAtoms, sizeof(pxyz[0]));
2585 [ # # ]: 0 : if (pxyz)
2586 : : {
2587 : 0 : memcpy(pxyz, pInChI->IsotopicTGroup, pInChI->nNumberOfAtoms * sizeof(pxyz[0]));
2588 : 0 : pAltInChI->IsotopicTGroup = (INChI_IsotopicTGroup*)pxyz;
2589 : : }
2590 : : else
2591 : : {
2592 : 0 : ret2 = RI_ERR_ALLOC;
2593 : 0 : goto exit_function;
2594 : : }
2595 : : }
2596 : : }
2597 : :
2598 : : /********************************************************
2599 : : * *
2600 : : * Restore omitted stereo seqments *
2601 : : * *
2602 : : * order of restoring: *
2603 : : * *
2604 : : * 1. Fixed H (F) -> (FI) Isotopic Fixed H *
2605 : : * 2. Mobile H (M) -> (F) Fixed H *
2606 : : * 3. Isotopic Mobile H (MI) -> (FI) Isotopic Fixed H *
2607 : : * 4. Mobile H (M) -> (MI) Isotopic Mobile H *
2608 : : * *
2609 : : ********************************************************/
2610 : :
2611 : : /***** (4) copy stereo: Mobile H --> isotopic Mobile H ******/
2612 [ # # ]: 0 : if (j == TAUT_YES)
2613 : : {
2614 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2615 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2616 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2617 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2618 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2619 : :
2620 : : /* non-isotopic Mobile H => isotopic Mobile H */
2621 [ # # ]: 0 : if (bIso)
2622 : : {
2623 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2624 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
2625 : : {
2626 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)) ||
2627 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
2628 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))) /* djb-rwth: addressing LLVM warning */
2629 : : {
2630 : 0 : goto exit_function;
2631 : : }
2632 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2633 : : {
2634 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2635 : : {
2636 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2637 : : }
2638 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2639 : : {
2640 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2641 : : }
2642 : : }
2643 : : }
2644 : : else
2645 : : {
2646 : : /* copy sp3 inversion info: non-isotopic Mobile H => isotopic Mobile H */
2647 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2648 [ # # # # ]: 0 : pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters &&
2649 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs)
2650 : : {
2651 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2652 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2653 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2654 : : {
2655 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2656 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2657 : : }
2658 : : else
2659 : : {
2660 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs)
2661 : : {
2662 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
2663 : : }
2664 : : }
2665 : : }
2666 : : }
2667 : : }
2668 [ # # ]: 0 : if (bIso &&
2669 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds &&
2670 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
2671 : : {
2672 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP2, 1, 0)))
2673 : : {
2674 : 0 : goto exit_function;
2675 : : }
2676 : : }
2677 : : }
2678 : : /***** (0) set nCompInv2Abs to Fixed-H *********************************/
2679 [ # # ]: 0 : if (j == TAUT_NON)
2680 : : {
2681 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2682 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2683 : : {
2684 : : /* case of /sN and /t... in non-isotopic Mobile-H, no /s in non-isotopic Fixed-H */
2685 [ # # # # : 0 : if (!s[iINChI][j][0] && s[iINChI][jAlt][0] > 0 && /* /sN is not present in F and is present in M */
# # ]
2686 [ # # # # ]: 0 : pInChI_Alt && pInChI_Alt->Stereo && pInChI_Alt->Stereo->nNumberOfStereoCenters)
2687 : : {
2688 : : /* inherit from Mobile-H */
2689 : : /* /s1 in M and MI; /m1 or /m0 in MI; /m. in M; no /m in F. Inherit MI->FI. Added 10-15-2007 */
2690 [ # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs == 0 && /* M: /m. ; means no /m for this component */
2691 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT && /* F: no /m segment for all components */
2692 [ # # ]: 0 : pInChI_Alt->StereoIsotopic && /* MI: present */
2693 [ # # ]: 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs != 0 &&
2694 [ # # ]: 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs != NO_VALUE_INT && /* MI: /m0 or /m1 */
2695 [ # # # # ]: 0 : !s[iINChI][j][0] && !s[iINChI][j][1] && /* F, FI: no /s */
2696 [ # # # # ]: 0 : s[iINChI][jAlt][0] == 1 && s[iINChI][jAlt][1] == 1 /* M, MI: /s1 and /s1 */
2697 : : )
2698 : : {
2699 : : /* copy /m from MI to FI */
2700 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI_Alt, CPY_SP3_M, 1, 1)))
2701 : : {
2702 : 0 : goto exit_function;
2703 : : }
2704 : : }
2705 : : else
2706 : : {
2707 : : /* the following if(){...} was added to fix m1 bug 2007-09-25 DT */
2708 [ # # # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs != NO_VALUE_INT && s[iINChI][jAlt][0] == 1)
2709 : : {
2710 : 0 : pInChI->Stereo->nCompInv2Abs = pInChI_Alt->Stereo->nCompInv2Abs;
2711 : : }
2712 : : else
2713 : : {
2714 : : /* M and MI contain /sN and /sN, N=2,3. Added 10-15-2007 */
2715 [ # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2716 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2717 [ # # # # ]: 0 : !s[iINChI][j][0] && !s[iINChI][j][1] &&
2718 [ # # ]: 0 : (s[iINChI][jAlt][0] & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2719 [ # # ]: 0 : (s[iINChI][jAlt][1] & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2720 : 0 : {
2721 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2722 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2723 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2724 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2725 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2726 [ # # ]: 0 : if (bIso)
2727 : : {
2728 [ # # # # ]: 0 : if (!pInChI_Alt->StereoIsotopic && /* create zero/NULL-initialized pInChI_Alt->StereoIsotopic */
2729 : 0 : 0 > (ret2 = CopySegment(pInChI_Alt, pInChI_Alt, CPY_SP3_M, 1, -1)))
2730 : : {
2731 : 0 : goto exit_function;
2732 : : }
2733 : 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs = 2; /* MI: /m1 or /m0 */
2734 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 0; /* M: /m. ; no /m for this component */
2735 : 0 : pInChI->Stereo->nCompInv2Abs = NO_VALUE_INT + 1; /* FI: Stereo->CompInv2Abs=0, StereoIsotopic->CompInv2Abs=1 or -1 */
2736 : : }
2737 : : else
2738 : : {
2739 : 0 : pInChI->Stereo->nCompInv2Abs = 2; /* F: /m1 or /m0, omitted from InChI as a repetition */
2740 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 2; /* M: /m1 or /m0; in Srel/SRac case the value = 2 */
2741 : : }
2742 : : }
2743 : : else
2744 : : {
2745 : 0 : pInChI->Stereo->nCompInv2Abs = 2; /* F: /m1 or /m0, omitted from InChI as a repetition */
2746 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 2; /* M: /m1 or /m0; in Srel/SRac case the value = 2 */
2747 : : }
2748 : : }
2749 : : }
2750 : : }
2751 : : else
2752 : : {
2753 : : /* case of /sN in Isotopic Fixed-H only, /t... in Fixed-H, no /m (2007-08-27 DT) */
2754 [ # # # # ]: 0 : if (!s[iINChI][j][0] && !s[iINChI][jAlt][0] && /* /sN in Fixed-H isotopic only */
2755 [ # # ]: 0 : (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2756 [ # # # # : 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) &&
# # ]
2757 : : /*!(pInChI_Alt && pInChI_Alt->Stereo && pInChI_Alt->Stereo->nNumberOfStereoCenters) &&*/
2758 [ # # # # ]: 0 : !(pInChI_Alt && pInChI_Alt->StereoIsotopic && pInChI_Alt->StereoIsotopic->nNumberOfStereoCenters))
2759 : : {
2760 : 0 : pInChI->Stereo->nCompInv2Abs = NO_VALUE_INT + 1; /* Stereo->CompInv2Abs=0, StereoIsotopic->CompInv2Abs=1 or -1 */
2761 : : }
2762 : : else
2763 : : {
2764 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2765 : : }
2766 : : }
2767 : : }
2768 : : }
2769 : :
2770 : : /***** (1) copy stereo: non-isotopic Fixed H --> isotopic Fixed H ******/
2771 [ # # ]: 0 : if (j == TAUT_NON)
2772 : : {
2773 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2774 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2775 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2776 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2777 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2778 : : /* non-isotopic Fixed H => isotopic Fixed H */
2779 [ # # ]: 0 : if (bIso)
2780 : : {
2781 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2782 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
2783 : : {
2784 : : /* -- replaced 2007-08-27 by (aaa), see below -- DT
2785 : : if ( 0 > (ret2 = CopySegment( pInChI, pInChI, CPY_SP3, 1, 0)) ||
2786 : : !(pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
2787 : : 0 > (ret2 = CopySegment( pInChI, pInChI, CPY_SP3_M, 1, 0))) {
2788 : : goto exit_function;
2789 : : }
2790 : : */
2791 : : /*----------- replacement (aaa) begin 2007-08-27 DT */
2792 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)))
2793 : : {
2794 : 0 : goto exit_function;
2795 : : }
2796 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT + 1)
2797 : : {
2798 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2799 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
2800 : : }
2801 : : else
2802 : : {
2803 [ # # # # : 0 : if (!(pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
2804 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))
2805 : : {
2806 : 0 : goto exit_function;
2807 : : }
2808 : : }
2809 : : /*----------- replacement (aaa) end 2007-08-27 DT */
2810 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2811 : : {
2812 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2813 : : {
2814 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2815 : : }
2816 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2817 : : {
2818 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2819 : : }
2820 : : }
2821 : : #ifdef NEVER
2822 : : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2823 : : !s[iINChI][j][0] && s[iINChI][j][0] > 0)
2824 : : {
2825 : : /* copied Rel/Rac stereo to Iso; /s is in Iso /s is not in non-Iso */
2826 : : /* this means all difference in stereo is in inversion */
2827 : : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2828 : : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2829 : : {
2830 : : pInChI->Stereo->nCompInv2Abs = 0; /* missing */
2831 : : pInChI->StereoIsotopic->nCompInv2Abs = 2; /* unusual value */
2832 : : }
2833 : : }
2834 : : #endif
2835 : : }
2836 : : else
2837 : : {
2838 : : /* copy sp3 inversion info: non-isotopic Fixed H --> isotopic Fixed H */
2839 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2840 [ # # # # ]: 0 : pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters &&
2841 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs)
2842 : : {
2843 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2844 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2845 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2846 : : {
2847 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2848 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2849 : : }
2850 : : else
2851 : : {
2852 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs)
2853 : : {
2854 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
2855 : : }
2856 : : }
2857 : : }
2858 : : }
2859 : : }
2860 [ # # ]: 0 : if (bIso &&
2861 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds &&
2862 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
2863 : : {
2864 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP2, 1, 0)))
2865 : : {
2866 : 0 : goto exit_function;
2867 : : }
2868 : : }
2869 : : }
2870 : :
2871 : : /***** copy stereo: Mobile H --> Fixed H ******/
2872 [ # # # # ]: 0 : if (j == TAUT_NON && k < nNumComponents[iINChI][TAUT_YES])
2873 : : {
2874 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_YES][k]; /* Mobile H InChI */
2875 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2876 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2877 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2878 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2879 : 0 : (pAltInChI && (
2880 [ # # ]: 0 : pAltInChI->nNumberOfIsotopicAtoms ||
2881 [ # # ]: 0 : (pAltInChI->StereoIsotopic &&
2882 : 0 : pAltInChI->StereoIsotopic->nNumberOfStereoCenters
2883 [ # # ]: 0 : + pAltInChI->StereoIsotopic->nNumberOfStereoBonds))); /* djb-rwth: addressing LLVM warning */
2884 [ # # # # ]: 0 : int bNo_InChI_t = (!pInChI->Stereo || !pInChI->Stereo->t_parity);
2885 [ # # # # ]: 0 : int bNo_InChI_m = (!pInChI->Stereo || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs);
2886 : :
2887 : : /* (2) non-isotopic Mobile H => non-isotopic Fixed H */
2888 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoCenters &&
2889 [ # # # # ]: 0 : (!pInChI->Stereo || !pInChI->Stereo->t_parity))
2890 : 0 : {
2891 : : #if ( FIX_I2I_STEREOCONVERSION_BUG2 == 1 )
2892 : : /* (2008-04-02) 1=> Fix bug of i2i conversion SAbs-->(SRel||Srac) */
2893 : : /* (converter skipped empty '/t' or sometimes produced an excess one */
2894 : :
2895 : : /* check whether t stereo is actually present */
2896 : 0 : int bHave_t_stereo = 1;
2897 [ # # ]: 0 : if (pInChI->Stereo)
2898 : 0 : bHave_t_stereo = pInChI->Stereo->nNumberOfStereoCenters;
2899 : : /* account for stereobonds present */
2900 [ # # ]: 0 : if (bHave_t_stereo < 1)
2901 [ # # ]: 0 : if (pInChI->Stereo->nNumberOfStereoBonds > 0)
2902 : 0 : bHave_t_stereo = 1;
2903 : : /* copy stereo anyway ... */
2904 : : #endif
2905 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3, 0, 0)) ||
2906 [ # # # # : 0 : ((!pInChI->Stereo->nCompInv2Abs || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs) &&
# # ]
2907 : 0 : 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 0, 0)))) /* djb-rwth: addressing LLVM warning */
2908 : : {
2909 : 0 : goto exit_function;
2910 : : }
2911 : :
2912 : : #if ( FIX_I2I_STEREOCONVERSION_BUG2 == 1 )
2913 : : /* ... correct just copied stereo if applicable */
2914 [ # # # # ]: 0 : if ((s[iINChI][j][0] < 1) &&
2915 : 0 : (bHave_t_stereo < 1) &&
2916 [ # # ]: 0 : (pAltInChI->Stereo->nNumberOfStereoCenters > 0) &&
2917 [ # # ]: 0 : (s[iINChI][jAlt][0] < 1))
2918 : : {
2919 : : /* (2010-02-28) if not all stereo centers are unknown/undefined */
2920 : : /* at which condition stereo still should present .. */
2921 : 0 : int all_UU = 1;
2922 [ # # ]: 0 : for (kc = 0; kc < pAltInChI->Stereo->nNumberOfStereoCenters; kc++)
2923 : : {
2924 [ # # ]: 0 : if ((pAltInChI->Stereo->t_parity[kc] != AB_PARITY_UNKN) &&
2925 [ # # ]: 0 : (pAltInChI->Stereo->t_parity[kc] != AB_PARITY_UNDF))
2926 : : {
2927 : 0 : all_UU = 0;
2928 : 0 : break;
2929 : : }
2930 : : }
2931 [ # # ]: 0 : if (!all_UU)
2932 : 0 : pInChI->Stereo->nNumberOfStereoCenters = 0;
2933 : : }
2934 : : #endif
2935 : :
2936 : : /* in case of missing nCompInv2Abs, 2005-05-10 */
2937 [ # # ]: 0 : if ((pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT) &&
2938 [ # # ]: 0 : (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2939 : : {
2940 [ # # # # ]: 0 : if (s[iINChI][jAlt][0] > 0 && s[iINChI][j][0] > 0)
2941 : : {
2942 : : /* suppose once in a while only non-taut stereo changes if inverted */
2943 [ # # ]: 0 : pAltInChI->Stereo->nCompInv2Abs = (++nMH2FH_AltInv) % 2 ? 2 : 0;
2944 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2945 : : }
2946 : : else
2947 : : {
2948 : : /* Mobile-H: /t.. /sN; Mobile-H isotopic: /sN (n=2 or 3), not /t...; Fixed-H layer is present, has no /t, no /i/t */
2949 : : /* Mobile-H /sN was caused by another component that would have same /mN in all layers */
2950 : : /* therefore, in case of Abs. Stereo, Mobile-H stereo isotopic stereo would have /m1 */
2951 : : /* In case of Rel/Rac stereo, since no /m1 could occur in Mobile-H isotopic, */
2952 : : /* no pAltInChI->StereoIsotopic or pInChI->StereoIsotopic have been created yet. */
2953 : : /* added 10-11-2007 to fix i2i bug for Rel/Rac stereo */
2954 [ # # # # ]: 0 : if (nNumComponents[iINChI][j] > 1 &&
2955 [ # # # # ]: 0 : bNo_InChI_t && bNo_InChI_m /* no /t... or /mN in Fixed-H */ && !nFlags &&
2956 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
2957 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity) &&
2958 [ # # # # ]: 0 : s[iINChI][j][0] == 0 && s[iINChI][j][1] == 0 &&
2959 : : /* /sN, N=2 or 3 only in Mobile-H AND Mobile-H isotopic */
2960 [ # # ]: 0 : (s[iINChI][jAlt][0] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))) &&
2961 [ # # ]: 0 : (s[iINChI][jAlt][1] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))))
2962 : : {
2963 [ # # ]: 0 : if (bIso)
2964 : : {
2965 : : /* create two zero/NULL-initialized isotopic stereo if they do not exist */
2966 [ # # # # ]: 0 : if ((!pInChI->StereoIsotopic && 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, -1)))
2967 : : /* -- the following will be created later, in TAUT_YES part of the code -- */
2968 [ # # # # ]: 0 : || (!pAltInChI->StereoIsotopic && 0 > (ret2 = CopySegment(pAltInChI, pAltInChI, CPY_SP3_M, 1, -1)))) /* djb-rwth: addressing LLVM warnings */ /* djb-rwth: addressing coverity ID #499533 -- unresolved issue -- revision required */
2969 : : {
2970 : 0 : goto exit_function;
2971 : : }
2972 : : /* same value = 2 for MI and FI; here we assign only FI */
2973 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
2974 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2975 : : /* -- the following will NOT be assigned later, in TAUT_YES part of the code -- */
2976 : 0 : pAltInChI->StereoIsotopic->nCompInv2Abs = 2;
2977 : 0 : pAltInChI->Stereo->nCompInv2Abs = 0;
2978 : : /* */
2979 : : }
2980 : : else
2981 : : {
2982 [ # # ]: 0 : if (NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs &&
2983 [ # # ]: 0 : NO_VALUE_INT == pAltInChI->Stereo->nCompInv2Abs)
2984 : : {
2985 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2986 : 0 : pAltInChI->Stereo->nCompInv2Abs = 2;
2987 : : }
2988 : : }
2989 : : }
2990 : : else
2991 : : {
2992 [ # # # # : 0 : if ((s[iINChI][jAlt][0] > 0 || s[iINChI][j][0] > 0) && s[iINChI][j][0] >= 0)
# # ]
2993 : : {
2994 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2995 : : }
2996 : : else
2997 : : {
2998 : : /* Mobile-H: /t..., no /sN; Mobile-H isotopic: /s2 or /s3, not /t; Fixed-H layer is present, has no /t, no /i/t */
2999 : : /* therefore, in case of Abs. Stereo, Mobile-H stereo isotopic stereo would have /m1 */
3000 : : /* In case of Rel/Rac stereo, since no /m1 could occur in Mobile-H isotopic, */
3001 : : /* no pAltInChI->StereoIsotopic or pInChI->StereoIsotopic have been created yet. */
3002 : : /* added 10-10-2007 to fix i2i bug for Rel/Rac stereo */
3003 [ # # # # : 0 : if (bIso && bNo_InChI_t && bNo_InChI_m /* no /t... or /mN in Fixed-H */ && !nFlags &&
# # # # ]
3004 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
3005 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity) &&
3006 [ # # # # : 0 : s[iINChI][jAlt][0] == 0 && s[iINChI][j][0] == 0 && s[iINChI][j][1] == 0 &&
# # ]
3007 : : /* /sN, N=2 or 3 only in Mobile-H isotopic */
3008 [ # # ]: 0 : (s[iINChI][jAlt][1] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))))
3009 : : {
3010 : : /* create two zero/NULL-initialized isotopic stereo if they do not exist */
3011 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic && 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, -1))
3012 : : /* -- the following will be created later, in TAUT_YES part of the code -- */
3013 : : /*|| !pAltInChI->StereoIsotopic && 0 > (ret2 = CopySegment( pAltInChI, pAltInChI, CPY_SP3_M, 1, -1))*/)
3014 : : {
3015 : 0 : goto exit_function;
3016 : : }
3017 : : /* same value = 2 for MI and FI; here we assign only FI */
3018 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
3019 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3020 : : /* -- the following will be assigned later, in TAUT_YES part of the code -- */
3021 : : /*
3022 : : pAltInChI->StereoIsotopic->nCompInv2Abs = 2;
3023 : : pAltInChI->Stereo->nCompInv2Abs = 0;
3024 : : */
3025 : : }
3026 : : else
3027 : : {
3028 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3029 : : }
3030 : : }
3031 : : }
3032 : : }
3033 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3034 : : {
3035 : 0 : pInChI->nFlags |= ((nFlagsAlt | nFlags) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3036 : : }
3037 : : }
3038 : : }
3039 : : else
3040 : : {
3041 : : /* copy sp3 inversion info: non-isotopic Mobile H => non-isotopic Fixed H */
3042 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoCenters &&
3043 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
3044 [ # # ]: 0 : pAltInChI->Stereo->nCompInv2Abs &&
3045 [ # # # # ]: 0 : (!pInChI->Stereo->nCompInv2Abs || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs))
3046 : : {
3047 [ # # # # : 0 : if (!(nFlagsAlt && !nFlags) || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs)
# # ]
3048 : : {
3049 : : /* ??? */
3050 : 0 : pInChI->Stereo->nCompInv2Abs = pAltInChI->Stereo->nCompInv2Abs;
3051 : : }
3052 : : }
3053 : : }
3054 : :
3055 : : /* use same rule to copy stereobonds */
3056 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoBonds &&
3057 [ # # # # ]: 0 : (!pInChI->Stereo || !pInChI->Stereo->b_parity))
3058 : : {
3059 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 0, 0)))
3060 : : {
3061 : 0 : goto exit_function;
3062 : : }
3063 : : }
3064 : : /* (3) isotopic Mobile H -> isotopic Fixed H */
3065 : : /* if !FH_Stereo && !MH_Stereo && MH_IsoStereo!=NULL && FH_IsoStereo==NULL */
3066 [ # # ]: 0 : if (bIso)
3067 : : {
3068 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->t_parity) && /* !FH_Stereo */
3069 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->t_parity) && /* !MH_Stereo */
3070 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) && /* MH_IsoStereo */
3071 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
3072 : : {
3073 : : /* !FH_IsoStereo */
3074 : : /* copy sp3 iso stereo MI->FI (/t) and, if FH nCompInv2Abs (/m) is missing, copy it, too, MI->FI */
3075 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3, 1, 1)) ||
3076 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
3077 : 0 : 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))) /* djb-rwth: addressing LLVM warning */
3078 : : {
3079 : 0 : goto exit_function;
3080 : : }
3081 : : /* in case of missing nCompInv2Abs, Relative or Racemic stereo 2005-05-10 */
3082 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT &&
3083 [ # # ]: 0 : (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3084 : : {
3085 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][jAlt][1] > 0 ? 2 : 0;
3086 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3087 : : {
3088 : 0 : pInChI->nFlags |= (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3089 : : }
3090 : : }
3091 : : }
3092 : : else
3093 : : {
3094 : : /* copy sp3 inversion info only: isotopic Mobile H -> isotopic Fixed H */
3095 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->t_parity) && /* !FH_Stereo /t */
3096 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->t_parity) && /* !MH_Stereo /t */
3097 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) && /* MH_IsoStereo /t */
3098 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) && /* FH_IsoStereo /t */
3099 [ # # ]: 0 : pAltInChI->StereoIsotopic->nCompInv2Abs && /* MH_IsoStereo /m */
3100 [ # # # # ]: 0 : (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs))
3101 : : {
3102 : : /* !FH_IsoStereo /m */
3103 : : /* added 02-09-2006 */
3104 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))
3105 : : {
3106 : 0 : goto exit_function;
3107 : : }
3108 : : }
3109 : : }
3110 : : /* use same rule to copy stereobonds */
3111 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->b_parity) &&
3112 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->b_parity) &&
3113 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoBonds) &&
3114 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
3115 : : {
3116 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 1, 1)))
3117 : : {
3118 : 0 : goto exit_function;
3119 : : }
3120 : : }
3121 : :
3122 : : /* (4) Copy Fixed-H -> isotopic Fixed-H */
3123 : : /* if FH_Stereo && !MH_IsoStereo && && !FH_IsoStereo */
3124 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters) && /* FH_Stereo /t */
3125 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) && /* !MH_IsoStereo /t */
3126 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity))
3127 : : {
3128 : : /* !FH_IsoStereo /t */
3129 : :
3130 : : /* added 10-10-2007 DT: copy MH_Iso /m => FH_Iso /m to fix i2i bug for Abs stereo */
3131 : : /* InChI string contains: MH(/t...), MH_Iso(/mN, no /t), FH(no /t /m), FH_Iso(no /t /m) */
3132 [ # # # # : 0 : if (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nCompInv2Abs && /* MH_IsoStereo /m */
# # ]
3133 : 0 : bNo_InChI_t &&
3134 [ # # ]: 0 : NO_VALUE_INT != pAltInChI->StereoIsotopic->nCompInv2Abs && /* undef FH_IsoStereo /m */
3135 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && NO_VALUE_INT != pInChI->StereoIsotopic->nCompInv2Abs))
3136 : : {
3137 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))
3138 : : {
3139 : 0 : goto exit_function;
3140 : : }
3141 : : }
3142 : :
3143 : : /* added 05-09-2006: copy sp3 FH=>FH_Iso */
3144 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)) ||
3145 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
3146 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))) /* djb-rwth: addressing LLVM warning */
3147 : : {
3148 : 0 : goto exit_function;
3149 : : }
3150 : :
3151 : : /* in case of missing nCompInv2Abs, Relative or Racemic stereo, /sN in Fixed-H, 2005-05-10 */
3152 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT &&
3153 [ # # ]: 0 : (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3154 : : {
3155 [ # # # # ]: 0 : if (s[iINChI][j][0] > 0 && s[iINChI][j][1] > 0)
3156 : : {
3157 : : /* suppose once in a while only non-taut stereo changes if inverted */
3158 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
3159 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = (++nFH2iFH_AltInv) % 2 ? 2 : 0;
3160 : : }
3161 : : else
3162 : : {
3163 [ # # # # : 0 : if ((s[iINChI][j][0] > 0 || s[iINChI][j][1] > 0) && s[iINChI][j][1] >= 0) /* ??? != NO_VALUE_INT ??? */
# # ]
3164 : : {
3165 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
3166 : : }
3167 : : else
3168 : : {
3169 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3170 : : }
3171 : : }
3172 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3173 : : {
3174 : 0 : pInChI->nFlags |= (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3175 : : }
3176 : : }
3177 : : }
3178 : : else
3179 : : {
3180 : : /* copy sp3 inversion info only: Fixed-H -> isotopic Fixed H */
3181 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->t_parity) &&
3182 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
3183 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) &&
3184 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) &&
3185 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs &&
3186 [ # # # # ]: 0 : (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs))
3187 : : {
3188 : : /* added 05-09-2006 */
3189 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))
3190 : : {
3191 : 0 : goto exit_function;
3192 : : }
3193 : : }
3194 : : }
3195 : : }
3196 [ # # ]: 0 : if (bIso &&
3197 [ # # # # ]: 0 : !(pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds) &&
3198 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoBonds) &&
3199 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoBonds) &&
3200 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
3201 : : {
3202 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 1, 1)))
3203 : : {
3204 : 0 : goto exit_function;
3205 : : }
3206 : : }
3207 : : }
3208 : : }
3209 : : } /* end of component cycle (k) */
3210 : : } /* end of Mobile/Fixed H cycle (j) */
3211 : :
3212 : : /**** replace NO_VALUE_INT with zeroes in all Mobile & Fixed H components ****/
3213 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3214 : : {
3215 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
3216 : : {
3217 [ # # ]: 0 : if (pInpInChI[iINChI][j])
3218 : : {
3219 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
3220 [ # # ]: 0 : if (pInChI->nTotalCharge == NO_VALUE_INT)
3221 : : {
3222 : 0 : pInChI->nTotalCharge = 0;
3223 : : }
3224 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->StereoIsotopic &&
3225 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
3226 : : {
3227 [ # # ]: 0 : if (pInChI->Stereo->nNumberOfStereoCenters &&
3228 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs != NO_VALUE_INT)
3229 : : {
3230 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
3231 : : }
3232 : : }
3233 : : /* Add special nCompInv2Abs=2 to force /s2 or /s3 in InChI output */
3234 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
3235 : : {
3236 [ # # ]: 0 : if (pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) &&
3237 [ # # ]: 0 : pInChI->Stereo->nNumberOfStereoCenters)
3238 : : {
3239 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = (s[iINChI][j][0] > 0 /*|| s[iINChI][j][1]>0*/) ? 2 : 0; /* we do not know the real value */
3240 : : }
3241 : : else
3242 : : {
3243 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3244 : : }
3245 : : }
3246 [ # # # # ]: 0 : if (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
3247 : : {
3248 [ # # ]: 0 : if (pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) &&
3249 [ # # ]: 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters)
3250 : : {
3251 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0; /* we do not know the real value */
3252 : : }
3253 : : else
3254 : : {
3255 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3256 : : }
3257 : : }
3258 : : /* added 02-07-2006 */
3259 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT) ||
3260 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)) /* djb-rwth: addressing LLVM warnings */
3261 : : {
3262 : 0 : ret2 = RI_ERR_PROGR;
3263 : 0 : goto exit_function;
3264 : : }
3265 [ # # # # ]: 0 : if (!pInChI->bDeleted && pInChI->nNumberOfAtoms)
3266 : : {
3267 : 0 : tot_charge[iINChI][j] += pInChI->nTotalCharge;
3268 [ # # ]: 0 : for (m = 0; m < pInChI->nNumberOfAtoms; m++)
3269 : : {
3270 [ # # # # ]: 0 : if (pInChI->nAtom[m] < EL_NUMBER_H || pInChI->nAtom[m] > nElDataLen)
3271 : : {
3272 : 0 : ret2 = RI_ERR_PROGR;
3273 : 0 : goto exit_function;
3274 : : }
3275 : : /* all atoms except H */
3276 [ # # ]: 0 : if (pInChI->nAtom[m] > EL_NUMBER_H)
3277 : : {
3278 : 0 : num_elem[iINChI][j][pInChI->nAtom[m]].num++;
3279 : : }
3280 : : }
3281 [ # # ]: 0 : if (0 > (ret2 = GetInChINumH(pInChI, &m)))
3282 : : {
3283 : 0 : goto exit_function;
3284 : : }
3285 : 0 : num_elem[iINChI][j][EL_NUMBER_H].num += m;
3286 : : }
3287 : : }
3288 : : }
3289 : : }
3290 : :
3291 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3292 : : {
3293 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
3294 : : {
3295 [ # # ]: 0 : if (pInpInChI[iINChI][j])
3296 : : {
3297 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
3298 [ # # # # ]: 0 : if (pInChI->Stereo && !pInChI->Stereo->nNumberOfStereoCenters)
3299 : : {
3300 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3301 : : }
3302 [ # # # # ]: 0 : if (pInChI->StereoIsotopic && !pInChI->StereoIsotopic->nNumberOfStereoCenters)
3303 : : {
3304 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3305 : : }
3306 : : }
3307 : : }
3308 : : }
3309 : :
3310 : : #if ( FIX_I2I_STEREOCONVERSION_BUG3 == 1 )
3311 : : /* (2008-04-10) 1=> Fix bug of i2i conversion */
3312 : : /* (missed repeating /s in FI after F for multi-component case) */
3313 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_NON] > 1) /* if multi-component */
3314 : : {
3315 [ # # # # ]: 0 : if (!s[iINChI][TAUT_YES][0] && !s[iINChI][TAUT_YES][1])/* if no /s in M, MI */
3316 : : {
3317 [ # # # # ]: 0 : if ((s[iINChI][TAUT_NON][0] > 1) && (s[iINChI][TAUT_NON][1] > 1)) /* if /srel/srac in both F, FI */
3318 : : {
3319 [ # # ]: 0 : if (s[iINChI][TAUT_NON][0] == s[iINChI][TAUT_NON][1]) /* if same stereo in F and FI */
3320 : : {
3321 : : /* we assume that at least one component in F has no actual stereo */
3322 : : /* and place deliberately 0 to appropriate place */
3323 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][TAUT_NON]; k++)
3324 : : {
3325 : 0 : INChI* pInChI = &pInpInChI[iINChI][TAUT_NON][k];
3326 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs != 0)
3327 : : {
3328 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3329 : 0 : goto fini;
3330 : : }
3331 : : }
3332 : : }
3333 : : }
3334 : : }
3335 : : }
3336 : 0 : fini:;
3337 : : #endif
3338 [ # # ]: 0 : if (num_elem[iINChI][TAUT_YES])
3339 : : {
3340 : 0 : tot_charge[iINChI][TAUT_YES] += nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
3341 : 0 : num_elem[iINChI][TAUT_YES][EL_NUMBER_H].num += nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
3342 : : }
3343 : :
3344 : : /**** Count H and isotopic H in Mobile and Fixed H represntations of components */
3345 : : /* if at least one component has Fixed-H layer then all components have Fixed-H */
3346 : : /* layer; those whose Fixed-H layer is empty have Fixed-H layer same as Mobile-H layer */
3347 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_NON])
3348 : : {
3349 : : /* only if both Mobile and Fixed H exist */
3350 : : int nFormulaH[TAUT_NUM], nNumH[TAUT_NUM], nCharge[TAUT_NUM], nNumIsotopicH[TAUT_NUM][NUM_H_ISOTOPES];
3351 : : int nRemovedCharge, nRemovedH, nRemovedIsotopicH[NUM_H_ISOTOPES], nFoundRemovedIsoH;
3352 : : int nTotRemovedProtons, nTotRemovedIsotopicH[NUM_H_ISOTOPES], bExists[TAUT_NUM];
3353 : : INChI* pInChI[TAUT_NUM];
3354 : 0 : nTotRemovedProtons = 0;
3355 : 0 : memset(nTotRemovedIsotopicH, 0, sizeof(nTotRemovedIsotopicH)); /* djb-rwth: memset_s C11/Annex K variant? */
3356 : 0 : len2 = inchi_max(nNumComponents[iINChI][TAUT_YES], nNumComponents[iINChI][TAUT_NON]);
3357 : :
3358 [ # # ]: 0 : for (k = 0; k < len2; k++)
3359 : : {
3360 : : /* k is a component index */
3361 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3362 : : {
3363 : : /* j is 0=TAUT_NON or 1=TAUT_YES */
3364 : 0 : pInChI[j] = NULL; /* initialization 2006-03 */
3365 : 0 : bExists[j] = (k < nNumComponents[iINChI][j]) &&
3366 [ # # # # ]: 0 : pInpInChI[iINChI][j][k].nNumberOfAtoms &&
3367 [ # # ]: 0 : !pInpInChI[iINChI][j][k].bDeleted;
3368 : : }
3369 [ # # ]: 0 : if (!bExists[TAUT_NON])
3370 : : {
3371 : : /* TAUT_YES does not exist for a proton (H+) in TAUT_NON */
3372 : 0 : ret2 = RI_ERR_SYNTAX;
3373 : 0 : goto exit_function;
3374 : : }
3375 : : /* at this point at least one of Mobile[k] and Fixed[k] real InChI exists */
3376 : : /* initialize for counting removed protons and isotopic H from kth Mobile-H component */
3377 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3378 : : {
3379 [ # # ]: 0 : if (bExists[j])
3380 : : {
3381 : 0 : pInChI[j] = &pInpInChI[iINChI][j][k]; /* BC: reading uninit memory (fixed?) */
3382 : : }
3383 : 0 : nFormulaH[j] = 0;
3384 : 0 : nNumH[j] = 0;
3385 : 0 : nCharge[j] = 0;
3386 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3387 : : {
3388 : 0 : nNumIsotopicH[j][m] = 0;
3389 : : }
3390 : : }
3391 : : /* extract number of H, isotopic H, and charge */
3392 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3393 : : {
3394 [ # # ]: 0 : if (!bExists[j])
3395 : : {
3396 : 0 : continue;
3397 : : }
3398 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI[j], &nFormulaH[j])) ||
3399 [ # # ]: 0 : 0 > (ret2 = GetInChINumH(pInChI[j], &nNumH[j])) ||
3400 : 0 : 0 > (ret2 = GetInChIIsoH(pInChI[j], nNumIsotopicH[j])))
3401 : : {
3402 : 0 : goto exit_function;
3403 : : }
3404 : 0 : nCharge[j] = pInChI[j]->nTotalCharge;
3405 : : }
3406 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3407 : : {
3408 [ # # ]: 0 : if (!bExists[j])
3409 : : {
3410 : 0 : continue;
3411 : : }
3412 [ # # ]: 0 : if (nFormulaH[j] != nNumH[j])
3413 : : {
3414 : 0 : ret2 = RI_ERR_SYNTAX;
3415 : 0 : goto exit_function;
3416 : : }
3417 : : }
3418 : 0 : nFoundRemovedIsoH = 0;
3419 : 0 : nRemovedCharge = nCharge[TAUT_NON] - nCharge[TAUT_YES];
3420 : 0 : nRemovedH = nNumH[TAUT_NON] - nNumH[TAUT_YES];
3421 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3422 : : {
3423 : 0 : nFoundRemovedIsoH += 0 != (nRemovedIsotopicH[m] = nNumIsotopicH[TAUT_NON][m] -
3424 : 0 : nNumIsotopicH[TAUT_YES][m]);
3425 : : }
3426 [ # # ]: 0 : if (nRemovedCharge != nRemovedH)
3427 : : {
3428 : 0 : ret2 = RI_ERR_SYNTAX;
3429 : 0 : goto exit_function;
3430 : : }
3431 [ # # # # ]: 0 : if (nRemovedCharge || nFoundRemovedIsoH)
3432 : : {
3433 : : COMPONENT_REM_PROTONS* pNumProtons;
3434 [ # # ]: 0 : if (!nNumProtons[iINChI][TAUT_YES].pNumProtons)
3435 : : {
3436 : : /* allocate only if needed */
3437 : 0 : nNumProtons[iINChI][TAUT_YES].pNumProtons =
3438 : 0 : (COMPONENT_REM_PROTONS*)inchi_calloc(len2,
3439 : : sizeof(nNumProtons[0][0].pNumProtons[0]));
3440 [ # # ]: 0 : if (!nNumProtons[iINChI][TAUT_YES].pNumProtons)
3441 : : {
3442 : 0 : ret2 = RI_ERR_ALLOC;
3443 : 0 : goto exit_function;
3444 : : }
3445 : : }
3446 : 0 : pNumProtons = nNumProtons[iINChI][TAUT_YES].pNumProtons + k;
3447 : 0 : pNumProtons->nNumRemovedProtons = nRemovedH;
3448 : 0 : nTotRemovedProtons += nRemovedH;
3449 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3450 : : {
3451 : 0 : pNumProtons->nNumRemovedIsotopicH[m] = nRemovedIsotopicH[m];
3452 : 0 : nTotRemovedIsotopicH[m] += nRemovedIsotopicH[m];
3453 : : }
3454 : : /* make sure the Mobile-H InChI has nTautomer */
3455 [ # # # # ]: 0 : if (pInChI[TAUT_YES] && bExists[TAUT_YES])
3456 : : {
3457 [ # # ]: 0 : if (!pInChI[TAUT_YES]->lenTautomer)
3458 : : {
3459 : 0 : pInChI[TAUT_YES]->lenTautomer = 1;
3460 : : }
3461 [ # # ]: 0 : if (!pInChI[TAUT_YES]->nTautomer)
3462 : : {
3463 : 0 : pInChI[TAUT_YES]->nTautomer = (AT_NUMB*)inchi_calloc(pInChI[TAUT_YES]->lenTautomer, sizeof(pInChI[0]->nTautomer[0]));
3464 : : }
3465 : : }
3466 : : }
3467 : : }
3468 [ # # ]: 0 : if (nNumProtons[iINChI][TAUT_YES].pNumProtons)
3469 : : {
3470 : : /* check consistency */
3471 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3472 : : int iso_diff[NUM_H_ISOTOPES], iso_diff_tot = 0;
3473 : : #endif
3474 [ # # ]: 0 : if (nTotRemovedProtons != nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons)
3475 : : {
3476 : 0 : ret2 = RI_ERR_SYNTAX;
3477 : 0 : goto exit_function;
3478 : : }
3479 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3480 : : for (m = 0; m < NUM_H_ISOTOPES; m++)
3481 : : {
3482 : : iso_diff[m] = nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m] - nTotRemovedIsotopicH[m];
3483 : : if (iso_diff[m] < 0)
3484 : : {
3485 : : ret2 = RI_ERR_SYNTAX;
3486 : : goto exit_function;
3487 : : }
3488 : : else
3489 : : {
3490 : : /* InChI-1.02b bug: nTotRemovedIsotopicH[m] < nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m] */
3491 : : /* in non-tautomeric components where D(+) or T(+) was removed from -NH(+)= or =OH(+) */
3492 : : iso_diff_tot += iso_diff[m];
3493 : : }
3494 : : }
3495 : : if (iso_diff_tot)
3496 : : {
3497 : : if (0 > bIsoMayBeArranged(bInchi2Struct, iso_diff, nNumProtons, pInpInChI, nNumComponents, iINChI))
3498 : : {
3499 : : ret2 = RI_ERR_SYNTAX;
3500 : : goto exit_function;
3501 : : }
3502 : : }
3503 : : #else
3504 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3505 : : {
3506 [ # # ]: 0 : if (nTotRemovedIsotopicH[m] != nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m])
3507 : : {
3508 : 0 : ret2 = RI_ERR_SYNTAX;
3509 : 0 : goto exit_function;
3510 : : }
3511 : : }
3512 : : #endif
3513 : : }
3514 : : }
3515 : :
3516 : : /* make Mobile H and Fixed H InChI arrays have same length */
3517 : 0 : len2 = len1 = 0;
3518 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_YES] < nNumComponents[iINChI][TAUT_NON])
3519 : : {
3520 : 0 : j = TAUT_YES; /* less components in Mobile-H layer */
3521 : 0 : len2 = nNumComponents[iINChI][TAUT_NON];
3522 : 0 : len1 = nNumComponents[iINChI][TAUT_YES];
3523 : : }
3524 : : else
3525 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_YES] > nNumComponents[iINChI][TAUT_NON])
3526 : : {
3527 : 0 : j = TAUT_NON; /* less components in Fixed-H layer */
3528 : 0 : len2 = nNumComponents[iINChI][TAUT_YES];
3529 : 0 : len1 = nNumComponents[iINChI][TAUT_NON];
3530 : : }
3531 : : /* always len1 <= len2; if Mobile-H and Fixed-H have same number of components then len1=len2=0 */
3532 [ # # # # ]: 0 : if (len2 && len1)
3533 : : {
3534 : 0 : INChI* pInChI = (INChI*)inchi_calloc(len2, sizeof(pInChI[0]));
3535 [ # # ]: 0 : if (!pInChI)
3536 : : {
3537 : 0 : ret2 = RI_ERR_ALLOC;
3538 : 0 : goto exit_function;
3539 : : }
3540 : 0 : memcpy(pInChI, pInpInChI[iINChI][j], len1 * sizeof(pInChI[0]));
3541 [ # # ]: 0 : inchi_free(pInpInChI[iINChI][j]);
3542 : 0 : pInpInChI[iINChI][j] = pInChI;
3543 : 0 : nNumComponents[iINChI][j] = len2;
3544 [ # # ]: 0 : for (; len1 < len2; len1++)
3545 : : {
3546 [ # # ]: 0 : if (j == TAUT_YES)
3547 : : {
3548 : : /* mark added to Mobile H layer components as deleted protons */
3549 [ # # ]: 0 : if (0 > (ret2 = nFillOutProtonMobileH(pInpInChI[iINChI][j] + len1)))
3550 : : {
3551 : 0 : goto exit_function;
3552 : : }
3553 [ # # ]: 0 : if (0 > (ret2 = nProtonCopyIsotopicInfo(pInpInChI[iINChI][j] + len1/* to */,
3554 : 0 : pInpInChI[iINChI][TAUT_NON] + len1/* from */)))
3555 : : {
3556 : 0 : goto exit_function;
3557 : : }
3558 : : }
3559 : : else
3560 : : {
3561 : : /* mark added to Fixed H layer components as empty deleted */
3562 : : /* this should not happen */
3563 : 0 : pInChI[len1].bDeleted = 1;
3564 : : }
3565 : : }
3566 : : }
3567 : : } /* end of iINChI cycle */
3568 : :
3569 : : /* check balances */
3570 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
3571 : : {
3572 [ # # ]: 0 : for (i = iINChI; i < INCHI_NUM; i++)
3573 : : {
3574 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3575 : : {
3576 [ # # ]: 0 : for (k = j; k < TAUT_NUM; k++)
3577 : : {
3578 [ # # # # : 0 : if ((iINChI != i || j != k) && num_elem[iINChI][j] && num_elem[i][k])
# # # # ]
3579 : : {
3580 [ # # ]: 0 : if (tot_charge[iINChI][j] != tot_charge[i][k])
3581 : : {
3582 : 0 : ret2 = RI_ERR_SYNTAX;
3583 : 0 : goto exit_function;
3584 : : }
3585 [ # # ]: 0 : for (m = 0; m <= nElDataLen; m++)
3586 : : {
3587 [ # # ]: 0 : if (num_elem[iINChI][j][m].num != num_elem[i][k][m].num)
3588 : : {
3589 : 0 : ret2 = RI_ERR_SYNTAX;
3590 : 0 : goto exit_function;
3591 : : }
3592 : : }
3593 : : /*
3594 : : if ( memcmp( num_elem[iINChI], num_elem[i][k], (nElDataLen+1)*sizeof(num_elem[0][0][0]) ) {
3595 : : ret2 = RI_ERR_SYNTAX;
3596 : : goto exit_function;
3597 : : }
3598 : : */
3599 : : }
3600 : : }
3601 : : }
3602 : : }
3603 : : }
3604 : :
3605 : : }
3606 : : else
3607 : : {
3608 : 0 : ret2 = ret;
3609 : : }
3610 : :
3611 : 0 : exit_function:
3612 : :
3613 [ # # ]: 0 : for (i = 0; i < INCHI_NUM; i++)
3614 : : {
3615 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3616 : : {
3617 [ # # ]: 0 : if (num_elem[i][j])
3618 : : {
3619 [ # # ]: 0 : inchi_free(num_elem[i][j]);
3620 : 0 : num_elem[i][j] = NULL;
3621 : : }
3622 : : }
3623 : : }
3624 [ # # # # ]: 0 : *nErr = (ret2 < 0 && ret2 != RI_ERR_EOL) ? ret2 : 0;
3625 : :
3626 : 0 : return ret;
3627 : : }
3628 : :
3629 : :
3630 : : /****************************************************************************/
3631 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3632 : : #undef TAUT_YES
3633 : : int bIsoMayBeArranged(int bInchi2Struct,
3634 : : int iso_diff[NUM_H_ISOTOPES],
3635 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
3636 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
3637 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
3638 : : int iINChI)
3639 : : {
3640 : : const int TAUT_YES = 1;
3641 : : int i, k, m, n_found = 0, n_found_at_in_component, n_found_H_in_component, i_iso_at, num_iso_H = 0, num_iso_H_orig, num_add_iso_H, orig_add_H;
3642 : : for (m = 0; m < NUM_H_ISOTOPES; m++)
3643 : : {
3644 : : num_iso_H += iso_diff[m];
3645 : : }
3646 : : num_iso_H_orig = num_iso_H;
3647 : : for (k = 0; k < nNumComponents[iINChI][TAUT_YES] && k < nNumComponents[iINChI][TAUT_NON]; k++)
3648 : : {
3649 : : INChI* pInChI = &pInpInChI[iINChI][TAUT_NON][k];
3650 : : INChI* pInChITaut = &pInpInChI[iINChI][TAUT_YES][k];
3651 : : if (pInChITaut->bDeleted || pInChI->bDeleted ||
3652 : : pInChITaut->nNumberOfIsotopicAtoms > 0 ||
3653 : : pInChITaut->lenTautomer > 1 && pInChITaut->nTautomer && pInChITaut->nTautomer[0] > 0 ||
3654 : : NULL == nNumProtons[iINChI][TAUT_YES].pNumProtons ||
3655 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons <= 0 ||
3656 : : pInChI->nNumberOfIsotopicAtoms > 0 ||
3657 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[0] ||
3658 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[1] ||
3659 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[2]
3660 : : )
3661 : : {
3662 : : continue;
3663 : : }
3664 : : /* check if fixed-H has isotopic H; count the possibilities */
3665 : : orig_add_H = nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons;
3666 : : n_found_at_in_component = 0; /* number of atoms that may accept isotopic H */
3667 : : n_found_H_in_component = 0;
3668 : : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
3669 : : {
3670 : : int nNumRemovedH = (int)pInChI->nNum_H[i] - (int)pInChITaut->nNum_H[i];
3671 : : if (nNumRemovedH > 0)
3672 : : {
3673 : : n_found_at_in_component++;
3674 : : n_found_H_in_component += nNumRemovedH;
3675 : : }
3676 : : }
3677 : : if (n_found_at_in_component > 0 && num_iso_H > 0 && bInchi2Struct)
3678 : : {
3679 : : pInChI->IsotopicAtom = (INChI_IsotopicAtom*)inchi_calloc(inchi_min(n_found_at_in_component, num_iso_H), sizeof(pInChI->IsotopicAtom[0]));
3680 : : }
3681 : : for (i = 0, i_iso_at = 0; i < pInChI->nNumberOfAtoms; i++)
3682 : : {
3683 : : int nNumRemovedH = (int)pInChI->nNum_H[i] - (int)pInChITaut->nNum_H[i];
3684 : : n_found += nNumRemovedH; /* found H removed in mobile-H layer */
3685 : : if (nNumRemovedH > 0 && num_iso_H > 0 && orig_add_H)
3686 : : {
3687 : : for (m = 0; m < NUM_H_ISOTOPES && 0 < num_iso_H && 0 < orig_add_H && 0 < nNumRemovedH; m++)
3688 : : {
3689 : : if (iso_diff[m] > 0)
3690 : : {
3691 : : num_add_iso_H = inchi_min(iso_diff[m], nNumRemovedH); /* atom limit */
3692 : : if (num_add_iso_H > orig_add_H) /* component limit */
3693 : : num_add_iso_H = orig_add_H;
3694 : : iso_diff[m] -= num_add_iso_H; /* update tot removed single isotope H limit */
3695 : : num_iso_H -= num_add_iso_H; /* update tot removed isotopic H limit */
3696 : : orig_add_H -= num_add_iso_H; /* update component limit */
3697 : : nNumRemovedH -= num_add_iso_H; /* update atom limit */
3698 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[m] += num_add_iso_H;
3699 : : if (pInChI->IsotopicAtom)
3700 : : {
3701 : : pInChI->IsotopicAtom[i_iso_at].nAtomNumber = i + 1;
3702 : : switch (m)
3703 : : {
3704 : : case 0:
3705 : : pInChI->IsotopicAtom[i_iso_at].nNum_H += num_add_iso_H;
3706 : : break;
3707 : : case 1:
3708 : : pInChI->IsotopicAtom[i_iso_at].nNum_D += num_add_iso_H;
3709 : : break;
3710 : : case 2:
3711 : : pInChI->IsotopicAtom[i_iso_at].nNum_T += num_add_iso_H;
3712 : : break;
3713 : : }
3714 : : }
3715 : : }
3716 : : }
3717 : : if (pInChI->IsotopicAtom)
3718 : : {
3719 : : i_iso_at++;
3720 : : }
3721 : : }
3722 : : }
3723 : : if (pInChI->IsotopicAtom && i_iso_at)
3724 : : {
3725 : : pInChI->nNumberOfIsotopicAtoms = i_iso_at;
3726 : : }
3727 : : }
3728 : : if (n_found - num_iso_H >= 0)
3729 : : {
3730 : : /* Success. Arrange isotopic H between components */
3731 : : }
3732 : :
3733 : : return n_found - num_iso_H_orig; /* >0 => ambiguous reconstruction, 0 => unambiguous, <0 => impossible */
3734 : : }
3735 : : #define TAUT_YES 1
3736 : : #endif
3737 : :
3738 : :
3739 : :
3740 : : /****************************************************************************/
3741 : : typedef enum tagAuxInfoState {
3742 : : AST_VERSION, /* 0 */
3743 : :
3744 : : AST_MOBILE_H_NUMBERS, /* 1 /N: */
3745 : : AST_MOBILE_H_ATOM_EQ, /* 2 /E: */
3746 : : AST_MOBILE_H_GROUP_EQ, /* 3 /gE: */
3747 : : AST_MOBILE_H_SP3_INV, /* 4 /it: */
3748 : : AST_MOBILE_H_SP3_INV_NUMBERS, /* 5 /iN: */
3749 : :
3750 : : AST_MOBILE_H_ISO_LAYER_FORK, /* 6 */
3751 : :
3752 : : AST_MOBILE_H_ISO_NUMBERS, /* 7 /I: */
3753 : : AST_MOBILE_H_ISO_ATOM_EQ, /* 8 /E: */
3754 : : AST_MOBILE_H_ISO_GROUP_EQ, /* 9 /gE: */
3755 : : AST_MOBILE_H_ISO_SP3_INV, /* 10 /it: */
3756 : : AST_MOBILE_H_ISO_SP3_INV_NUMBERS, /* 11 /iN: */
3757 : :
3758 : : AST_FIXED_H_LAYER_FORK, /* 12 */
3759 : :
3760 : : AST_FIXED_H_NUMBERS, /* 13 /F: */
3761 : : AST_FIXED_H_ATOM_EQ, /* 14 /E: */
3762 : : AST_FIXED_H_SP3_INV, /* 15 /it: */
3763 : : AST_FIXED_H_SP3_INV_NUMBERS, /* 16 /iN: */
3764 : :
3765 : : AST_FIXED_H_ISO_LAYER_FORK, /* 17 */
3766 : :
3767 : : AST_FIXED_H_ISO_NUMBERS, /* 18 /I: */
3768 : : AST_FIXED_H_ISO_ATOM_EQ, /* 19 /E: */
3769 : : AST_FIXED_H_ISO_SP3_INV, /* 20 /it: */
3770 : : AST_FIXED_H_ISO_SP3_INV_NUMBERS, /* 21 /iN: */
3771 : :
3772 : : AST_REVERSE_INFO_CRV, /* 22 /CRV: */
3773 : : AST_REVERSE_INFO_ATOMS, /* 23 /rA: */
3774 : : AST_REVERSE_INFO_BONDS, /* 24 /rB: */
3775 : : AST_REVERSE_INFO_XYZ, /* 25 /rC: */
3776 : :
3777 : : AST_RECONNECTED_LAYER_FORK, /* 26 /R: */
3778 : : AST_RECONNECTED_LAYER_NUMBERS /* 27 */
3779 : : }AUX_INFO_STATE;
3780 : :
3781 : :
3782 : : /****************************************************************************/
3783 : 0 : int ParseAuxSegmentVersion(const char* str,
3784 : : int bMobileH,
3785 : : INChI* pInpInChI[],
3786 : : int ppnNumComponents[],
3787 : : int state)
3788 : : {
3789 : : const char* q;
3790 [ # # # # ]: 0 : if (isdigit(UCINT * str) && (inchi_strtol(str, &q, 10), !*q))
3791 : : {
3792 : 0 : return 1;
3793 : : }
3794 : 0 : return RI_ERR_SYNTAX;
3795 : : }
3796 : :
3797 : :
3798 : : /****************************************************************************
3799 : : CopyAtomNumbers
3800 : :
3801 : : Save isotopic numbering into the first nNumberOfAtoms
3802 : : elements of INChI::nPossibleLocationsOfIsotopicH;
3803 : : save non-isotopic numbering into the second half of
3804 : : nNumberOfAtoms elements of INChI::nPossibleLocationsOfIsotopicH
3805 : : ****************************************************************************/
3806 : 0 : int CopyAtomNumbers(INChI* pInChI_To,
3807 : : int bIsoTo,
3808 : : INChI* pInChI_From,
3809 : : int bIsoFrom)
3810 : : {
3811 : : AT_NUMB* pTo, * pFrom;
3812 [ # # # # : 0 : if (!pInChI_To || !pInChI_From || pInChI_To->bDeleted || pInChI_From->bDeleted ||
# # # # ]
3813 [ # # # # ]: 0 : !pInChI_To->nNumberOfAtoms || !pInChI_From->nNumberOfAtoms ||
3814 [ # # ]: 0 : pInChI_To->nNumberOfAtoms != pInChI_From->nNumberOfAtoms ||
3815 [ # # ]: 0 : !pInChI_From->nPossibleLocationsOfIsotopicH)
3816 : : {
3817 : 0 : return RI_ERR_PROGR;
3818 : : }
3819 [ # # ]: 0 : if (!pInChI_To->nPossibleLocationsOfIsotopicH)
3820 : : {
3821 : 0 : pInChI_To->nPossibleLocationsOfIsotopicH = (AT_NUMB*)inchi_calloc(2 * (long long)pInChI_To->nNumberOfAtoms,
3822 : : sizeof(pInChI_To->nPossibleLocationsOfIsotopicH[0])); /* djb-rwth: cast operator added */
3823 [ # # ]: 0 : if (!pInChI_To->nPossibleLocationsOfIsotopicH)
3824 : : {
3825 : 0 : return RI_ERR_ALLOC;
3826 : : }
3827 : : }
3828 [ # # ]: 0 : pTo = pInChI_To->nPossibleLocationsOfIsotopicH + (bIsoTo ? 0 : pInChI_To->nNumberOfAtoms);
3829 [ # # ]: 0 : pFrom = pInChI_From->nPossibleLocationsOfIsotopicH + (bIsoFrom ? 0 : pInChI_To->nNumberOfAtoms);
3830 [ # # ]: 0 : if (pTo == pFrom)
3831 : : {
3832 : 0 : return RI_ERR_PROGR;
3833 : : }
3834 : 0 : memcpy(pTo, pFrom, pInChI_To->nNumberOfAtoms * sizeof(pTo[0]));
3835 : 0 : return 1;
3836 : : }
3837 : :
3838 : :
3839 : : /****************************************************************************
3840 : : Parse and save AuxInfo atom numbers in "/N:" or "/F:" or "/I:" segment
3841 : :
3842 : : NB: save isotopic numbering into the first nNumberOfAtoms
3843 : : elements of INChI::nPossibleLocationsOfIsotopicH;
3844 : : save non-isotopic numbering into the second half of nNumberOfAtoms
3845 : : elements of INChI::nPossibleLocationsOfIsotopicH
3846 : : ****************************************************************************/
3847 : 0 : int ParseAuxSegmentNumbers(const char* str, /* AuxInfo string */
3848 : : int bMobileH, /* treat mobile or fixedH domain nums */
3849 : : INChI* pInpInChI[],
3850 : : int ppnNumComponents[],
3851 : : int state, /* start position==state of reading */
3852 : : int* pbAbc /* ==1 if treating compresssed InChI */
3853 : : )
3854 : : {
3855 : 0 : int bIso = 0, iComponent = 0, nNumComponents, bIso_From = 0, bAltInChIExists;
3856 : 0 : INChI* pInChI = NULL, * pAltInChI = NULL, * pInChI_From = NULL;
3857 : : const char* p, * q, * pStart, * pEnd, * t;
3858 : : static const char mult_type[] = "mnM";
3859 : : int val, ret, k, mpy_component, num;
3860 : : AT_NUMB* pNumb;
3861 : 0 : int base = 10;
3862 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
3863 : :
3864 [ # # # # : 0 : switch (state)
# ]
3865 : : {
3866 : 0 : case AST_MOBILE_H_NUMBERS:
3867 [ # # ]: 0 : if (bMobileH != TAUT_YES)
3868 : : {
3869 : 0 : return RI_ERR_PROGR;
3870 : : }
3871 [ # # ]: 0 : if (memcmp(str, "N:", 2))
3872 : : {
3873 : 0 : return 0;
3874 : : }
3875 : 0 : break;
3876 : 0 : case AST_FIXED_H_NUMBERS:
3877 [ # # ]: 0 : if (bMobileH != TAUT_NON)
3878 : : {
3879 : 0 : return RI_ERR_PROGR;
3880 : : }
3881 [ # # ]: 0 : if (memcmp(str, "F:", 2))
3882 : : {
3883 : 0 : return 0;
3884 : : }
3885 : 0 : break;
3886 : 0 : case AST_MOBILE_H_ISO_NUMBERS:
3887 [ # # ]: 0 : if (bMobileH != TAUT_YES)
3888 : : {
3889 : 0 : return RI_ERR_PROGR;
3890 : : }
3891 [ # # ]: 0 : if (memcmp(str, "I:", 2))
3892 : : {
3893 : 0 : return 0;
3894 : : }
3895 : 0 : bIso = 1;
3896 : 0 : break;
3897 : 0 : case AST_FIXED_H_ISO_NUMBERS:
3898 [ # # ]: 0 : if (bMobileH != TAUT_NON)
3899 : : {
3900 : 0 : return RI_ERR_PROGR;
3901 : : }
3902 [ # # ]: 0 : if (memcmp(str, "I:", 2))
3903 : : {
3904 : 0 : return 0;
3905 : : }
3906 : 0 : bIso = 1;
3907 : 0 : break;
3908 : 0 : default:
3909 : 0 : return RI_ERR_PROGR;
3910 : : }
3911 : :
3912 : 0 : pStart = (char*)str + 2;
3913 [ # # ]: 0 : if (!*pStart)
3914 : : {
3915 : 0 : return 1;
3916 : : }
3917 : 0 : iComponent = 0;
3918 : 0 : nNumComponents = ppnNumComponents[bMobileH];
3919 : :
3920 [ # # ]: 0 : bAltInChIExists = (NULL != pInpInChI[ALT_TAUT(bMobileH)]);
3921 : : while (1)
3922 : : {
3923 : : /* Cycle over components */
3924 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
3925 : : {
3926 : 0 : pEnd = pStart + strlen(pStart);
3927 : : }
3928 : : /* check */
3929 [ # # ]: 0 : if (!pInpInChI[bMobileH])
3930 : : {
3931 : 0 : return 1; /* invalid aux info */
3932 : : }
3933 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
3934 [ # # ]: 0 : pAltInChI = pInpInChI[ALT_TAUT(bMobileH)] + iComponent;
3935 : :
3936 : : /* djb-rwth: condition for if block had to be rewritten */
3937 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
3938 : : {
3939 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
3940 : 0 : if_cnd = isdigit(UCINT * pStart);
3941 : :
3942 : : }
3943 : : else
3944 : : {
3945 : 0 : val = 1;
3946 : 0 : q = pStart;
3947 : 0 : if_cnd = 1;
3948 : : }
3949 : :
3950 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used to store function return value */
# # ]
3951 : : {
3952 : : /* Process the abbreviation */
3953 : 0 : pInChI_From = NULL;
3954 [ # # # ]: 0 : switch (bMobileH)
3955 : : {
3956 : 0 : case TAUT_YES:
3957 [ # # # ]: 0 : switch (bIso)
3958 : : {
3959 : 0 : case 0:
3960 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
3961 : 0 : goto exit_function;
3962 : 0 : case 1:
3963 [ # # ]: 0 : if (*q != 'm')
3964 : : {
3965 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
3966 : 0 : goto exit_function;
3967 : : }
3968 : : /* isotopic Mobile-H <-- non-isotopic Mobile H */
3969 : 0 : pInChI_From = pInChI;
3970 : 0 : bIso_From = 0;
3971 : 0 : break;
3972 : 0 : default:
3973 : 0 : ret = RI_ERR_PROGR;
3974 : 0 : goto exit_function;
3975 : : }
3976 : 0 : break;
3977 : :
3978 : 0 : case TAUT_NON:
3979 [ # # # # ]: 0 : switch (*q)
3980 : : {
3981 : 0 : case 'm': /* same as mobile H */
3982 [ # # # ]: 0 : switch (bIso)
3983 : : {
3984 : 0 : case 0: /* from Mobile-H not isotopic */
3985 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;
3986 : 0 : bIso_From = 0;
3987 : 0 : break;
3988 : :
3989 : 0 : case 1:
3990 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;;
3991 : 0 : bIso_From = 1;
3992 : 0 : break;
3993 : 0 : default:
3994 : 0 : ret = RI_ERR_PROGR;
3995 : 0 : goto exit_function;
3996 : : }
3997 : 0 : break;
3998 : 0 : case 'n': /* same as non-isotopic Fixed-H */
3999 [ # # # ]: 0 : switch (bIso)
4000 : : {
4001 : 0 : case 0:
4002 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
4003 : 0 : goto exit_function;
4004 : 0 : case 1:
4005 : 0 : pInChI_From = pInChI; /* djb-rwth: ignoring LLVM warning: value used */
4006 : 0 : bIso_From = 0; /* djb-rwth: ignoring LLVM warning: value used */
4007 : 0 : default:
4008 : 0 : ret = RI_ERR_PROGR;
4009 : 0 : goto exit_function;
4010 : : }
4011 : : break;
4012 : 0 : case 'M': /* same as isotopic Mobile-H */
4013 [ # # # ]: 0 : switch (bIso)
4014 : : {
4015 : 0 : case 0:
4016 : 0 : ret = RI_ERR_SYNTAX;
4017 : 0 : goto exit_function;
4018 : 0 : case 1:
4019 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;;
4020 : 0 : bIso_From = 1;
4021 : 0 : break;
4022 : 0 : default:
4023 : 0 : ret = RI_ERR_PROGR;
4024 : 0 : goto exit_function;
4025 : : }
4026 : 0 : break;
4027 : 0 : default:
4028 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
4029 : 0 : goto exit_function;
4030 : : }
4031 : 0 : break;
4032 : : }
4033 : :
4034 : : /* Save numbers */
4035 [ # # ]: 0 : if (pInChI_From)
4036 : : {
4037 [ # # ]: 0 : for (k = 0; k < val; k++)
4038 : : {
4039 : 0 : CopyAtomNumbers(pInChI + k, bIso, pInChI_From + k, bIso_From); /* djb-rwth: addressing coverity ID #499525 -- return values handled properly */
4040 : : }
4041 : : }
4042 : 0 : mpy_component = val;
4043 : : }
4044 : : else
4045 : : {
4046 : 0 : mpy_component = 1;
4047 : 0 : p = pStart; /* djb-rwth: ignoring LLVM warning: value used */
4048 : 0 : pNumb = pInChI->nPossibleLocationsOfIsotopicH;
4049 [ # # ]: 0 : if (!pNumb)
4050 : : {
4051 : 0 : pNumb = (AT_NUMB*)inchi_calloc(2 * (long long)pInChI->nNumberOfAtoms, sizeof(pNumb[0])); /* djb-rwth: cast operator added */
4052 [ # # ]: 0 : if (!pNumb)
4053 : : {
4054 : 0 : ret = RI_ERR_ALLOC;
4055 : 0 : goto exit_function;
4056 : : }
4057 : 0 : pInChI->nPossibleLocationsOfIsotopicH = pNumb;
4058 : : }
4059 [ # # ]: 0 : pNumb += bIso ? 0 : pInChI->nNumberOfAtoms;
4060 [ # # # # ]: 0 : if (pStart < pEnd && *pbAbc == -1)
4061 : : {
4062 : : /* Check if compressed InChI */
4063 : 0 : *pbAbc = isupper(UCINT * pStart) ? 1 : 0;
4064 : : }
4065 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
4066 : :
4067 [ # # ]: 0 : if (*pbAbc == 1)
4068 : : {
4069 [ # # # # ]: 0 : for (k = 0, p = pStart; k < pInChI->nNumberOfAtoms && p < pEnd; k++, p++)
4070 : : {
4071 : 0 : num = (AT_NUMB)inchi_strtol(p, &q, base);
4072 : : #if ( CHECK_STRTOL_ATNUMB==1 )
4073 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
4074 : : {
4075 : 0 : ret = RI_ERR_SYNTAX;
4076 : 0 : goto exit_function;
4077 : : }
4078 : : #endif
4079 [ # # # # ]: 0 : if (num <= 0 || p == q)
4080 : : {
4081 : 0 : ret = RI_ERR_SYNTAX;
4082 : 0 : goto exit_function;
4083 : : }
4084 : 0 : pNumb[k] = (AT_NUMB)num;
4085 : 0 : p = q;
4086 [ # # ]: 0 : if (p == pEnd)
4087 : : {
4088 : 0 : break; /* main end of cycle */
4089 : : }
4090 : : }
4091 : : }
4092 : : else
4093 : : {
4094 [ # # # # ]: 0 : for (k = 0, p = pStart; k < pInChI->nNumberOfAtoms && p < pEnd; k++, p++)
4095 : : {
4096 : 0 : pNumb[k] = (AT_NUMB)inchi_strtol(p, &q, 10);
4097 : : #if ( CHECK_STRTOL_ATNUMB==1 )
4098 [ # # ]: 0 : if (pNumb[k] > MAX_ATOMS || pNumb[k] < 0)
4099 : : {
4100 : 0 : ret = RI_ERR_SYNTAX;
4101 : 0 : goto exit_function;
4102 : : }
4103 : : #endif
4104 : 0 : p = q;
4105 [ # # ]: 0 : if (p == pEnd)
4106 : : {
4107 : 0 : break; /* main end of cycle */
4108 : : }
4109 : : else
4110 : : {
4111 [ # # ]: 0 : if (*p != ',')
4112 : : {
4113 : 0 : ret = RI_ERR_SYNTAX;
4114 : 0 : goto exit_function;
4115 : : }
4116 : : }
4117 : : }
4118 : : }
4119 [ # # # # ]: 0 : if (p != pEnd || k + 1 != pInChI->nNumberOfAtoms)
4120 : : {
4121 : 0 : ret = RI_ERR_SYNTAX;
4122 : 0 : goto exit_function;
4123 : : }
4124 : : }
4125 : :
4126 : 0 : iComponent += mpy_component;
4127 [ # # ]: 0 : if (*pEnd)
4128 : : {
4129 : 0 : pStart = pEnd + 1;
4130 : 0 : continue;
4131 : : }
4132 : : else
4133 : : {
4134 : 0 : break;
4135 : : }
4136 : : } /* end of cycle over components */
4137 : :
4138 [ # # ]: 0 : if (nNumComponents != iComponent)
4139 : : {
4140 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
4141 : 0 : goto exit_function;
4142 : : }
4143 : 0 : ret = iComponent + 1;
4144 : :
4145 : 0 : exit_function:
4146 : :
4147 : 0 : return ret;
4148 : : }
4149 : :
4150 : :
4151 : : /****************************************************************************
4152 : : Read and skip AuxInfo segment atom equivalence classes, "/E:" segments
4153 : : ****************************************************************************/
4154 : 0 : int ParseAuxSegmentAtomEqu(const char* str,
4155 : : int bMobileH,
4156 : : INChI* pInpInChI[],
4157 : : int ppnNumComponents[],
4158 : : int state)
4159 : : {
4160 [ # # # # : 0 : switch (state)
# ]
4161 : : {
4162 : 0 : case AST_MOBILE_H_ATOM_EQ:
4163 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4164 : : {
4165 : 0 : return RI_ERR_PROGR;
4166 : : }
4167 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4168 : : {
4169 : 0 : return 0;
4170 : : }
4171 : 0 : break;
4172 : 0 : case AST_MOBILE_H_ISO_ATOM_EQ:
4173 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4174 : : {
4175 : 0 : return RI_ERR_PROGR;
4176 : : }
4177 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4178 : : {
4179 : 0 : return 0;
4180 : : }
4181 : 0 : break;
4182 : 0 : case AST_FIXED_H_ATOM_EQ:
4183 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4184 : : {
4185 : 0 : return RI_ERR_PROGR;
4186 : : }
4187 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4188 : : {
4189 : 0 : return 0;
4190 : : }
4191 : 0 : break;
4192 : 0 : case AST_FIXED_H_ISO_ATOM_EQ:
4193 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4194 : : {
4195 : 0 : return RI_ERR_PROGR;
4196 : : }
4197 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4198 : : {
4199 : 0 : return 0;
4200 : : }
4201 : 0 : break;
4202 : 0 : default:
4203 : 0 : return RI_ERR_PROGR;
4204 : : }
4205 : :
4206 : 0 : return 1;
4207 : : }
4208 : :
4209 : :
4210 : : /****************************************************************************
4211 : : Read and skip AuxInfo segment group equivalence classes, "/gE:" segments
4212 : : ****************************************************************************/
4213 : 0 : int ParseAuxSegmentGroupEqu(const char* str,
4214 : : int bMobileH,
4215 : : INChI* pInpInChI[],
4216 : : int ppnNumComponents[],
4217 : : int state)
4218 : : {
4219 [ # # # ]: 0 : switch (state)
4220 : : {
4221 : 0 : case AST_MOBILE_H_GROUP_EQ:
4222 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4223 : : {
4224 : 0 : return RI_ERR_PROGR;
4225 : : }
4226 [ # # ]: 0 : if (memcmp(str, "gE:", 3))
4227 : : {
4228 : 0 : return 0;
4229 : : }
4230 : 0 : break;
4231 : 0 : case AST_MOBILE_H_ISO_GROUP_EQ:
4232 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4233 : : {
4234 : 0 : return RI_ERR_PROGR;
4235 : : }
4236 [ # # ]: 0 : if (memcmp(str, "gE:", 3))
4237 : : {
4238 : 0 : return 0;
4239 : : }
4240 : 0 : break;
4241 : 0 : default:
4242 : 0 : return RI_ERR_PROGR;
4243 : : }
4244 : :
4245 : 0 : return 1;
4246 : : }
4247 : :
4248 : :
4249 : : /****************************************************************************
4250 : : Read and skip AuxInfo segment sp3 inv info, , "/it:" segment
4251 : : ****************************************************************************/
4252 : 0 : int ParseAuxSegmentSp3Inv(const char* str,
4253 : : int bMobileH,
4254 : : INChI* pInpInChI[],
4255 : : int ppnNumComponents[],
4256 : : int state)
4257 : : {
4258 [ # # # # : 0 : switch (state)
# ]
4259 : : {
4260 : 0 : case AST_MOBILE_H_SP3_INV:
4261 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4262 : : {
4263 : 0 : return RI_ERR_PROGR;
4264 : : }
4265 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4266 : : {
4267 : 0 : return 0;
4268 : : }
4269 : 0 : break;
4270 : 0 : case AST_MOBILE_H_ISO_SP3_INV:
4271 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4272 : : {
4273 : 0 : return RI_ERR_PROGR;
4274 : : }
4275 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4276 : : {
4277 : 0 : return 0;
4278 : : }
4279 : 0 : break;
4280 : 0 : case AST_FIXED_H_SP3_INV:
4281 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4282 : : {
4283 : 0 : return RI_ERR_PROGR;
4284 : : }
4285 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4286 : : {
4287 : 0 : return 0;
4288 : : }
4289 : 0 : break;
4290 : 0 : case AST_FIXED_H_ISO_SP3_INV:
4291 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4292 : : {
4293 : 0 : return RI_ERR_PROGR;
4294 : : }
4295 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4296 : : {
4297 : 0 : return 0;
4298 : : }
4299 : 0 : break;
4300 : 0 : default:
4301 : 0 : return RI_ERR_PROGR;
4302 : : }
4303 : :
4304 : 0 : return 1;
4305 : : }
4306 : :
4307 : :
4308 : : /****************************************************************************
4309 : : Read and skip AuxInfo atom numbers in "/iN:"segment,
4310 : : for sp3 inv sub-layer at specific reading state
4311 : : ****************************************************************************/
4312 : 0 : int ParseAuxSegmentSp3InvNumbers(const char* str,
4313 : : int bMobileH,
4314 : : INChI* pInpInChI[],
4315 : : int ppnNumComponents[],
4316 : : int state)
4317 : : {
4318 [ # # # # : 0 : switch (state)
# ]
4319 : : {
4320 : 0 : case AST_MOBILE_H_SP3_INV_NUMBERS:
4321 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4322 : : {
4323 : 0 : return RI_ERR_PROGR;
4324 : : }
4325 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4326 : : {
4327 : 0 : return 0;
4328 : : }
4329 : 0 : break;
4330 : 0 : case AST_MOBILE_H_ISO_SP3_INV_NUMBERS:
4331 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4332 : : {
4333 : 0 : return RI_ERR_PROGR;
4334 : : }
4335 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4336 : : {
4337 : 0 : return 0;
4338 : : }
4339 : 0 : break;
4340 : 0 : case AST_FIXED_H_SP3_INV_NUMBERS:
4341 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4342 : : {
4343 : 0 : return RI_ERR_PROGR;
4344 : : }
4345 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4346 : : {
4347 : 0 : return 0;
4348 : : }
4349 : 0 : break;
4350 : 0 : case AST_FIXED_H_ISO_SP3_INV_NUMBERS:
4351 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4352 : : {
4353 : 0 : return RI_ERR_PROGR;
4354 : : }
4355 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4356 : : {
4357 : 0 : return 0;
4358 : : }
4359 : 0 : break;
4360 : 0 : default:
4361 : 0 : return RI_ERR_PROGR;
4362 : : }
4363 : :
4364 : 0 : return 1;
4365 : : }
4366 : :
4367 : :
4368 : : /****************************************************************************
4369 : : Read and skip AuxInfo sp3 CRV (charge, radical, valence) segment
4370 : : ****************************************************************************/
4371 : 0 : int ParseAuxSegmentReverseCRV(const char* str, int state)
4372 : : {
4373 [ # # ]: 0 : switch (state)
4374 : : {
4375 : 0 : case AST_REVERSE_INFO_CRV:
4376 [ # # ]: 0 : if (memcmp(str, "CRV:", 4))
4377 : : {
4378 : 0 : return 0;
4379 : : }
4380 : 0 : break;
4381 : 0 : default:
4382 : 0 : return RI_ERR_PROGR;
4383 : : }
4384 : :
4385 : 0 : return 1;
4386 : : }
4387 : :
4388 : :
4389 : : /****************************************************************************
4390 : : Read and skip AuxInfo segment ReverseAtoms
4391 : : ****************************************************************************/
4392 : 0 : int ParseAuxSegmentReverseAtoms(const char* str, int state)
4393 : : {
4394 [ # # ]: 0 : switch (state)
4395 : : {
4396 : 0 : case AST_REVERSE_INFO_ATOMS:
4397 [ # # ]: 0 : if (memcmp(str, "rA:", 3))
4398 : : {
4399 : 0 : return 0;
4400 : : }
4401 : 0 : break;
4402 : 0 : default:
4403 : 0 : return RI_ERR_PROGR;
4404 : : }
4405 : :
4406 : 0 : return 1;
4407 : : }
4408 : :
4409 : :
4410 : : /****************************************************************************
4411 : : Read and skip AuxInfo segment ReverseBonds
4412 : : ****************************************************************************/
4413 : 0 : int ParseAuxSegmentReverseBonds(const char* str, int state)
4414 : : {
4415 [ # # ]: 0 : switch (state)
4416 : : {
4417 : 0 : case AST_REVERSE_INFO_BONDS:
4418 [ # # ]: 0 : if (memcmp(str, "rB:", 3))
4419 : : {
4420 : 0 : return 0;
4421 : : }
4422 : 0 : break;
4423 : 0 : default:
4424 : 0 : return RI_ERR_PROGR;
4425 : : }
4426 : :
4427 : 0 : return 1;
4428 : : }
4429 : :
4430 : :
4431 : : /* Parse and save AuxInfo segment ReverseXYZ */
4432 : 0 : int ParseAuxSegmentReverseXYZ(const char* str,
4433 : : XYZ_COORD** ppXYZ,
4434 : : int state)
4435 : : {
4436 : : const char* pStart, * p, * q;
4437 : 0 : XYZ_COORD* pXYZ = NULL;
4438 : 0 : int nLenXYZ = 0, i, j;
4439 : :
4440 [ # # ]: 0 : switch (state)
4441 : : {
4442 : 0 : case AST_REVERSE_INFO_XYZ:
4443 [ # # ]: 0 : if (memcmp(str, "rC:", 3))
4444 : : {
4445 : 0 : return 0;
4446 : : }
4447 : 0 : break;
4448 : 0 : default:
4449 : 0 : return RI_ERR_PROGR;
4450 : : }
4451 : 0 : pStart = (char*)str + 3;
4452 : : /* Count coordinates */
4453 [ # # ]: 0 : for (p = pStart, nLenXYZ = 0; *p; p++)
4454 : : {
4455 : 0 : nLenXYZ += (*p == ';');
4456 : : }
4457 [ # # ]: 0 : if (!nLenXYZ)
4458 : : {
4459 : 0 : return RI_ERR_SYNTAX;
4460 : : }
4461 [ # # ]: 0 : if (NULL == (pXYZ = (XYZ_COORD*)inchi_calloc(nLenXYZ, sizeof(pXYZ[0]))))
4462 : : {
4463 : 0 : return RI_ERR_ALLOC;
4464 : : }
4465 [ # # # # ]: 0 : for (p = pStart, i = 0; *p && i < nLenXYZ; p++, i++)
4466 : : {
4467 [ # # ]: 0 : for (j = 0; j < 3; j++)
4468 : : {
4469 : 0 : pXYZ[i].xyz[j] = inchi_strtod(p, &q);
4470 : 0 : p = q + (*q == ',');
4471 : : }
4472 [ # # ]: 0 : if (*p != ';')
4473 : : {
4474 : 0 : break;
4475 : : }
4476 : : }
4477 [ # # # # ]: 0 : if (i != nLenXYZ || *p)
4478 : : {
4479 [ # # ]: 0 : inchi_free(pXYZ); /* djb-rwth: fixing a NULL pointer dereference */
4480 : 0 : return RI_ERR_SYNTAX;
4481 : : }
4482 : 0 : *ppXYZ = pXYZ;
4483 : :
4484 : 0 : return nLenXYZ + 1;
4485 : : }
4486 : :
4487 : :
4488 : : /****************************************************************************
4489 : : Parse and save atom coordinates from AuxInfo
4490 : : ****************************************************************************/
4491 : 0 : int AddAuxSegmentCoord(int nRet,
4492 : : XYZ_COORD* pXYZ,
4493 : : int nLenXYZ,
4494 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
4495 : : int nNumComponents[INCHI_NUM][TAUT_NUM])
4496 : : {
4497 : 0 : int iINChI, j, k, n, m, numAt[TAUT_NUM], num_at, ret = 0; /* djb-rwth: removing redundant variables */
4498 : 0 : INChI* pInChI = NULL;
4499 : 0 : INChI* pAltInChI = NULL;
4500 : : XYZ_COORD* pxyz;
4501 : :
4502 : : /* Propagate numberings (original:canonical atom mapping) */
4503 : : /* NB: we already saved isotopic numbering, if any, into the first nNumberOfAtoms elements of INChI::nPossibleLocationsOfIsotopicH, */
4504 : : /* and the non-isotopic numbering into the second half of nNumberOfAtoms elements of that INChI::nPossibleLocationsOfIsotopicH */
4505 : :
4506 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
4507 : : {
4508 [ # # ]: 0 : for (j = TAUT_YES; TAUT_NON <= j; j--) /* for FixedH and MobileH ... */
4509 : : {
4510 [ # # ]: 0 : if (pInpInChI[iINChI][j]) /* djb-rwth: fixing a NULL pointer dereference */
4511 : : {
4512 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++) /* for each component ... */
4513 : : {
4514 [ # # ]: 0 : int jj = ALT_TAUT(j);
4515 : 0 : pInChI = pInpInChI[iINChI][j] + k;
4516 [ # # ]: 0 : pAltInChI = (k < nNumComponents[iINChI][jj]) ? pInpInChI[iINChI][jj] + k : NULL;
4517 [ # # ]: 0 : numAt[j] = (!pInChI->bDeleted) ? pInChI->nNumberOfAtoms : 0;
4518 [ # # # # ]: 0 : numAt[jj] = (pAltInChI && !pAltInChI->bDeleted) ? pAltInChI->nNumberOfAtoms : 0;
4519 [ # # # ]: 0 : switch (j)
4520 : : {
4521 : 0 : case TAUT_YES:
4522 [ # # ]: 0 : if (!numAt[j])
4523 : : {
4524 : 0 : break; /* component does not exist */
4525 : : }
4526 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4527 : : {
4528 : : /* djb-rwth: removing redundant code */
4529 : 0 : break;
4530 : : }
4531 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH[0])
4532 : : {
4533 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH[numAt[j]])
4534 : : {
4535 : : /* copy from non-isotopic (2nd half of the at. numbers array) to the isotopic (1st half) */
4536 : 0 : ret = CopyAtomNumbers(pInChI, 1, pInChI, 0);
4537 [ # # ]: 0 : if (ret < 0)
4538 : : {
4539 : 0 : goto exit_function;
4540 : : }
4541 : : }
4542 : : else
4543 : : {
4544 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4545 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4546 : : /* djb-rwth: removing redundant code */
4547 : : }
4548 : : }
4549 : 0 : break;
4550 : :
4551 : 0 : case TAUT_NON:
4552 [ # # ]: 0 : if (!numAt[j])
4553 : : {
4554 : 0 : break; /* component does not exist */
4555 : : }
4556 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4557 : : {
4558 : : /* trying to get numbers from Mobile-H component */
4559 [ # # # # ]: 0 : if (!numAt[jj] || !(pAltInChI->nPossibleLocationsOfIsotopicH))
4560 : : {
4561 : : /* djb-rwth: removing redundant code */
4562 : : break;
4563 : : }
4564 [ # # ]: 0 : if (pAltInChI->nPossibleLocationsOfIsotopicH[0])
4565 : : {
4566 : 0 : ret = CopyAtomNumbers(pInChI, 1, pAltInChI, 1);
4567 [ # # ]: 0 : if (ret < 0)
4568 : : {
4569 : 0 : goto exit_function;
4570 : : }
4571 : : }
4572 : : else
4573 [ # # ]: 0 : if (pAltInChI->nPossibleLocationsOfIsotopicH[numAt[jj]])
4574 : : {
4575 : 0 : ret = CopyAtomNumbers(pInChI, 1, pAltInChI, 0);
4576 [ # # ]: 0 : if (ret < 0)
4577 : : {
4578 : 0 : goto exit_function;
4579 : : }
4580 : : }
4581 : : else
4582 : : {
4583 : : /* pAltInChI->nPossibleLocationsOfIsotopicH should have */
4584 : : /* been deallocated on previous TAUT_YES pass */
4585 : 0 : ret = RI_ERR_PROGR;
4586 : 0 : goto exit_function;
4587 : : }
4588 : : }
4589 [ # # ]: 0 : else if (!pInChI->nPossibleLocationsOfIsotopicH[0])
4590 : : {
4591 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH[numAt[j]])
4592 : : {
4593 : : /* copy from non-isotopic to isotopic */
4594 : 0 : ret = CopyAtomNumbers(pInChI, 1, pInChI, 0);
4595 [ # # ]: 0 : if (ret < 0)
4596 : : {
4597 : 0 : goto exit_function;
4598 : : }
4599 : : }
4600 : : else
4601 : : {
4602 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4603 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4604 : : /* djb-rwth: removing redundant code */
4605 : : }
4606 : : }
4607 : 0 : break;
4608 : : }
4609 : : }
4610 : : }
4611 : : }
4612 : : }
4613 : :
4614 : : /* Add coordinates */
4615 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
4616 : : {
4617 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
4618 : : {
4619 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
4620 : : {
4621 : 0 : pInChI = pInpInChI[iINChI][j] + k;
4622 [ # # ]: 0 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
4623 : : {
4624 [ # # ]: 0 : num_at = (!pInChI->bDeleted) ? pInChI->nNumberOfAtoms : 0;
4625 [ # # ]: 0 : if (!num_at)
4626 : : {
4627 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH)
4628 : : {
4629 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4630 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4631 : : }
4632 : 0 : continue;
4633 : : }
4634 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4635 : : {
4636 : 0 : continue;
4637 : : }
4638 [ # # # # ]: 0 : if (iINChI == INCHI_BAS && num_at == 1 &&
4639 [ # # # # ]: 0 : pInChI->szHillFormula && !strcmp(pInChI->szHillFormula, "H") &&
4640 [ # # ]: 0 : (int)pInChI->nPossibleLocationsOfIsotopicH[0] - 1 >= nLenXYZ)
4641 : : {
4642 : : ; /* a single atom H disconnected from a metal atom has no coordinates */
4643 : : }
4644 : : else
4645 : : {
4646 : : /* add atom coordinates */
4647 : 0 : pxyz = (XYZ_COORD*)inchi_calloc(num_at, sizeof(pxyz[0]));
4648 [ # # ]: 0 : if (!pxyz)
4649 : : {
4650 : 0 : ret = RI_ERR_ALLOC;
4651 : 0 : goto exit_function;
4652 : : }
4653 [ # # ]: 0 : for (n = 0; n < num_at; n++)
4654 : : {
4655 : 0 : m = (int)pInChI->nPossibleLocationsOfIsotopicH[n] - 1;
4656 [ # # # # ]: 0 : if (m < 0 || m >= nLenXYZ)
4657 : : {
4658 [ # # ]: 0 : inchi_free(pxyz);
4659 : 0 : ret = RI_ERR_SYNTAX;
4660 : 0 : goto exit_function;
4661 : : }
4662 : 0 : pxyz[n] = pXYZ[m];
4663 : : }
4664 : 0 : pInChI->IsotopicTGroup = (INChI_IsotopicTGroup*)pxyz;
4665 : : }
4666 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4667 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4668 : : }
4669 : : }
4670 : : }
4671 : : }
4672 : 0 : ret = nRet; /* normal exit */
4673 : :
4674 : 0 : exit_function:
4675 : :
4676 : 0 : return ret;
4677 : : }
4678 : :
4679 : :
4680 : : /****************************************************************************
4681 : : ReadInChICoord (from AuxInfo if present)
4682 : : ****************************************************************************/
4683 : 0 : int ReadInChICoord(INCHI_IOSTREAM* pInp,
4684 : : SEGM_LINE* pLine,
4685 : : int* pState,
4686 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
4687 : : int nNumComponents[INCHI_NUM][TAUT_NUM])
4688 : : {
4689 : : int c;
4690 : : /* djb-rwth: removing redundant variables */
4691 : 0 : int ret = RI_ERR_ALLOC;
4692 : 0 : int bMobileH = TAUT_YES;
4693 : 0 : int bReconn = INCHI_BAS;
4694 : 0 : int state = -1;
4695 : 0 : int prev_state = -1;
4696 : 0 : int nLenXYZ = 0;
4697 : 0 : int bAbc = -1; /* initially undefined */
4698 : : const char
4699 : 0 : szToken[] = INCHI_TOKEN;
4700 : : XYZ_COORD
4701 : 0 : * pXYZ = NULL;
4702 : :
4703 : 0 : *pState = 0;
4704 : : INCHI_HEAPCHK
4705 : :
4706 : : /* Get "InChI=1/" */
4707 [ # # ]: 0 : if (pLine->len)
4708 : : {
4709 : 0 : c = pLine->c;
4710 : : }
4711 : : else
4712 : : {
4713 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
4714 : : }
4715 [ # # # # : 0 : if (c == RI_ERR_EOF && !pLine->len && !pLine->str[0])
# # ]
4716 : : {
4717 : 0 : ret = c;
4718 : 0 : pLine->len = 0;
4719 : 0 : goto exit_error;
4720 : : }
4721 [ # # # # : 0 : if (pLine->len == 0 || (c != SEG_END && c != RI_ERR_EOF && !INCHI_INP_EOL(c))) /* djb-rwth: addressing LLVM warning */
# # # # #
# # # ]
4722 : : {
4723 : 0 : *pState = -1;
4724 : 0 : pLine->len = 0;
4725 : 0 : ret = RI_ERR_PROGR;
4726 : 0 : goto exit_error;
4727 : : }
4728 [ # # ]: 0 : if (memcmp(pLine->str, "AuxInfo=", 8))
4729 : : {
4730 : 0 : *pState = -1;
4731 : 0 : return c;
4732 : : }
4733 : :
4734 : 0 : state = AST_VERSION;
4735 : 0 : ret = 1; /* means read the next segment */
4736 : : do
4737 : : {
4738 : : /* Read the next segment up to the '/' */
4739 : : INCHI_HEAPCHK
4740 [ # # ]: 0 : if (ret < 0)
4741 : : {
4742 : 0 : *pState = prev_state;
4743 : 0 : break;
4744 : : }
4745 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
4746 [ # # ]: 0 : if (0 < ret)
4747 : : {
4748 : : /* read next segment */
4749 [ # # # # ]: 0 : if (c != RI_ERR_EOF && c != SEG_END)
4750 : : {
4751 : : /* abnormal reading result; should not happen */
4752 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
4753 : : {
4754 : : /* bypass to the end of line or file */
4755 : 0 : c = getInChIChar(pInp);
4756 : : }
4757 [ # # ]: 0 : ret = (c == RI_ERR_EOF) ? RI_ERR_EOF : RI_ERR_EOL; /* end of line */
4758 : 0 : pLine->len = 0;
4759 : 0 : pLine->c = ret;
4760 : 0 : break;
4761 : : }
4762 [ # # ]: 0 : if (c == RI_ERR_EOF)
4763 : : {
4764 : 0 : ret = RI_ERR_EOF; /* end of line */
4765 : 0 : break;
4766 : : }
4767 [ # # ]: 0 : if (c == SEG_END)
4768 : : {
4769 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
4770 : : }
4771 [ # # ]: 0 : if (c < 0)
4772 : : {
4773 : 0 : goto exit_error; /* error */
4774 : : }
4775 [ # # ]: 0 : if (!pLine->len)
4776 : : {
4777 : 0 : ret = RI_ERR_EOL; /* end of line */
4778 : 0 : break;
4779 : : }
4780 : : /* djb-rwth: removing redundant code */
4781 : : }
4782 : :
4783 : : /* Process the seqment */
4784 [ # # # # : 0 : switch (state)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
4785 : : {
4786 : 0 : case AST_VERSION:
4787 : : /* Mobile H */
4788 : 0 : bMobileH = TAUT_YES;
4789 : 0 : ret = ParseAuxSegmentVersion(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4790 : 0 : state = AST_MOBILE_H_NUMBERS;
4791 : 0 : break;
4792 : 0 : case AST_MOBILE_H_NUMBERS:
4793 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4794 : 0 : state = AST_MOBILE_H_ATOM_EQ;
4795 : 0 : break;
4796 : 0 : case AST_MOBILE_H_ATOM_EQ:
4797 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4798 : 0 : state = AST_MOBILE_H_GROUP_EQ;
4799 : 0 : break;
4800 : 0 : case AST_MOBILE_H_GROUP_EQ:
4801 : 0 : ret = ParseAuxSegmentGroupEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4802 : 0 : state = AST_MOBILE_H_SP3_INV;
4803 : 0 : break;
4804 : 0 : case AST_MOBILE_H_SP3_INV:
4805 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4806 : 0 : state = AST_MOBILE_H_SP3_INV_NUMBERS;
4807 : 0 : break;
4808 : 0 : case AST_MOBILE_H_SP3_INV_NUMBERS:
4809 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4810 : 0 : state = AST_MOBILE_H_ISO_LAYER_FORK;
4811 : 0 : break;
4812 : :
4813 : 0 : case AST_MOBILE_H_ISO_LAYER_FORK:
4814 [ # # ]: 0 : if (!memcmp(pLine->str, "I:", 2))
4815 : : {
4816 : 0 : state = AST_MOBILE_H_ISO_NUMBERS;
4817 : : }
4818 [ # # ]: 0 : else if (!inchi_memicmp(pLine->str, "F:", 2))
4819 : : {
4820 : 0 : state = AST_FIXED_H_NUMBERS;
4821 : 0 : bMobileH = TAUT_NON;
4822 : : }
4823 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4824 : : {
4825 : 0 : state = AST_REVERSE_INFO_CRV;
4826 : : }
4827 : : else
4828 [ # # # # ]: 0 : if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4829 : : {
4830 : 0 : state = AST_REVERSE_INFO_ATOMS;
4831 : : }
4832 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4833 : : {
4834 : 0 : ret = 1; /* read the next segment */
4835 : 0 : state = AST_VERSION;
4836 : 0 : bMobileH = TAUT_YES;
4837 : 0 : bReconn = INCHI_REC;
4838 : : }
4839 : : else
4840 : : {
4841 : 0 : ret = RI_ERR_SYNTAX;
4842 : : }
4843 : 0 : break;
4844 : :
4845 : : /* Mobile H, isotopic */
4846 : 0 : case AST_MOBILE_H_ISO_NUMBERS:
4847 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4848 : 0 : state = AST_MOBILE_H_ISO_ATOM_EQ;
4849 : 0 : break;
4850 : 0 : case AST_MOBILE_H_ISO_ATOM_EQ:
4851 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4852 : 0 : state = AST_MOBILE_H_ISO_GROUP_EQ;
4853 : 0 : break;
4854 : 0 : case AST_MOBILE_H_ISO_GROUP_EQ:
4855 : 0 : ret = ParseAuxSegmentGroupEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4856 : 0 : state = AST_MOBILE_H_ISO_SP3_INV;
4857 : 0 : break;
4858 : 0 : case AST_MOBILE_H_ISO_SP3_INV:
4859 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4860 : 0 : state = AST_MOBILE_H_ISO_SP3_INV_NUMBERS;
4861 : 0 : break;
4862 : 0 : case AST_MOBILE_H_ISO_SP3_INV_NUMBERS:
4863 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4864 : 0 : state = AST_FIXED_H_LAYER_FORK;
4865 : 0 : break;
4866 : :
4867 : 0 : case AST_FIXED_H_LAYER_FORK:
4868 [ # # ]: 0 : if (!inchi_memicmp(pLine->str, "F:", 2))
4869 : : {
4870 : 0 : state = AST_FIXED_H_NUMBERS;
4871 : 0 : bMobileH = TAUT_NON;
4872 : : }
4873 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4874 : : {
4875 : 0 : state = AST_REVERSE_INFO_CRV;
4876 : : }
4877 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4878 : : {
4879 : 0 : state = AST_REVERSE_INFO_ATOMS;
4880 : : }
4881 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4882 : : {
4883 : 0 : ret = 1; /* read the next segment */
4884 : 0 : state = AST_VERSION;
4885 : 0 : bMobileH = TAUT_YES;
4886 : 0 : bReconn = INCHI_REC;
4887 : : }
4888 : : else
4889 : : {
4890 : 0 : ret = RI_ERR_SYNTAX;
4891 : : }
4892 : 0 : break;
4893 : :
4894 : 0 : case AST_FIXED_H_NUMBERS:
4895 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4896 : 0 : state = AST_FIXED_H_ATOM_EQ;
4897 : 0 : break;
4898 : 0 : case AST_FIXED_H_ATOM_EQ:
4899 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4900 : 0 : state = AST_FIXED_H_SP3_INV;
4901 : 0 : break;
4902 : 0 : case AST_FIXED_H_SP3_INV:
4903 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4904 : 0 : state = AST_FIXED_H_SP3_INV_NUMBERS;
4905 : 0 : break;
4906 : 0 : case AST_FIXED_H_SP3_INV_NUMBERS:
4907 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4908 : 0 : state = AST_FIXED_H_ISO_LAYER_FORK;
4909 : 0 : break;
4910 : :
4911 : 0 : case AST_FIXED_H_ISO_LAYER_FORK:
4912 [ # # ]: 0 : if (!memcmp(pLine->str, "I:", 2))
4913 : : {
4914 : 0 : state = AST_FIXED_H_ISO_NUMBERS;
4915 : : }
4916 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4917 : : {
4918 : 0 : state = AST_REVERSE_INFO_CRV;
4919 : : }
4920 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4921 : : {
4922 : 0 : state = AST_REVERSE_INFO_ATOMS;
4923 : : }
4924 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4925 : : {
4926 : 0 : ret = 1; /* read the next segment */
4927 : 0 : state = AST_VERSION;
4928 : 0 : bMobileH = TAUT_YES;
4929 : 0 : bReconn = INCHI_REC;
4930 : : }
4931 : : else
4932 : : {
4933 : 0 : ret = RI_ERR_SYNTAX;
4934 : : }
4935 : 0 : break;
4936 : :
4937 : 0 : case AST_FIXED_H_ISO_NUMBERS:
4938 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4939 : 0 : state = AST_FIXED_H_ISO_ATOM_EQ;
4940 : 0 : break;
4941 : 0 : case AST_FIXED_H_ISO_ATOM_EQ:
4942 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4943 : 0 : state = AST_FIXED_H_SP3_INV;
4944 : 0 : break;
4945 : 0 : case AST_FIXED_H_ISO_SP3_INV:
4946 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4947 : 0 : state = AST_FIXED_H_ISO_SP3_INV_NUMBERS;
4948 : 0 : break;
4949 : 0 : case AST_FIXED_H_ISO_SP3_INV_NUMBERS:
4950 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4951 : 0 : state = AST_REVERSE_INFO_CRV;
4952 : 0 : break;
4953 : 0 : case AST_REVERSE_INFO_CRV:
4954 : 0 : ret = ParseAuxSegmentReverseCRV(pLine->str, state);
4955 : : /* state = (bReconn == INCHI_BAS)? AST_REVERSE_INFO_ATOMS : AST_RECONNECTED_LAYER_FORK;*/
4956 : 0 : state = AST_REVERSE_INFO_ATOMS;
4957 : 0 : break;
4958 : 0 : case AST_REVERSE_INFO_ATOMS:
4959 : 0 : ret = ParseAuxSegmentReverseAtoms(pLine->str, state);
4960 : 0 : state = AST_REVERSE_INFO_BONDS;
4961 : 0 : break;
4962 : 0 : case AST_REVERSE_INFO_BONDS:
4963 : 0 : ret = ParseAuxSegmentReverseBonds(pLine->str, state);
4964 : 0 : state = AST_REVERSE_INFO_XYZ;
4965 : 0 : break;
4966 : 0 : case AST_REVERSE_INFO_XYZ:
4967 : 0 : ret = ParseAuxSegmentReverseXYZ(pLine->str, &pXYZ, state);
4968 : 0 : state = AST_RECONNECTED_LAYER_FORK;
4969 [ # # ]: 0 : if (ret > 0)
4970 : : {
4971 : 0 : nLenXYZ = ret - 1;
4972 : : }
4973 : 0 : break;
4974 : 0 : case AST_RECONNECTED_LAYER_FORK:
4975 [ # # # # ]: 0 : if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4976 : : {
4977 : 0 : ret = 1; /* read the next segment */
4978 : 0 : state = AST_VERSION;
4979 : 0 : bMobileH = TAUT_YES;
4980 : 0 : bReconn = INCHI_REC;
4981 : : }
4982 : : else
4983 : : {
4984 : 0 : ret = RI_ERR_SYNTAX;
4985 : : }
4986 : 0 : break;
4987 : : }
4988 [ # # ]: 0 : } while (c >= 0);
4989 : :
4990 [ # # ]: 0 : if (pXYZ) /* djb-rwth: fixing coverity ID #499576 */
4991 : : {
4992 : 0 : ret = AddAuxSegmentCoord(ret, pXYZ, nLenXYZ, pInpInChI, nNumComponents);
4993 : : }
4994 : : else
4995 : : {
4996 : 0 : ret = RI_ERR_ALLOC;
4997 : : }
4998 : :
4999 : 0 : exit_error:
5000 [ # # ]: 0 : if (pXYZ)
5001 : : {
5002 [ # # ]: 0 : inchi_free(pXYZ);
5003 : : }
5004 [ # # # # : 0 : if (ret >= 0 || c == RI_ERR_EOF || c == RI_ERR_EOL)
# # ]
5005 : : {
5006 : 0 : pLine->len = 0;
5007 : : }
5008 : :
5009 : 0 : return ret;
5010 : : }
5011 : :
5012 : :
5013 : : /****************************************************************************
5014 : : Read a single InChI input line
5015 : : ****************************************************************************/
5016 : 0 : int ReadInChILine(INCHI_IOSTREAM* pInp,
5017 : : SEGM_LINE* pLine,
5018 : : char** pStr,
5019 : : int* pState,
5020 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
5021 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
5022 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
5023 : : int s[INCHI_NUM][TAUT_NUM][2],
5024 : : int* bStdFormat,
5025 : : int* input_has_save_opt,
5026 : : unsigned char* input_save_opt_bits,
5027 : : int bInchi2Struct,
5028 : : OAD_Polymer** ppPolymer,
5029 : : OAD_V3000** ppV3000)
5030 : : {
5031 : 0 : int c, ret = RI_ERR_ALLOC, len; /* djb-rwth: removing redundant variables */
5032 : 0 : int bMobileH = TAUT_YES, bReconn = INCHI_BAS;
5033 : 0 : const char szToken[] = INCHI_TOKEN;
5034 : : char* p;
5035 : 0 : int state = -1, prev_state = -1;
5036 : 0 : int bAbc = -1; /* -1=> undefined, 0=> decimal, 1=> abc (compressed) */
5037 : :
5038 : 0 : const int len_std_prefix = 8;
5039 : 0 : size_t k = 0;
5040 : 0 : unsigned char let1 = 0, let2 = 0;
5041 : 0 : const char a2p[] = "ABCDEFGHIJKLMNOP";
5042 : :
5043 : 0 : int na_total = 0; /* whole struct, without explH */
5044 : 0 : int nb_total = 0; /* whole struct, without explH */
5045 : : #if ( DISABLE_READ_COMPRESSED_INCHI==1 )
5046 : 0 : bAbc = 0;
5047 : : /* We do not support compressed InChI explicitly */
5048 : : /* Parsing compressed InChI easily fails on fake/fuzzing inputs */
5049 : : #endif
5050 : : /* memset( pLine, 0, sizeof( pLine[0] ) ); */
5051 : 0 : * pState = 0;
5052 : :
5053 : 0 : next_line:
5054 : : INCHI_HEAPCHK
5055 : : /* Got "InChI=1/" */
5056 [ # # ]: 0 : if (pLine->len)
5057 : : {
5058 : 0 : c = pLine->c;
5059 : : }
5060 : : else
5061 : : {
5062 : : INCHI_HEAPCHK
5063 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
5064 : : INCHI_HEAPCHK
5065 : : }
5066 [ # # # # : 0 : if (pLine->str && (c == RI_ERR_EOF && !pLine->len && !pLine->str[0])) /* djb-rwth: fixing a NULL pointer dereference */
# # # # ]
5067 : : {
5068 : 0 : ret = c;
5069 : 0 : goto exit_function;
5070 : : }
5071 : : INCHI_HEAPCHK
5072 : :
5073 [ # # # # : 0 : if (pLine->str && (pLine->len == 0 || (c != SEG_END && c != RI_ERR_EOF) || !(p = strstr(pLine->str, "InChI=1")))) /* djb-rwth: fixing a NULL pointer dereference; addressing LLVM warning; ignoring LLVM warning: value used */
# # # # #
# ]
5074 : : {
5075 [ # # # # ]: 0 : if (pLine->str && pLine->str == strstr(pLine->str, "Structure"))
5076 : : {
5077 [ # # ]: 0 : if (*pStr)
5078 : : {
5079 : : INCHI_HEAPCHK
5080 [ # # ]: 0 : inchi_free(*pStr);
5081 : : }
5082 : 0 : *pStr = pLine->str;
5083 : : /* bypass to the end of the 'Structure nnn' line */
5084 : 0 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
5085 [ # # # # : 0 : while (c && !INCHI_INP_EOL(c))
# # # # ]
5086 : : {
5087 : 0 : c = getInChIChar(pInp);
5088 : : }
5089 : 0 : goto next_line;
5090 : : }
5091 : : /* bypass to the end of unrecognized line */
5092 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
5093 : : {
5094 : 0 : c = getInChIChar(pInp);
5095 : : }
5096 : 0 : pLine->len = 0;
5097 : : INCHI_HEAPCHK
5098 : 0 : goto next_line;
5099 : : }
5100 : :
5101 : :
5102 : : /* Check if got a standard InChI */
5103 [ # # # # : 0 : if (pLine->str && (pLine->len == len_std_prefix) && (pLine->str[len_std_prefix - 1] == 'S')) /* djb-rwth: fixing a NULL pointer dereference */
# # ]
5104 : : {
5105 : 0 : *bStdFormat = 1;
5106 : : }
5107 : : else
5108 : : {
5109 : 0 : *bStdFormat = 0;
5110 : : }
5111 : :
5112 : 0 : state = IST_MOBILE_H_FORMULA;
5113 : 0 : ret = 1; /* means read the next segment */
5114 : : do
5115 : : {
5116 : : /* read the next segment up to the '/' */
5117 : : INCHI_HEAPCHK
5118 [ # # ]: 0 : if (ret < 0)
5119 : : {
5120 : 0 : *pState = prev_state;
5121 : 0 : break;
5122 : : }
5123 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5124 [ # # ]: 0 : if (0 < ret)
5125 : : {
5126 : : /* read next segment */
5127 [ # # # # ]: 0 : if (c != RI_ERR_EOF && c != SEG_END)
5128 : : {
5129 : : /* abnormal reading result; should not happen */
5130 : : /* unless we got backslash-SaveOpt */
5131 [ # # ]: 0 : if (c == '\\')
5132 : : {
5133 : : /* May be SaveOpt */
5134 : 0 : *input_has_save_opt = 1;
5135 : : }
5136 : 0 : k = 0;
5137 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
5138 : : {
5139 : : /* bypass to the end of line or file */
5140 : 0 : c = getInChIChar(pInp);
5141 : 0 : k++;
5142 [ # # ]: 0 : if (k == 1)
5143 : : {
5144 : 0 : let1 = c;
5145 : : }
5146 : : else
5147 : : {
5148 [ # # ]: 0 : if (k == 2)
5149 : : {
5150 : 0 : let2 = c;
5151 : : }
5152 : : }
5153 : : }
5154 [ # # ]: 0 : if (k != 3)
5155 : : {
5156 : : /* not a valid SaveOpt which must be of two chars */
5157 : 0 : *input_has_save_opt = 0;
5158 : : /* djb-rwth: removing redundant code */
5159 : : }
5160 : : else
5161 : : {
5162 : : /* may be SaveOpt - analyze the content */
5163 [ # # # # ]: 0 : if ((let2 >= 'A') && (let2 <= 'D')) /* letter-2 OK */
5164 : : {
5165 : 0 : *input_has_save_opt = 0;
5166 : 0 : *input_save_opt_bits = 0;
5167 [ # # ]: 0 : for (k = 0; k < 16; k++)
5168 : : {
5169 [ # # ]: 0 : if (a2p[k] == let1) /* letter-1 OK */
5170 : : {
5171 : 0 : *input_save_opt_bits = (unsigned char)k;
5172 : 0 : *input_has_save_opt = 1;
5173 : 0 : break;
5174 : : }
5175 : : }
5176 [ # # ]: 0 : if (*input_has_save_opt)
5177 : : {
5178 [ # # # # ]: 0 : if (let2 == 'B' || let2 == 'D')
5179 : : {
5180 : 0 : *input_save_opt_bits |= SAVE_OPT_15T;
5181 : : }
5182 [ # # # # ]: 0 : if (let2 == 'C' || let2 == 'D')
5183 : : {
5184 : 0 : *input_save_opt_bits |= SAVE_OPT_KET;
5185 : : }
5186 : : }
5187 : : }
5188 : : }
5189 : :
5190 [ # # ]: 0 : ret = (c == RI_ERR_EOF) ? RI_ERR_EOF : RI_ERR_EOL; /* end of line */
5191 : 0 : pLine->len = 0;
5192 : 0 : pLine->c = ret;
5193 : 0 : break; /* exit */
5194 : : }
5195 [ # # ]: 0 : if (c == RI_ERR_EOF)
5196 : : {
5197 : 0 : ret = RI_ERR_EOF; /* end of line */
5198 : 0 : break;
5199 : : }
5200 [ # # ]: 0 : if (c == SEG_END)
5201 : : {
5202 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
5203 : : }
5204 [ # # ]: 0 : if (c < 0)
5205 : : {
5206 : 0 : goto exit_error; /* error */
5207 : : }
5208 [ # # ]: 0 : if (!pLine->len)
5209 : : {
5210 : 0 : ret = RI_ERR_EOL; /* end of line */
5211 : 0 : break;
5212 : : }
5213 : : /* djb-rwth: removing redundant code */
5214 : :
5215 : : /*
5216 : : if ( fst == 'z' )
5217 : : {
5218 : : ret = RI_ERR_EOL;
5219 : : break;
5220 : : }*/
5221 : : }
5222 : : /* process the seqment */
5223 [ # # # # : 0 : switch (state)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
5224 : : {
5225 : : /* Mobile H, M */ /* / */
5226 : 0 : case IST_MOBILE_H_FORMULA:
5227 : 0 : bMobileH = TAUT_YES;
5228 : : #if ( FIX_GAF_2019_2==1 )
5229 : : /* hack: pass state in na_total (will be updated in ParseSegmentFormula anyway) */
5230 : 0 : na_total = state;
5231 : : #endif
5232 : 0 : ret = ParseSegmentFormula(pLine->str, bMobileH, pInpInChI[bReconn],
5233 : 0 : nNumComponents[bReconn], &na_total);
5234 : 0 : state = IST_MOBILE_H_CONNECTIONS;
5235 : 0 : break;
5236 : 0 : case IST_MOBILE_H_CONNECTIONS: /* /c */
5237 : 0 : ret = ParseSegmentConnections(pLine->str, bMobileH, &pInpInChI[bReconn][bMobileH],
5238 : 0 : &nNumComponents[bReconn][bMobileH], &bAbc, &nb_total);
5239 : 0 : state = IST_MOBILE_H;
5240 : 0 : break;
5241 : 0 : case IST_MOBILE_H: /* /h */
5242 : 0 : ret = ParseSegmentMobileH(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], &bAbc);
5243 : 0 : state = IST_MOBILE_H_CHARGE;
5244 : 0 : break;
5245 : 0 : case IST_MOBILE_H_CHARGE: /* /q */
5246 : 0 : ret = ParseSegmentCharge(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn]);
5247 : 0 : state = IST_MOBILE_H_PROTONS;
5248 : 0 : break;
5249 : 0 : case IST_MOBILE_H_PROTONS: /* /p */
5250 : 0 : ret = ParseSegmentProtons(pLine->str, bMobileH, nNumProtons[bReconn], nNumComponents[bReconn]);
5251 : 0 : state = IST_MOBILE_H_POLYMER;
5252 : 0 : break;
5253 : 0 : case IST_MOBILE_H_POLYMER: /* /z */
5254 : 0 : ret = ParseSegmentPolymer(pLine->str, bMobileH,
5255 : 0 : nNumProtons[bReconn], nNumComponents[bReconn],
5256 : : na_total, nb_total, bInchi2Struct, ppPolymer, ppV3000);
5257 [ # # ]: 0 : if (*ppPolymer)
5258 : 0 : (*ppPolymer)->is_in_reconn = bReconn;
5259 : 0 : state = IST_MOBILE_H_SP2;
5260 : 0 : break;
5261 : 0 : case IST_MOBILE_H_SP2: /* /b */
5262 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5263 : 0 : state = IST_MOBILE_H_SP3;
5264 : 0 : break;
5265 : 0 : case IST_MOBILE_H_SP3: /* t */
5266 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5267 : 0 : state = IST_MOBILE_H_SP3_M;
5268 : 0 : break;
5269 : 0 : case IST_MOBILE_H_SP3_M: /* /m */
5270 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5271 : 0 : state = IST_MOBILE_H_SP3_S;
5272 : 0 : break;
5273 : 0 : case IST_MOBILE_H_SP3_S: /* /s */
5274 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5275 : 0 : state = IST_MOBILE_H_ISO_LAYER_FORK;
5276 : 0 : break;
5277 : 0 : case IST_MOBILE_H_ISO_LAYER_FORK:
5278 : : /* find layer type after M */
5279 : 0 : ret = 0;
5280 [ # # # # ]: 0 : switch (pLine->str[0])
5281 : : {
5282 : 0 : case 'i':
5283 : 0 : state = IST_MOBILE_H_ISO_ATOMS; /* MI */
5284 : 0 : break;
5285 : 0 : case 'f':
5286 : 0 : state = IST_FIXED_H_FORMULA; /* F */
5287 : 0 : break;
5288 : 0 : case 'r':
5289 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5290 : 0 : break;
5291 : 0 : default:
5292 : 0 : ret = RI_ERR_SYNTAX;
5293 : : }
5294 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5295 : : {
5296 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5297 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /i or /f or /r at the end of InChI line */
5298 : : }
5299 : : else
5300 : : {
5301 [ # # # # ]: 0 : if (!ret && state != IST_MOBILE_H_ISO_ATOMS)
5302 : : {
5303 : 0 : len = (int)strlen(pLine->str);
5304 [ # # ]: 0 : if (len > 1)
5305 : : {
5306 : 0 : memmove(pLine->str, pLine->str + 1, len);
5307 : : }
5308 : : else
5309 : : {
5310 : 0 : ret = 1; /* read the next segment */
5311 : : }
5312 : : }
5313 : : }
5314 : 0 : break;
5315 : : /* Mobile H, isotopic, MI */
5316 : 0 : case IST_MOBILE_H_ISO_ATOMS: /* i */
5317 : 0 : ret = ParseSegmentIsoAtoms(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5318 : 0 : state = IST_MOBILE_H_ISO_EXCH_H;
5319 : 0 : break;
5320 : 0 : case IST_MOBILE_H_ISO_EXCH_H: /* /i/h */
5321 : 0 : ret = ParseSegmentIsoExchgH(pLine->str, bMobileH, nNumProtons[bReconn], nNumComponents[bReconn], state, &bAbc);
5322 : 0 : state = IST_MOBILE_H_ISO_SP2;
5323 : 0 : break;
5324 : 0 : case IST_MOBILE_H_ISO_SP2: /* /i/b */
5325 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5326 : 0 : state = IST_MOBILE_H_ISO_SP3;
5327 : 0 : break;
5328 : 0 : case IST_MOBILE_H_ISO_SP3: /* /i/t */
5329 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5330 : 0 : state = IST_MOBILE_H_ISO_SP3_M;
5331 : 0 : break;
5332 : 0 : case IST_MOBILE_H_ISO_SP3_M: /* /i/m */
5333 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5334 : 0 : state = IST_MOBILE_H_ISO_SP3_S;
5335 : 0 : break;
5336 : 0 : case IST_MOBILE_H_ISO_SP3_S: /* /i/s */
5337 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5338 : 0 : state = IST_FIXED_H_LAYER_FORK;
5339 : 0 : break;
5340 : 0 : case IST_FIXED_H_LAYER_FORK:
5341 : : /* find layer type after MI */
5342 : 0 : ret = 0;
5343 [ # # # ]: 0 : switch (pLine->str[0])
5344 : : {
5345 : 0 : case 'f':
5346 : 0 : state = IST_FIXED_H_FORMULA; /* F */
5347 : 0 : break;
5348 : 0 : case 'r':
5349 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5350 : 0 : break;
5351 : 0 : default:
5352 : 0 : ret = RI_ERR_SYNTAX;
5353 : : }
5354 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5355 : : {
5356 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5357 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /f or /r at the end of InChI line */
5358 : : }
5359 : : else
5360 : : {
5361 [ # # ]: 0 : if (!ret)
5362 : : {
5363 : 0 : len = (int)strlen(pLine->str);
5364 [ # # ]: 0 : if (len > 1)
5365 : : {
5366 : 0 : memmove(pLine->str, pLine->str + 1, len);
5367 : : }
5368 : : else
5369 : : {
5370 : 0 : ret = 1; /* read the next segment */
5371 : : }
5372 : : }
5373 : : }
5374 : 0 : break;
5375 : :
5376 : : /* Fixed H, F */
5377 : 0 : case IST_FIXED_H_FORMULA:
5378 : 0 : bMobileH = TAUT_NON;
5379 : : #if ( FIX_GAF_2019_2==1 )
5380 : : /* hack: pass state in na_total (will be updated in ParseSegmentFormula anyway) */
5381 : 0 : na_total = state;
5382 : : #endif
5383 : 0 : ret = ParseSegmentFormula(pLine->str, bMobileH, pInpInChI[bReconn],
5384 : 0 : nNumComponents[bReconn], &na_total);
5385 : 0 : state = IST_FIXED_H;
5386 : 0 : break;
5387 : 0 : case IST_FIXED_H: /* /f/h */
5388 : 0 : ret = ParseSegmentMobileH(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], &bAbc);
5389 : 0 : state = IST_FIXED_H_CHARGE;
5390 : 0 : break;
5391 : 0 : case IST_FIXED_H_CHARGE: /* /f/q */
5392 : 0 : ret = ParseSegmentCharge(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn]);
5393 : 0 : state = IST_FIXED_H_SP2;
5394 : 0 : break;
5395 : 0 : case IST_FIXED_H_SP2: /* /f/b */
5396 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5397 : 0 : state = IST_FIXED_H_SP3;
5398 : 0 : break;
5399 : 0 : case IST_FIXED_H_SP3: /* /f/t */
5400 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5401 : 0 : state = IST_FIXED_H_SP3_M;
5402 : 0 : break;
5403 : 0 : case IST_FIXED_H_SP3_M: /* /f/m */
5404 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5405 : 0 : state = IST_FIXED_H_SP3_S;
5406 : 0 : break;
5407 : 0 : case IST_FIXED_H_SP3_S: /* /f/s */
5408 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5409 : 0 : state = IST_FIXED_H_PERMUTATION;
5410 : 0 : break;
5411 : 0 : case IST_FIXED_H_PERMUTATION: /* /f/o */
5412 : 0 : ret = ParseSegmentPerm(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5413 : 0 : state = IST_FIXED_H_ISO_LAYER_FORK;
5414 : 0 : break;
5415 : 0 : case IST_FIXED_H_ISO_LAYER_FORK:
5416 : : /* find layer type after M */
5417 : 0 : ret = 0;
5418 [ # # # ]: 0 : switch (pLine->str[0])
5419 : : {
5420 : 0 : case 'i':
5421 : 0 : state = IST_FIXED_H_ISO_ATOMS; /* FI */
5422 : 0 : break;
5423 : 0 : case 'r':
5424 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5425 : 0 : break;
5426 : 0 : default:
5427 : 0 : ret = RI_ERR_SYNTAX;
5428 : : }
5429 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5430 : : {
5431 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5432 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /i or /r at the end of InChI line */
5433 : : }
5434 : : else
5435 : : {
5436 [ # # # # ]: 0 : if (!ret && state != IST_FIXED_H_ISO_ATOMS)
5437 : : {
5438 : 0 : len = (int)strlen(pLine->str);
5439 [ # # ]: 0 : if (len > 1)
5440 : : {
5441 : 0 : memmove(pLine->str, pLine->str + 1, len);
5442 : : }
5443 : : else
5444 : : {
5445 : 0 : ret = 1; /* read the next segment */
5446 : : }
5447 : : }
5448 : : }
5449 : 0 : break;
5450 : :
5451 : : /* Fixed H, isotopic, FI */
5452 : 0 : case IST_FIXED_H_ISO_ATOMS: /* /f/i */
5453 : 0 : ret = ParseSegmentIsoAtoms(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5454 : 0 : state = IST_FIXED_H_ISO_SP2;
5455 : 0 : break;
5456 : 0 : case IST_FIXED_H_ISO_SP2: /* /f/i/b */
5457 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5458 : 0 : state = IST_FIXED_H_ISO_SP3;
5459 : 0 : break;
5460 : 0 : case IST_FIXED_H_ISO_SP3: /* /f/i/t */
5461 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5462 : 0 : state = IST_FIXED_H_ISO_SP3_M;
5463 : 0 : break;
5464 : 0 : case IST_FIXED_H_ISO_SP3_M: /* /f/i/m */
5465 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5466 : 0 : state = IST_FIXED_H_ISO_SP3_S;
5467 : 0 : break;
5468 : 0 : case IST_FIXED_H_ISO_SP3_S: /* /f/i/s */
5469 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5470 : 0 : state = IST_FIXED_H_ISO_PERMUTATION;
5471 : 0 : break;
5472 : 0 : case IST_FIXED_H_ISO_PERMUTATION: /* /f/i/o */
5473 : 0 : ret = ParseSegmentPerm(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5474 : 0 : state = IST_RECONNECTED_LAYER_FORK;
5475 : 0 : break;
5476 : 0 : case IST_RECONNECTED_LAYER_FORK:
5477 : : /* find layer type after FI */
5478 : 0 : ret = 0;
5479 [ # # ]: 0 : switch (pLine->str[0])
5480 : : {
5481 : 0 : case 'r':
5482 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5483 : 0 : break;
5484 : 0 : default:
5485 : 0 : ret = RI_ERR_SYNTAX;
5486 : : }
5487 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5488 : : {
5489 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5490 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /r at the end of InChI line */
5491 : : }
5492 : : else
5493 : : {
5494 [ # # ]: 0 : if (!ret)
5495 : : {
5496 : 0 : len = (int)strlen(pLine->str);
5497 [ # # ]: 0 : if (len > 1)
5498 : : {
5499 : 0 : memmove(pLine->str, pLine->str + 1, len);
5500 : : }
5501 : : else
5502 : : {
5503 : 0 : ret = 1; /* read the next segment */
5504 : : }
5505 : : }
5506 : : }
5507 : 0 : break;
5508 : 0 : case IST_RECONNECTED_FORMULA:
5509 : : #if ( FIX_GAF_2019_1==1 )
5510 [ # # ]: 0 : if (bReconn == INCHI_REC)
5511 : : {
5512 : : /* reconnected layer may appear only once */
5513 : 0 : ret = RI_ERR_SYNTAX;
5514 : 0 : break;
5515 : : }
5516 : : #endif
5517 : 0 : bReconn = INCHI_REC;
5518 : 0 : bMobileH = TAUT_YES;
5519 : 0 : state = IST_MOBILE_H_FORMULA;
5520 : 0 : break;
5521 : : }
5522 [ # # ]: 0 : } while (c >= 0);
5523 : :
5524 : 0 : exit_function:;
5525 : 0 : exit_error:;
5526 : :
5527 : : INCHI_HEAPCHK
5528 : :
5529 [ # # # # : 0 : if (ret >= 0 || c == RI_ERR_EOF || c == RI_ERR_EOL)
# # ]
5530 : : {
5531 : 0 : pLine->len = 0;
5532 : : }
5533 : :
5534 : 0 : return ret;
5535 : : }
5536 : :
5537 : :
5538 : : /****************************************************************************
5539 : : Parse InChI layer "/i/h"
5540 : : ****************************************************************************/
5541 : 0 : int ParseSegmentIsoExchgH(const char* str,
5542 : : int bMobileH,
5543 : : REM_PROTONS nNumProtons[],
5544 : : int pnNumComponents[],
5545 : : int state,
5546 : : int* pbAbc)
5547 : : {
5548 : : /* Pass 1: count bonds and find actual numbers of atom */
5549 : : const char* p, * q, * pStart, * pEnd;
5550 : 0 : int ret = 0, num, i, i_prev;
5551 : : static const char abc_h[] = "hdt";
5552 : :
5553 [ # # ]: 0 : if (str[0] != 'h')
5554 : : {
5555 : 0 : return 0;
5556 : : }
5557 : :
5558 : 0 : pStart = (char*)str + 1;
5559 : :
5560 [ # # # # ]: 0 : if (!(bMobileH == TAUT_YES && state == IST_MOBILE_H_ISO_EXCH_H))
5561 : : {
5562 : 0 : return RI_ERR_PROGR; /* program error */
5563 : : }
5564 : :
5565 [ # # ]: 0 : if (!(strchr(pStart, ';'))) /* djb-rwth: removing redundant code */
5566 : : {
5567 : 0 : pEnd = pStart + strlen(pStart);
5568 : : }
5569 : : else
5570 : : {
5571 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5572 : 0 : goto exit_function;
5573 : : }
5574 : 0 : p = pStart;
5575 : :
5576 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
5577 : : {
5578 : : /* check if compressed InChI */
5579 : : /* compressed: /hNtNdNh where N is a decimal number */
5580 : : /* uncompressed: /hT[n]D[n]H[n] where n > 1 is a decimal number */
5581 : 0 : *pbAbc = isdigit(UCINT * p) ? 1 : 0;
5582 : : }
5583 : :
5584 [ # # ]: 0 : if (*pbAbc == 1)
5585 : : {
5586 : 0 : i_prev = (int)sizeof(abc_h);
5587 [ # # ]: 0 : while (p < pEnd)
5588 : : {
5589 : 0 : num = (int)inchi_strtol(p, &q, 10);
5590 : : #if ( CHECK_STRTOL_ATNUMB==1 )
5591 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
5592 : : {
5593 : 0 : ret = RI_ERR_SYNTAX;
5594 : 0 : goto exit_function;
5595 : : }
5596 : : #endif
5597 [ # # # # : 0 : if (0 >= num || p == q || q >= pEnd)
# # ]
5598 : : {
5599 : 0 : ret = RI_ERR_SYNTAX;
5600 : 0 : goto exit_function;
5601 : : }
5602 : 0 : p = strchr((char*)abc_h, *q);
5603 [ # # # # : 0 : if (p && (i = (int)(p - abc_h)) < i_prev && (i < NUM_H_ISOTOPES)) /* djb-rwth: additional condition for buffer overrun prevention */
# # ]
5604 : : {
5605 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[i] = (NUM_H)num;
5606 : 0 : p = q + 1;
5607 : 0 : i_prev = i;
5608 : : }
5609 : : else
5610 : : {
5611 : 0 : ret = RI_ERR_SYNTAX;
5612 : 0 : goto exit_function;
5613 : : }
5614 : : }
5615 : : }
5616 : : else
5617 : : {
5618 [ # # ]: 0 : if (*p == 'T')
5619 : : {
5620 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[2] = 1;
5621 : 0 : p++;
5622 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5623 : : {
5624 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[2] = (NUM_H)inchi_strtol(p, &q, 10);
5625 : 0 : p = q;
5626 : : }
5627 : : }
5628 [ # # ]: 0 : if (*p == 'D')
5629 : : {
5630 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[1] = 1;
5631 : 0 : p++;
5632 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5633 : : {
5634 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[1] = (NUM_H)inchi_strtol(p, &q, 10);
5635 : 0 : p = q;
5636 : : }
5637 : : }
5638 [ # # ]: 0 : if (*p == 'H')
5639 : : {
5640 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[0] = 1;
5641 : 0 : p++;
5642 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5643 : : {
5644 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[0] = (NUM_H)inchi_strtol(p, &q, 10);
5645 : 0 : p = q;
5646 : : }
5647 : : }
5648 : : }
5649 [ # # ]: 0 : if (p != pEnd)
5650 : : {
5651 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5652 : 0 : goto exit_function;
5653 : : }
5654 : 0 : ret = 1;
5655 : :
5656 : 0 : exit_function:
5657 : :
5658 : 0 : return ret;
5659 : : }
5660 : :
5661 : :
5662 : : /****************************************************************************/
5663 : 0 : int ParseSegmentPerm(const char* str,
5664 : : int bMobileH,
5665 : : INChI* pInpInChI[],
5666 : : int ppnNumComponents[],
5667 : : int state,
5668 : : int* pbAbc)
5669 : : {
5670 : : int nNumComponents, iComponent1, iComponent2, numTrans;
5671 : : const char* p, * q, * pStart, * pEnd, * pPermStart, * pPermEnd;
5672 : 0 : int ret = 0;
5673 : 0 : INChI* pInChI = pInpInChI[bMobileH]; /* bMobileH should be TAUT_NON = 0 */
5674 : : INChI tmp;
5675 : 0 : int base = 10;
5676 : :
5677 [ # # ]: 0 : if (str[0] != 'o')
5678 : : {
5679 : 0 : return 0;
5680 : : }
5681 : :
5682 : : /* djb-rwth: fixing oss-fuzz issue #66746 */
5683 [ # # ]: 0 : if (!pInChI)
5684 : : {
5685 : 0 : return RI_ERR_ALLOC;
5686 : : }
5687 : :
5688 : 0 : pStart = (char*)str + 1;
5689 : 0 : nNumComponents = ppnNumComponents[bMobileH];
5690 : :
5691 [ # # # # : 0 : if (!(bMobileH == TAUT_NON && (state == IST_FIXED_H_PERMUTATION || state == IST_FIXED_H_ISO_PERMUTATION)))
# # ]
5692 : : {
5693 : 0 : return RI_ERR_PROGR; /* program error */
5694 : : }
5695 : :
5696 [ # # ]: 0 : if (!(strchr(pStart, ';'))) /* djb-rwth: removing redundant code */
5697 : : {
5698 : 0 : pEnd = pStart + strlen(pStart);
5699 : : }
5700 : : else
5701 : : {
5702 : 0 : return RI_ERR_SYNTAX; /* syntax error */
5703 : : }
5704 [ # # ]: 0 : while (pStart < pEnd)
5705 : : {
5706 : : /* cycle over components; rearrange Fixed H components in order of Mobile H components */
5707 : : /* if /o(1,2,3) then reaarange Fixed H components in this way: tmp<-1, 1<-2, 2<-3, 3<-tmp */
5708 [ # # ]: 0 : if (*pStart != '(')
5709 : : {
5710 : 0 : ret = RI_ERR_SYNTAX;
5711 : 0 : goto exit_function;
5712 : : }
5713 : 0 : pPermStart = pStart + 1;
5714 : 0 : memset(&tmp, 0, sizeof(tmp)); /* initialization 2006-03 */ /* djb-rwth: memset_s C11/Annex K variant? */
5715 [ # # # # ]: 0 : if (!(pPermEnd = strchr(pPermStart, ')')) || pPermEnd == pPermStart)
5716 : : {
5717 : 0 : ret = RI_ERR_SYNTAX;
5718 : 0 : goto exit_function;
5719 : : }
5720 : :
5721 [ # # # # ]: 0 : if (pPermStart < pPermEnd && *pbAbc == -1)
5722 : : {
5723 : : /* check if compressed InChI */
5724 : 0 : *pbAbc = isupper(UCINT * pPermStart) ? 1 : 0;
5725 : : }
5726 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
5727 : :
5728 : : /* permutation cycle */
5729 [ # # ]: 0 : if (*pbAbc == 1)
5730 : : {
5731 [ # # ]: 0 : for (p = pPermStart, iComponent2 = numTrans = 0; p < pPermEnd; iComponent2 = iComponent1, p = q)
5732 : : {
5733 : : /* get first atom number */
5734 [ # # # # ]: 0 : if (0 >= (iComponent1 = (int)inchi_strtol(p, &q, base)) || iComponent1 > nNumComponents)
5735 : : {
5736 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5737 : 0 : goto exit_function;
5738 : : }
5739 : : #if ( FIX_GAF_2019_2==1 )
5740 [ # # # # ]: 0 : if ((iComponent1 - 1 > nNumComponents - 1) || (iComponent1 - 1 < 0))
5741 : : {
5742 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5743 : 0 : goto exit_function;
5744 : : }
5745 : : #endif
5746 [ # # ]: 0 : if (iComponent2)
5747 : : {
5748 : 0 : pInChI[iComponent2 - 1] = pInChI[iComponent1 - 1];
5749 : 0 : numTrans++;
5750 : : }
5751 : : else
5752 : : {
5753 : 0 : tmp = pInChI[iComponent1 - 1]; /* on the 1st pass save Component1 */
5754 : : }
5755 : : }
5756 : : }
5757 : : else
5758 : : {
5759 [ # # ]: 0 : for (p = pPermStart, iComponent2 = numTrans = 0; p < pPermEnd; iComponent2 = iComponent1, p = q + (*q == ','))
5760 : : {
5761 : : /* get first atom number */
5762 [ # # ]: 0 : if (!isdigit(UCINT * p))
5763 : : {
5764 : 0 : ret = RI_ERR_SYNTAX;
5765 : 0 : goto exit_function;
5766 : : }
5767 : 0 : iComponent1 = (int)inchi_strtol(p, &q, 10);
5768 [ # # # # ]: 0 : if ((iComponent1 < 1) || (iComponent1 > nNumComponents)) /* djb-rwth: fixing oss-fuzz issue #66746 */
5769 : : {
5770 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5771 : 0 : goto exit_function;
5772 : : }
5773 [ # # ]: 0 : if (iComponent2)
5774 : : {
5775 : 0 : pInChI[iComponent2 - 1] = pInChI[iComponent1 - 1];
5776 : 0 : numTrans++;
5777 : : }
5778 : : else
5779 : : {
5780 : 0 : tmp = pInChI[iComponent1 - 1]; /* on the 1st pass save Component1 */
5781 : : }
5782 : : }
5783 : : }
5784 : 0 : pInChI[iComponent2 - 1] = tmp;
5785 [ # # # # ]: 0 : if (!numTrans || p != pPermEnd)
5786 : : {
5787 : 0 : ret = RI_ERR_SYNTAX;
5788 : 0 : goto exit_function;
5789 : : }
5790 : : else
5791 : : {
5792 : 0 : pStart = p + 1;
5793 : : }
5794 : : }
5795 : 0 : ret = 1;
5796 : :
5797 : 0 : exit_function:
5798 : :
5799 : 0 : return ret;
5800 : : }
5801 : :
5802 : :
5803 : : /****************************************************************************
5804 : : Parse InChI layer "/i"
5805 : : ****************************************************************************/
5806 : 0 : int ParseSegmentIsoAtoms(const char* str,
5807 : : int bMobileH,
5808 : : INChI* pInpInChI[],
5809 : : int ppnNumComponents[],
5810 : : int state,
5811 : : int* pbAbc)
5812 : : {
5813 : : int i, mpy_component, val;
5814 : 0 : int nNumComponents, iComponent, len = 0, iAtom;
5815 : : int nAtom1; /* djb-rwth: fixing coverity ID #499573 */
5816 : : const char* p, * q, * t, * pStart, * pEnd, * r;
5817 : 0 : int ret = 0;
5818 : 0 : INChI* pInChI = pInpInChI[bMobileH];
5819 : 0 : INChI* pInChIFrom = NULL;
5820 : 0 : INChI_IsotopicAtom** pIsotopicAtom = NULL;
5821 : : INChI_IsotopicAtom isoAtom;
5822 : :
5823 : 0 : const char mult_type[] = "mnMNe";
5824 : 0 : const char parity_type[] = "-+TDH";
5825 : 0 : int bIsoFrom, nCpyType = CPY_ISO_AT;
5826 : 0 : int base = 10;
5827 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
5828 : :
5829 [ # # ]: 0 : if (str[0] != 'i')
5830 : : {
5831 : 0 : return 0;
5832 : : }
5833 : :
5834 : 0 : pStart = (char*)str + 1;
5835 : 0 : iComponent = 0;
5836 : 0 : nNumComponents = ppnNumComponents[bMobileH];
5837 : :
5838 [ # # # # : 0 : if (!((bMobileH == TAUT_YES && state == IST_MOBILE_H_ISO_ATOMS) ||
# # ]
5839 [ # # ]: 0 : (bMobileH == TAUT_NON && state == IST_FIXED_H_ISO_ATOMS))) /* djb-rwth: addressing LLVM warnings */
5840 : : {
5841 : 0 : return RI_ERR_PROGR; /* program error */
5842 : : }
5843 [ # # ]: 0 : if (!*pStart)
5844 : : {
5845 : 0 : return nNumComponents + 1; /* no isotopic atoms */
5846 : : }
5847 : :
5848 : : while (1)
5849 : : {
5850 : : /* cycle over components */
5851 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
5852 : : {
5853 : 0 : pEnd = pStart + strlen(pStart);
5854 : : }
5855 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
5856 : : {
5857 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
5858 [ # # ]: 0 : if (p != q)
5859 : : {
5860 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5861 : 0 : goto exit_function;
5862 : : }
5863 : : #if (FIX_DALKE_BUGS == 1)
5864 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
5865 : : {
5866 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5867 : 0 : goto exit_function;
5868 : : }
5869 : : #endif
5870 : 0 : p++; /* move to the 1st character of the component */
5871 : : }
5872 : : else
5873 : : {
5874 : : /* djb-rwth: condition for if block had to be rewritten */
5875 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
5876 : : {
5877 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
5878 : 0 : if_cnd = isdigit(*pStart);
5879 : :
5880 : : }
5881 : : else
5882 : : {
5883 : 0 : val = 1;
5884 : 0 : q = pStart;
5885 : 0 : if_cnd = 1;
5886 : : }
5887 : :
5888 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used to store function return value */
# # ]
5889 : : {
5890 : : /* process the abbreviation */
5891 : 0 : ret = 0;
5892 : : #if (FIX_DALKE_BUGS == 1)
5893 [ # # ]: 0 : if (iComponent + val > nNumComponents)
5894 : : {
5895 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5896 : 0 : goto exit_function;
5897 : : }
5898 : : #endif
5899 : 0 : bIsoFrom = 0;
5900 [ # # # ]: 0 : switch (bMobileH)
5901 : : {
5902 : 0 : case TAUT_YES:
5903 : 0 : ret = RI_ERR_SYNTAX;
5904 : 0 : break;
5905 : 0 : case TAUT_NON:
5906 [ # # ]: 0 : if (*q == 'm')
5907 : : {
5908 : : /* copy from mobile H to fixed H */
5909 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
5910 : : }
5911 : : else
5912 : : {
5913 [ # # ]: 0 : if (*q == 'e')
5914 : : {
5915 : : /* copy from mobile H to isotopic mobile H */
5916 : 0 : pInChIFrom = pInChI;
5917 : 0 : bIsoFrom = -1; /* empty */
5918 : : }
5919 : : else
5920 : : {
5921 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5922 : : }
5923 : : }
5924 : 0 : break;
5925 : 0 : default:
5926 : 0 : ret = RI_ERR_SYNTAX;
5927 : 0 : break;
5928 : : }
5929 [ # # ]: 0 : if (ret < 0)
5930 : : {
5931 : 0 : goto exit_function;
5932 : : }
5933 : : /* copy */
5934 [ # # ]: 0 : for (i = 0; i < val; i++)
5935 : : {
5936 : : #if ( FIX_GAF_2019_2==1 )
5937 : : {
5938 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents) || (iComponent + i < 0))
5939 : : {
5940 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5941 : 0 : goto exit_function;
5942 : : }
5943 : : }
5944 : : #endif
5945 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, 0, bIsoFrom);
5946 [ # # ]: 0 : if (!ret)
5947 : : {
5948 : 0 : ret = RI_ERR_SYNTAX;
5949 : : }
5950 [ # # ]: 0 : if (ret < 0)
5951 : : {
5952 : 0 : goto exit_function;
5953 : : }
5954 : : }
5955 : 0 : iComponent += val;
5956 : : /* continue to the next component(s) */
5957 [ # # ]: 0 : if (*pEnd)
5958 : : {
5959 : 0 : pStart = pEnd + 1;
5960 : 0 : continue;
5961 : : }
5962 : : else
5963 : : {
5964 : 0 : break;
5965 : : }
5966 : : }
5967 : : else
5968 : : {
5969 : 0 : mpy_component = 1;
5970 : 0 : p = pStart;
5971 : : }
5972 : : }
5973 : :
5974 : : #if ( FIX_GAF_2019_2==1 )
5975 [ # # # # ]: 0 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
5976 : : {
5977 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5978 : 0 : goto exit_function;
5979 : : }
5980 [ # # # # ]: 0 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
5981 : : {
5982 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5983 : 0 : goto exit_function;
5984 : : }
5985 : : #endif
5986 : 0 : pStart = p;
5987 : 0 : pIsotopicAtom = &pInChI[iComponent].IsotopicAtom;
5988 [ # # ]: 0 : if (*pIsotopicAtom)
5989 : : {
5990 : 0 : ret = RI_ERR_PROGR; /* program error */
5991 : 0 : goto exit_function;
5992 : : }
5993 : :
5994 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
5995 : : {
5996 : : /* check if compressed InChI */
5997 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
5998 : : }
5999 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
6000 : :
6001 : 0 : one_more_time:
6002 [ # # ]: 0 : if (*pbAbc == 1)
6003 : : {
6004 : : /* process the componnt: At[+/-Charge]TDH,... */
6005 : : /* pass 1: find number of stereoatoms */
6006 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
6007 : : {
6008 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base);
6009 : : #if ( CHECK_STRTOL_ATNUMB==1 )
6010 [ # # # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
6011 : : {
6012 : 0 : ret = RI_ERR_SYNTAX;
6013 : 0 : goto exit_function;
6014 : : }
6015 : : #endif
6016 [ # # ]: 0 : if (!nAtom1 ||
6017 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms)
6018 : : {
6019 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6020 : 0 : goto exit_function;
6021 : : }
6022 : 0 : memset(&isoAtom, 0, sizeof(isoAtom)); /* djb-rwth: memset_s C11/Annex K variant? */
6023 : 0 : isoAtom.nAtomNumber = nAtom1;
6024 : 0 : isoAtom.nIsoDifference = (NUM_H)inchi_strtol(p, &q, 10); /* alway in abc */
6025 [ # # ]: 0 : if (p == q)
6026 : : {
6027 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6028 : 0 : goto exit_function;
6029 : : }
6030 : 0 : p = q;
6031 [ # # ]: 0 : if (*p == 't')
6032 : : {
6033 : 0 : isoAtom.nNum_T = 1;
6034 : 0 : p++;
6035 [ # # ]: 0 : if (isdigit(UCINT * p))
6036 : : {
6037 : 0 : isoAtom.nNum_T = (NUM_H)inchi_strtol(p, &q, 10);
6038 : 0 : p = q;
6039 : : }
6040 : : }
6041 [ # # ]: 0 : if (*p == 'd')
6042 : : {
6043 : 0 : isoAtom.nNum_D = 1;
6044 : 0 : p++;
6045 [ # # ]: 0 : if (isdigit(UCINT * p))
6046 : : {
6047 : 0 : isoAtom.nNum_D = (NUM_H)inchi_strtol(p, &q, 10);
6048 : 0 : p = q;
6049 : : }
6050 : : }
6051 [ # # ]: 0 : if (*p == 'h')
6052 : : {
6053 : 0 : isoAtom.nNum_H = 1;
6054 : 0 : p++;
6055 [ # # ]: 0 : if (isdigit(UCINT * p))
6056 : : {
6057 : 0 : isoAtom.nNum_H = (NUM_H)inchi_strtol(p, &q, 10);
6058 : 0 : p = q;
6059 : : }
6060 : : }
6061 [ # # # # : 0 : if (p > pEnd || (!isoAtom.nIsoDifference && !isoAtom.nNum_T && !isoAtom.nNum_D && !isoAtom.nNum_H)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
6062 : : {
6063 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6064 : 0 : goto exit_function;
6065 : : }
6066 [ # # ]: 0 : if (*pIsotopicAtom)
6067 : : {
6068 : 0 : pIsotopicAtom[0][iAtom] = isoAtom;
6069 : : }
6070 : : }
6071 : : }
6072 : : else
6073 : : {
6074 : : /* process the componnt: At[+/-Charge]TDH,... */
6075 : : /* pass 1: find number of stereoatoms */
6076 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
6077 : : {
6078 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
6079 : : #if ( CHECK_STRTOL_ATNUMB==1 )
6080 [ # # # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
6081 : : {
6082 : 0 : ret = RI_ERR_SYNTAX;
6083 : 0 : goto exit_function;
6084 : : }
6085 : : #endif
6086 : 0 : p = q;
6087 [ # # ]: 0 : if (!nAtom1 ||
6088 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
6089 [ # # ]: 0 : !(r = strchr((char*)parity_type, *p))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
6090 : : {
6091 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6092 : 0 : goto exit_function;
6093 : : }
6094 : 0 : memset(&isoAtom, 0, sizeof(isoAtom)); /* djb-rwth: memset_s C11/Annex K variant? */
6095 : 0 : isoAtom.nAtomNumber = nAtom1;
6096 [ # # # # ]: 0 : if (p[0] == '+' && isdigit(UCINT p[1]))
6097 : : {
6098 : 0 : isoAtom.nIsoDifference = (NUM_H)inchi_strtol(p + 1, &q, 10);
6099 [ # # ]: 0 : if (isoAtom.nIsoDifference >= 0) isoAtom.nIsoDifference++;
6100 : 0 : p = q;
6101 : : }
6102 : : else
6103 [ # # # # ]: 0 : if (p[0] == '-' && isdigit(UCINT p[1]))
6104 : : {
6105 : 0 : isoAtom.nIsoDifference = -(NUM_H)inchi_strtol(p + 1, &q, 10);
6106 [ # # ]: 0 : if (isoAtom.nIsoDifference == 0) isoAtom.nIsoDifference++;
6107 : 0 : p = q;
6108 : : }
6109 [ # # ]: 0 : if (*p == 'T')
6110 : : {
6111 : 0 : isoAtom.nNum_T = 1;
6112 : 0 : p++;
6113 [ # # ]: 0 : if (isdigit(UCINT * p))
6114 : : {
6115 : 0 : isoAtom.nNum_T = (NUM_H)inchi_strtol(p, &q, 10);
6116 : 0 : p = q;
6117 : : }
6118 : : }
6119 [ # # ]: 0 : if (*p == 'D')
6120 : : {
6121 : 0 : isoAtom.nNum_D = 1;
6122 : 0 : p++;
6123 [ # # ]: 0 : if (isdigit(UCINT * p))
6124 : : {
6125 : 0 : isoAtom.nNum_D = (NUM_H)inchi_strtol(p, &q, 10);
6126 : 0 : p = q;
6127 : : }
6128 : : }
6129 [ # # ]: 0 : if (*p == 'H')
6130 : : {
6131 : 0 : isoAtom.nNum_H = 1;
6132 : 0 : p++;
6133 [ # # ]: 0 : if (isdigit(UCINT * p))
6134 : : {
6135 : 0 : isoAtom.nNum_H = (NUM_H)inchi_strtol(p, &q, 10);
6136 : 0 : p = q;
6137 : : }
6138 : : }
6139 [ # # # # : 0 : if (!isoAtom.nIsoDifference && !isoAtom.nNum_T && !isoAtom.nNum_D && !isoAtom.nNum_H)
# # # # ]
6140 : : {
6141 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6142 : 0 : goto exit_function;
6143 : : }
6144 [ # # ]: 0 : if (p < pEnd)
6145 : : {
6146 [ # # ]: 0 : if (*p == ',')
6147 : : {
6148 : 0 : p++;
6149 : : }
6150 : : else
6151 : : {
6152 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6153 : 0 : goto exit_function;
6154 : : }
6155 : : }
6156 [ # # ]: 0 : if (*pIsotopicAtom)
6157 : : {
6158 : 0 : pIsotopicAtom[0][iAtom] = isoAtom;
6159 : : }
6160 : : }
6161 : : }
6162 [ # # ]: 0 : if (p != pEnd)
6163 : : {
6164 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6165 : 0 : goto exit_function;
6166 : : }
6167 : :
6168 [ # # ]: 0 : if (!*pIsotopicAtom)
6169 : : {
6170 : : /* end of the 1st pass */
6171 : 0 : len = iAtom;
6172 : : /* memory allocation */
6173 [ # # ]: 0 : if (!(*pIsotopicAtom = (INChI_IsotopicAtom*)inchi_calloc((long long)len + 1, sizeof(**pIsotopicAtom)))) /* djb-rwth: cast operator added */
6174 : : {
6175 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6176 : 0 : goto exit_function;
6177 : : }
6178 : 0 : goto one_more_time; /* goto the 2nd pass */
6179 : : }
6180 : : else
6181 : : {
6182 : : /* 2nd pass */
6183 [ # # ]: 0 : if (len != iAtom)
6184 : : {
6185 : 0 : ret = RI_ERR_PROGR; /* program error */
6186 : 0 : goto exit_function;
6187 : : }
6188 : 0 : pInChI[iComponent].nNumberOfIsotopicAtoms = len;
6189 : : }
6190 : :
6191 : : /* multiplier */
6192 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
6193 : : {
6194 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, 0, 0);
6195 [ # # ]: 0 : if (!ret)
6196 : : {
6197 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6198 : : }
6199 [ # # ]: 0 : if (ret < 0)
6200 : : {
6201 : 0 : goto exit_function;
6202 : : }
6203 : : }
6204 : :
6205 : 0 : iComponent += mpy_component;
6206 [ # # ]: 0 : if (*pEnd)
6207 : : {
6208 : 0 : pStart = pEnd + 1;
6209 : 0 : continue;
6210 : : }
6211 : : else
6212 : : {
6213 : 0 : break;
6214 : : }
6215 : :
6216 : : }
6217 : :
6218 [ # # ]: 0 : if (nNumComponents != iComponent)
6219 : : {
6220 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6221 : 0 : goto exit_function;
6222 : : }
6223 : :
6224 : 0 : ret = iComponent + 1;
6225 : :
6226 : 0 : exit_function:
6227 : :
6228 : 0 : return ret;
6229 : : }
6230 : :
6231 : :
6232 : : /****************************************************************************
6233 : : Parse "/i/s" InChI layer
6234 : : ****************************************************************************/
6235 : 0 : int ParseSegmentSp3s(const char* str,
6236 : : int bMobileH,
6237 : : INChI* pInpInChI[],
6238 : : int s[TAUT_NUM][2],
6239 : : int ppnNumComponents[],
6240 : : int state)
6241 : : {
6242 : : /* Pass 1: count bonds and find actual numbers of atom */
6243 : : int nNumComponents, iComponent, val;
6244 : : const char* p, * q, * pStart, * pEnd;
6245 : 0 : int ret = 0;
6246 : 0 : INChI* pInChI = pInpInChI[bMobileH];
6247 : 0 : INChI_Stereo** pStereo = NULL;
6248 : :
6249 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP3_S || state == IST_FIXED_H_ISO_SP3_S);
6250 : :
6251 [ # # # # : 0 : if (!bIso && state != IST_MOBILE_H_SP3_S && state != IST_FIXED_H_SP3_S)
# # ]
6252 : : {
6253 : 0 : return RI_ERR_PROGR; /* program error */
6254 : : }
6255 : :
6256 [ # # ]: 0 : if (str[0] != 's')
6257 : : {
6258 : 0 : return 0;
6259 : : }
6260 : :
6261 : 0 : pStart = (char*)str + 1;
6262 : : /* djb-rwth: removing redundant code */
6263 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6264 : :
6265 : : /*if ( !(pEnd = strchr( pStart, ';' )) )*/ /* 2007-09-25 DT */
6266 [ # # ]: 0 : if (!(strchr(pStart, '/'))) /* djb-rwth: removing redundant variables/code */
6267 : : {
6268 : 0 : pEnd = pStart + strlen(pStart);
6269 : : }
6270 : : else
6271 : : {
6272 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6273 : 0 : goto exit_function;
6274 : : }
6275 : 0 : p = pStart;
6276 [ # # ]: 0 : if (pEnd == pStart)
6277 : : {
6278 : : /* create empty sp3 segment */
6279 : 0 : int len = 0;
6280 : 0 : s[bMobileH][bIso] = NO_VALUE_INT; /* empty */
6281 : : /* create empty sp3 segment */
6282 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6283 : : {
6284 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6285 [ # # ]: 0 : if (!*pStereo)
6286 : : {
6287 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6288 : : {
6289 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6290 : 0 : goto exit_function;
6291 : : }
6292 : : }
6293 : 0 : pStereo[0]->nCompInv2Abs = 0; /* deliberately empty */
6294 : :
6295 [ # # ]: 0 : if (pStereo[0]->nNumberOfStereoCenters)
6296 : : {
6297 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: "/s" without a digit describes "no stereo" */
6298 : 0 : goto exit_function;
6299 : : }
6300 : : /* allocate empty sp3 stereo */
6301 [ # # ]: 0 : if ((!pStereo[0]->t_parity &&
6302 [ # # ]: 0 : !(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0])))) ||
6303 [ # # ]: 0 : (!pStereo[0]->nNumber &&
6304 [ # # ]: 0 : !(pStereo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nNumber[0]))))) /* djb-rwth: cast operators added; addressing LLVM warnings */
6305 : : {
6306 : : /* cleanup */
6307 [ # # ]: 0 : if (pStereo[0]->t_parity)
6308 : : {
6309 : : INCHI_HEAPCHK
6310 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6311 : 0 : pStereo[0]->t_parity = NULL;
6312 : : }
6313 [ # # ]: 0 : if (pStereo[0]->nNumber)
6314 : : {
6315 : : INCHI_HEAPCHK
6316 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6317 : 0 : pStereo[0]->nNumber = NULL;
6318 : : }
6319 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6320 : 0 : goto exit_function;
6321 : : }
6322 : : }
6323 : 0 : ret = nNumComponents + 1;
6324 : : }
6325 : : else
6326 : : {
6327 : 0 : val = (int)inchi_strtol(p, &q, 10);
6328 [ # # # # : 0 : if (q == pEnd && 1 <= val && val <= 3)
# # ]
6329 : : {
6330 : 0 : s[bMobileH][bIso] = val;
6331 : 0 : ret = nNumComponents + 1;
6332 : : }
6333 : : else
6334 : : {
6335 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6336 : : }
6337 : : }
6338 : :
6339 : 0 : exit_function:
6340 : :
6341 : 0 : return ret;
6342 : : }
6343 : :
6344 : :
6345 : : /****************************************************************************/
6346 : 0 : int bIsSp3LayerNotEmpty(INChI* pInpInChI[],
6347 : : int bMobileH,
6348 : : int bIso,
6349 : : int nNumComponents)
6350 : : {
6351 : : INChI* pInChI;
6352 : : INChI_Stereo* pStereo;
6353 : 0 : int iComponent, num_not_empty = 0;
6354 : :
6355 [ # # ]: 0 : if (pInpInChI[bMobileH])
6356 : : {
6357 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6358 : : {
6359 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
6360 [ # # # # ]: 0 : if (pInChI->bDeleted || !pInChI->nNumberOfAtoms)
6361 : : {
6362 : 0 : continue;
6363 : : }
6364 [ # # ]: 0 : pStereo = bIso ? pInChI->StereoIsotopic : pInChI->Stereo;
6365 [ # # # # : 0 : if (pStereo && pStereo->nNumberOfStereoCenters > 0 && pStereo->nNumber && pStereo->t_parity)
# # # # ]
6366 : : {
6367 : 0 : num_not_empty++;
6368 : : }
6369 : : }
6370 : : }
6371 : 0 : return num_not_empty;
6372 : : }
6373 : :
6374 : :
6375 : : /****************************************************************************
6376 : : Parse "/i/m" InChI layer
6377 : : ****************************************************************************/
6378 : 0 : int ParseSegmentSp3m(const char* str,
6379 : : int bMobileH,
6380 : : INChI* pInpInChI[],
6381 : : int ppnNumComponents[],
6382 : : int state)
6383 : : {
6384 : : /* Pass 1: count bonds and find actual numbers of atom */
6385 : : int nNumComponents, iComponent;
6386 : : const char* p, * pStart, * pEnd;
6387 : 0 : int ret = 0;
6388 : 0 : INChI* pInChI = pInpInChI[bMobileH];
6389 : 0 : INChI_Stereo** pStereo = NULL;
6390 : :
6391 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP3_M || state == IST_FIXED_H_ISO_SP3_M);
6392 : :
6393 [ # # # # : 0 : if (!bIso && state != IST_MOBILE_H_SP3_M && state != IST_FIXED_H_SP3_M)
# # ]
6394 : : {
6395 : 0 : return RI_ERR_PROGR; /* program error */
6396 : : }
6397 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6398 : :
6399 [ # # ]: 0 : if (str[0] != 'm')
6400 : : {
6401 : : /* /m is missing: check whether we have to inherit /m from a preceding stereo layer */
6402 : : INChI_Stereo* pStereoFrom, * pStereoTo;
6403 : : INChI* pInChIFrom;
6404 : 0 : int bMobileHFrom = -1, bIsoFrom = -1; /* djb-rwth: removing redundant variables */
6405 [ # # # # ]: 0 : if (bMobileH && !bIso)
6406 : : {
6407 : 0 : return 0; /* Main non-isotopic cannot inherit: it has no preceding layer */
6408 : : }
6409 : : else
6410 : : {
6411 [ # # # # ]: 0 : if (!bMobileH && !bIso)
6412 : : {
6413 : : /* fixed-H non-isotopic (F) inherits from Mobile-H non-isotopic (M) */
6414 : 0 : bMobileHFrom = TAUT_YES;
6415 : 0 : bIsoFrom = 0;
6416 : : }
6417 : : else
6418 : : {
6419 [ # # # # ]: 0 : if (bMobileH && bIso)
6420 : : {
6421 : : /* Mobile-H isotopic (MI) inherits from Mobile-H non-isotopic (M) */
6422 : 0 : bMobileHFrom = TAUT_YES;
6423 : 0 : bIsoFrom = 0;
6424 : : }
6425 : : else
6426 : : {
6427 [ # # # # ]: 0 : if (!bMobileH && bIso)
6428 : : {
6429 : : /* Fixed-H isotopic (FI) inherits from Fixed-H non-isotopic (F) */
6430 : 0 : bMobileHFrom = TAUT_NON;
6431 : 0 : bIsoFrom = 0;
6432 : : /* if Sp3 is empty in F as well as in M, then inherit from MI */
6433 [ # # # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, TAUT_NON, 0, ppnNumComponents[TAUT_NON /*bMobileH*/]) /* F */ &&
6434 : 0 : !bIsSp3LayerNotEmpty(pInpInChI, TAUT_YES, 0, ppnNumComponents[TAUT_YES /*bMobileH*/]) /* M */)
6435 : : {
6436 : 0 : bMobileHFrom = TAUT_YES;
6437 : 0 : bIsoFrom = 1;
6438 : : }
6439 : : }
6440 : : }
6441 : : }
6442 : : }
6443 [ # # # # ]: 0 : if (bMobileHFrom < 0 || bIsoFrom < 0) /* djb-rwth: addressing coverity ID #499556 -- check necessary due to initialisation values */
6444 : : {
6445 : 0 : return RI_ERR_PROGR;
6446 : : }
6447 [ # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, bMobileHFrom, bIsoFrom, ppnNumComponents[/*bMobileH*/ bMobileHFrom]))
6448 : : {
6449 : : /* nothing to copy; check whether it should have inherited from a preceding layer */
6450 [ # # # # : 0 : if ((!bMobileHFrom && bIsoFrom) || (bMobileHFrom && !bIsoFrom)) /* djb-rwth: addressing LLVM warnings */
# # # # ]
6451 : : {
6452 : : /* MI or F inherit stereo from M */
6453 : 0 : bMobileHFrom = TAUT_YES;
6454 : 0 : bIsoFrom = 0;
6455 [ # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, bMobileHFrom, bIsoFrom, ppnNumComponents[bMobileHFrom /*bMobileH*/]))
6456 : : {
6457 : 0 : return 0;
6458 : : }
6459 : : }
6460 : : else
6461 : : {
6462 : 0 : return 0;
6463 : : }
6464 : : }
6465 : 0 : nNumComponents = inchi_min(ppnNumComponents[bMobileH], ppnNumComponents[bMobileHFrom]);
6466 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6467 : : {
6468 : 0 : pInChIFrom = pInpInChI[bMobileHFrom] + iComponent;
6469 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
6470 [ # # # # ]: 0 : if (pInChIFrom->nNumberOfAtoms > 0 && !pInChIFrom->bDeleted &&
6471 [ # # # # ]: 0 : pInChI->nNumberOfAtoms > 0 && !pInChI->bDeleted)
6472 : : {
6473 [ # # ]: 0 : pStereoFrom = bIsoFrom ? pInChIFrom->StereoIsotopic : pInChIFrom->Stereo;
6474 [ # # ]: 0 : pStereoTo = bIso ? pInChI->StereoIsotopic : pInChI->Stereo;
6475 [ # # # # ]: 0 : if (pStereoFrom && pStereoTo)
6476 : : {
6477 : 0 : pStereoTo->nCompInv2Abs = pStereoFrom->nCompInv2Abs;
6478 : : /* djb-rwth: removing redundant code */
6479 : : }
6480 : : }
6481 : : }
6482 : 0 : return 0; /* return value > 0 means the non-/m segment has been processed here */
6483 : : }
6484 : :
6485 : 0 : pStart = str + 1;
6486 : 0 : iComponent = 0;
6487 : :
6488 : : /*if ( !(pEnd = strchr( pStart, ';' )) )*/ /* 2007-09-25 DT */
6489 [ # # ]: 0 : if (!(strchr(pStart, '/'))) /* djb-rwth: removing redundant code */
6490 : : {
6491 : 0 : pEnd = pStart + strlen(pStart);
6492 : : }
6493 : : else
6494 : : {
6495 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6496 : 0 : goto exit_function;
6497 : : }
6498 : 0 : p = pStart;
6499 [ # # ]: 0 : if (pEnd == pStart)
6500 : : {
6501 : : /* create empty sp3 segment */
6502 : 0 : int len = 0;
6503 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6504 : : {
6505 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
6506 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
6507 [ # # ]: 0 : if (!*pStereo)
6508 : : {
6509 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6510 : : {
6511 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6512 : 0 : goto exit_function;
6513 : : }
6514 : : }
6515 : 0 : pStereo[0]->nCompInv2Abs = NO_VALUE_INT; /* deliberately empty */
6516 : : #ifdef NEVER
6517 : : if (pStereo[0]->nNumberOfStereoCenters)
6518 : : {
6519 : : ret = RI_ERR_SYNTAX; /* syntax error */
6520 : : goto exit_function;
6521 : : }
6522 : : #endif
6523 : : /* allocate empty sp3 stereo */
6524 [ # # ]: 0 : if ((!pStereo[0]->t_parity &&
6525 [ # # ]: 0 : !(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0])))) ||
6526 [ # # ]: 0 : (!pStereo[0]->nNumber &&
6527 [ # # ]: 0 : !(pStereo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nNumber[0]))))) /* djb-rwth: cast operators added; addressing LLVM warnings */
6528 : : {
6529 : : /* cleanup */
6530 [ # # ]: 0 : if (pStereo[0]->t_parity)
6531 : : {
6532 : : INCHI_HEAPCHK
6533 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6534 : 0 : pStereo[0]->t_parity = NULL;
6535 : : }
6536 [ # # ]: 0 : if (pStereo[0]->nNumber)
6537 : : {
6538 : : INCHI_HEAPCHK
6539 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6540 : 0 : pStereo[0]->nNumber = NULL;
6541 : : }
6542 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6543 : 0 : goto exit_function;
6544 : : }
6545 : : }
6546 : 0 : ret = nNumComponents + 1;
6547 : : }
6548 : : else
6549 : : {
6550 [ # # # # ]: 0 : while (p < pEnd && iComponent < nNumComponents)
6551 : : {
6552 : : /* cycle over components */
6553 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6554 [ # # # # ]: 0 : if (*p != '.' && !*pStereo)
6555 : : {
6556 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6557 : : {
6558 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6559 : 0 : goto exit_function;
6560 : : }
6561 : : }
6562 [ # # # # ]: 0 : switch (*p)
6563 : : {
6564 : 0 : case '1':
6565 : 0 : pStereo[0]->nCompInv2Abs = -1;
6566 : 0 : break;
6567 : 0 : case '0':
6568 : 0 : pStereo[0]->nCompInv2Abs = 1;
6569 : 0 : break;
6570 : 0 : case '.':
6571 [ # # ]: 0 : if (*pStereo)
6572 : : {
6573 : 0 : pStereo[0]->nCompInv2Abs = 0;
6574 : : }
6575 : 0 : break;
6576 : 0 : default:
6577 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6578 : 0 : goto exit_function;
6579 : : }
6580 : 0 : iComponent++;
6581 : 0 : p++;
6582 : : }
6583 [ # # # # ]: 0 : if (p != pEnd || iComponent != nNumComponents)
6584 : : {
6585 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6586 : 0 : goto exit_function;
6587 : : }
6588 : 0 : ret = nNumComponents + 1;
6589 : : }
6590 : :
6591 : 0 : exit_function:
6592 : :
6593 : 0 : return ret;
6594 : : }
6595 : :
6596 : :
6597 : : /****************************************************************************
6598 : : Parse "/t" InChI layer
6599 : : ****************************************************************************/
6600 : 0 : int ParseSegmentSp3(const char* str, /* input; string of segment starting with "/t" */
6601 : : int bMobileH, /* input; bMobileH indicates what we have, fixed or tauto */
6602 : : INChI* pInpInChI[], /* output; to be allocated and filled */
6603 : : int ppnNumComponents[], /* input; ppnNumComponents[bMobileH] is number of components*/
6604 : : int state, /* input; gen parser state code */
6605 : : int* pbAbc) /* input; inicator of compresssed InChI or not */
6606 : : {
6607 : : /* Pass 1: count bonds and find actual numbers of atom */
6608 : 0 : const char mult_type[] = "mnMNe";
6609 : 0 : const char parity_type[] = "-+u?";
6610 : : const char* p, * q, * t, * pStart, * pEnd, * r;
6611 : : AT_NUMB nAtom1;
6612 : 0 : int mpy_component = 0, val;
6613 : : int nNumComponents, iComponent, len, iAtom;
6614 : : int atomParity;
6615 : 0 : int ret = 0, retf = 0;
6616 : 0 : int base = 10;
6617 : 0 : int nCpyType = CPY_SP3;
6618 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP3 || state == IST_FIXED_H_ISO_SP3);
6619 : 0 : INChI* pInChI = pInpInChI[bMobileH];
6620 : 0 : INChI_Stereo** pStereo = NULL;
6621 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
6622 : :
6623 [ # # # # : 0 : if (!bIso && state != IST_MOBILE_H_SP3 && state != IST_FIXED_H_SP3)
# # ]
6624 : : {
6625 : 0 : return RI_ERR_PROGR;
6626 : : }
6627 [ # # ]: 0 : if (str[0] != 't')
6628 : : {
6629 : 0 : return 0; /* RI_ERR_EOF - ? */
6630 : : }
6631 : :
6632 : 0 : pStart = (char*)str + 1;
6633 : 0 : iComponent = 0;
6634 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6635 : :
6636 : : /* Pass 1: create empty segment and exit */
6637 [ # # ]: 0 : if (!*pStart)
6638 : : {
6639 : 0 : ret = SegmentSp3CreateEmpty(str, bMobileH, pInpInChI, nNumComponents, state, pbAbc);
6640 : 0 : goto exit_function;
6641 : : }
6642 : :
6643 : : /* Cycle over components */
6644 : : while (1)
6645 : : {
6646 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
6647 : : {
6648 : 0 : pEnd = pStart + strlen(pStart);
6649 : : }
6650 : :
6651 : : /* djb-rwth: condition for if block had to be rewritten */
6652 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
6653 : : {
6654 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
6655 : 0 : if_cnd = isdigit(*pStart);
6656 : :
6657 : : }
6658 : : else
6659 : : {
6660 : 0 : val = 1;
6661 : 0 : q = pStart;
6662 : 0 : if_cnd = 1;
6663 : : }
6664 : :
6665 : : /* Abbreviation? */
6666 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used */
# # ]
6667 : : {
6668 : : /* Process abbrebiation */
6669 : 0 : retf = SegmentSp3ProcessAbbreviation(&mpy_component, iComponent, nNumComponents,
6670 : : val, q, state, pbAbc, bMobileH, nCpyType,
6671 [ # # ]: 0 : pInChI, pInpInChI[ALT_TAUT(bMobileH)]);
6672 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6673 : : {
6674 : 0 : ret = RI_ERR_SYNTAX;
6675 : 0 : goto exit_function;
6676 : : }
6677 : 0 : goto end_main_cycle;
6678 : : }
6679 : : /* Multiplier? */
6680 [ # # # # ]: 0 : else if ((p = strchr(pStart, '*')) && p < pEnd)
6681 : : {
6682 : : /* Process regular multiplier */
6683 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
6684 [ # # ]: 0 : if (p != q)
6685 : : {
6686 : 0 : ret = RI_ERR_SYNTAX;
6687 : 0 : goto exit_function;
6688 : : }
6689 : 0 : p++; /* move to the 1st character of the component */
6690 : : }
6691 : : else
6692 : : {
6693 : : /* Just normal sequence of centers/configs, prepare to read */
6694 : 0 : mpy_component = 1;
6695 : 0 : p = pStart;
6696 : : }
6697 : : #if (FIX_DALKE_BUGS == 1)
6698 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
6699 : : {
6700 : 0 : ret = RI_ERR_SYNTAX;
6701 : 0 : goto exit_function;
6702 : : }
6703 : : #endif
6704 : :
6705 : 0 : pStart = p;
6706 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
6707 : : {
6708 : : /* check if compressed InChI */
6709 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
6710 : : }
6711 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
6712 : :
6713 : : /* Process the component: at1p,at1p,... */
6714 : :
6715 : : /* Pass 1: find number of stereoatoms len */
6716 [ # # ]: 0 : if (*pbAbc == 1)
6717 : : {
6718 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
6719 : : {
6720 [ # # # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
6721 : 0 : (atomParity = (int)inchi_strtol(p, &p, 10),
6722 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= atomParity && atomParity <= AB_MAX_KNOWN_PARITY))
6723 : : {
6724 : : ; /* okay */
6725 : : }
6726 : : else
6727 : : {
6728 : 0 : ret = RI_ERR_SYNTAX;
6729 : 0 : goto exit_function;
6730 : : }
6731 [ # # ]: 0 : if (nAtom1 > pInChI[iComponent].nNumberOfAtoms)
6732 : : {
6733 : 0 : ret = RI_ERR_SYNTAX;
6734 : 0 : goto exit_function;
6735 : : }
6736 : : }
6737 : : }
6738 : : else
6739 : : {
6740 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++, p += (*p == ','))
6741 : : {
6742 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
6743 : 0 : p = q + 1;
6744 [ # # ]: 0 : if (!nAtom1 ||
6745 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
6746 [ # # ]: 0 : !(r = strchr((char*)parity_type, *q))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
6747 : : {
6748 : 0 : ret = RI_ERR_SYNTAX;
6749 : 0 : goto exit_function;
6750 : : }
6751 : : }
6752 : : }
6753 [ # # ]: 0 : if (p != pEnd)
6754 : : {
6755 : 0 : ret = RI_ERR_SYNTAX;
6756 : 0 : goto exit_function;
6757 : : }
6758 : 0 : len = iAtom;
6759 : : /* Found len, the number of stereo centers in /t segment for component iComponent */
6760 : :
6761 : : #if ( ( FIX_GAF_2019_1==1 ) || ( FIX_GAF_2019_2==1 ) )
6762 [ # # # # ]: 0 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
6763 : : {
6764 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6765 : 0 : goto exit_function;
6766 : : }
6767 [ # # # # ]: 0 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
6768 : : {
6769 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6770 : 0 : goto exit_function;
6771 : : }
6772 : : #endif
6773 : :
6774 : : /* Allocate memory for pStereo */
6775 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6776 [ # # ]: 0 : if (!*pStereo)
6777 : : {
6778 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6779 : : {
6780 : 0 : ret = RI_ERR_ALLOC;
6781 : 0 : goto exit_function;
6782 : : }
6783 : : }
6784 [ # # # # ]: 0 : if (pStereo[0]->t_parity || pStereo[0]->nNumberOfStereoCenters ||
6785 [ # # ]: 0 : pStereo[0]->nNumber)
6786 : : {
6787 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6788 : 0 : goto exit_function;
6789 : : }
6790 : : /* Allocate sp3 stereo */
6791 [ # # ]: 0 : if (!(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0]))) ||
6792 [ # # ]: 0 : !(pStereo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nNumber[0])))) /* djb-rwth: cast operators added */
6793 : : {
6794 : : /* cleanup */
6795 [ # # ]: 0 : if (pStereo[0]->t_parity)
6796 : : {
6797 : : INCHI_HEAPCHK
6798 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6799 : 0 : pStereo[0]->t_parity = NULL;
6800 : : }
6801 [ # # ]: 0 : if (pStereo[0]->nNumber)
6802 : : {
6803 : : INCHI_HEAPCHK
6804 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6805 : 0 : pStereo[0]->nNumber = NULL;
6806 : : }
6807 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6808 : 0 : goto exit_function;
6809 : : }
6810 : :
6811 : :
6812 : : /* Store stereocenters (pass 2) */
6813 : 0 : retf = SegmentSp3StoreStereoCenters(pbAbc, pStart, pEnd, pInChI[iComponent].nNumberOfAtoms, pStereo[0]);
6814 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6815 : : {
6816 : 0 : ret = RI_ERR_SYNTAX;
6817 : 0 : goto exit_function;
6818 : : }
6819 : :
6820 : : /* Treat multiplier-covered components */
6821 : 0 : retf = SegmentSp3CopyMultiplierCovered(mpy_component, iComponent, pInChI, bIso, nCpyType);
6822 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6823 : : {
6824 : 0 : ret = RI_ERR_SYNTAX;
6825 : 0 : goto exit_function;
6826 : : }
6827 : :
6828 : 0 : end_main_cycle:
6829 : 0 : iComponent += mpy_component;
6830 [ # # ]: 0 : if (*pEnd)
6831 : : {
6832 : 0 : pStart = pEnd + 1;
6833 : 0 : continue;
6834 : : }
6835 : : else
6836 : : {
6837 : 0 : break;
6838 : : }
6839 : :
6840 : : } /* Cycle over components */
6841 : :
6842 [ # # ]: 0 : if (nNumComponents != iComponent)
6843 : : {
6844 : : /* Not all components treated, that's an error */
6845 : 0 : ret = RI_ERR_SYNTAX;
6846 : 0 : goto exit_function;
6847 : : }
6848 : : /* At this moment, INChI_Stereo pInChI[k].Stereo provides stereocenter parity info for k-th component
6849 : : pInChI[k].Stereo.
6850 : : nNumber[nNumberOfStereoCenters] cano numbers
6851 : : t_parity[nNumberOfStereoCenters] tetrahedral atom parities
6852 : : */
6853 : :
6854 : :
6855 : 0 : ret = iComponent + 1;
6856 : :
6857 : 0 : exit_function:
6858 : :
6859 : 0 : return ret;
6860 : : }
6861 : :
6862 : :
6863 : : /****************************************************************************
6864 : : Parse "/b" InChI layer
6865 : : ****************************************************************************/
6866 : 0 : int ParseSegmentSp2(const char* str,
6867 : : int bMobileH,
6868 : : INChI* pInpInChI[],
6869 : : int ppnNumComponents[],
6870 : : int state,
6871 : : int* pbAbc)
6872 : : {
6873 : : /* Pass 1: count bonds and find actual numbers of atom */
6874 : : int i, mpy_component, val, len_limit;
6875 : : int nNumComponents, iComponent, len, iBond;
6876 : : AT_NUMB nAtom1, nAtom2;
6877 : : int bondParity;
6878 : : const char* p, * q, * t, * pStart, * pEnd, * r;
6879 : 0 : int ret = 0;
6880 : 0 : INChI* pInChI = pInpInChI[bMobileH];
6881 : 0 : INChI* pInChIFrom = NULL;
6882 : : /*
6883 : : INChI_Stereo *Stereo = NULL;
6884 : : INChI_Stereo *StereoOther = NULL;
6885 : : */
6886 : 0 : INChI_Stereo** pStereo = NULL;
6887 : :
6888 : 0 : const char mult_type[] = "mnMNe";
6889 : 0 : const char parity_type[] = "-+u?";
6890 : 0 : int bIsoTo, bIsoFrom, nCpyType = CPY_SP2;
6891 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP2 || state == IST_FIXED_H_ISO_SP2);
6892 : 0 : int base = 10;
6893 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
6894 : :
6895 [ # # # # : 0 : if (!bIso && state != IST_MOBILE_H_SP2 && state != IST_FIXED_H_SP2)
# # ]
6896 : : {
6897 : 0 : return RI_ERR_PROGR; /* program error */
6898 : : }
6899 : :
6900 [ # # ]: 0 : if (str[0] != 'b')
6901 : : {
6902 : 0 : return 0;
6903 : : }
6904 : :
6905 : 0 : pStart = (char*)str + 1;
6906 : 0 : iComponent = 0;
6907 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6908 : :
6909 [ # # ]: 0 : if (!*pStart)
6910 : : {
6911 : : /* create empty sp2 segment which means no sp2 */
6912 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6913 : : {
6914 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
6915 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
6916 [ # # # # : 0 : if (*pStereo && (pStereo[0]->b_parity || pStereo[0]->nNumberOfStereoBonds ||
# # ]
6917 [ # # # # ]: 0 : pStereo[0]->nBondAtom1 || pStereo[0]->nBondAtom2))
6918 : : {
6919 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6920 : 0 : goto exit_function;
6921 : : }
6922 : : /* allocate empty sp2 stereo */
6923 : 0 : ret = CopySegment(pIsoInChI, NULL, CPY_SP2, bIso, -1);
6924 [ # # ]: 0 : if (ret < 0)
6925 : : {
6926 : 0 : goto exit_function;
6927 : : }
6928 : : }
6929 : 0 : ret = nNumComponents + 1;
6930 : 0 : goto exit_function;
6931 : : }
6932 : :
6933 : : while (1)
6934 : : {
6935 : : /* Cycle over components */
6936 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
6937 : : {
6938 : 0 : pEnd = pStart + strlen(pStart);
6939 : : }
6940 : :
6941 : : /* djb-rwth: condition for if block had to be rewritten -- GH issue #09, thanks to Istvan Ori */
6942 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
6943 : : {
6944 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
6945 : 0 : if_cnd = isdigit(*pStart);
6946 : :
6947 : : }
6948 : : else
6949 : : {
6950 : 0 : val = 1;
6951 : 0 : q = pStart;
6952 : 0 : if_cnd = 1;
6953 : : }
6954 : :
6955 : :
6956 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used to store function return value */
# # ]
6957 : : {
6958 : : /* process the abbreviation */
6959 : 0 : ret = 0;
6960 : : #if (FIX_DALKE_BUGS == 1)
6961 : : /* djb-rwth: fixing GH issue #59.2 */
6962 : : if ((iComponent + val >= INT_MIN) && (iComponent + val <= INT_MAX))
6963 : : {
6964 [ # # ]: 0 : if ((iComponent + val > nNumComponents))
6965 : : {
6966 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6967 : 0 : goto exit_function;
6968 : : }
6969 : : }
6970 : : else
6971 : : {
6972 : : ret = BNS_PROGRAM_ERR;
6973 : : goto exit_function;
6974 : : }
6975 : : #endif
6976 [ # # # ]: 0 : switch (bMobileH)
6977 : : {
6978 : 0 : case TAUT_YES:
6979 [ # # ]: 0 : switch (state)
6980 : : {
6981 : 0 : case IST_MOBILE_H_ISO_SP2:
6982 [ # # ]: 0 : if (*q == 'm')
6983 : : {
6984 : : /* copy from mobile H to isotopic mobile H */
6985 : 0 : pInChIFrom = pInChI;
6986 : 0 : bIsoTo = 1;
6987 : 0 : bIsoFrom = 0;
6988 : : }
6989 : : else
6990 : : {
6991 [ # # ]: 0 : if (*q == 'e')
6992 : : {
6993 : : /* copy from mobile H to isotopic mobile H */
6994 : 0 : pInChIFrom = pInChI;
6995 : 0 : bIsoTo = 1;
6996 : 0 : bIsoFrom = -1; /* empty */
6997 : : }
6998 : : else
6999 : : {
7000 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7001 : : }
7002 : : }
7003 : 0 : break;
7004 : 0 : default:
7005 : 0 : ret = RI_ERR_SYNTAX;
7006 : 0 : break;
7007 : : }
7008 : 0 : break;
7009 : 0 : case TAUT_NON:
7010 [ # # # ]: 0 : switch (state)
7011 : : {
7012 : 0 : case IST_FIXED_H_SP2:
7013 [ # # ]: 0 : if (*q == 'm')
7014 : : {
7015 : : /* copy from mobile H to fixed H */
7016 : : #if ( FIX_GAF_2019_2==1 )
7017 [ # # ]: 0 : int inum = ALT_TAUT(bMobileH);
7018 : 0 : pInChIFrom = pInpInChI[inum];
7019 : : #else
7020 : : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
7021 : : #endif
7022 : 0 : bIsoTo = 0;
7023 : 0 : bIsoFrom = 0;
7024 : : }
7025 : : else
7026 : : {
7027 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7028 : : }
7029 : 0 : break;
7030 : 0 : case IST_FIXED_H_ISO_SP2:
7031 [ # # ]: 0 : if (*q == 'm')
7032 : : {
7033 : : /* copy from mobile H to fixed isotopic H */
7034 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
7035 : 0 : bIsoTo = 1;
7036 : 0 : bIsoFrom = 0;
7037 : : }
7038 : : else
7039 : : {
7040 [ # # ]: 0 : if (*q == 'M')
7041 : : {
7042 : : /* copy from isotopic mobile H to fixed isotopic H */
7043 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
7044 : 0 : bIsoTo = 1;
7045 : 0 : bIsoFrom = 1;
7046 : : }
7047 : : else
7048 : : {
7049 [ # # ]: 0 : if (*q == 'n')
7050 : : {
7051 : : /* copy from fixed H to fixed isotopic H */
7052 : 0 : pInChIFrom = pInChI;
7053 : 0 : bIsoTo = 1;
7054 : 0 : bIsoFrom = 0;
7055 : : }
7056 : : else
7057 : : {
7058 [ # # ]: 0 : if (*q == 'e')
7059 : : {
7060 : : /* copy from mobile H to isotopic mobile H */
7061 : 0 : pInChIFrom = pInChI;
7062 : 0 : bIsoTo = 1;
7063 : 0 : bIsoFrom = -1; /* empty */
7064 : : }
7065 : : else
7066 : : {
7067 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7068 : : }
7069 : : }
7070 : : }
7071 : : }
7072 : 0 : break;
7073 : 0 : default:
7074 : 0 : ret = RI_ERR_SYNTAX;
7075 : 0 : break;
7076 : : }
7077 : 0 : break;
7078 : :
7079 : 0 : default:
7080 : 0 : ret = RI_ERR_SYNTAX;
7081 : 0 : break;
7082 : : }
7083 [ # # ]: 0 : if (ret < 0)
7084 : : {
7085 : 0 : goto exit_function;
7086 : : }
7087 : : /* copy */
7088 [ # # ]: 0 : for (i = 0; i < val; i++)
7089 : : {
7090 : : #if ( FIX_GAF_2019_2==1 )
7091 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
7092 : : {
7093 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7094 : 0 : goto exit_function;
7095 : : }
7096 [ # # # # ]: 0 : if (NULL == pInChIFrom || NULL == pInChIFrom + iComponent + i) /* djb-rwth: ignoring GCC warning */
7097 : : {
7098 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7099 : 0 : goto exit_function;
7100 : : }
7101 : :
7102 [ # # # # ]: 0 : if ((pInChIFrom[iComponent + i].nNumberOfAtoms <= 0) || (pInChIFrom[iComponent + i].nNumberOfAtoms > MAX_ATOMS))
7103 : : {
7104 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7105 : 0 : goto exit_function;
7106 : : }
7107 : : #endif
7108 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, bIsoTo, bIsoFrom);
7109 [ # # ]: 0 : if (!ret)
7110 : : {
7111 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7112 : : }
7113 [ # # ]: 0 : if (ret < 0)
7114 : : {
7115 : 0 : goto exit_function;
7116 : : }
7117 : : }
7118 : 0 : mpy_component = val;
7119 : 0 : goto end_main_cycle;
7120 : : }
7121 : : else
7122 : : /* regular multiplier */
7123 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
7124 : : {
7125 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
7126 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7127 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
7128 : : {
7129 : 0 : ret = RI_ERR_SYNTAX;
7130 : 0 : goto exit_function;
7131 : : }
7132 : : #endif
7133 [ # # ]: 0 : if (p != q)
7134 : : {
7135 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7136 : 0 : goto exit_function;
7137 : : }
7138 : :
7139 : 0 : p++; /* move to the 1st character of the component */
7140 : : }
7141 : : else
7142 : : {
7143 : 0 : mpy_component = 1;
7144 : 0 : p = pStart;
7145 : : }
7146 : : #if (FIX_DALKE_BUGS == 1)
7147 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
7148 : : {
7149 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7150 : 0 : goto exit_function;
7151 : : }
7152 : : #endif
7153 : 0 : pStart = p;
7154 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
7155 : : {
7156 : : /* check if compressed InChI */
7157 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
7158 : : }
7159 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
7160 [ # # ]: 0 : if (*pbAbc == 1)
7161 : : {
7162 : : /* process the componnt: at1-at2p,at1-at2p,... */
7163 : : /* pass 1: find number of stereobonds */
7164 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++)
7165 : : {
7166 : : /* atoms 1, 2, and parity */
7167 [ # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7168 [ # # # # ]: 0 : (nAtom2 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7169 : 0 : (bondParity = (int)inchi_strtol(p, &p, 10),
7170 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= bondParity && bondParity <= AB_MAX_KNOWN_PARITY))
7171 : : {
7172 : : ; /* okay */
7173 : : }
7174 : : else
7175 : : {
7176 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7177 : 0 : goto exit_function;
7178 : : }
7179 [ # # ]: 0 : if (nAtom1 <= nAtom2 ||
7180 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms)
7181 : : {
7182 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7183 : 0 : goto exit_function;
7184 : : }
7185 : : }
7186 : : }
7187 : : else
7188 : : {
7189 : : /* process the componnt: at1-at2p,at1-at2p,... */
7190 : : /* pass 1: find number of stereobonds */
7191 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++, p += (*p == ','))
7192 : : {
7193 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
7194 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7195 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
7196 : : {
7197 : 0 : ret = RI_ERR_SYNTAX;
7198 : 0 : goto exit_function;
7199 : : }
7200 : : #endif
7201 [ # # ]: 0 : if (*q != '-')
7202 : : {
7203 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7204 : 0 : goto exit_function;
7205 : : }
7206 : 0 : p = q + 1;
7207 : 0 : nAtom2 = (AT_NUMB)inchi_strtol(p, &q, 10);
7208 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7209 [ # # ]: 0 : if (nAtom2 > MAX_ATOMS || nAtom2 < 0)
7210 : : {
7211 : 0 : ret = RI_ERR_SYNTAX;
7212 : 0 : goto exit_function;
7213 : : }
7214 : : #endif
7215 [ # # # # : 0 : if (!nAtom1 || !nAtom2 ||
# # ]
7216 : 0 : nAtom1 <= nAtom2 ||
7217 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
7218 [ # # ]: 0 : !(r = strchr((char*)parity_type, *q))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7219 : : {
7220 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7221 : 0 : goto exit_function;
7222 : : }
7223 : 0 : p = q + 1;
7224 : : }
7225 : : }
7226 : :
7227 [ # # ]: 0 : if (p != pEnd)
7228 : : {
7229 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7230 : 0 : goto exit_function;
7231 : : }
7232 : 0 : len = iBond;
7233 : :
7234 : : #if ( FIX_GAF_2019_2==1 )
7235 [ # # # # ]: 0 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
7236 : : {
7237 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7238 : 0 : goto exit_function;
7239 : : }
7240 [ # # # # ]: 0 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
7241 : : {
7242 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7243 : 0 : goto exit_function;
7244 : : }
7245 : : #endif
7246 : :
7247 : : /* memory allocation */
7248 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
7249 [ # # ]: 0 : if (!*pStereo)
7250 : : {
7251 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
7252 : : {
7253 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
7254 : 0 : goto exit_function;
7255 : : }
7256 : : }
7257 [ # # # # ]: 0 : if (pStereo[0]->b_parity || pStereo[0]->nNumberOfStereoBonds ||
7258 [ # # # # ]: 0 : pStereo[0]->nBondAtom1 || pStereo[0]->nBondAtom2)
7259 : : {
7260 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: bonds have already been allocated */
7261 : 0 : goto exit_function;
7262 : : }
7263 : : /* allocate sp2 stereo */
7264 : 0 : len_limit = len + 1;
7265 [ # # ]: 0 : if (!(pStereo[0]->b_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0]))) ||
7266 [ # # ]: 0 : !(pStereo[0]->nBondAtom1 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nBondAtom1[0]))) ||
7267 [ # # ]: 0 : !(pStereo[0]->nBondAtom2 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nBondAtom2[0])))) /* djb-rwth: cast operators added */
7268 : : {
7269 : : /* cleanup */
7270 [ # # ]: 0 : if (pStereo[0]->b_parity)
7271 : : {
7272 : : INCHI_HEAPCHK
7273 [ # # ]: 0 : inchi_free(pStereo[0]->b_parity);
7274 : 0 : pStereo[0]->b_parity = NULL;
7275 : : }
7276 [ # # ]: 0 : if (pStereo[0]->nBondAtom1)
7277 : : {
7278 : : INCHI_HEAPCHK
7279 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom1);
7280 : 0 : pStereo[0]->nBondAtom1 = NULL;
7281 : : }
7282 [ # # ]: 0 : if (pStereo[0]->nBondAtom2)
7283 : : {
7284 : : INCHI_HEAPCHK
7285 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom2);
7286 : 0 : pStereo[0]->nBondAtom2 = NULL;
7287 : : }
7288 : : INCHI_HEAPCHK
7289 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
7290 : 0 : goto exit_function;
7291 : : }
7292 : :
7293 : : /* pass 2: store stereobonds */
7294 [ # # ]: 0 : if (*pbAbc == 1)
7295 : : {
7296 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++)
7297 : : {
7298 [ # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7299 [ # # # # ]: 0 : (nAtom2 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7300 : 0 : (bondParity = (int)inchi_strtol(p, &p, 10),
7301 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= bondParity && bondParity <= AB_MAX_KNOWN_PARITY))
7302 : : {
7303 : : ; /* okay */
7304 : : }
7305 : : else
7306 : : {
7307 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7308 : 0 : goto exit_function;
7309 : : }
7310 : 0 : pStereo[0]->b_parity[iBond] = bondParity;
7311 : 0 : pStereo[0]->nBondAtom1[iBond] = nAtom1;
7312 : 0 : pStereo[0]->nBondAtom2[iBond] = nAtom2;
7313 : :
7314 [ # # ]: 0 : if (iBond &&
7315 [ # # ]: 0 : !(pStereo[0]->nBondAtom1[iBond - 1] < nAtom1 ||
7316 [ # # ]: 0 : (pStereo[0]->nBondAtom1[iBond - 1] == nAtom1 &&
7317 [ # # ]: 0 : pStereo[0]->nBondAtom2[iBond - 1] < nAtom2))) /* djb-rwth: addressing LLVM warning */
7318 : : {
7319 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: wrong bond order */
7320 : 0 : goto exit_function;
7321 : : }
7322 : : }
7323 : : }
7324 : : else
7325 : : {
7326 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++, p += (*p == ','))
7327 : : {
7328 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
7329 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7330 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
7331 : : {
7332 : 0 : ret = RI_ERR_SYNTAX;
7333 : 0 : goto exit_function;
7334 : : }
7335 : : #endif
7336 [ # # ]: 0 : if (*q != '-')
7337 : : {
7338 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7339 : 0 : goto exit_function;
7340 : : }
7341 : 0 : p = q + 1;
7342 : 0 : nAtom2 = (AT_NUMB)inchi_strtol(p, &q, 10);
7343 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7344 [ # # ]: 0 : if (nAtom2 > MAX_ATOMS || nAtom2 < 0)
7345 : : {
7346 : 0 : ret = RI_ERR_SYNTAX;
7347 : 0 : goto exit_function;
7348 : : }
7349 : : #endif
7350 [ # # ]: 0 : if (!(r = strchr((char*)parity_type, *q)))
7351 : : {
7352 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7353 : 0 : goto exit_function;
7354 : : }
7355 : 0 : p = q + 1;
7356 : 0 : bondParity = (int)(r - parity_type) + 1;
7357 : : /* djb-rwth: preventing buffer overrun */
7358 [ # # ]: 0 : if (iBond < len_limit)
7359 : : {
7360 : 0 : pStereo[0]->b_parity[iBond] = bondParity;
7361 : 0 : pStereo[0]->nBondAtom1[iBond] = nAtom1;
7362 : 0 : pStereo[0]->nBondAtom2[iBond] = nAtom2;
7363 : : }
7364 : : else
7365 : : {
7366 : 0 : ret = RI_ERR_PROGR;
7367 : 0 : goto exit_function;
7368 : : }
7369 : :
7370 [ # # ]: 0 : if (iBond &&
7371 [ # # ]: 0 : !(pStereo[0]->nBondAtom1[iBond - 1] < nAtom1 ||
7372 [ # # ]: 0 : (pStereo[0]->nBondAtom1[iBond - 1] == nAtom1 &&
7373 [ # # ]: 0 : pStereo[0]->nBondAtom2[iBond - 1] < nAtom2))) /* djb-rwth: addressing LLVM warning */
7374 : : {
7375 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: wrong bond order */
7376 : 0 : goto exit_function;
7377 : : }
7378 : : }
7379 : : }
7380 : 0 : pStereo[0]->nNumberOfStereoBonds = iBond;
7381 : :
7382 [ # # ]: 0 : if (p != pEnd)
7383 : : {
7384 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7385 : 0 : goto exit_function;
7386 : : }
7387 : :
7388 : : /* multiplier */
7389 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
7390 : : {
7391 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, bIso, bIso);
7392 [ # # ]: 0 : if (ret < 0)
7393 : : {
7394 : 0 : goto exit_function;
7395 : : }
7396 : : }
7397 : :
7398 : 0 : end_main_cycle:
7399 : 0 : iComponent += mpy_component;
7400 [ # # ]: 0 : if (*pEnd)
7401 : : {
7402 : 0 : pStart = pEnd + 1;
7403 : 0 : continue;
7404 : : }
7405 : : else
7406 : : {
7407 : 0 : break;
7408 : : }
7409 : : }
7410 [ # # ]: 0 : if (nNumComponents != iComponent)
7411 : : {
7412 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7413 : 0 : goto exit_function;
7414 : : }
7415 : 0 : ret = iComponent + 1;
7416 : :
7417 : 0 : exit_function:
7418 : :
7419 : 0 : return ret;
7420 : : }
7421 : :
7422 : :
7423 : : /****************************************************************************
7424 : : Parse "/p" InChI layer
7425 : : ****************************************************************************/
7426 : 0 : int ParseSegmentProtons(const char* str,
7427 : : int bMobileH,
7428 : : REM_PROTONS nNumProtons[],
7429 : : int ppnNumComponents[])
7430 : : {
7431 : : /* Pass 1: count bonds and find actual numbers of atom */
7432 : : int val;
7433 : : const char* q, * pStart, * pEnd;
7434 : : int ret;
7435 : :
7436 [ # # ]: 0 : if (str[0] != 'p')
7437 : : {
7438 : 0 : return 0;
7439 : : }
7440 : :
7441 : 0 : pStart = (char*)str + 1;
7442 : :
7443 : : while (1)
7444 : : {
7445 : : /* cycle over components */
7446 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
7447 : : {
7448 : 0 : pEnd = pStart + strlen(pStart);
7449 : : }
7450 : :
7451 [ # # # # ]: 0 : if (pStart[0] == '+' && isdigit(UCINT pStart[1]))
7452 : : {
7453 : 0 : val = (int)inchi_strtol(pStart + 1, &q, 10);
7454 : : }
7455 : : else
7456 : : {
7457 [ # # # # ]: 0 : if (pStart[0] == '-' && isdigit(UCINT pStart[1]))
7458 : : {
7459 : 0 : val = -(int)inchi_strtol(pStart + 1, &q, 10);
7460 : : }
7461 : : else
7462 : : {
7463 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7464 : 0 : goto exit_function;
7465 : : }
7466 : : }
7467 [ # # ]: 0 : if (!val)
7468 : : {
7469 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7470 : 0 : goto exit_function;
7471 : : }
7472 : 0 : nNumProtons[bMobileH].nNumRemovedProtons = val;
7473 [ # # # # ]: 0 : if (*pEnd || q != pEnd)
7474 : : {
7475 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7476 : 0 : goto exit_function;
7477 : : }
7478 : : else
7479 : : {
7480 : : break;
7481 : : }
7482 : : }
7483 : 0 : ret = 1;
7484 : :
7485 : 0 : exit_function:
7486 : :
7487 : 0 : return ret;
7488 : : }
7489 : :
7490 : :
7491 : : /****************************************************************************
7492 : : Parse "/z" InChI layer
7493 : : ****************************************************************************/
7494 : 0 : int ParseSegmentPolymer(const char* str,
7495 : : int bMobileH,
7496 : : REM_PROTONS nNumProtons[],
7497 : : int ppnNumComponents[],
7498 : : int na_total,
7499 : : int nb_total,
7500 : : int bInchi2Struct,
7501 : : OAD_Polymer** ppPolymer,
7502 : : OAD_V3000** ppV3000)
7503 : : {
7504 : : const char* p, * q, * pStart, * pEnd, * p0;
7505 : 0 : char comma = ',', dot = '.', dash = '-', lt_par = '(', rt_par = ')';
7506 : : int iunit, val, ret, prev, is_range, pdn_limit;
7507 : 0 : int curr_atom, type = -1, subtype = -1, conn = -1;
7508 : : AT_NUMB num_atom;
7509 : : INT_ARRAY alist;
7510 : 0 : OAD_Polymer* pd = NULL;
7511 : :
7512 [ # # ]: 0 : if (str[0] != 'z')
7513 : : {
7514 : 0 : return 0;
7515 : : }
7516 : :
7517 [ # # ]: 0 : if (IntArray_Alloc(&alist, 4))
7518 : : {
7519 : 0 : return RI_ERR_ALLOC;
7520 : : }
7521 : :
7522 [ # # ]: 0 : if (*ppPolymer)
7523 : : {
7524 : 0 : OAD_Polymer_Free(*ppPolymer);
7525 : : }
7526 : :
7527 : 0 : pd = *ppPolymer = (OAD_Polymer*)
7528 : 0 : inchi_calloc(1, sizeof(OAD_Polymer));
7529 : 0 : (*ppPolymer)->pzz = NULL;
7530 : :
7531 [ # # ]: 0 : if (!pd)
7532 : : {
7533 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7534 : : }
7535 : :
7536 : :
7537 [ # # ]: 0 : if (!bInchi2Struct)
7538 : : {
7539 : 0 : ret = RI_ERR_SYNTAX; goto exit_function;
7540 : : }
7541 : :
7542 : : /* Count units */
7543 : 0 : pd->n = 1;
7544 : 0 : p = (char*)str + 1;
7545 [ # # ]: 0 : while ((p = strchr(p, ';'))) /* djb-rwth: addressing LLVM warning */
7546 : : {
7547 : 0 : p++;
7548 : 0 : pd->n++;
7549 : : }
7550 : 0 : pd->units = (OAD_PolymerUnit**)
7551 : 0 : inchi_calloc(pd->n, sizeof(OAD_PolymerUnit*));
7552 : 0 : pdn_limit = pd->n;
7553 [ # # ]: 0 : if (!pd->units)
7554 : : {
7555 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7556 : : }
7557 : :
7558 : 0 : pStart = (char*)str;
7559 : 0 : pStart++;
7560 [ # # ]: 0 : if (!pStart)
7561 : : {
7562 : 0 : ret = RI_ERR_PROGR;
7563 : 0 : goto exit_function;
7564 : : }
7565 : :
7566 : 0 : iunit = 0;
7567 : : /* djb-rwth: fixing oss-fuzz issue #67678 */
7568 [ # # # # ]: 0 : while (pStart && (*pStart))
7569 : : {
7570 : 0 : OAD_PolymerUnit* unit = NULL;
7571 : :
7572 [ # # ]: 0 : if (*pStart == ';')
7573 : : {
7574 : 0 : pStart++;
7575 : : }
7576 : :
7577 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
7578 : : {
7579 : 0 : pEnd = pStart + strlen(pStart);
7580 : : }
7581 [ # # ]: 0 : if (!isdigit(UCINT pStart[0]))
7582 : : {
7583 : 0 : ret = RI_ERR_SYNTAX;
7584 : 0 : goto exit_function;
7585 : : }
7586 : 0 : val = (int)inchi_strtol(pStart + 0, &q, 10);
7587 : 0 : type = val / 100;
7588 : 0 : subtype = (val - (type * 100)) / 10;
7589 : 0 : conn = (val - (type * 100 + subtype * 10));
7590 [ # # ]: 0 : if (*q != '-')
7591 : : {
7592 : 0 : ret = RI_ERR_SYNTAX;
7593 : 0 : goto exit_function;
7594 : : }
7595 : : #if ( FIX_OSS_FUZZ_30162_30343==1 )
7596 [ # # ]: 0 : if (val < 100) /* type should always be non-zero followed by subtype and conn, like 101 or 200 */
7597 : : {
7598 : 0 : ret = RI_ERR_SYNTAX;
7599 : 0 : goto exit_function;
7600 : : }
7601 : : #endif
7602 : :
7603 : : #if ( FIX_GAF_2020_25741==1 )
7604 : : {
7605 : 0 : int valid_unit = 0;
7606 [ # # # # : 0 : if (type == POLYMER_STY_NON || type == POLYMER_STY_SRU || type == POLYMER_STY_MON ||
# # # # ]
7607 [ # # # # : 0 : type == POLYMER_STY_COP || type == POLYMER_STY_MOD || type == POLYMER_STY_CRO ||
# # ]
7608 : : type == POLYMER_STY_MER)
7609 : : {
7610 [ # # # # : 0 : if (subtype == POLYMER_SST_NON || subtype == POLYMER_SST_ALT ||
# # ]
7611 [ # # ]: 0 : subtype == POLYMER_SST_RAN || subtype == POLYMER_SST_BLK)
7612 : : {
7613 [ # # # # : 0 : if (conn == POLYMER_CONN_NON || conn == POLYMER_CONN_HT ||
# # ]
7614 [ # # ]: 0 : conn == POLYMER_CONN_HH || conn == POLYMER_CONN_EU)
7615 : : {
7616 : 0 : valid_unit = 1;
7617 : : }
7618 : : }
7619 : : }
7620 [ # # ]: 0 : if (!valid_unit)
7621 : : {
7622 : 0 : ret = RI_ERR_SYNTAX;
7623 : 0 : goto exit_function;
7624 : : }
7625 : : }
7626 : : #endif
7627 : :
7628 : 0 : q++;
7629 : 0 : prev = 0;
7630 : 0 : is_range = 0;
7631 [ # # # # ]: 0 : for (p = q, curr_atom = 0; p < pEnd && *p != '('; curr_atom++)
7632 : : {
7633 : 0 : num_atom = (AT_NUMB)inchi_strtol(p, &p, 10);
7634 : : #if ( ( CHECK_STRTOL_ATNUMB==1 ) || ( FIX_GAF_2019_2==1 ) )
7635 [ # # ]: 0 : if (num_atom > na_total || num_atom < 0)
7636 : : {
7637 : 0 : ret = RI_ERR_SYNTAX;
7638 : 0 : goto exit_function;
7639 : : }
7640 : : #endif
7641 [ # # # # ]: 0 : if (!num_atom || num_atom > na_total)
7642 : : {
7643 : 0 : ret = RI_ERR_SYNTAX; goto exit_function;
7644 : : }
7645 [ # # ]: 0 : if (is_range)
7646 : : {
7647 : : int a;
7648 [ # # ]: 0 : for (a = prev + 1; a <= num_atom; a++)
7649 : : {
7650 [ # # ]: 0 : if (0 != IntArray_Append(&alist, a))
7651 : : {
7652 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7653 : : }
7654 : : }
7655 : 0 : is_range = 0;
7656 : 0 : prev = 0;
7657 : : }
7658 : : else
7659 : : {
7660 [ # # ]: 0 : if (0 != IntArray_Append(&alist, num_atom))
7661 : : {
7662 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7663 : : }
7664 : 0 : prev = num_atom;
7665 : : }
7666 [ # # ]: 0 : if (*p == '-')
7667 : : {
7668 : 0 : p++;
7669 : 0 : is_range = 1;
7670 : : }
7671 [ # # ]: 0 : else if (*p == ',')
7672 : : {
7673 : 0 : p++;
7674 : : }
7675 : : }
7676 : :
7677 [ # # ]: 0 : if (alist.used)
7678 : : {
7679 : 0 : unit = OAD_PolymerUnit_New(4, /* maxatoms */
7680 : : 0, /* maxbonds=0 for now */
7681 : : iunit + 1, /* id */
7682 : : iunit + 1, /* label */
7683 : : type,
7684 : : subtype,
7685 : : conn,
7686 : : "", /* smt */
7687 : : alist.used,
7688 : : &alist,
7689 : : 0, /* blist.used */
7690 : : NULL, /* &blist */
7691 : : 0, /* nlinks */
7692 : : NULL /* **links */
7693 : : );
7694 : :
7695 [ # # ]: 0 : if (!unit)
7696 : : {
7697 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7698 : : }
7699 : : /* djb-rwth: preventing buffer overrun */
7700 [ # # ]: 0 : if (iunit < pdn_limit)
7701 : : {
7702 : 0 : pd->units[iunit] = unit;
7703 : : }
7704 : : else
7705 : : {
7706 : 0 : ret = RI_ERR_PROGR;
7707 : 0 : goto exit_function;
7708 : : }
7709 : 0 : IntArray_Reset(&alist);
7710 : 0 : iunit++;
7711 : : }
7712 : :
7713 [ # # ]: 0 : if (*p == lt_par)
7714 : 0 : {
7715 : : /* Structure-based representn, read crossing bonds information */
7716 : 0 : const int nothing = 0, endgroups = 1, stars = 2, stars_ring = 3, stars_bond = 4, stars_atom = 5;
7717 : 0 : int have = nothing;
7718 : 0 : int res, ib, err = 0; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7719 : : INT_ARRAY numlist;
7720 : :
7721 [ # # ]: 0 : if (IntArray_Alloc(&numlist, 4))
7722 : : {
7723 : 0 : ret = RI_ERR_ALLOC;
7724 : 0 : goto exit_function;
7725 : : }
7726 : :
7727 : 0 : p0 = p;
7728 [ # # ]: 0 : while (*(++p))
7729 : : {
7730 [ # # ]: 0 : if (*p == '-')
7731 : : {
7732 : 0 : have = endgroups; break;
7733 : : }
7734 [ # # ]: 0 : if (*p == ',')
7735 : : {
7736 : 0 : have = stars; break;
7737 : : }
7738 : : }
7739 [ # # ]: 0 : if (have == stars)
7740 : : {
7741 [ # # ]: 0 : while (*(++p))
7742 : : {
7743 [ # # ]: 0 : if (*p == ',')
7744 : : {
7745 : 0 : have = stars_ring; break;
7746 : : }
7747 [ # # ]: 0 : if (*p == '.')
7748 : : {
7749 : 0 : have = stars_bond; break;
7750 : : }
7751 [ # # ]: 0 : if (*p == ')')
7752 : : {
7753 : 0 : have = stars_atom; break;
7754 : : }
7755 : : }
7756 : : }
7757 : 0 : p = p0;
7758 : :
7759 [ # # ]: 0 : if (unit) /* djb-rwth: fixing a NULL pointer dereference */
7760 : : {
7761 : 0 : unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
7762 [ # # ]: 0 : if (have == endgroups)
7763 : : {
7764 : : /* Read end groups notation */
7765 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dash, comma, &res);
7766 [ # # # # ]: 0 : if (res == 1 && numlist.used == 2)
7767 : : {
7768 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dash, rt_par, &res);
7769 : : }
7770 [ # # # # ]: 0 : if (res == 1 && numlist.used == 4)
7771 : : {
7772 : 0 : pStart = p + 1;
7773 : 0 : unit->nb = 2;
7774 : 0 : unit->blist = (int*)inchi_calloc(2 * (long long)unit->nb, sizeof(int)); /* djb-rwth: cast operator added */
7775 [ # # ]: 0 : if (!unit->blist)
7776 : : {
7777 : 0 : ret = RI_ERR_ALLOC; IntArray_Free(&numlist); goto exit_function;
7778 : : }
7779 : 0 : unit->blist[0] = numlist.item[0]; unit->blist[1] = numlist.item[1];
7780 : 0 : unit->blist[2] = numlist.item[2]; unit->blist[3] = numlist.item[3];
7781 : 0 : unit->cap1 = numlist.item[0]; /* just for GAF check belows */
7782 : 0 : unit->cap2 = numlist.item[2];
7783 : 0 : IntArray_Free(&numlist);
7784 : 0 : continue;
7785 : : }
7786 : : }
7787 [ # # # # ]: 0 : else if (have == stars_ring ||
7788 [ # # ]: 0 : have == stars_bond ||
7789 : : have == stars_atom)
7790 : : {
7791 : : /* Read star atoms - frame shiftable bonds notation */
7792 : 0 : IntArray_Reset(&numlist);
7793 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, comma, dash, &res);
7794 [ # # # # ]: 0 : if (res != 1 || numlist.used != 2)
7795 : : {
7796 : 0 : ret = RI_ERR_SYNTAX; IntArray_Free(&numlist); goto exit_function;
7797 : : }
7798 : : /* OK, we got star atom numbers */
7799 [ # # ]: 0 : if (have == stars_ring)
7800 : : {
7801 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, comma, rt_par, &res);
7802 [ # # # # ]: 0 : if (res != 1 || numlist.used < 4)
7803 : : {
7804 : 0 : ret = RI_ERR_SYNTAX;
7805 : 0 : IntArray_Free(&numlist);
7806 : 0 : goto exit_function;
7807 : : }
7808 : 0 : unit->cyclizable = CLOSING_SRU_RING;
7809 : 0 : unit->nbkbonds = (numlist.used - 2) / 2;
7810 : : }
7811 [ # # ]: 0 : else if (have == stars_bond)
7812 : : {
7813 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dot, rt_par, &res);
7814 [ # # # # ]: 0 : if (res != 1 || numlist.used < 4)
7815 : : {
7816 : 0 : ret = RI_ERR_SYNTAX;
7817 : 0 : IntArray_Free(&numlist);
7818 : 0 : goto exit_function;
7819 : : }
7820 : 0 : unit->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;
7821 : 0 : unit->nbkbonds = 1;
7822 : : }
7823 [ # # ]: 0 : else if (have == stars_atom)
7824 : : {
7825 : 0 : int num = inchi_strtol(++p, &p, 10);
7826 : : #if ( ( CHECK_STRTOL_ATNUMB==1 ) || ( FIX_GAF_2019_2==1 ) )
7827 [ # # # # ]: 0 : if (num > na_total || num < 0)
7828 : : {
7829 : 0 : IntArray_Free(&numlist);
7830 : 0 : ret = RI_ERR_SYNTAX;
7831 : 0 : goto exit_function;
7832 : : }
7833 : : #endif
7834 [ # # ]: 0 : if (*p != rt_par)
7835 : : {
7836 : 0 : ret = RI_ERR_SYNTAX;
7837 : 0 : IntArray_Free(&numlist);
7838 : 0 : goto exit_function;
7839 : : }
7840 : 0 : IntArray_Append(&numlist, num);
7841 : 0 : unit->cyclizable = CLOSING_SRU_DIRADICAL;
7842 : 0 : unit->nbkbonds = 1;
7843 : : }
7844 : : }
7845 : : else
7846 : : {
7847 : 0 : ret = RI_ERR_SYNTAX; IntArray_Free(&numlist); goto exit_function;
7848 : : }
7849 : :
7850 : 0 : unit->cap1 = numlist.item[0];
7851 : 0 : unit->cap2 = numlist.item[1];
7852 : :
7853 [ # # ]: 0 : if (unit->bkbonds)
7854 : : {
7855 : 0 : imat_free(unit->maxbkbonds, unit->bkbonds);
7856 : 0 : unit->bkbonds = NULL;
7857 : : }
7858 : 0 : unit->maxbkbonds = inchi_max(unit->maxbkbonds, unit->nbkbonds);
7859 : 0 : err = imat_new(unit->maxbkbonds, 2, &(unit->bkbonds)); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7860 [ # # ]: 0 : for (ib = 0; ib < unit->nbkbonds; ib++)
7861 : : {
7862 : 0 : unit->bkbonds[ib][0] = numlist.item[ib * 2 + 2];
7863 [ # # ]: 0 : if (numlist.used != 3)
7864 : : {
7865 : 0 : unit->bkbonds[ib][1] = numlist.item[ib * 2 + 3];
7866 : : }
7867 : : else
7868 : : {
7869 : 0 : unit->bkbonds[ib][1] = unit->bkbonds[ib][0];
7870 : : }
7871 : : }
7872 [ # # ]: 0 : if (unit->nbkbonds > 0)
7873 : : {
7874 : : /*unit->cyclizable = 1;*/
7875 : 0 : unit->cap1 = numlist.item[0];
7876 : 0 : unit->cap2 = numlist.item[1];
7877 : : }
7878 : : }
7879 : :
7880 : 0 : pStart = p + 1;
7881 : 0 : IntArray_Free(&numlist);
7882 : 0 : continue;
7883 : : }
7884 : :
7885 [ # # ]: 0 : if (*p == ';')
7886 : : {
7887 : 0 : p++;
7888 : : }
7889 : 0 : q = p;
7890 : 0 : pStart = p;
7891 : : }
7892 : :
7893 : 0 : pd->really_do_frame_shift = 1;
7894 : 0 : pd->frame_shift_scheme = FSS_STARS_CYCLED;
7895 : 0 : pd->treat = POLYMERS_MODERN;
7896 : 0 : pd->is_in_reconn = 0;
7897 : :
7898 : : /*OAD_Polymer_DebugTrace( pd );*/
7899 : :
7900 : 0 : ret = pd->n;
7901 : :
7902 : 0 : exit_function:
7903 : :
7904 : 0 : IntArray_Free(&alist);
7905 [ # # # # : 0 : if (ret == RI_ERR_ALLOC || ret == RI_ERR_SYNTAX || ret == RI_ERR_PROGR)
# # ]
7906 : : {
7907 : : /*FreeExtOrigAtData( pd, pv );*/
7908 : : }
7909 : : #if ( FIX_GAF_2019_2==1 )
7910 : : else
7911 : : {
7912 [ # # ]: 0 : if (pd)
7913 : : {
7914 : 0 : int iu, ipsb, maxats = na_total + pd->n_pzz;
7915 [ # # ]: 0 : for (iu = 0; iu < pd->n; iu++)
7916 : : {
7917 : : int astar1, astar2;
7918 : : #if ( FIX_OSS_FUZZ_25604==1 )
7919 [ # # ]: 0 : if (NULL == pd->units[iu])
7920 : : {
7921 : 0 : ret = RI_ERR_SYNTAX;
7922 : 0 : break;
7923 : : }
7924 : : #endif
7925 : 0 : astar1 = pd->units[iu]->cap1;
7926 : 0 : astar2 = pd->units[iu]->cap2;
7927 [ # # ]: 0 : if (0 == pd->units[iu]->nb)
7928 : : {
7929 : 0 : continue;
7930 : : }
7931 [ # # ]: 0 : if (ret == RI_ERR_SYNTAX)
7932 : : {
7933 : 0 : break;
7934 : : }
7935 [ # # # # : 0 : if (astar1 > maxats || astar1 <= 0 || astar2 > maxats || astar2 <= 0)
# # # # ]
7936 : : {
7937 : 0 : ret = RI_ERR_SYNTAX;
7938 : 0 : break;
7939 : : }
7940 [ # # ]: 0 : for (ipsb = 0; ipsb < pd->units[iu]->nbkbonds; ipsb++)
7941 : : {
7942 : : int a1psb, a2psb;
7943 : 0 : a1psb = pd->units[iu]->bkbonds[ipsb][0];
7944 : 0 : a2psb = pd->units[iu]->bkbonds[ipsb][1];
7945 [ # # # # : 0 : if (a1psb > maxats || a1psb <= 0 || a2psb > maxats || a2psb <= 0)
# # # # ]
7946 : : {
7947 : 0 : ret = RI_ERR_SYNTAX;
7948 : 0 : break;
7949 : : }
7950 : : }
7951 : : }
7952 : : }
7953 : : }
7954 : : #endif
7955 : :
7956 : 0 : return ret;
7957 : : }
7958 : :
7959 : : /****************************************************************************
7960 : : Read sequence of integer numbers from str into growing int array numlist
7961 : : until NULL, EOL or 'c_stop' symbol occurred, whichever is the first.
7962 : : Numbers are assumed to be delimited with commas.
7963 : :
7964 : : NB: on success, returns 1.
7965 : : ****************************************************************************/
7966 : 0 : const char* ParseSegmentReadDelimitedNumbers(const char* str,
7967 : : const char* pEnd,
7968 : : INT_ARRAY* numlist,
7969 : : char c_delim,
7970 : : char c_stop,
7971 : : int* ret)
7972 : : {
7973 : : const char* p, * pStart;
7974 : 0 : int num, curr_atom = 0;
7975 : :
7976 : 0 : *ret = 1;
7977 : :
7978 [ # # ]: 0 : if (!str)
7979 : : {
7980 : 0 : *ret = -1;
7981 : 0 : return NULL;
7982 : : }
7983 : :
7984 : 0 : pStart = (char*)(str + 1);
7985 : 0 : p = pStart;
7986 [ # # ]: 0 : while (*pStart)
7987 : : {
7988 [ # # # # ]: 0 : for (p = pStart, curr_atom = 0; p < pEnd && *p != c_stop; curr_atom++)
7989 : : {
7990 : 0 : num = (AT_NUMB)inchi_strtol(p, &p, 10);
7991 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7992 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
7993 : : {
7994 : 0 : *ret = RI_ERR_SYNTAX;
7995 : 0 : return p;
7996 : : }
7997 : : #endif
7998 : : {
7999 [ # # ]: 0 : if (0 != IntArray_Append(numlist, num))
8000 : : {
8001 : 0 : *ret = RI_ERR_SYNTAX;
8002 : 0 : return p;
8003 : : }
8004 : : }
8005 [ # # ]: 0 : if (*p == c_delim)
8006 : : {
8007 : 0 : p++;
8008 : : }
8009 [ # # ]: 0 : else if (*p == c_stop)
8010 : : {
8011 : 0 : return p;
8012 : : }
8013 : : else
8014 : : {
8015 : 0 : *ret = -1; return NULL;
8016 : : }
8017 : : }
8018 [ # # ]: 0 : if (*p == c_stop)
8019 : : {
8020 : 0 : return p;
8021 : : }
8022 : : }
8023 : :
8024 : 0 : return p;
8025 : : }
8026 : :
8027 : :
8028 : :
8029 : : /****************************************************************************
8030 : : Parse "/q" InChI layer
8031 : : ****************************************************************************/
8032 : 0 : int ParseSegmentCharge(const char* str,
8033 : : int bMobileH,
8034 : : INChI* pInpInChI[],
8035 : : int ppnNumComponents[])
8036 : : {
8037 : : /* Pass 1: count bonds and find actual numbers of atom */
8038 : : int i, mpy_component, val;
8039 : : int nNumComponents, iComponent;
8040 : : const char* p, * q, * t, * pStart, * pEnd;
8041 : : int ret;
8042 : 0 : INChI* pInChI = pInpInChI[bMobileH];
8043 : 0 : const char mult_type[] = "mnMNe";
8044 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
8045 : :
8046 [ # # ]: 0 : if (str[0] != 'q')
8047 : : {
8048 : 0 : return 0;
8049 : : }
8050 : :
8051 : 0 : pStart = (char*)str + 1;
8052 : 0 : iComponent = 0;
8053 : 0 : nNumComponents = ppnNumComponents[bMobileH];
8054 : :
8055 [ # # # # ]: 0 : if (!*pStart && bMobileH == TAUT_NON)
8056 : : {
8057 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
8058 : : {
8059 : 0 : pInChI[i].nTotalCharge = NO_VALUE_INT;
8060 : : }
8061 : 0 : return nNumComponents + 1;
8062 : : }
8063 : :
8064 : : while (1)
8065 : : {
8066 : : /* cycle over components */
8067 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
8068 : : {
8069 : 0 : pEnd = pStart + strlen(pStart);
8070 : : }
8071 : :
8072 : : /* djb-rwth: condition for if block had to be rewritten */
8073 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
8074 : : {
8075 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
8076 : 0 : if_cnd = isdigit(UCINT * pStart);
8077 : :
8078 : : }
8079 : : else
8080 : : {
8081 : 0 : val = 1;
8082 : 0 : q = pStart;
8083 : 0 : if_cnd = 1;
8084 : : }
8085 : :
8086 : :
8087 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used to store function return value */
# # ]
8088 : : {
8089 : : /* process the abbreviation */
8090 : :
8091 [ # # # ]: 0 : switch (bMobileH)
8092 : : {
8093 : 0 : case TAUT_YES:
8094 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8095 : 0 : goto exit_function;
8096 : 0 : case TAUT_NON:
8097 [ # # ]: 0 : if (*q != 'm' ||
8098 [ # # ]: 0 : iComponent + val > nNumComponents ||
8099 [ # # ]: 0 : iComponent + val > ppnNumComponents[TAUT_YES])
8100 : : {
8101 : :
8102 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8103 : 0 : goto exit_function;
8104 : : }
8105 [ # # ]: 0 : for (i = 0; i < val; i++)
8106 : : {
8107 : : /* avoid 0 which means "omitted" */
8108 : 0 : pInChI[iComponent + i].nTotalCharge = pInpInChI[TAUT_YES][iComponent + i].nTotalCharge ?
8109 [ # # ]: 0 : pInpInChI[TAUT_YES][iComponent + i].nTotalCharge :
8110 : : NO_VALUE_INT;
8111 : : }
8112 : 0 : mpy_component = val;
8113 : 0 : goto end_main_cycle;
8114 : 0 : default:
8115 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8116 : 0 : goto exit_function;
8117 : : }
8118 : : }
8119 : : else
8120 : : {
8121 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
8122 : : {
8123 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
8124 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8125 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
8126 : : {
8127 : 0 : ret = RI_ERR_SYNTAX;
8128 : 0 : goto exit_function;
8129 : : }
8130 : : #endif
8131 [ # # ]: 0 : if (p != q)
8132 : : {
8133 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8134 : 0 : goto exit_function;
8135 : : }
8136 : 0 : p++;
8137 : : }
8138 : : else
8139 : : {
8140 : 0 : mpy_component = 1;
8141 : 0 : p = pStart;
8142 : : }
8143 : : }
8144 : : #if ( FIX_DALKE_BUGS == 1 )
8145 [ # # # # ]: 0 : if (mpy_component + iComponent > nNumComponents || mpy_component <= 0)
8146 : : {
8147 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: too many components in charge layer */
8148 : 0 : goto exit_function;
8149 : : }
8150 : : #endif
8151 : 0 : pStart = p;
8152 [ # # ]: 0 : if (pStart < pEnd)
8153 : : {
8154 [ # # # # ]: 0 : if (pStart[0] == '+' && isdigit(UCINT pStart[1]))
8155 : : {
8156 : 0 : val = (int)inchi_strtol(pStart + 1, &q, 10);
8157 : 0 : pStart = q;
8158 : : }
8159 : : else
8160 : : {
8161 [ # # # # ]: 0 : if (pStart[0] == '-' && isdigit(UCINT pStart[1]))
8162 : : {
8163 : 0 : val = -(int)inchi_strtol(pStart + 1, &q, 10);
8164 : 0 : pStart = q;
8165 : : }
8166 : : else
8167 : : {
8168 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8169 : 0 : goto exit_function;
8170 : : }
8171 : : }
8172 : : #if ( FIX_DALKE_BUGS == 1 )
8173 [ # # # # ]: 0 : if (val < -256 || val > 256)
8174 : : {
8175 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8176 : 0 : goto exit_function;
8177 : : }
8178 : : #endif
8179 [ # # ]: 0 : if (!val)
8180 : : {
8181 [ # # ]: 0 : if (pStart != pEnd)
8182 : : {
8183 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8184 : 0 : goto exit_function;
8185 : : }
8186 [ # # ]: 0 : if (bMobileH == TAUT_NON)
8187 : : {
8188 : 0 : val = NO_VALUE_INT; /* avoid 0 which means "omitted" */
8189 : : }
8190 : : }
8191 : : }
8192 : : else
8193 : : {
8194 : 0 : val = NO_VALUE_INT;
8195 : : }
8196 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
8197 : : {
8198 : 0 : pInChI[iComponent + i].nTotalCharge = val;
8199 : : }
8200 : :
8201 : 0 : end_main_cycle:
8202 : 0 : iComponent += mpy_component;
8203 [ # # ]: 0 : if (*pEnd)
8204 : : {
8205 : 0 : pStart = pEnd + 1;
8206 : 0 : continue;
8207 : : }
8208 : : else
8209 : : {
8210 : 0 : break;
8211 : : }
8212 : : }
8213 : :
8214 [ # # ]: 0 : if (nNumComponents != iComponent)
8215 : : {
8216 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8217 : 0 : goto exit_function;
8218 : : }
8219 : 0 : ret = iComponent + 1;
8220 : :
8221 : 0 : exit_function:
8222 : :
8223 : 0 : return ret;
8224 : : }
8225 : :
8226 : :
8227 : : /****************************************************************************
8228 : : Parse "/h" InChI layer
8229 : : ****************************************************************************/
8230 : 0 : int ParseSegmentMobileH(const char* str,
8231 : : int bMobileH,
8232 : : INChI* pInpInChI[],
8233 : : int pnNumComponents[],
8234 : : int* pbAbc)
8235 : : {
8236 : : #define nNum_H( ICOMPONENT ) ((bMobileH==TAUT_YES)? pInChI[ICOMPONENT].nNum_H : pInChI[ICOMPONENT].nNum_H_fixed)
8237 : :
8238 : : /* Pass 1: count bonds and find actual numbers of atom */
8239 : :
8240 : 0 : int i, mpy_component, num_H, num_Minus, val, num_Atoms, numCtAtoms, tg_alloc_len, len, len2, k = 0;
8241 : : int num_H_component, num_H_formula, num_taut_H_component, num_H_InChI, ret2;
8242 : : int nNumComponents, iComponent, lenTautomer, tg_pos_Tautomer, iTGroup; /* djb-rwth: removing redundant variables */
8243 : : const char* p, * q, * h, * t, * p1, * pTaut, * pStart, * pEnd;
8244 : : int curAtom, nxtAtom; /* djb-rwth: fixing coverity ID #499563 */
8245 [ # # ]: 0 : int state, ret, nAltMobileH = ALT_TAUT(bMobileH); /* djb-rwth: removing redundant variables */
8246 : 0 : INChI* pInChI = pInpInChI[bMobileH];
8247 : 0 : INChI* pAltInChI = pInpInChI[nAltMobileH];
8248 : 0 : int base = 10;
8249 : :
8250 : 0 : num_H = -999; /* impossible value */
8251 : 0 : num_Minus = -999; /* impossible value */
8252 : 0 : tg_pos_Tautomer = -999; /* impossible value */
8253 : :
8254 : : /* number of immobile H is always allocated; immobile H are present in M layer only */
8255 : 0 : nNumComponents = pnNumComponents[bMobileH];
8256 : :
8257 : : /* djb-rwth: fixing oss-fuzz issues #66985, #66718, #43512, #43456, #43420, #42774, #34772, #30156 */
8258 : :
8259 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
8260 : : {
8261 : 0 : len = pInChI[i].nNumberOfAtoms;
8262 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && i < pnNumComponents[nAltMobileH])
8263 : : {
8264 [ # # ]: 0 : if (len < pAltInChI[i].nNumberOfAtoms)
8265 : : {
8266 : 0 : len = pAltInChI[i].nNumberOfAtoms;
8267 [ # # ]: 0 : if (pInChI[i].nNum_H)
8268 : : {
8269 [ # # ]: 0 : inchi_free(pInChI[i].nNum_H);
8270 : 0 : pInChI[i].nNum_H = NULL;
8271 : : }
8272 : : }
8273 : : }
8274 : 0 : len++;
8275 [ # # ]: 0 : if (!pInChI[i].nNum_H)
8276 : : {
8277 : 0 : S_CHAR* pi_nnh2 = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H[0]));
8278 [ # # ]: 0 : if (!pi_nnh2)
8279 : : {
8280 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8281 : 0 : goto exit_function;
8282 : : }
8283 : 0 : pInChI[i].nNum_H = pi_nnh2;
8284 : : /* pi_nnh2_init = true; */
8285 : : }
8286 : : /* copy immobile H from Mobile-H layer to Fixed-H layer */
8287 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && i < pnNumComponents[nAltMobileH])
8288 : : {
8289 : 0 : S_CHAR* pai_nnh = (S_CHAR*)inchi_realloc(pAltInChI[i].nNum_H, len * sizeof(pAltInChI[0].nNum_H[0]));
8290 [ # # ]: 0 : if (pai_nnh)
8291 : : {
8292 : 0 : S_CHAR* pi_nnh1 = NULL; /* copied from below to satisfy C syntax 2024-09-01 DT */
8293 : 0 : pAltInChI[i].nNum_H = pai_nnh;
8294 : : /*if (!pi_nnh2_init)
8295 : : {
8296 : : */
8297 : 0 : pi_nnh1 = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H[0]));
8298 [ # # ]: 0 : if (!pi_nnh1)
8299 : : {
8300 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8301 : 0 : goto exit_function;
8302 : : }
8303 : 0 : memcpy(pi_nnh1, pai_nnh, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0])); /* djb-rwth: cast operator added */
8304 : : /* djb-rwth: alternative solution
8305 : : k = memcpy_custom(&pi_nnh1[i], pAltInChI[i].nNum_H, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0]))
8306 : : if (k)
8307 : : {
8308 : : ret = RI_ERR_ALLOC;
8309 : : goto exit_function;
8310 : : }
8311 : : */
8312 : 0 : pInChI[i].nNum_H = pi_nnh1;
8313 : : /*
8314 : : }
8315 : : else
8316 : : {
8317 : : memcpy(pi_nnh2, pai_nnh, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0])); * djb-rwth: cast operator added *
8318 : : * djb-rwth: alternative solution *
8319 : : k = memcpy_custom(&pi_nnh2[i], pAltInChI[i].nNum_H, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0]))
8320 : : if (k)
8321 : : {
8322 : : ret = RI_ERR_ALLOC;
8323 : : goto exit_function;
8324 : : }
8325 : :
8326 : : }
8327 : : */
8328 : : }
8329 : : else
8330 : : {
8331 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8332 : 0 : goto exit_function;
8333 : : }
8334 : : }
8335 : : }
8336 : :
8337 [ # # ]: 0 : if (str[0] != 'h')
8338 : : {
8339 : 0 : return 0;
8340 : : }
8341 : :
8342 : : /* Read Hydrogen info in 1 pass */
8343 : :
8344 : 0 : pStart = (char*)str + 1;
8345 : 0 : iComponent = 0;
8346 : 0 : nNumComponents = pnNumComponents[bMobileH];
8347 : :
8348 : : while (1)
8349 : : {
8350 : : /* cycle over components */
8351 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
8352 : : {
8353 : 0 : pEnd = pStart + strlen(pStart);
8354 : : }
8355 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
8356 : : {
8357 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
8358 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8359 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
8360 : : {
8361 : 0 : ret = RI_ERR_SYNTAX;
8362 : 0 : goto exit_function;
8363 : : }
8364 : : #endif
8365 : : #if ( FIX_DALKE_BUGS == 1 )
8366 [ # # # # ]: 0 : if (p != q || !isdigit(UCINT* pStart)) /* prevent non-positive multipliers */
8367 : : #else
8368 : : if (p != q)
8369 : : #endif
8370 : : {
8371 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8372 : 0 : goto exit_function;
8373 : : }
8374 : 0 : p++;
8375 : : }
8376 : : else
8377 : : {
8378 : 0 : mpy_component = 1;
8379 : 0 : p = pStart;
8380 : : }
8381 : 0 : pStart = p;
8382 : : /* Pass 1.1 parse a component */
8383 : : /* djb-rwth: removing redundant code */
8384 : : /* djb-rwth: removing redundant code */
8385 : : /* djb-rwth: removing redundant code */
8386 : 0 : curAtom = 0; /* djb-rwth: ignoring LLVM warning: value used */
8387 : 0 : numCtAtoms = pInChI[iComponent].nNumberOfAtoms;
8388 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && iComponent < pnNumComponents[nAltMobileH])
8389 : : {
8390 : 0 : numCtAtoms = pAltInChI[iComponent].nNumberOfAtoms;
8391 : : }
8392 : :
8393 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
8394 : : {
8395 : : /* check if compressed InChI */
8396 [ # # # # ]: 0 : *pbAbc = (*p == ',' || isupper(UCINT* p)) ? 1 : 0;
8397 : : }
8398 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
8399 : :
8400 : : /* immobile H */
8401 [ # # ]: 0 : t = pTaut = (*pbAbc == 1) ? strchr(p, ',') : strchr(p, '('); /* locate the first tautomer group character */
8402 : :
8403 [ # # # # ]: 0 : if (t && bMobileH == TAUT_NON)
8404 : : {
8405 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8406 : 0 : goto exit_function;
8407 : : }
8408 [ # # # # ]: 0 : if (!pTaut || pTaut > pEnd)
8409 : : {
8410 : 0 : pTaut = pEnd;
8411 : 0 : t = NULL; /* found no tautomeric group for this component */
8412 : : }
8413 : : /* djb-rwth: fixing oss-fuzz issue #69489 */
8414 [ # # # # ]: 0 : for (i = 0; (i < mpy_component) && (iComponent + i < nNumComponents); i++)
8415 : : {
8416 [ # # ]: 0 : if (bMobileH == TAUT_NON)
8417 : : {
8418 : : /* allocate nNum_H_fixed */
8419 [ # # ]: 0 : if (pInChI[iComponent + i].nNum_H_fixed)
8420 : : {
8421 : 0 : ret = RI_ERR_PROGR; /* program error */
8422 : 0 : goto exit_function;
8423 : : }
8424 [ # # ]: 0 : if (iComponent + i < pnNumComponents[nAltMobileH])
8425 : : {
8426 : 0 : len = inchi_max(pInChI[iComponent + i].nNumberOfAtoms, pAltInChI[iComponent + i].nNumberOfAtoms) + 1;
8427 : : }
8428 : : else
8429 : : {
8430 : 0 : len = pInChI[iComponent + i].nNumberOfAtoms + 1;
8431 : : }
8432 : 0 : pInChI[iComponent + i].nNum_H_fixed = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H_fixed[0]));
8433 [ # # ]: 0 : if (!pInChI[iComponent + i].nNum_H_fixed)
8434 : : {
8435 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8436 : 0 : goto exit_function;
8437 : : }
8438 : : /* compare nAtom */
8439 [ # # ]: 0 : if (iComponent + i < pnNumComponents[nAltMobileH])
8440 : : {
8441 : 0 : len2 = inchi_min(pInChI[iComponent + i].nNumberOfAtoms, pAltInChI[iComponent + i].nNumberOfAtoms);
8442 [ # # # # ]: 0 : if (pInChI[iComponent + i].nAtom && len2)
8443 : : {
8444 : : /* check */
8445 [ # # ]: 0 : if (memcmp(pInChI[iComponent + i].nAtom, pAltInChI[iComponent + i].nAtom, len2 * sizeof(pInChI[0].nAtom[0])))
8446 : : {
8447 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8448 : 0 : goto exit_function;
8449 : : }
8450 : : }
8451 : : /* allocate and copy atom if bridging H are present */
8452 [ # # ]: 0 : if (pInChI[iComponent + i].nNumberOfAtoms < pAltInChI[iComponent + i].nNumberOfAtoms)
8453 : : {
8454 [ # # ]: 0 : if (pInChI[iComponent + i].nAtom)
8455 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
8456 [ # # ]: 0 : if (!(pInChI[iComponent + i].nAtom = (U_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nAtom[0]))))
8457 : : {
8458 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8459 : 0 : goto exit_function;
8460 : : }
8461 [ # # ]: 0 : if (len > 1)
8462 : : {
8463 : 0 : memcpy(pInChI[iComponent + i].nAtom, pAltInChI[iComponent + i].nAtom, ((long long)len - 1) * sizeof(pInChI[0].nAtom[0])); /* djb-rwth: cast operator added */
8464 : : }
8465 : : /* correct number of atoms including bridging H */
8466 : 0 : pInChI[iComponent + i].nNumberOfAtoms = pAltInChI[iComponent + i].nNumberOfAtoms;
8467 : : }
8468 : : }
8469 : : }
8470 : : }
8471 : :
8472 [ # # ]: 0 : if (*pbAbc == 1)
8473 : : {
8474 : : /* read numbers of H: XnYn... or XYn... */
8475 : 0 : p = pStart;
8476 : 0 : tg_alloc_len = 0;
8477 : 0 : num_H_component = num_taut_H_component = 0;
8478 [ # # ]: 0 : while (p < pTaut)
8479 : : {
8480 : : /* syntax check: atom number */
8481 [ # # # # ]: 0 : if (!*p || !isupper(UCINT* p))
8482 : : {
8483 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8484 : 0 : goto exit_function;
8485 : : }
8486 [ # # ]: 0 : if ((curAtom = nxtAtom = (int)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
8487 : : {
8488 : 0 : p = q;
8489 [ # # ]: 0 : if (isupper(UCINT* p))
8490 : : {
8491 : 0 : nxtAtom = (int)inchi_strtol(p, &q, base);
8492 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8493 [ # # # # ]: 0 : if (nxtAtom > MAX_ATOMS || nxtAtom < 0)
8494 : : {
8495 : 0 : ret = RI_ERR_SYNTAX;
8496 : 0 : goto exit_function;
8497 : : }
8498 : : #endif
8499 : 0 : p = q;
8500 : : }
8501 : : }
8502 [ # # # # : 0 : if (curAtom > nxtAtom || nxtAtom > numCtAtoms || p > pTaut)
# # ]
8503 : : {
8504 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8505 : 0 : goto exit_function;
8506 : : }
8507 : : /* number of H, may be negative */
8508 [ # # # # ]: 0 : if (!(num_H = (int)inchi_strtol(p, &q, 10)) || q > pTaut)
8509 : : {
8510 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8511 : 0 : goto exit_function;
8512 : : }
8513 : 0 : p = q;
8514 : : /* set number of H */
8515 : : /* djb-rwth: fixing oss-fuzz issue #38399 */
8516 [ # # # # : 0 : if (((bMobileH == TAUT_YES) && pInChI[iComponent].nNum_H) || ((bMobileH != TAUT_YES) && pInChI[iComponent].nNum_H_fixed))
# # # # ]
8517 : : {
8518 [ # # ]: 0 : for (i = curAtom; i <= nxtAtom; i++)
8519 : : {
8520 [ # # ]: 0 : nNum_H(iComponent)[i - 1] = num_H;
8521 : 0 : num_H_component += num_H;
8522 : : }
8523 : : }
8524 : : }
8525 [ # # ]: 0 : if (p != pTaut)
8526 : : {
8527 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8528 : 0 : goto exit_function;
8529 : : }
8530 : : }
8531 : : else
8532 : : {
8533 : : /* read numbers of H: 1-2,3H2,4,5H3 */
8534 : 0 : p = pStart;
8535 : 0 : tg_alloc_len = 0;
8536 : 0 : num_H_component = num_taut_H_component = 0;
8537 : : #if ( FIX_GAF_2019_1==1 )
8538 : : {
8539 : : char invalid;
8540 : 0 : const char* str1 = str + 1;
8541 [ # # ]: 0 : if (bMobileH == TAUT_NON) /* FixedH layer "/h"*/
8542 : : {
8543 : 0 : invalid = str1[strspn(str1, "0123456789hDHT-,;()*")];
8544 : : }
8545 : : else /* Main layer (mobileH) "/h"*/
8546 : : {
8547 : 0 : invalid = str1[strspn(str1, "0123456789DHT-,;()*")];
8548 : : }
8549 [ # # ]: 0 : if (invalid != '\0')
8550 : : {
8551 : 0 : ret = RI_ERR_SYNTAX;
8552 : 0 : goto exit_function;
8553 : : }
8554 : : }
8555 : : #endif
8556 [ # # ]: 0 : while (p < pTaut)
8557 : : {
8558 : : /* syntax check: atom number */
8559 [ # # # # ]: 0 : if (!*p || !isdigit(UCINT* p))
8560 : : {
8561 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8562 : 0 : goto exit_function;
8563 : : }
8564 : : /* number of H */
8565 : 0 : h = p + strcspn(p, "Hh");
8566 : : /*h = strchr( p, 'H' );*/
8567 [ # # # # ]: 0 : if (!*h || h >= pTaut)
8568 : : {
8569 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8570 : 0 : goto exit_function;
8571 : : /*
8572 : : p = pTaut;
8573 : : h = NULL;
8574 : : break; */ /* no more H found */
8575 : : }
8576 [ # # # # ]: 0 : num_H = (*h == 'H') ? 1 : (*h == 'h') ? -1 : 0;
8577 [ # # ]: 0 : if (!num_H)
8578 : : {
8579 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8580 : 0 : goto exit_function;
8581 : : }
8582 [ # # # # ]: 0 : if (h[1] && isdigit(UCINT h[1]))
8583 : : {
8584 : 0 : num_H *= (int)inchi_strtol(h + 1, &p1, 10);
8585 : : }
8586 : : else
8587 : : {
8588 : 0 : p1 = h + 1; /* next set of immobile H */
8589 : : }
8590 [ # # ]: 0 : if (*p1 == ',')
8591 : : {
8592 : 0 : p1++; /* next H-subsegment; otherwise (H or ; or end of the segment */
8593 : : }
8594 : : /* list of atoms that have num_H */
8595 [ # # ]: 0 : while (p < h)
8596 : : {
8597 [ # # # # ]: 0 : if (!*p || !isdigit(UCINT* p))
8598 : : {
8599 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8600 : 0 : goto exit_function;
8601 : : }
8602 : 0 : nxtAtom = curAtom = (int)inchi_strtol(p, &q, 10);
8603 [ # # ]: 0 : if (*q == '-')
8604 : : {
8605 : 0 : nxtAtom = (int)inchi_strtol(q + 1, &q, 10);
8606 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8607 [ # # # # ]: 0 : if (nxtAtom > MAX_ATOMS || nxtAtom < 0)
8608 : : {
8609 : 0 : ret = RI_ERR_SYNTAX;
8610 : 0 : goto exit_function;
8611 : : }
8612 : : #endif
8613 : : }
8614 : : /* consitency check */
8615 [ # # # # : 0 : if (!curAtom || curAtom > numCtAtoms ||
# # ]
8616 [ # # ]: 0 : nxtAtom < curAtom || nxtAtom > numCtAtoms)
8617 : : {
8618 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8619 : 0 : goto exit_function;
8620 : : }
8621 : : /* set number of H */
8622 : : /* djb-rwth: fixing oss-fuzz issue #38399 */
8623 [ # # # # : 0 : if (((bMobileH == TAUT_YES) && pInChI[iComponent].nNum_H) || ((bMobileH != TAUT_YES) && pInChI[iComponent].nNum_H_fixed))
# # # # ]
8624 : : {
8625 [ # # ]: 0 : for (i = curAtom; i <= nxtAtom; i++)
8626 : : {
8627 [ # # ]: 0 : nNum_H(iComponent)[i - 1] = num_H;
8628 : 0 : num_H_component += num_H;
8629 : : }
8630 : : }
8631 : : /* move to the next atom number if any */
8632 : 0 : p = q;
8633 [ # # ]: 0 : if (*p == ',')
8634 : : {
8635 : 0 : p++;
8636 : : }
8637 : : }
8638 : :
8639 [ # # ]: 0 : if (p == h)
8640 : : {
8641 : 0 : p = p1;
8642 : : }
8643 : : else
8644 : : {
8645 [ # # ]: 0 : if (p == pTaut)
8646 : : {
8647 : 0 : break;
8648 : : }
8649 : : else
8650 : : {
8651 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8652 : 0 : goto exit_function;
8653 : : }
8654 : : }
8655 : : }
8656 : : }
8657 : :
8658 : : INCHI_HEAPCHK
8659 : : /* ) -> (, H, N, [-, N,], AtNum,... AtNum) */
8660 : 0 : lenTautomer = 0;
8661 [ # # ]: 0 : if ((p = t)) /* djb-rwth: addressing LLVM warning */
8662 : : {
8663 [ # # ]: 0 : if (*pbAbc == 1)
8664 : : {
8665 : : /* tautomeric groups: pass 1 */
8666 : 0 : iTGroup = 0;
8667 : 0 : state = ')'; /* init as if the prev. t-group just ended */ /* djb-rwth: ignoring LLVM warning: value used */
8668 : 0 : num_Atoms = 0;
8669 : : /* Tautomeric info storage */
8670 : : /* NumGroups; ((NumAt+2, NumH, Num(-), At1..AtNumAt),...); {INCHI_T_NUM_MOVABLE = 2} */
8671 : : /* Allocated length: [5*nNumberOfAtoms/2+1], see Alloc_INChI(...) */
8672 [ # # ]: 0 : if (*p == ',')
8673 : : { /* start t-group */
8674 : 0 : p++;
8675 : : }
8676 : : else
8677 : : {
8678 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8679 : 0 : goto exit_function;
8680 : : }
8681 [ # # ]: 0 : while (p < pEnd)
8682 : : {
8683 : : /* start t-group */
8684 [ # # # # : 0 : if (!isdigit(UCINT* p) || !(num_H = (int)inchi_strtol(p, &q, 10)) || q > pEnd)
# # ]
8685 : : {
8686 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8687 : 0 : goto exit_function;
8688 : : }
8689 : 0 : p = q;
8690 : 0 : num_Minus = 0;
8691 [ # # ]: 0 : if (*p == '-')
8692 : : {
8693 : 0 : p++;
8694 [ # # ]: 0 : if (isdigit(UCINT* p))
8695 : : {
8696 : 0 : num_Minus = (int)inchi_strtol(p, &q, 10);
8697 : 0 : p = q;
8698 : : }
8699 : : else
8700 : : {
8701 : 0 : num_Minus = 1;
8702 : : }
8703 : : }
8704 [ # # ]: 0 : if (p >= pEnd)
8705 : : {
8706 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8707 : 0 : goto exit_function;
8708 : : }
8709 [ # # ]: 0 : if (!tg_alloc_len)
8710 : : {
8711 : : /*
8712 : : --- header ---
8713 : : [num_t_groups]
8714 : : --- one t-group: ---
8715 : : [len=group length no including this value]
8716 : : [num_H]
8717 : : [num_(-)]
8718 : : [Endpoint(1),...,Endpoint(len-2)]
8719 : : --- next t-group ---
8720 : : ...
8721 : :
8722 : : Max. size = 1 + 3*max_num_t_groups + max_num_endpoints
8723 : :
8724 : : max_num_t_groups = num_at/2
8725 : : max_num_endpoints = num_at
8726 : :
8727 : : Max. size = 1 + 3*(num_at/2) + num_at = 1 + (5*num_at)/2
8728 : : 5 = 3 + INCHI_T_NUM_MOVABLE = 3 + num_types_of_attachments
8729 : :
8730 : : This does not include zero termination!
8731 : :
8732 : : */
8733 : 0 : tg_alloc_len = ((3 + INCHI_T_NUM_MOVABLE) * pInChI[iComponent].nNumberOfAtoms) / 2 + 1;
8734 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
8735 : : {
8736 : 0 : pInChI[iComponent + i].nTautomer = (AT_NUMB*)inchi_calloc((long long)tg_alloc_len + 1, sizeof(pInChI->nTautomer[0])); /* djb-rwth: cast operator added */
8737 [ # # ]: 0 : if (!pInChI[iComponent + i].nTautomer)
8738 : : {
8739 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8740 : 0 : goto exit_function;
8741 : : }
8742 : 0 : pInChI[iComponent + i].lenTautomer = 0;
8743 : : }
8744 : 0 : tg_pos_Tautomer = 1; /* number atoms (NumAt+2) position */
8745 : : }
8746 : : else
8747 : : {
8748 : : /* next t-group */
8749 : 0 : tg_pos_Tautomer = lenTautomer;
8750 : : }
8751 [ # # ]: 0 : if (tg_pos_Tautomer + 3 >= tg_alloc_len)
8752 : : {
8753 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8754 : 0 : goto exit_function;
8755 : : }
8756 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 1] = num_H;
8757 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 2] = num_Minus;
8758 : 0 : lenTautomer = tg_pos_Tautomer + 3; /* first atom number position */
8759 : 0 : num_taut_H_component += num_H;
8760 : :
8761 [ # # # # ]: 0 : while (p < pEnd && isupper(UCINT* p))
8762 : : {
8763 : : /* read list of tautomeric atoms */
8764 : 0 : val = (int)inchi_strtol(p, &q, base);
8765 [ # # # # ]: 0 : if (lenTautomer >= tg_alloc_len || val > numCtAtoms)
8766 : : {
8767 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8768 : 0 : goto exit_function;
8769 : : }
8770 : 0 : num_Atoms++;
8771 : 0 : pInChI[iComponent].nTautomer[lenTautomer++] = val;
8772 : 0 : p = q;
8773 : : }
8774 [ # # # # : 0 : if (!num_Atoms || (p < pEnd && !isdigit(UCINT * p))) /* djb-rwth: addressing LLVM warning */
# # ]
8775 : : {
8776 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8777 : 0 : goto exit_function;
8778 : : }
8779 : 0 : iTGroup++;
8780 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer] = lenTautomer - tg_pos_Tautomer - 1; /* length of the rest of the t-group */
8781 : 0 : pInChI[iComponent].lenTautomer = lenTautomer;
8782 : : }
8783 [ # # # # ]: 0 : if (!iTGroup || p != pEnd)
8784 : : {
8785 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8786 : 0 : goto exit_function;
8787 : : }
8788 : 0 : pInChI[iComponent].nTautomer[0] = iTGroup;
8789 : : }
8790 : : else
8791 : : {
8792 : : /* tautomeric groups: pass 1 */
8793 : 0 : iTGroup = 0;
8794 : 0 : state = ')'; /* init as if the prev. t-group just ended */
8795 : 0 : num_Atoms = 0;
8796 : : /* Tautomeric info storage */
8797 : : /* NumGroups; ((NumAt+2, NumH, Num(-), At1..AtNumAt),...); {INCHI_T_NUM_MOVABLE = 2} */
8798 : : /* Allocated length: [5*nNumberOfAtoms/2+1], see Alloc_INChI(...) */
8799 [ # # ]: 0 : while (p < pEnd)
8800 : : {
8801 : : /* t-group */
8802 [ # # # # : 0 : switch (*p)
# # ]
8803 : : {
8804 : 0 : case '(': /* start t-group */
8805 [ # # ]: 0 : switch (state)
8806 : : {
8807 : 0 : case ')':
8808 : 0 : state = *p++;
8809 : 0 : num_H = 0;
8810 : 0 : num_Minus = 0;
8811 : 0 : continue;
8812 : 0 : default:
8813 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8814 : 0 : goto exit_function;
8815 : : }
8816 : 0 : case ')': /* end t-group */
8817 [ # # ]: 0 : switch (state)
8818 : : {
8819 : 0 : case 'A': /* previuos was atom number */
8820 [ # # ]: 0 : if (!tg_alloc_len)
8821 : : {
8822 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8823 : 0 : goto exit_function;
8824 : : }
8825 : 0 : iTGroup++;
8826 : 0 : state = *p++;
8827 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer] = lenTautomer - tg_pos_Tautomer - 1; /* length of the rest of the t-group */
8828 : 0 : pInChI[iComponent].lenTautomer = lenTautomer;
8829 : 0 : continue;
8830 : 0 : default:
8831 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8832 : 0 : goto exit_function;
8833 : : }
8834 : 0 : case 'H': /* number of H */
8835 [ # # ]: 0 : switch (state)
8836 : : {
8837 : 0 : case '(':
8838 : 0 : state = *p++;
8839 : 0 : num_H = 1;
8840 : 0 : continue;
8841 : 0 : default:
8842 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8843 : 0 : goto exit_function;
8844 : : }
8845 : 0 : case '-': /* number of (-) */
8846 [ # # ]: 0 : switch (state)
8847 : : {
8848 : 0 : case 'N': /* previous was number of H */
8849 : : case 'H': /* previous was H */
8850 : 0 : state = *p++;
8851 : 0 : num_Minus = 1;
8852 : 0 : continue;
8853 : 0 : default:
8854 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8855 : 0 : goto exit_function;
8856 : : }
8857 : 0 : case ',':
8858 [ # # # ]: 0 : switch (state)
8859 : : {
8860 : 0 : case 'N': /* previous was number of H */
8861 : : case 'H': /* previous was H */
8862 : : case '-': /* previuos was - */
8863 : : case 'M': /* previous was number of (-) */
8864 : : /* the next must be the first tautomeric atom number; save num_H & num_Minus */
8865 [ # # # # ]: 0 : if (num_H <= 0 && num_Minus <= 0)
8866 : : {
8867 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8868 : 0 : goto exit_function;
8869 : : }
8870 [ # # ]: 0 : if (!tg_alloc_len)
8871 : : {
8872 : : /*
8873 : : --- header ---
8874 : : [num_t_groups]
8875 : : --- one t-group: ---
8876 : : [len=group length no including this value]
8877 : : [num_H]
8878 : : [num_(-)]
8879 : : [Endpoint(1),...,Endpoint(len-2)]
8880 : : --- next t-group ---
8881 : : ...
8882 : :
8883 : : Max. size = 1 + 3*max_num_t_groups + max_num_endpoints
8884 : :
8885 : : max_num_t_groups = num_at/2
8886 : : max_num_endpoints = num_at
8887 : :
8888 : : Max. size = 1 + 3*(num_at/2) + num_at = 1 + (5*num_at)/2
8889 : : 5 = 3 + INCHI_T_NUM_MOVABLE = 3 + num_types_of_attachments
8890 : :
8891 : : This does not include zero termination!
8892 : :
8893 : : */
8894 : 0 : tg_alloc_len = ((3 + INCHI_T_NUM_MOVABLE) * pInChI[iComponent].nNumberOfAtoms) / 2 + 1;
8895 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
8896 : : {
8897 : : /* djb-rwth: fixing oss-fuzz issue #68314 */
8898 : 0 : AT_NUMB* pinchi_icint = (AT_NUMB*)inchi_calloc((long long)tg_alloc_len + 1, sizeof(pInChI->nTautomer[0])); /* djb-rwth: cast operator added */
8899 [ # # ]: 0 : if (!pinchi_icint)
8900 : : {
8901 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8902 : 0 : goto exit_function;
8903 : : }
8904 : 0 : pInChI[iComponent + i].nTautomer = pinchi_icint;
8905 : 0 : pInChI[iComponent + i].lenTautomer = 0;
8906 : : }
8907 : 0 : tg_pos_Tautomer = 1; /* number atoms (NumAt+2) position */
8908 : : }
8909 : : else
8910 : : {
8911 : : /* next t-group */
8912 : 0 : tg_pos_Tautomer = lenTautomer;
8913 : : }
8914 [ # # ]: 0 : if (tg_pos_Tautomer + 3 >= tg_alloc_len)
8915 : : {
8916 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8917 : 0 : goto exit_function;
8918 : : }
8919 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 1] = num_H;
8920 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 2] = num_Minus;
8921 : 0 : lenTautomer = tg_pos_Tautomer + 3; /* first atom number position */
8922 : : /* djb-rwth: fixing GH issue #59.1 */
8923 : : if (num_H >= INT_MIN && num_H <= INT_MAX) /* djb-rwth: addressing coverity ID #499582 -- boundary check is required */
8924 : : {
8925 : 0 : num_taut_H_component += num_H;
8926 : : }
8927 : : else
8928 : : {
8929 : : ret = BNS_PROGRAM_ERR;
8930 : : goto exit_function;
8931 : : }
8932 : 0 : state = *p++;
8933 : 0 : continue;
8934 : 0 : case 'A':
8935 : : /* previuos was atom number */
8936 : 0 : state = *p++;
8937 : 0 : continue;
8938 : 0 : default:
8939 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8940 : 0 : goto exit_function;
8941 : : }
8942 : 0 : default:
8943 [ # # ]: 0 : if (isdigit(UCINT* p))
8944 : : {
8945 : 0 : val = (int)inchi_strtol(p, &q, 10);
8946 [ # # ]: 0 : if (val <= 0)
8947 : : {
8948 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8949 : 0 : goto exit_function;
8950 : : }
8951 : 0 : p = q;
8952 [ # # # # ]: 0 : switch (state)
8953 : : {
8954 : 0 : case 'H':
8955 : 0 : num_H = val;
8956 : 0 : state = 'N';
8957 : 0 : continue;
8958 : 0 : case '-':
8959 : 0 : num_Minus = val;
8960 : 0 : state = 'M';
8961 : 0 : continue;
8962 : 0 : case ',':
8963 [ # # # # ]: 0 : if (lenTautomer >= tg_alloc_len || val > numCtAtoms)
8964 : : {
8965 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8966 : 0 : goto exit_function;
8967 : : }
8968 : 0 : num_Atoms++;
8969 : 0 : pInChI[iComponent].nTautomer[lenTautomer++] = val;
8970 : 0 : state = 'A';
8971 : 0 : continue;
8972 : 0 : default:
8973 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8974 : 0 : goto exit_function;
8975 : : }
8976 : : }
8977 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8978 : 0 : goto exit_function;
8979 : : }
8980 : : }
8981 [ # # # # ]: 0 : if (!iTGroup || state != ')')
8982 : : {
8983 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8984 : 0 : goto exit_function;
8985 : : }
8986 : 0 : pInChI[iComponent].nTautomer[0] = iTGroup;
8987 : : }
8988 : : }
8989 : : /* check num_H in components; for bMobileH=TAUT_NON, pInChI->nNum_H_fixed[] has not been added to pInChI->nNum_H[] yet */
8990 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI + iComponent, &num_H_formula)) ||
8991 : 0 : 0 > (ret2 = GetInChINumH(pInChI + iComponent, &num_H_InChI)))
8992 : : {
8993 : 0 : ret = ret2;
8994 : 0 : goto exit_function;
8995 : : }
8996 [ # # # # ]: 0 : if (num_H_formula != num_H_InChI + (bMobileH == TAUT_NON ? num_H_component : 0))
8997 : : {
8998 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8999 : 0 : goto exit_function;
9000 : : }
9001 : :
9002 : : /* duplicate according to multiplication */
9003 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
9004 : : {
9005 : : #if ( FIX_GAF_2019_2==1 )
9006 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
9007 : : {
9008 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9009 : 0 : goto exit_function;
9010 : : }
9011 : :
9012 [ # # # # ]: 0 : if ((pInChI[iComponent + i].nNumberOfAtoms <= 0) || (pInChI[iComponent + i].nNumberOfAtoms > MAX_ATOMS))
9013 : : {
9014 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9015 : 0 : goto exit_function;
9016 : : }
9017 : : #endif
9018 : : /* djb-rwth: fixing oss-fuzz issue #69699 */
9019 [ # # # # ]: 0 : if (nNum_H(iComponent)) /* djb-rwth: fixing GH issues #27/#28 */
9020 : : {
9021 [ # # # # ]: 0 : memcpy(nNum_H(iComponent + i), nNum_H(iComponent), pInChI[iComponent + i].nNumberOfAtoms * sizeof(nNum_H(0)[0]));
9022 : : }
9023 : : /*
9024 : : memcpy( pInChI[iComponent+i].nNum_H, pInChI[iComponent].nNum_H,
9025 : : pInChI[iComponent+i].nNumberOfAtoms * sizeof(pInChI[0].nNum_H[0]) );
9026 : : */
9027 [ # # # # : 0 : if (pInChI[iComponent + i].nTautomer && pInChI[iComponent].nTautomer && pInChI[iComponent].lenTautomer)
# # ]
9028 : : {
9029 : 0 : memcpy(pInChI[iComponent + i].nTautomer, pInChI[iComponent].nTautomer,
9030 : 0 : pInChI[iComponent].lenTautomer * sizeof(pInChI[0].nTautomer[0]));
9031 : 0 : pInChI[iComponent + i].lenTautomer = pInChI[iComponent].lenTautomer;
9032 : : }
9033 : : /* check num_H in components */
9034 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI + iComponent + i, &num_H_formula)) ||
9035 : 0 : 0 > (ret2 = GetInChINumH(pInChI + iComponent + i, &num_H_InChI)))
9036 : : {
9037 : 0 : ret = ret2;
9038 : 0 : goto exit_function;
9039 : : }
9040 [ # # # # ]: 0 : if (num_H_formula != num_H_InChI + (bMobileH == TAUT_NON ? num_H_component : 0))
9041 : : {
9042 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9043 : 0 : goto exit_function;
9044 : : }
9045 : : }
9046 : :
9047 : : /* prepare for the next component */
9048 : 0 : iComponent += i;
9049 [ # # ]: 0 : if (*pEnd)
9050 : : {
9051 : : #if (FIX_DALKE_BUGS == 1)
9052 : : /* prevent crash on extra trailing ';' */
9053 [ # # ]: 0 : if (iComponent >= nNumComponents)
9054 : : {
9055 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: extra component */
9056 : 0 : goto exit_function;
9057 : : }
9058 : : #endif
9059 : 0 : pStart = pEnd + 1;
9060 : : }
9061 : : else
9062 : : {
9063 : 0 : break;
9064 : : }
9065 : : }
9066 : :
9067 [ # # ]: 0 : if (nNumComponents != iComponent)
9068 : : {
9069 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9070 : 0 : goto exit_function;
9071 : : }
9072 : 0 : ret = iComponent + 1;
9073 : :
9074 : 0 : exit_function:
9075 : : INCHI_HEAPCHK
9076 : :
9077 : 0 : return ret;
9078 : : }
9079 : :
9080 : :
9081 : : /****************************************************************************
9082 : : Parse "/c" InChI layer
9083 : : ****************************************************************************/
9084 : 0 : int ParseSegmentConnections(const char* str,
9085 : : int bMobileH,
9086 : : INChI** pInpInChI,
9087 : : int* pnNumComponents,
9088 : : int* pbAbc,
9089 : : int* nb_total)
9090 : : {
9091 : : #define LAST_AT_LEN 256
9092 : : /* Pass 1: count bonds and find actual numbers of atom */
9093 : : int i, j, k, m, c, mpy_component;
9094 : : int nNumComponents, iComponent, nNumAtoms, nNumBonds, lenConnTable; /* djb-rwth: removing redundant variables */
9095 : : const char* p, * q, * pStart, * pEnd;
9096 : : AT_NUMB last_atom[LAST_AT_LEN], curAtom, maxAtom;
9097 : : int num_open, state, ret, base;
9098 : 0 : INChI* pInChI = *pInpInChI;
9099 : : LINKED_BONDS LB;
9100 : 0 : LINKED_BONDS* pLB = &LB; /* a list of linked lists of bonds, for each atom */
9101 : : AT_NUMB neighbor[MAXVAL];
9102 : 0 : int bPrevVersion = -1;
9103 : :
9104 : 0 : *nb_total = 0;
9105 : 0 : iComponent = 0;
9106 : 0 : LB.pBond = NULL; /* djb-rwth: initialization required to avoid garbage values */
9107 [ # # ]: 0 : if (str[0] != 'c')
9108 : : {
9109 [ # # # # ]: 0 : if (!pInChI && !*pnNumComponents)
9110 : 0 : {
9111 : 0 : int lenFormula = 1;
9112 : : /* component has no formula; allocate InChI */
9113 : 0 : lenConnTable = 0;
9114 : 0 : nNumComponents = 1;
9115 : : /* allocate InChI */
9116 [ # # ]: 0 : if (!(pInChI = *pInpInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))
9117 : : {
9118 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9119 : : }
9120 : : /* allocate empty formula */
9121 : 0 : pInChI[iComponent].szHillFormula = (char*)inchi_calloc((long long)lenFormula + 1, sizeof(pInChI[0].szHillFormula[0])); /* djb-rwth: cast operator added */
9122 [ # # ]: 0 : if (!pInChI[iComponent].szHillFormula)
9123 : : {
9124 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9125 : 0 : goto exit_function;
9126 : : }
9127 : : /* allocate empty connection table */
9128 : 0 : pInChI[iComponent].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9129 [ # # ]: 0 : if (!pInChI[iComponent].nConnTable)
9130 : : {
9131 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9132 : 0 : goto exit_function;
9133 : : }
9134 : 0 : pInChI[iComponent].lenConnTable = lenConnTable;
9135 : 0 : *pnNumComponents = nNumComponents;
9136 : : }
9137 : : else
9138 : : {
9139 : 0 : lenConnTable = 1;
9140 : 0 : nNumComponents = *pnNumComponents;
9141 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
9142 : : {
9143 : : /* allocate 1 atom connection table */
9144 [ # # ]: 0 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
9145 : : {
9146 [ # # ]: 0 : if (pInChI[i].nConnTable)
9147 : : {
9148 [ # # ]: 0 : inchi_free(pInChI[i].nConnTable);
9149 : : }
9150 : 0 : pInChI[i].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9151 [ # # ]: 0 : if (!pInChI[i].nConnTable)
9152 : : {
9153 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9154 : 0 : goto exit_function;
9155 : : }
9156 : 0 : pInChI[i].nConnTable[0] = 1;
9157 : 0 : pInChI[i].lenConnTable = lenConnTable;
9158 : : }
9159 : : }
9160 : : }
9161 : 0 : return 0;
9162 : : }
9163 : :
9164 : : /* Pass 1. Re-Count atoms, count bonds */
9165 : :
9166 : 0 : pStart = (char*)str + 1;
9167 : 0 : nNumComponents = *pnNumComponents;
9168 : : #if (FIX_DALKE_BUGS == 1)
9169 : : /* prevent crash on too many components */
9170 [ # # ]: 0 : if (nNumComponents > MAX_ATOMS)
9171 : : {
9172 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: extra component */
9173 : 0 : goto exit_function;
9174 : : }
9175 : : #endif
9176 : 0 : memset(pLB, 0, sizeof(pLB[0])); /* djb-rwth: memset_s C11/Annex K variant? */
9177 : :
9178 : : while (1)
9179 : : {
9180 : : /* cycle over components */
9181 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
9182 : : {
9183 : 0 : pEnd = pStart + strlen(pStart);
9184 : : }
9185 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
9186 : : {
9187 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
9188 : : #if ( CHECK_STRTOL_ATNUMB==1 )
9189 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
9190 : : {
9191 : 0 : ret = RI_ERR_SYNTAX;
9192 : 0 : goto exit_function;
9193 : : }
9194 : : #endif
9195 [ # # ]: 0 : if (p != q
9196 : : #if (FIX_DALKE_BUGS == 1)
9197 [ # # ]: 0 : || !isdigit(UCINT * pStart)
9198 : : #endif
9199 : : )
9200 : : {
9201 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9202 : 0 : goto exit_function;
9203 : : }
9204 : 0 : p++;
9205 : : }
9206 : : else
9207 : : {
9208 : 0 : mpy_component = 1;
9209 : 0 : p = pStart;
9210 : : }
9211 : : #if (FIX_DALKE_BUGS == 1)
9212 [ # # ]: 0 : if (iComponent + mpy_component > MAX_ATOMS)
9213 : : {
9214 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9215 : 0 : goto exit_function;
9216 : : }
9217 : : #endif
9218 : 0 : pStart = p;
9219 : : /* Pass 1.1 parse a component */
9220 : 0 : num_open = 0;
9221 : 0 : memset(last_atom, 0, sizeof(last_atom)); /* djb-rwth: memset_s C11/Annex K variant? */
9222 : 0 : state = '\0'; /* initial state */
9223 : 0 : maxAtom = 0;
9224 : 0 : nNumBonds = 0;
9225 : : /* djb-rwth: removing redundant code */
9226 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
9227 : : {
9228 : : /* check if compressed InChI */
9229 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
9230 : : }
9231 [ # # ]: 0 : base = *pbAbc ? ALPHA_BASE : 10;
9232 : :
9233 [ # # ]: 0 : if (*pbAbc == 1)
9234 : : {
9235 : 0 : nNumAtoms = 1;
9236 [ # # ]: 0 : while (p < pEnd)
9237 : : {
9238 [ # # ]: 0 : if (*p == '-')
9239 : : {
9240 [ # # ]: 0 : if (bPrevVersion == -1)
9241 : : {
9242 : : /* previous InChI version */
9243 : 0 : bPrevVersion = 1;
9244 : : }
9245 : : else
9246 [ # # ]: 0 : if (bPrevVersion != 1)
9247 : : {
9248 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9249 : 0 : goto exit_function;
9250 : : }
9251 : 0 : nNumAtoms--;
9252 : 0 : p++;
9253 : : }
9254 [ # # ]: 0 : if (isdigit(UCINT * p))
9255 : : {
9256 [ # # ]: 0 : if (bPrevVersion == -1)
9257 : : {
9258 : : /* curreny InChI, version 1 */
9259 : 0 : bPrevVersion = 0;
9260 : : }
9261 : : else
9262 [ # # ]: 0 : if (bPrevVersion != 0)
9263 : : {
9264 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9265 : 0 : goto exit_function;
9266 : : }
9267 : 0 : nNumAtoms -= inchi_strtol(p, &p, 10); /* bypass digits */
9268 : : }
9269 [ # # # # ]: 0 : if (*p != '-' && (curAtom = (AT_NUMB)inchi_strtol(p, &q, base)))
9270 : : {
9271 : 0 : nNumAtoms++;
9272 : 0 : nNumBonds++;
9273 : 0 : p = q;
9274 [ # # ]: 0 : if (maxAtom < curAtom)
9275 : 0 : maxAtom = curAtom;
9276 : : }
9277 : : else
9278 : : {
9279 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9280 : 0 : goto exit_function;
9281 : : }
9282 : : }
9283 [ # # # # ]: 0 : if (maxAtom < nNumAtoms && nNumBonds)
9284 : : {
9285 : 0 : maxAtom = nNumAtoms;
9286 : : }
9287 : : }
9288 : : else
9289 : : {
9290 [ # # ]: 0 : while (p < pEnd)
9291 : : {
9292 : : /* atom number */
9293 : 0 : c = UCINT * p++;
9294 [ # # ]: 0 : switch (c)
9295 : : {
9296 : 0 : case '(':
9297 : : case ')':
9298 : : case ',':
9299 : : case '-':
9300 [ # # ]: 0 : if (state != 'N')
9301 : : {
9302 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9303 : 0 : goto exit_function;
9304 : : }
9305 : 0 : state = c;
9306 : 0 : num_open += (c == '(') - (c == ')');
9307 [ # # ]: 0 : if (num_open < 0)
9308 : : {
9309 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9310 : 0 : goto exit_function;
9311 : : }
9312 : 0 : break;
9313 : 0 : default:
9314 [ # # # # ]: 0 : if (isdigit(c) && (curAtom = (AT_NUMB)inchi_strtol(p - 1, &q, 10)))
9315 : : {
9316 : 0 : p = q;
9317 [ # # # ]: 0 : switch (state)
9318 : : {
9319 : 0 : case '(':
9320 : : case ')':
9321 : : case ',':
9322 : : case '-':
9323 : 0 : nNumBonds++;
9324 : 0 : case '\0':
9325 [ # # ]: 0 : if (maxAtom < curAtom)
9326 : 0 : maxAtom = curAtom;
9327 : 0 : state = 'N';
9328 : 0 : break;
9329 : 0 : default:
9330 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9331 : 0 : goto exit_function;
9332 : : }
9333 : : }
9334 : : else
9335 : : {
9336 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9337 : 0 : goto exit_function;
9338 : : }
9339 : 0 : break;
9340 : : }
9341 : : }
9342 [ # # ]: 0 : if (num_open)
9343 : : {
9344 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9345 : 0 : goto exit_function;
9346 : : /* syntax error: parentheses do not match */
9347 : : }
9348 : : }
9349 : 0 : (*nb_total) += nNumBonds;
9350 : :
9351 : : /* Save the results and allocate memory */
9352 : 0 : nNumAtoms = (int)maxAtom; /* 0 if empty connection table and no bonds present */
9353 : 0 : lenConnTable = nNumAtoms + nNumBonds;
9354 : :
9355 : : /* connection table format: At1[,Neigh11,Neigh12,...],At2[,Neigh21,Neigh22,...],AtN[NeighN1,NeighN2,...] */
9356 : : /* where AtK > NeighK1 > NeighK2,...; At(K) < At(K+1); the length = num.atoms + num.bonds */
9357 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
9358 : : {
9359 : : #if ( FIX_GAF_2019_2==1 )
9360 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
9361 : : {
9362 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9363 : 0 : goto exit_function;
9364 : : }
9365 [ # # # # ]: 0 : if (pInChI[iComponent + i].nNumberOfAtoms <= 0 || pInChI[iComponent + i].nNumberOfAtoms > MAX_ATOMS)
9366 : : {
9367 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9368 : 0 : goto exit_function;
9369 : : }
9370 : : #endif
9371 : : /* check number of atoms: the difference may be due to bridging H */
9372 [ # # ]: 0 : if ((j = pInChI[iComponent + i].nNumberOfAtoms) < nNumAtoms)
9373 : : {
9374 : : /* reallocate */
9375 : 0 : U_CHAR* nAtomTmp = (U_CHAR*)inchi_malloc((long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
9376 [ # # ]: 0 : if (!nAtomTmp)
9377 : : {
9378 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9379 : 0 : goto exit_function;
9380 : : }
9381 : 0 : memcpy(nAtomTmp, pInChI[iComponent + i].nAtom, sizeof(nAtomTmp[0]) * j);
9382 [ # # ]: 0 : while (j < nNumAtoms)
9383 : : {
9384 : 0 : nAtomTmp[j++] = EL_NUMBER_H; /* bridging H */
9385 : : }
9386 : 0 : nAtomTmp[j] = '\0';
9387 : : INCHI_HEAPCHK
9388 [ # # ]: 0 : if (pInChI[iComponent + i].nAtom)
9389 : : {
9390 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
9391 : : }
9392 : 0 : pInChI[iComponent + i].nAtom = nAtomTmp;
9393 : 0 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtoms;
9394 : : }
9395 : : else
9396 : : {
9397 [ # # # # : 0 : if (j > nNumAtoms && (lenConnTable || j != 1))
# # ]
9398 : : {
9399 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9400 : 0 : goto exit_function;
9401 : : }
9402 : : }
9403 : : /* allocate connection table */
9404 [ # # ]: 0 : if (pInChI[iComponent + i].nConnTable)
9405 : : {
9406 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nConnTable);
9407 : : }
9408 [ # # # # : 0 : if (!nNumAtoms && !nNumBonds && !lenConnTable)
# # ]
9409 : : {
9410 : 0 : lenConnTable = 1; /* one atom, no bonds */
9411 : : }
9412 : 0 : pInChI[iComponent + i].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9413 [ # # ]: 0 : if (!pInChI[iComponent + i].nConnTable)
9414 : : {
9415 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9416 : 0 : goto exit_function;
9417 : : }
9418 : 0 : pInChI[iComponent + i].lenConnTable = lenConnTable;
9419 : : }
9420 : :
9421 : : /* Pass 1.2 parse a component and extract the bonds */
9422 : 0 : num_open = 0;
9423 : 0 : memset(last_atom, 0, sizeof(last_atom)); /* djb-rwth: memset_s C11/Annex K variant? */
9424 : 0 : state = '\0'; /* initial state */
9425 : : /* djb-rwth: removing redundant code */
9426 : 0 : p = pStart;
9427 : 0 : pLB->len = 0;
9428 : :
9429 [ # # ]: 0 : if (*pbAbc == 1)
9430 : : {
9431 : : /* compressed */
9432 : : int num_neigh;
9433 : 0 : num_open = 0;
9434 : 0 : last_atom[num_open] = 2;
9435 [ # # ]: 0 : while (p < pEnd)
9436 : : {
9437 [ # # ]: 0 : if (last_atom[num_open] > maxAtom)
9438 : : {
9439 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9440 : 0 : goto exit_function;
9441 : : }
9442 [ # # ]: 0 : if (isupper(UCINT * p))
9443 : : {
9444 : 0 : curAtom = (AT_NUMB)inchi_strtol(p, &q, base);
9445 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9446 : : {
9447 : 0 : goto exit_function;
9448 : : }
9449 : 0 : p = q;
9450 [ # # ]: 0 : if (bPrevVersion == 1)
9451 : : {
9452 [ # # # # ]: 0 : while (p < pEnd && *p == '-')
9453 : : {
9454 : 0 : p++;
9455 [ # # ]: 0 : if ((curAtom = (AT_NUMB)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
9456 : : {
9457 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9458 : : {
9459 : 0 : goto exit_function;
9460 : : }
9461 : 0 : p = q;
9462 : : }
9463 : : else
9464 : : {
9465 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9466 : 0 : goto exit_function;
9467 : : }
9468 : : }
9469 : : }
9470 : : else
9471 : : {
9472 [ # # # # ]: 0 : if (bPrevVersion == 0 && isdigit(*p))
9473 : : {
9474 : 0 : num_neigh = (int)inchi_strtol(p, &q, 10);
9475 : 0 : p = q;
9476 [ # # # # ]: 0 : while (num_neigh-- && p < pEnd)
9477 : : {
9478 [ # # ]: 0 : if ((curAtom = (AT_NUMB)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
9479 : : {
9480 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9481 : : {
9482 : 0 : goto exit_function;
9483 : : }
9484 : 0 : p = q;
9485 : : }
9486 : : else
9487 : : {
9488 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9489 : 0 : goto exit_function;
9490 : : }
9491 : : }
9492 : : }
9493 : : }
9494 : 0 : last_atom[num_open]++;
9495 : : }
9496 : : else
9497 : : {
9498 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9499 : 0 : goto exit_function;
9500 : : }
9501 : : }
9502 : : }
9503 : : else
9504 : : {
9505 [ # # ]: 0 : while (p < pEnd)
9506 : : {
9507 : : /* each atom number except the first means a new bond */
9508 : 0 : c = UCINT * p++;
9509 [ # # ]: 0 : switch (c)
9510 : : {
9511 : 0 : case '(':
9512 : : case ')':
9513 : : case ',':
9514 : : case '-':
9515 [ # # ]: 0 : switch (state)
9516 : : {
9517 : 0 : case 'N':
9518 : 0 : state = c;
9519 : 0 : break;
9520 : 0 : default:
9521 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9522 : 0 : goto exit_function;
9523 : : }
9524 : 0 : break;
9525 : 0 : default:
9526 [ # # # # ]: 0 : if (isdigit(c) && (curAtom = (AT_NUMB)inchi_strtol(p - 1, &q, 10)))
9527 : : {
9528 : 0 : p = q;
9529 [ # # # # : 0 : switch (state)
# # ]
9530 : : {
9531 : 0 : case '\0':
9532 : 0 : last_atom[num_open] = curAtom;
9533 : 0 : state = 'N';
9534 : 0 : break;
9535 : 0 : case '(':
9536 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9537 : : {
9538 : 0 : goto exit_function;
9539 : : }
9540 [ # # ]: 0 : if (++num_open >= LAST_AT_LEN)
9541 : : {
9542 : 0 : ret = RI_ERR_PROGR; /* program error: buffer overflow */
9543 : 0 : goto exit_function;
9544 : : }
9545 : 0 : last_atom[num_open] = curAtom;
9546 : 0 : state = 'N';
9547 : 0 : break;
9548 : :
9549 : 0 : case ')':
9550 [ # # ]: 0 : if (!num_open)
9551 : : {
9552 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9553 : 0 : goto exit_function;
9554 : : }
9555 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[--num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9556 : : {
9557 : 0 : goto exit_function;
9558 : : }
9559 : 0 : last_atom[num_open] = curAtom;
9560 : 0 : state = 'N';
9561 : 0 : break;
9562 : :
9563 : 0 : case ',':
9564 [ # # ]: 0 : if (!num_open)
9565 : : {
9566 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9567 : 0 : goto exit_function;
9568 : : }
9569 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open - 1], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9570 : : {
9571 : 0 : goto exit_function;
9572 : : }
9573 : 0 : last_atom[num_open] = curAtom;
9574 : 0 : state = 'N';
9575 : 0 : break;
9576 : 0 : case '-':
9577 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9578 : : {
9579 : 0 : goto exit_function;
9580 : : }
9581 : 0 : last_atom[num_open] = curAtom;
9582 : 0 : state = 'N';
9583 : 0 : break;
9584 : 0 : default:
9585 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9586 : 0 : goto exit_function;
9587 : : }
9588 : : }
9589 : : else
9590 : : {
9591 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9592 : 0 : goto exit_function;
9593 : : }
9594 : 0 : break;
9595 : : }
9596 : : }
9597 : : }
9598 : :
9599 : : /* Store the bonds in connection table */
9600 [ # # ]: 0 : if (lenConnTable > 1)
9601 : : {
9602 [ # # ]: 0 : for (i = 0, m = 0; i < nNumAtoms; i++)
9603 : : {
9604 : 0 : k = 0;
9605 : :
9606 [ # # ]: 0 : if (!pLB->pBond)
9607 : : {
9608 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9609 : 0 : goto exit_function;
9610 : : }
9611 : :
9612 [ # # ]: 0 : if ((j = pLB->pBond[i + 1].prev)) /* djb-rwth: addressing LLVM warning */
9613 : : {
9614 [ # # ]: 0 : while (k < MAXVAL)
9615 : : {
9616 : 0 : neighbor[k++] = pLB->pBond[j].neigh;
9617 [ # # ]: 0 : if (j == i + 1)
9618 : 0 : break;
9619 : 0 : j = pLB->pBond[j].prev;
9620 : : }
9621 : : }
9622 [ # # ]: 0 : if (j != i + 1)
9623 : : {
9624 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9625 : 0 : goto exit_function;
9626 : : }
9627 : :
9628 : : /* sort the neighbors */
9629 : :
9630 : 0 : insertions_sort_AT_NUMB(neighbor, k);
9631 : :
9632 [ # # ]: 0 : if (m == pInChI[iComponent].lenConnTable)
9633 : : {
9634 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9635 : 0 : goto exit_function;
9636 : : }
9637 : :
9638 : : #if ( FIX_GAF_2020_25726==1 )
9639 [ # # ]: 0 : for (j = 1; j < k; j++)
9640 : : {
9641 [ # # ]: 0 : if (neighbor[j] == neighbor[j - 1])
9642 : : {
9643 : 0 : ret = RI_ERR_SYNTAX; /* syntax error - same nbr twice, i.e. multiple bond between same atoms */
9644 : 0 : goto exit_function;
9645 : : }
9646 : : }
9647 : : #endif
9648 : 0 : pInChI[iComponent].nConnTable[m++] = i + 1; /* atom number */
9649 [ # # # # ]: 0 : for (j = 0; j < k && (int)neighbor[j] <= i; j++)
9650 : : {
9651 [ # # ]: 0 : if (m == pInChI[iComponent].lenConnTable)
9652 : : {
9653 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9654 : 0 : goto exit_function;
9655 : : }
9656 : 0 : pInChI[iComponent].nConnTable[m++] = neighbor[j];
9657 : : }
9658 : : }
9659 [ # # ]: 0 : if (m != lenConnTable)
9660 : : {
9661 : 0 : ret = RI_ERR_PROGR; /* program error */
9662 : 0 : goto exit_function;
9663 : : }
9664 : : }
9665 : : else
9666 : : {
9667 : 0 : pInChI[iComponent].nConnTable[0] = 1; /* single atom */
9668 : : }
9669 : :
9670 : : /* Duplicate if needed */
9671 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
9672 : : {
9673 : : /*
9674 : : if ( pInChI[iComponent+i].nConnTable ) {
9675 : : inchi_free( pInChI[iComponent+i].nConnTable );
9676 : : }
9677 : : pInChI[iComponent+i].nConnTable = (AT_NUMB *)inchi_calloc( lenConnTable+1, sizeof(pInChI[0].nConnTable[0]) );
9678 : : if ( !pInChI[iComponent+i].nConnTable ) {
9679 : : ret = RI_ERR_ALLOC;
9680 : : goto exit_function;
9681 : : }
9682 : : */
9683 [ # # # # ]: 0 : if (!pInChI[iComponent + i].nConnTable || pInChI[iComponent + i].lenConnTable != lenConnTable)
9684 : : {
9685 : 0 : ret = RI_ERR_PROGR;
9686 : 0 : goto exit_function;
9687 : : }
9688 : 0 : memcpy(pInChI[iComponent + i].nConnTable, pInChI[iComponent].nConnTable, lenConnTable * sizeof(pInChI[0].nConnTable[0]));
9689 : : }
9690 : : /* prepare for the next connection table */
9691 : 0 : iComponent += i;
9692 [ # # ]: 0 : if (*pEnd)
9693 : 0 : pStart = pEnd + 1;
9694 : : else
9695 : 0 : break;
9696 : : /* We must check if we have already read as many components as we have in the fragment. */
9697 : : /* If yes, then we break, because anything else that might follow cannot be useful information. */
9698 : : /* There are files with a trailing ";" that would cause a problem (memory allocation bug) if we did not do this. */
9699 [ # # ]: 0 : if (iComponent == nNumComponents)
9700 : 0 : break;
9701 : : }
9702 : 0 : ret = iComponent;
9703 : :
9704 : 0 : exit_function:
9705 : :
9706 [ # # ]: 0 : if (pLB->pBond)
9707 : : {
9708 : : INCHI_HEAPCHK
9709 [ # # ]: 0 : inchi_free(pLB->pBond);
9710 : : }
9711 : :
9712 : 0 : return ret;
9713 : : #undef LAST_AT_LEN
9714 : : }
9715 : :
9716 : :
9717 : : /****************************************************************************/
9718 : 0 : int nFillOutProtonMobileH(INChI* pInChI)
9719 : : {
9720 : 0 : int len = 1;
9721 : 0 : pInChI->bDeleted = 1;
9722 : : /* formula */
9723 [ # # ]: 0 : if (!pInChI->szHillFormula &&
9724 [ # # ]: 0 : !(pInChI->szHillFormula = (char*)inchi_calloc((long long)len + 1, sizeof(pInChI->szHillFormula[0])))) /* djb-rwth: cast operator added */
9725 : : {
9726 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9727 : : }
9728 : 0 : strcpy(pInChI->szHillFormula, "H");
9729 : 0 : pInChI->nNumberOfAtoms = 1;
9730 : :
9731 : : /* atoms */
9732 [ # # ]: 0 : if (!pInChI->nAtom &&
9733 [ # # ]: 0 : !(pInChI->nAtom = (U_CHAR*)inchi_calloc((long long)len + 1, sizeof(pInChI->nAtom[0])))) /* djb-rwth: cast operator added */
9734 : : {
9735 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9736 : : }
9737 : 0 : pInChI->nAtom[0] = 1;
9738 : : /* charge */
9739 : 0 : pInChI->nTotalCharge = 1;
9740 : : /* connection table */
9741 [ # # ]: 0 : if (!pInChI->nConnTable &&
9742 [ # # ]: 0 : !(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
9743 : : {
9744 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9745 : : }
9746 : 0 : pInChI->nConnTable[0] = 1;
9747 : 0 : pInChI->lenConnTable = len;
9748 : : /* tautomer */
9749 [ # # ]: 0 : if (!pInChI->nTautomer &&
9750 [ # # ]: 0 : !(pInChI->nTautomer = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pInChI->nTautomer[0])))) /* djb-rwth: cast operator added */
9751 : : {
9752 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9753 : : }
9754 : : /* nNum_H */
9755 [ # # ]: 0 : if (!pInChI->nNum_H &&
9756 [ # # ]: 0 : !(pInChI->nNum_H = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pInChI->nNum_H[0])))) /* djb-rwth: cast operator added */
9757 : : {
9758 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9759 : : }
9760 : 0 : pInChI->nNum_H[0] = 0;
9761 : :
9762 : 0 : pInChI->nTautomer[0] = 0;
9763 : 0 : pInChI->lenTautomer = 1;
9764 : :
9765 : 0 : return 0;
9766 : : }
9767 : :
9768 : :
9769 : : /****************************************************************************/
9770 : 0 : int nProtonCopyIsotopicInfo(INChI* pInChI_to, INChI* pInChI_from)
9771 : : {
9772 [ # # ]: 0 : if (pInChI_from->nNumberOfIsotopicAtoms)
9773 : : {
9774 [ # # ]: 0 : if (pInChI_to->nNumberOfIsotopicAtoms &&
9775 [ # # ]: 0 : pInChI_from->nNumberOfIsotopicAtoms > pInChI_to->nNumberOfIsotopicAtoms)
9776 : : {
9777 : :
9778 [ # # ]: 0 : inchi_free(pInChI_to->IsotopicAtom);
9779 : 0 : pInChI_to->IsotopicAtom = NULL;
9780 : 0 : pInChI_to->nNumberOfIsotopicAtoms = 0;
9781 : : }
9782 [ # # ]: 0 : if (!pInChI_to->IsotopicAtom &&
9783 : 0 : !(pInChI_to->IsotopicAtom =
9784 [ # # ]: 0 : (INChI_IsotopicAtom*)inchi_calloc(pInChI_from->nNumberOfIsotopicAtoms,
9785 : : sizeof(pInChI_to->IsotopicAtom[0]))))
9786 : : {
9787 : 0 : return RI_ERR_ALLOC;
9788 : : }
9789 : 0 : pInChI_to->nNumberOfIsotopicAtoms = pInChI_from->nNumberOfIsotopicAtoms;
9790 : 0 : memcpy(pInChI_to->IsotopicAtom, pInChI_from->IsotopicAtom,
9791 : 0 : pInChI_from->nNumberOfIsotopicAtoms * sizeof(pInChI_to->IsotopicAtom[0]));
9792 : : }
9793 : : else
9794 : : {
9795 [ # # ]: 0 : if (pInChI_to->IsotopicAtom)
9796 : : {
9797 [ # # ]: 0 : inchi_free(pInChI_to->IsotopicAtom);
9798 : : }
9799 : 0 : pInChI_to->IsotopicAtom = NULL;
9800 : 0 : pInChI_to->nNumberOfIsotopicAtoms = 0;
9801 : : }
9802 : :
9803 : 0 : return 0;
9804 : : }
9805 : :
9806 : :
9807 : : /****************************************************************************
9808 : : Parse InChI formula layer
9809 : : ****************************************************************************/
9810 : 0 : int ParseSegmentFormula(const char* str,
9811 : : int bMobileH,
9812 : : INChI* pInpInChI[],
9813 : : int pnNumComponents[],
9814 : : int* na_total)
9815 : : {
9816 : : int i, j, mpy_component, mpy_atom, len, el_number;
9817 [ # # ]: 0 : int nNumComponents = 0, iComponent, nNumAtoms, nNumAtomsAndH, iAtom, nNumH, nAltMobileH = ALT_TAUT(bMobileH);
9818 : : const char* p, * q, * e, * pStart, * pEnd;
9819 : : INChI* pInChI;
9820 : : char szEl[3];
9821 : : #if ( FIX_GAF_2019_2==1 )
9822 : : /* hack: state passed in *na_total (will be updated in ParseSegmentFormula anyway) */
9823 : 0 : int state = *na_total;
9824 : : #endif
9825 : 0 : nNumAtoms = -999; /* impossible value */
9826 : 0 : *na_total = 0;
9827 : :
9828 : : /* Pass 1. Count components */
9829 : :
9830 : 0 : pStart = (char*)str;
9831 : : while (1)
9832 : : {
9833 [ # # ]: 0 : if (!(pEnd = strchr(pStart, '.')))
9834 : : {
9835 : 0 : pEnd = pStart + strlen(pStart);
9836 : : }
9837 : 0 : p = pStart;
9838 [ # # ]: 0 : if (isdigit(*p))
9839 : : {
9840 : 0 : mpy_component = (int)inchi_strtol(p, &q, 10);
9841 : 0 : p = q;
9842 : : }
9843 : : else
9844 : : {
9845 : 0 : mpy_component = 1;
9846 : : }
9847 [ # # ]: 0 : if (!mpy_component)
9848 : : {
9849 : 0 : break;
9850 : : }
9851 [ # # ]: 0 : if (!isupper(UCINT * p))
9852 : : {
9853 : 0 : break; /* not a formula layer */
9854 : : }
9855 [ # # ]: 0 : if (pEnd == p)
9856 : : {
9857 : 0 : break; /* zero length formula */
9858 : : }
9859 : 0 : nNumComponents += mpy_component;
9860 [ # # ]: 0 : if (*pEnd)
9861 : : {
9862 : 0 : pStart = pEnd + 1;
9863 : : }
9864 : : else
9865 : : {
9866 : 0 : break;
9867 : : }
9868 : : }
9869 : 0 : pnNumComponents[bMobileH] = nNumComponents;
9870 : : #if ( FIX_GAF_2019_1==1 )
9871 [ # # ]: 0 : if (nNumComponents > MAX_ATOMS)
9872 : : {
9873 : 0 : pnNumComponents[bMobileH] = 0;
9874 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9875 : : }
9876 : : /* pnNumComponents was not reset to 0 which results
9877 : : in attempt then to free() garbage at
9878 : : Free_INChI_Stereo ( <-- Free_INChI_Members <-- FreeInpInChI ) */
9879 : : #elif ( FIX_DALKE_BUGS == 1 )
9880 : : if (nNumComponents > MAX_ATOMS)
9881 : : {
9882 : : return RI_ERR_SYNTAX; /* syntax error */
9883 : : }
9884 : : #endif
9885 : : /* exit or error check */
9886 [ # # ]: 0 : if (!nNumComponents)
9887 : : {
9888 : : #if ( FIX_GAF_2019_2==1 )
9889 : 0 : int low_case = 0;
9890 [ # # ]: 0 : if (*pStart)
9891 : : {
9892 : 0 : low_case = islower(UCINT * pStart);
9893 : : }
9894 [ # # # # ]: 0 : if (!*pStart || low_case) {
9895 [ # # ]: 0 : if (low_case)
9896 : : {
9897 [ # # ]: 0 : if (state == IST_MOBILE_H_FORMULA)
9898 : : {
9899 [ # # # # ]: 0 : if (*pStart != 'q' && *pStart != 'p')
9900 : : {
9901 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9902 : : }
9903 : : }
9904 : : /*
9905 : : else if (state == IST_FIXED_H_FORMULA)
9906 : : {
9907 : : if (*pStart != 'h' && *pStart != 'i' && *pStart != 'b' && *pStart != 'q' && *pStart != 'p')
9908 : : {
9909 : : return RI_ERR_SYNTAX;
9910 : : }
9911 : : }*/
9912 : : }
9913 : : #else
9914 : : if (!*pStart || islower(UCINT * pStart)) {
9915 : : #endif
9916 : :
9917 : : INCHI_HEAPCHK
9918 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && 0 < (nNumComponents = pnNumComponents[nAltMobileH]))
9919 : : {
9920 : : /* allocate InChI */
9921 : 0 : pInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI));
9922 [ # # ]: 0 : if (!(pInChI))
9923 : : {
9924 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9925 : : }
9926 : 0 : pInpInChI[bMobileH] = pInChI;
9927 : 0 : pnNumComponents[bMobileH] = nNumComponents;
9928 : : /* djb-rwth: fixing oss-fuzz issue #66985, #66718 */
9929 : : /* U_CHAR** piibmi_na = (U_CHAR**)inchi_malloc(nNumComponents * sizeof(U_CHAR*));
9930 : : char** piibmi_shf = (char**)inchi_malloc(nNumComponents * sizeof(char*)); */
9931 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
9932 : : {
9933 : 0 : U_CHAR* piibmi_na = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
9934 : 0 : char* piibmi_shf = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
9935 : : /* copy number of atoms */
9936 : 0 : len = pInpInChI[bMobileH][i].nNumberOfAtoms = pInpInChI[nAltMobileH][i].nNumberOfAtoms;
9937 : : /* copy atoms */
9938 : 0 : len = (len + 1) * sizeof(pInpInChI[0][0].nAtom[0]);
9939 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nAtom)
9940 : : {
9941 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].nAtom);
9942 : : }
9943 : 0 : piibmi_na = (U_CHAR*)inchi_malloc(((long long)len + 1) * sizeof(pInpInChI[0][0].nAtom[0]));
9944 [ # # ]: 0 : if (piibmi_na) /* djb-rwth: cast operator added; addressing LLVM warning */
9945 : : {
9946 : 0 : memcpy(piibmi_na, pInpInChI[nAltMobileH][i].nAtom, len);
9947 : 0 : piibmi_na[len] = 0;
9948 : 0 : pInpInChI[bMobileH][i].nAtom = piibmi_na;
9949 : : }
9950 : : else
9951 : : {
9952 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9953 : : }
9954 : : /* copy Hill formula */
9955 : 0 : len = (int)strlen(pInpInChI[nAltMobileH][i].szHillFormula) + 1;
9956 [ # # ]: 0 : if (pInpInChI[bMobileH][i].szHillFormula)
9957 : : {
9958 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].szHillFormula);
9959 : : }
9960 : 0 : piibmi_shf = (char*)inchi_malloc((inchi_max(len, 2)) * sizeof(char));
9961 [ # # ]: 0 : if (piibmi_shf) /* djb-rwth: addressing LLVM warning */
9962 : : {
9963 : 0 : memcpy(piibmi_shf, pInpInChI[nAltMobileH][i].szHillFormula, len);
9964 : 0 : pInpInChI[bMobileH][i].szHillFormula = piibmi_shf;
9965 : : }
9966 : : else
9967 : : {
9968 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9969 : : }
9970 : : }
9971 : : }
9972 : : else
9973 : : {
9974 [ # # ]: 0 : if (bMobileH == TAUT_YES)
9975 : : {
9976 : : int ret;
9977 : : /* allocate InChI */
9978 : 0 : nNumComponents = 1;
9979 : : /* InChI */
9980 : 0 : pnNumComponents[bMobileH] = nNumComponents;
9981 [ # # ]: 0 : if (!(pInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))
9982 : : {
9983 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9984 : : }
9985 : 0 : pInpInChI[bMobileH] = pInChI;
9986 : 0 : ret = nFillOutProtonMobileH(pInChI);
9987 [ # # ]: 0 : if (ret < 0)
9988 : : {
9989 : 0 : return ret;
9990 : : }
9991 : : }
9992 : : }
9993 : 0 : return 0;
9994 : : }
9995 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9996 : : }
9997 : :
9998 [ # # ]: 0 : if (*pEnd)
9999 : : {
10000 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10001 : : }
10002 : :
10003 : : /* allocate InChI */
10004 [ # # ]: 0 : if (!((sizeof(INChI) > 0) && (pInpInChI[bMobileH] = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))) /* djb-rwth: fixing GH issue #58 */
10005 : : {
10006 : 0 : return RI_ERR_ALLOC; /* alloc failure */
10007 : : }
10008 : 0 : pInChI = pInpInChI[bMobileH];
10009 : :
10010 : : /* Pass 2. Count elements, save formulas and elements */
10011 : 0 : pStart = (char*)str;
10012 : 0 : iComponent = 0;
10013 : : while (1)
10014 : : {
10015 [ # # ]: 0 : if (!(pEnd = strchr(pStart, '.')))
10016 : : {
10017 : 0 : pEnd = pStart + strlen(pStart);
10018 : : }
10019 : 0 : p = pStart;
10020 [ # # ]: 0 : if (isdigit(UCINT * p))
10021 : : {
10022 : 0 : mpy_component = (int)inchi_strtol(p, &q, 10);
10023 : : #if ( CHECK_STRTOL_ATNUMB==1 )
10024 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
10025 : : {
10026 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10027 : : }
10028 : : #endif
10029 : 0 : p = q;
10030 : : }
10031 : : else
10032 : : {
10033 : 0 : mpy_component = 1;
10034 : : }
10035 : : #if ( FIX_DALKE_BUGS == 1 )
10036 [ # # ]: 0 : if (iComponent + mpy_component > MAX_ATOMS)
10037 : : {
10038 : : #if ( FIX_GAF_2019_1==1 )
10039 : 0 : nNumComponents = 0; /* djb-rwth: ignoring LLVM warning: value used */
10040 : : #endif
10041 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10042 : : }
10043 : : #endif
10044 : 0 : len = (int)(pEnd - p);
10045 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
10046 : : {
10047 [ # # ]: 0 : if (iComponent + i >= nNumComponents)
10048 : : {
10049 : 0 : return RI_ERR_SYNTAX;
10050 : : }
10051 [ # # ]: 0 : if (pInChI[iComponent + i].szHillFormula)
10052 : : {
10053 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].szHillFormula);
10054 : : }
10055 : 0 : pInChI[iComponent + i].szHillFormula = (char*)inchi_malloc(inchi_max((long long)len, 1) + 1); /* djb-rwth: cast operator added */
10056 [ # # ]: 0 : if (pInChI[iComponent + i].szHillFormula) /* djb-rwth: fixing a NULL pointer dereference */
10057 : : {
10058 : 0 : memcpy(pInChI[iComponent].szHillFormula, p, len);
10059 : 0 : pInChI[iComponent + i].szHillFormula[len] = '\0';
10060 : : }
10061 : : else
10062 : : {
10063 : 0 : return RI_ERR_ALLOC; /* djb-rwth: memory could not be allocated */
10064 : : }
10065 [ # # ]: 0 : if (!i)
10066 : : {
10067 : : /* Pass 2.1 Parse formula and count atoms except H */
10068 : 0 : nNumAtoms = 0;
10069 : 0 : nNumH = 0;
10070 : : /* djb-rwth: removing redundant code */
10071 : 0 : e = pInChI[iComponent].szHillFormula;
10072 [ # # # # ]: 0 : while (e && *e) /* djb-rwth: fixing a NULL pointer dereference */
10073 : : {
10074 [ # # ]: 0 : if (!isupper(UCINT * e))
10075 : : {
10076 : 0 : return RI_ERR_SYNTAX;
10077 : : }
10078 : 0 : j = 0;
10079 : 0 : szEl[j++] = *e++;
10080 [ # # # # ]: 0 : if (*e && islower(UCINT * e))
10081 : 0 : szEl[j++] = *e++;
10082 : 0 : szEl[j++] = '\0';
10083 [ # # # # ]: 0 : if (*e && isdigit(UCINT * e))
10084 : : {
10085 : 0 : mpy_atom = (int)inchi_strtol(e, &q, 10);
10086 : : #if ( CHECK_STRTOL_ATNUMB==1 )
10087 [ # # # # ]: 0 : if (mpy_atom > MAX_ATOMS || mpy_atom < 0)
10088 : : {
10089 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10090 : : }
10091 : : #endif
10092 : 0 : e = q;
10093 : : }
10094 : : else
10095 : : {
10096 : 0 : mpy_atom = 1;
10097 : : }
10098 [ # # ]: 0 : if (!mpy_atom)
10099 : : {
10100 : 0 : return RI_ERR_SYNTAX;
10101 : : }
10102 [ # # # # ]: 0 : if (szEl[0] == 'H' && !szEl[1])
10103 : : {
10104 : 0 : nNumH += mpy_atom;
10105 : 0 : continue; /* ignore H in counting number of atoms */
10106 : : }
10107 : 0 : nNumAtoms += mpy_atom;
10108 : : }
10109 : : #if ( FIX_DALKE_BUGS == 1 )
10110 [ # # ]: 0 : if (nNumAtoms > MAX_ATOMS)
10111 : : {
10112 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10113 : : }
10114 : : #endif
10115 : 0 : (*na_total) += mpy_component * nNumAtoms;
10116 : :
10117 [ # # ]: 0 : nNumAtomsAndH = nNumAtoms ? nNumAtoms : (nNumH > 0);
10118 : 0 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtomsAndH;
10119 [ # # ]: 0 : if (pInChI[iComponent + i].nAtom)
10120 : : {
10121 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
10122 : : }
10123 : 0 : pInChI[iComponent + i].nAtom = (U_CHAR*)inchi_malloc(((long long)nNumAtomsAndH + 1) * sizeof(pInChI[0].nAtom[0])); /* djb-rwth: cast operator added */
10124 [ # # ]: 0 : if (!pInChI[iComponent + i].nAtom)
10125 : : {
10126 : 0 : return RI_ERR_ALLOC; /* failed allocation */
10127 : : }
10128 : : /* Pass 2.2 Store elements; this assumes no bridging H. Bridging H will be found in connection table, /c */
10129 : 0 : iAtom = 0;
10130 [ # # ]: 0 : if (nNumAtoms > 0)
10131 : : {
10132 : 0 : e = pInChI[iComponent + i].szHillFormula;
10133 [ # # ]: 0 : while (*e)
10134 : : {
10135 [ # # ]: 0 : if (!isupper(UCINT * e))
10136 : : {
10137 : 0 : return RI_ERR_SYNTAX;
10138 : : }
10139 : 0 : j = 0;
10140 : 0 : szEl[j++] = *e++;
10141 [ # # # # ]: 0 : if (*e && islower(UCINT * e))
10142 : 0 : szEl[j++] = *e++;
10143 : 0 : szEl[j++] = '\0';
10144 [ # # # # ]: 0 : if (*e && isdigit(UCINT * e))
10145 : : {
10146 : 0 : mpy_atom = (int)inchi_strtol(e, &q, 10);
10147 : : #if ( CHECK_STRTOL_ATNUMB==1 )
10148 [ # # # # ]: 0 : if (mpy_atom > MAX_ATOMS || mpy_atom < 0)
10149 : : {
10150 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10151 : : }
10152 : : #endif
10153 : 0 : e = q;
10154 : : }
10155 : : else
10156 : : {
10157 : 0 : mpy_atom = 1;
10158 : : }
10159 [ # # ]: 0 : if (!mpy_atom)
10160 : : {
10161 : 0 : return RI_ERR_SYNTAX;
10162 : : }
10163 [ # # # # ]: 0 : if (szEl[0] == 'H' && !szEl[1])
10164 : 0 : continue; /* ignore H */
10165 : 0 : el_number = get_periodic_table_number(szEl);
10166 [ # # ]: 0 : if (el_number == ERR_ELEM)
10167 : : {
10168 : 0 : return RI_ERR_SYNTAX; /* wrong element */
10169 : : }
10170 [ # # ]: 0 : while (mpy_atom--)
10171 : : {
10172 [ # # ]: 0 : if (iAtom >= nNumAtoms)
10173 : : {
10174 : 0 : return RI_ERR_PROGR; /* program error */
10175 : : }
10176 : 0 : pInChI[iComponent + i].nAtom[iAtom++] = (U_CHAR)el_number;
10177 : : }
10178 : : }
10179 : : }
10180 : : else
10181 : : {
10182 [ # # ]: 0 : if (nNumH > 0)
10183 : : {
10184 : 0 : pInChI[iComponent + i].nAtom[iAtom++] = EL_NUMBER_H;
10185 : 0 : nNumAtoms = 1;
10186 : : }
10187 : : }
10188 : 0 : pInChI[iComponent + i].nAtom[iAtom] = '\0';
10189 [ # # ]: 0 : if (nNumAtoms != iAtom)
10190 : : {
10191 : 0 : return RI_ERR_PROGR; /* program error */
10192 : : }
10193 : : }
10194 : : else
10195 : : {
10196 : 0 : U_CHAR* pci1 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10197 : : /* Copy duplicated formula */
10198 : 0 : strcpy(pInChI[iComponent + i].szHillFormula, pInChI[iComponent].szHillFormula); /* djb-rwth: unresolved issue -- revision required? */
10199 : : /* Copy atoms in the duplicated formula */
10200 : 0 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtoms;
10201 : : /* djb-rwth: fixing oss-fuzz issue #43420, #34772 */
10202 : 0 : pci1 = (U_CHAR*)inchi_malloc((long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
10203 [ # # ]: 0 : if (!pci1)
10204 : : {
10205 : 0 : return RI_ERR_ALLOC; /* failed allocation */
10206 : : }
10207 : 0 : pInChI[iComponent + i].nAtom = pci1;
10208 : 0 : memcpy(pci1, pInChI[iComponent].nAtom, (long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
10209 : : }
10210 : : }
10211 : 0 : iComponent += i;
10212 [ # # ]: 0 : if (*pEnd)
10213 : : {
10214 [ # # ]: 0 : if (*pEnd != '.')
10215 : : {
10216 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10217 : : }
10218 : 0 : pStart = pEnd + 1;
10219 : : }
10220 : : else
10221 : : {
10222 : 0 : break;
10223 : : }
10224 : : }
10225 : :
10226 [ # # ]: 0 : if (iComponent != nNumComponents)
10227 : : {
10228 : 0 : return RI_ERR_PROGR; /* program error */
10229 : : }
10230 [ # # ]: 0 : if (bMobileH == TAUT_NON)
10231 : : {
10232 : : /* at this point the exact number of atoms including bridging H is known from TAUT_YES */
10233 [ # # # # ]: 0 : for (i = 0; i < nNumComponents && i < pnNumComponents[nAltMobileH]; i++)
10234 : : {
10235 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nNumberOfAtoms < (len = pInpInChI[nAltMobileH][i].nNumberOfAtoms))
10236 : : {
10237 : : /* there are bridging H in this component */
10238 [ # # ]: 0 : if (pInpInChI[nAltMobileH][i].nAtom)
10239 : : {
10240 : 0 : U_CHAR* nAtom = (U_CHAR*)inchi_malloc(((long long)len + 1) * sizeof(nAtom[0])); /* djb-rwth: cast operator added */
10241 [ # # ]: 0 : if (!nAtom)
10242 : : {
10243 : 0 : return RI_ERR_ALLOC;
10244 : : }
10245 : 0 : memcpy(nAtom, pInpInChI[nAltMobileH][i].nAtom, len * sizeof(nAtom[0]));
10246 : 0 : nAtom[len] = 0;
10247 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nAtom)
10248 : : {
10249 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].nAtom);
10250 : : }
10251 : 0 : pInpInChI[bMobileH][i].nAtom = nAtom;
10252 : : }
10253 : 0 : pInpInChI[bMobileH][i].nNumberOfAtoms = len;
10254 : : }
10255 : : }
10256 : : }
10257 : :
10258 : 0 : return nNumComponents + 1;
10259 : : }
10260 : :
10261 : :
10262 : : /****************************************************************************/
10263 : 0 : int CopySegment(INChI* pInChITo,
10264 : : INChI* pInChIFrom,
10265 : : int SegmentType,
10266 : : int bIsotopicTo,
10267 : : int bIsotopicFrom)
10268 : : {
10269 : 0 : int ret = RI_ERR_ALLOC;
10270 : : int len;
10271 : :
10272 [ # # # # ]: 0 : if (SegmentType == CPY_SP2 ||
10273 [ # # ]: 0 : SegmentType == CPY_SP3 ||
10274 [ # # ]: 0 : SegmentType == CPY_SP3_M ||
10275 : : SegmentType == CPY_SP3_S)
10276 : : {
10277 : 0 : INChI_Stereo** pstereoTo = NULL;
10278 [ # # ]: 0 : INChI_Stereo* stereoFrom = bIsotopicFrom == 1 ? pInChIFrom->StereoIsotopic :
10279 [ # # ]: 0 : bIsotopicFrom == 0 ? pInChIFrom->Stereo : NULL;
10280 [ # # # # ]: 0 : if (stereoFrom || bIsotopicFrom < 0)
10281 : : {
10282 [ # # ]: 0 : if (SegmentType == CPY_SP2)
10283 : : {
10284 : : #if ( FIX_GAF_2019_1==1 )
10285 [ # # ]: 0 : if (bIsotopicFrom >= 0 &&
10286 [ # # # # ]: 0 : (pInChIFrom->nNumberOfAtoms > MAX_ATOMS || pInChIFrom->nNumberOfAtoms < 0))
10287 : : {
10288 : 0 : ret = RI_ERR_SYNTAX;
10289 : 0 : goto exit_function;
10290 : : }
10291 : : #endif
10292 [ # # ]: 0 : if (bIsotopicFrom < 0 ||
10293 [ # # ]: 0 : (stereoFrom->b_parity &&
10294 [ # # ]: 0 : stereoFrom->nBondAtom1 &&
10295 [ # # ]: 0 : stereoFrom->nBondAtom2)) /* djb-rwth: addressing LLVM warning */
10296 : : {
10297 : 0 : S_CHAR* pst0_bp = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10298 : 0 : AT_NUMB* pst0_nba1 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10299 : 0 : AT_NUMB* pst0_nba2 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10300 : :
10301 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : stereoFrom->nNumberOfStereoBonds;
10302 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10303 [ # # ]: 0 : if (!pstereoTo[0])
10304 : : {
10305 : : /* djb-rwth: fixing oss-fuzz issue #66985 */
10306 : 0 : INChI_Stereo* pst0 = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo));
10307 : 0 : pstereoTo[0] = pst0;
10308 [ # # ]: 0 : if (!pst0)
10309 : : {
10310 : 0 : goto exit_function;
10311 : : }
10312 : : }
10313 [ # # # # ]: 0 : if (pstereoTo[0]->nNumberOfStereoBonds > 0 || pstereoTo[0]->b_parity ||
10314 [ # # # # ]: 0 : pstereoTo[0]->nBondAtom1 || pstereoTo[0]->nBondAtom2)
10315 : : {
10316 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10317 : 0 : goto exit_function;
10318 : : }
10319 : : /* allocate sp2 stereo */
10320 : : /* djb-rwth: fixing oss-fuzz issue #66985 */
10321 : : /* djb-rwth: cast operators added */
10322 : 0 : pst0_bp = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->b_parity[0]));
10323 : 0 : pst0_nba1 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom1[0]));
10324 : 0 : pst0_nba2 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom2[0]));
10325 : 0 : pstereoTo[0]->b_parity = pst0_bp;
10326 : 0 : pstereoTo[0]->nBondAtom1 = pst0_nba1;
10327 : 0 : pstereoTo[0]->nBondAtom2 = pst0_nba2;
10328 [ # # # # : 0 : if (!pst0_bp || !pst0_nba1 || !pst0_nba2)
# # ]
10329 : : {
10330 : : /* cleanup */
10331 [ # # ]: 0 : if (pst0_bp)
10332 : : {
10333 : : INCHI_HEAPCHK
10334 [ # # ]: 0 : inchi_free(pst0_bp);
10335 : 0 : pst0_bp = NULL;
10336 : : }
10337 [ # # ]: 0 : if (pst0_nba1)
10338 : : {
10339 : : INCHI_HEAPCHK
10340 [ # # ]: 0 : inchi_free(pst0_nba1);
10341 : 0 : pst0_nba1 = NULL;
10342 : : }
10343 [ # # ]: 0 : if (pstereoTo[0]->nBondAtom2)
10344 : : {
10345 : : INCHI_HEAPCHK
10346 [ # # ]: 0 : inchi_free(pst0_nba2);
10347 : 0 : pst0_nba2 = NULL;
10348 : : }
10349 : : INCHI_HEAPCHK
10350 : 0 : goto exit_function;
10351 : : }
10352 : : /* copy stereo */
10353 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10354 : : {
10355 : : #if ( FIX_GAF_2019_1==1 )
10356 [ # # # # ]: 0 : if (pInChIFrom->nNumberOfAtoms > MAX_ATOMS || pInChIFrom->nNumberOfAtoms < 0)
10357 : : {
10358 : 0 : ret = RI_ERR_SYNTAX;
10359 : 0 : goto exit_function;
10360 : : }
10361 : : #endif
10362 : 0 : memcpy(pst0_bp, stereoFrom->b_parity, ((long long)len + 1) * sizeof(pst0_bp[0])); /* djb-rwth: cast operator added */
10363 : 0 : memcpy(pst0_nba1, stereoFrom->nBondAtom1, ((long long)len + 1) * sizeof(pst0_nba1[0])); /* djb-rwth: cast operator added */
10364 : 0 : memcpy(pst0_nba2, stereoFrom->nBondAtom2, ((long long)len + 1) * sizeof(pst0_nba2[0])); /* djb-rwth: cast operator added */
10365 : : }
10366 : 0 : pstereoTo[0]->nNumberOfStereoBonds = len;
10367 : :
10368 : 0 : return len + 1;
10369 : : }
10370 : : else
10371 : : {
10372 : 0 : return 0;
10373 : : }
10374 : : }
10375 : : else
10376 : : {
10377 [ # # ]: 0 : if (SegmentType == CPY_SP3)
10378 : : {
10379 [ # # ]: 0 : if (bIsotopicFrom < 0 ||
10380 [ # # ]: 0 : (stereoFrom->t_parity &&
10381 [ # # ]: 0 : stereoFrom->nNumber)) /* djb-rwth: addressing LLVM warning */
10382 : : {
10383 : :
10384 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : stereoFrom->nNumberOfStereoCenters;
10385 : :
10386 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10387 [ # # ]: 0 : if (!pstereoTo[0])
10388 : : {
10389 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10390 : : {
10391 : 0 : goto exit_function;
10392 : : }
10393 : : }
10394 [ # # # # ]: 0 : if (pstereoTo[0]->nNumberOfStereoCenters > 0 || pstereoTo[0]->t_parity ||
10395 [ # # ]: 0 : pstereoTo[0]->nNumber)
10396 : : {
10397 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10398 : 0 : goto exit_function;
10399 : : }
10400 : : /* allocate sp3 stereo */
10401 [ # # ]: 0 : if (!(pstereoTo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->b_parity[0]))) ||
10402 [ # # ]: 0 : !(pstereoTo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom1[0])))) /* djb-rwth: cast operators added */
10403 : : {
10404 : : /* cleanup */
10405 [ # # ]: 0 : if (pstereoTo[0]->t_parity)
10406 : : {
10407 [ # # ]: 0 : inchi_free(pstereoTo[0]->t_parity);
10408 : 0 : pstereoTo[0]->t_parity = NULL;
10409 : : }
10410 [ # # ]: 0 : if (pstereoTo[0]->nNumber)
10411 : : {
10412 [ # # ]: 0 : inchi_free(pstereoTo[0]->nNumber);
10413 : 0 : pstereoTo[0]->nNumber = NULL;
10414 : : }
10415 : 0 : goto exit_function;
10416 : : }
10417 : : /* copy stereo */
10418 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10419 : : {
10420 : 0 : memcpy(pstereoTo[0]->t_parity, stereoFrom->t_parity, ((long long)len + 1) * sizeof(pstereoTo[0]->t_parity[0])); /* djb-rwth: cast operator added */
10421 : 0 : memcpy(pstereoTo[0]->nNumber, stereoFrom->nNumber, ((long long)len + 1) * sizeof(pstereoTo[0]->nNumber[0])); /* djb-rwth: cast operator added */
10422 : : }
10423 : 0 : pstereoTo[0]->nNumberOfStereoCenters = len;
10424 : 0 : return len + 1;
10425 : : }
10426 : : else
10427 : : {
10428 : 0 : return 0;
10429 : : }
10430 : : }
10431 : : else
10432 : : {
10433 [ # # ]: 0 : if (SegmentType == CPY_SP3_M)
10434 : : {
10435 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10436 [ # # ]: 0 : if (!pstereoTo[0])
10437 : : {
10438 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10439 : : {
10440 : 0 : goto exit_function;
10441 : : }
10442 : : }
10443 [ # # # # ]: 0 : if (pstereoTo[0]->nCompInv2Abs && NO_VALUE_INT != pstereoTo[0]->nCompInv2Abs)
10444 : : {
10445 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10446 : 0 : goto exit_function;
10447 : : }
10448 [ # # ]: 0 : if (bIsotopicFrom < 0)
10449 : : {
10450 : 0 : pstereoTo[0]->nCompInv2Abs = 0;
10451 : : }
10452 : : else
10453 : : {
10454 : 0 : pstereoTo[0]->nCompInv2Abs = stereoFrom->nCompInv2Abs;
10455 : : }
10456 : 0 : return 1;
10457 : : }
10458 : : else
10459 : : {
10460 : : /* use bTrivialInv to save /s1, /s2, /s3 */
10461 [ # # ]: 0 : if (SegmentType == CPY_SP3_S)
10462 : : {
10463 [ # # ]: 0 : pstereoTo = bIsotopicFrom ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10464 [ # # ]: 0 : if (!pstereoTo[0])
10465 : : {
10466 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10467 : : {
10468 : 0 : goto exit_function;
10469 : : }
10470 : : }
10471 [ # # ]: 0 : if (pstereoTo[0]->bTrivialInv)
10472 : : {
10473 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10474 : 0 : goto exit_function;
10475 : : }
10476 [ # # ]: 0 : if (stereoFrom) /* djb-rwth: fixing a NULL pointer dereference */
10477 : 0 : pstereoTo[0]->bTrivialInv = stereoFrom->bTrivialInv;
10478 [ # # ]: 0 : if (bIsotopicFrom < 0)
10479 : : {
10480 : 0 : pstereoTo[0]->bTrivialInv = 0;
10481 : : }
10482 : : else
10483 : : {
10484 : 0 : pstereoTo[0]->bTrivialInv = stereoFrom->bTrivialInv;
10485 : : }
10486 : 0 : return 1;
10487 : : }
10488 : : }
10489 : : }
10490 : : }
10491 : : }
10492 : :
10493 : 0 : return 0; /* nothing to copy */
10494 : : }
10495 : :
10496 [ # # ]: 0 : else if (SegmentType == CPY_ISO_AT)
10497 : : {
10498 : 0 : int nNumberOfIsotopicAtoms = pInChIFrom->nNumberOfIsotopicAtoms;
10499 : 0 : INChI_IsotopicAtom** pIsotopicAtomTo = NULL;
10500 : 0 : INChI_IsotopicAtom* IsotopicAtomFrom = pInChIFrom->IsotopicAtom;
10501 [ # # # # ]: 0 : if (bIsotopicFrom < 0 || IsotopicAtomFrom)
10502 : : {
10503 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : nNumberOfIsotopicAtoms;
10504 : : #if ( FIX_GAF_2019_3==1 )
10505 [ # # ]: 0 : if (pInChITo->nNumberOfIsotopicAtoms < 1)
10506 : : {
10507 : : /* forcibly free iso-related memory and set to NULL */
10508 [ # # # # ]: 0 : qzfree(pInChITo->IsotopicAtom);
10509 : : }
10510 : : #endif
10511 : 0 : pIsotopicAtomTo = &pInChITo->IsotopicAtom;
10512 [ # # ]: 0 : if (!*pIsotopicAtomTo)
10513 : : {
10514 [ # # ]: 0 : if (!(*pIsotopicAtomTo = (INChI_IsotopicAtom*)inchi_calloc((long long)len + 1, sizeof(**pIsotopicAtomTo)))) /* djb-rwth: cast operator added */
10515 : : {
10516 : 0 : goto exit_function;
10517 : : }
10518 : : }
10519 [ # # ]: 0 : if (pInChITo->nNumberOfIsotopicAtoms)
10520 : : {
10521 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10522 : 0 : goto exit_function;
10523 : : }
10524 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10525 : : {
10526 : 0 : memcpy(*pIsotopicAtomTo, IsotopicAtomFrom, ((long long)len + 1) * sizeof(**pIsotopicAtomTo)); /* djb-rwth: cast operator added */
10527 : : }
10528 : 0 : pInChITo->nNumberOfIsotopicAtoms = len;
10529 : 0 : return len + 1;
10530 : : }
10531 : :
10532 : 0 : return 0;
10533 : : }
10534 : :
10535 : 0 : ret = RI_ERR_PROGR; /* program error */
10536 : :
10537 : 0 : exit_function:
10538 : :
10539 : 0 : return ret;
10540 : : }
10541 : :
10542 : :
10543 : : /****************************************************************************
10544 : : Sort neighbors in ascending order
10545 : : ****************************************************************************/
10546 : 0 : int insertions_sort_AT_NUMB(AT_NUMB* base, int num)
10547 : : {
10548 : : AT_NUMB* i, * j, * pk, tmp;
10549 : 0 : int k, num_trans = 0;
10550 [ # # ]: 0 : for (k = 1, pk = base; k < num; k++, pk++)
10551 : : {
10552 [ # # # # ]: 0 : for (j = (i = pk) + 1, tmp = *j; j > base && *i > tmp; j = i, i--)
10553 : : {
10554 : 0 : *j = *i;
10555 : 0 : num_trans++;
10556 : : }
10557 : 0 : *j = tmp;
10558 : : }
10559 : :
10560 : 0 : return num_trans;
10561 : : }
10562 : :
10563 : :
10564 : : /****************************************************************************/
10565 : 0 : int getInChIChar(INCHI_IOSTREAM* pInp)
10566 : : {
10567 [ # # ]: 0 : if (pInp->type == INCHI_IOS_TYPE_STRING)
10568 : : {
10569 : : /* input from string */
10570 [ # # ]: 0 : if (pInp->s.nPtr < pInp->s.nUsedLength)
10571 : : {
10572 : 0 : return (int)pInp->s.pStr[pInp->s.nPtr++];
10573 : : }
10574 : 0 : return RI_ERR_EOF;
10575 : : }
10576 : : else
10577 : : {
10578 : : /* input from plain file */
10579 : : int c;
10580 : : #if ( defined(_MSC_VER)&&defined(_WIN32) || defined(__BORLANDC__)&&defined(__WIN32__) || defined(__GNUC__)&&defined(__MINGW32__)&&defined(_WIN32) )
10581 : : do
10582 : : {
10583 : : c = getc(pInp->f);
10584 : : if (c == EOF)
10585 : : {
10586 : : c = RI_ERR_EOF;
10587 : : break;
10588 : : }
10589 : : } while (c == '\r');
10590 : : #else
10591 : 0 : c = getc(pInp->f);
10592 [ # # ]: 0 : if (c == EOF)
10593 : : {
10594 : 0 : c = RI_ERR_EOF;
10595 : : }
10596 : : #endif
10597 : 0 : return c;
10598 : : }
10599 : : }
10600 : :
10601 : :
10602 : : /****************************************************************************/
10603 : 0 : int AddInChIChar(INCHI_IOSTREAM* pInp,
10604 : : SEGM_LINE* Line,
10605 : : const char* pszToken)
10606 : : {
10607 : 0 : int c = getInChIChar(pInp);
10608 : : /*
10609 : : while ( c == '\r' ) {
10610 : : c = getInChIChar( pInp );
10611 : : }
10612 : : */
10613 : :
10614 : : INCHI_HEAPCHK
10615 : :
10616 [ # # ]: 0 : if (Line->len + 2 >= Line->len_alloc)
10617 : : {
10618 : 0 : char* str = (char*)inchi_calloc((long long)Line->len_alloc + SEGM_LINE_ADD, sizeof(str[0])); /* djb-rwth: cast operator added */
10619 : : INCHI_HEAPCHK
10620 [ # # ]: 0 : if (str)
10621 : : {
10622 [ # # # # ]: 0 : if (Line->len > 0 && Line->str)
10623 : : {
10624 : 0 : memcpy(str, Line->str, sizeof(str[0]) * Line->len);
10625 : 0 : Line->len_alloc += SEGM_LINE_ADD;
10626 [ # # ]: 0 : inchi_free(Line->str);
10627 : : INCHI_HEAPCHK
10628 : : }
10629 : : else
10630 : : {
10631 : 0 : Line->len_alloc += SEGM_LINE_ADD;
10632 : : }
10633 : 0 : Line->str = str;
10634 : : }
10635 : : else
10636 : : {
10637 : 0 : c = RI_ERR_ALLOC; /* fatal error */
10638 : 0 : goto exit_function;
10639 : : }
10640 : : }
10641 : : INCHI_HEAPCHK
10642 [ # # ]: 0 : if (c < 0)
10643 : : {
10644 : 0 : Line->str[Line->len] = '\0';
10645 : : INCHI_HEAPCHK
10646 : 0 : c = RI_ERR_SYNTAX; /* fatal error: wrong char */
10647 : 0 : goto exit_function;
10648 : : }
10649 : :
10650 [ # # # # ]: 0 : if (c && strchr(pszToken, c)) /* /\ */
10651 : : {
10652 : 0 : Line->str[Line->len] = '\0';
10653 : : INCHI_HEAPCHK
10654 : 0 : c = -(c + 2);
10655 : 0 : goto exit_function;
10656 : : }
10657 [ # # # # ]: 0 : else if (!c && !Line->len)
10658 : : {
10659 : 0 : Line->str[Line->len] = c;
10660 : : INCHI_HEAPCHK
10661 : : }
10662 : : else
10663 : : {
10664 : 0 : Line->str[Line->len++] = c;
10665 : : INCHI_HEAPCHK
10666 : : }
10667 : :
10668 : 0 : exit_function:
10669 : :
10670 : : INCHI_HEAPCHK
10671 : :
10672 : 0 : return c; /* djb-rwth: addressing coverity ID #499500 -- c = getInChIChar(pInp) cannot be tainted */
10673 : : }
10674 : :
10675 : : /****************************************************************************/
10676 : 0 : int nGetInChISegment(INCHI_IOSTREAM* pInp,
10677 : : SEGM_LINE* Line,
10678 : : const char* pszToken)
10679 : : {
10680 : : int c;
10681 : 0 : Line->len = 0;
10682 [ # # ]: 0 : while (0 < (c = AddInChIChar(pInp, Line, pszToken)))
10683 : : {
10684 : : ;
10685 : : }
10686 [ # # ]: 0 : if (c < -2)
10687 : : {
10688 : 0 : c = -(c + 2);
10689 : : }
10690 : 0 : Line->c = c;
10691 : :
10692 : 0 : return c;
10693 : : }
10694 : :
10695 : :
10696 : : /****************************************************************************
10697 : : Add one more bond to the linked lists for both neighbors
10698 : : ****************************************************************************/
10699 : 0 : int AddLinkedBond(AT_NUMB at1,
10700 : : AT_NUMB at2,
10701 : : AT_NUMB num_at,
10702 : : LINKED_BONDS* pLB)
10703 : : {
10704 : 0 : int nReqLen = inchi_max(2 * num_at + 2, pLB->len + 2);
10705 : : AT_NUMB prev;
10706 : : #if ( FIX_GAF_2019_2==1 )
10707 : : {
10708 [ # # # # : 0 : if (at2 > num_at || at1 > num_at || at1 < 0 || at2<0 || num_at>MAX_ATOMS)
# # ]
10709 : : {
10710 : 0 : return RI_ERR_SYNTAX;
10711 : : }
10712 : : }
10713 : : #endif
10714 [ # # ]: 0 : if (pLB->len_alloc <= nReqLen)
10715 : : {
10716 : : /*int nNewLen = nReqLen + (nReqLen + LINKED_BOND_ADD - 1)%LINKED_BOND_ADD + LINKED_BOND_ADD;*/
10717 : 0 : int nNewLen = nReqLen - nReqLen % LINKED_BOND_ADD + 2 * LINKED_BOND_ADD;
10718 : 0 : ONE_LINKED_BOND* pBond = (ONE_LINKED_BOND*)inchi_calloc(nNewLen, sizeof(pBond[0]));
10719 [ # # ]: 0 : if (!pBond)
10720 : : {
10721 : 0 : return RI_ERR_ALLOC; /* allocation error */
10722 : : }
10723 [ # # # # ]: 0 : if (pLB->pBond && pLB->len)
10724 : : {
10725 : 0 : memcpy(pBond, pLB->pBond, pLB->len * sizeof(pBond[0]));
10726 : : }
10727 [ # # ]: 0 : if (pLB->pBond)
10728 [ # # ]: 0 : inchi_free(pLB->pBond);
10729 : 0 : pLB->pBond = pBond;
10730 : 0 : pLB->len_alloc = nNewLen;
10731 : : }
10732 [ # # ]: 0 : if (!pLB->len)
10733 : : {
10734 : 0 : pLB->len = num_at + 1;
10735 : 0 : memset(pLB->pBond, 0, ((long long)num_at + 1) * sizeof(pLB->pBond[0])); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
10736 : : }
10737 : :
10738 : 0 : prev = pLB->pBond[at1].prev; /* position of the last neighbor of at1 in the pLB->pBond */
10739 [ # # ]: 0 : if (!prev)
10740 : : {
10741 : 0 : pLB->pBond[at1].neigh = at2;
10742 : 0 : pLB->pBond[at1].prev = at1;
10743 : : }
10744 : : else
10745 : : {
10746 : 0 : pLB->pBond[pLB->len].neigh = at2;
10747 : 0 : pLB->pBond[pLB->len].prev = prev;
10748 : 0 : pLB->pBond[at1].prev = pLB->len++;
10749 : : }
10750 : :
10751 : 0 : prev = pLB->pBond[at2].prev; /* position of the last neighbor of at2 in the pLB->pBond */
10752 [ # # ]: 0 : if (!prev)
10753 : : {
10754 : 0 : pLB->pBond[at2].neigh = at1;
10755 : 0 : pLB->pBond[at2].prev = at2;
10756 : : }
10757 : : else
10758 : : {
10759 : 0 : pLB->pBond[pLB->len].neigh = at1;
10760 : 0 : pLB->pBond[pLB->len].prev = prev;
10761 : 0 : pLB->pBond[at2].prev = pLB->len++;
10762 : : }
10763 : :
10764 : 0 : return 0;
10765 : : }
10766 : :
10767 : :
10768 : : /****************************************************************************
10769 : : PrepareSaveOptBits
10770 : : ****************************************************************************/
10771 : 0 : void PrepareSaveOptBits(INPUT_PARMS* ip,
10772 : : INCHI_IOSTREAM* pLog,
10773 : : const long num_inp,
10774 : : const char* szCurHdr,
10775 : : int input_has_save_opt,
10776 : : unsigned char input_save_opt_bits,
10777 : : unsigned char* save_opt_bits)
10778 : : {
10779 : :
10780 [ # # ]: 0 : if (!input_has_save_opt)
10781 : : {
10782 : : /* Does not allow to create SaveOpt if the source lacks appendix */
10783 : 0 : ip->bINChIOutputOptions &= ~INCHI_OUT_SAVEOPT;
10784 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10785 : : {
10786 : 0 : inchi_ios_eprint(pLog,
10787 : : "Warning: ignore SaveOpt request for SaveOpt-less input, %s\n",
10788 : : szCurHdr);
10789 : : }
10790 : : else
10791 : : {
10792 : 0 : inchi_ios_eprint(pLog,
10793 : : "Warning: ignore SaveOpt request for SaveOpt-less input, Structure %ld\n",
10794 : : num_inp);
10795 : : }
10796 : : }
10797 : : else
10798 : : {
10799 : : /* Analyze existing and prepare new SaveOpt appendix */
10800 : : /* djb-rwth: addressing coverity ID #499490 -- these are variable initialisers setting values to 0 */
10801 : 0 : int input_save_opt_has_recmet = input_save_opt_bits & SAVE_OPT_RECMET;
10802 : 0 : int input_save_opt_has_fixedh = input_save_opt_bits & SAVE_OPT_FIXEDH;
10803 : 0 : int input_save_opt_has_suu = input_save_opt_bits & SAVE_OPT_SUU;
10804 : 0 : int input_save_opt_has_sluud = input_save_opt_bits & SAVE_OPT_SLUUD;
10805 : 0 : int input_save_opt_has_ket = input_save_opt_bits & SAVE_OPT_KET;
10806 : 0 : int input_save_opt_has_15t = input_save_opt_bits & SAVE_OPT_15T;
10807 : 0 : int input_save_opt_has_pt_22_00 = input_save_opt_bits & SAVE_OPT_PT_22_00;
10808 : 0 : int input_save_opt_has_pt_16_00 = input_save_opt_bits & SAVE_OPT_PT_16_00;
10809 : 0 : int input_save_opt_has_pt_06_00 = input_save_opt_bits & SAVE_OPT_PT_06_00;
10810 : 0 : int input_save_opt_has_pt_39_00 = input_save_opt_bits & SAVE_OPT_PT_39_00;
10811 : 0 : int input_save_opt_has_pt_13_00 = input_save_opt_bits & SAVE_OPT_PT_13_00;
10812 : 0 : int input_save_opt_has_pt_18_00 = input_save_opt_bits & SAVE_OPT_PT_18_00;
10813 : :
10814 [ # # ]: 0 : if (0 != (ip->bTautFlags & TG_FLAG_RECONNECT_COORD))
10815 : : {
10816 : : /* RecMet requested */
10817 [ # # ]: 0 : if (input_save_opt_has_recmet)
10818 : : {
10819 : 0 : *save_opt_bits |= SAVE_OPT_RECMET;
10820 : : }
10821 : : else
10822 : : {
10823 : 0 : ip->bTautFlags &= ~TG_FLAG_RECONNECT_COORD;
10824 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10825 : : {
10826 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o RecMet - ignoring RecMet request, %s\n", szCurHdr);
10827 : : }
10828 : : else
10829 : : {
10830 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o RecMet - ignoring RecMet request, Structure %ld\n", num_inp);
10831 : : }
10832 : : }
10833 : : }
10834 : :
10835 [ # # ]: 0 : if (0 != (ip->nMode & REQ_MODE_BASIC))
10836 : : {
10837 : : /* FixedH requested */
10838 [ # # ]: 0 : if (input_save_opt_has_fixedh)
10839 : : {
10840 : 0 : *save_opt_bits |= SAVE_OPT_FIXEDH;
10841 : : }
10842 : : else
10843 : : {
10844 : 0 : ip->nMode &= ~REQ_MODE_BASIC;
10845 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10846 : : {
10847 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o FixedH - ignoring FixedH request, %s\n", szCurHdr);
10848 : : }
10849 : : else
10850 : : {
10851 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o FixedH - ignoring FixedH request, Structure %ld\n", num_inp);
10852 : : }
10853 : : }
10854 : : }
10855 : :
10856 : : /* Copy from source SaveOpt those bits which we do not touch */
10857 : : /* while converting InChI: SUU SLUUD KET 15T */
10858 [ # # ]: 0 : if (input_save_opt_has_suu)
10859 : : {
10860 : 0 : *save_opt_bits |= SAVE_OPT_SUU;
10861 : : }
10862 [ # # ]: 0 : if (input_save_opt_has_sluud)
10863 : : {
10864 : 0 : *save_opt_bits |= SAVE_OPT_SLUUD;
10865 : : }
10866 [ # # ]: 0 : if (input_save_opt_has_ket)
10867 : : {
10868 : 0 : *save_opt_bits |= SAVE_OPT_KET;
10869 : : }
10870 [ # # ]: 0 : if (input_save_opt_has_15t)
10871 : : {
10872 : 0 : *save_opt_bits |= SAVE_OPT_15T;
10873 : : }
10874 : :
10875 [ # # ]: 0 : if (input_save_opt_has_pt_22_00)
10876 : 0 : *save_opt_bits |= SAVE_OPT_PT_22_00;
10877 [ # # ]: 0 : if (input_save_opt_has_pt_16_00)
10878 : 0 : *save_opt_bits |= SAVE_OPT_PT_16_00;
10879 [ # # ]: 0 : if (input_save_opt_has_pt_06_00)
10880 : 0 : *save_opt_bits |= SAVE_OPT_PT_06_00;
10881 [ # # ]: 0 : if (input_save_opt_has_pt_39_00)
10882 : 0 : *save_opt_bits |= SAVE_OPT_PT_39_00;
10883 [ # # ]: 0 : if (input_save_opt_has_pt_13_00)
10884 : 0 : *save_opt_bits |= SAVE_OPT_PT_13_00;
10885 [ # # ]: 0 : if (input_save_opt_has_pt_18_00)
10886 : 0 : *save_opt_bits |= SAVE_OPT_PT_18_00;
10887 : :
10888 : : /* Check if /SNon requested and turn OFF stereo bits if so */
10889 [ # # ]: 0 : if (!(ip->nMode & REQ_MODE_STEREO))
10890 : : {
10891 : 0 : *save_opt_bits &= ~SAVE_OPT_SUU;
10892 : 0 : *save_opt_bits &= ~SAVE_OPT_SLUUD;
10893 : : }
10894 : : }
10895 : :
10896 : 0 : return;
10897 : : }
10898 : :
10899 : :
10900 : : /****************************************************************************/
10901 : 0 : void TreatErrorsInReadInChIString(int nReadStatus,
10902 : : int nErr,
10903 : : int pState,
10904 : : INPUT_PARMS* ip,
10905 : : INCHI_IOSTREAM* pOut,
10906 : : INCHI_IOSTREAM* pLog,
10907 : : long* num_inp,
10908 : : long* num_errors,
10909 : : long* num_processed,
10910 : : char** pstrHdr,
10911 : : char** pszCurHdr,
10912 : : InpInChI* pOneInput)
10913 : : {
10914 [ # # # # ]: 0 : int bInChI2Struct = (ip->bReadInChIOptions & READ_INCHI_TO_STRUCTURE) && ip->nInputType == INPUT_INCHI;
10915 : :
10916 : : /* InChI could not be read */
10917 [ # # # # : 0 : if (nReadStatus == RI_ERR_EOF && nErr == 0 && pState == 0) /* && !(*pstrHdr) ) */
# # ]
10918 : : {
10919 : : /*if ( !(*pstrHdr) ) */
10920 : : ;/*inchi_ios_eprint( pLog, "\nEnd of file detected after structure %ld. \n", *num_inp );*/
10921 : : }
10922 : : else
10923 : : {
10924 : : /* Output InChI parsing error message */
10925 : : char szHdrSimulation[128];
10926 : : char szMsg2[1024];
10927 : 0 : (*num_inp)++;
10928 : 0 : sprintf(szHdrSimulation, "Structure: %ld", *num_inp);
10929 : 0 : getInchiStateReadErr(pState, szMsg2);
10930 : :
10931 : : #ifdef TARGET_EXE_STANDALONE
10932 : : if (pOneInput->polymer &&
10933 : : bInChI2Struct &&
10934 : : !(ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
10935 : : {
10936 : : inchi_ios_eprint(pLog, "%s Skipping polymer InChI (only conversion to Molfile is available, use OutputSDF option)\n",
10937 : : *pstrHdr ? *pstrHdr : szHdrSimulation);
10938 : : }
10939 : : else
10940 : : #endif
10941 : : {
10942 [ # # # # ]: 0 : if (!bInChI2Struct &&
10943 [ # # ]: 0 : (pState == IST_MOBILE_H_POLYMER && !ip->bPolymers))
10944 : : {
10945 : : /* TO DO: implement InChI2InChI for polymers in a way similar to InChI2Struct
10946 : : thru an external (to ReadWriteInchi) loop */
10947 : 0 : inchi_ios_eprint(pLog, "%s Skipping polymer InChI for conversion of InChI to InChI\n",
10948 [ # # ]: 0 : *pstrHdr ? *pstrHdr : szHdrSimulation);
10949 : : }
10950 : : else
10951 : : {
10952 : 0 : inchi_ios_eprint(pLog, "\n%s %s (%d) in %s (%d)\n",
10953 [ # # ]: 0 : *pstrHdr ? *pstrHdr : szHdrSimulation,
10954 : : getInchiErrName(nErr), nErr,
10955 : : szMsg2, pState);
10956 : : }
10957 : : }
10958 : :
10959 [ # # ]: 0 : if (ip->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR)
10960 : : {
10961 [ # # ]: 0 : if (!(ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
10962 : : {
10963 [ # # ]: 0 : inchi_ios_eprint(pOut, "%s\n", *pstrHdr ? *pstrHdr : szHdrSimulation);
10964 [ # # ]: 0 : if (ip->bINChIOutputOptions & INCHI_OUT_STDINCHI)
10965 : : {
10966 : 0 : inchi_ios_eprint(pOut, "InChI=1S//\n");
10967 : : }
10968 : : else
10969 : : {
10970 : 0 : inchi_ios_eprint(pOut, "InChI=1//\n");
10971 : : }
10972 : : }
10973 : : }
10974 : :
10975 [ # # ]: 0 : if (0 != (ip->bReadInChIOptions & READ_INCHI_TO_STRUCTURE))
10976 : :
10977 : 0 : (*num_errors)++;
10978 : 0 : (*num_processed)++;
10979 : : }
10980 [ # # ]: 0 : if (*pstrHdr)
10981 : : {
10982 [ # # ]: 0 : inchi_free(*pstrHdr);
10983 : 0 : *pstrHdr = NULL;
10984 : : }
10985 [ # # ]: 0 : if (*pszCurHdr)
10986 : : {
10987 [ # # ]: 0 : inchi_free(*pszCurHdr);
10988 : 0 : *pszCurHdr = NULL;
10989 : : }
10990 : :
10991 : 0 : FreeInpInChI(pOneInput);
10992 : :
10993 : 0 : return;
10994 : : }
10995 : :
10996 : :
10997 : : /*
10998 : : InChi --> InChI string(s)
10999 : : */
11000 : :
11001 : :
11002 : : /****************************************************************************/
11003 : 0 : int ConvertInChI2InChI(INPUT_PARMS* ip,
11004 : : InpInChI* pOneInput,
11005 : : INCHI_IOSTREAM* pOut,
11006 : : INCHI_IOSTREAM* pLog,
11007 : : STRUCT_DATA* sd,
11008 : : int num_components[INCHI_NUM],
11009 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
11010 : : char** pszCurHdr,
11011 : : long num_inp,
11012 : : long* num_errors,
11013 : : unsigned char save_opt_bits,
11014 : : inchiTime* pulTStart,
11015 : : long* ulProcessingTime,
11016 : : struct tagINCHI_CLOCK* ic,
11017 : : struct tagCANON_GLOBALS* pCG)
11018 : : {
11019 : : int ret, tmp;
11020 : :
11021 : 0 : InchiTimeGet(pulTStart);
11022 : :
11023 : 0 : tmp = ip->bNoStructLabels;
11024 : 0 : ip->bNoStructLabels = 1;
11025 : : INCHI_HEAPCHK
11026 : 0 : ip->pSdfValue = NULL;
11027 : 0 : ip->pSdfLabel = NULL;
11028 : :
11029 : : #if ( FIX_DALKE_BUGS == 1 )
11030 : 0 : SetHillFormFromInChI(pOneInput);
11031 : : #endif
11032 : :
11033 : 0 : ret = OutputInChIAsRequested(pCG, pOut, pLog, ip, sd,
11034 : : pOneInput, num_components,
11035 : : nModeProtonIsoExchgH,
11036 : : num_inp, save_opt_bits);
11037 : :
11038 : : #if ( !defined(TARGET_API_LIB) && defined(TARGET_EXE_STANDALONE) )
11039 : :
11040 : : /* Calculate InChIKey if requested */
11041 : : /* However, do not calculate/write it if this function is called from within dll */
11042 : : {
11043 : : char ik_string[256]; /* Resulting InChIKey string */
11044 : : int ik_ret = 0; /* InChIKey-calc result code */
11045 : : int xhash1, xhash2;
11046 : : char szXtra1[65], szXtra2[65];
11047 : :
11048 : : inchi_ios_flush2(pLog, stderr);
11049 : :
11050 : : /* post-1.02b addition - correctly treat tabbed output with InChIKey */
11051 : : if (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT)
11052 : : {
11053 : : if (ip->bCalcInChIHash != INCHIHASH_NONE)
11054 : : {
11055 : : if (pOut->s.pStr)
11056 : : {
11057 : : if (pOut->s.nUsedLength > 0)
11058 : : {
11059 : : if (pOut->s.pStr[pOut->s.nUsedLength - 1] == '\n')
11060 : : { /* replace LF with TAB */
11061 : : pOut->s.pStr[pOut->s.nUsedLength - 1] = '\t';
11062 : : }
11063 : : }
11064 : : }
11065 : : }
11066 : : }
11067 : :
11068 : : if (ip->bCalcInChIHash == INCHIHASH_NONE)
11069 : : {
11070 : : /* inchi_ios_flush(pOut); */
11071 : : }
11072 : : else
11073 : : {
11074 : : char* buf = NULL;
11075 : : size_t slen = pOut->s.nUsedLength;
11076 : : extract_inchi_substring(&buf, pOut->s.pStr, slen);
11077 : :
11078 : : if (NULL != buf)
11079 : : {
11080 : : xhash1 = xhash2 = 0;
11081 : : if ((ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1) ||
11082 : : (ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2))
11083 : : {
11084 : : xhash1 = 1;
11085 : : }
11086 : : if ((ip->bCalcInChIHash == INCHIHASH_KEY_XTRA2) ||
11087 : : (ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2))
11088 : : {
11089 : : xhash2 = 1;
11090 : : }
11091 : :
11092 : : ik_ret = GetINCHIKeyFromINCHI(buf,
11093 : : xhash1,
11094 : : xhash2,
11095 : : ik_string,
11096 : : szXtra1,
11097 : : szXtra2);
11098 : : inchi_free(buf);
11099 : : }
11100 : : else
11101 : : {
11102 : : ik_ret = INCHIKEY_NOT_ENOUGH_MEMORY;
11103 : : }
11104 : :
11105 : :
11106 : : if (ik_ret == INCHIKEY_OK)
11107 : : {
11108 : : inchi_ios_print(pOut, "InChIKey=%-s\n", ik_string);
11109 : : }
11110 : : else
11111 : : {
11112 : : inchi_ios_print(pLog, "Warning (Could not compute InChIKey: ", num_inp);
11113 : : switch (ik_ret)
11114 : : {
11115 : : case INCHIKEY_UNKNOWN_ERROR:
11116 : : inchi_ios_print(pLog, "unresolved error)");
11117 : : break;
11118 : : case INCHIKEY_EMPTY_INPUT:
11119 : : inchi_ios_print(pLog, "got an empty string)");
11120 : : break;
11121 : : case INCHIKEY_INVALID_INCHI_PREFIX:
11122 : : case INCHIKEY_INVALID_INCHI:
11123 : : case INCHIKEY_INVALID_STD_INCHI:
11124 : : inchi_ios_print(pLog, "no valid InChI string found)");
11125 : : break;
11126 : : case INCHIKEY_NOT_ENOUGH_MEMORY:
11127 : : inchi_ios_print(pLog, "not enough memory to treat the string)");
11128 : : break;
11129 : : default:inchi_ios_print(pLog, "internal program error)");
11130 : : break;
11131 : : }
11132 : :
11133 : : inchi_ios_print(pLog, " structure #%-lu.\n", num_inp);
11134 : : if (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT)
11135 : : {
11136 : : inchi_ios_print(pOut, "\n");
11137 : : }
11138 : : } /* if (ip->bCalcInChIHash!=INCHIHASH_NONE) */
11139 : :
11140 : : inchi_ios_flush(pOut);
11141 : : inchi_ios_flush2(pLog, stderr);
11142 : : }
11143 : : } /* Calculate InChIKey if requested */
11144 : : #endif
11145 : :
11146 : 0 : ip->bNoStructLabels = tmp;
11147 : :
11148 : : #ifndef TARGET_API_LIB
11149 : : if (ret < 0)
11150 : : {
11151 : :
11152 : : if (*pszCurHdr && (*pszCurHdr)[0])
11153 : : {
11154 : : inchi_ios_eprint(pLog, "Error %d creating InChI string %s\n", ret, *pszCurHdr);
11155 : : }
11156 : : else
11157 : : {
11158 : : inchi_ios_eprint(pLog, "Error %d creating InChI string, Structure %ld\n", ret, num_inp);
11159 : : }
11160 : : if (ip->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR)
11161 : : {/* inchi_ios_eprint( pOut, "InChICreationError!\n"); *//* emit err string */
11162 : : if (ip->bINChIOutputOptions & INCHI_OUT_STDINCHI)
11163 : : {
11164 : : inchi_ios_eprint(pOut, "InChI=1S//\n");
11165 : : }
11166 : : else
11167 : : {
11168 : : inchi_ios_eprint(pOut, "InChI=1//\n");
11169 : : }
11170 : : }
11171 : :
11172 : : (*num_errors)++;
11173 : : }
11174 : :
11175 : : #if ( !defined(TARGET_API_LIB) && !defined(TARGET_EXE_STANDALONE) )
11176 : : else
11177 : : if (*pszCurHdr && (*pszCurHdr)[0])
11178 : : {
11179 : : inchi_fprintf(stderr, "%s\r", *pszCurHdr);
11180 : : }
11181 : : #endif
11182 : : #endif
11183 : :
11184 : :
11185 [ # # ]: 0 : if (*pszCurHdr)
11186 : : {
11187 [ # # ]: 0 : inchi_free(*pszCurHdr);
11188 : 0 : *pszCurHdr = NULL;
11189 : : }
11190 : :
11191 : : INCHI_HEAPCHK
11192 : :
11193 : 0 : * ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11194 : :
11195 : 0 : return ret;
11196 : : }
11197 : :
11198 : :
11199 : : /* InChi --> Structure (presented as AuxInfo or MolFile) */
11200 : :
11201 : :
11202 : : /****************************************************************************/
11203 : 0 : int ConvertInChI2Struct(ICHICONST INPUT_PARMS* ip_inp,
11204 : : INPUT_PARMS* ip,
11205 : : InpInChI* pOneInput,
11206 : : inp_ATOM** at,
11207 : : int* num_at,
11208 : : OAD_Polymer** polymer,
11209 : : OAD_V3000** v3000,
11210 : : INCHI_IOSTREAM* pOut,
11211 : : INCHI_IOSTREAM* pLog,
11212 : : STRUCT_DATA* sd,
11213 : : int num_components[INCHI_NUM],
11214 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
11215 : : char** pszCurHdr,
11216 : : char* szMsg,
11217 : : int nMsgLen,
11218 : : char szMessage[MAX_MSG_LEN],
11219 : : int nInitLenMessage,
11220 : : int nMessageLen,
11221 : : int input_is_stdinchi,
11222 : : int bHasSomeReconnected,
11223 : : int bHasSomeFixedH,
11224 : : int bHasMetal,
11225 : : int nModeFlagsStereo,
11226 : : int bTautFlags,
11227 : : int bReqNonTaut,
11228 : : unsigned long WarningFlags[2][2],
11229 : : long num_inp,
11230 : : long* num_errors,
11231 : : unsigned char save_opt_bits,
11232 : : inchiTime* pulTStart,
11233 : : long* ulProcessingTime,
11234 : : struct tagINCHI_CLOCK* ic,
11235 : : struct tagCANON_GLOBALS* pCG)
11236 : : {
11237 : : int ret, i, j;
11238 : : SRM srm; /* rules how to handle bonds to metal atoms */
11239 : : StrFromINChI* pStruct[INCHI_NUM][TAUT_NUM];
11240 : :
11241 : 0 : int bINChIOutputOptions = /* djb-rwth: ignoring LLVM warning: variable used */
11242 : : #if ( I2S_MODIFY_OUTPUT != 1 )
11243 : : 0;
11244 : : #else
11245 : : /* transfer user's InChI output options to serialization 10-12-2007 */
11246 : : ip_inp->bINChIOutputOptions&
11247 : : (
11248 : : INCHI_OUT_NO_AUX_INFO | /* do not output Aux Info */
11249 : : INCHI_OUT_SHORT_AUX_INFO | /* output short version of Aux Info */
11250 : : INCHI_OUT_ONLY_AUX_INFO | /* output only Aux Info */
11251 : : /* INCHI_OUT_EMBED_REC |*/ /* embed reconnected INChI into disconnected INChI */
11252 : : INCHI_OUT_SDFILE_ONLY | /* save input data in a Molfile instead of creating INChI */
11253 : : INCHI_OUT_PLAIN_TEXT | /* output plain text INChI */
11254 : : INCHI_OUT_PLAIN_TEXT_COMMENTS | /* output plain text annotation */
11255 : : /* INCHI_OUT_WINCHI_WINDOW |*/ /* output into wINChI text window */
11256 : : INCHI_OUT_TABBED_OUTPUT | /* tab-delimited (only for plain text) */
11257 : : INCHI_OUT_SDFILE_ATOMS_DT | /* SDfile output H isotopes as D and T */
11258 : : INCHI_OUT_SDFILE_SPLIT | /* Split SDfile into components */
11259 : : 0
11260 : : );
11261 : : #endif
11262 : :
11263 : : /* Preliminaries */
11264 : 0 : InchiTimeGet(pulTStart);
11265 : :
11266 [ # # ]: 0 : if (input_is_stdinchi)
11267 : : {
11268 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_STDINCHI)
11269 : : {
11270 : 0 : bINChIOutputOptions |= INCHI_OUT_STDINCHI;
11271 : : }
11272 : : }
11273 : : else
11274 : : {
11275 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_SAVEOPT)
11276 : : {
11277 : 0 : bINChIOutputOptions |= INCHI_OUT_SAVEOPT;
11278 : : }
11279 : : }
11280 : :
11281 : 0 : memset(pStruct, 0, sizeof(pStruct)); /* djb-rwth: memset_s C11/Annex K variant? */
11282 : :
11283 : 0 : SetUpSrm(&srm); /* structure restore parms */
11284 : :
11285 : : /* Eliminate Fixed-H InChI that are exactly same as the corresponding Mobile-H structures */
11286 : 0 : RemoveFixHInChIIdentical2MobH(pOneInput);
11287 : :
11288 : : /* Recheck layers after thee elimination; get optional stereo flags */
11289 : 0 : ret = DetectInpInchiCreationOptions(pOneInput, &bHasSomeReconnected,
11290 : : &bHasMetal, &bHasSomeFixedH,
11291 : : &nModeFlagsStereo, &bTautFlags);
11292 [ # # ]: 0 : if (ret < 0)
11293 : : {
11294 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen,
11295 : : "Error in detecting input InChI options", "; ");
11296 : 0 : (*num_errors)++;
11297 : 0 : goto dealloc;
11298 : : }
11299 : :
11300 [ # # # # ]: 0 : if (bHasSomeFixedH && !bReqNonTaut)
11301 : : {
11302 : 0 : bHasSomeFixedH = 0;
11303 : : }
11304 : :
11305 : : /* Set stereo flags */
11306 : 0 : ip->nMode &= ~(REQ_MODE_STEREO |
11307 : : REQ_MODE_ISO_STEREO |
11308 : : REQ_MODE_RELATIVE_STEREO |
11309 : : REQ_MODE_RACEMIC_STEREO |
11310 : : REQ_MODE_CHIR_FLG_STEREO |
11311 : : REQ_MODE_SB_IGN_ALL_UU |
11312 : : REQ_MODE_SC_IGN_ALL_UU);
11313 : :
11314 : 0 : ip->nMode |= nModeFlagsStereo;
11315 : :
11316 : : /* Remove Phosphine and Arsine Stereo Flags */
11317 : 0 : ip->bTautFlags &= ~TG_FLAG_PHOSPHINE_STEREO;
11318 : 0 : ip->bTautFlags &= ~TG_FLAG_ARSINE_STEREO;
11319 : 0 : ip->bTautFlags &= ~TG_FLAG_FIX_SP3_BUG;
11320 : :
11321 : 0 : ip->bTautFlags |= bTautFlags;
11322 : :
11323 : : /* Mark Disconnected InChI components that are exactly came as Reconnected ones */
11324 : : /* Disconnected will have a negative number of the reconnected component */
11325 : : /* Reconnected will have a positive number of the disconnected component */
11326 : :
11327 : 0 : MarkDisconectedIdenticalToReconnected(pOneInput);
11328 : :
11329 : : /*****************************************************************************/
11330 : : /* Pay attention to: */
11331 : : /* 1) .nLink < 0 in Disonnected which means InChI is same as in Reconnected */
11332 : : /* The component in Reconnected has .nLink pointing to the Disconnected; */
11333 : : /* each .nLink = (1+component index) or -(1+component index) */
11334 : : /* In the future .nLink>0 in Disconnected shall point to the Reconnectrd */
11335 : : /* component from which it was created */
11336 : : /* 2) Currently reversed structures from Disconnected components are created */
11337 : : /* and abandoned if Reconnected layer exists */
11338 : : /* 3) Connect/disconnect H depends on the presence of atom/bond parity */
11339 : : /* The combined Mobile/Fixed-H parity should be set for Fixed-H components*/
11340 : : /* 4) No comparison of the Disconnected layer is done if Reconnected exists */
11341 : : /* 5) Reading InChI was not fully tested in case one component has stereo in */
11342 : : /* both Mobile-H and Fixed-H layers while another component has stereo */
11343 : : /* only in Mobile-H layer */
11344 : : /*****************************************************************************/
11345 : :
11346 : :
11347 : : /* Main conversion InChI->Structure for each component and */
11348 : : /* after that pStruct[iRec][iMobH][iComponent].at2 is the structure, */
11349 : : /* pStruct[iRec][iMobH][iComponent].RevInChI full InChI for the structure */
11350 : : /* In case of both Fixed-H and Mobile-H layers the results are in iMobH=0 */
11351 : : /* In case of only Mobile-H/Main layer the results are in iMobH=1 */
11352 : :
11353 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11354 : :
11355 : 0 : sd->ulStructTime = 0;
11356 : :
11357 : 0 : ret = AllInchiToStructure(ic, pCG, ip, sd, num_inp, *pszCurHdr, &srm, bHasSomeFixedH, pStruct, pOneInput);
11358 : :
11359 : 0 : ulProcessingTime += sd->ulStructTime;
11360 : 0 : InchiTimeGet(pulTStart);
11361 : :
11362 : : /* ret < 0 is error code; ret > 0 is number of errors */
11363 : : /* in pStruct[iInchiRec][iMobileH][iComponent].nError */
11364 [ # # ]: 0 : if (ret)
11365 : : {
11366 : : #if ( FIX_GAF_2019_1==1 )
11367 [ # # ]: 0 : if (ret > 0)
11368 : : {
11369 : 0 : ret = RI_ERR_PROGR;
11370 : : }
11371 : : #endif
11372 : : /* conversion error */
11373 : 0 : (*num_errors)++;
11374 : 0 : goto dealloc;
11375 : : }
11376 : :
11377 : : /* Attempt to fix the numumber of removed protons in case of Mobile-H */
11378 [ # # ]: 0 : if (!pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons &&
11379 [ # # ]: 0 : !pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons)
11380 : : {
11381 : 0 : ret = AddProtonAndIsoHBalanceToMobHStruct(ic, pCG, ip, sd, num_inp, bHasSomeFixedH, *pszCurHdr, pStruct, pOneInput);
11382 : :
11383 [ # # ]: 0 : if (ret < 0)
11384 : : {
11385 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Add/Remove protons error", "; ");
11386 : 0 : (*num_errors)++;
11387 : 0 : goto dealloc;
11388 : : }
11389 : : }
11390 : :
11391 : : /* Compare InChI from the Reversed Structure to the original input InChI */
11392 : 0 : ret = CompareAllOrigInchiToRevInChI(pStruct, pOneInput, bHasSomeFixedH, num_inp, *pszCurHdr);
11393 [ # # ]: 0 : if (ret < 0)
11394 : : {
11395 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "InChI compare error", "; ");
11396 : 0 : (*num_errors)++;
11397 : 0 : goto dealloc;
11398 : : }
11399 : :
11400 : : /* Compare disconnected versions */
11401 : 0 : ret = CompareAllDisconnectedOrigInchiToRevInChI(pStruct, pOneInput,
11402 : : bHasSomeFixedH, num_inp, *pszCurHdr);
11403 [ # # ]: 0 : if (ret < 0)
11404 : : {
11405 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "InChI compare2 error", "; ");
11406 : 0 : (*num_errors)++;
11407 : 0 : goto dealloc;
11408 : : }
11409 : :
11410 [ # # ]: 0 : if (WarningFlags)
11411 : : {
11412 [ # # ]: 0 : for (i = 0; i < 2; i++)
11413 : : {
11414 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
11415 : : {
11416 : 0 : WarningFlags[i][j] = (unsigned long)pOneInput->CompareInchiFlags[i][j];
11417 : : }
11418 : : }
11419 : : }
11420 : :
11421 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11422 : :
11423 : : #ifndef COMPILE_ANSI_ONLY
11424 : : ret = DisplayStructureComponents(pCG, ip, sd, num_inp, *pszCurHdr, &srm, bReqNonTaut, pStruct, pOneInput);
11425 : : if (ret < 0)
11426 : : {
11427 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Display structure error", "; ");
11428 : : }
11429 : : #endif
11430 : :
11431 : :
11432 : 0 : InchiTimeGet(pulTStart);
11433 : :
11434 : 0 : ret = MergeStructureComponents(ip, sd, num_inp, *pszCurHdr, &srm, bReqNonTaut, pStruct, pOneInput);
11435 : :
11436 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11437 : :
11438 [ # # ]: 0 : if (ret < 0)
11439 : : {
11440 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Merge Components error", "; ");
11441 : 0 : (*num_errors)++;
11442 : 0 : goto dealloc;
11443 : : }
11444 : :
11445 : :
11446 : : #ifdef TARGET_API_LIB
11447 : : /*------------- for debug only -------------------
11448 : : InchiTimeGet(&ulTStart);
11449 : : ret = OutputInChIOutOfStrFromINChI( ic, pCG,
11450 : : ip, sd, num_inp, 0,
11451 : : pOut, pLog, &OneInput,
11452 : : save_opt_bits);
11453 : : ulProcessingTime += InchiTimeElapsed( ic, pulTStart);
11454 : : if ( ret < 0 )
11455 : : {
11456 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Restored structure to InChI conversion failed", "; ");
11457 : : goto dealloc;
11458 : : }
11459 : : -------------------------------------------------*/
11460 [ # # # # ]: 0 : if (at && num_at)
11461 : : {
11462 : 0 : *at = pOneInput->atom;
11463 : 0 : *num_at = pOneInput->num_atoms;
11464 : 0 : pOneInput->atom = NULL;
11465 : 0 : *polymer = pOneInput->polymer;
11466 : 0 : pOneInput->polymer = NULL;
11467 : 0 : *v3000 = pOneInput->v3000;
11468 : 0 : pOneInput->v3000 = NULL;
11469 : : }
11470 : : #else
11471 : :
11472 : : InchiTimeGet(pulTStart);
11473 : :
11474 : : ret = OutputInChIOutOfStrFromINChI(ic, pCG, ip, sd, num_inp, bINChIOutputOptions,
11475 : : pOut, NULL, pOneInput, bHasSomeFixedH, save_opt_bits);
11476 : :
11477 : : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11478 : :
11479 : : if (ret < 0)
11480 : : {
11481 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Restored structure to InChI conversion error", "; ");
11482 : : (*num_errors)++;
11483 : : goto dealloc;
11484 : : }
11485 : : #endif
11486 : :
11487 [ # # ]: 0 : if (szMessage)
11488 : : {
11489 : 0 : int len, retcomp = 0, retcomp1 = 0;
11490 : 0 : InchiTimeGet(pulTStart);
11491 : 0 : retcomp = FillOutCompareMessage(szMessage, nMessageLen, pOneInput->CompareInchiFlags[0]);
11492 : :
11493 [ # # # # ]: 0 : if (pOneInput->CompareInchiFlags[1][0] || pOneInput->CompareInchiFlags[1][1])
11494 : : {
11495 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Disconnected: ", "; ");
11496 : 0 : retcomp1 = FillOutCompareMessage(szMessage, nMessageLen, pOneInput->CompareInchiFlags[1]);
11497 : : }
11498 : : /* add a metal warning */
11499 [ # # # # ]: 0 : if (bHasMetal && nInitLenMessage < (len = (int)strlen(szMessage)))
11500 : : {
11501 : 0 : char szMetal[] = " (Metal compound)";
11502 : : int shift;
11503 [ # # ]: 0 : if (len + (int)sizeof(szMetal) > nMessageLen)
11504 : : {
11505 : 0 : len = nMessageLen - (int)sizeof(szMetal);
11506 : : }
11507 : 0 : shift = nInitLenMessage + (int)sizeof(szMetal) - 1;
11508 : 0 : memmove(szMessage + shift, szMessage + nInitLenMessage, ((long long)len - nInitLenMessage) * sizeof(szMessage[0])); /* djb-rwth: cast operator added */
11509 : 0 : memcpy(szMessage + nInitLenMessage, szMetal, sizeof(szMetal) - sizeof(szMessage[0]));
11510 : 0 : szMessage[shift + len - nInitLenMessage] = '\0';
11511 : : }
11512 : :
11513 : 0 : retcomp = inchi_min(retcomp, retcomp1);
11514 : :
11515 [ # # ]: 0 : if (retcomp < 0 &&
11516 [ # # ]: 0 : (ip_inp->bINChIOutputOptions2 & INCHI_OUT_MISMATCH_AS_ERROR)
11517 : : )
11518 : : {
11519 : 0 : ret = RI_ERR_MISMATCH;
11520 : : /* AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "* Treated as error by user supplied option", "; "); */
11521 : 0 : (*num_errors)++;
11522 : 0 : goto dealloc;
11523 : : }
11524 : :
11525 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11526 : : }
11527 : :
11528 : 0 : ret = 0;
11529 : :
11530 : 0 : dealloc:
11531 : : /* Deallocate */
11532 [ # # ]: 0 : if (ret)
11533 : : {
11534 [ # # ]: 0 : if (ret < 0)
11535 : : {
11536 [ # # ]: 0 : if (ret == CT_USER_QUIT_ERR)
11537 : : {
11538 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Terminated by the user*", "; ");
11539 : : }
11540 : : else
11541 : : {
11542 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Conversion failed*", "; ");
11543 : : }
11544 : : }
11545 : : else
11546 : : {
11547 : : int iRec, iMob, iComp, nComp, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11548 : : char szTemp[128];
11549 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Conversion failed on component(s)", "; ");
11550 : 0 : len = (int)strlen(szMessage); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11551 [ # # ]: 0 : for (iRec = 0; iRec < INCHI_NUM; iRec++)
11552 : : {
11553 [ # # ]: 0 : for (iMob = bHasSomeFixedH ? TAUT_NON : TAUT_YES; iMob < TAUT_NUM; iMob++)
11554 : : {
11555 : 0 : nComp = pOneInput->nNumComponents[iRec][iMob];
11556 [ # # ]: 0 : if (!pStruct[iRec][iMob])
11557 : : {
11558 : 0 : continue;
11559 : : }
11560 [ # # ]: 0 : for (iComp = 0; iComp < nComp; iComp++)
11561 : : {
11562 [ # # ]: 0 : if (pStruct[iRec][iMob][iComp].nError)
11563 : : {
11564 : 0 : char* szFormula = pOneInput->pInpInChI[iRec][iMob][iComp].szHillFormula;
11565 [ # # ]: 0 : sprintf(szTemp,
11566 : : #if ( FIX_DALKE_BUGS == 1 )
11567 : : " %s%s%d(%.96s)",
11568 : : #else
11569 : : " %s%s%d(%s)",
11570 : : #endif
11571 [ # # # # ]: 0 : !bHasSomeReconnected ? "" : iRec ? "R" : "D",
11572 [ # # # # ]: 0 : !bHasSomeFixedH ? "" : iMob ? "M" : "F",
11573 : : iComp + 1, szFormula ? szFormula : "???");
11574 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, szTemp, NULL);
11575 : : }
11576 : : }
11577 : : }
11578 : : }
11579 : : } /* if ( ret > 0 ) */
11580 : : } /* if ( ret ) */
11581 : :
11582 : :
11583 : 0 : InchiTimeGet(pulTStart);
11584 : :
11585 : : /* Print one structure report */
11586 [ # # # # : 0 : if (szMessage && szMsg && nMsgLen > 1) /* djb-rwth: additional condition for szMessage */
# # ]
11587 : : {
11588 [ # # ]: 0 : int len = inchi_min((int)strlen(szMessage), nMsgLen - 1);
11589 [ # # ]: 0 : if (len > 0)
11590 : : {
11591 : 0 : memcpy(szMsg, szMessage, len);
11592 : 0 : szMsg[len] = '\0';
11593 : : }
11594 : : else
11595 : : {
11596 : 0 : szMsg[0] = '\0';
11597 : : }
11598 : : }
11599 : :
11600 [ # # # # ]: 0 : if (szMessage && (nInitLenMessage < (int)strlen(szMessage))) /* djb-rwth: additional condition for szMessage */
11601 : : {
11602 : 0 : inchi_ios_eprint(pLog, "%s\n", szMessage);
11603 : : }
11604 : : #ifndef TARGET_API_LIB
11605 : : else
11606 : : {
11607 : : /*^^^inchi_ios_eprint( stderr, "%s\r", szMessage );*/
11608 : : inchi_fprintf(stderr, "%s\r", szMessage);
11609 : : }
11610 : : #endif
11611 : :
11612 : 0 : FreeStrFromINChI(pStruct, pOneInput->nNumComponents);
11613 : 0 : FreeInpInChI(pOneInput);
11614 [ # # ]: 0 : if (*pszCurHdr)
11615 : : {
11616 [ # # ]: 0 : inchi_free(*pszCurHdr);
11617 : 0 : *pszCurHdr = NULL;
11618 : : }
11619 : :
11620 : : INCHI_HEAPCHK
11621 : :
11622 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11623 : :
11624 : 0 : return ret;
11625 : : }
11626 : :
11627 : :
11628 : : /****************************************************************************/
11629 : 0 : int DetectAndExposePolymerInternals(INCHI_IOSTREAM* is)
11630 : : {
11631 : 0 : int i, j, elindex, ret = 0, nheavy = 0,
11632 : 0 : nstars = 0, zlen = 0, star0 = 0, i_last_sym,
11633 : 0 : slen = 0, i2 = 0, ninsert = 0, kinsert, lead_pos, nc, ntimes, nc_max;
11634 : : const char* p, * pz, * pz2, * pr, * pend, * q;
11635 : 0 : char prev_layer_symbol = '0';
11636 : 0 : char element[3], * tmpstr = NULL, * edited_s = NULL;
11637 : 0 : int* insert_pos = NULL; /* inserts go before insert_pos[k] */
11638 : 0 : char* s = NULL, * s2 = NULL;
11639 : : int slength;
11640 : :
11641 : 0 : slength = is->s.nUsedLength;
11642 : 0 : s = (char*)inchi_calloc(2 * (long long)slength + 32, sizeof(char)); /* djb-rwth: cast operator added */
11643 [ # # ]: 0 : if (!s)
11644 : : {
11645 : 0 : goto endf;
11646 : : }
11647 : :
11648 : : /* Remove but save a tail (AuxInfo, InChIKey, etc.) if any */
11649 : 0 : strcpy(s, is->s.pStr);
11650 [ # # ]: 0 : for (i = 0; i < slength; i++)
11651 : : {
11652 [ # # ]: 0 : if (isspace(UCINT s[i]))
11653 : : {
11654 : 0 : i2 = i;
11655 : 0 : break;
11656 : : }
11657 : : }
11658 [ # # ]: 0 : if (i2)
11659 : : {
11660 : 0 : s2 = (char*)inchi_calloc((long long)slength - (long long)i2 + 2, sizeof(char)); /* djb-rwth: cast operators added */
11661 [ # # ]: 0 : if (!s2) goto endf;
11662 : 0 : strcpy(s2, s + i2);
11663 : 0 : s[i2] = '\0';
11664 : : }
11665 : :
11666 : 0 : i_last_sym = strlen(s) - 1;
11667 : 0 : p = strstr(s, "InChI=1");
11668 [ # # ]: 0 : if (!p)
11669 : : {
11670 : 0 : goto endf;
11671 : : }
11672 : :
11673 : 0 : pz = strstr(p, "/z");
11674 [ # # ]: 0 : if (!pz)
11675 : : {
11676 : 0 : goto endf;
11677 : : }
11678 : 0 : pz++;
11679 : :
11680 : : /* Check formula */
11681 : 0 : p = strchr(p, '/');
11682 [ # # ]: 0 : if (!p) /* djb-rwth: fixing coverity ID #499505 */
11683 : : {
11684 : 0 : goto endf;
11685 : : }
11686 : 0 : p++;
11687 : 0 : pend = strchr(p, '/');
11688 : 0 : ntimes = 1;
11689 [ # # ]: 0 : while (p != pend)
11690 : : {
11691 [ # # ]: 0 : if (isdigit(*p))
11692 : : {
11693 : 0 : ntimes = (int)inchi_strtol(p, &q, 10);
11694 : : #if ( CHECK_STRTOL_ATNUMB==1 )
11695 [ # # # # ]: 0 : if (ntimes > MAX_ATOMS || ntimes < 0)
11696 : : {
11697 : : #if (FIX_GAF_2020_25607 == 1)
11698 : 0 : ret = RI_ERR_SYNTAX;
11699 : 0 : goto endf;
11700 : : #else
11701 : : return RI_ERR_SYNTAX; /* syntax error */
11702 : : #endif
11703 : : }
11704 : : #endif
11705 : 0 : p = q;
11706 : : }
11707 : : else
11708 : : {
11709 [ # # ]: 0 : if (*p == '.')
11710 : : {
11711 : 0 : ntimes = 1;
11712 : : }
11713 : : }
11714 : :
11715 [ # # ]: 0 : if (!isupper(UCINT * p))
11716 : : {
11717 : 0 : ret = -1;
11718 : 0 : goto endf;
11719 : : }
11720 : :
11721 : 0 : j = 0;
11722 : 0 : element[j++] = *p++;
11723 [ # # # # ]: 0 : if (*p && islower(UCINT * p))
11724 : : {
11725 : 0 : element[j++] = *p++;
11726 : : }
11727 : 0 : element[j++] = '\0';
11728 [ # # # # ]: 0 : if (*p && isdigit(UCINT * p))
11729 : : {
11730 : 0 : elindex = (int)inchi_strtol(p, &q, 10);
11731 : : #if ( CHECK_STRTOL_ATNUMB==1 )
11732 [ # # # # ]: 0 : if (elindex > MAX_ATOMS || elindex < 0)
11733 : : {
11734 : : #if (FIX_GAF_2020_25607 == 1)
11735 : 0 : ret = RI_ERR_SYNTAX;
11736 : 0 : goto endf;
11737 : : #else
11738 : : return RI_ERR_SYNTAX; /* syntax error */
11739 : : #endif
11740 : :
11741 : : }
11742 : : #endif
11743 : 0 : p = q;
11744 : : }
11745 : : else
11746 : : {
11747 : 0 : elindex = 1;
11748 : : }
11749 [ # # ]: 0 : if (!elindex)
11750 : : {
11751 : 0 : ret = -1;
11752 : 0 : goto endf;
11753 : : }
11754 : : #if ( FIX_GAF_2019_2==1 )
11755 [ # # ]: 0 : if (ERR_ELEM == get_periodic_table_number(element))
11756 : : {
11757 : 0 : ret = -1;
11758 : 0 : goto endf;
11759 : : }
11760 : : #endif
11761 [ # # # # ]: 0 : if (element[0] != 'H' || element[1])
11762 : : {
11763 : 0 : nheavy += ntimes * elindex;
11764 : : }
11765 : :
11766 [ # # ]: 0 : if (*p == '.')
11767 : : {
11768 : 0 : p++;
11769 : : }
11770 : : }
11771 : :
11772 : : #if ( FIX_GAF_2019_2==1 )
11773 : 0 : insert_pos = (int*)inchi_calloc((long long)is->s.nUsedLength + 1, sizeof(int)); /* djb-rwth: cast operator added */
11774 : : #else
11775 : : /* max num of insert positions is 2 in formulas + Npolymeric units, the latter may not be > nheavy */
11776 : : insert_pos = (int*)inchi_calloc(nheavy + 32, sizeof(int));
11777 : : #endif
11778 [ # # ]: 0 : if (!insert_pos)
11779 : : {
11780 : 0 : ret = -2;
11781 : 0 : goto endf;
11782 : : }
11783 : :
11784 : 0 : ninsert = 0;
11785 [ # # ]: 0 : if (pend)
11786 : : {
11787 : 0 : insert_pos[ninsert] = (int)(pend - s);
11788 : : }
11789 : : else
11790 : : {
11791 : 0 : insert_pos[ninsert] = i_last_sym;
11792 : : }
11793 : 0 : ninsert++;
11794 : :
11795 : : /* Check hidden stars */
11796 : 0 : lead_pos = (int)(pz - s);
11797 : 0 : pend = strchr(pz, '/');
11798 [ # # ]: 0 : if (pend)
11799 : : {
11800 : 0 : zlen = (int)(pend - pz);
11801 : : }
11802 : : else
11803 : : {
11804 : 0 : zlen = (int)strlen(pz);
11805 : : }
11806 : 0 : tmpstr = (char*)inchi_calloc((long long)zlen + 32, sizeof(char)); /* djb-rwth: cast operator added */
11807 [ # # ]: 0 : if (!tmpstr)
11808 : : {
11809 : 0 : ret = -2;
11810 : 0 : goto endf;
11811 : : }
11812 : 0 : memcpy(tmpstr, pz, zlen);
11813 : 0 : ret = DetectHiddenPolymerStuff(tmpstr, zlen, &ninsert, insert_pos, lead_pos, &nstars);
11814 [ # # ]: 0 : if (ret)
11815 : : {
11816 : 0 : goto endf;
11817 : : }
11818 [ # # ]: 0 : if (!nstars)
11819 : : {
11820 : 0 : goto endf;
11821 : : }
11822 : :
11823 : : /* Have second '/z' ? */
11824 : 0 : pr = strstr(s, "/r");
11825 [ # # ]: 0 : if (pr)
11826 : : {
11827 : 0 : pr++;
11828 : :
11829 : 0 : pend = strchr(pr, '/');
11830 [ # # ]: 0 : if (pend)
11831 : : {
11832 : 0 : insert_pos[ninsert] = (int)(pend - s);
11833 : : }
11834 : : else
11835 : : {
11836 : 0 : insert_pos[ninsert] = i_last_sym;
11837 : : }
11838 : 0 : ninsert++;
11839 : :
11840 : 0 : pz2 = strstr(pr, "/z");
11841 [ # # ]: 0 : if (pz2)
11842 : : {
11843 : 0 : pz2++;
11844 : 0 : lead_pos = (int)(pz2 - s);
11845 : 0 : pend = strchr(pz2, '/');
11846 [ # # ]: 0 : if (pend)
11847 : : {
11848 : 0 : zlen = (int)(pend - pz2);
11849 : : }
11850 : : else
11851 : : {
11852 : 0 : zlen = (int)strlen(pz2);
11853 : : }
11854 [ # # ]: 0 : if (tmpstr)
11855 : : {
11856 [ # # ]: 0 : inchi_free(tmpstr);
11857 : : }
11858 : 0 : tmpstr = (char*)inchi_calloc((long long)zlen + 32, sizeof(char)); /* djb-rwth: cast operator added */
11859 [ # # ]: 0 : if (!tmpstr)
11860 : : {
11861 : 0 : ret = -2;
11862 : 0 : goto endf;
11863 : : }
11864 : 0 : memcpy(tmpstr, pz2, zlen);
11865 : 0 : nstars = 0;
11866 : 0 : ret = DetectHiddenPolymerStuff(tmpstr, zlen, &ninsert, insert_pos, lead_pos, &nstars);
11867 [ # # ]: 0 : if (ret)
11868 : : {
11869 : 0 : goto endf;
11870 : : }
11871 : : }
11872 : : }
11873 : :
11874 : 0 : slen = (int)strlen(s);
11875 : 0 : edited_s = (char*)inchi_calloc((long long)slen * 100 + 32 * 10 * (long long)ninsert, sizeof(char)); /* high reservation */ /* djb-rwth: cast operator added */
11876 [ # # ]: 0 : if (!edited_s)
11877 : : {
11878 : 0 : ret = -2;
11879 : 0 : goto endf;
11880 : : }
11881 : :
11882 : : /* Edits */
11883 : 0 : nc = 0;
11884 : 0 : nc_max = slen * 100 + 32 * 10 * ninsert; /* djb-rwth: fixing oss-fuzz issue #384549256 */
11885 : 0 : kinsert = 0;
11886 : 0 : star0 = nheavy + 1;
11887 [ # # ]: 0 : for (i = 0; i < slen; i++)
11888 : : {
11889 [ # # # # ]: 0 : if (kinsert < ninsert && i == insert_pos[kinsert])
11890 : : {
11891 [ # # # # ]: 0 : if (kinsert == 0 || prev_layer_symbol == 'r')
11892 : : {
11893 : 0 : sprintf(tmpstr, ".%dZz", nstars);
11894 : 0 : star0 = nheavy + 1; /* reset star numbers pool */
11895 : 0 : prev_layer_symbol = '0'; /* avoid printing ';' also */
11896 : : }
11897 : : else
11898 : : {
11899 : 0 : sprintf(tmpstr, "%d,%d-", star0, star0 + 1);
11900 : 0 : star0 += 2;
11901 : : }
11902 : 0 : kinsert++;
11903 [ # # ]: 0 : for (j = 0; j < (int)strlen(tmpstr); j++)
11904 : : {
11905 [ # # ]: 0 : if (nc < nc_max)
11906 : : {
11907 : 0 : edited_s[nc] = tmpstr[j];
11908 : 0 : nc++;
11909 : : }
11910 : : }
11911 : : }
11912 : :
11913 [ # # # # ]: 0 : if ((i == i_last_sym) && (nc < nc_max))
11914 : : {
11915 : 0 : edited_s[nc++] = s[i];
11916 : : }
11917 : :
11918 [ # # # # ]: 0 : if (s[i] == '/' || i == i_last_sym)
11919 : : {
11920 [ # # # # ]: 0 : if (prev_layer_symbol != '0' &&
11921 [ # # ]: 0 : prev_layer_symbol != 'f' &&
11922 [ # # ]: 0 : prev_layer_symbol != 'z' &&
11923 [ # # ]: 0 : prev_layer_symbol != 'p' &&
11924 [ # # ]: 0 : prev_layer_symbol != 'r' &&
11925 : : prev_layer_symbol != 's'
11926 : : )
11927 : 0 : {
11928 : 0 : char addon = ';';
11929 [ # # ]: 0 : if (prev_layer_symbol == 'm')
11930 : : {
11931 : 0 : addon = '.';
11932 : : }
11933 [ # # ]: 0 : for (j = 0; j < nstars; j++)
11934 : : {
11935 [ # # ]: 0 : if (nc < nc_max)
11936 : : {
11937 : 0 : edited_s[nc++] = addon;
11938 : : }
11939 : : }
11940 : : }
11941 [ # # ]: 0 : else if (prev_layer_symbol == 'f')
11942 : : {
11943 [ # # # # ]: 0 : if (s[i - 1] != 'f' && s[i - 2] != '/')
11944 : : {
11945 : 0 : sprintf(tmpstr, ".%dZz", nstars);
11946 [ # # ]: 0 : for (j = 0; j < (int)strlen(tmpstr); j++)
11947 : : {
11948 [ # # ]: 0 : if (nc < nc_max)
11949 : : {
11950 : 0 : edited_s[nc] = tmpstr[j];
11951 : 0 : nc++;
11952 : : }
11953 : : }
11954 : : }
11955 : : }
11956 : :
11957 [ # # ]: 0 : if (i != i_last_sym)
11958 : : {
11959 : 0 : prev_layer_symbol = s[i + 1];
11960 : : }
11961 : : else
11962 : : {
11963 : 0 : break;
11964 : : }
11965 : : }
11966 [ # # ]: 0 : if (nc < nc_max)
11967 : : {
11968 : 0 : edited_s[nc] = s[i];
11969 : 0 : nc++;
11970 : : }
11971 : : }
11972 [ # # ]: 0 : if (nc < nc_max)
11973 : : {
11974 : 0 : edited_s[nc] = '\0';
11975 : : }
11976 : 0 : inchi_strbuf_close(&is->s);
11977 [ # # ]: 0 : inchi_ios_print(is, "%-s%-s\n", edited_s, s2 ? s2 : "");
11978 : :
11979 : 0 : endf:
11980 [ # # ]: 0 : if (s)
11981 : : {
11982 [ # # ]: 0 : inchi_free(s);
11983 : : }
11984 [ # # ]: 0 : if (s2)
11985 : : {
11986 [ # # ]: 0 : inchi_free(s2);
11987 : : }
11988 [ # # ]: 0 : if (edited_s)
11989 : : {
11990 [ # # ]: 0 : inchi_free(edited_s);
11991 : : }
11992 [ # # ]: 0 : if (tmpstr)
11993 : : {
11994 [ # # ]: 0 : inchi_free(tmpstr);
11995 : : }
11996 [ # # ]: 0 : if (insert_pos)
11997 : : {
11998 [ # # ]: 0 : inchi_free(insert_pos);
11999 : : }
12000 : :
12001 : 0 : return ret;
12002 : : }
12003 : :
12004 : :
12005 : : /****************************************************************************/
12006 : 0 : int DetectHiddenPolymerStuff(char* tmpstr,
12007 : : int tmpstrlen,
12008 : : int* ninsert,
12009 : : int* insert_pos,
12010 : : int insert_lead_offset,
12011 : : int* nstars)
12012 : : {
12013 : : char c;
12014 : 0 : int opened, skip, i, i0, closed, ret = 0;
12015 : :
12016 : 0 : *nstars = opened = skip = i0 = 0;
12017 : 0 : closed = 1;
12018 [ # # ]: 0 : for (i = 0; i < tmpstrlen; i++)
12019 : : {
12020 : 0 : c = tmpstr[i];
12021 : :
12022 [ # # ]: 0 : if (c == '(')
12023 : : {
12024 [ # # ]: 0 : if (!closed)
12025 : : {
12026 : 0 : ret = -3; goto endf;
12027 : : }
12028 : 0 : opened = 1;
12029 : 0 : skip = 0;
12030 : 0 : i0 = i;
12031 : : }
12032 [ # # ]: 0 : else if (c == ')')
12033 : : {
12034 [ # # ]: 0 : if (!opened)
12035 : : {
12036 : 0 : ret = -3; goto endf;
12037 : : }
12038 [ # # ]: 0 : if (!skip)
12039 : : {
12040 : 0 : (*nstars) += 2;
12041 : 0 : insert_pos[(*ninsert)] = i0 + 1 + insert_lead_offset;
12042 : 0 : (*ninsert)++;
12043 : : }
12044 : 0 : opened = 0;
12045 : : }
12046 [ # # ]: 0 : else if (c == '-')
12047 : : {
12048 : 0 : skip = 1;
12049 : : }
12050 : : }
12051 : :
12052 : 0 : endf:
12053 : 0 : return ret;
12054 : : }
12055 : :
12056 : :
12057 : : /****************************************************************************
12058 : : Create empty sp3 segment
12059 : : ****************************************************************************/
12060 : 0 : static int SegmentSp3CreateEmpty(const char* str,
12061 : : int bMobileH,
12062 : : INChI* pInpInChI[],
12063 : : int nNumComponents,
12064 : : int state,
12065 : : int* pbAbc)
12066 : : {
12067 : 0 : int ret = 0;
12068 : : int iComponent;
12069 : 0 : int len0 = 0;
12070 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP3 || state == IST_FIXED_H_ISO_SP3);
12071 : 0 : INChI_Stereo** pStereo = NULL;
12072 : 0 : INChI* pInChI = pInpInChI[bMobileH];
12073 : :
12074 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
12075 : : {
12076 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
12077 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
12078 [ # # ]: 0 : if (!*pStereo)
12079 : : {
12080 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
12081 : : {
12082 : 0 : return RI_ERR_ALLOC;
12083 : : }
12084 : : }
12085 : : /* allocate empty sp3 stereo */
12086 [ # # ]: 0 : if ((!pStereo[0]->b_parity &&
12087 [ # # ]: 0 : !(pStereo[0]->b_parity = (S_CHAR*)inchi_calloc((long long)len0 + 1, sizeof(pStereo[0]->b_parity[0])))) ||
12088 [ # # ]: 0 : (!pStereo[0]->nBondAtom1 &&
12089 [ # # ]: 0 : !(pStereo[0]->nBondAtom1 = (AT_NUMB*)inchi_calloc((long long)len0 + 1, sizeof(pStereo[0]->nBondAtom1[0])))) ||
12090 [ # # ]: 0 : (!pStereo[0]->nBondAtom2 &&
12091 [ # # ]: 0 : !(pStereo[0]->nBondAtom2 = (AT_NUMB*)inchi_calloc((long long)len0 + 1, sizeof(pStereo[0]->nBondAtom2[0]))))) /* djb-rwth: cast operator added; addressing LLVM warnings */
12092 : : {
12093 : : /* cleanup */
12094 [ # # ]: 0 : if (pStereo[0]->b_parity)
12095 : : {
12096 : : INCHI_HEAPCHK
12097 [ # # ]: 0 : inchi_free(pStereo[0]->b_parity);
12098 : 0 : pStereo[0]->b_parity = NULL;
12099 : : }
12100 [ # # ]: 0 : if (pStereo[0]->nBondAtom1)
12101 : : {
12102 : : INCHI_HEAPCHK
12103 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom1);
12104 : 0 : pStereo[0]->nBondAtom1 = NULL;
12105 : : }
12106 [ # # ]: 0 : if (pStereo[0]->nBondAtom2)
12107 : : {
12108 : : INCHI_HEAPCHK
12109 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom2);
12110 : 0 : pStereo[0]->nBondAtom2 = NULL;
12111 : : }
12112 : 0 : return RI_ERR_ALLOC;
12113 : : }
12114 : 0 : pStereo[0]->nCompInv2Abs = NO_VALUE_INT;
12115 : : }
12116 : 0 : ret = nNumComponents + 1;
12117 : :
12118 : 0 : return ret;
12119 : : }
12120 : :
12121 : :
12122 : : /****************************************************************************/
12123 : 0 : static int SegmentSp3StoreStereoCenters(int* pbAbc,
12124 : : const char* pStart,
12125 : : const char* pEnd,
12126 : : int pInChI_iComponent_nNumberOfAtoms,
12127 : : INChI_Stereo* PStereo_0)
12128 : : {
12129 : 0 : const char parity_type[] = "-+u?";
12130 : : const char* p, * q, * r;
12131 : : AT_NUMB nAtom1;
12132 : : int iAtom;
12133 : : int atomParity;
12134 : 0 : int base = 10;
12135 : :
12136 [ # # ]: 0 : if (*pbAbc == 1)
12137 : : {
12138 [ # # ]: 0 : for (p = (char*)pStart, iAtom = 0; p < pEnd; iAtom++)
12139 : : {
12140 [ # # # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
12141 : 0 : (atomParity = (int)inchi_strtol(p, &p, 10),
12142 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= atomParity && atomParity <= AB_MAX_KNOWN_PARITY))
12143 : : {
12144 : : ; /* okay */
12145 : : }
12146 : : else
12147 : : {
12148 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12149 : : }
12150 [ # # ]: 0 : if (nAtom1 > pInChI_iComponent_nNumberOfAtoms)
12151 : : {
12152 : 0 : return RI_ERR_SYNTAX;
12153 : : }
12154 : 0 : PStereo_0->t_parity[iAtom] = atomParity;
12155 : 0 : PStereo_0->nNumber[iAtom] = nAtom1;
12156 [ # # # # ]: 0 : if (iAtom && !(PStereo_0->nNumber[iAtom - 1] < nAtom1))
12157 : : {
12158 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12159 : : }
12160 : : }
12161 : : }
12162 : : else
12163 : : {
12164 [ # # ]: 0 : for (p = (char*)pStart, iAtom = 0; p < pEnd; iAtom++, p += (*p == ','))
12165 : : {
12166 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
12167 : : #if ( CHECK_STRTOL_ATNUMB==1 )
12168 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
12169 : : {
12170 : 0 : return RI_ERR_SYNTAX;
12171 : : }
12172 : : #endif
12173 [ # # ]: 0 : if (!(r = strchr((char*)parity_type, *q)))
12174 : : {
12175 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12176 : : }
12177 : 0 : p = q + 1;
12178 : 0 : atomParity = (int)(r - parity_type) + 1;
12179 : 0 : PStereo_0->t_parity[iAtom] = atomParity;
12180 : 0 : PStereo_0->nNumber[iAtom] = nAtom1;
12181 [ # # # # ]: 0 : if (iAtom && !(PStereo_0->nNumber[iAtom - 1] < nAtom1))
12182 : : {
12183 : 0 : return RI_ERR_SYNTAX;
12184 : : }
12185 : : }
12186 : : }
12187 : 0 : PStereo_0->nNumberOfStereoCenters = iAtom;
12188 : : /*if ( iAtom ) {*/
12189 : 0 : PStereo_0->nCompInv2Abs = NO_VALUE_INT; /* unknown yet */
12190 : :
12191 [ # # ]: 0 : if (p != pEnd)
12192 : : {
12193 : 0 : return RI_ERR_SYNTAX;
12194 : : }
12195 : :
12196 : 0 : return 0;
12197 : : }
12198 : :
12199 : :
12200 : : /****************************************************************************
12201 : : Treat multiplier-served components
12202 : : ****************************************************************************/
12203 : 0 : static int SegmentSp3CopyMultiplierCovered(int mpy_component,
12204 : : int iComponent,
12205 : : INChI* pInChI,
12206 : : int bIso,
12207 : : int nCpyType)
12208 : : {
12209 : 0 : int i, ret = 0;
12210 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
12211 : : {
12212 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, bIso, bIso);
12213 [ # # ]: 0 : if (!ret)
12214 : : {
12215 : 0 : ret = RI_ERR_SYNTAX;
12216 : : }
12217 [ # # ]: 0 : if (ret < 0)
12218 : : {
12219 : 0 : return ret;
12220 : : }
12221 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, CPY_SP3_M, bIso, bIso);
12222 [ # # ]: 0 : if (!ret)
12223 : : {
12224 : 0 : ret = RI_ERR_SYNTAX;
12225 : : }
12226 [ # # ]: 0 : if (ret < 0)
12227 : : {
12228 : 0 : return ret;
12229 : : }
12230 : : }
12231 : :
12232 : 0 : return ret;
12233 : : }
12234 : :
12235 : :
12236 : : /****************************************************************************
12237 : : Process the abbreviation
12238 : : ****************************************************************************/
12239 : 0 : static int SegmentSp3ProcessAbbreviation(int* mpy_component,
12240 : : int iComponent,
12241 : : int nNumComponents,
12242 : : int val,
12243 : : const char* q,
12244 : : int state,
12245 : : int* pbAbc,
12246 : : int bMobileH,
12247 : : int nCpyType,
12248 : : INChI* pInChI,
12249 : : INChI* pInpInChI_ALT_TAUT_bMobileH)
12250 : : {
12251 : 0 : int i, bIsoTo = -1, bIsoFrom = -1;
12252 : 0 : int ret = 0;
12253 : 0 : INChI* pInChIFrom = NULL;
12254 : :
12255 : : #if (FIX_DALKE_BUGS == 1)
12256 [ # # ]: 0 : if (iComponent + val > nNumComponents)
12257 : : {
12258 : 0 : return RI_ERR_SYNTAX;
12259 : : }
12260 : : #endif
12261 : : #if (FIX_GAF_ISSUES==1)
12262 : : if (iComponent < 0)
12263 : : {
12264 : : return RI_ERR_SYNTAX;
12265 : : }
12266 : : #endif
12267 : :
12268 [ # # # ]: 0 : switch (bMobileH)
12269 : : {
12270 : 0 : case TAUT_YES:
12271 [ # # ]: 0 : switch (state)
12272 : : {
12273 : 0 : case IST_MOBILE_H_ISO_SP3:
12274 [ # # ]: 0 : if (*q == 'm')
12275 : : {
12276 : : /* copy from mobile H to isotopic mobile H */
12277 : 0 : pInChIFrom = pInChI;
12278 : 0 : bIsoTo = 1;
12279 : 0 : bIsoFrom = 0;
12280 : : }
12281 : : else
12282 : : {
12283 [ # # ]: 0 : if (*q == 'e')
12284 : : {
12285 : : /* copy from mobile H to isotopic mobile H */
12286 : 0 : pInChIFrom = pInChI;
12287 : 0 : bIsoTo = 1;
12288 : 0 : bIsoFrom = -1; /* empty */
12289 : : }
12290 : : else
12291 : : {
12292 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12293 : : }
12294 : : }
12295 : 0 : break;
12296 : 0 : default:
12297 : 0 : ret = RI_ERR_SYNTAX;
12298 : 0 : break;
12299 : : }
12300 : 0 : break;
12301 : 0 : case TAUT_NON:
12302 [ # # # ]: 0 : switch (state)
12303 : : {
12304 : 0 : case IST_FIXED_H_SP3:
12305 [ # # ]: 0 : if (*q == 'm')
12306 : : {
12307 : : /* copy from mobile H to fixed H */
12308 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12309 : 0 : bIsoTo = 0;
12310 : 0 : bIsoFrom = 0;
12311 : : }
12312 : : else
12313 : : {
12314 [ # # ]: 0 : if (*q == 'e')
12315 : : {
12316 : : /* copy from mobile H to isotopic mobile H */
12317 : 0 : pInChIFrom = pInChI; /* djb-rwth: addressing coverity ID #499498 -- definitely not a copy-paste error */
12318 : 0 : bIsoTo = 1;
12319 : 0 : bIsoFrom = -1; /* empty */
12320 : : }
12321 : : else
12322 : : {
12323 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12324 : : }
12325 : : }
12326 : 0 : break;
12327 : 0 : case IST_FIXED_H_ISO_SP3:
12328 [ # # ]: 0 : if (*q == 'm')
12329 : : {
12330 : : /* copy from mobile H to fixed isotopic H */
12331 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12332 : 0 : bIsoTo = 1;
12333 : 0 : bIsoFrom = 0;
12334 : : }
12335 : : else
12336 : : {
12337 [ # # ]: 0 : if (*q == 'M')
12338 : : {
12339 : : /* copy from isotopic mobile H to fixed isotopic H */
12340 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12341 : 0 : bIsoTo = 1;
12342 : 0 : bIsoFrom = 1;
12343 : : }
12344 : : else
12345 : : {
12346 [ # # ]: 0 : if (*q == 'n')
12347 : : {
12348 : : /* copy from fixed H to fixed isotopic H */
12349 : 0 : pInChIFrom = pInChI;
12350 : 0 : bIsoTo = 1;
12351 : 0 : bIsoFrom = 0;
12352 : : }
12353 : : else
12354 : : {
12355 [ # # ]: 0 : if (*q == 'e')
12356 : : {
12357 : : /* copy from mobile H to isotopic mobile H */
12358 : 0 : pInChIFrom = pInChI;
12359 : 0 : bIsoTo = 1;
12360 : 0 : bIsoFrom = -1; /* empty */
12361 : : }
12362 : : else
12363 : : {
12364 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12365 : : }
12366 : : }
12367 : : }
12368 : : }
12369 : 0 : break;
12370 : 0 : default:
12371 : 0 : ret = RI_ERR_SYNTAX;
12372 : 0 : break;
12373 : : }
12374 : 0 : break;
12375 : :
12376 : 0 : default:
12377 : 0 : ret = RI_ERR_SYNTAX;
12378 : 0 : break;
12379 : : }
12380 : :
12381 [ # # ]: 0 : if (ret < 0)
12382 : : {
12383 : 0 : return ret;
12384 : : }
12385 : :
12386 : : /* copy */
12387 [ # # ]: 0 : for (i = 0; i < val; i++)
12388 : : {
12389 : : /* djb-rwth: fixing oss-fuzz issue #26540 */
12390 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, bIsoTo, bIsoFrom);
12391 [ # # ]: 0 : if (!ret)
12392 : : {
12393 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12394 : : }
12395 [ # # ]: 0 : if (ret < 0)
12396 : : {
12397 : 0 : return ret;
12398 : : }
12399 [ # # ]: 0 : if (bIsoFrom >= 0)
12400 : : {
12401 [ # # ]: 0 : INChI_Stereo* pStereoTo = bIsoTo ? pInChI[iComponent + i].StereoIsotopic : pInChI[iComponent + i].Stereo;
12402 [ # # ]: 0 : if (pStereoTo)
12403 : : {
12404 : 0 : pStereoTo->nCompInv2Abs = NO_VALUE_INT; /* in case there in no /m segment after this */
12405 : : }
12406 : : }
12407 : : }
12408 : :
12409 : 0 : *mpy_component = val;
12410 : :
12411 : 0 : return ret;
12412 : : }
12413 : :
12414 : :
12415 : : /* Internal: a generic parser/extractor interface */
12416 : 0 : int extract_from_inchi_string(char* sinchi, InpInChI* OneInput)
12417 : : {
12418 : 0 : int ret = _IS_OKAY;
12419 : :
12420 : 0 : char* strHdr = NULL;
12421 : : SEGM_LINE Line;
12422 : 0 : SEGM_LINE* pLine = &Line;
12423 : : int pState, nErr;
12424 : 0 : const int bInChI2Structure = 1, bReadCoord = 1;
12425 : : int input_is_stdinchi, input_has_save_opt;
12426 : : unsigned char input_save_opt_bits;
12427 : : int end_of_data_reached, read_inchi_ok;
12428 : : INCHI_IOSTREAM tmpinputstream;
12429 : 0 : INCHI_IOSTREAM* pInp = &tmpinputstream;
12430 : 0 : INCHI_MODE nMode = 0;
12431 : : /* djb-rwth: removing redundant code */
12432 : :
12433 : 0 : nMode = (INCHI_MODE)530462;
12434 : :
12435 : 0 : memset(OneInput, 0, sizeof(*OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
12436 : 0 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
12437 : 0 : OneInput->polymer = NULL; /* v. 1.05 added */
12438 : 0 : OneInput->v3000 = NULL;
12439 : 0 : inchi_ios_init(pInp, INCHI_IOS_TYPE_STRING, NULL);
12440 : 0 : inchi_ios_print(pInp, "%-s", sinchi);
12441 : :
12442 : 0 : ret = DetectAndExposePolymerInternals(pInp);
12443 [ # # ]: 0 : if (ret)
12444 : : {
12445 : 0 : ret = _IS_ERROR;
12446 : 0 : goto exit_function;
12447 : : }
12448 : : /*strcpy(pInp->s.pStr, "InChI=1B/C4H4N4.2Zz/c1-5-2-7-4-8-3-6-1;;/h1-4H;;/z101-1-8(9,10-8,3,1,6,2,5,2,7,3,6,1,5,4,7,4,8)/b5-1-,5-2+,6-1+,6-3-,7-2+,7-4+,8-3+,8-4+;;");*/
12449 : 0 : ret = InChILine2Data(pInp,
12450 : : pLine,
12451 : : &strHdr,
12452 : : &pState,
12453 : : &nErr,
12454 : 0 : OneInput->pInpInChI,
12455 : 0 : OneInput->nNumComponents,
12456 : 0 : OneInput->nNumProtons,
12457 : 0 : OneInput->s,
12458 : : bReadCoord,
12459 : : bInChI2Structure,
12460 : : nMode,
12461 : : &input_is_stdinchi,
12462 : : &input_has_save_opt,
12463 : : &input_save_opt_bits,
12464 : : &OneInput->polymer,
12465 : : &OneInput->v3000);
12466 : :
12467 [ # # # # ]: 0 : end_of_data_reached = ret == RI_ERR_EOL || ret == RI_ERR_EOF;
12468 [ # # # # ]: 0 : read_inchi_ok = end_of_data_reached && !nErr;
12469 [ # # ]: 0 : if (!read_inchi_ok)
12470 : : {
12471 : 0 : ret = _IS_ERROR;
12472 : 0 : goto exit_function;
12473 : : }
12474 : : else
12475 : : {
12476 : 0 : ret = _IS_OKAY;
12477 : : }
12478 : :
12479 : :
12480 : 0 : exit_function:
12481 [ # # ]: 0 : if (strHdr)
12482 : : {
12483 [ # # ]: 0 : inchi_free(strHdr);
12484 : 0 : strHdr = NULL;
12485 : : }
12486 [ # # ]: 0 : if (pLine->str)
12487 : : {
12488 [ # # ]: 0 : inchi_free(pLine->str);
12489 : : }
12490 : 0 : inchi_ios_close(pInp);
12491 : :
12492 : 0 : return ret;
12493 : : }
12494 : :
12495 : :
12496 : : /****************************************************************************
12497 : : Extract_stereo_info_from_inchi_string
12498 : : ****************************************************************************/
12499 : 0 : int extract_stereo_info_from_inchi_string(char* sinchi,
12500 : : int nat,
12501 : : int* orig,
12502 : : int* at_stereo_mark_orig)
12503 : : {
12504 : : InpInChI OneInput;
12505 : 0 : int ret = _IS_OKAY;
12506 : 0 : int icomponent, i, bReconn = 0, bMobileH = 1, at_offset_component = 0;
12507 : :
12508 : : /* 0 is INCHI_PARITY_NONE */
12509 : 0 : memset(at_stereo_mark_orig, 0, ((long long)nat + 1) * sizeof(int)); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
12510 : :
12511 : 0 : ret = extract_from_inchi_string(sinchi, &OneInput);
12512 [ # # # # ]: 0 : if (ret == _IS_ERROR || ret == _IS_FATAL)
12513 : : {
12514 : 0 : ret = _IS_ERROR;
12515 : 0 : goto exit_function;
12516 : : }
12517 : :
12518 : :
12519 : :
12520 [ # # ]: 0 : for (icomponent = 0; icomponent < OneInput.nNumComponents[bReconn][bMobileH]; icomponent++)
12521 : : {
12522 : 0 : INChI pI = OneInput.pInpInChI[bReconn][bMobileH][icomponent];
12523 [ # # ]: 0 : if (NULL == pI.Stereo)
12524 : : {
12525 : 0 : continue;
12526 : : }
12527 [ # # ]: 0 : for (i = 0; i < pI.Stereo->nNumberOfStereoCenters; i++)
12528 : : {
12529 : 0 : int icano = pI.Stereo->nNumber[i] + at_offset_component;
12530 : 0 : int iorig = orig[icano];
12531 : 0 : at_stereo_mark_orig[iorig] = pI.Stereo->t_parity[i];
12532 : : }
12533 : 0 : at_offset_component += pI.nNumberOfAtoms;
12534 : : }
12535 : :
12536 : 0 : exit_function:
12537 : 0 : FreeInpInChI(&OneInput);
12538 : :
12539 : 0 : return ret;
12540 : : }
12541 : :
12542 : :
12543 : : /****************************************************************************
12544 : : Extract all backbone bonds, in all units, from InChI string
12545 : : NB: as units are not 'inter-crossing' any bkbond belongs to some unique CRU
12546 : : ****************************************************************************/
12547 : 0 : int extract_all_backbone_bonds_from_inchi_string(char* sinchi,
12548 : : int* n_all_bkb_orig,
12549 : : int* orig,
12550 : : int* all_bkb_orig)
12551 : : {
12552 : : InpInChI OneInput;
12553 : 0 : int i, ret = _IS_OKAY;
12554 : :
12555 : 0 : ret = extract_from_inchi_string(sinchi, &OneInput);
12556 [ # # # # ]: 0 : if (ret == _IS_ERROR || ret == _IS_FATAL)
12557 : : {
12558 : 0 : ret = _IS_ERROR;
12559 : 0 : goto exit_function;
12560 : : }
12561 : :
12562 [ # # ]: 0 : for (i = 0; i < OneInput.polymer->n; i++)
12563 : : {
12564 : : int j;
12565 : 0 : OAD_PolymerUnit* u = OneInput.polymer->units[i];
12566 [ # # ]: 0 : for (j = 0; j < u->nbkbonds; j++)
12567 : : {
12568 : : int icano1, iorig1, icano2, iorig2;
12569 : 0 : icano1 = u->bkbonds[j][0];
12570 : 0 : iorig1 = orig[icano1];
12571 : 0 : icano2 = u->bkbonds[j][1];
12572 : 0 : iorig2 = orig[icano2];
12573 : :
12574 : 0 : all_bkb_orig[2 * (*n_all_bkb_orig)] = iorig1;
12575 : 0 : all_bkb_orig[2 * (*n_all_bkb_orig) + 1] = iorig2;
12576 : 0 : (*n_all_bkb_orig)++;
12577 : : }
12578 : : }
12579 : :
12580 : 0 : FreeInpInChI(&OneInput);
12581 : :
12582 : 0 : exit_function:
12583 : 0 : return ret;
12584 : : }
12585 : :
12586 : : #endif /* READ_INCHI_STRING */
|