Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <string.h>
7 : : #include <ctype.h>
8 : : #include <limits.h>
9 : : #include <locale.h>
10 : :
11 : : /* #define CHECK_WIN32_VC_HEAP */
12 : :
13 : : #include "mode.h"
14 : :
15 : : #if ( READ_INCHI_STRING == 1 )
16 : :
17 : : #include "ichierr.h"
18 : : #include "ichi.h"
19 : : #include "ichitime.h"
20 : : #include "ichidrp.h"
21 : : #include "inpdef.h"
22 : : #include "util.h"
23 : : #include "strutil.h"
24 : : #include "ichi_io.h"
25 : :
26 : : /* reverse InChI */
27 : : #include "ichimain.h"
28 : : #include "extr_ct.h"
29 : : #include "ichitaut.h"
30 : : #include "ichister.h"
31 : : #include "strutil.h"
32 : : #include "ichisize.h"
33 : : #include "ichiring.h"
34 : : #include "ichinorm.h"
35 : : #include "ichierr.h"
36 : : #include "ichicant.h"
37 : :
38 : : #include "ichirvrs.h"
39 : : #include "mol_fmt.h"
40 : :
41 : :
42 : : /* */
43 : : #if ( defined(TARGET_API_LIB) || defined(TARGET_EXE_STANDALONE) )
44 : : #include "inchi_api.h"
45 : : #endif
46 : : /* */
47 : :
48 : : #include "bcf_s.h"
49 : :
50 : : #define SEGM_LINE_ADD 128
51 : :
52 : : typedef struct tagOneLinkedBond
53 : : {
54 : : AT_NUMB neigh; /* canonical number of a neighbor */
55 : : AT_NUMB prev; /* position of the previous neighbor in the list */
56 : : } ONE_LINKED_BOND;
57 : :
58 : : typedef struct tagLinkedBonds
59 : : {
60 : : ONE_LINKED_BOND* pBond;
61 : : int len;
62 : : int len_alloc;
63 : : }LINKED_BONDS;
64 : : #define LINKED_BOND_ADD 128
65 : :
66 : : typedef enum tagModeProtonIsoExchgH
67 : : {
68 : : MODE_PIXH_UNDEFINED, /* 0 */
69 : : MODE_PIXH_ADD_TO_FIRST, /* 1 */
70 : : MODE_PIXH_ADD_TO_EACH, /* 2 */
71 : : MODE_PIXH_ADD_A_PIXH_COMPONENT, /* 3 */
72 : : MODE_PIXH_KEEP_TOTALS /* 4 */
73 : : } MODE_PIXH;
74 : :
75 : :
76 : : /* Local prototypes */
77 : : int InChILine2Data(INCHI_IOSTREAM* pInp,
78 : : SEGM_LINE* pLine,
79 : : char** pStr,
80 : : int* pState,
81 : : int* nErr,
82 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
83 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
84 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
85 : : int s[INCHI_NUM][TAUT_NUM][2],
86 : : int bReadCoord,
87 : : int bInchi2Struct,
88 : : INCHI_MODE nMode,
89 : : int* bStdFormat,
90 : : int* input_has_save_opt,
91 : : unsigned char* input_save_opt_bits,
92 : : OAD_Polymer** ppolymer,
93 : : OAD_V3000** pv3000);
94 : :
95 : : static int GetInChIFormulaNumH(INChI* pInChI, int* nNumH);
96 : : static int GetInChINumH(INChI* pInChI, int* nNumH);
97 : : static int GetInChIIsoH(INChI* pInChI, int nNumIsotopicH[NUM_H_ISOTOPES]);
98 : :
99 : : static int getInChIChar(INCHI_IOSTREAM* pInp);
100 : : static int AddInChIChar(INCHI_IOSTREAM* pInp, SEGM_LINE* Line, const char* pszToken);
101 : : static int AddLinkedBond(AT_NUMB at1, AT_NUMB at2, AT_NUMB num_at, LINKED_BONDS* pLB);
102 : : static int bInChIHasReconnectedMetal(INChI* pInChI);
103 : : static int SetProtonsAndXchgIsoH(int bInChI2Structure,
104 : : int bReqSplitOutputInChI,
105 : : int bReqProtonsForEachComponent,
106 : : int bReqNonTaut, int bReqStereo,
107 : : int num_components[INCHI_NUM],
108 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
109 : : InpInChI* OneInput);
110 : : #if ( FIX_DALKE_BUGS == 1 )
111 : : static int SetHillFormFromInChI(InpInChI* OneInput);
112 : : #endif
113 : :
114 : : static int nGetInChISegment(INCHI_IOSTREAM* pInp, SEGM_LINE* Line, const char* pszToken);
115 : :
116 : : static int CopySegment(INChI* pInChITo, INChI* pInChIFrom, int StereoType,
117 : : int bIsotopicTo, int bIsotopicFrom);
118 : : static int nFillOutProtonMobileH(INChI* pInChI);
119 : : static int nProtonCopyIsotopicInfo(INChI* pInChI_to, INChI* pInChI_from);
120 : : static int CopyAtomNumbers(INChI* pInChI_To, int bIsoTo, INChI* pInChI_From, int bIsoFrom);
121 : :
122 : : static int ParseSegmentFormula(const char* str, int bMobileH, INChI* pInpInChI[],
123 : : int nNumComponents[], int* na_total);
124 : : static int ParseSegmentConnections(const char* str, int bMobileH, INChI** pInpInChI,
125 : : int* pnNumComponents, int* pbAbc, int* nb_total);
126 : : static int ParseSegmentMobileH(const char* str, int bMobileH, INChI* pInpInChI[],
127 : : int pnNumComponents[], int* pbAbc);
128 : : static int ParseSegmentCharge(const char* str, int bMobileH, INChI* pInpInChI[],
129 : : int nNumComponents[]);
130 : : static int ParseSegmentProtons(const char* str, int bMobileH,
131 : : REM_PROTONS nNumProtons[], int nNumComponents[]);
132 : : static int ParseSegmentPolymer(const char* str, int bMobileH,
133 : : REM_PROTONS nNumProtons[], int nNumComponents[],
134 : : int na_total, int nb_total,
135 : : int bInchi2Struct,
136 : : OAD_Polymer** ppPolymer, OAD_V3000** ppV3000);
137 : : static int ParseSegmentSp2(const char* str, int bMobileH, INChI* pInpInChI[],
138 : : int nNumComponents[], int state, int* pbAbc);
139 : : static int ParseSegmentSp3(const char* str, int bMobileH, INChI* pInpInChI[],
140 : : int ppnNumComponents[], int state, int* pbAbc);
141 : : static int SegmentSp3CreateEmpty(const char* str, int bMobileH, INChI* pInpInChI[],
142 : : int nNumComponents, int state, int* pbAbc);
143 : : static int SegmentSp3StoreStereoCenters(int* pbAbc, const char* pStart, const char* pEnd,
144 : : int pInChI_iComponent_nNumberOfAtoms,
145 : : INChI_Stereo* PStereo_0);
146 : : static int SegmentSp3ProcessAbbreviation(int* mpy_component, int iComponent, int nNumComponents,
147 : : int val, const char* q, int state, int* pbAbc,
148 : : int bMobileH, int nCpyType,
149 : : INChI* pInChI, INChI* pInpInChI_ALT_TAUT_bMobileH);
150 : : static int SegmentSp3CopyMultiplierCovered(int mpy_component, int iComponent,
151 : : INChI* pInpInChI, int bIso, int nCpyType);
152 : : static int ParseSegmentSp3m(const char* str, int bMobileH, INChI* pInpInChI[],
153 : : int nNumComponents[], int state);
154 : : static int bIsSp3LayerNotEmpty(INChI* pInpInChI[], int bMobileH,
155 : : int bIso, int nNumComponents);
156 : : static int ParseSegmentSp3s(const char* str, int bMobileH, INChI* pInpInChI[],
157 : : int s[TAUT_NUM][2], int ppnNumComponents[], int state);
158 : : static int ParseSegmentIsoAtoms(const char* str, int bMobileH, INChI* pInpInChI[],
159 : : int nNumComponents[], int state, int* pbAbc);
160 : : static int ParseSegmentIsoExchgH(const char* str, int bMobileH,
161 : : REM_PROTONS nNumProtons[],
162 : : int nNumComponents[], int state, int* pbAbc);
163 : : static int ParseSegmentPerm(const char* str, int bMobileH, INChI* pInpInChI[],
164 : : int ppnNumComponents[], int state, int* pbAbc);
165 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
166 : : static int bIsoMayBeArranged(int bInchi2Struct, int iso_diff[NUM_H_ISOTOPES],
167 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
168 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM], int nNumComponents[INCHI_NUM][TAUT_NUM], int iINChI);
169 : : #endif
170 : :
171 : : static int ReadInChILine(INCHI_IOSTREAM* pInp,
172 : : SEGM_LINE* pLine,
173 : : char** pStr,
174 : : int* pState,
175 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
176 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
177 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
178 : : int s[INCHI_NUM][TAUT_NUM][2],
179 : : int* input_is_stdinchi,
180 : : int* input_has_save_opt,
181 : : unsigned char* input_save_opt_bits,
182 : : int bInchi2Struct,
183 : : OAD_Polymer** ppolymer,
184 : : OAD_V3000** pv3000);
185 : :
186 : : int ReadInChICoord(INCHI_IOSTREAM* pInp,
187 : : SEGM_LINE* pLine,
188 : : int* pState,
189 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
190 : : int nNumComponents[INCHI_NUM][TAUT_NUM]);
191 : :
192 : : static int OutputInChIAsRequested(struct tagCANON_GLOBALS* pCG,
193 : : INCHI_IOSTREAM* pOut,
194 : : INCHI_IOSTREAM* pLog,
195 : : ICHICONST INPUT_PARMS* ip_inp,
196 : : STRUCT_DATA* sd_inp,
197 : : InpInChI* OneInput,
198 : : int num_components[INCHI_NUM],
199 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
200 : : long num_inp,
201 : : unsigned char save_opt_bits);
202 : :
203 : : static int ParseAuxSegmentVersion(const char* str,
204 : : int bMobileH,
205 : : INChI* pInpInChI[],
206 : : int ppnNumComponents[],
207 : : int state);
208 : :
209 : : static int ParseAuxSegmentNumbers(const char* str,
210 : : int bMobileH,
211 : : INChI* pInpInChI[],
212 : : int ppnNumComponents[],
213 : : int state,
214 : : int* pbAbc);
215 : :
216 : : static int ParseAuxSegmentAtomEqu(const char* str,
217 : : int bMobileH,
218 : : INChI* pInpInChI[],
219 : : int ppnNumComponents[],
220 : : int state);
221 : :
222 : : static int ParseAuxSegmentGroupEqu(const char* str,
223 : : int bMobileH,
224 : : INChI* pInpInChI[],
225 : : int ppnNumComponents[],
226 : : int state);
227 : :
228 : : static int ParseAuxSegmentSp3Inv(const char* str,
229 : : int bMobileH,
230 : : INChI* pInpInChI[],
231 : : int ppnNumComponents[],
232 : : int state);
233 : :
234 : : static int ParseAuxSegmentSp3InvNumbers(const char* str,
235 : : int bMobileH,
236 : : INChI* pInpInChI[],
237 : : int ppnNumComponents[],
238 : : int state);
239 : :
240 : : static int ParseAuxSegmentReverseCRV(const char* str, int state);
241 : :
242 : : static int ParseAuxSegmentReverseAtoms(const char* str, int state);
243 : :
244 : : static int ParseAuxSegmentReverseBonds(const char* str, int state);
245 : :
246 : : static int ParseAuxSegmentReverseXYZ(const char* str,
247 : : XYZ_COORD** ppXYZ,
248 : : int state);
249 : :
250 : : static int AddAuxSegmentCoord(int nRet,
251 : : XYZ_COORD* pXYZ,
252 : : int nLenXYZ,
253 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
254 : : int nNumComponents[INCHI_NUM][TAUT_NUM]);
255 : :
256 : :
257 : : static void getInchiStateReadErr(int stat, char* szMsg);
258 : :
259 : : static const char* getInchiErrName(int nErr);
260 : :
261 : : static int extract_from_inchi_string(char* sinchi, InpInChI* OneInput);
262 : :
263 : : const char* ParseSegmentReadDelimitedNumbers(const char* str, const char* pEnd,
264 : : INT_ARRAY* numlist, char c_delim,
265 : : char c_stop, int* ret);
266 : :
267 : : #define SEG_END '/'
268 : : /* the following 2 definitions are used to allow tab-delimited InChI input - 2008-11-17 DT */
269 : : #define INCHI_INP_EOL(X) ((X)=='\n' || (X)=='\r' || (X)=='\t')
270 : : /*#define INCHI_TOKEN "/\n\r\t"*/
271 : : #define INCHI_TOKEN "/\n\r\t\\"
272 : :
273 : : typedef enum tagInChI_STATE
274 : : {
275 : : /* M */
276 : : IST_MOBILE_H_FORMULA, /* 0 */
277 : : IST_MOBILE_H_CONNECTIONS, /* 1 */
278 : : IST_MOBILE_H, /* 2 */
279 : : IST_MOBILE_H_CHARGE, /* 3 */
280 : : IST_MOBILE_H_PROTONS, /* 4 */
281 : : IST_MOBILE_H_SP2, /* 5 */
282 : : IST_MOBILE_H_SP3, /* 6 */
283 : : IST_MOBILE_H_SP3_M, /* 7 */
284 : : IST_MOBILE_H_SP3_S, /* 8 */
285 : :
286 : : /* Fork */
287 : : IST_MOBILE_H_ISO_LAYER_FORK, /* 9 */
288 : :
289 : : /* MI */
290 : : IST_MOBILE_H_ISO_ATOMS, /* 10 */
291 : : IST_MOBILE_H_ISO_EXCH_H, /* 11 */
292 : : IST_MOBILE_H_ISO_SP2, /* 12 */
293 : : IST_MOBILE_H_ISO_SP3, /* 13 */
294 : : IST_MOBILE_H_ISO_SP3_M, /* 14 */
295 : : IST_MOBILE_H_ISO_SP3_S, /* 15 */
296 : :
297 : : /* Fork */
298 : : IST_FIXED_H_LAYER_FORK, /* 16 */
299 : :
300 : : /* F */
301 : : IST_FIXED_H_FORMULA, /* 17 */
302 : : IST_FIXED_H, /* 18 */
303 : : IST_FIXED_H_CHARGE, /* 19 */
304 : : IST_FIXED_H_SP2, /* 20 */
305 : : IST_FIXED_H_SP3, /* 21 */
306 : : IST_FIXED_H_SP3_M, /* 22 */
307 : : IST_FIXED_H_SP3_S, /* 23 */
308 : : IST_FIXED_H_PERMUTATION, /* 24 */
309 : :
310 : : /* Fork */
311 : : IST_FIXED_H_ISO_LAYER_FORK, /* 25 */
312 : :
313 : : /* FI */
314 : : IST_FIXED_H_ISO_ATOMS, /* 26 */
315 : : IST_FIXED_H_ISO_LAYER, /* 27 */
316 : : IST_FIXED_H_ISO_SP2, /* 28 */
317 : : IST_FIXED_H_ISO_SP3, /* 29 */
318 : : IST_FIXED_H_ISO_SP3_M, /* 30 */
319 : : IST_FIXED_H_ISO_SP3_S, /* 31 */
320 : : IST_FIXED_H_ISO_PERMUTATION, /* 32 */
321 : :
322 : : /* Reconnected */
323 : : IST_RECONNECTED_LAYER_FORK, /* 33 */
324 : : IST_RECONNECTED_FORMULA, /* 34 */
325 : :
326 : : /* Other reading errors */
327 : : IST_MATERIAL_BALANCE_ERROR, /* 35 */
328 : :
329 : : /* */
330 : : IST_MOBILE_H_POLYMER, /* 36 */
331 : :
332 : : IST_END = -1
333 : : }INCHI_STATE;
334 : :
335 : :
336 : : #define IST_HAPPENED_IN_RECMET 100
337 : :
338 : :
339 : : typedef struct tagInchiReadErrMsg
340 : : {
341 : : int stat;
342 : : const char* msg;
343 : : } INCHI_READ_ERR_MSG;
344 : :
345 : : ICHICONST INCHI_READ_ERR_MSG irErrMsg[] =
346 : : {
347 : : /* M */
348 : : { IST_MOBILE_H_FORMULA, "MOBILE_H_FORMULA" },
349 : : { IST_MOBILE_H_CONNECTIONS, "MOBILE_H_CONNECTIONS" },
350 : : { IST_MOBILE_H, "MOBILE_H" },
351 : : { IST_MOBILE_H_CHARGE, "MOBILE_H_CHARGE" },
352 : : { IST_MOBILE_H_PROTONS, "MOBILE_H_PROTONS" },
353 : : { IST_MOBILE_H_SP2, "MOBILE_H_SP2" },
354 : : { IST_MOBILE_H_SP3, "MOBILE_H_SP3" },
355 : : { IST_MOBILE_H_SP3_M, "MOBILE_H_SP3_/m" },
356 : : { IST_MOBILE_H_SP3_S, "MOBILE_H_SP3_/s" },
357 : :
358 : : /* Fork */
359 : : { IST_MOBILE_H_ISO_LAYER_FORK, "MOBILE_H_ISO_LAYER_FORK" },
360 : :
361 : : /* MI */
362 : : { IST_MOBILE_H_ISO_ATOMS, "MOBILE_H_ISO_ATOMS" },
363 : : { IST_MOBILE_H_ISO_EXCH_H, "MOBILE_H_ISO_EXCH_H" },
364 : : { IST_MOBILE_H_ISO_SP2, "MOBILE_H_ISO_SP2" },
365 : : { IST_MOBILE_H_ISO_SP3, "MOBILE_H_ISO_SP3" },
366 : : { IST_MOBILE_H_ISO_SP3_M, "MOBILE_H_ISO_SP3_/m" },
367 : : { IST_MOBILE_H_ISO_SP3_S, "MOBILE_H_ISO_SP3_/s" },
368 : :
369 : : /* Fork */
370 : : { IST_FIXED_H_LAYER_FORK, "FIXED_H_LAYER_FORK" },
371 : :
372 : : /* F */
373 : : { IST_FIXED_H_FORMULA, "FIXED_H_FORMULA" },
374 : : { IST_FIXED_H, "FIXED_H" },
375 : : { IST_FIXED_H_CHARGE, "FIXED_H_CHARGE" },
376 : : { IST_FIXED_H_SP2, "FIXED_H_SP2" },
377 : : { IST_FIXED_H_SP3, "FIXED_H_SP3" },
378 : : { IST_FIXED_H_SP3_M, "FIXED_H_SP3_/m" },
379 : : { IST_FIXED_H_SP3_S, "FIXED_H_SP3_/s" },
380 : : { IST_FIXED_H_PERMUTATION, "FIXED_H_PERMUTATION" },
381 : :
382 : : /* Fork */
383 : : { IST_FIXED_H_ISO_LAYER_FORK, "FIXED_H_ISO_LAYER_FORK" },
384 : :
385 : : /* FI */
386 : : { IST_FIXED_H_ISO_ATOMS, "FIXED_H_ISO_ATOMS" },
387 : : { IST_FIXED_H_ISO_LAYER, "FIXED_H_ISO_LAYER" },
388 : : { IST_FIXED_H_ISO_SP2, "FIXED_H_ISO_SP2" },
389 : : { IST_FIXED_H_ISO_SP3, "FIXED_H_ISO_SP3" },
390 : : { IST_FIXED_H_ISO_SP3_M, "FIXED_H_ISO_SP3_m" },
391 : : { IST_FIXED_H_ISO_SP3_S, "FIXED_H_ISO_SP3_s" },
392 : : { IST_FIXED_H_ISO_PERMUTATION, "FIXED_H_ISO_PERMUTATION" },
393 : :
394 : : /* Reconnected */
395 : : { IST_RECONNECTED_LAYER_FORK, "RECONNECTED_LAYER_FORK" },
396 : : { IST_RECONNECTED_FORMULA, "RECONNECTED_FORMULA" },
397 : :
398 : : { IST_MATERIAL_BALANCE_ERROR, "MATERIAL_BALANCE" },
399 : :
400 : : { IST_MOBILE_H_POLYMER, "POLYMER_LAYER" },
401 : :
402 : : { IST_END, "Unknown Error" }
403 : : };
404 : :
405 : :
406 : :
407 : : typedef enum tagCopySegmentType
408 : : {
409 : : CPY_SP2,
410 : : CPY_SP3,
411 : : CPY_SP3_M,
412 : : CPY_SP3_S,
413 : : CPY_ISO_AT
414 : : } COPY_SEG_TYPE;
415 : :
416 : : #define NSTRLEN 524288
417 : : #define MAX_MSG_LEN 512
418 : : #define MAX_MSG_BUF_LEN 128
419 : :
420 : :
421 : : void PrepareSaveOptBits(INPUT_PARMS* ip,
422 : : INCHI_IOSTREAM* pLog,
423 : : const long num_inp,
424 : : const char* szCurHdr,
425 : : int input_has_save_opt,
426 : : unsigned char input_save_opt_bits,
427 : : unsigned char* save_opt_bits);
428 : :
429 : : void TreatErrorsInReadInChIString(int nReadStatus,
430 : : int nErr,
431 : : int pState,
432 : : INPUT_PARMS* ip,
433 : : INCHI_IOSTREAM* pOut,
434 : : INCHI_IOSTREAM* pLog,
435 : : long* num_inp,
436 : : long* num_errors,
437 : : long* num_processed,
438 : : char** pstrHdr,
439 : : char** pszCurHdr,
440 : : InpInChI* pOneInput);
441 : :
442 : : int ConvertInChI2Struct(ICHICONST INPUT_PARMS* ip_inp,
443 : : INPUT_PARMS* ip,
444 : : InpInChI* pOneInput,
445 : : inp_ATOM** at,
446 : : int* num_at,
447 : : OAD_Polymer** polymer,
448 : : OAD_V3000** v3000,
449 : : INCHI_IOSTREAM* pOut,
450 : : INCHI_IOSTREAM* pLog,
451 : : STRUCT_DATA* sd,
452 : : int num_components[INCHI_NUM],
453 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
454 : : char** pszCurHdr,
455 : : char* szMsg,
456 : : int nMsgLen,
457 : : char szMessage[MAX_MSG_LEN],
458 : : int nInitLenMessage,
459 : : int nMessageLen,
460 : : int input_is_stdinchi,
461 : : int bHasSomeReconnected,
462 : : int bHasSomeFixedH,
463 : : int bHasMetal,
464 : : int nModeFlagsStereo,
465 : : int bTautFlags,
466 : : int bReqNonTaut,
467 : : unsigned long WarningFlags[2][2],
468 : : long num_inp,
469 : : long* num_errors,
470 : : unsigned char save_opt_bits,
471 : : inchiTime* pulTStart,
472 : : long* ulProcessingTime,
473 : : struct tagINCHI_CLOCK* ic,
474 : : struct tagCANON_GLOBALS* pCG);
475 : :
476 : : int ConvertInChI2InChI(INPUT_PARMS* ip,
477 : : InpInChI* pOneInput,
478 : : INCHI_IOSTREAM* pOut,
479 : : INCHI_IOSTREAM* pLog,
480 : : STRUCT_DATA* sd,
481 : : int num_components[INCHI_NUM],
482 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
483 : : char** pszCurHdr,
484 : : long num_inp,
485 : : long* num_errors,
486 : : unsigned char save_opt_bits,
487 : : inchiTime* pulTStart,
488 : : long* ulProcessingTime,
489 : : struct tagINCHI_CLOCK* ic,
490 : : struct tagCANON_GLOBALS* pCG);
491 : :
492 : : int DetectAndExposePolymerInternals(INCHI_IOSTREAM* is);
493 : :
494 : : int DetectHiddenPolymerStuff(char* tmpstr, int tmpstrlen,
495 : : int* ninsert, int* insert_pos,
496 : : int insert_lead_offset, int* nstars);
497 : :
498 : :
499 : :
500 : : /****************************************************************************/
501 : 2 : void getInchiStateReadErr(int stat, char* szMsg)
502 : : /* const char *getInchiStateReadErr(int stat) */
503 : : {
504 : 2 : int i, bRecMet = 0;
505 : :
506 [ - + ]: 2 : if (stat >= IST_HAPPENED_IN_RECMET)
507 : : {
508 : 0 : bRecMet = 1;
509 : 0 : stat -= IST_HAPPENED_IN_RECMET;
510 : : }
511 [ + - + + ]: 14 : for (i = 0; 0 <= irErrMsg[i].stat && stat != irErrMsg[i].stat; i++)
512 : : {
513 : : ;
514 : : }
515 [ - + ]: 2 : sprintf(szMsg,
516 : : #if ( FIX_DALKE_BUGS == 1 )
517 : : "%s%.100s",
518 : : #else
519 : : "%s%s",
520 : : #endif
521 : 2 : irErrMsg[i].msg, bRecMet ? ", Reconnected layer" : "");
522 : :
523 : 2 : }
524 : :
525 : :
526 : : /****************************************************************************/
527 : 2 : const char* getInchiErrName(int nErr)
528 : : {
529 [ - - + - : 2 : switch (nErr)
- ]
530 : : {
531 : 0 : case RI_ERR_ALLOC:
532 : 0 : return "Allocation failed";
533 : 0 : case RI_ERR_PROGR:
534 : 0 : return "Program error";
535 : 2 : case RI_ERR_SYNTAX:
536 : 2 : return "Syntax error";
537 : 0 : case RI_ERR_EOL:
538 : 0 : return "End of line";
539 : : }
540 : 0 : return "Unknown error";
541 : : }
542 : :
543 : :
544 : : #if ( FIX_DALKE_BUGS == 1 )
545 : :
546 : :
547 : : /****************************************************************************/
548 : 0 : int SetHillFormFromInChI(InpInChI* OneInput)
549 : : {
550 : : int iINChI, iTaut, iComp, num_diff;
551 : : INChI* pINChI;
552 : : char* szHillFormulaOld;
553 [ # # ]: 0 : for (iINChI = 0, num_diff = 0; iINChI < INCHI_NUM; iINChI++)
554 : : {
555 [ # # ]: 0 : for (iTaut = TAUT_NON; iTaut < TAUT_NUM; iTaut++)
556 : : {
557 [ # # ]: 0 : for (iComp = 0; iComp < OneInput->nNumComponents[iINChI][iTaut]; iComp++)
558 : : {
559 : 0 : pINChI = &OneInput->pInpInChI[iINChI][iTaut][iComp];
560 [ # # # # : 0 : if (!pINChI->nNumberOfAtoms || pINChI->bDeleted || !pINChI->szHillFormula || !pINChI->szHillFormula[0])
# # # # ]
561 : : {
562 : 0 : continue;
563 : : }
564 : 0 : szHillFormulaOld = pINChI->szHillFormula;
565 : 0 : pINChI->szHillFormula = AllocateAndFillHillFormula(pINChI);
566 [ # # # # : 0 : num_diff += !pINChI->szHillFormula || !pINChI->szHillFormula[0] || strcmp(pINChI->szHillFormula, szHillFormulaOld);
# # ]
567 [ # # ]: 0 : inchi_free(szHillFormulaOld);
568 : : }
569 : : }
570 : : }
571 : :
572 : 0 : return num_diff;
573 : : }
574 : : #endif
575 : :
576 : :
577 : : /****************************************************************************
578 : : Main entry point
579 : : ****************************************************************************/
580 : 2 : int ReadWriteInChI(INCHI_CLOCK* ic,
581 : : struct tagCANON_GLOBALS* pCG,
582 : : INCHI_IOSTREAM* pInp,
583 : : INCHI_IOSTREAM* pOut,
584 : : INCHI_IOSTREAM* pLog,
585 : : INPUT_PARMS* ip_inp,
586 : : STRUCT_DATA* sd_inp,
587 : : /* the following are InChI library-specific parameters */
588 : : inp_ATOM** at,
589 : : int* num_at,
590 : : int* num_bonds,
591 : : OAD_Polymer** polymer,
592 : : OAD_V3000** v3000,
593 : : /* end of InChI library-specific parameters */
594 : : char* szMsg,
595 : : int nMsgLen,
596 : : unsigned long WarningFlags[2][2])
597 : : {
598 : : InpInChI OneInput;
599 : 2 : char* strHdr = NULL;
600 : 2 : char* szCurHdr = NULL;
601 : : int num_components[INCHI_NUM];
602 [ - + ]: 2 : int bReqNonTaut = (0 != ((ip_inp->nMode & REQ_MODE_BASIC) &&
603 [ # # ]: 0 : (ip_inp->nMode & REQ_MODE_TAUT)));
604 : : /*
605 : : int bReqRecmet = (0 != ((ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
606 : : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD)));
607 : : */
608 : 2 : int bReqStereo = (0 != (ip_inp->nMode & REQ_MODE_STEREO));
609 : 2 : int bHasSomeReconnected = 0, bHasSomeFixedH = 0, bHasMetal = 0;
610 : 2 : int nModeFlagsStereo = 0, bTautFlags = 0; /* InChI creation flags modifications derived from current InChI */
611 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM];
612 : :
613 : : NORM_CANON_FLAGS ncFlags;
614 : 2 : NORM_CANON_FLAGS* pncFlags = &ncFlags;
615 : : INPUT_PARMS ip_cur, * ip;
616 : : STRUCT_DATA sd_cur, * sd;
617 : :
618 : : int pState; /* djb-rwth: removing redundant variables */
619 : 2 : int bReqProtonsForEachComponent = 0;
620 : 2 : int bReqSplitOutputInChI = 0;
621 : : SEGM_LINE Line;
622 : 2 : SEGM_LINE* pLine = &Line;
623 : 2 : long ulProcessingTime = 0;
624 : : inchiTime ulTStart;
625 : 2 : long num_processed = 0, num_errors = 0;
626 : : int bPlainTabbedOutput; /* djb-rwth: ignoring LLVM warning: variable used */
627 : : const char* pTAB; /* djb-rwth: ignoring LLVM warning: variable used */
628 : :
629 : 2 : long num_inp = 0;
630 : :
631 : 2 : int read_inchi_ok = 0;
632 : 2 : int end_of_data_reached = 0;
633 : 2 : int treat_save_opt = 0;
634 : 2 : int input_is_stdinchi = 0;
635 : 2 : int input_has_save_opt = 0;
636 : 2 : unsigned char input_save_opt_bits = 0;
637 : 2 : unsigned char save_opt_bits = 0;
638 : :
639 : 2 : const int bInChI2Structure = 0 != (ip_inp->bReadInChIOptions & READ_INCHI_TO_STRUCTURE);
640 : 2 : const int bInChI2InChI = 0 != (ip_inp->bReadInChIOptions & READ_INCHI_OUTPUT_INCHI);
641 : 2 : const int bReadCoord = bInChI2Structure;
642 : :
643 : 2 : int nMessageLen = MAX_MSG_LEN;
644 : : char szMessage[MAX_MSG_LEN];
645 : : int nInitLenMessage;
646 : 2 : int invalid_opt = 0;
647 : : int j, nErr, iINChI;
648 : :
649 : 2 : int treat_mismatch_as_error = ip_inp->bINChIOutputOptions2 & INCHI_OUT_MISMATCH_AS_ERROR;
650 : 2 : int output_error_inchi = ip_inp->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR;
651 : :
652 : 2 : int ret = 0;
653 : 2 : int nReadStatus = RI_ERR_EOL;
654 : :
655 : 2 : INCHI_IOSTREAM* pRealOut = pOut;
656 : : /* temporary output buffer pTmpOut may be used */
657 : : /* locally instead of legal pOut to capture */
658 : : /* InChI string which may then be recognised */
659 : : /* as erratic (whence should not be finally */
660 : : /* printed) */
661 : : INCHI_IOSTREAM tmpoutputstr;
662 : 2 : INCHI_IOSTREAM* pTmpOut = &tmpoutputstr;
663 [ + + ]: 2 : if (bInChI2Structure)
664 : : {
665 : 1 : inchi_ios_init(pTmpOut, INCHI_IOS_TYPE_STRING, NULL);
666 [ - + ]: 1 : if (pTmpOut->s.pStr)
667 : 0 : pRealOut = pTmpOut;
668 : : }
669 : :
670 : : #ifdef GHI100_FIX
671 : : #if ((SPRINTF_FLAG != 1) && (SPRINTF_FLAG != 2))
672 : : setlocale(LC_ALL, "en-US"); /* djb-rwth: setting all locales to "en-US" */
673 : : #endif
674 : : #endif
675 : :
676 : 2 : memset(szMessage, 0, sizeof(szMessage)); /* djb-rwth: memset_s C11/Annex K variant? */
677 : 2 : memset(&OneInput, 0, sizeof(OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
678 : 2 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
679 [ + - ]: 2 : if (szMsg)
680 : 2 : szMsg[0] = '\0';
681 : :
682 : 2 : OneInput.polymer = NULL; /* v. 1.05 added */
683 : 2 : OneInput.v3000 = NULL;
684 : :
685 : :
686 : : /* Read input, InChI by InChI*/
687 [ + - ]: 2 : while (nReadStatus != RI_ERR_EOF)
688 : : {
689 [ + + ]: 6 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
690 : : {
691 [ + + ]: 12 : for (j = 0; j < TAUT_NUM; j++)
692 : : {
693 [ - + ]: 8 : if (OneInput.nNumProtons[iINChI][j].pNumProtons)
694 : : {
695 [ # # ]: 0 : inchi_free(OneInput.nNumProtons[iINChI][j].pNumProtons);
696 : 0 : OneInput.nNumProtons[iINChI][j].pNumProtons = NULL;
697 : : }
698 : : }
699 : : }
700 : :
701 : 2 : memset(&OneInput, 0, sizeof(OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
702 : 2 : memset(pncFlags, 0, sizeof(*pncFlags)); /* djb-rwth: memset_s C11/Annex K variant? */
703 : : /* djb-rwth: removing redundant code */
704 : 2 : ip_cur = *ip_inp;
705 : 2 : ip = &ip_cur;
706 : 2 : sd_cur = *sd_inp;
707 : 2 : sd = &sd_cur;
708 : :
709 : 2 : bReqSplitOutputInChI =
710 : 2 : 0 != (ip->bReadInChIOptions & READ_INCHI_SPLIT_OUTPUT);
711 : 2 : bReqProtonsForEachComponent =
712 [ - + ]: 2 : bReqSplitOutputInChI &&
713 [ # # ]: 0 : 0 != (READ_INCHI_KEEP_BALANCE_P & ip->bReadInChIOptions);
714 : 2 : bPlainTabbedOutput =
715 : 2 : 0 != (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT);
716 : :
717 : 2 : pTAB =
718 : : #if ( defined(TARGET_API_LIB) || defined(TARGET_LIB_FOR_WINCHI) )
719 : : "\n";
720 : : #else
721 : : bPlainTabbedOutput ? "\t" : "\n";
722 : : #endif
723 : :
724 : :
725 [ + + ]: 2 : if (bInChI2Structure)
726 : : {
727 : 1 : bReqStereo = 1;
728 : 1 : bReqSplitOutputInChI = 1;
729 : 1 : bReqProtonsForEachComponent = bReqNonTaut;
730 : 1 : ip->bTautFlags |= (TG_FLAG_DISCONNECT_COORD | TG_FLAG_RECONNECT_COORD);
731 : 1 : ip->nMode |= (REQ_MODE_BASIC | REQ_MODE_TAUT | REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_ISO);
732 : : /* bReqRecmet = 1; */
733 : : #if ( bRELEASE_VERSION == 1 )
734 : 1 : bReqNonTaut = 1; /* bReqNonTaut=0 ignores Fixed-H layer in input InChI, for testing only */
735 : : #endif
736 : : /* polymer stuff added */
737 [ + - ]: 1 : if (pInp->type == INCHI_IOS_TYPE_STRING)
738 : : {
739 : : int res; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
740 : :
741 [ - + ]: 1 : if (ip_inp->lMolfileNumber)
742 : : /* get here from inchi-1 main emulation mode */
743 : 0 : num_inp = ip_inp->lMolfileNumber - 1;
744 : :
745 : 1 : res = DetectAndExposePolymerInternals(pInp); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
746 : : /* proceed silently for now, errs mist be uncovered further on conversion */
747 : : }
748 : : }
749 : :
750 : 2 : InchiTimeGet(&ulTStart);
751 : :
752 : : /* Read InChI string */
753 : 2 : nReadStatus = InChILine2Data(pInp, pLine, &strHdr, &pState, &nErr,
754 : : OneInput.pInpInChI, OneInput.nNumComponents,
755 : : OneInput.nNumProtons, OneInput.s,
756 : : bReadCoord, bInChI2Structure, ip_inp->nMode,
757 : : &input_is_stdinchi, &input_has_save_opt,
758 : : &input_save_opt_bits,
759 : : &OneInput.polymer, &OneInput.v3000);
760 : :
761 : 2 : ulProcessingTime += InchiTimeElapsed(ic, &ulTStart);
762 : :
763 : : #if 0
764 : : if (!bInChI2Structure && OneInput.polymer)
765 : : {
766 : : /* inchi2inchi for polymers: for now skip */
767 : : pState == IST_MOBILE_H_POLYMER;
768 : : nReadStatus = -2;
769 : : }
770 : : #endif
771 : :
772 : :
773 [ + - - + ]: 2 : end_of_data_reached = nReadStatus == RI_ERR_EOL || nReadStatus == RI_ERR_EOF;
774 : :
775 [ + + ]: 2 : if (!bInChI2Structure)
776 : : {
777 : : /* i2i, disable polymer related */
778 [ - + ]: 1 : if (OneInput.polymer)
779 : : {
780 : 0 : pState = IST_MOBILE_H_POLYMER;
781 : 0 : nErr = RI_ERR_PROGR;
782 : : }
783 : : }
784 : :
785 [ - + - - ]: 2 : read_inchi_ok = end_of_data_reached && !nErr;
786 : :
787 : : /* then uncommented... commented out 2020-07-10 (potentially dangerous change, needs testing (TODO: i2s for InChI=1// )*/
788 [ - + ]: 2 : read_inchi_ok = read_inchi_ok &&
789 [ # # ]: 0 : (OneInput.nNumComponents[INCHI_BAS][TAUT_YES] + OneInput.nNumComponents[INCHI_BAS][TAUT_NON]);
790 : :
791 : : #if ALLOW_EMPTY_INCHI_AS_INPUT!=1
792 : : /* no empty InChI allowed */
793 : : read_inchi_ok = read_inchi_ok &&
794 : : (OneInput.nNumComponents[INCHI_BAS][TAUT_YES] +
795 : : OneInput.nNumComponents[INCHI_BAS][TAUT_NON]);
796 : : #endif
797 : : #ifdef TARGET_EXE_STANDALONE
798 : : /* inchi-1: we currently disable conversion of polymeric InChI (inchi2struct)
799 : : to anything but SDF (would it be necessary in the future?) */
800 : : if (OneInput.polymer &&
801 : : bInChI2Structure &&
802 : : !(ip_inp->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
803 : : {
804 : : read_inchi_ok = 0;
805 : : nErr = RI_ERR_PROGR;
806 : : }
807 : : #endif
808 : :
809 [ + - ]: 2 : if (!read_inchi_ok)
810 : : {
811 : 2 : TreatErrorsInReadInChIString(nReadStatus, nErr, pState, ip_inp, pRealOut, pLog,
812 : : &num_inp, &num_errors, &num_processed,
813 : : &strHdr, &szCurHdr, &OneInput);
814 [ - + - - ]: 2 : if (nReadStatus == RI_ERR_SYNTAX || nReadStatus == RI_ERR_PROGR)
815 : : {
816 : 2 : ret = nReadStatus;
817 : : }
818 : : }
819 : : else
820 : : {
821 : : /* InChI has been successfully read */
822 : 0 : ret = 0;
823 : 0 : num_inp++;
824 : 0 : ip->lMolfileNumber = num_inp;
825 : 0 : bHasSomeReconnected = 0;
826 : 0 : bHasSomeFixedH = 0;
827 : :
828 [ # # ]: 0 : if (pRealOut == pTmpOut)
829 : : {
830 : 0 : inchi_ios_reset(pRealOut);
831 : : /*inchi_ios_close( pRealOut );
832 : : inchi_ios_init( pRealOut, INCHI_IOS_TYPE_STRING, NULL );*/
833 : : }
834 : : /* inchi_ios_print( pRealOut, ""); */
835 : :
836 : : /* Does not allow conversion non-standard->standard */
837 : : /* (force target to be non-standard also) */
838 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_STDINCHI)
839 : : {
840 [ # # ]: 0 : if (!input_is_stdinchi)
841 : : {
842 : : /* Input InChI is a non-standard one */
843 : 0 : ip->bINChIOutputOptions &= ~INCHI_OUT_STDINCHI;
844 : : /*
845 : : if (szCurHdr && szCurHdr[0])
846 : : inchi_ios_eprint( pLog, "Warning: forced conversion to non-standard InChI for non-std input, %s\n", szCurHdr );
847 : : else
848 : : inchi_ios_eprint( pLog, "Warning: forced conversion to non-standard InChI for non-std input, Structure %ld\n", num_inp );
849 : : */
850 : : }
851 : : }
852 : :
853 : :
854 : 0 : treat_save_opt = ip->bINChIOutputOptions & INCHI_OUT_SAVEOPT;
855 : :
856 [ # # ]: 0 : if (treat_save_opt)
857 : : {
858 : 0 : PrepareSaveOptBits(ip, pLog, num_inp, szCurHdr,
859 : : input_has_save_opt,
860 : : input_save_opt_bits,
861 : : &save_opt_bits);
862 : : }
863 : :
864 : : #ifndef TARGET_API_LIB
865 : : /*
866 : : inchi_ios_eprint(stderr, "%ld: %s\r", num_inp, strHdr? strHdr : "");
867 : : inchi_ios_eprint(pLog, "%ld: %s\n", num_inp, strHdr? strHdr : "");
868 : : */
869 : :
870 : : if (!ip->bNoStructLabels &&
871 : : !(bInChI2Structure && (ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
872 : : )
873 : : {
874 : : /* Added 2nd item: Do not output this extra line into the output SDfile. 2008-11-17 DCh */
875 : : if (strHdr && strstr(strHdr, "Structure:"))
876 : : {
877 : : inchi_ios_print(pRealOut, "%s%s", strHdr, pTAB); /* output header */
878 : : #if ( FIX_DALKE_BUGS == 1 )
879 : : #else
880 : : sprintf(szMessage, "%s (%ld)", strHdr ? strHdr : "", num_inp);
881 : : #endif
882 : : }
883 : : else
884 : : {
885 : : if (bInChI2Structure) inchi_ios_print(pRealOut, "Structure: %ld. (%s)%s",
886 : : num_inp, strHdr ? strHdr : "No struct name",
887 : : pTAB); /* output header */
888 : : #if ( FIX_DALKE_BUGS == 1 )
889 : : #else
890 : : sprintf(szMessage, "Structure: %ld. (%s)%s", num_inp, strHdr ? strHdr : "No struct name", pTAB);
891 : : #endif
892 : : }
893 : : if (strHdr && strHdr[0])
894 : : {
895 : : strncpy(ip->szSdfDataHeader, strHdr, sizeof(ip->szSdfDataHeader));
896 : : ip->szSdfDataHeader[sizeof(ip->szSdfDataHeader) - 1] = '\0';
897 : : ip->pSdfLabel = NULL;
898 : : ip->pSdfValue = ip->szSdfDataHeader;
899 : : }
900 : : else
901 : : {
902 : : ip->pSdfValue = NULL;
903 : : ip->szSdfDataHeader[0] = '\0';
904 : : }
905 : : }
906 : :
907 : : #if ( FIX_DALKE_BUGS == 1 )
908 : : sprintf(szMessage, "%ld: %.400s", num_inp, strHdr ? strHdr : "");
909 : : #else
910 : : sprintf(szMessage, "%ld: %s", num_inp, strHdr ? strHdr : "");
911 : : #endif
912 : : #endif
913 : :
914 : 0 : nInitLenMessage = (int)strlen(szMessage);
915 [ # # ]: 0 : if (strHdr)
916 : : {
917 : 0 : szCurHdr = strHdr;
918 : 0 : strHdr = NULL;
919 : : }
920 [ # # # # : 0 : if (szCurHdr && ip && ip->first_struct_number > 0)
# # ]
921 : : {
922 : : /* Check whether the structure should be skipped */
923 : : static const char szStruct[] = "Structure:";
924 : 0 : char* pStrNum = strstr(szCurHdr, szStruct);
925 : : long cur_struct_number;
926 [ # # ]: 0 : if (pStrNum)
927 : : {
928 : 0 : pStrNum += sizeof(szStruct) - 1; /* -1 takes care of the string terminal zero */
929 : 0 : cur_struct_number = inchi_strtol(pStrNum, NULL, 10);
930 [ # # ]: 0 : if (cur_struct_number)
931 : : {
932 : 0 : OneInput.num_inp = cur_struct_number;
933 : : }
934 : : /* Process request to bypass first several InChIs */
935 [ # # # # ]: 0 : if (cur_struct_number > 0 && cur_struct_number < ip->first_struct_number)
936 : : {
937 : :
938 : : #if ( !defined(TARGET_API_LIB) && !defined(TARGET_EXE_STANDALONE) )
939 : : inchi_fprintf(stderr, "Skipping %s\r", szMessage);
940 : : #endif
941 : 0 : FreeInpInChI(&OneInput);
942 [ # # ]: 0 : if (szCurHdr)
943 : : {
944 [ # # ]: 0 : inchi_free(szCurHdr);
945 : 0 : szCurHdr = NULL;
946 : : }
947 : : INCHI_HEAPCHK
948 : 0 : continue;
949 : : }
950 : : }
951 : : }
952 : :
953 : 0 : num_processed++;
954 : :
955 : : /* In case of splitting InChI into separate components */
956 : : /* decide whether to keep /p in each component or */
957 : : /* output /p and /i/h as a separate component */
958 : : /* Note: if InChI is not to be splitted DO NOT create */
959 : : /* a separate component for /p, /i/h: it would be a bug*/
960 : :
961 : 0 : InchiTimeGet(&ulTStart);
962 : :
963 : : INCHI_HEAPCHK
964 : :
965 : 0 : ret = SetProtonsAndXchgIsoH(bInChI2Structure, bReqSplitOutputInChI,
966 : : bReqProtonsForEachComponent, bReqNonTaut, bReqStereo,
967 : : num_components, nModeProtonIsoExchgH, &OneInput);
968 : : INCHI_HEAPCHK
969 : :
970 [ # # ]: 0 : if (ret < 0)
971 : : {
972 : 0 : num_errors++;
973 : 0 : goto exit_error;
974 : : }
975 : :
976 : 0 : sd->num_components[INCHI_BAS] = num_components[INCHI_BAS];
977 : 0 : sd->num_components[INCHI_REC] = num_components[INCHI_REC];
978 : :
979 : : /* Do we have reconnected InChI ? */
980 [ # # ]: 0 : if ((OneInput.nNumComponents[INCHI_REC][TAUT_YES] ||
981 [ # # ]: 0 : OneInput.nNumComponents[INCHI_REC][TAUT_NON]) &&
982 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
983 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD)
984 : : )
985 : : {
986 : : /* needed for InChI string output to include reconnected InChI */
987 : 0 : sd->bTautFlagsDone[0] |= TG_FLAG_DISCONNECT_COORD_DONE;
988 : 0 : bHasSomeReconnected = 1;
989 : : }
990 : :
991 : : /* Do we have fixed H InChI ? */
992 [ # # ]: 0 : if (bReqNonTaut &&
993 : : /*OneInput.nNumComponents[bHasSomeReconnected?INCHI_REC:INCHI_BAS][TAUT_NON]*/
994 [ # # ]: 0 : (OneInput.nNumComponents[INCHI_REC][TAUT_NON] ||
995 [ # # ]: 0 : OneInput.nNumComponents[INCHI_BAS][TAUT_NON]))
996 : : {
997 : 0 : bHasSomeFixedH = 1;
998 : : }
999 : :
1000 : 0 : ulProcessingTime += InchiTimeElapsed(ic, &ulTStart);
1001 : :
1002 [ # # # # : 0 : invalid_opt = (!bInChI2Structure && !bInChI2InChI) ||
# # ]
1003 [ # # ]: 0 : (bInChI2Structure && bInChI2InChI);
1004 : :
1005 [ # # ]: 0 : if (invalid_opt)
1006 : : {
1007 : 0 : inchi_ios_eprint(pLog, "\nWrong command line options: expected Inch2Struct or Inchi2Inchi\n", num_inp);
1008 : 0 : break;
1009 : : }
1010 : :
1011 : : /* InChI --> Structure */
1012 [ # # ]: 0 : else if (bInChI2Structure)
1013 : : {
1014 : : char* result_string;
1015 : :
1016 [ # # # # ]: 0 : if (OneInput.polymer && OneInput.polymer->n)
1017 : : {
1018 : 0 : OneInput.valid_polymer = 1;
1019 : : }
1020 : :
1021 : 0 : ret = ConvertInChI2Struct(ip_inp, ip, &OneInput,
1022 : : at, num_at,
1023 : : polymer, v3000,
1024 : : pRealOut, pLog,
1025 : : sd, num_components, nModeProtonIsoExchgH,
1026 : : &szCurHdr, szMsg, nMsgLen, szMessage,
1027 : : nInitLenMessage, nMessageLen,
1028 : : input_is_stdinchi, bHasSomeReconnected,
1029 : : bHasSomeFixedH, bHasMetal,
1030 : : nModeFlagsStereo, bTautFlags, bReqNonTaut,
1031 : : WarningFlags, num_inp, &num_errors,
1032 : : save_opt_bits, &ulTStart, &ulProcessingTime,
1033 : : ic, pCG);
1034 : :
1035 : 0 : result_string = pRealOut->s.pStr;
1036 [ # # ]: 0 : if (ret == 0) /* no problems */
1037 : : {
1038 : : ;
1039 : : }
1040 [ # # ]: 0 : else if (ret > 0)
1041 : : {
1042 : : /* error */
1043 [ # # ]: 0 : if (output_error_inchi)
1044 : : {
1045 : : /* emit error string */
1046 : 0 : inchi_ios_eprint(pRealOut, "InChI creation Error!\n");
1047 : : }
1048 : : }
1049 [ # # ]: 0 : else if (ret < 0)
1050 : : {
1051 : : /* error or a mismatch possibly treated as error */
1052 [ # # ]: 0 : if (ret != RI_ERR_MISMATCH)
1053 : : {
1054 : 0 : goto exit_error;
1055 : : }
1056 : : else
1057 : : {
1058 [ # # ]: 0 : if (!treat_mismatch_as_error)
1059 : : {
1060 : : /* ignore mismatch, print InChI as usual */
1061 [ # # ]: 0 : if (result_string)
1062 : : {
1063 : 0 : inchi_ios_eprint(pRealOut, "%-s\n", result_string);
1064 : : }
1065 : : }
1066 : : else
1067 : : {
1068 : : /* concider mismatch an error */
1069 [ # # ]: 0 : if (!output_error_inchi)
1070 : : {
1071 : : ; /* print nothing for now*/
1072 : : }
1073 : : else
1074 : : {
1075 : : /* emit err string instead of InChI */
1076 [ # # ]: 0 : if (result_string)
1077 : : {
1078 : : /* try to preserve header if any */
1079 : 0 : char* pi = strstr(result_string, "InChI=");
1080 [ # # ]: 0 : if (pi)
1081 : : {
1082 : 0 : int np = pi - result_string;
1083 [ # # ]: 0 : if (np)
1084 : 0 : result_string[np - 1] = '\0';
1085 : 0 : inchi_ios_eprint(pRealOut, "%-s\n", result_string);
1086 : : }
1087 : : }
1088 : 0 : inchi_ios_eprint(pRealOut, "InChICreationError!\n"); /* emit err string */
1089 : : }
1090 : : }
1091 : 0 : FreeInpInChI(&OneInput);
1092 [ # # ]: 0 : if (strHdr)
1093 : : {
1094 [ # # ]: 0 : inchi_free(strHdr);
1095 : 0 : strHdr = NULL;
1096 : : }
1097 [ # # ]: 0 : if (szCurHdr)
1098 : : {
1099 [ # # ]: 0 : inchi_free(szCurHdr);
1100 : 0 : szCurHdr = NULL;
1101 : : }
1102 : : INCHI_HEAPCHK
1103 : 0 : continue;
1104 : : }
1105 : : }
1106 : : } /* ( bInChI2Structure ) */
1107 : :
1108 : :
1109 : : /* InChI --> InChI */
1110 [ # # ]: 0 : else if (bInChI2InChI)
1111 : : {
1112 : 0 : ret = ConvertInChI2InChI(ip, &OneInput, pRealOut, pLog, sd,
1113 : : num_components, nModeProtonIsoExchgH,
1114 : : &szCurHdr, num_inp, &num_errors,
1115 : : save_opt_bits, &ulTStart,
1116 : : &ulProcessingTime, ic, pCG);
1117 : : }
1118 : :
1119 [ # # ]: 0 : if (nReadStatus == RI_ERR_EOF)
1120 : : #if ( FIX_ONE_LINE_INCHI_INPUT_CONVERSION_ISSUE==1 && defined(TARGET_EXE_STANDALONE) && !defined(TARGET_API_LIB) )
1121 : : {
1122 : : inchi_ios_flush(pRealOut);
1123 : : inchi_ios_flush2(pLog, stderr);
1124 : : break;
1125 : : }
1126 : : #else
1127 : 0 : break;
1128 : : #endif
1129 : : } /* InChI has been successfully read */
1130 : :
1131 : :
1132 : : #ifdef TARGET_EXE_STANDALONE
1133 : : #ifndef TARGET_API_LIB
1134 : : inchi_ios_flush(pRealOut);
1135 : : inchi_ios_flush2(pLog, stderr);
1136 : : #endif
1137 : : #endif
1138 : : #ifdef TARGET_API_LIB
1139 : 2 : break; /* exit after the 1st structure */
1140 : : #endif
1141 : : } /* while */
1142 : :
1143 : 0 : exit_error:
1144 : 2 : FreeInpInChI(&OneInput);
1145 [ - + ]: 2 : if (strHdr)
1146 : : {
1147 [ # # ]: 0 : inchi_free(strHdr);
1148 : 0 : strHdr = NULL;
1149 : : }
1150 [ + - ]: 2 : if (pLine->str)
1151 : : {
1152 [ + - ]: 2 : inchi_free(pLine->str);
1153 : : }
1154 [ - + ]: 2 : if (szCurHdr)
1155 : : {
1156 [ # # ]: 0 : inchi_free(szCurHdr);
1157 : 0 : szCurHdr = NULL;
1158 : : }
1159 : :
1160 : : INCHI_HEAPCHK
1161 : :
1162 [ + - ]: 2 : if (sd_inp)
1163 : : {
1164 : 2 : sd_inp->ulStructTime = ulProcessingTime;
1165 : 2 : sd_inp->fPtrStart = num_processed;
1166 : 2 : sd_inp->fPtrEnd = num_errors;
1167 : : }
1168 [ - + ]: 2 : if (pRealOut == pTmpOut)
1169 : : {
1170 : 0 : inchi_ios_close(pTmpOut);
1171 : : }
1172 : :
1173 : 2 : return ret;
1174 : : }
1175 : :
1176 : :
1177 : : /****************************************************************************/
1178 : 0 : int OutputInChIAsRequested(struct tagCANON_GLOBALS* pCG,
1179 : : INCHI_IOSTREAM* pOut,
1180 : : INCHI_IOSTREAM* pLog,
1181 : : ICHICONST INPUT_PARMS* ip_inp,
1182 : : STRUCT_DATA* sd_inp,
1183 : : InpInChI* OneInput,
1184 : : int num_components[INCHI_NUM],
1185 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
1186 : : long num_inp,
1187 : : unsigned char save_opt_bits)
1188 : : {
1189 : 0 : int j, k, k1, k2, ret2 = 0, iINChI, iINChI1; /* djb-rwth: removing redundant variables */
1190 : : PINChI2* pINChI[INCHI_NUM], * newPTR1;
1191 : : PINChI_Aux2* pINChI_Aux[INCHI_NUM], * newPTR2;
1192 : : int bReqNonTaut;
1193 : : int bHasSomeReconnected;
1194 : :
1195 : : INPUT_PARMS ip_local;
1196 : : STRUCT_DATA sd_local;
1197 : 0 : INPUT_PARMS* ip = &ip_local;
1198 : 0 : STRUCT_DATA* sd = &sd_local;
1199 : : NORM_CANON_FLAGS ncFlags;
1200 : 0 : NORM_CANON_FLAGS* pncFlags = &ncFlags;
1201 : : int nRet1, bSortPrintINChIFlags;
1202 : : int bReqSplitOutputInChI;
1203 : : int nNumOutputComponents;
1204 : :
1205 : : INCHI_IOS_STRING temp_string_container;
1206 : 0 : INCHI_IOS_STRING* strbuf = &temp_string_container;
1207 : 0 : memset(strbuf, 0, sizeof(*strbuf)); /* djb-rwth: memset_s C11/Annex K variant? */
1208 : :
1209 [ # # ]: 0 : if (0 >= inchi_strbuf_init(strbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT))
1210 : : {
1211 : 0 : ret2 = RI_ERR_ALLOC;
1212 : 0 : goto exit_error;
1213 : : }
1214 : :
1215 : 0 : nRet1 = 0;
1216 : 0 : k1 = k2 = 0;
1217 : 0 : memset(pncFlags, 0, sizeof(*pncFlags)); /* djb-rwth: memset_s C11/Annex K variant? */
1218 : 0 : memset(pINChI, 0, sizeof(pINChI)); /* djb-rwth: memset_s C11/Annex K variant? */
1219 : 0 : memset(pINChI_Aux, 0, sizeof(pINChI_Aux)); /* djb-rwth: memset_s C11/Annex K variant? */
1220 : :
1221 : 0 : *ip = *ip_inp;
1222 : 0 : *sd = *sd_inp;
1223 : 0 : bHasSomeReconnected = 0;
1224 : 0 : bSortPrintINChIFlags = 0;
1225 : : /* djb-rwth: removing redundant code */
1226 : 0 : bReqNonTaut = (0 != (ip->nMode & REQ_MODE_BASIC));
1227 : 0 : bReqSplitOutputInChI = (0 != (ip->bReadInChIOptions & READ_INCHI_SPLIT_OUTPUT));
1228 : :
1229 : : INCHI_HEAPCHK
1230 : :
1231 [ # # ]: 0 : if (num_components[INCHI_BAS])
1232 : : {
1233 : : /* 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 */
1234 : :
1235 : : do {
1236 : : if ((num_components[INCHI_BAS]) <= ((long long)num_components[INCHI_BAS]))
1237 : : {
1238 : 0 : newPTR1 = (PINChI2*)inchi_calloc(((long long)num_components[INCHI_BAS]) + 1, sizeof(PINChI2));
1239 : 0 : newPTR2 = (PINChI_Aux2*)inchi_calloc(((long long)num_components[INCHI_BAS]) + 1, sizeof(PINChI_Aux2));
1240 [ # # # # ]: 0 : if (newPTR1 && newPTR2) {
1241 [ # # # # ]: 0 : if ((pINChI[INCHI_BAS]) && (num_components[INCHI_BAS]) > 0)
1242 : 0 : memcpy(newPTR1, (pINChI[INCHI_BAS]), (num_components[INCHI_BAS]) * sizeof(PINChI2));
1243 [ # # # # ]: 0 : if ((pINChI_Aux[INCHI_BAS]) && (num_components[INCHI_BAS]) > 0)
1244 : 0 : memcpy(newPTR2, (pINChI_Aux[INCHI_BAS]), (num_components[INCHI_BAS]) * sizeof(PINChI_Aux2));
1245 [ # # ]: 0 : if (pINChI[INCHI_BAS])
1246 [ # # ]: 0 : inchi_free(pINChI[INCHI_BAS]);
1247 [ # # ]: 0 : if (pINChI_Aux[INCHI_BAS])
1248 [ # # ]: 0 : inchi_free(pINChI_Aux[INCHI_BAS]);
1249 : 0 : pINChI[INCHI_BAS] = newPTR1;
1250 : 0 : pINChI_Aux[INCHI_BAS] = newPTR2;
1251 : 0 : num_components[INCHI_BAS] = (long long)num_components[INCHI_BAS];
1252 : 0 : k1 = 0;
1253 : : }
1254 : : else
1255 : : {
1256 [ # # ]: 0 : inchi_free(newPTR1);
1257 [ # # ]: 0 : inchi_free(newPTR2);
1258 : 0 : k1 = 1;
1259 : : }
1260 : : }
1261 : : else { k1 = 0; }
1262 : : } while (0);
1263 : : }
1264 : :
1265 [ # # ]: 0 : if (num_components[INCHI_REC])
1266 : : {
1267 : : /* 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 */
1268 : :
1269 : : do {
1270 : : if ((num_components[INCHI_REC]) <= ((long long)num_components[INCHI_REC]))
1271 : : {
1272 : 0 : newPTR1 = (PINChI2*)inchi_calloc(((long long)num_components[INCHI_REC]) + 1, sizeof(PINChI2));
1273 : 0 : newPTR2 = (PINChI_Aux2*)inchi_calloc(((long long)num_components[INCHI_REC]) + 1, sizeof(PINChI_Aux2));
1274 [ # # # # ]: 0 : if (newPTR1 && newPTR2) {
1275 [ # # # # ]: 0 : if ((pINChI[INCHI_REC]) && (num_components[INCHI_REC]) > 0)
1276 : 0 : memcpy(newPTR1, (pINChI[INCHI_REC]), (num_components[INCHI_REC]) * sizeof(PINChI2));
1277 [ # # # # ]: 0 : if ((pINChI_Aux[INCHI_REC]) && (num_components[INCHI_REC]) > 0)
1278 : 0 : memcpy(newPTR2, (pINChI_Aux[INCHI_REC]), (num_components[INCHI_REC]) * sizeof(PINChI_Aux2));
1279 [ # # ]: 0 : if (pINChI[INCHI_REC])
1280 [ # # ]: 0 : inchi_free(pINChI[INCHI_REC]);
1281 [ # # ]: 0 : if (pINChI_Aux[INCHI_REC])
1282 [ # # ]: 0 : inchi_free(pINChI_Aux[INCHI_REC]);
1283 : 0 : pINChI[INCHI_REC] = newPTR1;
1284 : 0 : pINChI_Aux[INCHI_REC] = newPTR2;
1285 : 0 : num_components[INCHI_REC] = (long long)num_components[INCHI_REC];
1286 : 0 : k2 = 0;
1287 : : }
1288 : : else
1289 : : {
1290 [ # # ]: 0 : inchi_free(newPTR1);
1291 [ # # ]: 0 : inchi_free(newPTR2);
1292 : 0 : k2 = 1;
1293 : : }
1294 : : }
1295 : : else { k2 = 0; }
1296 : : } while (0);
1297 : : }
1298 : :
1299 : :
1300 : : INCHI_HEAPCHK
1301 : :
1302 [ # # # # ]: 0 : if (k1 || k2 /*|| !pStr*/)
1303 : : {
1304 : : /* djb-rwth: avoiding memory leak */
1305 : 0 : free(pINChI[INCHI_BAS]);
1306 : 0 : free(pINChI_Aux[INCHI_BAS]);
1307 : 0 : free(pINChI[INCHI_REC]);
1308 : 0 : free(pINChI_Aux[INCHI_REC]);
1309 : 0 : ret2 = RI_ERR_ALLOC;
1310 : 0 : goto exit_error;
1311 : : }
1312 : :
1313 [ # # ]: 0 : if (num_components[INCHI_REC] &&
1314 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_RECONNECT_COORD) &&
1315 [ # # ]: 0 : (ip->bTautFlags & TG_FLAG_DISCONNECT_COORD))
1316 : : {
1317 : 0 : sd->bTautFlagsDone[0] |= TG_FLAG_DISCONNECT_COORD_DONE;
1318 : 0 : bHasSomeReconnected = 1;
1319 : : }
1320 : :
1321 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1322 : : {
1323 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1324 : : {
1325 [ # # # # : 0 : if (bReqNonTaut || (j != TAUT_NON && OneInput->pInpInChI[iINChI][j])) /* djb-rwth: addressing LLVM warning */
# # ]
1326 : : {
1327 [ # # ]: 0 : for (k = 0; k < num_components[iINChI]; k++)
1328 : : {
1329 : : /* allocate InChI & AuxInfo */
1330 [ # # ]: 0 : if (!(pINChI[iINChI][k][j] = (INChI*)inchi_calloc(1, sizeof(INChI))))
1331 : : {
1332 : : /* djb-rwth: avoiding memory leak */
1333 : 0 : free(pINChI[INCHI_BAS]);
1334 : 0 : free(pINChI_Aux[INCHI_BAS]);
1335 : 0 : free(pINChI[INCHI_REC]);
1336 : 0 : free(pINChI_Aux[INCHI_REC]);
1337 : 0 : ret2 = RI_ERR_ALLOC;
1338 : 0 : goto exit_error;
1339 : : }
1340 [ # # ]: 0 : if (!(pINChI_Aux[iINChI][k][j] = (INChI_Aux*)inchi_calloc(1, sizeof(INChI_Aux))))
1341 : : {
1342 : : /* djb-rwth: avoiding memory leak */
1343 : 0 : free(pINChI[INCHI_BAS]);
1344 : 0 : free(pINChI_Aux[INCHI_BAS]);
1345 : 0 : free(pINChI[INCHI_REC]);
1346 : 0 : free(pINChI_Aux[INCHI_REC]);
1347 : 0 : ret2 = RI_ERR_ALLOC;
1348 : 0 : goto exit_error;
1349 : : }
1350 : : /* copy InChI & AuxInfo */
1351 [ # # ]: 0 : if (k < OneInput->nNumComponents[iINChI][j])
1352 : : {
1353 : :
1354 : : /* copy InChI */
1355 : 0 : *pINChI[iINChI][k][j] = OneInput->pInpInChI[iINChI][j][k];
1356 : 0 : memset(&OneInput->pInpInChI[iINChI][j][k], 0, sizeof(OneInput->pInpInChI[iINChI][j][k])); /* djb-rwth: memset_s C11/Annex K variant? */
1357 : : INCHI_HEAPCHK
1358 : : /* take care of protons in AuxInfo */
1359 : :
1360 [ # # # # ]: 0 : if (nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_EACH && j == TAUT_YES)
1361 : : {
1362 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedProtons =
1363 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons[k].nNumRemovedProtons;
1364 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
1365 : : {
1366 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedIsotopicH[k1] =
1367 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons[k].nNumRemovedIsotopicH[k1];
1368 : : }
1369 : : INCHI_HEAPCHK
1370 : : }
1371 [ # # # # ]: 0 : else if ((!k && nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_FIRST) ||
1372 [ # # ]: 0 : (k + 1 == OneInput->nNumComponents[iINChI][j] &&
1373 [ # # ]: 0 : nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_A_PIXH_COMPONENT)) /* djb-rwth: addressing LLVM warnings */
1374 : : {
1375 : : /* add protons and exchangeable isotopic H to the first component's AuxInfo */
1376 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedProtons = OneInput->nNumProtons[iINChI][j].nNumRemovedProtons;
1377 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
1378 : : {
1379 : 0 : pINChI_Aux[iINChI][k][j]->nNumRemovedIsotopicH[k1] =
1380 : 0 : OneInput->nNumProtons[iINChI][j].nNumRemovedIsotopicH[k1];
1381 : : }
1382 : : INCHI_HEAPCHK
1383 : : }
1384 : : else
1385 : : {
1386 : 0 : pINChI_Aux[iINChI][k][j]->bDeleted = pINChI[iINChI][k][j]->bDeleted;
1387 : : }
1388 : :
1389 [ # # # # : 0 : if (j == TAUT_YES && pINChI[iINChI][k][j] && pINChI[iINChI][k][j]->nNumberOfAtoms &&
# # ]
1390 [ # # ]: 0 : !pINChI[iINChI][k][j]->nNum_H_fixed)
1391 : : {
1392 : : /* serializer crashes if it is not allocated */
1393 : 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 */
1394 : : }
1395 : :
1396 [ # # # # ]: 0 : if (j == TAUT_YES && k < OneInput->nNumComponents[iINChI][TAUT_NON] &&
1397 [ # # # # ]: 0 : pINChI[iINChI][k][j] && pINChI[iINChI][k][j]->nNumberOfAtoms &&
1398 [ # # # # : 0 : pINChI[iINChI][k][TAUT_NON] && pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms &&
# # ]
1399 : 0 : !CompareReversedINChI(pINChI[iINChI][k][j], pINChI[iINChI][k][TAUT_NON], NULL, NULL))
1400 : : {
1401 : 0 : pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms = 0; /* eliminate non-taut equal to taut */
1402 : : }
1403 : : }
1404 : : else
1405 : : {
1406 : : /* extra component, usually it is a Mobile H component */
1407 : : /* corresponding to a free proton component in Fixed H */
1408 : 0 : pINChI[iINChI][k][j]->bDeleted = 1;
1409 : 0 : pINChI_Aux[iINChI][k][j]->bDeleted = 1;
1410 : : }
1411 : : } /* k */
1412 : : } /* if ( bReqNonTaut || j != TAUT_NON && OneInput->pInpInChI[iINChI][j] ) */
1413 : :
1414 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j])
1415 : : {
1416 : : INCHI_HEAPCHK
1417 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
1418 : 0 : OneInput->pInpInChI[iINChI][j] = NULL;
1419 : : }
1420 : : } /* j */
1421 : : } /* iINChI */
1422 : :
1423 [ # # ]: 0 : if (bReqSplitOutputInChI)
1424 : : {
1425 [ # # ]: 0 : if (bHasSomeReconnected)
1426 : : {
1427 : 0 : iINChI1 = INCHI_REC; /* only reconnected */
1428 : : /* djb-rwth: removing redundant code */
1429 : 0 : sd->num_components[INCHI_BAS] = sd->num_components[INCHI_REC];
1430 : : }
1431 : : else
1432 : : {
1433 : 0 : iINChI1 = 0; /* only disconnected */
1434 : : /* djb-rwth: removing redundant code */
1435 : : }
1436 : 0 : sd->num_components[INCHI_REC] = 0; /* treat reconnected as connected */
1437 : 0 : nNumOutputComponents = sd->num_components[INCHI_BAS];
1438 : : }
1439 : : else
1440 : : {
1441 : 0 : iINChI1 = 0;
1442 : : /* djb-rwth: removing redundant code */
1443 : 0 : nNumOutputComponents = 1;
1444 : : }
1445 : :
1446 [ # # # # : 0 : for (k1 = 0, k2 = (bReqSplitOutputInChI ? k1 + 1 : nNumOutputComponents); k1 < k2 && k1 < nNumOutputComponents; k1 = k2, k2++)
# # ]
1447 : : {
1448 : :
1449 [ # # ]: 0 : if (bReqSplitOutputInChI)
1450 : : {
1451 : 0 : sd->num_components[INCHI_BAS] = 1;
1452 : 0 : sd->num_components[INCHI_REC] = 0;
1453 : : /* additional data */
1454 : 0 : sd->num_non_taut[INCHI_BAS] =
1455 : 0 : sd->num_taut[INCHI_BAS] =
1456 : 0 : sd->num_non_taut[INCHI_REC] =
1457 : 0 : sd->num_taut[INCHI_REC] = 0;
1458 : 0 : iINChI = iINChI1;
1459 [ # # # # ]: 0 : for (j = 0; j < TAUT_NUM && sd->num_components[iINChI]; j++)
1460 : : {
1461 [ # # ]: 0 : for (k = k1; k < k2; k++)
1462 : : {
1463 : : /* find where the current processed structure is located */
1464 [ # # # # ]: 0 : int cur_is_in_non_taut = (pINChI[iINChI][k][TAUT_NON] && pINChI[iINChI][k][TAUT_NON]->nNumberOfAtoms > 0);
1465 [ # # # # ]: 0 : int cur_is_in_taut = (pINChI[iINChI][k][TAUT_YES] && pINChI[iINChI][k][TAUT_YES]->nNumberOfAtoms > 0);
1466 [ # # # # : 0 : int cur_is_non_taut = (cur_is_in_non_taut && 0 == pINChI[iINChI][k][TAUT_NON]->lenTautomer) ||
# # ]
1467 [ # # ]: 0 : (cur_is_in_taut && 0 == pINChI[iINChI][k][TAUT_YES]->lenTautomer); /* djb-rwth: addressing LLVM warnings */
1468 [ # # # # ]: 0 : int cur_is_taut = cur_is_in_taut && 0 < pINChI[iINChI][k][TAUT_YES]->lenTautomer;
1469 [ # # ]: 0 : if (cur_is_non_taut + cur_is_taut)
1470 : : {
1471 : : /* count tautomeric and non-tautomeric components of the structures */
1472 : : /*
1473 : : int j1 = cur_is_in_non_taut? TAUT_NON:TAUT_YES;
1474 : : int j2 = cur_is_in_taut? TAUT_YES:TAUT_NON;
1475 : : */
1476 : 0 : sd->num_non_taut[INCHI_BAS] += cur_is_non_taut;
1477 : 0 : sd->num_taut[INCHI_BAS] += cur_is_taut;
1478 : : }
1479 : : }
1480 : : }
1481 : : INCHI_HEAPCHK
1482 : : }
1483 : : else
1484 : : {
1485 : 0 : sd->num_components[INCHI_BAS] = inchi_max(OneInput->nNumComponents[INCHI_BAS][TAUT_YES],
1486 : : OneInput->nNumComponents[INCHI_BAS][TAUT_NON]);
1487 : 0 : sd->num_components[INCHI_REC] = inchi_max(OneInput->nNumComponents[INCHI_REC][TAUT_YES],
1488 : : OneInput->nNumComponents[INCHI_REC][TAUT_NON]);
1489 : : /* additional data needed for SortAndPrintINChI() */
1490 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1491 : : {
1492 : 0 : sd->num_non_taut[iINChI] =
1493 : 0 : sd->num_taut[iINChI] = 0;
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[iINChI] += cur_is_non_taut;
1512 : 0 : sd->num_taut[iINChI] += cur_is_taut;
1513 : : }
1514 : : }
1515 : : }
1516 : : }
1517 : : INCHI_HEAPCHK
1518 : : }
1519 [ # # ]: 0 : if (bReqSplitOutputInChI)
1520 : : {
1521 : : /* output components one by one (for splitting input InChI into components) */
1522 : : PINChI2* pInChI_2[INCHI_NUM];
1523 : : PINChI_Aux2* pInChI_Aux_2[INCHI_NUM];
1524 : : INChI* pInChI_1[1][2];
1525 : : INChI_Aux* pInChI_Aux_1[1][2];
1526 : 0 : memset(pInChI_2, 0, sizeof(pInChI_2)); /* djb-rwth: memset_s C11/Annex K variant? */
1527 : 0 : memset(pInChI_Aux_2, 0, sizeof(pInChI_Aux_2)); /* djb-rwth: memset_s C11/Annex K variant? */
1528 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1529 : : {
1530 : 0 : pInChI_1[0][j] = pINChI[iINChI1][k1][j];
1531 : 0 : pInChI_Aux_1[0][j] = pINChI_Aux[iINChI1][k1][j];
1532 : : }
1533 : 0 : pInChI_2[INCHI_BAS] = pInChI_1;
1534 : 0 : pInChI_Aux_2[INCHI_BAS] = pInChI_Aux_1;
1535 : : /* make sure purely reconnected InChI is marked as ReChI, not InChI */
1536 [ # # # # ]: 0 : if (bHasSomeReconnected &&
1537 [ # # ]: 0 : (bInChIHasReconnectedMetal(pInChI_1[0][TAUT_YES]) ||
1538 : 0 : bInChIHasReconnectedMetal(pInChI_1[0][TAUT_NON])))
1539 : : {
1540 : 0 : bSortPrintINChIFlags = FLAG_SORT_PRINT_ReChI_PREFIX;
1541 : : }
1542 : : else
1543 : : {
1544 : 0 : bSortPrintINChIFlags = 0;
1545 : : }
1546 : : INCHI_HEAPCHK
1547 : 0 : nRet1 = SortAndPrintINChI(pCG, pOut, strbuf, pLog, ip,
1548 : : NULL /*orig_inp_data*/,
1549 : : NULL /*prep_inp_data*/,
1550 : : NULL /*composite_norm_data*/,
1551 : : NULL /*pOrigStruct*/,
1552 : 0 : sd->num_components, sd->num_non_taut,
1553 : 0 : sd->num_taut, sd->bTautFlags,
1554 : 0 : sd->bTautFlagsDone, pncFlags, num_inp,
1555 : : pInChI_2, pInChI_Aux_2,
1556 : : &bSortPrintINChIFlags, save_opt_bits);
1557 : : INCHI_HEAPCHK
1558 : : }
1559 : : else
1560 : : {
1561 : : INCHI_HEAPCHK
1562 : :
1563 : 0 : bSortPrintINChIFlags = 0;
1564 : 0 : nRet1 = SortAndPrintINChI(pCG, pOut, strbuf, pLog, ip,
1565 : : NULL /*orig_inp_data*/, NULL /*prep_inp_data*/,
1566 : : NULL /*composite_norm_data*/, NULL /*pOrigStruct*/,
1567 : 0 : sd->num_components, sd->num_non_taut, sd->num_taut,
1568 : 0 : sd->bTautFlags, sd->bTautFlagsDone, pncFlags, num_inp,
1569 : : pINChI, pINChI_Aux, &bSortPrintINChIFlags,
1570 : : save_opt_bits);
1571 : : INCHI_HEAPCHK
1572 : : }
1573 [ # # # # ]: 0 : if (nRet1 == _IS_FATAL || nRet1 == _IS_ERROR)
1574 : : {
1575 : : break;
1576 : : }
1577 : : }
1578 : :
1579 : : INCHI_HEAPCHK
1580 : 0 : FreeAllINChIArrays(pINChI, pINChI_Aux, num_components);
1581 : : INCHI_HEAPCHK
1582 : :
1583 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1584 : : {
1585 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
1586 : : {
1587 [ # # ]: 0 : if (OneInput->nNumProtons[iINChI][j].pNumProtons)
1588 : : {
1589 [ # # ]: 0 : inchi_free(OneInput->nNumProtons[iINChI][j].pNumProtons);
1590 : 0 : OneInput->nNumProtons[iINChI][j].pNumProtons = NULL;
1591 : : }
1592 : : }
1593 : : }
1594 : :
1595 : : INCHI_HEAPCHK
1596 : :
1597 [ # # # # ]: 0 : if (nRet1 == _IS_FATAL || nRet1 == _IS_ERROR)
1598 : : {
1599 : 0 : ret2 = RI_ERR_PROGR;
1600 : : }
1601 : :
1602 : 0 : exit_error:
1603 : :
1604 : 0 : inchi_strbuf_close(strbuf);
1605 : :
1606 : 0 : return ret2;
1607 : : }
1608 : :
1609 : :
1610 : : /****************************************************************************/
1611 : 0 : int GetNumNeighborsFromInchi(INChI* pInChI, AT_NUMB nAtNumber)
1612 : : {
1613 : : int i, j, n_vertex, n_neigh, nNumNeigh, bTautAtom, nNumH, nTotNumNeigh, num_atoms;
1614 : : AT_NUMB taut_at_number;
1615 : 0 : nAtNumber -= 1;
1616 : 0 : nNumNeigh = 0; /* number of bonds */
1617 : 0 : bTautAtom = 0; /* 1 if atom belongs to a Mobile-H group */
1618 : 0 : nNumH = 0; /* number of terminal neighbors H */
1619 : 0 : num_atoms = 0; /* djb-rwth: initialisation with pInChI below */
1620 : :
1621 [ # # ]: 0 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
1622 : : {
1623 : 0 : num_atoms = pInChI->nNumberOfAtoms;
1624 : : /* from RestoreAtomConnectionsSetStereo() */
1625 : : /* Connection table structure:
1626 : : Vert(1) [, Neigh(11), Neigh(12),...], Vert(2) [, Neigh(2,1), Neigh(2,2),...] ...
1627 : : where Neigh(i,1) < Neigh(i,2) <... < Vert(i);
1628 : : Vert(i) < Vert(i+1)
1629 : : */
1630 [ # # ]: 0 : for (i = 1, n_vertex = pInChI->nConnTable[0] - 1; i < pInChI->lenConnTable; i++)
1631 : : {
1632 [ # # ]: 0 : if ((n_neigh = pInChI->nConnTable[i] - 1) < n_vertex)
1633 : : {
1634 : : /* vertex - neighbor connection */
1635 [ # # # # ]: 0 : nNumNeigh += (nAtNumber == n_vertex || nAtNumber == n_neigh);
1636 : : }
1637 : : else
1638 : : {/* n_neigh is the next vertex */
1639 [ # # ]: 0 : if ((n_vertex = n_neigh) >= num_atoms)
1640 : : {
1641 : 0 : return RI_ERR_PROGR;
1642 : : }
1643 : : }
1644 : : }
1645 : : }
1646 : :
1647 : :
1648 : : /* is atom tautomeric, from GetTgroupInfoFromInChI() */
1649 [ # # # # : 0 : if (pInChI && pInChI->lenTautomer > 1 && pInChI->nTautomer && pInChI->nTautomer[0] > 0)
# # # # ]
1650 : : {
1651 : : int itg, len_tg;
1652 : 0 : int tot_len_tg = pInChI->lenTautomer - T_GROUP_HDR_LEN * pInChI->nTautomer[0] - 1; /* number of endpoints */
1653 : 0 : j = 1; /* index in pInChI->nTautomer[] */
1654 : 0 : i = 0; /* index in ti->nEndpointAtomNumber[] */
1655 [ # # ]: 0 : for (itg = 0; itg < pInChI->nTautomer[0]; itg++)
1656 : : {
1657 : 0 : len_tg = pInChI->nTautomer[j]; /* t-group length not including pInChI->nTautomer[j] */
1658 : 0 : j += T_GROUP_HDR_LEN; /* skip t-group header */
1659 : 0 : len_tg -= T_GROUP_HDR_LEN - 1;
1660 [ # # ]: 0 : for (; 0 < len_tg--; j++, i++)
1661 : : {
1662 : 0 : taut_at_number = pInChI->nTautomer[j] - 1; /* Mobile-H group atom number */
1663 : 0 : bTautAtom += (taut_at_number == nAtNumber);
1664 : : }
1665 : : }
1666 [ # # ]: 0 : if (i != tot_len_tg)
1667 : : {
1668 : 0 : return RI_ERR_PROGR;
1669 : : }
1670 : : }
1671 : : /* count hydrogen neighbors */
1672 [ # # # # ]: 0 : if (pInChI && pInChI->nNum_H) /* djb-rwth: condition added for fixing a NULL pointer dereference */
1673 : : {
1674 : 0 : nNumH = pInChI->nNum_H[nAtNumber];
1675 : : }
1676 : : /* conclusion: if not tautomeric then return positive number, otherwise add 1000 */
1677 : 0 : nTotNumNeigh = nNumNeigh + nNumH;
1678 [ # # ]: 0 : if (bTautAtom)
1679 : : {
1680 : 0 : nTotNumNeigh += 1000;
1681 : : }
1682 : 0 : return nTotNumNeigh;
1683 : :
1684 : : }
1685 : :
1686 : :
1687 : : /****************************************************************************/
1688 : 0 : int CountStereoTypes(INChI* pInChI,
1689 : : int* num_known_SB,
1690 : : int* num_known_SC,
1691 : : int* num_unk_und_SB,
1692 : : int* num_unk_und_SC,
1693 : : int* num_SC_PIII,
1694 : : int* num_SC_AsIII)
1695 : : {
1696 : : INChI_Stereo* Stereo;
1697 : : int i, ret;
1698 : : AT_NUMB nAtNumber;
1699 : : U_CHAR el_number;
1700 : :
1701 [ # # # # ]: 0 : if (!pInChI->nNumberOfAtoms || pInChI->bDeleted)
1702 : : {
1703 : 0 : return 0; /* no InChI */
1704 : : }
1705 : 0 : Stereo = (pInChI->StereoIsotopic &&
1706 : 0 : (pInChI->StereoIsotopic->nNumberOfStereoBonds +
1707 [ # # # # ]: 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters)) ? pInChI->StereoIsotopic :
1708 : 0 : (pInChI->Stereo &&
1709 : 0 : (pInChI->Stereo->nNumberOfStereoBonds +
1710 [ # # # # ]: 0 : pInChI->Stereo->nNumberOfStereoCenters)) ? pInChI->Stereo : NULL;
1711 [ # # ]: 0 : if (!Stereo)
1712 : : {
1713 : 0 : return 1; /* No Stereo */
1714 : : }
1715 : :
1716 : : /* count SB and cumulenes */
1717 [ # # ]: 0 : for (i = 0; i < Stereo->nNumberOfStereoBonds; i++)
1718 : : {
1719 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(Stereo->b_parity[i]))
1720 : : {
1721 : 0 : (*num_known_SB)++;
1722 : : }
1723 : : else
1724 : : {
1725 : 0 : (*num_unk_und_SB)++;
1726 : : }
1727 : : }
1728 : : /* count SC and allenes */
1729 [ # # ]: 0 : for (i = 0; i < Stereo->nNumberOfStereoCenters; i++)
1730 : : {
1731 [ # # # # ]: 0 : if (!(nAtNumber = Stereo->nNumber[i]) || nAtNumber > pInChI->nNumberOfAtoms)
1732 : : {
1733 : 0 : return RI_ERR_PROGR; /* wrong data, should never happen */
1734 : : }
1735 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(Stereo->t_parity[i]))
1736 : : {
1737 : 0 : (*num_known_SC)++;
1738 : : }
1739 : : else
1740 : : {
1741 : 0 : (*num_unk_und_SC)++;
1742 : : }
1743 : 0 : el_number = pInChI->nAtom[nAtNumber - 1];
1744 [ # # # # ]: 0 : if (el_number != EL_NUMBER_P && el_number != EL_NUMBER_AS)
1745 : : {
1746 : 0 : continue;
1747 : : }
1748 : 0 : ret = GetNumNeighborsFromInchi(pInChI, nAtNumber);
1749 [ # # ]: 0 : if (ret < 0)
1750 : : {
1751 : 0 : return ret;
1752 : : }
1753 [ # # ]: 0 : if (3 == ret)
1754 : : {
1755 : 0 : *num_SC_PIII += (EL_NUMBER_P == el_number);
1756 : 0 : *num_SC_AsIII += (EL_NUMBER_AS == el_number);
1757 : : }
1758 : : }
1759 : :
1760 : 0 : return 2; /* Has Stereo */
1761 : : }
1762 : :
1763 : :
1764 : : /****************************************************************************/
1765 : 0 : int bInpInchiComponentExists(InpInChI* pOneInput,
1766 : : int iInChI,
1767 : : int bMobileH,
1768 : : int k)
1769 : : {
1770 [ # # # # : 0 : if ((INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
# # ]
1771 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1772 : : {
1773 : 0 : return 0;
1774 : : }
1775 : :
1776 : 0 : return (k < pOneInput->nNumComponents[iInChI][bMobileH] &&
1777 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH] &&
1778 [ # # # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].nNumberOfAtoms > 0 &&
1779 [ # # ]: 0 : !pOneInput->pInpInChI[iInChI][bMobileH][k].bDeleted);
1780 : : }
1781 : :
1782 : :
1783 : : /****************************************************************************/
1784 : 0 : int bInpInchiComponentDeleted(InpInChI* pOneInput,
1785 : : int iInChI,
1786 : : int bMobileH,
1787 : : int k)
1788 : : {
1789 [ # # # # : 0 : if ((INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
# # ]
1790 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1791 : : {
1792 : 0 : return 0;
1793 : : }
1794 : :
1795 : 0 : return (k < pOneInput->nNumComponents[iInChI][bMobileH] &&
1796 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH] &&
1797 [ # # # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].nNumberOfAtoms > 0 &&
1798 [ # # ]: 0 : pOneInput->pInpInChI[iInChI][bMobileH][k].bDeleted);
1799 : : }
1800 : :
1801 : :
1802 : : /****************************************************************************/
1803 : 0 : int bRevInchiComponentExists(StrFromINChI* pStruct,
1804 : : int iInChI,
1805 : : int bMobileH,
1806 : : int k)
1807 : : {
1808 [ # # # # : 0 : if (!pStruct || /*!pStruct->at2 ||*/ !pStruct->num_atoms ||
# # ]
1809 [ # # # # ]: 0 : (INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
1810 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1811 : : {
1812 : 0 : return 0;
1813 : : }
1814 : :
1815 : 0 : return (k < pStruct->RevInChI.num_components[iInChI] &&
1816 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI] &&
1817 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH] &&
1818 [ # # # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->nNumberOfAtoms > 0 &&
1819 [ # # ]: 0 : !pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->bDeleted);
1820 : : }
1821 : :
1822 : :
1823 : : /****************************************************************************/
1824 : 0 : int bRevInchiComponentDeleted(StrFromINChI* pStruct,
1825 : : int iInChI,
1826 : : int bMobileH,
1827 : : int k)
1828 : : {
1829 [ # # # # : 0 : if (!pStruct || /*!pStruct->at2 ||*/ !pStruct->num_atoms ||
# # ]
1830 [ # # # # ]: 0 : (INCHI_BAS != iInChI && iInChI != INCHI_REC) ||
1831 [ # # # # ]: 0 : (TAUT_NON != bMobileH && TAUT_YES != bMobileH) || k < 0) /* djb-rwth: addressing LLVM warnings */
1832 : : {
1833 : 0 : return 0;
1834 : : }
1835 : :
1836 : 0 : return (k < pStruct->RevInChI.num_components[iInChI] &&
1837 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI] &&
1838 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH] &&
1839 [ # # # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->nNumberOfAtoms > 0 &&
1840 [ # # ]: 0 : pStruct->RevInChI.pINChI[iInChI][k][bMobileH]->bDeleted);
1841 : : }
1842 : :
1843 : :
1844 : : /****************************************************************************/
1845 : 0 : int DetectInpInchiCreationOptions(InpInChI* pOneInput,
1846 : : int* bHasReconnected,
1847 : : int* bHasMetal,
1848 : : int* bHasFixedH,
1849 : : int* nModeFlagsStereo,
1850 : : int* bTautFlagsStereo)
1851 : : {
1852 : 0 : int ret = 0, bHasStereo;
1853 : 0 : int nModeFlagsValue = 0, bTautFlagsValue; /* stereo flags */
1854 : : int iInChI, iMobileH, bIso, k, max_components, num_components;
1855 : : INChI* pInChI;
1856 : : int num_known_SB /*Stereo Bonds & Cumulenes >C==C==C==C< */;
1857 : : int num_known_SC /* Stereo Centers & Allenes >C=C=C< */;
1858 : : int num_unk_und_SB, num_unk_und_SC;
1859 : : int num_SC_PIII, num_SC_AsIII; /* has Phosphine or Arsine stereo center(s) */
1860 : :
1861 : 0 : *bHasReconnected = *bHasFixedH = *nModeFlagsStereo = *bTautFlagsStereo = 0;
1862 : 0 : nModeFlagsValue = bTautFlagsValue = bHasStereo = 0;
1863 : 0 : num_known_SB = num_known_SC = num_unk_und_SB = num_unk_und_SC = num_SC_PIII = num_SC_AsIII = 0;
1864 : 0 : *bHasMetal = 0;
1865 : :
1866 [ # # ]: 0 : for (iInChI = 0; iInChI < INCHI_NUM; iInChI++)
1867 : : {
1868 [ # # ]: 0 : for (iMobileH = 0; iMobileH < TAUT_NUM; iMobileH++)
1869 : : {
1870 [ # # # # ]: 0 : for (bIso = 1; !nModeFlagsValue && 0 <= bIso; bIso--)
1871 : : {
1872 [ # # # # ]: 0 : switch (pOneInput->s[iInChI][iMobileH][bIso])
1873 : : {
1874 : 0 : case 1: /* SABS */
1875 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO;
1876 : 0 : break;
1877 : 0 : case 2:
1878 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_RELATIVE_STEREO;
1879 : 0 : break;
1880 : 0 : case 3:
1881 : 0 : nModeFlagsValue |= REQ_MODE_STEREO | REQ_MODE_ISO_STEREO | REQ_MODE_RACEMIC_STEREO;
1882 : : }
1883 : : }
1884 : :
1885 : 0 : max_components = pOneInput->pInpInChI[iInChI][iMobileH] ?
1886 [ # # ]: 0 : pOneInput->nNumComponents[iInChI][iMobileH] : 0;
1887 : :
1888 [ # # ]: 0 : for (k = num_components = 0; k < max_components; k++)
1889 : : {
1890 : 0 : pInChI = pOneInput->pInpInChI[iInChI][iMobileH] + k;
1891 : 0 : ret = CountStereoTypes(pInChI,
1892 : : &num_known_SB, &num_known_SC,
1893 : : &num_unk_und_SB, &num_unk_und_SC,
1894 : : &num_SC_PIII, &num_SC_AsIII);
1895 [ # # ]: 0 : if (ret < 0)
1896 : : {
1897 : 0 : return ret; /* error */
1898 : : }
1899 : 0 : bHasStereo += (ret == 2);
1900 [ # # ]: 0 : if ((ret > 0))
1901 : : {
1902 : : /* ret == 0 => Empty InChI, 1=> No Stereo, 2=> Has Stereo */
1903 : 0 : num_components++;
1904 : 0 : *bHasReconnected |= (iInChI == INCHI_REC);
1905 : 0 : *bHasFixedH |= (iMobileH == TAUT_NON);
1906 : : }
1907 : 0 : *bHasMetal |= bInChIHasReconnectedMetal(pInChI);
1908 : : }
1909 : : }
1910 : : }
1911 : :
1912 [ # # # # ]: 0 : if ((nModeFlagsValue & REQ_MODE_RELATIVE_STEREO) && (nModeFlagsValue & REQ_MODE_RACEMIC_STEREO))
1913 : : {
1914 : 0 : return RI_ERR_SYNTAX;
1915 : : }
1916 [ # # # # ]: 0 : if (bHasStereo && !nModeFlagsValue) /* REQ_MODE_SB_IGN_ALL_UU | REQ_MODE_SC_IGN_ALL_UU*/
1917 : : {
1918 : : /* inversion does not change the stereo or no stereo at all */
1919 : 0 : nModeFlagsValue = REQ_MODE_STEREO | REQ_MODE_ISO_STEREO; /* Abs */
1920 : : }
1921 : :
1922 [ # # # # ]: 0 : if (!num_known_SB && num_unk_und_SB)
1923 : : {
1924 : : ; /* full SUU option or SB part of it */
1925 : : }
1926 : : else
1927 : : {
1928 : 0 : nModeFlagsValue |= REQ_MODE_SB_IGN_ALL_UU; /* ignore Unknown/Undefind SB if no well-defined SB exist */
1929 : : }
1930 : :
1931 [ # # # # ]: 0 : if (!num_known_SC && num_unk_und_SC)
1932 : : {
1933 : : ; /* full SUU option or SB part of it */
1934 : : }
1935 : : else
1936 : : {
1937 : 0 : nModeFlagsValue |= REQ_MODE_SC_IGN_ALL_UU; /* ignore Unknown/Undefind SC if no well-defined SB exist */
1938 : : }
1939 : : /* Phosphine and Arsine Stereo */
1940 [ # # ]: 0 : if (num_SC_PIII)
1941 : : {
1942 : 0 : bTautFlagsValue |= TG_FLAG_PHOSPHINE_STEREO;
1943 : : }
1944 : : /* Phosphine and Arsine Stereo */
1945 [ # # ]: 0 : if (num_SC_AsIII)
1946 : : {
1947 : 0 : bTautFlagsValue |= TG_FLAG_ARSINE_STEREO;
1948 : : }
1949 : :
1950 : 0 : *nModeFlagsStereo = nModeFlagsValue;
1951 : 0 : *bTautFlagsStereo = bTautFlagsValue;
1952 : :
1953 : 0 : return 0;
1954 : : }
1955 : :
1956 : :
1957 : : /****************************************************************************/
1958 : 0 : int bInChIHasReconnectedMetal(INChI* pInChI)
1959 : : {
1960 : : int i;
1961 [ # # # # : 0 : if (pInChI && !pInChI->bDeleted && pInChI->nNumberOfAtoms && pInChI->nAtom)
# # # # ]
1962 : : {
1963 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
1964 : : {
1965 [ # # ]: 0 : if (is_el_a_metal((int)pInChI->nAtom[i]))
1966 : : {
1967 [ # # # # : 0 : if (pInChI->nNumberOfAtoms > 1 || (pInChI->nNum_H && pInChI->nNum_H[0])) /* djb-rwth: addressing LLVM warning */
# # ]
1968 : : {
1969 : 0 : return 1;
1970 : : }
1971 : : }
1972 : : }
1973 : : }
1974 : :
1975 : 0 : return 0;
1976 : : }
1977 : :
1978 : :
1979 : : /****************************************************************************/
1980 : 0 : int SetProtonsAndXchgIsoH(int bInChI2Structure,
1981 : : int bReqSplitOutputInChI,
1982 : : int bReqProtonsForEachComponent,
1983 : : int bReqNonTaut,
1984 : : int bReqStereo,
1985 : : int num_components[INCHI_NUM],
1986 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
1987 : : InpInChI* OneInput)
1988 : : {
1989 : 0 : int j, k, k1, ret2 = 0, iINChI;
1990 : : int bAvailableProtonsForEachComponent, bAvailableProtonsTotal;
1991 : :
1992 : : INCHI_HEAPCHK
1993 : :
1994 : 0 : num_components[INCHI_BAS] = num_components[INCHI_REC] = 0;
1995 : :
1996 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
1997 : : {
1998 : 0 : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_UNDEFINED;
1999 : : /* are totals of /p and/or /i/h available ? */
2000 : 0 : bAvailableProtonsTotal = 0 != OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
2001 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
2002 : : {
2003 : 0 : bAvailableProtonsTotal |= 0 != OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[k1];
2004 : : }
2005 : : /* are /p and/or /i/h available for each component ? */
2006 : 0 : bAvailableProtonsForEachComponent = (NULL != OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2007 : :
2008 : : /* decision: add /p to each component, add total to the 1st, add total as one more component */
2009 : : /* In case of bInChI2Structure just keep totals if not available for each component */
2010 : :
2011 [ # # ]: 0 : if (bInChI2Structure)
2012 : : {
2013 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsForEachComponent ?
2014 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2015 : : MODE_PIXH_KEEP_TOTALS;
2016 : : }
2017 : : else
2018 : : {
2019 [ # # ]: 0 : if (!bReqSplitOutputInChI)
2020 : : {
2021 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsForEachComponent ?
2022 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2023 : : MODE_PIXH_ADD_TO_FIRST;
2024 : : }
2025 : : else
2026 : : {
2027 [ # # ]: 0 : if (!bAvailableProtonsForEachComponent)
2028 : : {
2029 : 0 : nModeProtonIsoExchgH[iINChI] = bAvailableProtonsTotal ?
2030 [ # # ]: 0 : MODE_PIXH_ADD_A_PIXH_COMPONENT :
2031 : : MODE_PIXH_ADD_TO_FIRST;
2032 : : }
2033 : : else
2034 : : {
2035 : : /* bAvailableProtonsForEachComponent && bReqSplitOutputInChI */
2036 [ # # ]: 0 : if (bReqProtonsForEachComponent)
2037 : : {
2038 : 0 : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_ADD_TO_EACH;
2039 : : }
2040 : : else
2041 : : {
2042 : 0 : nModeProtonIsoExchgH[iINChI] = bReqNonTaut ?
2043 [ # # ]: 0 : MODE_PIXH_ADD_TO_EACH :
2044 : : MODE_PIXH_ADD_A_PIXH_COMPONENT;
2045 : : }
2046 : : }
2047 : : }
2048 : : }
2049 : :
2050 : : /* remove unneeded data: protons for each component */
2051 [ # # ]: 0 : if (bAvailableProtonsForEachComponent &&
2052 [ # # ]: 0 : nModeProtonIsoExchgH[iINChI] != MODE_PIXH_ADD_TO_EACH)
2053 : : {
2054 [ # # ]: 0 : inchi_free(OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2055 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons = NULL;
2056 : 0 : bAvailableProtonsForEachComponent = 0;
2057 : : }
2058 : : /* remove unneeded data: total protons all components */
2059 [ # # # # ]: 0 : if (bAvailableProtonsTotal && nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_TO_EACH)
2060 : : {
2061 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons = 0;
2062 [ # # ]: 0 : for (k1 = 0; k1 < NUM_H_ISOTOPES; k1++)
2063 : : {
2064 : 0 : OneInput->nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[k1] = 0;
2065 : : }
2066 : : /* djb-rwth: removing redundant code */
2067 : : }
2068 : : /* remove unneeded data: Fixed-H InChI; no protons data exist for Fixed-H */
2069 [ # # # # ]: 0 : if (!bReqNonTaut && OneInput->nNumComponents[iINChI][TAUT_NON])
2070 : : {
2071 : 0 : j = TAUT_NON;
2072 [ # # ]: 0 : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2073 : : {
2074 : 0 : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2075 : : }
2076 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
2077 : 0 : OneInput->pInpInChI[iINChI][j] = NULL;
2078 : 0 : OneInput->nNumComponents[iINChI][j] = 0;
2079 : : }
2080 : : #ifdef NEVER
2081 : : /* remove unneeded data: Mobile-H InChI ????? */
2082 : : if (bReqNonTaut && OneInput->nNumComponents[iINChI][TAUT_NON])
2083 : : {
2084 : : j = TAUT_YES;
2085 : : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2086 : : {
2087 : : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2088 : : }
2089 : : inchi_free(OneInput->pInpInChI[iINChI][j]);
2090 : : OneInput->pInpInChI[iINChI][j] = NULL;
2091 : : OneInput->nNumComponents[iINChI][j] = 0;
2092 : : nModeProtonIsoExchgH[iINChI] = MODE_PIXH_UNDEFINED;
2093 : : if (OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons)
2094 : : {
2095 : : inchi_free(OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons);
2096 : : OneInput->nNumProtons[iINChI][TAUT_YES].pNumProtons = NULL;
2097 : : }
2098 : : }
2099 : : #endif
2100 : : /* add one more component containing only /p and /i/h */
2101 [ # # ]: 0 : if ((nModeProtonIsoExchgH[iINChI] == MODE_PIXH_ADD_A_PIXH_COMPONENT &&
2102 [ # # # # ]: 0 : OneInput->nNumComponents[iINChI][TAUT_YES]) ||
2103 : : /* always add one deleted component if no non-taut InChI is available */
2104 [ # # ]: 0 : (bInChI2Structure && !bAvailableProtonsForEachComponent &&
2105 [ # # ]: 0 : !OneInput->nNumComponents[iINChI][TAUT_NON] &&
2106 [ # # ]: 0 : OneInput->nNumComponents[iINChI][TAUT_YES])) /* djb-rwth: addressing LLVM warnings */
2107 : : {
2108 : 0 : int nPrevLen, nLen = 0;
2109 : 0 : j = TAUT_YES;
2110 : 0 : nPrevLen = OneInput->nNumComponents[iINChI][j];
2111 [ # # ]: 0 : for (k = 0; k < nPrevLen; k++)
2112 : : {
2113 : 0 : nLen += !OneInput->pInpInChI[iINChI][j][k].bDeleted;
2114 : : }
2115 [ # # ]: 0 : if (nLen == nPrevLen)
2116 : : {
2117 : : /* add one more component */
2118 : 0 : INChI* pInChI = (INChI*)inchi_calloc((long long)nLen + 1, sizeof(*pInChI)); /* djb-rwth: cast operator added */
2119 [ # # ]: 0 : if (!pInChI)
2120 : : {
2121 : 0 : ret2 = RI_ERR_ALLOC;
2122 : 0 : goto exit_error;
2123 : : }
2124 : 0 : memcpy(pInChI, OneInput->pInpInChI[iINChI][j], nLen * sizeof(*pInChI));
2125 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j]);
2126 : 0 : OneInput->pInpInChI[iINChI][j] = pInChI;
2127 : : }
2128 : 0 : OneInput->nNumComponents[iINChI][j] = nLen + 1;
2129 : :
2130 [ # # ]: 0 : for (k = nLen; k < nPrevLen; k++)
2131 : : {
2132 : 0 : Free_INChI_Members(&OneInput->pInpInChI[iINChI][j][k]);
2133 : 0 : memset(&OneInput->pInpInChI[iINChI][j][k], 0, sizeof(OneInput->pInpInChI[iINChI][j][k])); /* djb-rwth: memset_s C11/Annex K variant? */
2134 : : }
2135 : : /* mark the last component as a proton */
2136 [ # # ]: 0 : if (0 > (ret2 = nFillOutProtonMobileH(OneInput->pInpInChI[iINChI][j] + nLen)))
2137 : : {
2138 : 0 : goto exit_error;
2139 : : }
2140 : : }
2141 : : INCHI_HEAPCHK
2142 : :
2143 : : /* remove unneeded Stereo and/or Fixed H */
2144 [ # # ]: 0 : if (!bReqStereo)
2145 : : {
2146 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
2147 : : {
2148 [ # # ]: 0 : for (k = 0; k < OneInput->nNumComponents[iINChI][j]; k++)
2149 : : {
2150 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j][k].Stereo)
2151 : : {
2152 : 0 : Free_INChI_Stereo(OneInput->pInpInChI[iINChI][j][k].Stereo);
2153 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j][k].Stereo);
2154 : 0 : OneInput->pInpInChI[iINChI][j][k].Stereo = NULL;
2155 : : }
2156 [ # # ]: 0 : if (OneInput->pInpInChI[iINChI][j][k].StereoIsotopic)
2157 : : {
2158 : 0 : Free_INChI_Stereo(OneInput->pInpInChI[iINChI][j][k].StereoIsotopic);
2159 [ # # ]: 0 : inchi_free(OneInput->pInpInChI[iINChI][j][k].StereoIsotopic);
2160 : 0 : OneInput->pInpInChI[iINChI][j][k].StereoIsotopic = NULL;
2161 : : }
2162 : : INCHI_HEAPCHK
2163 : : }
2164 : : }
2165 : : }
2166 : :
2167 : : }
2168 : :
2169 : 0 : num_components[INCHI_BAS] = inchi_max(OneInput->nNumComponents[INCHI_BAS][TAUT_YES],
2170 : : OneInput->nNumComponents[INCHI_BAS][TAUT_NON]);
2171 : 0 : num_components[INCHI_REC] = inchi_max(OneInput->nNumComponents[INCHI_REC][TAUT_YES],
2172 : : OneInput->nNumComponents[INCHI_REC][TAUT_NON]);
2173 : :
2174 : 0 : exit_error:
2175 : 0 : return ret2;
2176 : : }
2177 : :
2178 : :
2179 : : /****************************************************************************/
2180 : 0 : int GetInChIFormulaNumH(INChI* pInChI, int* nNumH)
2181 : : { /* get number of H including bridging hydrogen atoms */
2182 : : const char* p, * q;
2183 : 0 : *nNumH = 0;
2184 [ # # ]: 0 : if (pInChI->szHillFormula)
2185 : : {
2186 [ # # ]: 0 : for (p = strchr(pInChI->szHillFormula, 'H'); p; p = strchr(p, 'H'))
2187 : : {
2188 : 0 : p++;
2189 [ # # ]: 0 : if (!islower(UCINT * p))
2190 : : {
2191 : : /* found hydrogen in the formula */
2192 [ # # ]: 0 : if (isdigit(UCINT * p))
2193 : : {
2194 : : #if ( CHECK_STRTOL_ATNUMB==1 )
2195 : 0 : int delta = (int)inchi_strtol(p, &q, 10);
2196 [ # # # # ]: 0 : if (delta > MAX_ATOMS || delta < 0)
2197 : : {
2198 : 0 : return RI_ERR_SYNTAX; /* syntax error */
2199 : : }
2200 : 0 : *nNumH += delta;
2201 : : #else
2202 : : * nNumH += (int)inchi_strtol(p, &q, 10);
2203 : : #endif
2204 : 0 : p = q;
2205 : : }
2206 : : else
2207 : : {
2208 : 0 : *nNumH += 1;
2209 : : }
2210 : : }
2211 : : }
2212 : : }
2213 : :
2214 : 0 : return 0;
2215 : : }
2216 : :
2217 : :
2218 : : /****************************************************************************/
2219 : 0 : int GetInChINumH(INChI* pInChI, int* nNumH)
2220 : : {
2221 : : int i, j, nNumTautGroups, iTautGroup, nTautGroupLen, lenTautomer;
2222 : 0 : *nNumH = 0;
2223 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
2224 : : {
2225 : 0 : *nNumH += (pInChI->nAtom[i] == EL_NUMBER_H); /* bridging H */
2226 : 0 : *nNumH += pInChI->nNum_H[i];
2227 : : }
2228 : : /* earlier nNum_H_fixed[] should have been added to pInChI->nNum_H[] */
2229 : : /*
2230 : : if ( pInChI->nNum_H_fixed ) {
2231 : : for ( i = 0; i < pInChI->nNumberOfAtoms; i ++ ) {
2232 : : *nNumH += pInChI->nNum_H_fixed[i];
2233 : : }
2234 : : }
2235 : : */
2236 [ # # # # ]: 0 : if (pInChI->lenTautomer > 3 && pInChI->nTautomer)
2237 : : {
2238 : 0 : lenTautomer = pInChI->lenTautomer;
2239 : 0 : j = 0;
2240 : 0 : nNumTautGroups = pInChI->nTautomer[j++];
2241 [ # # # # ]: 0 : for (iTautGroup = 0; j < lenTautomer && iTautGroup < nNumTautGroups; iTautGroup++, j += nTautGroupLen)
2242 : : {
2243 : 0 : nTautGroupLen = pInChI->nTautomer[j] + 1;
2244 : 0 : *nNumH += pInChI->nTautomer[j + 1];
2245 : : }
2246 [ # # # # ]: 0 : if (iTautGroup != nNumTautGroups || j != lenTautomer)
2247 : : {
2248 : 0 : return RI_ERR_PROGR;
2249 : : }
2250 : : }
2251 [ # # # # : 0 : if (pInChI->nNum_H_fixed && (pInChI->lenTautomer || pInChI->nTautomer))
# # ]
2252 : : {
2253 : 0 : return RI_ERR_PROGR;
2254 : : }
2255 : :
2256 : 0 : return 0;
2257 : : }
2258 : :
2259 : :
2260 : : /****************************************************************************/
2261 : 0 : int GetInChIIsoH(INChI* pInChI, int nNumIsotopicH[NUM_H_ISOTOPES])
2262 : : {
2263 : : int i;
2264 [ # # ]: 0 : for (i = 0; i < NUM_H_ISOTOPES; i++)
2265 : : {
2266 : 0 : nNumIsotopicH[i] = 0;
2267 : : }
2268 [ # # ]: 0 : for (i = 0; i < pInChI->nNumberOfIsotopicAtoms; i++)
2269 : : {
2270 [ # # ]: 0 : if (pInChI->IsotopicAtom[i].nIsoDifference > 0 &&
2271 [ # # ]: 0 : pInChI->IsotopicAtom[i].nIsoDifference <= NUM_H_ISOTOPES)
2272 : : {
2273 [ # # ]: 0 : if (!pInChI->nAtom ||
2274 [ # # ]: 0 : !pInChI->IsotopicAtom[i].nAtomNumber ||
2275 [ # # ]: 0 : pInChI->IsotopicAtom[i].nAtomNumber > pInChI->nNumberOfAtoms)
2276 : : {
2277 : 0 : return RI_ERR_PROGR;
2278 : : }
2279 [ # # ]: 0 : if (pInChI->nAtom[pInChI->IsotopicAtom[i].nAtomNumber - 1] == (AT_NUMB)EL_NUMBER_H)
2280 : : {
2281 : : /* isotopic H in connection table */
2282 : 0 : nNumIsotopicH[pInChI->IsotopicAtom[i].nIsoDifference - 1]++;
2283 : : }
2284 : : }
2285 : 0 : nNumIsotopicH[0] += pInChI->IsotopicAtom[i].nNum_H;
2286 : 0 : nNumIsotopicH[1] += pInChI->IsotopicAtom[i].nNum_D;
2287 : 0 : nNumIsotopicH[2] += pInChI->IsotopicAtom[i].nNum_T;
2288 : : }
2289 : :
2290 : 0 : return 0;
2291 : : }
2292 : :
2293 : :
2294 : : /****************************************************************************/
2295 : : typedef struct tagNumElem
2296 : : {
2297 : : int num;
2298 : : /*
2299 : : int iso;
2300 : : */
2301 : : } NUM_ELEM;
2302 : :
2303 : :
2304 : : /****************************************************************************
2305 : : Read a single InChI input Line and convert to data
2306 : : ****************************************************************************/
2307 : 2 : int InChILine2Data(INCHI_IOSTREAM* pInp,
2308 : : SEGM_LINE* pLine,
2309 : : char** pStr,
2310 : : int* pState,
2311 : : int* nErr,
2312 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
2313 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
2314 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
2315 : : int s[INCHI_NUM][TAUT_NUM][2],
2316 : : int bReadCoord,
2317 : : int bInchi2Struct,
2318 : : INCHI_MODE nMode,
2319 : : int* bStdFormat,
2320 : : int* input_has_save_opt,
2321 : : unsigned char* input_save_opt_bits,
2322 : : OAD_Polymer** ppolymer,
2323 : : OAD_V3000** pv3000)
2324 : : {
2325 : 2 : 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 */
2326 : : int ret, tot_charge[INCHI_NUM][TAUT_NUM];
2327 : : int i1, i2, i3;
2328 : : int kc;
2329 : : NUM_ELEM* num_elem[INCHI_NUM][TAUT_NUM];
2330 : :
2331 : :
2332 : : #if ( FIX_I2I_STEREOCONVERSION_BUG == 1 )
2333 : : /* (2008-03-06) 1=> Fix bug of i2i conversion SAbs-->(SRel||Srac) */
2334 : : /* (converter does not placed proper stereo to output) */
2335 : :
2336 : : /* set new stereo type as requested by conversion option */
2337 : 2 : int target_stereo_type = 1;
2338 [ - + ]: 2 : if (nMode & REQ_MODE_RELATIVE_STEREO)
2339 : : {
2340 : 0 : target_stereo_type = 2;
2341 : : }
2342 [ - + ]: 2 : else if (nMode & REQ_MODE_RACEMIC_STEREO)
2343 : : {
2344 : 0 : target_stereo_type = 3;
2345 : : }
2346 : : #endif
2347 : :
2348 : 2 : memset(num_elem, 0, sizeof(num_elem)); /* djb-rwth: memset_s C11/Annex K variant? */
2349 : :
2350 : 2 : ret = ReadInChILine(pInp, pLine, pStr, pState, pInpInChI,
2351 : : nNumComponents, nNumProtons, s, bStdFormat,
2352 : : input_has_save_opt, input_save_opt_bits,
2353 : : bInchi2Struct, ppolymer, pv3000);
2354 : :
2355 : : #if ( FIX_I2I_STEREOCONVERSION_BUG == 1 )
2356 : : /* modify stereo type for layers as requested */
2357 [ - + ]: 2 : if (target_stereo_type > 1)
2358 : : {
2359 [ # # ]: 0 : for (i1 = 0; i1 < INCHI_NUM; i1++)
2360 : : {
2361 [ # # ]: 0 : for (i2 = 0; i2 < TAUT_NUM; i2++)
2362 : : {
2363 [ # # ]: 0 : for (i3 = 0; i3 < 2; i3++)
2364 : : {
2365 [ # # ]: 0 : if (s[i1][i2][i3] != 0)
2366 : : {
2367 [ # # ]: 0 : if (target_stereo_type != 1)
2368 : : {
2369 : : /* do not allow conversion SRel=>SAbs, SRac=>SAbs */
2370 : 0 : s[i1][i2][i3] = target_stereo_type;
2371 : : }
2372 : : }
2373 : : }
2374 : : }
2375 : : }
2376 : : }
2377 : : #endif
2378 : :
2379 : 2 : * nErr = 0;
2380 : :
2381 [ - + ]: 2 : if ((ret == RI_ERR_EOL) &&
2382 : 0 : nNumComponents[INCHI_BAS][TAUT_YES]
2383 [ # # # # ]: 0 : + nNumComponents[INCHI_BAS][TAUT_NON] && bReadCoord)
2384 : : {
2385 : 0 : retAux = ReadInChICoord(pInp, pLine, &stateAux, pInpInChI, nNumComponents); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2386 : : }
2387 : :
2388 [ + - - + ]: 2 : if ((ret == RI_ERR_EOL || ret == RI_ERR_EOF) &&
2389 : 0 : nNumComponents[INCHI_BAS][TAUT_YES]
2390 [ # # ]: 0 : + nNumComponents[INCHI_BAS][TAUT_NON])
2391 : : {
2392 : : /* post-processing: add omitted layers */
2393 : 0 : *pState = IST_MATERIAL_BALANCE_ERROR;
2394 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
2395 : : {
2396 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
2397 : : {
2398 : : /* for Mobile/Fixed H (j) ... */
2399 : : int bIsotopic, bStereoType, bStereoTypeAlt;
2400 : 0 : int nMH2FH_AltInv = 0, nFH2iFH_AltInv = 0 /*, niMH2iFH_AltInv=0, nMH2iMH_AltInv=0*/;
2401 [ # # ]: 0 : int jAlt = ALT_TAUT(j);
2402 : 0 : INCHI_MODE nFlags = 0, nFlagsAlt = 0;
2403 : : /* get stereo type: ABS, REL, RAC, or nothing */
2404 : 0 : tot_charge[iINChI][j] = 0;
2405 [ # # ]: 0 : for (bIsotopic = bStereoType = bStereoTypeAlt = 0; bIsotopic < 2; bIsotopic++)
2406 : : {
2407 [ # # # # ]: 0 : if (!bStereoType || bStereoType < s[iINChI][j][bIsotopic])
2408 : : {
2409 : 0 : bStereoType = s[iINChI][j][bIsotopic];
2410 : : }
2411 [ # # # # ]: 0 : if (!bStereoTypeAlt || bStereoTypeAlt < s[iINChI][jAlt][bIsotopic])
2412 : : {
2413 : 0 : bStereoTypeAlt = s[iINChI][jAlt][bIsotopic];
2414 : : }
2415 [ # # # # ]: 0 : nFlags = bStereoType == 2 ? INCHI_FLAG_REL_STEREO : bStereoType == 3 ? INCHI_FLAG_RAC_STEREO : 0;
2416 [ # # # # ]: 0 : nFlagsAlt = bStereoTypeAlt == 2 ? INCHI_FLAG_REL_STEREO : bStereoTypeAlt == 3 ? INCHI_FLAG_RAC_STEREO : 0;
2417 : : }
2418 : : /* set stereo type to each component */
2419 : : /* add missing nNum_H and nConnTable */
2420 [ # # ]: 0 : if (nNumComponents[iINChI][j])
2421 : : {
2422 : 0 : num_elem[iINChI][j] = (NUM_ELEM*)inchi_calloc((long long)nElDataLen + 1, sizeof(num_elem[0][0][0])); /* djb-rwth: cast operator added */
2423 [ # # ]: 0 : if (!num_elem[iINChI][j])
2424 : : {
2425 : 0 : ret2 = RI_ERR_ALLOC;
2426 : 0 : goto exit_function;
2427 : : }
2428 : : }
2429 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
2430 : : {
2431 : : /* for each component k ... */
2432 [ # # ]: 0 : if (pInpInChI[iINChI][j])
2433 : : {
2434 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
2435 : 0 : INChI* pInChI_Alt = (k < nNumComponents[iINChI][jAlt] &&
2436 [ # # ]: 0 : pInpInChI[iINChI][jAlt] &&
2437 : : /*pInpInChI[iINChI][jAlt]->nNumberOfAtoms)? pInpInChI[iINChI][jAlt]:NULL;*/ /* 2007-09-25 DT */
2438 [ # # # # ]: 0 : pInpInChI[iINChI][jAlt][k].nNumberOfAtoms) ? &pInpInChI[iINChI][jAlt][k] : NULL;
2439 [ # # ]: 0 : if (nFlags)
2440 : : {
2441 : 0 : pInChI->nFlags |= nFlags;
2442 : : }
2443 : : else
2444 : : {
2445 [ # # # # : 0 : if (j == TAUT_NON && !nFlags && nFlagsAlt)
# # ]
2446 : : {
2447 : 0 : pInChI->nFlags |= nFlagsAlt;
2448 : : }
2449 : : }
2450 : : /**** add empty immobile H (nNum_H) if it is missing ****/
2451 [ # # ]: 0 : if (!pInChI->nNum_H &&
2452 [ # # ]: 0 : !(pInChI->nNum_H = (S_CHAR*)inchi_calloc((long long)pInChI->nNumberOfAtoms + 1, sizeof(pInChI->nNum_H[0])))) /* djb-rwth: cast operator added */
2453 : : {
2454 : 0 : ret2 = RI_ERR_ALLOC;
2455 : 0 : goto exit_function;
2456 : : }
2457 : : /**** add single atom nConnTable if it is missing ****/
2458 [ # # # # ]: 0 : if (!pInChI->nConnTable && pInpInChI[iINChI][TAUT_YES]) /* djb-rwth: fixing a NULL pointer dereference */
2459 : 0 : {
2460 : : AT_NUMB* pCT;
2461 : : int lenCT;
2462 [ # # # # ]: 0 : if (j == TAUT_NON && k < nNumComponents[iINChI][TAUT_YES] &&
2463 [ # # ]: 0 : (pCT = pInpInChI[iINChI][TAUT_YES][k].nConnTable) &&
2464 [ # # ]: 0 : (lenCT = pInpInChI[iINChI][TAUT_YES][k].lenConnTable) > 0)
2465 : : {
2466 [ # # ]: 0 : if (!(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)lenCT + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
2467 : : {
2468 : 0 : ret2 = RI_ERR_ALLOC;
2469 : 0 : goto exit_function;
2470 : : }
2471 : 0 : memcpy(pInChI->nConnTable, pCT, lenCT * sizeof(pInChI->nConnTable[0]));
2472 : 0 : pInChI->lenConnTable = lenCT;
2473 : : }
2474 : : else
2475 : : {
2476 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->nNumberOfAtoms > 1)
2477 : : {
2478 [ # # ]: 0 : *pState = IST_MOBILE_H_CONNECTIONS + (iINChI == INCHI_REC ? IST_HAPPENED_IN_RECMET : 0);
2479 : 0 : ret2 = RI_ERR_SYNTAX;
2480 : 0 : goto exit_function;
2481 : : }
2482 [ # # ]: 0 : if (!(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)pInChI->nNumberOfAtoms + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
2483 : : {
2484 : 0 : ret2 = RI_ERR_ALLOC;
2485 : 0 : goto exit_function;
2486 : : }
2487 : 0 : pInChI->lenConnTable = 1;
2488 : 0 : pInChI->nConnTable[0] = 1;
2489 : : }
2490 : : }
2491 : : else
2492 : : {
2493 [ # # # # : 0 : if (pInChI->nConnTable && !pInChI->lenConnTable && pInChI->nNumberOfAtoms == 1)
# # ]
2494 : : {
2495 : 0 : pInChI->nConnTable[0] = 1;
2496 : 0 : pInChI->lenConnTable = 1;
2497 : : }
2498 : : }
2499 : : /**** copy charge: Mobile H --> Fixed H; ****/
2500 [ # # ]: 0 : if (j == TAUT_NON)
2501 : : {
2502 : : /*
2503 : : if ( pInChI->nTotalCharge == NO_VALUE_INT )
2504 : : {
2505 : : pInChI->nTotalCharge = 0;
2506 : : }
2507 : : else
2508 : : */
2509 [ # # # # : 0 : if (!pInChI->nTotalCharge && k < nNumComponents[iINChI][TAUT_YES] && pInpInChI[iINChI][TAUT_YES]) /* djb-rwth: fixing a NULL pointer dereference */
# # ]
2510 : : {
2511 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_YES][k]; /* Mobile H InChI */
2512 [ # # # # ]: 0 : if (pAltInChI->nTotalCharge && pAltInChI->nTotalCharge != NO_VALUE_INT)
2513 : : {
2514 : 0 : pInChI->nTotalCharge = pAltInChI->nTotalCharge;
2515 : : }
2516 : : }
2517 : : }
2518 : : /***** Fixed H: add pInChI->nNum_H_fixed to pInChI->nNum_H ****/
2519 [ # # # # : 0 : if (j == TAUT_NON && pInChI->nNum_H && pInChI->nNum_H_fixed)
# # ]
2520 : : {
2521 [ # # ]: 0 : for (m = 0; m < pInChI->nNumberOfAtoms; m++)
2522 : : {
2523 : 0 : pInChI->nNum_H[m] += pInChI->nNum_H_fixed[m];
2524 : : }
2525 : : }
2526 : : /***** copy isotopic atoms: Mobile H --> Fixed H ******/
2527 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->nNumberOfIsotopicAtoms &&
2528 [ # # ]: 0 : k < nNumComponents[iINChI][TAUT_NON])
2529 : : {
2530 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_NON][k]; /* Fixed H InChI */
2531 : :
2532 [ # # ]: 0 : if (!pAltInChI->nNumberOfIsotopicAtoms)
2533 : : {
2534 : 0 : ret2 = CopySegment(pAltInChI, pInChI, CPY_ISO_AT, 0, 0);
2535 [ # # ]: 0 : if (ret2 < 0)
2536 : : {
2537 : 0 : goto exit_function;
2538 : : }
2539 : : }
2540 : : }
2541 : : /**** copy coordinates: Mobile H --> Fixed H ******/
2542 [ # # # # ]: 0 : if (j == TAUT_YES && pInChI->IsotopicTGroup &&
2543 [ # # ]: 0 : k < nNumComponents[iINChI][TAUT_NON])
2544 : : {
2545 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_NON][k]; /* Fixed H InChI */
2546 : :
2547 [ # # ]: 0 : if (!pAltInChI->IsotopicTGroup)
2548 : : {
2549 : 0 : XYZ_COORD* pxyz = (XYZ_COORD*)inchi_calloc(pInChI->nNumberOfAtoms, sizeof(pxyz[0]));
2550 [ # # ]: 0 : if (pxyz)
2551 : : {
2552 : 0 : memcpy(pxyz, pInChI->IsotopicTGroup, pInChI->nNumberOfAtoms * sizeof(pxyz[0]));
2553 : 0 : pAltInChI->IsotopicTGroup = (INChI_IsotopicTGroup*)pxyz;
2554 : : }
2555 : : else
2556 : : {
2557 : 0 : ret2 = RI_ERR_ALLOC;
2558 : 0 : goto exit_function;
2559 : : }
2560 : : }
2561 : : }
2562 : :
2563 : : /********************************************************
2564 : : * *
2565 : : * Restore omitted stereo seqments *
2566 : : * *
2567 : : * order of restoring: *
2568 : : * *
2569 : : * 1. Fixed H (F) -> (FI) Isotopic Fixed H *
2570 : : * 2. Mobile H (M) -> (F) Fixed H *
2571 : : * 3. Isotopic Mobile H (MI) -> (FI) Isotopic Fixed H *
2572 : : * 4. Mobile H (M) -> (MI) Isotopic Mobile H *
2573 : : * *
2574 : : ********************************************************/
2575 : :
2576 : : /***** (4) copy stereo: Mobile H --> isotopic Mobile H ******/
2577 [ # # ]: 0 : if (j == TAUT_YES)
2578 : : {
2579 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2580 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2581 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2582 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2583 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2584 : :
2585 : : /* non-isotopic Mobile H => isotopic Mobile H */
2586 [ # # ]: 0 : if (bIso)
2587 : : {
2588 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2589 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
2590 : : {
2591 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)) ||
2592 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
2593 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))) /* djb-rwth: addressing LLVM warning */
2594 : : {
2595 : 0 : goto exit_function;
2596 : : }
2597 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2598 : : {
2599 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2600 : : {
2601 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2602 : : }
2603 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2604 : : {
2605 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2606 : : }
2607 : : }
2608 : : }
2609 : : else
2610 : : {
2611 : : /* copy sp3 inversion info: non-isotopic Mobile H => isotopic Mobile H */
2612 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2613 [ # # # # ]: 0 : pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters &&
2614 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs)
2615 : : {
2616 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2617 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2618 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2619 : : {
2620 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2621 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2622 : : }
2623 : : else
2624 : : {
2625 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs)
2626 : : {
2627 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
2628 : : }
2629 : : }
2630 : : }
2631 : : }
2632 : : }
2633 [ # # ]: 0 : if (bIso &&
2634 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds &&
2635 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
2636 : : {
2637 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP2, 1, 0)))
2638 : : {
2639 : 0 : goto exit_function;
2640 : : }
2641 : : }
2642 : : }
2643 : : /***** (0) set nCompInv2Abs to Fixed-H *********************************/
2644 [ # # ]: 0 : if (j == TAUT_NON)
2645 : : {
2646 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2647 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2648 : : {
2649 : : /* case of /sN and /t... in non-isotopic Mobile-H, no /s in non-isotopic Fixed-H */
2650 [ # # # # : 0 : if (!s[iINChI][j][0] && s[iINChI][jAlt][0] > 0 && /* /sN is not present in F and is present in M */
# # ]
2651 [ # # # # ]: 0 : pInChI_Alt && pInChI_Alt->Stereo && pInChI_Alt->Stereo->nNumberOfStereoCenters)
2652 : : {
2653 : : /* inherit from Mobile-H */
2654 : : /* /s1 in M and MI; /m1 or /m0 in MI; /m. in M; no /m in F. Inherit MI->FI. Added 10-15-2007 */
2655 [ # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs == 0 && /* M: /m. ; means no /m for this component */
2656 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT && /* F: no /m segment for all components */
2657 [ # # ]: 0 : pInChI_Alt->StereoIsotopic && /* MI: present */
2658 [ # # ]: 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs != 0 &&
2659 [ # # ]: 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs != NO_VALUE_INT && /* MI: /m0 or /m1 */
2660 [ # # # # ]: 0 : !s[iINChI][j][0] && !s[iINChI][j][1] && /* F, FI: no /s */
2661 [ # # # # ]: 0 : s[iINChI][jAlt][0] == 1 && s[iINChI][jAlt][1] == 1 /* M, MI: /s1 and /s1 */
2662 : : )
2663 : : {
2664 : : /* copy /m from MI to FI */
2665 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI_Alt, CPY_SP3_M, 1, 1)))
2666 : : {
2667 : 0 : goto exit_function;
2668 : : }
2669 : : }
2670 : : else
2671 : : {
2672 : : /* the following if(){...} was added to fix m1 bug 2007-09-25 DT */
2673 [ # # # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs != NO_VALUE_INT && s[iINChI][jAlt][0] == 1)
2674 : : {
2675 : 0 : pInChI->Stereo->nCompInv2Abs = pInChI_Alt->Stereo->nCompInv2Abs;
2676 : : }
2677 : : else
2678 : : {
2679 : : /* M and MI contain /sN and /sN, N=2,3. Added 10-15-2007 */
2680 [ # # ]: 0 : if (pInChI_Alt->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2681 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2682 [ # # # # ]: 0 : !s[iINChI][j][0] && !s[iINChI][j][1] &&
2683 [ # # ]: 0 : (s[iINChI][jAlt][0] & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2684 [ # # ]: 0 : (s[iINChI][jAlt][1] & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2685 : 0 : {
2686 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2687 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2688 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2689 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2690 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2691 [ # # ]: 0 : if (bIso)
2692 : : {
2693 [ # # # # ]: 0 : if (!pInChI_Alt->StereoIsotopic && /* create zero/NULL-initialized pInChI_Alt->StereoIsotopic */
2694 : 0 : 0 > (ret2 = CopySegment(pInChI_Alt, pInChI_Alt, CPY_SP3_M, 1, -1)))
2695 : : {
2696 : 0 : goto exit_function;
2697 : : }
2698 : 0 : pInChI_Alt->StereoIsotopic->nCompInv2Abs = 2; /* MI: /m1 or /m0 */
2699 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 0; /* M: /m. ; no /m for this component */
2700 : 0 : pInChI->Stereo->nCompInv2Abs = NO_VALUE_INT + 1; /* FI: Stereo->CompInv2Abs=0, StereoIsotopic->CompInv2Abs=1 or -1 */
2701 : : }
2702 : : else
2703 : : {
2704 : 0 : pInChI->Stereo->nCompInv2Abs = 2; /* F: /m1 or /m0, omitted from InChI as a repetition */
2705 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 2; /* M: /m1 or /m0; in Srel/SRac case the value = 2 */
2706 : : }
2707 : : }
2708 : : else
2709 : : {
2710 : 0 : pInChI->Stereo->nCompInv2Abs = 2; /* F: /m1 or /m0, omitted from InChI as a repetition */
2711 : 0 : pInChI_Alt->Stereo->nCompInv2Abs = 2; /* M: /m1 or /m0; in Srel/SRac case the value = 2 */
2712 : : }
2713 : : }
2714 : : }
2715 : : }
2716 : : else
2717 : : {
2718 : : /* case of /sN in Isotopic Fixed-H only, /t... in Fixed-H, no /m (2007-08-27 DT) */
2719 [ # # # # ]: 0 : if (!s[iINChI][j][0] && !s[iINChI][jAlt][0] && /* /sN in Fixed-H isotopic only */
2720 [ # # ]: 0 : (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2721 [ # # # # : 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) &&
# # ]
2722 : : /*!(pInChI_Alt && pInChI_Alt->Stereo && pInChI_Alt->Stereo->nNumberOfStereoCenters) &&*/
2723 [ # # # # ]: 0 : !(pInChI_Alt && pInChI_Alt->StereoIsotopic && pInChI_Alt->StereoIsotopic->nNumberOfStereoCenters))
2724 : : {
2725 : 0 : pInChI->Stereo->nCompInv2Abs = NO_VALUE_INT + 1; /* Stereo->CompInv2Abs=0, StereoIsotopic->CompInv2Abs=1 or -1 */
2726 : : }
2727 : : else
2728 : : {
2729 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2730 : : }
2731 : : }
2732 : : }
2733 : : }
2734 : :
2735 : : /***** (1) copy stereo: non-isotopic Fixed H --> isotopic Fixed H ******/
2736 [ # # ]: 0 : if (j == TAUT_NON)
2737 : : {
2738 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2739 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2740 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2741 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2742 [ # # ]: 0 : (pInChI_Alt && pInChI_Alt->nNumberOfIsotopicAtoms); /* djb-rwth: addressing LLVM warning */
2743 : : /* non-isotopic Fixed H => isotopic Fixed H */
2744 [ # # ]: 0 : if (bIso)
2745 : : {
2746 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2747 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
2748 : : {
2749 : : /* -- replaced 2007-08-27 by (aaa), see below -- DT
2750 : : if ( 0 > (ret2 = CopySegment( pInChI, pInChI, CPY_SP3, 1, 0)) ||
2751 : : !(pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
2752 : : 0 > (ret2 = CopySegment( pInChI, pInChI, CPY_SP3_M, 1, 0))) {
2753 : : goto exit_function;
2754 : : }
2755 : : */
2756 : : /*----------- replacement (aaa) begin 2007-08-27 DT */
2757 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)))
2758 : : {
2759 : 0 : goto exit_function;
2760 : : }
2761 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT + 1)
2762 : : {
2763 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2764 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
2765 : : }
2766 : : else
2767 : : {
2768 [ # # # # : 0 : if (!(pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
2769 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))
2770 : : {
2771 : 0 : goto exit_function;
2772 : : }
2773 : : }
2774 : : /*----------- replacement (aaa) end 2007-08-27 DT */
2775 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2776 : : {
2777 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
2778 : : {
2779 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2780 : : }
2781 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2782 : : {
2783 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2784 : : }
2785 : : }
2786 : : #ifdef NEVER
2787 : : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2788 : : !s[iINChI][j][0] && s[iINChI][j][0] > 0)
2789 : : {
2790 : : /* copied Rel/Rac stereo to Iso; /s is in Iso /s is not in non-Iso */
2791 : : /* this means all difference in stereo is in inversion */
2792 : : if (pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2793 : : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2794 : : {
2795 : : pInChI->Stereo->nCompInv2Abs = 0; /* missing */
2796 : : pInChI->StereoIsotopic->nCompInv2Abs = 2; /* unusual value */
2797 : : }
2798 : : }
2799 : : #endif
2800 : : }
2801 : : else
2802 : : {
2803 : : /* copy sp3 inversion info: non-isotopic Fixed H --> isotopic Fixed H */
2804 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
2805 [ # # # # ]: 0 : pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters &&
2806 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs)
2807 : : {
2808 [ # # ]: 0 : if ((nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)) &&
2809 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT &&
2810 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
2811 : : {
2812 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = s[iINChI][j][0] > 0 ? 2 : 0;
2813 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0;
2814 : : }
2815 : : else
2816 : : {
2817 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs)
2818 : : {
2819 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
2820 : : }
2821 : : }
2822 : : }
2823 : : }
2824 : : }
2825 [ # # ]: 0 : if (bIso &&
2826 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds &&
2827 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
2828 : : {
2829 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP2, 1, 0)))
2830 : : {
2831 : 0 : goto exit_function;
2832 : : }
2833 : : }
2834 : : }
2835 : :
2836 : : /***** copy stereo: Mobile H --> Fixed H ******/
2837 [ # # # # ]: 0 : if (j == TAUT_NON && k < nNumComponents[iINChI][TAUT_YES])
2838 : : {
2839 : 0 : INChI* pAltInChI = &pInpInChI[iINChI][TAUT_YES][k]; /* Mobile H InChI */
2840 : 0 : int bIso = pInChI->nNumberOfIsotopicAtoms ||
2841 [ # # ]: 0 : (pInChI->StereoIsotopic &&
2842 : 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters
2843 [ # # # # : 0 : + pInChI->StereoIsotopic->nNumberOfStereoBonds) ||
# # ]
2844 : 0 : (pAltInChI && (
2845 [ # # ]: 0 : pAltInChI->nNumberOfIsotopicAtoms ||
2846 [ # # ]: 0 : (pAltInChI->StereoIsotopic &&
2847 : 0 : pAltInChI->StereoIsotopic->nNumberOfStereoCenters
2848 [ # # ]: 0 : + pAltInChI->StereoIsotopic->nNumberOfStereoBonds))); /* djb-rwth: addressing LLVM warning */
2849 [ # # # # ]: 0 : int bNo_InChI_t = (!pInChI->Stereo || !pInChI->Stereo->t_parity);
2850 [ # # # # ]: 0 : int bNo_InChI_m = (!pInChI->Stereo || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs);
2851 : :
2852 : : /* (2) non-isotopic Mobile H => non-isotopic Fixed H */
2853 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoCenters &&
2854 [ # # # # ]: 0 : (!pInChI->Stereo || !pInChI->Stereo->t_parity))
2855 : 0 : {
2856 : : #if ( FIX_I2I_STEREOCONVERSION_BUG2 == 1 )
2857 : : /* (2008-04-02) 1=> Fix bug of i2i conversion SAbs-->(SRel||Srac) */
2858 : : /* (converter skipped empty '/t' or sometimes produced an excess one */
2859 : :
2860 : : /* check whether t stereo is actually present */
2861 : 0 : int bHave_t_stereo = 1;
2862 [ # # ]: 0 : if (pInChI->Stereo)
2863 : 0 : bHave_t_stereo = pInChI->Stereo->nNumberOfStereoCenters;
2864 : : /* account for stereobonds present */
2865 [ # # ]: 0 : if (bHave_t_stereo < 1)
2866 [ # # ]: 0 : if (pInChI->Stereo->nNumberOfStereoBonds > 0)
2867 : 0 : bHave_t_stereo = 1;
2868 : : /* copy stereo anyway ... */
2869 : : #endif
2870 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3, 0, 0)) ||
2871 [ # # # # : 0 : ((!pInChI->Stereo->nCompInv2Abs || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs) &&
# # ]
2872 : 0 : 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 0, 0)))) /* djb-rwth: addressing LLVM warning */
2873 : : {
2874 : 0 : goto exit_function;
2875 : : }
2876 : :
2877 : : #if ( FIX_I2I_STEREOCONVERSION_BUG2 == 1 )
2878 : : /* ... correct just copied stereo if applicable */
2879 [ # # # # ]: 0 : if ((s[iINChI][j][0] < 1) &&
2880 : 0 : (bHave_t_stereo < 1) &&
2881 [ # # ]: 0 : (pAltInChI->Stereo->nNumberOfStereoCenters > 0) &&
2882 [ # # ]: 0 : (s[iINChI][jAlt][0] < 1))
2883 : : {
2884 : : /* (2010-02-28) if not all stereo centers are unknown/undefined */
2885 : : /* at which condition stereo still should present .. */
2886 : 0 : int all_UU = 1;
2887 [ # # ]: 0 : for (kc = 0; kc < pAltInChI->Stereo->nNumberOfStereoCenters; kc++)
2888 : : {
2889 [ # # ]: 0 : if ((pAltInChI->Stereo->t_parity[kc] != AB_PARITY_UNKN) &&
2890 [ # # ]: 0 : (pAltInChI->Stereo->t_parity[kc] != AB_PARITY_UNDF))
2891 : : {
2892 : 0 : all_UU = 0;
2893 : 0 : break;
2894 : : }
2895 : : }
2896 [ # # ]: 0 : if (!all_UU)
2897 : 0 : pInChI->Stereo->nNumberOfStereoCenters = 0;
2898 : : }
2899 : : #endif
2900 : :
2901 : : /* in case of missing nCompInv2Abs, 2005-05-10 */
2902 [ # # ]: 0 : if ((pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT) &&
2903 [ # # ]: 0 : (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2904 : : {
2905 [ # # # # ]: 0 : if (s[iINChI][jAlt][0] > 0 && s[iINChI][j][0] > 0)
2906 : : {
2907 : : /* suppose once in a while only non-taut stereo changes if inverted */
2908 [ # # ]: 0 : pAltInChI->Stereo->nCompInv2Abs = (++nMH2FH_AltInv) % 2 ? 2 : 0;
2909 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2910 : : }
2911 : : else
2912 : : {
2913 : : /* 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 */
2914 : : /* Mobile-H /sN was caused by another component that would have same /mN in all layers */
2915 : : /* therefore, in case of Abs. Stereo, Mobile-H stereo isotopic stereo would have /m1 */
2916 : : /* In case of Rel/Rac stereo, since no /m1 could occur in Mobile-H isotopic, */
2917 : : /* no pAltInChI->StereoIsotopic or pInChI->StereoIsotopic have been created yet. */
2918 : : /* added 10-11-2007 to fix i2i bug for Rel/Rac stereo */
2919 [ # # # # ]: 0 : if (nNumComponents[iINChI][j] > 1 &&
2920 [ # # # # ]: 0 : bNo_InChI_t && bNo_InChI_m /* no /t... or /mN in Fixed-H */ && !nFlags &&
2921 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
2922 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity) &&
2923 [ # # # # ]: 0 : s[iINChI][j][0] == 0 && s[iINChI][j][1] == 0 &&
2924 : : /* /sN, N=2 or 3 only in Mobile-H AND Mobile-H isotopic */
2925 [ # # ]: 0 : (s[iINChI][jAlt][0] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))) &&
2926 [ # # ]: 0 : (s[iINChI][jAlt][1] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))))
2927 : : {
2928 [ # # ]: 0 : if (bIso)
2929 : : {
2930 : : /* create two zero/NULL-initialized isotopic stereo if they do not exist */
2931 [ # # # # ]: 0 : if ((!pInChI->StereoIsotopic && 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, -1)))
2932 : : /* -- the following will be created later, in TAUT_YES part of the code -- */
2933 [ # # # # ]: 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 */
2934 : : {
2935 : 0 : goto exit_function;
2936 : : }
2937 : : /* same value = 2 for MI and FI; here we assign only FI */
2938 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
2939 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2940 : : /* -- the following will NOT be assigned later, in TAUT_YES part of the code -- */
2941 : 0 : pAltInChI->StereoIsotopic->nCompInv2Abs = 2;
2942 : 0 : pAltInChI->Stereo->nCompInv2Abs = 0;
2943 : : /* */
2944 : : }
2945 : : else
2946 : : {
2947 [ # # ]: 0 : if (NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs &&
2948 [ # # ]: 0 : NO_VALUE_INT == pAltInChI->Stereo->nCompInv2Abs)
2949 : : {
2950 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2951 : 0 : pAltInChI->Stereo->nCompInv2Abs = 2;
2952 : : }
2953 : : }
2954 : : }
2955 : : else
2956 : : {
2957 [ # # # # : 0 : if ((s[iINChI][jAlt][0] > 0 || s[iINChI][j][0] > 0) && s[iINChI][j][0] >= 0)
# # ]
2958 : : {
2959 : 0 : pInChI->Stereo->nCompInv2Abs = 2;
2960 : : }
2961 : : else
2962 : : {
2963 : : /* Mobile-H: /t..., no /sN; Mobile-H isotopic: /s2 or /s3, not /t; Fixed-H layer is present, has no /t, no /i/t */
2964 : : /* therefore, in case of Abs. Stereo, Mobile-H stereo isotopic stereo would have /m1 */
2965 : : /* In case of Rel/Rac stereo, since no /m1 could occur in Mobile-H isotopic, */
2966 : : /* no pAltInChI->StereoIsotopic or pInChI->StereoIsotopic have been created yet. */
2967 : : /* added 10-10-2007 to fix i2i bug for Rel/Rac stereo */
2968 [ # # # # : 0 : if (bIso && bNo_InChI_t && bNo_InChI_m /* no /t... or /mN in Fixed-H */ && !nFlags &&
# # # # ]
2969 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
2970 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity) &&
2971 [ # # # # : 0 : s[iINChI][jAlt][0] == 0 && s[iINChI][j][0] == 0 && s[iINChI][j][1] == 0 &&
# # ]
2972 : : /* /sN, N=2 or 3 only in Mobile-H isotopic */
2973 [ # # ]: 0 : (s[iINChI][jAlt][1] & ((INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO))))
2974 : : {
2975 : : /* create two zero/NULL-initialized isotopic stereo if they do not exist */
2976 [ # # # # ]: 0 : if (!pInChI->StereoIsotopic && 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, -1))
2977 : : /* -- the following will be created later, in TAUT_YES part of the code -- */
2978 : : /*|| !pAltInChI->StereoIsotopic && 0 > (ret2 = CopySegment( pAltInChI, pAltInChI, CPY_SP3_M, 1, -1))*/)
2979 : : {
2980 : 0 : goto exit_function;
2981 : : }
2982 : : /* same value = 2 for MI and FI; here we assign only FI */
2983 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
2984 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2985 : : /* -- the following will be assigned later, in TAUT_YES part of the code -- */
2986 : : /*
2987 : : pAltInChI->StereoIsotopic->nCompInv2Abs = 2;
2988 : : pAltInChI->Stereo->nCompInv2Abs = 0;
2989 : : */
2990 : : }
2991 : : else
2992 : : {
2993 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
2994 : : }
2995 : : }
2996 : : }
2997 : : }
2998 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
2999 : : {
3000 : 0 : pInChI->nFlags |= ((nFlagsAlt | nFlags) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3001 : : }
3002 : : }
3003 : : }
3004 : : else
3005 : : {
3006 : : /* copy sp3 inversion info: non-isotopic Mobile H => non-isotopic Fixed H */
3007 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoCenters &&
3008 [ # # # # ]: 0 : pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters &&
3009 [ # # ]: 0 : pAltInChI->Stereo->nCompInv2Abs &&
3010 [ # # # # ]: 0 : (!pInChI->Stereo->nCompInv2Abs || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs))
3011 : : {
3012 [ # # # # : 0 : if (!(nFlagsAlt && !nFlags) || NO_VALUE_INT == pInChI->Stereo->nCompInv2Abs)
# # ]
3013 : : {
3014 : : /* ??? */
3015 : 0 : pInChI->Stereo->nCompInv2Abs = pAltInChI->Stereo->nCompInv2Abs;
3016 : : }
3017 : : }
3018 : : }
3019 : :
3020 : : /* use same rule to copy stereobonds */
3021 [ # # # # ]: 0 : if (pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoBonds &&
3022 [ # # # # ]: 0 : (!pInChI->Stereo || !pInChI->Stereo->b_parity))
3023 : : {
3024 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 0, 0)))
3025 : : {
3026 : 0 : goto exit_function;
3027 : : }
3028 : : }
3029 : : /* (3) isotopic Mobile H -> isotopic Fixed H */
3030 : : /* if !FH_Stereo && !MH_Stereo && MH_IsoStereo!=NULL && FH_IsoStereo==NULL */
3031 [ # # ]: 0 : if (bIso)
3032 : : {
3033 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->t_parity) && /* !FH_Stereo */
3034 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->t_parity) && /* !MH_Stereo */
3035 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) && /* MH_IsoStereo */
3036 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->t_parity))
3037 : : {
3038 : : /* !FH_IsoStereo */
3039 : : /* copy sp3 iso stereo MI->FI (/t) and, if FH nCompInv2Abs (/m) is missing, copy it, too, MI->FI */
3040 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3, 1, 1)) ||
3041 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
3042 : 0 : 0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))) /* djb-rwth: addressing LLVM warning */
3043 : : {
3044 : 0 : goto exit_function;
3045 : : }
3046 : : /* in case of missing nCompInv2Abs, Relative or Racemic stereo 2005-05-10 */
3047 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT &&
3048 [ # # ]: 0 : (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3049 : : {
3050 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][jAlt][1] > 0 ? 2 : 0;
3051 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3052 : : {
3053 : 0 : pInChI->nFlags |= (nFlagsAlt & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3054 : : }
3055 : : }
3056 : : }
3057 : : else
3058 : : {
3059 : : /* copy sp3 inversion info only: isotopic Mobile H -> isotopic Fixed H */
3060 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->t_parity) && /* !FH_Stereo /t */
3061 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->t_parity) && /* !MH_Stereo /t */
3062 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) && /* MH_IsoStereo /t */
3063 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) && /* FH_IsoStereo /t */
3064 [ # # ]: 0 : pAltInChI->StereoIsotopic->nCompInv2Abs && /* MH_IsoStereo /m */
3065 [ # # # # ]: 0 : (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs))
3066 : : {
3067 : : /* !FH_IsoStereo /m */
3068 : : /* added 02-09-2006 */
3069 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))
3070 : : {
3071 : 0 : goto exit_function;
3072 : : }
3073 : : }
3074 : : }
3075 : : /* use same rule to copy stereobonds */
3076 [ # # # # ]: 0 : if (!(pInChI->Stereo && pInChI->Stereo->b_parity) &&
3077 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->b_parity) &&
3078 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoBonds) &&
3079 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
3080 : : {
3081 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 1, 1)))
3082 : : {
3083 : 0 : goto exit_function;
3084 : : }
3085 : : }
3086 : :
3087 : : /* (4) Copy Fixed-H -> isotopic Fixed-H */
3088 : : /* if FH_Stereo && !MH_IsoStereo && && !FH_IsoStereo */
3089 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->nNumberOfStereoCenters) && /* FH_Stereo /t */
3090 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) && /* !MH_IsoStereo /t */
3091 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && pInChI->StereoIsotopic->t_parity))
3092 : : {
3093 : : /* !FH_IsoStereo /t */
3094 : :
3095 : : /* added 10-10-2007 DT: copy MH_Iso /m => FH_Iso /m to fix i2i bug for Abs stereo */
3096 : : /* InChI string contains: MH(/t...), MH_Iso(/mN, no /t), FH(no /t /m), FH_Iso(no /t /m) */
3097 [ # # # # : 0 : if (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nCompInv2Abs && /* MH_IsoStereo /m */
# # ]
3098 : 0 : bNo_InChI_t &&
3099 [ # # ]: 0 : NO_VALUE_INT != pAltInChI->StereoIsotopic->nCompInv2Abs && /* undef FH_IsoStereo /m */
3100 [ # # # # ]: 0 : !(pInChI->StereoIsotopic && NO_VALUE_INT != pInChI->StereoIsotopic->nCompInv2Abs))
3101 : : {
3102 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP3_M, 1, 1)))
3103 : : {
3104 : 0 : goto exit_function;
3105 : : }
3106 : : }
3107 : :
3108 : : /* added 05-09-2006: copy sp3 FH=>FH_Iso */
3109 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3, 1, 0)) ||
3110 [ # # # # : 0 : ((!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs) &&
# # ]
3111 : 0 : 0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))) /* djb-rwth: addressing LLVM warning */
3112 : : {
3113 : 0 : goto exit_function;
3114 : : }
3115 : :
3116 : : /* in case of missing nCompInv2Abs, Relative or Racemic stereo, /sN in Fixed-H, 2005-05-10 */
3117 [ # # ]: 0 : if (pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT &&
3118 [ # # ]: 0 : (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3119 : : {
3120 [ # # # # ]: 0 : if (s[iINChI][j][0] > 0 && s[iINChI][j][1] > 0)
3121 : : {
3122 : : /* suppose once in a while only non-taut stereo changes if inverted */
3123 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
3124 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = (++nFH2iFH_AltInv) % 2 ? 2 : 0;
3125 : : }
3126 : : else
3127 : : {
3128 [ # # # # : 0 : if ((s[iINChI][j][0] > 0 || s[iINChI][j][1] > 0) && s[iINChI][j][1] >= 0) /* ??? != NO_VALUE_INT ??? */
# # ]
3129 : : {
3130 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 2;
3131 : : }
3132 : : else
3133 : : {
3134 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3135 : : }
3136 : : }
3137 [ # # ]: 0 : if (!(pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO)))
3138 : : {
3139 : 0 : pInChI->nFlags |= (nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO));
3140 : : }
3141 : : }
3142 : : }
3143 : : else
3144 : : {
3145 : : /* copy sp3 inversion info only: Fixed-H -> isotopic Fixed H */
3146 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->t_parity) &&
3147 [ # # # # ]: 0 : !(pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->t_parity) &&
3148 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoCenters) &&
3149 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nNumberOfStereoCenters) &&
3150 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs &&
3151 [ # # # # ]: 0 : (!pInChI->StereoIsotopic->nCompInv2Abs || NO_VALUE_INT == pInChI->StereoIsotopic->nCompInv2Abs))
3152 : : {
3153 : : /* added 05-09-2006 */
3154 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pInChI, CPY_SP3_M, 1, 0)))
3155 : : {
3156 : 0 : goto exit_function;
3157 : : }
3158 : : }
3159 : : }
3160 : : }
3161 [ # # ]: 0 : if (bIso &&
3162 [ # # # # ]: 0 : !(pInChI->Stereo && pInChI->Stereo->nNumberOfStereoBonds) &&
3163 [ # # # # ]: 0 : !(pAltInChI->Stereo && pAltInChI->Stereo->nNumberOfStereoBonds) &&
3164 [ # # # # ]: 0 : (pAltInChI->StereoIsotopic && pAltInChI->StereoIsotopic->nNumberOfStereoBonds) &&
3165 [ # # # # ]: 0 : (!pInChI->StereoIsotopic || !pInChI->StereoIsotopic->b_parity))
3166 : : {
3167 [ # # ]: 0 : if (0 > (ret2 = CopySegment(pInChI, pAltInChI, CPY_SP2, 1, 1)))
3168 : : {
3169 : 0 : goto exit_function;
3170 : : }
3171 : : }
3172 : : }
3173 : : }
3174 : : } /* end of component cycle (k) */
3175 : : } /* end of Mobile/Fixed H cycle (j) */
3176 : :
3177 : : /**** replace NO_VALUE_INT with zeroes in all Mobile & Fixed H components ****/
3178 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3179 : : {
3180 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
3181 : : {
3182 [ # # ]: 0 : if (pInpInChI[iINChI][j])
3183 : : {
3184 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
3185 [ # # ]: 0 : if (pInChI->nTotalCharge == NO_VALUE_INT)
3186 : : {
3187 : 0 : pInChI->nTotalCharge = 0;
3188 : : }
3189 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->StereoIsotopic &&
3190 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
3191 : : {
3192 [ # # ]: 0 : if (pInChI->Stereo->nNumberOfStereoCenters &&
3193 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs != NO_VALUE_INT)
3194 : : {
3195 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = pInChI->Stereo->nCompInv2Abs;
3196 : : }
3197 : : }
3198 : : /* Add special nCompInv2Abs=2 to force /s2 or /s3 in InChI output */
3199 [ # # # # ]: 0 : if (pInChI->Stereo && pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT)
3200 : : {
3201 [ # # ]: 0 : if (pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) &&
3202 [ # # ]: 0 : pInChI->Stereo->nNumberOfStereoCenters)
3203 : : {
3204 [ # # ]: 0 : pInChI->Stereo->nCompInv2Abs = (s[iINChI][j][0] > 0 /*|| s[iINChI][j][1]>0*/) ? 2 : 0; /* we do not know the real value */
3205 : : }
3206 : : else
3207 : : {
3208 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3209 : : }
3210 : : }
3211 [ # # # # ]: 0 : if (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)
3212 : : {
3213 [ # # ]: 0 : if (pInChI->nFlags & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) &&
3214 [ # # ]: 0 : pInChI->StereoIsotopic->nNumberOfStereoCenters)
3215 : : {
3216 [ # # ]: 0 : pInChI->StereoIsotopic->nCompInv2Abs = s[iINChI][j][1] > 0 ? 2 : 0; /* we do not know the real value */
3217 : : }
3218 : : else
3219 : : {
3220 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3221 : : }
3222 : : }
3223 : : /* added 02-07-2006 */
3224 [ # # # # ]: 0 : if ((pInChI->Stereo && pInChI->Stereo->nCompInv2Abs == NO_VALUE_INT) ||
3225 [ # # # # ]: 0 : (pInChI->StereoIsotopic && pInChI->StereoIsotopic->nCompInv2Abs == NO_VALUE_INT)) /* djb-rwth: addressing LLVM warnings */
3226 : : {
3227 : 0 : ret2 = RI_ERR_PROGR;
3228 : 0 : goto exit_function;
3229 : : }
3230 [ # # # # ]: 0 : if (!pInChI->bDeleted && pInChI->nNumberOfAtoms)
3231 : : {
3232 : 0 : tot_charge[iINChI][j] += pInChI->nTotalCharge;
3233 [ # # ]: 0 : for (m = 0; m < pInChI->nNumberOfAtoms; m++)
3234 : : {
3235 [ # # # # ]: 0 : if (pInChI->nAtom[m] < EL_NUMBER_H || pInChI->nAtom[m] > nElDataLen)
3236 : : {
3237 : 0 : ret2 = RI_ERR_PROGR;
3238 : 0 : goto exit_function;
3239 : : }
3240 : : /* all atoms except H */
3241 [ # # ]: 0 : if (pInChI->nAtom[m] > EL_NUMBER_H)
3242 : : {
3243 : 0 : num_elem[iINChI][j][pInChI->nAtom[m]].num++;
3244 : : }
3245 : : }
3246 [ # # ]: 0 : if (0 > (ret2 = GetInChINumH(pInChI, &m)))
3247 : : {
3248 : 0 : goto exit_function;
3249 : : }
3250 : 0 : num_elem[iINChI][j][EL_NUMBER_H].num += m;
3251 : : }
3252 : : }
3253 : : }
3254 : : }
3255 : :
3256 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3257 : : {
3258 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
3259 : : {
3260 [ # # ]: 0 : if (pInpInChI[iINChI][j])
3261 : : {
3262 : 0 : INChI* pInChI = &pInpInChI[iINChI][j][k];
3263 [ # # # # ]: 0 : if (pInChI->Stereo && !pInChI->Stereo->nNumberOfStereoCenters)
3264 : : {
3265 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3266 : : }
3267 [ # # # # ]: 0 : if (pInChI->StereoIsotopic && !pInChI->StereoIsotopic->nNumberOfStereoCenters)
3268 : : {
3269 : 0 : pInChI->StereoIsotopic->nCompInv2Abs = 0;
3270 : : }
3271 : : }
3272 : : }
3273 : : }
3274 : :
3275 : : #if ( FIX_I2I_STEREOCONVERSION_BUG3 == 1 )
3276 : : /* (2008-04-10) 1=> Fix bug of i2i conversion */
3277 : : /* (missed repeating /s in FI after F for multi-component case) */
3278 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_NON] > 1) /* if multi-component */
3279 : : {
3280 [ # # # # ]: 0 : if (!s[iINChI][TAUT_YES][0] && !s[iINChI][TAUT_YES][1])/* if no /s in M, MI */
3281 : : {
3282 [ # # # # ]: 0 : if ((s[iINChI][TAUT_NON][0] > 1) && (s[iINChI][TAUT_NON][1] > 1)) /* if /srel/srac in both F, FI */
3283 : : {
3284 [ # # ]: 0 : if (s[iINChI][TAUT_NON][0] == s[iINChI][TAUT_NON][1]) /* if same stereo in F and FI */
3285 : : {
3286 : : /* we assume that at least one component in F has no actual stereo */
3287 : : /* and place deliberately 0 to appropriate place */
3288 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][TAUT_NON]; k++)
3289 : : {
3290 : 0 : INChI* pInChI = &pInpInChI[iINChI][TAUT_NON][k];
3291 [ # # ]: 0 : if (pInChI->Stereo->nCompInv2Abs != 0)
3292 : : {
3293 : 0 : pInChI->Stereo->nCompInv2Abs = 0;
3294 : 0 : goto fini;
3295 : : }
3296 : : }
3297 : : }
3298 : : }
3299 : : }
3300 : : }
3301 : 0 : fini:;
3302 : : #endif
3303 [ # # ]: 0 : if (num_elem[iINChI][TAUT_YES])
3304 : : {
3305 : 0 : tot_charge[iINChI][TAUT_YES] += nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
3306 : 0 : num_elem[iINChI][TAUT_YES][EL_NUMBER_H].num += nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons;
3307 : : }
3308 : :
3309 : : /**** Count H and isotopic H in Mobile and Fixed H represntations of components */
3310 : : /* if at least one component has Fixed-H layer then all components have Fixed-H */
3311 : : /* layer; those whose Fixed-H layer is empty have Fixed-H layer same as Mobile-H layer */
3312 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_NON])
3313 : : {
3314 : : /* only if both Mobile and Fixed H exist */
3315 : : int nFormulaH[TAUT_NUM], nNumH[TAUT_NUM], nCharge[TAUT_NUM], nNumIsotopicH[TAUT_NUM][NUM_H_ISOTOPES];
3316 : : int nRemovedCharge, nRemovedH, nRemovedIsotopicH[NUM_H_ISOTOPES], nFoundRemovedIsoH;
3317 : : int nTotRemovedProtons, nTotRemovedIsotopicH[NUM_H_ISOTOPES], bExists[TAUT_NUM];
3318 : : INChI* pInChI[TAUT_NUM];
3319 : 0 : nTotRemovedProtons = 0;
3320 : 0 : memset(nTotRemovedIsotopicH, 0, sizeof(nTotRemovedIsotopicH)); /* djb-rwth: memset_s C11/Annex K variant? */
3321 : 0 : len2 = inchi_max(nNumComponents[iINChI][TAUT_YES], nNumComponents[iINChI][TAUT_NON]);
3322 : :
3323 [ # # ]: 0 : for (k = 0; k < len2; k++)
3324 : : {
3325 : : /* k is a component index */
3326 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3327 : : {
3328 : : /* j is 0=TAUT_NON or 1=TAUT_YES */
3329 : 0 : pInChI[j] = NULL; /* initialization 2006-03 */
3330 : 0 : bExists[j] = (k < nNumComponents[iINChI][j]) &&
3331 [ # # # # ]: 0 : pInpInChI[iINChI][j][k].nNumberOfAtoms &&
3332 [ # # ]: 0 : !pInpInChI[iINChI][j][k].bDeleted;
3333 : : }
3334 [ # # ]: 0 : if (!bExists[TAUT_NON])
3335 : : {
3336 : : /* TAUT_YES does not exist for a proton (H+) in TAUT_NON */
3337 : 0 : ret2 = RI_ERR_SYNTAX;
3338 : 0 : goto exit_function;
3339 : : }
3340 : : /* at this point at least one of Mobile[k] and Fixed[k] real InChI exists */
3341 : : /* initialize for counting removed protons and isotopic H from kth Mobile-H component */
3342 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3343 : : {
3344 [ # # ]: 0 : if (bExists[j])
3345 : : {
3346 : 0 : pInChI[j] = &pInpInChI[iINChI][j][k]; /* BC: reading uninit memory (fixed?) */
3347 : : }
3348 : 0 : nFormulaH[j] = 0;
3349 : 0 : nNumH[j] = 0;
3350 : 0 : nCharge[j] = 0;
3351 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3352 : : {
3353 : 0 : nNumIsotopicH[j][m] = 0;
3354 : : }
3355 : : }
3356 : : /* extract number of H, isotopic H, and charge */
3357 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3358 : : {
3359 [ # # ]: 0 : if (!bExists[j])
3360 : : {
3361 : 0 : continue;
3362 : : }
3363 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI[j], &nFormulaH[j])) ||
3364 [ # # ]: 0 : 0 > (ret2 = GetInChINumH(pInChI[j], &nNumH[j])) ||
3365 : 0 : 0 > (ret2 = GetInChIIsoH(pInChI[j], nNumIsotopicH[j])))
3366 : : {
3367 : 0 : goto exit_function;
3368 : : }
3369 : 0 : nCharge[j] = pInChI[j]->nTotalCharge;
3370 : : }
3371 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3372 : : {
3373 [ # # ]: 0 : if (!bExists[j])
3374 : : {
3375 : 0 : continue;
3376 : : }
3377 [ # # ]: 0 : if (nFormulaH[j] != nNumH[j])
3378 : : {
3379 : 0 : ret2 = RI_ERR_SYNTAX;
3380 : 0 : goto exit_function;
3381 : : }
3382 : : }
3383 : 0 : nFoundRemovedIsoH = 0;
3384 : 0 : nRemovedCharge = nCharge[TAUT_NON] - nCharge[TAUT_YES];
3385 : 0 : nRemovedH = nNumH[TAUT_NON] - nNumH[TAUT_YES];
3386 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3387 : : {
3388 : 0 : nFoundRemovedIsoH += 0 != (nRemovedIsotopicH[m] = nNumIsotopicH[TAUT_NON][m] -
3389 : 0 : nNumIsotopicH[TAUT_YES][m]);
3390 : : }
3391 [ # # ]: 0 : if (nRemovedCharge != nRemovedH)
3392 : : {
3393 : 0 : ret2 = RI_ERR_SYNTAX;
3394 : 0 : goto exit_function;
3395 : : }
3396 [ # # # # ]: 0 : if (nRemovedCharge || nFoundRemovedIsoH)
3397 : : {
3398 : : COMPONENT_REM_PROTONS* pNumProtons;
3399 [ # # ]: 0 : if (!nNumProtons[iINChI][TAUT_YES].pNumProtons)
3400 : : {
3401 : : /* allocate only if needed */
3402 : 0 : nNumProtons[iINChI][TAUT_YES].pNumProtons =
3403 : 0 : (COMPONENT_REM_PROTONS*)inchi_calloc(len2,
3404 : : sizeof(nNumProtons[0][0].pNumProtons[0]));
3405 [ # # ]: 0 : if (!nNumProtons[iINChI][TAUT_YES].pNumProtons)
3406 : : {
3407 : 0 : ret2 = RI_ERR_ALLOC;
3408 : 0 : goto exit_function;
3409 : : }
3410 : : }
3411 : 0 : pNumProtons = nNumProtons[iINChI][TAUT_YES].pNumProtons + k;
3412 : 0 : pNumProtons->nNumRemovedProtons = nRemovedH;
3413 : 0 : nTotRemovedProtons += nRemovedH;
3414 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3415 : : {
3416 : 0 : pNumProtons->nNumRemovedIsotopicH[m] = nRemovedIsotopicH[m];
3417 : 0 : nTotRemovedIsotopicH[m] += nRemovedIsotopicH[m];
3418 : : }
3419 : : /* make sure the Mobile-H InChI has nTautomer */
3420 [ # # # # ]: 0 : if (pInChI[TAUT_YES] && bExists[TAUT_YES])
3421 : : {
3422 [ # # ]: 0 : if (!pInChI[TAUT_YES]->lenTautomer)
3423 : : {
3424 : 0 : pInChI[TAUT_YES]->lenTautomer = 1;
3425 : : }
3426 [ # # ]: 0 : if (!pInChI[TAUT_YES]->nTautomer)
3427 : : {
3428 : 0 : pInChI[TAUT_YES]->nTautomer = (AT_NUMB*)inchi_calloc(pInChI[TAUT_YES]->lenTautomer, sizeof(pInChI[0]->nTautomer[0]));
3429 : : }
3430 : : }
3431 : : }
3432 : : }
3433 [ # # ]: 0 : if (nNumProtons[iINChI][TAUT_YES].pNumProtons)
3434 : : {
3435 : : /* check consistency */
3436 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3437 : : int iso_diff[NUM_H_ISOTOPES], iso_diff_tot = 0;
3438 : : #endif
3439 [ # # ]: 0 : if (nTotRemovedProtons != nNumProtons[iINChI][TAUT_YES].nNumRemovedProtons)
3440 : : {
3441 : 0 : ret2 = RI_ERR_SYNTAX;
3442 : 0 : goto exit_function;
3443 : : }
3444 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3445 : : for (m = 0; m < NUM_H_ISOTOPES; m++)
3446 : : {
3447 : : iso_diff[m] = nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m] - nTotRemovedIsotopicH[m];
3448 : : if (iso_diff[m] < 0)
3449 : : {
3450 : : ret2 = RI_ERR_SYNTAX;
3451 : : goto exit_function;
3452 : : }
3453 : : else
3454 : : {
3455 : : /* InChI-1.02b bug: nTotRemovedIsotopicH[m] < nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m] */
3456 : : /* in non-tautomeric components where D(+) or T(+) was removed from -NH(+)= or =OH(+) */
3457 : : iso_diff_tot += iso_diff[m];
3458 : : }
3459 : : }
3460 : : if (iso_diff_tot)
3461 : : {
3462 : : if (0 > bIsoMayBeArranged(bInchi2Struct, iso_diff, nNumProtons, pInpInChI, nNumComponents, iINChI))
3463 : : {
3464 : : ret2 = RI_ERR_SYNTAX;
3465 : : goto exit_function;
3466 : : }
3467 : : }
3468 : : #else
3469 [ # # ]: 0 : for (m = 0; m < NUM_H_ISOTOPES; m++)
3470 : : {
3471 [ # # ]: 0 : if (nTotRemovedIsotopicH[m] != nNumProtons[iINChI][TAUT_YES].nNumRemovedIsotopicH[m])
3472 : : {
3473 : 0 : ret2 = RI_ERR_SYNTAX;
3474 : 0 : goto exit_function;
3475 : : }
3476 : : }
3477 : : #endif
3478 : : }
3479 : : }
3480 : :
3481 : : /* make Mobile H and Fixed H InChI arrays have same length */
3482 : 0 : len2 = len1 = 0;
3483 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_YES] < nNumComponents[iINChI][TAUT_NON])
3484 : : {
3485 : 0 : j = TAUT_YES; /* less components in Mobile-H layer */
3486 : 0 : len2 = nNumComponents[iINChI][TAUT_NON];
3487 : 0 : len1 = nNumComponents[iINChI][TAUT_YES];
3488 : : }
3489 : : else
3490 [ # # ]: 0 : if (nNumComponents[iINChI][TAUT_YES] > nNumComponents[iINChI][TAUT_NON])
3491 : : {
3492 : 0 : j = TAUT_NON; /* less components in Fixed-H layer */
3493 : 0 : len2 = nNumComponents[iINChI][TAUT_YES];
3494 : 0 : len1 = nNumComponents[iINChI][TAUT_NON];
3495 : : }
3496 : : /* always len1 <= len2; if Mobile-H and Fixed-H have same number of components then len1=len2=0 */
3497 [ # # # # ]: 0 : if (len2 && len1)
3498 : : {
3499 : 0 : INChI* pInChI = (INChI*)inchi_calloc(len2, sizeof(pInChI[0]));
3500 [ # # ]: 0 : if (!pInChI)
3501 : : {
3502 : 0 : ret2 = RI_ERR_ALLOC;
3503 : 0 : goto exit_function;
3504 : : }
3505 : 0 : memcpy(pInChI, pInpInChI[iINChI][j], len1 * sizeof(pInChI[0]));
3506 [ # # ]: 0 : inchi_free(pInpInChI[iINChI][j]);
3507 : 0 : pInpInChI[iINChI][j] = pInChI;
3508 : 0 : nNumComponents[iINChI][j] = len2;
3509 [ # # ]: 0 : for (; len1 < len2; len1++)
3510 : : {
3511 [ # # ]: 0 : if (j == TAUT_YES)
3512 : : {
3513 : : /* mark added to Mobile H layer components as deleted protons */
3514 [ # # ]: 0 : if (0 > (ret2 = nFillOutProtonMobileH(pInpInChI[iINChI][j] + len1)))
3515 : : {
3516 : 0 : goto exit_function;
3517 : : }
3518 [ # # ]: 0 : if (0 > (ret2 = nProtonCopyIsotopicInfo(pInpInChI[iINChI][j] + len1/* to */,
3519 : 0 : pInpInChI[iINChI][TAUT_NON] + len1/* from */)))
3520 : : {
3521 : 0 : goto exit_function;
3522 : : }
3523 : : }
3524 : : else
3525 : : {
3526 : : /* mark added to Fixed H layer components as empty deleted */
3527 : : /* this should not happen */
3528 : 0 : pInChI[len1].bDeleted = 1;
3529 : : }
3530 : : }
3531 : : }
3532 : : } /* end of iINChI cycle */
3533 : :
3534 : : /* check balances */
3535 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
3536 : : {
3537 [ # # ]: 0 : for (i = iINChI; i < INCHI_NUM; i++)
3538 : : {
3539 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
3540 : : {
3541 [ # # ]: 0 : for (k = j; k < TAUT_NUM; k++)
3542 : : {
3543 [ # # # # : 0 : if ((iINChI != i || j != k) && num_elem[iINChI][j] && num_elem[i][k])
# # # # ]
3544 : : {
3545 [ # # ]: 0 : if (tot_charge[iINChI][j] != tot_charge[i][k])
3546 : : {
3547 : 0 : ret2 = RI_ERR_SYNTAX;
3548 : 0 : goto exit_function;
3549 : : }
3550 [ # # ]: 0 : for (m = 0; m <= nElDataLen; m++)
3551 : : {
3552 [ # # ]: 0 : if (num_elem[iINChI][j][m].num != num_elem[i][k][m].num)
3553 : : {
3554 : 0 : ret2 = RI_ERR_SYNTAX;
3555 : 0 : goto exit_function;
3556 : : }
3557 : : }
3558 : : /*
3559 : : if ( memcmp( num_elem[iINChI], num_elem[i][k], (nElDataLen+1)*sizeof(num_elem[0][0][0]) ) {
3560 : : ret2 = RI_ERR_SYNTAX;
3561 : : goto exit_function;
3562 : : }
3563 : : */
3564 : : }
3565 : : }
3566 : : }
3567 : : }
3568 : : }
3569 : :
3570 : : }
3571 : : else
3572 : : {
3573 : 2 : ret2 = ret;
3574 : : }
3575 : :
3576 : 2 : exit_function:
3577 : :
3578 [ + + ]: 6 : for (i = 0; i < INCHI_NUM; i++)
3579 : : {
3580 [ + + ]: 12 : for (j = 0; j < TAUT_NUM; j++)
3581 : : {
3582 [ - + ]: 8 : if (num_elem[i][j])
3583 : : {
3584 [ # # ]: 0 : inchi_free(num_elem[i][j]);
3585 : 0 : num_elem[i][j] = NULL;
3586 : : }
3587 : : }
3588 : : }
3589 [ + - + - ]: 2 : *nErr = (ret2 < 0 && ret2 != RI_ERR_EOL) ? ret2 : 0;
3590 : :
3591 : 2 : return ret;
3592 : : }
3593 : :
3594 : :
3595 : : /****************************************************************************/
3596 : : #if ( FIX_ISO_FIXEDH_BUG_READ == 1 )
3597 : : #undef TAUT_YES
3598 : : int bIsoMayBeArranged(int bInchi2Struct,
3599 : : int iso_diff[NUM_H_ISOTOPES],
3600 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
3601 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
3602 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
3603 : : int iINChI)
3604 : : {
3605 : : const int TAUT_YES = 1;
3606 : : 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;
3607 : : for (m = 0; m < NUM_H_ISOTOPES; m++)
3608 : : {
3609 : : num_iso_H += iso_diff[m];
3610 : : }
3611 : : num_iso_H_orig = num_iso_H;
3612 : : for (k = 0; k < nNumComponents[iINChI][TAUT_YES] && k < nNumComponents[iINChI][TAUT_NON]; k++)
3613 : : {
3614 : : INChI* pInChI = &pInpInChI[iINChI][TAUT_NON][k];
3615 : : INChI* pInChITaut = &pInpInChI[iINChI][TAUT_YES][k];
3616 : : if (pInChITaut->bDeleted || pInChI->bDeleted ||
3617 : : pInChITaut->nNumberOfIsotopicAtoms > 0 ||
3618 : : pInChITaut->lenTautomer > 1 && pInChITaut->nTautomer && pInChITaut->nTautomer[0] > 0 ||
3619 : : NULL == nNumProtons[iINChI][TAUT_YES].pNumProtons ||
3620 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons <= 0 ||
3621 : : pInChI->nNumberOfIsotopicAtoms > 0 ||
3622 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[0] ||
3623 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[1] ||
3624 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[2]
3625 : : )
3626 : : {
3627 : : continue;
3628 : : }
3629 : : /* check if fixed-H has isotopic H; count the possibilities */
3630 : : orig_add_H = nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedProtons;
3631 : : n_found_at_in_component = 0; /* number of atoms that may accept isotopic H */
3632 : : n_found_H_in_component = 0;
3633 : : for (i = 0; i < pInChI->nNumberOfAtoms; i++)
3634 : : {
3635 : : int nNumRemovedH = (int)pInChI->nNum_H[i] - (int)pInChITaut->nNum_H[i];
3636 : : if (nNumRemovedH > 0)
3637 : : {
3638 : : n_found_at_in_component++;
3639 : : n_found_H_in_component += nNumRemovedH;
3640 : : }
3641 : : }
3642 : : if (n_found_at_in_component > 0 && num_iso_H > 0 && bInchi2Struct)
3643 : : {
3644 : : pInChI->IsotopicAtom = (INChI_IsotopicAtom*)inchi_calloc(inchi_min(n_found_at_in_component, num_iso_H), sizeof(pInChI->IsotopicAtom[0]));
3645 : : }
3646 : : for (i = 0, i_iso_at = 0; i < pInChI->nNumberOfAtoms; i++)
3647 : : {
3648 : : int nNumRemovedH = (int)pInChI->nNum_H[i] - (int)pInChITaut->nNum_H[i];
3649 : : n_found += nNumRemovedH; /* found H removed in mobile-H layer */
3650 : : if (nNumRemovedH > 0 && num_iso_H > 0 && orig_add_H)
3651 : : {
3652 : : for (m = 0; m < NUM_H_ISOTOPES && 0 < num_iso_H && 0 < orig_add_H && 0 < nNumRemovedH; m++)
3653 : : {
3654 : : if (iso_diff[m] > 0)
3655 : : {
3656 : : num_add_iso_H = inchi_min(iso_diff[m], nNumRemovedH); /* atom limit */
3657 : : if (num_add_iso_H > orig_add_H) /* component limit */
3658 : : num_add_iso_H = orig_add_H;
3659 : : iso_diff[m] -= num_add_iso_H; /* update tot removed single isotope H limit */
3660 : : num_iso_H -= num_add_iso_H; /* update tot removed isotopic H limit */
3661 : : orig_add_H -= num_add_iso_H; /* update component limit */
3662 : : nNumRemovedH -= num_add_iso_H; /* update atom limit */
3663 : : nNumProtons[iINChI][TAUT_YES].pNumProtons[k].nNumRemovedIsotopicH[m] += num_add_iso_H;
3664 : : if (pInChI->IsotopicAtom)
3665 : : {
3666 : : pInChI->IsotopicAtom[i_iso_at].nAtomNumber = i + 1;
3667 : : switch (m)
3668 : : {
3669 : : case 0:
3670 : : pInChI->IsotopicAtom[i_iso_at].nNum_H += num_add_iso_H;
3671 : : break;
3672 : : case 1:
3673 : : pInChI->IsotopicAtom[i_iso_at].nNum_D += num_add_iso_H;
3674 : : break;
3675 : : case 2:
3676 : : pInChI->IsotopicAtom[i_iso_at].nNum_T += num_add_iso_H;
3677 : : break;
3678 : : }
3679 : : }
3680 : : }
3681 : : }
3682 : : if (pInChI->IsotopicAtom)
3683 : : {
3684 : : i_iso_at++;
3685 : : }
3686 : : }
3687 : : }
3688 : : if (pInChI->IsotopicAtom && i_iso_at)
3689 : : {
3690 : : pInChI->nNumberOfIsotopicAtoms = i_iso_at;
3691 : : }
3692 : : }
3693 : : if (n_found - num_iso_H >= 0)
3694 : : {
3695 : : /* Success. Arrange isotopic H between components */
3696 : : }
3697 : :
3698 : : return n_found - num_iso_H_orig; /* >0 => ambiguous reconstruction, 0 => unambiguous, <0 => impossible */
3699 : : }
3700 : : #define TAUT_YES 1
3701 : : #endif
3702 : :
3703 : :
3704 : :
3705 : : /****************************************************************************/
3706 : : typedef enum tagAuxInfoState {
3707 : : AST_VERSION, /* 0 */
3708 : :
3709 : : AST_MOBILE_H_NUMBERS, /* 1 /N: */
3710 : : AST_MOBILE_H_ATOM_EQ, /* 2 /E: */
3711 : : AST_MOBILE_H_GROUP_EQ, /* 3 /gE: */
3712 : : AST_MOBILE_H_SP3_INV, /* 4 /it: */
3713 : : AST_MOBILE_H_SP3_INV_NUMBERS, /* 5 /iN: */
3714 : :
3715 : : AST_MOBILE_H_ISO_LAYER_FORK, /* 6 */
3716 : :
3717 : : AST_MOBILE_H_ISO_NUMBERS, /* 7 /I: */
3718 : : AST_MOBILE_H_ISO_ATOM_EQ, /* 8 /E: */
3719 : : AST_MOBILE_H_ISO_GROUP_EQ, /* 9 /gE: */
3720 : : AST_MOBILE_H_ISO_SP3_INV, /* 10 /it: */
3721 : : AST_MOBILE_H_ISO_SP3_INV_NUMBERS, /* 11 /iN: */
3722 : :
3723 : : AST_FIXED_H_LAYER_FORK, /* 12 */
3724 : :
3725 : : AST_FIXED_H_NUMBERS, /* 13 /F: */
3726 : : AST_FIXED_H_ATOM_EQ, /* 14 /E: */
3727 : : AST_FIXED_H_SP3_INV, /* 15 /it: */
3728 : : AST_FIXED_H_SP3_INV_NUMBERS, /* 16 /iN: */
3729 : :
3730 : : AST_FIXED_H_ISO_LAYER_FORK, /* 17 */
3731 : :
3732 : : AST_FIXED_H_ISO_NUMBERS, /* 18 /I: */
3733 : : AST_FIXED_H_ISO_ATOM_EQ, /* 19 /E: */
3734 : : AST_FIXED_H_ISO_SP3_INV, /* 20 /it: */
3735 : : AST_FIXED_H_ISO_SP3_INV_NUMBERS, /* 21 /iN: */
3736 : :
3737 : : AST_REVERSE_INFO_CRV, /* 22 /CRV: */
3738 : : AST_REVERSE_INFO_ATOMS, /* 23 /rA: */
3739 : : AST_REVERSE_INFO_BONDS, /* 24 /rB: */
3740 : : AST_REVERSE_INFO_XYZ, /* 25 /rC: */
3741 : :
3742 : : AST_RECONNECTED_LAYER_FORK, /* 26 /R: */
3743 : : AST_RECONNECTED_LAYER_NUMBERS /* 27 */
3744 : : }AUX_INFO_STATE;
3745 : :
3746 : :
3747 : : /****************************************************************************/
3748 : 0 : int ParseAuxSegmentVersion(const char* str,
3749 : : int bMobileH,
3750 : : INChI* pInpInChI[],
3751 : : int ppnNumComponents[],
3752 : : int state)
3753 : : {
3754 : : const char* q;
3755 [ # # # # ]: 0 : if (isdigit(UCINT * str) && (inchi_strtol(str, &q, 10), !*q))
3756 : : {
3757 : 0 : return 1;
3758 : : }
3759 : 0 : return RI_ERR_SYNTAX;
3760 : : }
3761 : :
3762 : :
3763 : : /****************************************************************************
3764 : : CopyAtomNumbers
3765 : :
3766 : : Save isotopic numbering into the first nNumberOfAtoms
3767 : : elements of INChI::nPossibleLocationsOfIsotopicH;
3768 : : save non-isotopic numbering into the second half of
3769 : : nNumberOfAtoms elements of INChI::nPossibleLocationsOfIsotopicH
3770 : : ****************************************************************************/
3771 : 0 : int CopyAtomNumbers(INChI* pInChI_To,
3772 : : int bIsoTo,
3773 : : INChI* pInChI_From,
3774 : : int bIsoFrom)
3775 : : {
3776 : : AT_NUMB* pTo, * pFrom;
3777 [ # # # # : 0 : if (!pInChI_To || !pInChI_From || pInChI_To->bDeleted || pInChI_From->bDeleted ||
# # # # ]
3778 [ # # # # ]: 0 : !pInChI_To->nNumberOfAtoms || !pInChI_From->nNumberOfAtoms ||
3779 [ # # ]: 0 : pInChI_To->nNumberOfAtoms != pInChI_From->nNumberOfAtoms ||
3780 [ # # ]: 0 : !pInChI_From->nPossibleLocationsOfIsotopicH)
3781 : : {
3782 : 0 : return RI_ERR_PROGR;
3783 : : }
3784 [ # # ]: 0 : if (!pInChI_To->nPossibleLocationsOfIsotopicH)
3785 : : {
3786 : 0 : pInChI_To->nPossibleLocationsOfIsotopicH = (AT_NUMB*)inchi_calloc(2 * (long long)pInChI_To->nNumberOfAtoms,
3787 : : sizeof(pInChI_To->nPossibleLocationsOfIsotopicH[0])); /* djb-rwth: cast operator added */
3788 [ # # ]: 0 : if (!pInChI_To->nPossibleLocationsOfIsotopicH)
3789 : : {
3790 : 0 : return RI_ERR_ALLOC;
3791 : : }
3792 : : }
3793 [ # # ]: 0 : pTo = pInChI_To->nPossibleLocationsOfIsotopicH + (bIsoTo ? 0 : pInChI_To->nNumberOfAtoms);
3794 [ # # ]: 0 : pFrom = pInChI_From->nPossibleLocationsOfIsotopicH + (bIsoFrom ? 0 : pInChI_To->nNumberOfAtoms);
3795 [ # # ]: 0 : if (pTo == pFrom)
3796 : : {
3797 : 0 : return RI_ERR_PROGR;
3798 : : }
3799 : 0 : memcpy(pTo, pFrom, pInChI_To->nNumberOfAtoms * sizeof(pTo[0]));
3800 : 0 : return 1;
3801 : : }
3802 : :
3803 : :
3804 : : /****************************************************************************
3805 : : Parse and save AuxInfo atom numbers in "/N:" or "/F:" or "/I:" segment
3806 : :
3807 : : NB: save isotopic numbering into the first nNumberOfAtoms
3808 : : elements of INChI::nPossibleLocationsOfIsotopicH;
3809 : : save non-isotopic numbering into the second half of nNumberOfAtoms
3810 : : elements of INChI::nPossibleLocationsOfIsotopicH
3811 : : ****************************************************************************/
3812 : 0 : int ParseAuxSegmentNumbers(const char* str, /* AuxInfo string */
3813 : : int bMobileH, /* treat mobile or fixedH domain nums */
3814 : : INChI* pInpInChI[],
3815 : : int ppnNumComponents[],
3816 : : int state, /* start position==state of reading */
3817 : : int* pbAbc /* ==1 if treating compresssed InChI */
3818 : : )
3819 : : {
3820 : 0 : int bIso = 0, iComponent = 0, nNumComponents, bIso_From = 0, bAltInChIExists;
3821 : 0 : INChI* pInChI = NULL, * pAltInChI = NULL, * pInChI_From = NULL;
3822 : : const char* p, * q, * pStart, * pEnd, * t;
3823 : : static const char mult_type[] = "mnM";
3824 : : int val, ret, k, mpy_component, num;
3825 : : AT_NUMB* pNumb;
3826 : 0 : int base = 10;
3827 : 0 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
3828 : :
3829 [ # # # # : 0 : switch (state)
# ]
3830 : : {
3831 : 0 : case AST_MOBILE_H_NUMBERS:
3832 [ # # ]: 0 : if (bMobileH != TAUT_YES)
3833 : : {
3834 : 0 : return RI_ERR_PROGR;
3835 : : }
3836 [ # # ]: 0 : if (memcmp(str, "N:", 2))
3837 : : {
3838 : 0 : return 0;
3839 : : }
3840 : 0 : break;
3841 : 0 : case AST_FIXED_H_NUMBERS:
3842 [ # # ]: 0 : if (bMobileH != TAUT_NON)
3843 : : {
3844 : 0 : return RI_ERR_PROGR;
3845 : : }
3846 [ # # ]: 0 : if (memcmp(str, "F:", 2))
3847 : : {
3848 : 0 : return 0;
3849 : : }
3850 : 0 : break;
3851 : 0 : case AST_MOBILE_H_ISO_NUMBERS:
3852 [ # # ]: 0 : if (bMobileH != TAUT_YES)
3853 : : {
3854 : 0 : return RI_ERR_PROGR;
3855 : : }
3856 [ # # ]: 0 : if (memcmp(str, "I:", 2))
3857 : : {
3858 : 0 : return 0;
3859 : : }
3860 : 0 : bIso = 1;
3861 : 0 : break;
3862 : 0 : case AST_FIXED_H_ISO_NUMBERS:
3863 [ # # ]: 0 : if (bMobileH != TAUT_NON)
3864 : : {
3865 : 0 : return RI_ERR_PROGR;
3866 : : }
3867 [ # # ]: 0 : if (memcmp(str, "I:", 2))
3868 : : {
3869 : 0 : return 0;
3870 : : }
3871 : 0 : bIso = 1;
3872 : 0 : break;
3873 : 0 : default:
3874 : 0 : return RI_ERR_PROGR;
3875 : : }
3876 : :
3877 : 0 : pStart = (char*)str + 2;
3878 [ # # ]: 0 : if (!*pStart)
3879 : : {
3880 : 0 : return 1;
3881 : : }
3882 : 0 : iComponent = 0;
3883 : 0 : nNumComponents = ppnNumComponents[bMobileH];
3884 : :
3885 [ # # ]: 0 : bAltInChIExists = (NULL != pInpInChI[ALT_TAUT(bMobileH)]);
3886 : : while (1)
3887 : : {
3888 : : /* Cycle over components */
3889 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
3890 : : {
3891 : 0 : pEnd = pStart + strlen(pStart);
3892 : : }
3893 : : /* check */
3894 [ # # ]: 0 : if (!pInpInChI[bMobileH])
3895 : : {
3896 : 0 : return 1; /* invalid aux info */
3897 : : }
3898 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
3899 [ # # ]: 0 : pAltInChI = pInpInChI[ALT_TAUT(bMobileH)] + iComponent;
3900 : :
3901 : : /* djb-rwth: condition for if block had to be rewritten */
3902 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
3903 : : {
3904 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
3905 : 0 : if_cnd = isdigit(UCINT * pStart);
3906 : :
3907 : : }
3908 : : else
3909 : : {
3910 : 0 : val = 1;
3911 : 0 : q = pStart;
3912 : 0 : if_cnd = 1;
3913 : : }
3914 : :
3915 [ # # # # : 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 */
# # ]
3916 : : {
3917 : : /* Process the abbreviation */
3918 : 0 : pInChI_From = NULL;
3919 [ # # # ]: 0 : switch (bMobileH)
3920 : : {
3921 : 0 : case TAUT_YES:
3922 [ # # # ]: 0 : switch (bIso)
3923 : : {
3924 : 0 : case 0:
3925 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
3926 : 0 : goto exit_function;
3927 : 0 : case 1:
3928 [ # # ]: 0 : if (*q != 'm')
3929 : : {
3930 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
3931 : 0 : goto exit_function;
3932 : : }
3933 : : /* isotopic Mobile-H <-- non-isotopic Mobile H */
3934 : 0 : pInChI_From = pInChI;
3935 : 0 : bIso_From = 0;
3936 : 0 : break;
3937 : 0 : default:
3938 : 0 : ret = RI_ERR_PROGR;
3939 : 0 : goto exit_function;
3940 : : }
3941 : 0 : break;
3942 : :
3943 : 0 : case TAUT_NON:
3944 [ # # # # ]: 0 : switch (*q)
3945 : : {
3946 : 0 : case 'm': /* same as mobile H */
3947 [ # # # ]: 0 : switch (bIso)
3948 : : {
3949 : 0 : case 0: /* from Mobile-H not isotopic */
3950 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;
3951 : 0 : bIso_From = 0;
3952 : 0 : break;
3953 : :
3954 : 0 : case 1:
3955 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;;
3956 : 0 : bIso_From = 1;
3957 : 0 : break;
3958 : 0 : default:
3959 : 0 : ret = RI_ERR_PROGR;
3960 : 0 : goto exit_function;
3961 : : }
3962 : 0 : break;
3963 : 0 : case 'n': /* same as non-isotopic Fixed-H */
3964 [ # # # ]: 0 : switch (bIso)
3965 : : {
3966 : 0 : case 0:
3967 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
3968 : 0 : goto exit_function;
3969 : 0 : case 1:
3970 : 0 : pInChI_From = pInChI; /* djb-rwth: ignoring LLVM warning: value used */
3971 : 0 : bIso_From = 0; /* djb-rwth: ignoring LLVM warning: value used */
3972 : 0 : default:
3973 : 0 : ret = RI_ERR_PROGR;
3974 : 0 : goto exit_function;
3975 : : }
3976 : : break;
3977 : 0 : case 'M': /* same as isotopic Mobile-H */
3978 [ # # # ]: 0 : switch (bIso)
3979 : : {
3980 : 0 : case 0:
3981 : 0 : ret = RI_ERR_SYNTAX;
3982 : 0 : goto exit_function;
3983 : 0 : case 1:
3984 [ # # ]: 0 : pInChI_From = bAltInChIExists ? pAltInChI : NULL;;
3985 : 0 : bIso_From = 1;
3986 : 0 : break;
3987 : 0 : default:
3988 : 0 : ret = RI_ERR_PROGR;
3989 : 0 : goto exit_function;
3990 : : }
3991 : 0 : break;
3992 : 0 : default:
3993 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
3994 : 0 : goto exit_function;
3995 : : }
3996 : 0 : break;
3997 : : }
3998 : :
3999 : : /* Save numbers */
4000 [ # # ]: 0 : if (pInChI_From)
4001 : : {
4002 [ # # ]: 0 : for (k = 0; k < val; k++)
4003 : : {
4004 : 0 : CopyAtomNumbers(pInChI + k, bIso, pInChI_From + k, bIso_From); /* djb-rwth: addressing coverity ID #499525 -- return values handled properly */
4005 : : }
4006 : : }
4007 : 0 : mpy_component = val;
4008 : : }
4009 : : else
4010 : : {
4011 : 0 : mpy_component = 1;
4012 : 0 : p = pStart; /* djb-rwth: ignoring LLVM warning: value used */
4013 : 0 : pNumb = pInChI->nPossibleLocationsOfIsotopicH;
4014 [ # # ]: 0 : if (!pNumb)
4015 : : {
4016 : 0 : pNumb = (AT_NUMB*)inchi_calloc(2 * (long long)pInChI->nNumberOfAtoms, sizeof(pNumb[0])); /* djb-rwth: cast operator added */
4017 [ # # ]: 0 : if (!pNumb)
4018 : : {
4019 : 0 : ret = RI_ERR_ALLOC;
4020 : 0 : goto exit_function;
4021 : : }
4022 : 0 : pInChI->nPossibleLocationsOfIsotopicH = pNumb;
4023 : : }
4024 [ # # ]: 0 : pNumb += bIso ? 0 : pInChI->nNumberOfAtoms;
4025 [ # # # # ]: 0 : if (pStart < pEnd && *pbAbc == -1)
4026 : : {
4027 : : /* Check if compressed InChI */
4028 : 0 : *pbAbc = isupper(UCINT * pStart) ? 1 : 0;
4029 : : }
4030 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
4031 : :
4032 [ # # ]: 0 : if (*pbAbc == 1)
4033 : : {
4034 [ # # # # ]: 0 : for (k = 0, p = pStart; k < pInChI->nNumberOfAtoms && p < pEnd; k++, p++)
4035 : : {
4036 : 0 : num = (AT_NUMB)inchi_strtol(p, &q, base);
4037 : : #if ( CHECK_STRTOL_ATNUMB==1 )
4038 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
4039 : : {
4040 : 0 : ret = RI_ERR_SYNTAX;
4041 : 0 : goto exit_function;
4042 : : }
4043 : : #endif
4044 [ # # # # ]: 0 : if (num <= 0 || p == q)
4045 : : {
4046 : 0 : ret = RI_ERR_SYNTAX;
4047 : 0 : goto exit_function;
4048 : : }
4049 : 0 : pNumb[k] = (AT_NUMB)num;
4050 : 0 : p = q;
4051 [ # # ]: 0 : if (p == pEnd)
4052 : : {
4053 : 0 : break; /* main end of cycle */
4054 : : }
4055 : : }
4056 : : }
4057 : : else
4058 : : {
4059 [ # # # # ]: 0 : for (k = 0, p = pStart; k < pInChI->nNumberOfAtoms && p < pEnd; k++, p++)
4060 : : {
4061 : 0 : pNumb[k] = (AT_NUMB)inchi_strtol(p, &q, 10);
4062 : : #if ( CHECK_STRTOL_ATNUMB==1 )
4063 [ # # ]: 0 : if (pNumb[k] > MAX_ATOMS || pNumb[k] < 0)
4064 : : {
4065 : 0 : ret = RI_ERR_SYNTAX;
4066 : 0 : goto exit_function;
4067 : : }
4068 : : #endif
4069 : 0 : p = q;
4070 [ # # ]: 0 : if (p == pEnd)
4071 : : {
4072 : 0 : break; /* main end of cycle */
4073 : : }
4074 : : else
4075 : : {
4076 [ # # ]: 0 : if (*p != ',')
4077 : : {
4078 : 0 : ret = RI_ERR_SYNTAX;
4079 : 0 : goto exit_function;
4080 : : }
4081 : : }
4082 : : }
4083 : : }
4084 [ # # # # ]: 0 : if (p != pEnd || k + 1 != pInChI->nNumberOfAtoms)
4085 : : {
4086 : 0 : ret = RI_ERR_SYNTAX;
4087 : 0 : goto exit_function;
4088 : : }
4089 : : }
4090 : :
4091 : 0 : iComponent += mpy_component;
4092 [ # # ]: 0 : if (*pEnd)
4093 : : {
4094 : 0 : pStart = pEnd + 1;
4095 : 0 : continue;
4096 : : }
4097 : : else
4098 : : {
4099 : 0 : break;
4100 : : }
4101 : : } /* end of cycle over components */
4102 : :
4103 [ # # ]: 0 : if (nNumComponents != iComponent)
4104 : : {
4105 : 0 : ret = 1; /*RI_ERR_SYNTAX;*/
4106 : 0 : goto exit_function;
4107 : : }
4108 : 0 : ret = iComponent + 1;
4109 : :
4110 : 0 : exit_function:
4111 : :
4112 : 0 : return ret;
4113 : : }
4114 : :
4115 : :
4116 : : /****************************************************************************
4117 : : Read and skip AuxInfo segment atom equivalence classes, "/E:" segments
4118 : : ****************************************************************************/
4119 : 0 : int ParseAuxSegmentAtomEqu(const char* str,
4120 : : int bMobileH,
4121 : : INChI* pInpInChI[],
4122 : : int ppnNumComponents[],
4123 : : int state)
4124 : : {
4125 [ # # # # : 0 : switch (state)
# ]
4126 : : {
4127 : 0 : case AST_MOBILE_H_ATOM_EQ:
4128 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4129 : : {
4130 : 0 : return RI_ERR_PROGR;
4131 : : }
4132 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4133 : : {
4134 : 0 : return 0;
4135 : : }
4136 : 0 : break;
4137 : 0 : case AST_MOBILE_H_ISO_ATOM_EQ:
4138 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4139 : : {
4140 : 0 : return RI_ERR_PROGR;
4141 : : }
4142 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4143 : : {
4144 : 0 : return 0;
4145 : : }
4146 : 0 : break;
4147 : 0 : case AST_FIXED_H_ATOM_EQ:
4148 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4149 : : {
4150 : 0 : return RI_ERR_PROGR;
4151 : : }
4152 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4153 : : {
4154 : 0 : return 0;
4155 : : }
4156 : 0 : break;
4157 : 0 : case AST_FIXED_H_ISO_ATOM_EQ:
4158 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4159 : : {
4160 : 0 : return RI_ERR_PROGR;
4161 : : }
4162 [ # # ]: 0 : if (memcmp(str, "E:", 2))
4163 : : {
4164 : 0 : return 0;
4165 : : }
4166 : 0 : break;
4167 : 0 : default:
4168 : 0 : return RI_ERR_PROGR;
4169 : : }
4170 : :
4171 : 0 : return 1;
4172 : : }
4173 : :
4174 : :
4175 : : /****************************************************************************
4176 : : Read and skip AuxInfo segment group equivalence classes, "/gE:" segments
4177 : : ****************************************************************************/
4178 : 0 : int ParseAuxSegmentGroupEqu(const char* str,
4179 : : int bMobileH,
4180 : : INChI* pInpInChI[],
4181 : : int ppnNumComponents[],
4182 : : int state)
4183 : : {
4184 [ # # # ]: 0 : switch (state)
4185 : : {
4186 : 0 : case AST_MOBILE_H_GROUP_EQ:
4187 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4188 : : {
4189 : 0 : return RI_ERR_PROGR;
4190 : : }
4191 [ # # ]: 0 : if (memcmp(str, "gE:", 3))
4192 : : {
4193 : 0 : return 0;
4194 : : }
4195 : 0 : break;
4196 : 0 : case AST_MOBILE_H_ISO_GROUP_EQ:
4197 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4198 : : {
4199 : 0 : return RI_ERR_PROGR;
4200 : : }
4201 [ # # ]: 0 : if (memcmp(str, "gE:", 3))
4202 : : {
4203 : 0 : return 0;
4204 : : }
4205 : 0 : break;
4206 : 0 : default:
4207 : 0 : return RI_ERR_PROGR;
4208 : : }
4209 : :
4210 : 0 : return 1;
4211 : : }
4212 : :
4213 : :
4214 : : /****************************************************************************
4215 : : Read and skip AuxInfo segment sp3 inv info, , "/it:" segment
4216 : : ****************************************************************************/
4217 : 0 : int ParseAuxSegmentSp3Inv(const char* str,
4218 : : int bMobileH,
4219 : : INChI* pInpInChI[],
4220 : : int ppnNumComponents[],
4221 : : int state)
4222 : : {
4223 [ # # # # : 0 : switch (state)
# ]
4224 : : {
4225 : 0 : case AST_MOBILE_H_SP3_INV:
4226 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4227 : : {
4228 : 0 : return RI_ERR_PROGR;
4229 : : }
4230 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4231 : : {
4232 : 0 : return 0;
4233 : : }
4234 : 0 : break;
4235 : 0 : case AST_MOBILE_H_ISO_SP3_INV:
4236 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4237 : : {
4238 : 0 : return RI_ERR_PROGR;
4239 : : }
4240 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4241 : : {
4242 : 0 : return 0;
4243 : : }
4244 : 0 : break;
4245 : 0 : case AST_FIXED_H_SP3_INV:
4246 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4247 : : {
4248 : 0 : return RI_ERR_PROGR;
4249 : : }
4250 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4251 : : {
4252 : 0 : return 0;
4253 : : }
4254 : 0 : break;
4255 : 0 : case AST_FIXED_H_ISO_SP3_INV:
4256 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4257 : : {
4258 : 0 : return RI_ERR_PROGR;
4259 : : }
4260 [ # # ]: 0 : if (memcmp(str, "it:", 3))
4261 : : {
4262 : 0 : return 0;
4263 : : }
4264 : 0 : break;
4265 : 0 : default:
4266 : 0 : return RI_ERR_PROGR;
4267 : : }
4268 : :
4269 : 0 : return 1;
4270 : : }
4271 : :
4272 : :
4273 : : /****************************************************************************
4274 : : Read and skip AuxInfo atom numbers in "/iN:"segment,
4275 : : for sp3 inv sub-layer at specific reading state
4276 : : ****************************************************************************/
4277 : 0 : int ParseAuxSegmentSp3InvNumbers(const char* str,
4278 : : int bMobileH,
4279 : : INChI* pInpInChI[],
4280 : : int ppnNumComponents[],
4281 : : int state)
4282 : : {
4283 [ # # # # : 0 : switch (state)
# ]
4284 : : {
4285 : 0 : case AST_MOBILE_H_SP3_INV_NUMBERS:
4286 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4287 : : {
4288 : 0 : return RI_ERR_PROGR;
4289 : : }
4290 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4291 : : {
4292 : 0 : return 0;
4293 : : }
4294 : 0 : break;
4295 : 0 : case AST_MOBILE_H_ISO_SP3_INV_NUMBERS:
4296 [ # # ]: 0 : if (bMobileH != TAUT_YES)
4297 : : {
4298 : 0 : return RI_ERR_PROGR;
4299 : : }
4300 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4301 : : {
4302 : 0 : return 0;
4303 : : }
4304 : 0 : break;
4305 : 0 : case AST_FIXED_H_SP3_INV_NUMBERS:
4306 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4307 : : {
4308 : 0 : return RI_ERR_PROGR;
4309 : : }
4310 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4311 : : {
4312 : 0 : return 0;
4313 : : }
4314 : 0 : break;
4315 : 0 : case AST_FIXED_H_ISO_SP3_INV_NUMBERS:
4316 [ # # ]: 0 : if (bMobileH != TAUT_NON)
4317 : : {
4318 : 0 : return RI_ERR_PROGR;
4319 : : }
4320 [ # # ]: 0 : if (memcmp(str, "iN:", 3))
4321 : : {
4322 : 0 : return 0;
4323 : : }
4324 : 0 : break;
4325 : 0 : default:
4326 : 0 : return RI_ERR_PROGR;
4327 : : }
4328 : :
4329 : 0 : return 1;
4330 : : }
4331 : :
4332 : :
4333 : : /****************************************************************************
4334 : : Read and skip AuxInfo sp3 CRV (charge, radical, valence) segment
4335 : : ****************************************************************************/
4336 : 0 : int ParseAuxSegmentReverseCRV(const char* str, int state)
4337 : : {
4338 [ # # ]: 0 : switch (state)
4339 : : {
4340 : 0 : case AST_REVERSE_INFO_CRV:
4341 [ # # ]: 0 : if (memcmp(str, "CRV:", 4))
4342 : : {
4343 : 0 : return 0;
4344 : : }
4345 : 0 : break;
4346 : 0 : default:
4347 : 0 : return RI_ERR_PROGR;
4348 : : }
4349 : :
4350 : 0 : return 1;
4351 : : }
4352 : :
4353 : :
4354 : : /****************************************************************************
4355 : : Read and skip AuxInfo segment ReverseAtoms
4356 : : ****************************************************************************/
4357 : 0 : int ParseAuxSegmentReverseAtoms(const char* str, int state)
4358 : : {
4359 [ # # ]: 0 : switch (state)
4360 : : {
4361 : 0 : case AST_REVERSE_INFO_ATOMS:
4362 [ # # ]: 0 : if (memcmp(str, "rA:", 3))
4363 : : {
4364 : 0 : return 0;
4365 : : }
4366 : 0 : break;
4367 : 0 : default:
4368 : 0 : return RI_ERR_PROGR;
4369 : : }
4370 : :
4371 : 0 : return 1;
4372 : : }
4373 : :
4374 : :
4375 : : /****************************************************************************
4376 : : Read and skip AuxInfo segment ReverseBonds
4377 : : ****************************************************************************/
4378 : 0 : int ParseAuxSegmentReverseBonds(const char* str, int state)
4379 : : {
4380 [ # # ]: 0 : switch (state)
4381 : : {
4382 : 0 : case AST_REVERSE_INFO_BONDS:
4383 [ # # ]: 0 : if (memcmp(str, "rB:", 3))
4384 : : {
4385 : 0 : return 0;
4386 : : }
4387 : 0 : break;
4388 : 0 : default:
4389 : 0 : return RI_ERR_PROGR;
4390 : : }
4391 : :
4392 : 0 : return 1;
4393 : : }
4394 : :
4395 : :
4396 : : /* Parse and save AuxInfo segment ReverseXYZ */
4397 : 0 : int ParseAuxSegmentReverseXYZ(const char* str,
4398 : : XYZ_COORD** ppXYZ,
4399 : : int state)
4400 : : {
4401 : : const char* pStart, * p, * q;
4402 : 0 : XYZ_COORD* pXYZ = NULL;
4403 : 0 : int nLenXYZ = 0, i, j;
4404 : :
4405 [ # # ]: 0 : switch (state)
4406 : : {
4407 : 0 : case AST_REVERSE_INFO_XYZ:
4408 [ # # ]: 0 : if (memcmp(str, "rC:", 3))
4409 : : {
4410 : 0 : return 0;
4411 : : }
4412 : 0 : break;
4413 : 0 : default:
4414 : 0 : return RI_ERR_PROGR;
4415 : : }
4416 : 0 : pStart = (char*)str + 3;
4417 : : /* Count coordinates */
4418 [ # # ]: 0 : for (p = pStart, nLenXYZ = 0; *p; p++)
4419 : : {
4420 : 0 : nLenXYZ += (*p == ';');
4421 : : }
4422 [ # # ]: 0 : if (!nLenXYZ)
4423 : : {
4424 : 0 : return RI_ERR_SYNTAX;
4425 : : }
4426 [ # # ]: 0 : if (NULL == (pXYZ = (XYZ_COORD*)inchi_calloc(nLenXYZ, sizeof(pXYZ[0]))))
4427 : : {
4428 : 0 : return RI_ERR_ALLOC;
4429 : : }
4430 [ # # # # ]: 0 : for (p = pStart, i = 0; *p && i < nLenXYZ; p++, i++)
4431 : : {
4432 [ # # ]: 0 : for (j = 0; j < 3; j++)
4433 : : {
4434 : 0 : pXYZ[i].xyz[j] = inchi_strtod(p, &q);
4435 : 0 : p = q + (*q == ',');
4436 : : }
4437 [ # # ]: 0 : if (*p != ';')
4438 : : {
4439 : 0 : break;
4440 : : }
4441 : : }
4442 [ # # # # ]: 0 : if (i != nLenXYZ || *p)
4443 : : {
4444 [ # # ]: 0 : inchi_free(pXYZ); /* djb-rwth: fixing a NULL pointer dereference */
4445 : 0 : return RI_ERR_SYNTAX;
4446 : : }
4447 : 0 : *ppXYZ = pXYZ;
4448 : :
4449 : 0 : return nLenXYZ + 1;
4450 : : }
4451 : :
4452 : :
4453 : : /****************************************************************************
4454 : : Parse and save atom coordinates from AuxInfo
4455 : : ****************************************************************************/
4456 : 0 : int AddAuxSegmentCoord(int nRet,
4457 : : XYZ_COORD* pXYZ,
4458 : : int nLenXYZ,
4459 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
4460 : : int nNumComponents[INCHI_NUM][TAUT_NUM])
4461 : : {
4462 : 0 : int iINChI, j, k, n, m, numAt[TAUT_NUM], num_at, ret = 0; /* djb-rwth: removing redundant variables */
4463 : 0 : INChI* pInChI = NULL;
4464 : 0 : INChI* pAltInChI = NULL;
4465 : : XYZ_COORD* pxyz;
4466 : :
4467 : : /* Propagate numberings (original:canonical atom mapping) */
4468 : : /* NB: we already saved isotopic numbering, if any, into the first nNumberOfAtoms elements of INChI::nPossibleLocationsOfIsotopicH, */
4469 : : /* and the non-isotopic numbering into the second half of nNumberOfAtoms elements of that INChI::nPossibleLocationsOfIsotopicH */
4470 : :
4471 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
4472 : : {
4473 [ # # ]: 0 : for (j = TAUT_YES; TAUT_NON <= j; j--) /* for FixedH and MobileH ... */
4474 : : {
4475 [ # # ]: 0 : if (pInpInChI[iINChI][j]) /* djb-rwth: fixing a NULL pointer dereference */
4476 : : {
4477 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++) /* for each component ... */
4478 : : {
4479 [ # # ]: 0 : int jj = ALT_TAUT(j);
4480 : 0 : pInChI = pInpInChI[iINChI][j] + k;
4481 [ # # ]: 0 : pAltInChI = (k < nNumComponents[iINChI][jj]) ? pInpInChI[iINChI][jj] + k : NULL;
4482 [ # # ]: 0 : numAt[j] = (!pInChI->bDeleted) ? pInChI->nNumberOfAtoms : 0;
4483 [ # # # # ]: 0 : numAt[jj] = (pAltInChI && !pAltInChI->bDeleted) ? pAltInChI->nNumberOfAtoms : 0;
4484 [ # # # ]: 0 : switch (j)
4485 : : {
4486 : 0 : case TAUT_YES:
4487 [ # # ]: 0 : if (!numAt[j])
4488 : : {
4489 : 0 : break; /* component does not exist */
4490 : : }
4491 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4492 : : {
4493 : : /* djb-rwth: removing redundant code */
4494 : 0 : break;
4495 : : }
4496 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH[0])
4497 : : {
4498 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH[numAt[j]])
4499 : : {
4500 : : /* copy from non-isotopic (2nd half of the at. numbers array) to the isotopic (1st half) */
4501 : 0 : ret = CopyAtomNumbers(pInChI, 1, pInChI, 0);
4502 [ # # ]: 0 : if (ret < 0)
4503 : : {
4504 : 0 : goto exit_function;
4505 : : }
4506 : : }
4507 : : else
4508 : : {
4509 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4510 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4511 : : /* djb-rwth: removing redundant code */
4512 : : }
4513 : : }
4514 : 0 : break;
4515 : :
4516 : 0 : case TAUT_NON:
4517 [ # # ]: 0 : if (!numAt[j])
4518 : : {
4519 : 0 : break; /* component does not exist */
4520 : : }
4521 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4522 : : {
4523 : : /* trying to get numbers from Mobile-H component */
4524 [ # # # # ]: 0 : if (!numAt[jj] || !(pAltInChI->nPossibleLocationsOfIsotopicH))
4525 : : {
4526 : : /* djb-rwth: removing redundant code */
4527 : : break;
4528 : : }
4529 [ # # ]: 0 : if (pAltInChI->nPossibleLocationsOfIsotopicH[0])
4530 : : {
4531 : 0 : ret = CopyAtomNumbers(pInChI, 1, pAltInChI, 1);
4532 [ # # ]: 0 : if (ret < 0)
4533 : : {
4534 : 0 : goto exit_function;
4535 : : }
4536 : : }
4537 : : else
4538 [ # # ]: 0 : if (pAltInChI->nPossibleLocationsOfIsotopicH[numAt[jj]])
4539 : : {
4540 : 0 : ret = CopyAtomNumbers(pInChI, 1, pAltInChI, 0);
4541 [ # # ]: 0 : if (ret < 0)
4542 : : {
4543 : 0 : goto exit_function;
4544 : : }
4545 : : }
4546 : : else
4547 : : {
4548 : : /* pAltInChI->nPossibleLocationsOfIsotopicH should have */
4549 : : /* been deallocated on previous TAUT_YES pass */
4550 : 0 : ret = RI_ERR_PROGR;
4551 : 0 : goto exit_function;
4552 : : }
4553 : : }
4554 [ # # ]: 0 : else if (!pInChI->nPossibleLocationsOfIsotopicH[0])
4555 : : {
4556 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH[numAt[j]])
4557 : : {
4558 : : /* copy from non-isotopic to isotopic */
4559 : 0 : ret = CopyAtomNumbers(pInChI, 1, pInChI, 0);
4560 [ # # ]: 0 : if (ret < 0)
4561 : : {
4562 : 0 : goto exit_function;
4563 : : }
4564 : : }
4565 : : else
4566 : : {
4567 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4568 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4569 : : /* djb-rwth: removing redundant code */
4570 : : }
4571 : : }
4572 : 0 : break;
4573 : : }
4574 : : }
4575 : : }
4576 : : }
4577 : : }
4578 : :
4579 : : /* Add coordinates */
4580 [ # # ]: 0 : for (iINChI = 0; iINChI < INCHI_NUM; iINChI++)
4581 : : {
4582 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
4583 : : {
4584 [ # # ]: 0 : for (k = 0; k < nNumComponents[iINChI][j]; k++)
4585 : : {
4586 : 0 : pInChI = pInpInChI[iINChI][j] + k;
4587 [ # # ]: 0 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
4588 : : {
4589 [ # # ]: 0 : num_at = (!pInChI->bDeleted) ? pInChI->nNumberOfAtoms : 0;
4590 [ # # ]: 0 : if (!num_at)
4591 : : {
4592 [ # # ]: 0 : if (pInChI->nPossibleLocationsOfIsotopicH)
4593 : : {
4594 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4595 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4596 : : }
4597 : 0 : continue;
4598 : : }
4599 [ # # ]: 0 : if (!pInChI->nPossibleLocationsOfIsotopicH)
4600 : : {
4601 : 0 : continue;
4602 : : }
4603 [ # # # # ]: 0 : if (iINChI == INCHI_BAS && num_at == 1 &&
4604 [ # # # # ]: 0 : pInChI->szHillFormula && !strcmp(pInChI->szHillFormula, "H") &&
4605 [ # # ]: 0 : (int)pInChI->nPossibleLocationsOfIsotopicH[0] - 1 >= nLenXYZ)
4606 : : {
4607 : : ; /* a single atom H disconnected from a metal atom has no coordinates */
4608 : : }
4609 : : else
4610 : : {
4611 : : /* add atom coordinates */
4612 : 0 : pxyz = (XYZ_COORD*)inchi_calloc(num_at, sizeof(pxyz[0]));
4613 [ # # ]: 0 : if (!pxyz)
4614 : : {
4615 : 0 : ret = RI_ERR_ALLOC;
4616 : 0 : goto exit_function;
4617 : : }
4618 [ # # ]: 0 : for (n = 0; n < num_at; n++)
4619 : : {
4620 : 0 : m = (int)pInChI->nPossibleLocationsOfIsotopicH[n] - 1;
4621 [ # # # # ]: 0 : if (m < 0 || m >= nLenXYZ)
4622 : : {
4623 [ # # ]: 0 : inchi_free(pxyz);
4624 : 0 : ret = RI_ERR_SYNTAX;
4625 : 0 : goto exit_function;
4626 : : }
4627 : 0 : pxyz[n] = pXYZ[m];
4628 : : }
4629 : 0 : pInChI->IsotopicTGroup = (INChI_IsotopicTGroup*)pxyz;
4630 : : }
4631 [ # # ]: 0 : inchi_free(pInChI->nPossibleLocationsOfIsotopicH);
4632 : 0 : pInChI->nPossibleLocationsOfIsotopicH = NULL;
4633 : : }
4634 : : }
4635 : : }
4636 : : }
4637 : 0 : ret = nRet; /* normal exit */
4638 : :
4639 : 0 : exit_function:
4640 : :
4641 : 0 : return ret;
4642 : : }
4643 : :
4644 : :
4645 : : /****************************************************************************
4646 : : ReadInChICoord (from AuxInfo if present)
4647 : : ****************************************************************************/
4648 : 0 : int ReadInChICoord(INCHI_IOSTREAM* pInp,
4649 : : SEGM_LINE* pLine,
4650 : : int* pState,
4651 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
4652 : : int nNumComponents[INCHI_NUM][TAUT_NUM])
4653 : : {
4654 : : int c;
4655 : : /* djb-rwth: removing redundant variables */
4656 : 0 : int ret = RI_ERR_ALLOC;
4657 : 0 : int bMobileH = TAUT_YES;
4658 : 0 : int bReconn = INCHI_BAS;
4659 : 0 : int state = -1;
4660 : 0 : int prev_state = -1;
4661 : 0 : int nLenXYZ = 0;
4662 : 0 : int bAbc = -1; /* initially undefined */
4663 : : const char
4664 : 0 : szToken[] = INCHI_TOKEN;
4665 : : XYZ_COORD
4666 : 0 : * pXYZ = NULL;
4667 : :
4668 : 0 : *pState = 0;
4669 : : INCHI_HEAPCHK
4670 : :
4671 : : /* Get "InChI=1/" */
4672 [ # # ]: 0 : if (pLine->len)
4673 : : {
4674 : 0 : c = pLine->c;
4675 : : }
4676 : : else
4677 : : {
4678 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
4679 : : }
4680 [ # # # # : 0 : if (c == RI_ERR_EOF && !pLine->len && !pLine->str[0])
# # ]
4681 : : {
4682 : 0 : ret = c;
4683 : 0 : pLine->len = 0;
4684 : 0 : goto exit_error;
4685 : : }
4686 [ # # # # : 0 : if (pLine->len == 0 || (c != SEG_END && c != RI_ERR_EOF && !INCHI_INP_EOL(c))) /* djb-rwth: addressing LLVM warning */
# # # # #
# # # ]
4687 : : {
4688 : 0 : *pState = -1;
4689 : 0 : pLine->len = 0;
4690 : 0 : ret = RI_ERR_PROGR;
4691 : 0 : goto exit_error;
4692 : : }
4693 [ # # ]: 0 : if (memcmp(pLine->str, "AuxInfo=", 8))
4694 : : {
4695 : 0 : *pState = -1;
4696 : 0 : return c;
4697 : : }
4698 : :
4699 : 0 : state = AST_VERSION;
4700 : 0 : ret = 1; /* means read the next segment */
4701 : : do
4702 : : {
4703 : : /* Read the next segment up to the '/' */
4704 : : INCHI_HEAPCHK
4705 [ # # ]: 0 : if (ret < 0)
4706 : : {
4707 : 0 : *pState = prev_state;
4708 : 0 : break;
4709 : : }
4710 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
4711 [ # # ]: 0 : if (0 < ret)
4712 : : {
4713 : : /* read next segment */
4714 [ # # # # ]: 0 : if (c != RI_ERR_EOF && c != SEG_END)
4715 : : {
4716 : : /* abnormal reading result; should not happen */
4717 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
4718 : : {
4719 : : /* bypass to the end of line or file */
4720 : 0 : c = getInChIChar(pInp);
4721 : : }
4722 [ # # ]: 0 : ret = (c == RI_ERR_EOF) ? RI_ERR_EOF : RI_ERR_EOL; /* end of line */
4723 : 0 : pLine->len = 0;
4724 : 0 : pLine->c = ret;
4725 : 0 : break;
4726 : : }
4727 [ # # ]: 0 : if (c == RI_ERR_EOF)
4728 : : {
4729 : 0 : ret = RI_ERR_EOF; /* end of line */
4730 : 0 : break;
4731 : : }
4732 [ # # ]: 0 : if (c == SEG_END)
4733 : : {
4734 : 0 : c = nGetInChISegment(pInp, pLine, szToken);
4735 : : }
4736 [ # # ]: 0 : if (c < 0)
4737 : : {
4738 : 0 : goto exit_error; /* error */
4739 : : }
4740 [ # # ]: 0 : if (!pLine->len)
4741 : : {
4742 : 0 : ret = RI_ERR_EOL; /* end of line */
4743 : 0 : break;
4744 : : }
4745 : : /* djb-rwth: removing redundant code */
4746 : : }
4747 : :
4748 : : /* Process the seqment */
4749 [ # # # # : 0 : switch (state)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
4750 : : {
4751 : 0 : case AST_VERSION:
4752 : : /* Mobile H */
4753 : 0 : bMobileH = TAUT_YES;
4754 : 0 : ret = ParseAuxSegmentVersion(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4755 : 0 : state = AST_MOBILE_H_NUMBERS;
4756 : 0 : break;
4757 : 0 : case AST_MOBILE_H_NUMBERS:
4758 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4759 : 0 : state = AST_MOBILE_H_ATOM_EQ;
4760 : 0 : break;
4761 : 0 : case AST_MOBILE_H_ATOM_EQ:
4762 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4763 : 0 : state = AST_MOBILE_H_GROUP_EQ;
4764 : 0 : break;
4765 : 0 : case AST_MOBILE_H_GROUP_EQ:
4766 : 0 : ret = ParseAuxSegmentGroupEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4767 : 0 : state = AST_MOBILE_H_SP3_INV;
4768 : 0 : break;
4769 : 0 : case AST_MOBILE_H_SP3_INV:
4770 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4771 : 0 : state = AST_MOBILE_H_SP3_INV_NUMBERS;
4772 : 0 : break;
4773 : 0 : case AST_MOBILE_H_SP3_INV_NUMBERS:
4774 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4775 : 0 : state = AST_MOBILE_H_ISO_LAYER_FORK;
4776 : 0 : break;
4777 : :
4778 : 0 : case AST_MOBILE_H_ISO_LAYER_FORK:
4779 [ # # ]: 0 : if (!memcmp(pLine->str, "I:", 2))
4780 : : {
4781 : 0 : state = AST_MOBILE_H_ISO_NUMBERS;
4782 : : }
4783 [ # # ]: 0 : else if (!inchi_memicmp(pLine->str, "F:", 2))
4784 : : {
4785 : 0 : state = AST_FIXED_H_NUMBERS;
4786 : 0 : bMobileH = TAUT_NON;
4787 : : }
4788 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4789 : : {
4790 : 0 : state = AST_REVERSE_INFO_CRV;
4791 : : }
4792 : : else
4793 [ # # # # ]: 0 : if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4794 : : {
4795 : 0 : state = AST_REVERSE_INFO_ATOMS;
4796 : : }
4797 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4798 : : {
4799 : 0 : ret = 1; /* read the next segment */
4800 : 0 : state = AST_VERSION;
4801 : 0 : bMobileH = TAUT_YES;
4802 : 0 : bReconn = INCHI_REC;
4803 : : }
4804 : : else
4805 : : {
4806 : 0 : ret = RI_ERR_SYNTAX;
4807 : : }
4808 : 0 : break;
4809 : :
4810 : : /* Mobile H, isotopic */
4811 : 0 : case AST_MOBILE_H_ISO_NUMBERS:
4812 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4813 : 0 : state = AST_MOBILE_H_ISO_ATOM_EQ;
4814 : 0 : break;
4815 : 0 : case AST_MOBILE_H_ISO_ATOM_EQ:
4816 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4817 : 0 : state = AST_MOBILE_H_ISO_GROUP_EQ;
4818 : 0 : break;
4819 : 0 : case AST_MOBILE_H_ISO_GROUP_EQ:
4820 : 0 : ret = ParseAuxSegmentGroupEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4821 : 0 : state = AST_MOBILE_H_ISO_SP3_INV;
4822 : 0 : break;
4823 : 0 : case AST_MOBILE_H_ISO_SP3_INV:
4824 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4825 : 0 : state = AST_MOBILE_H_ISO_SP3_INV_NUMBERS;
4826 : 0 : break;
4827 : 0 : case AST_MOBILE_H_ISO_SP3_INV_NUMBERS:
4828 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4829 : 0 : state = AST_FIXED_H_LAYER_FORK;
4830 : 0 : break;
4831 : :
4832 : 0 : case AST_FIXED_H_LAYER_FORK:
4833 [ # # ]: 0 : if (!inchi_memicmp(pLine->str, "F:", 2))
4834 : : {
4835 : 0 : state = AST_FIXED_H_NUMBERS;
4836 : 0 : bMobileH = TAUT_NON;
4837 : : }
4838 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4839 : : {
4840 : 0 : state = AST_REVERSE_INFO_CRV;
4841 : : }
4842 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4843 : : {
4844 : 0 : state = AST_REVERSE_INFO_ATOMS;
4845 : : }
4846 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4847 : : {
4848 : 0 : ret = 1; /* read the next segment */
4849 : 0 : state = AST_VERSION;
4850 : 0 : bMobileH = TAUT_YES;
4851 : 0 : bReconn = INCHI_REC;
4852 : : }
4853 : : else
4854 : : {
4855 : 0 : ret = RI_ERR_SYNTAX;
4856 : : }
4857 : 0 : break;
4858 : :
4859 : 0 : case AST_FIXED_H_NUMBERS:
4860 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4861 : 0 : state = AST_FIXED_H_ATOM_EQ;
4862 : 0 : break;
4863 : 0 : case AST_FIXED_H_ATOM_EQ:
4864 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4865 : 0 : state = AST_FIXED_H_SP3_INV;
4866 : 0 : break;
4867 : 0 : case AST_FIXED_H_SP3_INV:
4868 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4869 : 0 : state = AST_FIXED_H_SP3_INV_NUMBERS;
4870 : 0 : break;
4871 : 0 : case AST_FIXED_H_SP3_INV_NUMBERS:
4872 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4873 : 0 : state = AST_FIXED_H_ISO_LAYER_FORK;
4874 : 0 : break;
4875 : :
4876 : 0 : case AST_FIXED_H_ISO_LAYER_FORK:
4877 [ # # ]: 0 : if (!memcmp(pLine->str, "I:", 2))
4878 : : {
4879 : 0 : state = AST_FIXED_H_ISO_NUMBERS;
4880 : : }
4881 [ # # ]: 0 : else if ( /*bReconn == INCHI_BAS &&*/ !inchi_memicmp(pLine->str, "CRV:", 4))
4882 : : {
4883 : 0 : state = AST_REVERSE_INFO_CRV;
4884 : : }
4885 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "rA:", 3))
4886 : : {
4887 : 0 : state = AST_REVERSE_INFO_ATOMS;
4888 : : }
4889 [ # # # # ]: 0 : else if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4890 : : {
4891 : 0 : ret = 1; /* read the next segment */
4892 : 0 : state = AST_VERSION;
4893 : 0 : bMobileH = TAUT_YES;
4894 : 0 : bReconn = INCHI_REC;
4895 : : }
4896 : : else
4897 : : {
4898 : 0 : ret = RI_ERR_SYNTAX;
4899 : : }
4900 : 0 : break;
4901 : :
4902 : 0 : case AST_FIXED_H_ISO_NUMBERS:
4903 : 0 : ret = ParseAuxSegmentNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
4904 : 0 : state = AST_FIXED_H_ISO_ATOM_EQ;
4905 : 0 : break;
4906 : 0 : case AST_FIXED_H_ISO_ATOM_EQ:
4907 : 0 : ret = ParseAuxSegmentAtomEqu(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4908 : 0 : state = AST_FIXED_H_SP3_INV;
4909 : 0 : break;
4910 : 0 : case AST_FIXED_H_ISO_SP3_INV:
4911 : 0 : ret = ParseAuxSegmentSp3Inv(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4912 : 0 : state = AST_FIXED_H_ISO_SP3_INV_NUMBERS;
4913 : 0 : break;
4914 : 0 : case AST_FIXED_H_ISO_SP3_INV_NUMBERS:
4915 : 0 : ret = ParseAuxSegmentSp3InvNumbers(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
4916 : 0 : state = AST_REVERSE_INFO_CRV;
4917 : 0 : break;
4918 : 0 : case AST_REVERSE_INFO_CRV:
4919 : 0 : ret = ParseAuxSegmentReverseCRV(pLine->str, state);
4920 : : /* state = (bReconn == INCHI_BAS)? AST_REVERSE_INFO_ATOMS : AST_RECONNECTED_LAYER_FORK;*/
4921 : 0 : state = AST_REVERSE_INFO_ATOMS;
4922 : 0 : break;
4923 : 0 : case AST_REVERSE_INFO_ATOMS:
4924 : 0 : ret = ParseAuxSegmentReverseAtoms(pLine->str, state);
4925 : 0 : state = AST_REVERSE_INFO_BONDS;
4926 : 0 : break;
4927 : 0 : case AST_REVERSE_INFO_BONDS:
4928 : 0 : ret = ParseAuxSegmentReverseBonds(pLine->str, state);
4929 : 0 : state = AST_REVERSE_INFO_XYZ;
4930 : 0 : break;
4931 : 0 : case AST_REVERSE_INFO_XYZ:
4932 : 0 : ret = ParseAuxSegmentReverseXYZ(pLine->str, &pXYZ, state);
4933 : 0 : state = AST_RECONNECTED_LAYER_FORK;
4934 [ # # ]: 0 : if (ret > 0)
4935 : : {
4936 : 0 : nLenXYZ = ret - 1;
4937 : : }
4938 : 0 : break;
4939 : 0 : case AST_RECONNECTED_LAYER_FORK:
4940 [ # # # # ]: 0 : if (bReconn == INCHI_BAS && !inchi_memicmp(pLine->str, "R:", 3))
4941 : : {
4942 : 0 : ret = 1; /* read the next segment */
4943 : 0 : state = AST_VERSION;
4944 : 0 : bMobileH = TAUT_YES;
4945 : 0 : bReconn = INCHI_REC;
4946 : : }
4947 : : else
4948 : : {
4949 : 0 : ret = RI_ERR_SYNTAX;
4950 : : }
4951 : 0 : break;
4952 : : }
4953 [ # # ]: 0 : } while (c >= 0);
4954 : :
4955 [ # # ]: 0 : if (pXYZ) /* djb-rwth: fixing coverity ID #499576 */
4956 : : {
4957 : 0 : ret = AddAuxSegmentCoord(ret, pXYZ, nLenXYZ, pInpInChI, nNumComponents);
4958 : : }
4959 : : else
4960 : : {
4961 : 0 : ret = RI_ERR_ALLOC;
4962 : : }
4963 : :
4964 : 0 : exit_error:
4965 [ # # ]: 0 : if (pXYZ)
4966 : : {
4967 [ # # ]: 0 : inchi_free(pXYZ);
4968 : : }
4969 [ # # # # : 0 : if (ret >= 0 || c == RI_ERR_EOF || c == RI_ERR_EOL)
# # ]
4970 : : {
4971 : 0 : pLine->len = 0;
4972 : : }
4973 : :
4974 : 0 : return ret;
4975 : : }
4976 : :
4977 : :
4978 : : /****************************************************************************
4979 : : Read a single InChI input line
4980 : : ****************************************************************************/
4981 : 2 : int ReadInChILine(INCHI_IOSTREAM* pInp,
4982 : : SEGM_LINE* pLine,
4983 : : char** pStr,
4984 : : int* pState,
4985 : : INChI* pInpInChI[INCHI_NUM][TAUT_NUM],
4986 : : int nNumComponents[INCHI_NUM][TAUT_NUM],
4987 : : REM_PROTONS nNumProtons[INCHI_NUM][TAUT_NUM],
4988 : : int s[INCHI_NUM][TAUT_NUM][2],
4989 : : int* bStdFormat,
4990 : : int* input_has_save_opt,
4991 : : unsigned char* input_save_opt_bits,
4992 : : int bInchi2Struct,
4993 : : OAD_Polymer** ppPolymer,
4994 : : OAD_V3000** ppV3000)
4995 : : {
4996 : 2 : int c, ret = RI_ERR_ALLOC, len; /* djb-rwth: removing redundant variables */
4997 : 2 : int bMobileH = TAUT_YES, bReconn = INCHI_BAS;
4998 : 2 : const char szToken[] = INCHI_TOKEN;
4999 : : char* p;
5000 : 2 : int state = -1, prev_state = -1;
5001 : 2 : int bAbc = -1; /* -1=> undefined, 0=> decimal, 1=> abc (compressed) */
5002 : :
5003 : 2 : const int len_std_prefix = 8;
5004 : 2 : size_t k = 0;
5005 : 2 : unsigned char let1 = 0, let2 = 0;
5006 : 2 : const char a2p[] = "ABCDEFGHIJKLMNOP";
5007 : :
5008 : 2 : int na_total = 0; /* whole struct, without explH */
5009 : 2 : int nb_total = 0; /* whole struct, without explH */
5010 : : #if ( DISABLE_READ_COMPRESSED_INCHI==1 )
5011 : 2 : bAbc = 0;
5012 : : /* We do not support compressed InChI explicitly */
5013 : : /* Parsing compressed InChI easily fails on fake/fuzzing inputs */
5014 : : #endif
5015 : : /* memset( pLine, 0, sizeof( pLine[0] ) ); */
5016 : 2 : * pState = 0;
5017 : :
5018 : 0 : next_line:
5019 : : INCHI_HEAPCHK
5020 : : /* Got "InChI=1/" */
5021 [ - + ]: 2 : if (pLine->len)
5022 : : {
5023 : 0 : c = pLine->c;
5024 : : }
5025 : : else
5026 : : {
5027 : : INCHI_HEAPCHK
5028 : 2 : c = nGetInChISegment(pInp, pLine, szToken);
5029 : : INCHI_HEAPCHK
5030 : : }
5031 [ + - - + : 2 : if (pLine->str && (c == RI_ERR_EOF && !pLine->len && !pLine->str[0])) /* djb-rwth: fixing a NULL pointer dereference */
- - - - ]
5032 : : {
5033 : 0 : ret = c;
5034 : 0 : goto exit_function;
5035 : : }
5036 : : INCHI_HEAPCHK
5037 : :
5038 [ + - + - : 2 : 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 */
- + - - -
+ ]
5039 : : {
5040 [ # # # # ]: 0 : if (pLine->str && pLine->str == strstr(pLine->str, "Structure"))
5041 : : {
5042 [ # # ]: 0 : if (*pStr)
5043 : : {
5044 : : INCHI_HEAPCHK
5045 [ # # ]: 0 : inchi_free(*pStr);
5046 : : }
5047 : 0 : *pStr = pLine->str;
5048 : : /* bypass to the end of the 'Structure nnn' line */
5049 : 0 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
5050 [ # # # # : 0 : while (c && !INCHI_INP_EOL(c))
# # # # ]
5051 : : {
5052 : 0 : c = getInChIChar(pInp);
5053 : : }
5054 : 0 : goto next_line;
5055 : : }
5056 : : /* bypass to the end of unrecognized line */
5057 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
5058 : : {
5059 : 0 : c = getInChIChar(pInp);
5060 : : }
5061 : 0 : pLine->len = 0;
5062 : : INCHI_HEAPCHK
5063 : 0 : goto next_line;
5064 : : }
5065 : :
5066 : :
5067 : : /* Check if got a standard InChI */
5068 [ + - - + : 2 : if (pLine->str && (pLine->len == len_std_prefix) && (pLine->str[len_std_prefix - 1] == 'S')) /* djb-rwth: fixing a NULL pointer dereference */
- - ]
5069 : : {
5070 : 0 : *bStdFormat = 1;
5071 : : }
5072 : : else
5073 : : {
5074 : 2 : *bStdFormat = 0;
5075 : : }
5076 : :
5077 : 2 : state = IST_MOBILE_H_FORMULA;
5078 : 2 : ret = 1; /* means read the next segment */
5079 : : do
5080 : : {
5081 : : /* read the next segment up to the '/' */
5082 : : INCHI_HEAPCHK
5083 [ + + ]: 17 : if (ret < 0)
5084 : : {
5085 : 2 : *pState = prev_state;
5086 : 2 : break;
5087 : : }
5088 [ - + ]: 15 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5089 [ + + ]: 15 : if (0 < ret)
5090 : : {
5091 : : /* read next segment */
5092 [ + - - + ]: 5 : if (c != RI_ERR_EOF && c != SEG_END)
5093 : : {
5094 : : /* abnormal reading result; should not happen */
5095 : : /* unless we got backslash-SaveOpt */
5096 [ # # ]: 0 : if (c == '\\')
5097 : : {
5098 : : /* May be SaveOpt */
5099 : 0 : *input_has_save_opt = 1;
5100 : : }
5101 : 0 : k = 0;
5102 [ # # # # : 0 : while (c != RI_ERR_EOF && !INCHI_INP_EOL(c))
# # # # ]
5103 : : {
5104 : : /* bypass to the end of line or file */
5105 : 0 : c = getInChIChar(pInp);
5106 : 0 : k++;
5107 [ # # ]: 0 : if (k == 1)
5108 : : {
5109 : 0 : let1 = c;
5110 : : }
5111 : : else
5112 : : {
5113 [ # # ]: 0 : if (k == 2)
5114 : : {
5115 : 0 : let2 = c;
5116 : : }
5117 : : }
5118 : : }
5119 [ # # ]: 0 : if (k != 3)
5120 : : {
5121 : : /* not a valid SaveOpt which must be of two chars */
5122 : 0 : *input_has_save_opt = 0;
5123 : : /* djb-rwth: removing redundant code */
5124 : : }
5125 : : else
5126 : : {
5127 : : /* may be SaveOpt - analyze the content */
5128 [ # # # # ]: 0 : if ((let2 >= 'A') && (let2 <= 'D')) /* letter-2 OK */
5129 : : {
5130 : 0 : *input_has_save_opt = 0;
5131 : 0 : *input_save_opt_bits = 0;
5132 [ # # ]: 0 : for (k = 0; k < 16; k++)
5133 : : {
5134 [ # # ]: 0 : if (a2p[k] == let1) /* letter-1 OK */
5135 : : {
5136 : 0 : *input_save_opt_bits = (unsigned char)k;
5137 : 0 : *input_has_save_opt = 1;
5138 : 0 : break;
5139 : : }
5140 : : }
5141 [ # # ]: 0 : if (*input_has_save_opt)
5142 : : {
5143 [ # # # # ]: 0 : if (let2 == 'B' || let2 == 'D')
5144 : : {
5145 : 0 : *input_save_opt_bits |= SAVE_OPT_15T;
5146 : : }
5147 [ # # # # ]: 0 : if (let2 == 'C' || let2 == 'D')
5148 : : {
5149 : 0 : *input_save_opt_bits |= SAVE_OPT_KET;
5150 : : }
5151 : : }
5152 : : }
5153 : : }
5154 : :
5155 [ # # ]: 0 : ret = (c == RI_ERR_EOF) ? RI_ERR_EOF : RI_ERR_EOL; /* end of line */
5156 : 0 : pLine->len = 0;
5157 : 0 : pLine->c = ret;
5158 : 0 : break; /* exit */
5159 : : }
5160 [ - + ]: 5 : if (c == RI_ERR_EOF)
5161 : : {
5162 : 0 : ret = RI_ERR_EOF; /* end of line */
5163 : 0 : break;
5164 : : }
5165 [ + - ]: 5 : if (c == SEG_END)
5166 : : {
5167 : 5 : c = nGetInChISegment(pInp, pLine, szToken);
5168 : : }
5169 [ - + ]: 5 : if (c < 0)
5170 : : {
5171 : 0 : goto exit_error; /* error */
5172 : : }
5173 [ - + ]: 5 : if (!pLine->len)
5174 : : {
5175 : 0 : ret = RI_ERR_EOL; /* end of line */
5176 : 0 : break;
5177 : : }
5178 : : /* djb-rwth: removing redundant code */
5179 : :
5180 : : /*
5181 : : if ( fst == 'z' )
5182 : : {
5183 : : ret = RI_ERR_EOL;
5184 : : break;
5185 : : }*/
5186 : : }
5187 : : /* process the seqment */
5188 [ + + + + : 15 : switch (state)
+ + + + +
+ + + - -
- - - - -
- - - - -
- - - - -
- - - - -
- - ]
5189 : : {
5190 : : /* Mobile H, M */ /* / */
5191 : 2 : case IST_MOBILE_H_FORMULA:
5192 : 2 : bMobileH = TAUT_YES;
5193 : : #if ( FIX_GAF_2019_2==1 )
5194 : : /* hack: pass state in na_total (will be updated in ParseSegmentFormula anyway) */
5195 : 2 : na_total = state;
5196 : : #endif
5197 : 2 : ret = ParseSegmentFormula(pLine->str, bMobileH, pInpInChI[bReconn],
5198 : 2 : nNumComponents[bReconn], &na_total);
5199 : 2 : state = IST_MOBILE_H_CONNECTIONS;
5200 : 2 : break;
5201 : 2 : case IST_MOBILE_H_CONNECTIONS: /* /c */
5202 : 2 : ret = ParseSegmentConnections(pLine->str, bMobileH, &pInpInChI[bReconn][bMobileH],
5203 : 2 : &nNumComponents[bReconn][bMobileH], &bAbc, &nb_total);
5204 : 2 : state = IST_MOBILE_H;
5205 : 2 : break;
5206 : 2 : case IST_MOBILE_H: /* /h */
5207 : 2 : ret = ParseSegmentMobileH(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], &bAbc);
5208 : 2 : state = IST_MOBILE_H_CHARGE;
5209 : 2 : break;
5210 : 1 : case IST_MOBILE_H_CHARGE: /* /q */
5211 : 1 : ret = ParseSegmentCharge(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn]);
5212 : 1 : state = IST_MOBILE_H_PROTONS;
5213 : 1 : break;
5214 : 1 : case IST_MOBILE_H_PROTONS: /* /p */
5215 : 1 : ret = ParseSegmentProtons(pLine->str, bMobileH, nNumProtons[bReconn], nNumComponents[bReconn]);
5216 : 1 : state = IST_MOBILE_H_POLYMER;
5217 : 1 : break;
5218 : 1 : case IST_MOBILE_H_POLYMER: /* /z */
5219 : 1 : ret = ParseSegmentPolymer(pLine->str, bMobileH,
5220 : 1 : nNumProtons[bReconn], nNumComponents[bReconn],
5221 : : na_total, nb_total, bInchi2Struct, ppPolymer, ppV3000);
5222 [ - + ]: 1 : if (*ppPolymer)
5223 : 0 : (*ppPolymer)->is_in_reconn = bReconn;
5224 : 1 : state = IST_MOBILE_H_SP2;
5225 : 1 : break;
5226 : 1 : case IST_MOBILE_H_SP2: /* /b */
5227 : 1 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5228 : 1 : state = IST_MOBILE_H_SP3;
5229 : 1 : break;
5230 : 1 : case IST_MOBILE_H_SP3: /* t */
5231 : 1 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5232 : 1 : state = IST_MOBILE_H_SP3_M;
5233 : 1 : break;
5234 : 1 : case IST_MOBILE_H_SP3_M: /* /m */
5235 : 1 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5236 : 1 : state = IST_MOBILE_H_SP3_S;
5237 : 1 : break;
5238 : 1 : case IST_MOBILE_H_SP3_S: /* /s */
5239 : 1 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5240 : 1 : state = IST_MOBILE_H_ISO_LAYER_FORK;
5241 : 1 : break;
5242 : 1 : case IST_MOBILE_H_ISO_LAYER_FORK:
5243 : : /* find layer type after M */
5244 : 1 : ret = 0;
5245 [ + - - - ]: 1 : switch (pLine->str[0])
5246 : : {
5247 : 1 : case 'i':
5248 : 1 : state = IST_MOBILE_H_ISO_ATOMS; /* MI */
5249 : 1 : break;
5250 : 0 : case 'f':
5251 : 0 : state = IST_FIXED_H_FORMULA; /* F */
5252 : 0 : break;
5253 : 0 : case 'r':
5254 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5255 : 0 : break;
5256 : 0 : default:
5257 : 0 : ret = RI_ERR_SYNTAX;
5258 : : }
5259 [ + - + - : 1 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
- + - - -
- ]
5260 : : {
5261 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5262 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /i or /f or /r at the end of InChI line */
5263 : : }
5264 : : else
5265 : : {
5266 [ + - - + ]: 1 : if (!ret && state != IST_MOBILE_H_ISO_ATOMS)
5267 : : {
5268 : 0 : len = (int)strlen(pLine->str);
5269 [ # # ]: 0 : if (len > 1)
5270 : : {
5271 : 0 : memmove(pLine->str, pLine->str + 1, len);
5272 : : }
5273 : : else
5274 : : {
5275 : 0 : ret = 1; /* read the next segment */
5276 : : }
5277 : : }
5278 : : }
5279 : 1 : break;
5280 : : /* Mobile H, isotopic, MI */
5281 : 1 : case IST_MOBILE_H_ISO_ATOMS: /* i */
5282 : 1 : ret = ParseSegmentIsoAtoms(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5283 : 1 : state = IST_MOBILE_H_ISO_EXCH_H;
5284 : 1 : break;
5285 : 0 : case IST_MOBILE_H_ISO_EXCH_H: /* /i/h */
5286 : 0 : ret = ParseSegmentIsoExchgH(pLine->str, bMobileH, nNumProtons[bReconn], nNumComponents[bReconn], state, &bAbc);
5287 : 0 : state = IST_MOBILE_H_ISO_SP2;
5288 : 0 : break;
5289 : 0 : case IST_MOBILE_H_ISO_SP2: /* /i/b */
5290 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5291 : 0 : state = IST_MOBILE_H_ISO_SP3;
5292 : 0 : break;
5293 : 0 : case IST_MOBILE_H_ISO_SP3: /* /i/t */
5294 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5295 : 0 : state = IST_MOBILE_H_ISO_SP3_M;
5296 : 0 : break;
5297 : 0 : case IST_MOBILE_H_ISO_SP3_M: /* /i/m */
5298 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5299 : 0 : state = IST_MOBILE_H_ISO_SP3_S;
5300 : 0 : break;
5301 : 0 : case IST_MOBILE_H_ISO_SP3_S: /* /i/s */
5302 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5303 : 0 : state = IST_FIXED_H_LAYER_FORK;
5304 : 0 : break;
5305 : 0 : case IST_FIXED_H_LAYER_FORK:
5306 : : /* find layer type after MI */
5307 : 0 : ret = 0;
5308 [ # # # ]: 0 : switch (pLine->str[0])
5309 : : {
5310 : 0 : case 'f':
5311 : 0 : state = IST_FIXED_H_FORMULA; /* F */
5312 : 0 : break;
5313 : 0 : case 'r':
5314 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5315 : 0 : break;
5316 : 0 : default:
5317 : 0 : ret = RI_ERR_SYNTAX;
5318 : : }
5319 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5320 : : {
5321 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5322 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /f or /r at the end of InChI line */
5323 : : }
5324 : : else
5325 : : {
5326 [ # # ]: 0 : if (!ret)
5327 : : {
5328 : 0 : len = (int)strlen(pLine->str);
5329 [ # # ]: 0 : if (len > 1)
5330 : : {
5331 : 0 : memmove(pLine->str, pLine->str + 1, len);
5332 : : }
5333 : : else
5334 : : {
5335 : 0 : ret = 1; /* read the next segment */
5336 : : }
5337 : : }
5338 : : }
5339 : 0 : break;
5340 : :
5341 : : /* Fixed H, F */
5342 : 0 : case IST_FIXED_H_FORMULA:
5343 : 0 : bMobileH = TAUT_NON;
5344 : : #if ( FIX_GAF_2019_2==1 )
5345 : : /* hack: pass state in na_total (will be updated in ParseSegmentFormula anyway) */
5346 : 0 : na_total = state;
5347 : : #endif
5348 : 0 : ret = ParseSegmentFormula(pLine->str, bMobileH, pInpInChI[bReconn],
5349 : 0 : nNumComponents[bReconn], &na_total);
5350 : 0 : state = IST_FIXED_H;
5351 : 0 : break;
5352 : 0 : case IST_FIXED_H: /* /f/h */
5353 : 0 : ret = ParseSegmentMobileH(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], &bAbc);
5354 : 0 : state = IST_FIXED_H_CHARGE;
5355 : 0 : break;
5356 : 0 : case IST_FIXED_H_CHARGE: /* /f/q */
5357 : 0 : ret = ParseSegmentCharge(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn]);
5358 : 0 : state = IST_FIXED_H_SP2;
5359 : 0 : break;
5360 : 0 : case IST_FIXED_H_SP2: /* /f/b */
5361 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5362 : 0 : state = IST_FIXED_H_SP3;
5363 : 0 : break;
5364 : 0 : case IST_FIXED_H_SP3: /* /f/t */
5365 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5366 : 0 : state = IST_FIXED_H_SP3_M;
5367 : 0 : break;
5368 : 0 : case IST_FIXED_H_SP3_M: /* /f/m */
5369 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5370 : 0 : state = IST_FIXED_H_SP3_S;
5371 : 0 : break;
5372 : 0 : case IST_FIXED_H_SP3_S: /* /f/s */
5373 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5374 : 0 : state = IST_FIXED_H_PERMUTATION;
5375 : 0 : break;
5376 : 0 : case IST_FIXED_H_PERMUTATION: /* /f/o */
5377 : 0 : ret = ParseSegmentPerm(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5378 : 0 : state = IST_FIXED_H_ISO_LAYER_FORK;
5379 : 0 : break;
5380 : 0 : case IST_FIXED_H_ISO_LAYER_FORK:
5381 : : /* find layer type after M */
5382 : 0 : ret = 0;
5383 [ # # # ]: 0 : switch (pLine->str[0])
5384 : : {
5385 : 0 : case 'i':
5386 : 0 : state = IST_FIXED_H_ISO_ATOMS; /* FI */
5387 : 0 : break;
5388 : 0 : case 'r':
5389 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5390 : 0 : break;
5391 : 0 : default:
5392 : 0 : ret = RI_ERR_SYNTAX;
5393 : : }
5394 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5395 : : {
5396 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5397 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /i or /r at the end of InChI line */
5398 : : }
5399 : : else
5400 : : {
5401 [ # # # # ]: 0 : if (!ret && state != IST_FIXED_H_ISO_ATOMS)
5402 : : {
5403 : 0 : len = (int)strlen(pLine->str);
5404 [ # # ]: 0 : if (len > 1)
5405 : : {
5406 : 0 : memmove(pLine->str, pLine->str + 1, len);
5407 : : }
5408 : : else
5409 : : {
5410 : 0 : ret = 1; /* read the next segment */
5411 : : }
5412 : : }
5413 : : }
5414 : 0 : break;
5415 : :
5416 : : /* Fixed H, isotopic, FI */
5417 : 0 : case IST_FIXED_H_ISO_ATOMS: /* /f/i */
5418 : 0 : ret = ParseSegmentIsoAtoms(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5419 : 0 : state = IST_FIXED_H_ISO_SP2;
5420 : 0 : break;
5421 : 0 : case IST_FIXED_H_ISO_SP2: /* /f/i/b */
5422 : 0 : ret = ParseSegmentSp2(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5423 : 0 : state = IST_FIXED_H_ISO_SP3;
5424 : 0 : break;
5425 : 0 : case IST_FIXED_H_ISO_SP3: /* /f/i/t */
5426 : 0 : ret = ParseSegmentSp3(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5427 : 0 : state = IST_FIXED_H_ISO_SP3_M;
5428 : 0 : break;
5429 : 0 : case IST_FIXED_H_ISO_SP3_M: /* /f/i/m */
5430 : 0 : ret = ParseSegmentSp3m(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state);
5431 : 0 : state = IST_FIXED_H_ISO_SP3_S;
5432 : 0 : break;
5433 : 0 : case IST_FIXED_H_ISO_SP3_S: /* /f/i/s */
5434 : 0 : ret = ParseSegmentSp3s(pLine->str, bMobileH, pInpInChI[bReconn], s[bReconn], nNumComponents[bReconn], state);
5435 : 0 : state = IST_FIXED_H_ISO_PERMUTATION;
5436 : 0 : break;
5437 : 0 : case IST_FIXED_H_ISO_PERMUTATION: /* /f/i/o */
5438 : 0 : ret = ParseSegmentPerm(pLine->str, bMobileH, pInpInChI[bReconn], nNumComponents[bReconn], state, &bAbc);
5439 : 0 : state = IST_RECONNECTED_LAYER_FORK;
5440 : 0 : break;
5441 : 0 : case IST_RECONNECTED_LAYER_FORK:
5442 : : /* find layer type after FI */
5443 : 0 : ret = 0;
5444 [ # # ]: 0 : switch (pLine->str[0])
5445 : : {
5446 : 0 : case 'r':
5447 : 0 : state = IST_RECONNECTED_FORMULA; /* reconnected */
5448 : 0 : break;
5449 : 0 : default:
5450 : 0 : ret = RI_ERR_SYNTAX;
5451 : : }
5452 [ # # # # : 0 : if (INCHI_INP_EOL(c) && ret == 0 && !pLine->str[1])
# # # # #
# ]
5453 : : {
5454 [ # # ]: 0 : prev_state = state + (bReconn ? IST_HAPPENED_IN_RECMET : 0);
5455 : 0 : ret = RI_ERR_SYNTAX; /* empty layer /r at the end of InChI line */
5456 : : }
5457 : : else
5458 : : {
5459 [ # # ]: 0 : if (!ret)
5460 : : {
5461 : 0 : len = (int)strlen(pLine->str);
5462 [ # # ]: 0 : if (len > 1)
5463 : : {
5464 : 0 : memmove(pLine->str, pLine->str + 1, len);
5465 : : }
5466 : : else
5467 : : {
5468 : 0 : ret = 1; /* read the next segment */
5469 : : }
5470 : : }
5471 : : }
5472 : 0 : break;
5473 : 0 : case IST_RECONNECTED_FORMULA:
5474 : : #if ( FIX_GAF_2019_1==1 )
5475 [ # # ]: 0 : if (bReconn == INCHI_REC)
5476 : : {
5477 : : /* reconnected layer may appear only once */
5478 : 0 : ret = RI_ERR_SYNTAX;
5479 : 0 : break;
5480 : : }
5481 : : #endif
5482 : 0 : bReconn = INCHI_REC;
5483 : 0 : bMobileH = TAUT_YES;
5484 : 0 : state = IST_MOBILE_H_FORMULA;
5485 : 0 : break;
5486 : : }
5487 [ + - ]: 15 : } while (c >= 0);
5488 : :
5489 : 2 : exit_function:;
5490 : 2 : exit_error:;
5491 : :
5492 : : INCHI_HEAPCHK
5493 : :
5494 [ + - - + : 2 : if (ret >= 0 || c == RI_ERR_EOF || c == RI_ERR_EOL)
- - ]
5495 : : {
5496 : 2 : pLine->len = 0;
5497 : : }
5498 : :
5499 : 2 : return ret;
5500 : : }
5501 : :
5502 : :
5503 : : /****************************************************************************
5504 : : Parse InChI layer "/i/h"
5505 : : ****************************************************************************/
5506 : 0 : int ParseSegmentIsoExchgH(const char* str,
5507 : : int bMobileH,
5508 : : REM_PROTONS nNumProtons[],
5509 : : int pnNumComponents[],
5510 : : int state,
5511 : : int* pbAbc)
5512 : : {
5513 : : /* Pass 1: count bonds and find actual numbers of atom */
5514 : : const char* p, * q, * pStart, * pEnd;
5515 : 0 : int ret = 0, num, i, i_prev;
5516 : : static const char abc_h[] = "hdt";
5517 : :
5518 [ # # ]: 0 : if (str[0] != 'h')
5519 : : {
5520 : 0 : return 0;
5521 : : }
5522 : :
5523 : 0 : pStart = (char*)str + 1;
5524 : :
5525 [ # # # # ]: 0 : if (!(bMobileH == TAUT_YES && state == IST_MOBILE_H_ISO_EXCH_H))
5526 : : {
5527 : 0 : return RI_ERR_PROGR; /* program error */
5528 : : }
5529 : :
5530 [ # # ]: 0 : if (!(strchr(pStart, ';'))) /* djb-rwth: removing redundant code */
5531 : : {
5532 : 0 : pEnd = pStart + strlen(pStart);
5533 : : }
5534 : : else
5535 : : {
5536 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5537 : 0 : goto exit_function;
5538 : : }
5539 : 0 : p = pStart;
5540 : :
5541 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
5542 : : {
5543 : : /* check if compressed InChI */
5544 : : /* compressed: /hNtNdNh where N is a decimal number */
5545 : : /* uncompressed: /hT[n]D[n]H[n] where n > 1 is a decimal number */
5546 : 0 : *pbAbc = isdigit(UCINT * p) ? 1 : 0;
5547 : : }
5548 : :
5549 [ # # ]: 0 : if (*pbAbc == 1)
5550 : : {
5551 : 0 : i_prev = (int)sizeof(abc_h);
5552 [ # # ]: 0 : while (p < pEnd)
5553 : : {
5554 : 0 : num = (int)inchi_strtol(p, &q, 10);
5555 : : #if ( CHECK_STRTOL_ATNUMB==1 )
5556 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
5557 : : {
5558 : 0 : ret = RI_ERR_SYNTAX;
5559 : 0 : goto exit_function;
5560 : : }
5561 : : #endif
5562 [ # # # # : 0 : if (0 >= num || p == q || q >= pEnd)
# # ]
5563 : : {
5564 : 0 : ret = RI_ERR_SYNTAX;
5565 : 0 : goto exit_function;
5566 : : }
5567 : 0 : p = strchr((char*)abc_h, *q);
5568 [ # # # # : 0 : if (p && (i = (int)(p - abc_h)) < i_prev && (i < NUM_H_ISOTOPES)) /* djb-rwth: additional condition for buffer overrun prevention */
# # ]
5569 : : {
5570 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[i] = (NUM_H)num;
5571 : 0 : p = q + 1;
5572 : 0 : i_prev = i;
5573 : : }
5574 : : else
5575 : : {
5576 : 0 : ret = RI_ERR_SYNTAX;
5577 : 0 : goto exit_function;
5578 : : }
5579 : : }
5580 : : }
5581 : : else
5582 : : {
5583 [ # # ]: 0 : if (*p == 'T')
5584 : : {
5585 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[2] = 1;
5586 : 0 : p++;
5587 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5588 : : {
5589 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[2] = (NUM_H)inchi_strtol(p, &q, 10);
5590 : 0 : p = q;
5591 : : }
5592 : : }
5593 [ # # ]: 0 : if (*p == 'D')
5594 : : {
5595 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[1] = 1;
5596 : 0 : p++;
5597 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5598 : : {
5599 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[1] = (NUM_H)inchi_strtol(p, &q, 10);
5600 : 0 : p = q;
5601 : : }
5602 : : }
5603 [ # # ]: 0 : if (*p == 'H')
5604 : : {
5605 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[0] = 1;
5606 : 0 : p++;
5607 [ # # ]: 0 : if (isdigit(UCINT p[0]))
5608 : : {
5609 : 0 : nNumProtons[bMobileH].nNumRemovedIsotopicH[0] = (NUM_H)inchi_strtol(p, &q, 10);
5610 : 0 : p = q;
5611 : : }
5612 : : }
5613 : : }
5614 [ # # ]: 0 : if (p != pEnd)
5615 : : {
5616 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5617 : 0 : goto exit_function;
5618 : : }
5619 : 0 : ret = 1;
5620 : :
5621 : 0 : exit_function:
5622 : :
5623 : 0 : return ret;
5624 : : }
5625 : :
5626 : :
5627 : : /****************************************************************************/
5628 : 0 : int ParseSegmentPerm(const char* str,
5629 : : int bMobileH,
5630 : : INChI* pInpInChI[],
5631 : : int ppnNumComponents[],
5632 : : int state,
5633 : : int* pbAbc)
5634 : : {
5635 : : int nNumComponents, iComponent1, iComponent2, numTrans;
5636 : : const char* p, * q, * pStart, * pEnd, * pPermStart, * pPermEnd;
5637 : 0 : int ret = 0;
5638 : 0 : INChI* pInChI = pInpInChI[bMobileH]; /* bMobileH should be TAUT_NON = 0 */
5639 : : INChI tmp;
5640 : 0 : int base = 10;
5641 : :
5642 [ # # ]: 0 : if (str[0] != 'o')
5643 : : {
5644 : 0 : return 0;
5645 : : }
5646 : :
5647 : : /* djb-rwth: fixing oss-fuzz issue #66746 */
5648 [ # # ]: 0 : if (!pInChI)
5649 : : {
5650 : 0 : return RI_ERR_ALLOC;
5651 : : }
5652 : :
5653 : 0 : pStart = (char*)str + 1;
5654 : 0 : nNumComponents = ppnNumComponents[bMobileH];
5655 : :
5656 [ # # # # : 0 : if (!(bMobileH == TAUT_NON && (state == IST_FIXED_H_PERMUTATION || state == IST_FIXED_H_ISO_PERMUTATION)))
# # ]
5657 : : {
5658 : 0 : return RI_ERR_PROGR; /* program error */
5659 : : }
5660 : :
5661 [ # # ]: 0 : if (!(strchr(pStart, ';'))) /* djb-rwth: removing redundant code */
5662 : : {
5663 : 0 : pEnd = pStart + strlen(pStart);
5664 : : }
5665 : : else
5666 : : {
5667 : 0 : return RI_ERR_SYNTAX; /* syntax error */
5668 : : }
5669 [ # # ]: 0 : while (pStart < pEnd)
5670 : : {
5671 : : /* cycle over components; rearrange Fixed H components in order of Mobile H components */
5672 : : /* if /o(1,2,3) then reaarange Fixed H components in this way: tmp<-1, 1<-2, 2<-3, 3<-tmp */
5673 [ # # ]: 0 : if (*pStart != '(')
5674 : : {
5675 : 0 : ret = RI_ERR_SYNTAX;
5676 : 0 : goto exit_function;
5677 : : }
5678 : 0 : pPermStart = pStart + 1;
5679 : 0 : memset(&tmp, 0, sizeof(tmp)); /* initialization 2006-03 */ /* djb-rwth: memset_s C11/Annex K variant? */
5680 [ # # # # ]: 0 : if (!(pPermEnd = strchr(pPermStart, ')')) || pPermEnd == pPermStart)
5681 : : {
5682 : 0 : ret = RI_ERR_SYNTAX;
5683 : 0 : goto exit_function;
5684 : : }
5685 : :
5686 [ # # # # ]: 0 : if (pPermStart < pPermEnd && *pbAbc == -1)
5687 : : {
5688 : : /* check if compressed InChI */
5689 : 0 : *pbAbc = isupper(UCINT * pPermStart) ? 1 : 0;
5690 : : }
5691 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
5692 : :
5693 : : /* permutation cycle */
5694 [ # # ]: 0 : if (*pbAbc == 1)
5695 : : {
5696 [ # # ]: 0 : for (p = pPermStart, iComponent2 = numTrans = 0; p < pPermEnd; iComponent2 = iComponent1, p = q)
5697 : : {
5698 : : /* get first atom number */
5699 [ # # # # ]: 0 : if (0 >= (iComponent1 = (int)inchi_strtol(p, &q, base)) || iComponent1 > nNumComponents)
5700 : : {
5701 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5702 : 0 : goto exit_function;
5703 : : }
5704 : : #if ( FIX_GAF_2019_2==1 )
5705 [ # # # # ]: 0 : if ((iComponent1 - 1 > nNumComponents - 1) || (iComponent1 - 1 < 0))
5706 : : {
5707 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5708 : 0 : goto exit_function;
5709 : : }
5710 : : #endif
5711 [ # # ]: 0 : if (iComponent2)
5712 : : {
5713 : 0 : pInChI[iComponent2 - 1] = pInChI[iComponent1 - 1];
5714 : 0 : numTrans++;
5715 : : }
5716 : : else
5717 : : {
5718 : 0 : tmp = pInChI[iComponent1 - 1]; /* on the 1st pass save Component1 */
5719 : : }
5720 : : }
5721 : : }
5722 : : else
5723 : : {
5724 [ # # ]: 0 : for (p = pPermStart, iComponent2 = numTrans = 0; p < pPermEnd; iComponent2 = iComponent1, p = q + (*q == ','))
5725 : : {
5726 : : /* get first atom number */
5727 [ # # ]: 0 : if (!isdigit(UCINT * p))
5728 : : {
5729 : 0 : ret = RI_ERR_SYNTAX;
5730 : 0 : goto exit_function;
5731 : : }
5732 : 0 : iComponent1 = (int)inchi_strtol(p, &q, 10);
5733 [ # # # # ]: 0 : if ((iComponent1 < 1) || (iComponent1 > nNumComponents)) /* djb-rwth: fixing oss-fuzz issue #66746 */
5734 : : {
5735 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5736 : 0 : goto exit_function;
5737 : : }
5738 [ # # ]: 0 : if (iComponent2)
5739 : : {
5740 : 0 : pInChI[iComponent2 - 1] = pInChI[iComponent1 - 1];
5741 : 0 : numTrans++;
5742 : : }
5743 : : else
5744 : : {
5745 : 0 : tmp = pInChI[iComponent1 - 1]; /* on the 1st pass save Component1 */
5746 : : }
5747 : : }
5748 : : }
5749 : 0 : pInChI[iComponent2 - 1] = tmp;
5750 [ # # # # ]: 0 : if (!numTrans || p != pPermEnd)
5751 : : {
5752 : 0 : ret = RI_ERR_SYNTAX;
5753 : 0 : goto exit_function;
5754 : : }
5755 : : else
5756 : : {
5757 : 0 : pStart = p + 1;
5758 : : }
5759 : : }
5760 : 0 : ret = 1;
5761 : :
5762 : 0 : exit_function:
5763 : :
5764 : 0 : return ret;
5765 : : }
5766 : :
5767 : :
5768 : : /****************************************************************************
5769 : : Parse InChI layer "/i"
5770 : : ****************************************************************************/
5771 : 1 : int ParseSegmentIsoAtoms(const char* str,
5772 : : int bMobileH,
5773 : : INChI* pInpInChI[],
5774 : : int ppnNumComponents[],
5775 : : int state,
5776 : : int* pbAbc)
5777 : : {
5778 : : int i, mpy_component, val;
5779 : 1 : int nNumComponents, iComponent, len = 0, iAtom;
5780 : : int nAtom1; /* djb-rwth: fixing coverity ID #499573 */
5781 : : const char* p, * q, * t, * pStart, * pEnd, * r;
5782 : 1 : int ret = 0;
5783 : 1 : INChI* pInChI = pInpInChI[bMobileH];
5784 : 1 : INChI* pInChIFrom = NULL;
5785 : 1 : INChI_IsotopicAtom** pIsotopicAtom = NULL;
5786 : : INChI_IsotopicAtom isoAtom;
5787 : :
5788 : 1 : const char mult_type[] = "mnMNe";
5789 : 1 : const char parity_type[] = "-+TDH";
5790 : 1 : int bIsoFrom, nCpyType = CPY_ISO_AT;
5791 : 1 : int base = 10;
5792 : 1 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
5793 : :
5794 [ - + ]: 1 : if (str[0] != 'i')
5795 : : {
5796 : 0 : return 0;
5797 : : }
5798 : :
5799 : 1 : pStart = (char*)str + 1;
5800 : 1 : iComponent = 0;
5801 : 1 : nNumComponents = ppnNumComponents[bMobileH];
5802 : :
5803 [ + - - + : 1 : if (!((bMobileH == TAUT_YES && state == IST_MOBILE_H_ISO_ATOMS) ||
- - ]
5804 [ # # ]: 0 : (bMobileH == TAUT_NON && state == IST_FIXED_H_ISO_ATOMS))) /* djb-rwth: addressing LLVM warnings */
5805 : : {
5806 : 0 : return RI_ERR_PROGR; /* program error */
5807 : : }
5808 [ - + ]: 1 : if (!*pStart)
5809 : : {
5810 : 0 : return nNumComponents + 1; /* no isotopic atoms */
5811 : : }
5812 : :
5813 : : while (1)
5814 : : {
5815 : : /* cycle over components */
5816 [ + - ]: 1 : if (!(pEnd = strchr(pStart, ';')))
5817 : : {
5818 : 1 : pEnd = pStart + strlen(pStart);
5819 : : }
5820 [ - + - - ]: 1 : if ((p = strchr(pStart, '*')) && p < pEnd)
5821 : : {
5822 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
5823 [ # # ]: 0 : if (p != q)
5824 : : {
5825 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5826 : 0 : goto exit_function;
5827 : : }
5828 : : #if (FIX_DALKE_BUGS == 1)
5829 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
5830 : : {
5831 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5832 : 0 : goto exit_function;
5833 : : }
5834 : : #endif
5835 : 0 : p++; /* move to the 1st character of the component */
5836 : : }
5837 : : else
5838 : : {
5839 : : /* djb-rwth: condition for if block had to be rewritten */
5840 [ + - ]: 1 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
5841 : : {
5842 : 1 : val = (int)inchi_strtol(pStart, &q, 10);
5843 : 1 : if_cnd = isdigit(*pStart);
5844 : :
5845 : : }
5846 : : else
5847 : : {
5848 : 0 : val = 1;
5849 : 0 : q = pStart;
5850 : 0 : if_cnd = 1;
5851 : : }
5852 : :
5853 [ + - - + : 1 : 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 */
- - ]
5854 : : {
5855 : : /* process the abbreviation */
5856 : 0 : ret = 0;
5857 : : #if (FIX_DALKE_BUGS == 1)
5858 [ # # ]: 0 : if (iComponent + val > nNumComponents)
5859 : : {
5860 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5861 : 0 : goto exit_function;
5862 : : }
5863 : : #endif
5864 : 0 : bIsoFrom = 0;
5865 [ # # # ]: 0 : switch (bMobileH)
5866 : : {
5867 : 0 : case TAUT_YES:
5868 : 0 : ret = RI_ERR_SYNTAX;
5869 : 0 : break;
5870 : 0 : case TAUT_NON:
5871 [ # # ]: 0 : if (*q == 'm')
5872 : : {
5873 : : /* copy from mobile H to fixed H */
5874 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
5875 : : }
5876 : : else
5877 : : {
5878 [ # # ]: 0 : if (*q == 'e')
5879 : : {
5880 : : /* copy from mobile H to isotopic mobile H */
5881 : 0 : pInChIFrom = pInChI;
5882 : 0 : bIsoFrom = -1; /* empty */
5883 : : }
5884 : : else
5885 : : {
5886 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5887 : : }
5888 : : }
5889 : 0 : break;
5890 : 0 : default:
5891 : 0 : ret = RI_ERR_SYNTAX;
5892 : 0 : break;
5893 : : }
5894 [ # # ]: 0 : if (ret < 0)
5895 : : {
5896 : 0 : goto exit_function;
5897 : : }
5898 : : /* copy */
5899 [ # # ]: 0 : for (i = 0; i < val; i++)
5900 : : {
5901 : : #if ( FIX_GAF_2019_2==1 )
5902 : : {
5903 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents) || (iComponent + i < 0))
5904 : : {
5905 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5906 : 0 : goto exit_function;
5907 : : }
5908 : : }
5909 : : #endif
5910 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, 0, bIsoFrom);
5911 [ # # ]: 0 : if (!ret)
5912 : : {
5913 : 0 : ret = RI_ERR_SYNTAX;
5914 : : }
5915 [ # # ]: 0 : if (ret < 0)
5916 : : {
5917 : 0 : goto exit_function;
5918 : : }
5919 : : }
5920 : 0 : iComponent += val;
5921 : : /* continue to the next component(s) */
5922 [ # # ]: 0 : if (*pEnd)
5923 : : {
5924 : 0 : pStart = pEnd + 1;
5925 : 0 : continue;
5926 : : }
5927 : : else
5928 : : {
5929 : 0 : break;
5930 : : }
5931 : : }
5932 : : else
5933 : : {
5934 : 1 : mpy_component = 1;
5935 : 1 : p = pStart;
5936 : : }
5937 : : }
5938 : :
5939 : : #if ( FIX_GAF_2019_2==1 )
5940 [ + - - + ]: 1 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
5941 : : {
5942 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5943 : 0 : goto exit_function;
5944 : : }
5945 [ + - - + ]: 1 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
5946 : : {
5947 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5948 : 0 : goto exit_function;
5949 : : }
5950 : : #endif
5951 : 1 : pStart = p;
5952 : 1 : pIsotopicAtom = &pInChI[iComponent].IsotopicAtom;
5953 [ - + ]: 1 : if (*pIsotopicAtom)
5954 : : {
5955 : 0 : ret = RI_ERR_PROGR; /* program error */
5956 : 0 : goto exit_function;
5957 : : }
5958 : :
5959 [ + - - + ]: 1 : if (p < pEnd && *pbAbc == -1)
5960 : : {
5961 : : /* check if compressed InChI */
5962 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
5963 : : }
5964 [ - + ]: 1 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
5965 : :
5966 : 1 : one_more_time:
5967 [ - + ]: 1 : if (*pbAbc == 1)
5968 : : {
5969 : : /* process the componnt: At[+/-Charge]TDH,... */
5970 : : /* pass 1: find number of stereoatoms */
5971 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
5972 : : {
5973 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base);
5974 : : #if ( CHECK_STRTOL_ATNUMB==1 )
5975 [ # # # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
5976 : : {
5977 : 0 : ret = RI_ERR_SYNTAX;
5978 : 0 : goto exit_function;
5979 : : }
5980 : : #endif
5981 [ # # ]: 0 : if (!nAtom1 ||
5982 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms)
5983 : : {
5984 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5985 : 0 : goto exit_function;
5986 : : }
5987 : 0 : memset(&isoAtom, 0, sizeof(isoAtom)); /* djb-rwth: memset_s C11/Annex K variant? */
5988 : 0 : isoAtom.nAtomNumber = nAtom1;
5989 : 0 : isoAtom.nIsoDifference = (NUM_H)inchi_strtol(p, &q, 10); /* alway in abc */
5990 [ # # ]: 0 : if (p == q)
5991 : : {
5992 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
5993 : 0 : goto exit_function;
5994 : : }
5995 : 0 : p = q;
5996 [ # # ]: 0 : if (*p == 't')
5997 : : {
5998 : 0 : isoAtom.nNum_T = 1;
5999 : 0 : p++;
6000 [ # # ]: 0 : if (isdigit(UCINT * p))
6001 : : {
6002 : 0 : isoAtom.nNum_T = (NUM_H)inchi_strtol(p, &q, 10);
6003 : 0 : p = q;
6004 : : }
6005 : : }
6006 [ # # ]: 0 : if (*p == 'd')
6007 : : {
6008 : 0 : isoAtom.nNum_D = 1;
6009 : 0 : p++;
6010 [ # # ]: 0 : if (isdigit(UCINT * p))
6011 : : {
6012 : 0 : isoAtom.nNum_D = (NUM_H)inchi_strtol(p, &q, 10);
6013 : 0 : p = q;
6014 : : }
6015 : : }
6016 [ # # ]: 0 : if (*p == 'h')
6017 : : {
6018 : 0 : isoAtom.nNum_H = 1;
6019 : 0 : p++;
6020 [ # # ]: 0 : if (isdigit(UCINT * p))
6021 : : {
6022 : 0 : isoAtom.nNum_H = (NUM_H)inchi_strtol(p, &q, 10);
6023 : 0 : p = q;
6024 : : }
6025 : : }
6026 [ # # # # : 0 : if (p > pEnd || (!isoAtom.nIsoDifference && !isoAtom.nNum_T && !isoAtom.nNum_D && !isoAtom.nNum_H)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
6027 : : {
6028 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6029 : 0 : goto exit_function;
6030 : : }
6031 [ # # ]: 0 : if (*pIsotopicAtom)
6032 : : {
6033 : 0 : pIsotopicAtom[0][iAtom] = isoAtom;
6034 : : }
6035 : : }
6036 : : }
6037 : : else
6038 : : {
6039 : : /* process the componnt: At[+/-Charge]TDH,... */
6040 : : /* pass 1: find number of stereoatoms */
6041 [ + - ]: 1 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
6042 : : {
6043 : 1 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
6044 : : #if ( CHECK_STRTOL_ATNUMB==1 )
6045 [ + - - + ]: 1 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
6046 : : {
6047 : 0 : ret = RI_ERR_SYNTAX;
6048 : 0 : goto exit_function;
6049 : : }
6050 : : #endif
6051 : 1 : p = q;
6052 [ + - ]: 1 : if (!nAtom1 ||
6053 [ - + ]: 1 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
6054 [ # # ]: 0 : !(r = strchr((char*)parity_type, *p))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
6055 : : {
6056 : 1 : ret = RI_ERR_SYNTAX; /* syntax error */
6057 : 1 : goto exit_function;
6058 : : }
6059 : 0 : memset(&isoAtom, 0, sizeof(isoAtom)); /* djb-rwth: memset_s C11/Annex K variant? */
6060 : 0 : isoAtom.nAtomNumber = nAtom1;
6061 [ # # # # ]: 0 : if (p[0] == '+' && isdigit(UCINT p[1]))
6062 : : {
6063 : 0 : isoAtom.nIsoDifference = (NUM_H)inchi_strtol(p + 1, &q, 10);
6064 [ # # ]: 0 : if (isoAtom.nIsoDifference >= 0) isoAtom.nIsoDifference++;
6065 : 0 : p = q;
6066 : : }
6067 : : else
6068 [ # # # # ]: 0 : if (p[0] == '-' && isdigit(UCINT p[1]))
6069 : : {
6070 : 0 : isoAtom.nIsoDifference = -(NUM_H)inchi_strtol(p + 1, &q, 10);
6071 [ # # ]: 0 : if (isoAtom.nIsoDifference == 0) isoAtom.nIsoDifference++;
6072 : 0 : p = q;
6073 : : }
6074 [ # # ]: 0 : if (*p == 'T')
6075 : : {
6076 : 0 : isoAtom.nNum_T = 1;
6077 : 0 : p++;
6078 [ # # ]: 0 : if (isdigit(UCINT * p))
6079 : : {
6080 : 0 : isoAtom.nNum_T = (NUM_H)inchi_strtol(p, &q, 10);
6081 : 0 : p = q;
6082 : : }
6083 : : }
6084 [ # # ]: 0 : if (*p == 'D')
6085 : : {
6086 : 0 : isoAtom.nNum_D = 1;
6087 : 0 : p++;
6088 [ # # ]: 0 : if (isdigit(UCINT * p))
6089 : : {
6090 : 0 : isoAtom.nNum_D = (NUM_H)inchi_strtol(p, &q, 10);
6091 : 0 : p = q;
6092 : : }
6093 : : }
6094 [ # # ]: 0 : if (*p == 'H')
6095 : : {
6096 : 0 : isoAtom.nNum_H = 1;
6097 : 0 : p++;
6098 [ # # ]: 0 : if (isdigit(UCINT * p))
6099 : : {
6100 : 0 : isoAtom.nNum_H = (NUM_H)inchi_strtol(p, &q, 10);
6101 : 0 : p = q;
6102 : : }
6103 : : }
6104 [ # # # # : 0 : if (!isoAtom.nIsoDifference && !isoAtom.nNum_T && !isoAtom.nNum_D && !isoAtom.nNum_H)
# # # # ]
6105 : : {
6106 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6107 : 0 : goto exit_function;
6108 : : }
6109 [ # # ]: 0 : if (p < pEnd)
6110 : : {
6111 [ # # ]: 0 : if (*p == ',')
6112 : : {
6113 : 0 : p++;
6114 : : }
6115 : : else
6116 : : {
6117 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6118 : 0 : goto exit_function;
6119 : : }
6120 : : }
6121 [ # # ]: 0 : if (*pIsotopicAtom)
6122 : : {
6123 : 0 : pIsotopicAtom[0][iAtom] = isoAtom;
6124 : : }
6125 : : }
6126 : : }
6127 [ # # ]: 0 : if (p != pEnd)
6128 : : {
6129 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6130 : 0 : goto exit_function;
6131 : : }
6132 : :
6133 [ # # ]: 0 : if (!*pIsotopicAtom)
6134 : : {
6135 : : /* end of the 1st pass */
6136 : 0 : len = iAtom;
6137 : : /* memory allocation */
6138 [ # # ]: 0 : if (!(*pIsotopicAtom = (INChI_IsotopicAtom*)inchi_calloc((long long)len + 1, sizeof(**pIsotopicAtom)))) /* djb-rwth: cast operator added */
6139 : : {
6140 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6141 : 0 : goto exit_function;
6142 : : }
6143 : 0 : goto one_more_time; /* goto the 2nd pass */
6144 : : }
6145 : : else
6146 : : {
6147 : : /* 2nd pass */
6148 [ # # ]: 0 : if (len != iAtom)
6149 : : {
6150 : 0 : ret = RI_ERR_PROGR; /* program error */
6151 : 0 : goto exit_function;
6152 : : }
6153 : 0 : pInChI[iComponent].nNumberOfIsotopicAtoms = len;
6154 : : }
6155 : :
6156 : : /* multiplier */
6157 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
6158 : : {
6159 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, 0, 0);
6160 [ # # ]: 0 : if (!ret)
6161 : : {
6162 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6163 : : }
6164 [ # # ]: 0 : if (ret < 0)
6165 : : {
6166 : 0 : goto exit_function;
6167 : : }
6168 : : }
6169 : :
6170 : 0 : iComponent += mpy_component;
6171 [ # # ]: 0 : if (*pEnd)
6172 : : {
6173 : 0 : pStart = pEnd + 1;
6174 : 0 : continue;
6175 : : }
6176 : : else
6177 : : {
6178 : 0 : break;
6179 : : }
6180 : :
6181 : : }
6182 : :
6183 [ # # ]: 0 : if (nNumComponents != iComponent)
6184 : : {
6185 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6186 : 0 : goto exit_function;
6187 : : }
6188 : :
6189 : 0 : ret = iComponent + 1;
6190 : :
6191 : 1 : exit_function:
6192 : :
6193 : 1 : return ret;
6194 : : }
6195 : :
6196 : :
6197 : : /****************************************************************************
6198 : : Parse "/i/s" InChI layer
6199 : : ****************************************************************************/
6200 : 1 : int ParseSegmentSp3s(const char* str,
6201 : : int bMobileH,
6202 : : INChI* pInpInChI[],
6203 : : int s[TAUT_NUM][2],
6204 : : int ppnNumComponents[],
6205 : : int state)
6206 : : {
6207 : : /* Pass 1: count bonds and find actual numbers of atom */
6208 : : int nNumComponents, iComponent, val;
6209 : : const char* p, * q, * pStart, * pEnd;
6210 : 1 : int ret = 0;
6211 : 1 : INChI* pInChI = pInpInChI[bMobileH];
6212 : 1 : INChI_Stereo** pStereo = NULL;
6213 : :
6214 [ + - - + ]: 1 : int bIso = (state == IST_MOBILE_H_ISO_SP3_S || state == IST_FIXED_H_ISO_SP3_S);
6215 : :
6216 [ + - - + : 1 : if (!bIso && state != IST_MOBILE_H_SP3_S && state != IST_FIXED_H_SP3_S)
- - ]
6217 : : {
6218 : 0 : return RI_ERR_PROGR; /* program error */
6219 : : }
6220 : :
6221 [ + - ]: 1 : if (str[0] != 's')
6222 : : {
6223 : 1 : return 0;
6224 : : }
6225 : :
6226 : 0 : pStart = (char*)str + 1;
6227 : : /* djb-rwth: removing redundant code */
6228 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6229 : :
6230 : : /*if ( !(pEnd = strchr( pStart, ';' )) )*/ /* 2007-09-25 DT */
6231 [ # # ]: 0 : if (!(strchr(pStart, '/'))) /* djb-rwth: removing redundant variables/code */
6232 : : {
6233 : 0 : pEnd = pStart + strlen(pStart);
6234 : : }
6235 : : else
6236 : : {
6237 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6238 : 0 : goto exit_function;
6239 : : }
6240 : 0 : p = pStart;
6241 [ # # ]: 0 : if (pEnd == pStart)
6242 : : {
6243 : : /* create empty sp3 segment */
6244 : 0 : int len = 0;
6245 : 0 : s[bMobileH][bIso] = NO_VALUE_INT; /* empty */
6246 : : /* create empty sp3 segment */
6247 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6248 : : {
6249 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6250 [ # # ]: 0 : if (!*pStereo)
6251 : : {
6252 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6253 : : {
6254 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6255 : 0 : goto exit_function;
6256 : : }
6257 : : }
6258 : 0 : pStereo[0]->nCompInv2Abs = 0; /* deliberately empty */
6259 : :
6260 [ # # ]: 0 : if (pStereo[0]->nNumberOfStereoCenters)
6261 : : {
6262 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: "/s" without a digit describes "no stereo" */
6263 : 0 : goto exit_function;
6264 : : }
6265 : : /* allocate empty sp3 stereo */
6266 [ # # ]: 0 : if ((!pStereo[0]->t_parity &&
6267 [ # # ]: 0 : !(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0])))) ||
6268 [ # # ]: 0 : (!pStereo[0]->nNumber &&
6269 [ # # ]: 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 */
6270 : : {
6271 : : /* cleanup */
6272 [ # # ]: 0 : if (pStereo[0]->t_parity)
6273 : : {
6274 : : INCHI_HEAPCHK
6275 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6276 : 0 : pStereo[0]->t_parity = NULL;
6277 : : }
6278 [ # # ]: 0 : if (pStereo[0]->nNumber)
6279 : : {
6280 : : INCHI_HEAPCHK
6281 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6282 : 0 : pStereo[0]->nNumber = NULL;
6283 : : }
6284 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6285 : 0 : goto exit_function;
6286 : : }
6287 : : }
6288 : 0 : ret = nNumComponents + 1;
6289 : : }
6290 : : else
6291 : : {
6292 : 0 : val = (int)inchi_strtol(p, &q, 10);
6293 [ # # # # : 0 : if (q == pEnd && 1 <= val && val <= 3)
# # ]
6294 : : {
6295 : 0 : s[bMobileH][bIso] = val;
6296 : 0 : ret = nNumComponents + 1;
6297 : : }
6298 : : else
6299 : : {
6300 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6301 : : }
6302 : : }
6303 : :
6304 : 0 : exit_function:
6305 : :
6306 : 0 : return ret;
6307 : : }
6308 : :
6309 : :
6310 : : /****************************************************************************/
6311 : 0 : int bIsSp3LayerNotEmpty(INChI* pInpInChI[],
6312 : : int bMobileH,
6313 : : int bIso,
6314 : : int nNumComponents)
6315 : : {
6316 : : INChI* pInChI;
6317 : : INChI_Stereo* pStereo;
6318 : 0 : int iComponent, num_not_empty = 0;
6319 : :
6320 [ # # ]: 0 : if (pInpInChI[bMobileH])
6321 : : {
6322 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6323 : : {
6324 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
6325 [ # # # # ]: 0 : if (pInChI->bDeleted || !pInChI->nNumberOfAtoms)
6326 : : {
6327 : 0 : continue;
6328 : : }
6329 [ # # ]: 0 : pStereo = bIso ? pInChI->StereoIsotopic : pInChI->Stereo;
6330 [ # # # # : 0 : if (pStereo && pStereo->nNumberOfStereoCenters > 0 && pStereo->nNumber && pStereo->t_parity)
# # # # ]
6331 : : {
6332 : 0 : num_not_empty++;
6333 : : }
6334 : : }
6335 : : }
6336 : 0 : return num_not_empty;
6337 : : }
6338 : :
6339 : :
6340 : : /****************************************************************************
6341 : : Parse "/i/m" InChI layer
6342 : : ****************************************************************************/
6343 : 1 : int ParseSegmentSp3m(const char* str,
6344 : : int bMobileH,
6345 : : INChI* pInpInChI[],
6346 : : int ppnNumComponents[],
6347 : : int state)
6348 : : {
6349 : : /* Pass 1: count bonds and find actual numbers of atom */
6350 : : int nNumComponents, iComponent;
6351 : : const char* p, * pStart, * pEnd;
6352 : 1 : int ret = 0;
6353 : 1 : INChI* pInChI = pInpInChI[bMobileH];
6354 : 1 : INChI_Stereo** pStereo = NULL;
6355 : :
6356 [ + - - + ]: 1 : int bIso = (state == IST_MOBILE_H_ISO_SP3_M || state == IST_FIXED_H_ISO_SP3_M);
6357 : :
6358 [ + - - + : 1 : if (!bIso && state != IST_MOBILE_H_SP3_M && state != IST_FIXED_H_SP3_M)
- - ]
6359 : : {
6360 : 0 : return RI_ERR_PROGR; /* program error */
6361 : : }
6362 : 1 : nNumComponents = ppnNumComponents[bMobileH];
6363 : :
6364 [ + - ]: 1 : if (str[0] != 'm')
6365 : : {
6366 : : /* /m is missing: check whether we have to inherit /m from a preceding stereo layer */
6367 : : INChI_Stereo* pStereoFrom, * pStereoTo;
6368 : : INChI* pInChIFrom;
6369 : 1 : int bMobileHFrom = -1, bIsoFrom = -1; /* djb-rwth: removing redundant variables */
6370 [ + - + - ]: 1 : if (bMobileH && !bIso)
6371 : : {
6372 : 1 : return 0; /* Main non-isotopic cannot inherit: it has no preceding layer */
6373 : : }
6374 : : else
6375 : : {
6376 [ # # # # ]: 0 : if (!bMobileH && !bIso)
6377 : : {
6378 : : /* fixed-H non-isotopic (F) inherits from Mobile-H non-isotopic (M) */
6379 : 0 : bMobileHFrom = TAUT_YES;
6380 : 0 : bIsoFrom = 0;
6381 : : }
6382 : : else
6383 : : {
6384 [ # # # # ]: 0 : if (bMobileH && bIso)
6385 : : {
6386 : : /* Mobile-H isotopic (MI) inherits from Mobile-H non-isotopic (M) */
6387 : 0 : bMobileHFrom = TAUT_YES;
6388 : 0 : bIsoFrom = 0;
6389 : : }
6390 : : else
6391 : : {
6392 [ # # # # ]: 0 : if (!bMobileH && bIso)
6393 : : {
6394 : : /* Fixed-H isotopic (FI) inherits from Fixed-H non-isotopic (F) */
6395 : 0 : bMobileHFrom = TAUT_NON;
6396 : 0 : bIsoFrom = 0;
6397 : : /* if Sp3 is empty in F as well as in M, then inherit from MI */
6398 [ # # # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, TAUT_NON, 0, ppnNumComponents[TAUT_NON /*bMobileH*/]) /* F */ &&
6399 : 0 : !bIsSp3LayerNotEmpty(pInpInChI, TAUT_YES, 0, ppnNumComponents[TAUT_YES /*bMobileH*/]) /* M */)
6400 : : {
6401 : 0 : bMobileHFrom = TAUT_YES;
6402 : 0 : bIsoFrom = 1;
6403 : : }
6404 : : }
6405 : : }
6406 : : }
6407 : : }
6408 [ # # # # ]: 0 : if (bMobileHFrom < 0 || bIsoFrom < 0) /* djb-rwth: addressing coverity ID #499556 -- check necessary due to initialisation values */
6409 : : {
6410 : 0 : return RI_ERR_PROGR;
6411 : : }
6412 [ # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, bMobileHFrom, bIsoFrom, ppnNumComponents[/*bMobileH*/ bMobileHFrom]))
6413 : : {
6414 : : /* nothing to copy; check whether it should have inherited from a preceding layer */
6415 [ # # # # : 0 : if ((!bMobileHFrom && bIsoFrom) || (bMobileHFrom && !bIsoFrom)) /* djb-rwth: addressing LLVM warnings */
# # # # ]
6416 : : {
6417 : : /* MI or F inherit stereo from M */
6418 : 0 : bMobileHFrom = TAUT_YES;
6419 : 0 : bIsoFrom = 0;
6420 [ # # ]: 0 : if (!bIsSp3LayerNotEmpty(pInpInChI, bMobileHFrom, bIsoFrom, ppnNumComponents[bMobileHFrom /*bMobileH*/]))
6421 : : {
6422 : 0 : return 0;
6423 : : }
6424 : : }
6425 : : else
6426 : : {
6427 : 0 : return 0;
6428 : : }
6429 : : }
6430 : 0 : nNumComponents = inchi_min(ppnNumComponents[bMobileH], ppnNumComponents[bMobileHFrom]);
6431 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6432 : : {
6433 : 0 : pInChIFrom = pInpInChI[bMobileHFrom] + iComponent;
6434 : 0 : pInChI = pInpInChI[bMobileH] + iComponent;
6435 [ # # # # ]: 0 : if (pInChIFrom->nNumberOfAtoms > 0 && !pInChIFrom->bDeleted &&
6436 [ # # # # ]: 0 : pInChI->nNumberOfAtoms > 0 && !pInChI->bDeleted)
6437 : : {
6438 [ # # ]: 0 : pStereoFrom = bIsoFrom ? pInChIFrom->StereoIsotopic : pInChIFrom->Stereo;
6439 [ # # ]: 0 : pStereoTo = bIso ? pInChI->StereoIsotopic : pInChI->Stereo;
6440 [ # # # # ]: 0 : if (pStereoFrom && pStereoTo)
6441 : : {
6442 : 0 : pStereoTo->nCompInv2Abs = pStereoFrom->nCompInv2Abs;
6443 : : /* djb-rwth: removing redundant code */
6444 : : }
6445 : : }
6446 : : }
6447 : 0 : return 0; /* return value > 0 means the non-/m segment has been processed here */
6448 : : }
6449 : :
6450 : 0 : pStart = str + 1;
6451 : 0 : iComponent = 0;
6452 : :
6453 : : /*if ( !(pEnd = strchr( pStart, ';' )) )*/ /* 2007-09-25 DT */
6454 [ # # ]: 0 : if (!(strchr(pStart, '/'))) /* djb-rwth: removing redundant code */
6455 : : {
6456 : 0 : pEnd = pStart + strlen(pStart);
6457 : : }
6458 : : else
6459 : : {
6460 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6461 : 0 : goto exit_function;
6462 : : }
6463 : 0 : p = pStart;
6464 [ # # ]: 0 : if (pEnd == pStart)
6465 : : {
6466 : : /* create empty sp3 segment */
6467 : 0 : int len = 0;
6468 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6469 : : {
6470 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
6471 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
6472 [ # # ]: 0 : if (!*pStereo)
6473 : : {
6474 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6475 : : {
6476 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6477 : 0 : goto exit_function;
6478 : : }
6479 : : }
6480 : 0 : pStereo[0]->nCompInv2Abs = NO_VALUE_INT; /* deliberately empty */
6481 : : #ifdef NEVER
6482 : : if (pStereo[0]->nNumberOfStereoCenters)
6483 : : {
6484 : : ret = RI_ERR_SYNTAX; /* syntax error */
6485 : : goto exit_function;
6486 : : }
6487 : : #endif
6488 : : /* allocate empty sp3 stereo */
6489 [ # # ]: 0 : if ((!pStereo[0]->t_parity &&
6490 [ # # ]: 0 : !(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0])))) ||
6491 [ # # ]: 0 : (!pStereo[0]->nNumber &&
6492 [ # # ]: 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 */
6493 : : {
6494 : : /* cleanup */
6495 [ # # ]: 0 : if (pStereo[0]->t_parity)
6496 : : {
6497 : : INCHI_HEAPCHK
6498 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6499 : 0 : pStereo[0]->t_parity = NULL;
6500 : : }
6501 [ # # ]: 0 : if (pStereo[0]->nNumber)
6502 : : {
6503 : : INCHI_HEAPCHK
6504 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6505 : 0 : pStereo[0]->nNumber = NULL;
6506 : : }
6507 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6508 : 0 : goto exit_function;
6509 : : }
6510 : : }
6511 : 0 : ret = nNumComponents + 1;
6512 : : }
6513 : : else
6514 : : {
6515 [ # # # # ]: 0 : while (p < pEnd && iComponent < nNumComponents)
6516 : : {
6517 : : /* cycle over components */
6518 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6519 [ # # # # ]: 0 : if (*p != '.' && !*pStereo)
6520 : : {
6521 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6522 : : {
6523 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6524 : 0 : goto exit_function;
6525 : : }
6526 : : }
6527 [ # # # # ]: 0 : switch (*p)
6528 : : {
6529 : 0 : case '1':
6530 : 0 : pStereo[0]->nCompInv2Abs = -1;
6531 : 0 : break;
6532 : 0 : case '0':
6533 : 0 : pStereo[0]->nCompInv2Abs = 1;
6534 : 0 : break;
6535 : 0 : case '.':
6536 [ # # ]: 0 : if (*pStereo)
6537 : : {
6538 : 0 : pStereo[0]->nCompInv2Abs = 0;
6539 : : }
6540 : 0 : break;
6541 : 0 : default:
6542 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6543 : 0 : goto exit_function;
6544 : : }
6545 : 0 : iComponent++;
6546 : 0 : p++;
6547 : : }
6548 [ # # # # ]: 0 : if (p != pEnd || iComponent != nNumComponents)
6549 : : {
6550 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6551 : 0 : goto exit_function;
6552 : : }
6553 : 0 : ret = nNumComponents + 1;
6554 : : }
6555 : :
6556 : 0 : exit_function:
6557 : :
6558 : 0 : return ret;
6559 : : }
6560 : :
6561 : :
6562 : : /****************************************************************************
6563 : : Parse "/t" InChI layer
6564 : : ****************************************************************************/
6565 : 1 : int ParseSegmentSp3(const char* str, /* input; string of segment starting with "/t" */
6566 : : int bMobileH, /* input; bMobileH indicates what we have, fixed or tauto */
6567 : : INChI* pInpInChI[], /* output; to be allocated and filled */
6568 : : int ppnNumComponents[], /* input; ppnNumComponents[bMobileH] is number of components*/
6569 : : int state, /* input; gen parser state code */
6570 : : int* pbAbc) /* input; inicator of compresssed InChI or not */
6571 : : {
6572 : : /* Pass 1: count bonds and find actual numbers of atom */
6573 : 1 : const char mult_type[] = "mnMNe";
6574 : 1 : const char parity_type[] = "-+u?";
6575 : : const char* p, * q, * t, * pStart, * pEnd, * r;
6576 : : AT_NUMB nAtom1;
6577 : 1 : int mpy_component = 0, val;
6578 : : int nNumComponents, iComponent, len, iAtom;
6579 : : int atomParity;
6580 : 1 : int ret = 0, retf = 0;
6581 : 1 : int base = 10;
6582 : 1 : int nCpyType = CPY_SP3;
6583 [ + - - + ]: 1 : int bIso = (state == IST_MOBILE_H_ISO_SP3 || state == IST_FIXED_H_ISO_SP3);
6584 : 1 : INChI* pInChI = pInpInChI[bMobileH];
6585 : 1 : INChI_Stereo** pStereo = NULL;
6586 : 1 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
6587 : :
6588 [ + - - + : 1 : if (!bIso && state != IST_MOBILE_H_SP3 && state != IST_FIXED_H_SP3)
- - ]
6589 : : {
6590 : 0 : return RI_ERR_PROGR;
6591 : : }
6592 [ + - ]: 1 : if (str[0] != 't')
6593 : : {
6594 : 1 : return 0; /* RI_ERR_EOF - ? */
6595 : : }
6596 : :
6597 : 0 : pStart = (char*)str + 1;
6598 : 0 : iComponent = 0;
6599 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6600 : :
6601 : : /* Pass 1: create empty segment and exit */
6602 [ # # ]: 0 : if (!*pStart)
6603 : : {
6604 : 0 : ret = SegmentSp3CreateEmpty(str, bMobileH, pInpInChI, nNumComponents, state, pbAbc);
6605 : 0 : goto exit_function;
6606 : : }
6607 : :
6608 : : /* Cycle over components */
6609 : : while (1)
6610 : : {
6611 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
6612 : : {
6613 : 0 : pEnd = pStart + strlen(pStart);
6614 : : }
6615 : :
6616 : : /* djb-rwth: condition for if block had to be rewritten */
6617 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
6618 : : {
6619 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
6620 : 0 : if_cnd = isdigit(*pStart);
6621 : :
6622 : : }
6623 : : else
6624 : : {
6625 : 0 : val = 1;
6626 : 0 : q = pStart;
6627 : 0 : if_cnd = 1;
6628 : : }
6629 : :
6630 : : /* Abbreviation? */
6631 [ # # # # : 0 : if (if_cnd && (t = strchr((char*)mult_type, *q)) && q + 1 == pEnd) /* djb-rwth: if_cnd applied; ignoring LLVM warning: variable used */
# # ]
6632 : : {
6633 : : /* Process abbrebiation */
6634 : 0 : retf = SegmentSp3ProcessAbbreviation(&mpy_component, iComponent, nNumComponents,
6635 : : val, q, state, pbAbc, bMobileH, nCpyType,
6636 [ # # ]: 0 : pInChI, pInpInChI[ALT_TAUT(bMobileH)]);
6637 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6638 : : {
6639 : 0 : ret = RI_ERR_SYNTAX;
6640 : 0 : goto exit_function;
6641 : : }
6642 : 0 : goto end_main_cycle;
6643 : : }
6644 : : /* Multiplier? */
6645 [ # # # # ]: 0 : else if ((p = strchr(pStart, '*')) && p < pEnd)
6646 : : {
6647 : : /* Process regular multiplier */
6648 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
6649 [ # # ]: 0 : if (p != q)
6650 : : {
6651 : 0 : ret = RI_ERR_SYNTAX;
6652 : 0 : goto exit_function;
6653 : : }
6654 : 0 : p++; /* move to the 1st character of the component */
6655 : : }
6656 : : else
6657 : : {
6658 : : /* Just normal sequence of centers/configs, prepare to read */
6659 : 0 : mpy_component = 1;
6660 : 0 : p = pStart;
6661 : : }
6662 : : #if (FIX_DALKE_BUGS == 1)
6663 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
6664 : : {
6665 : 0 : ret = RI_ERR_SYNTAX;
6666 : 0 : goto exit_function;
6667 : : }
6668 : : #endif
6669 : :
6670 : 0 : pStart = p;
6671 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
6672 : : {
6673 : : /* check if compressed InChI */
6674 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
6675 : : }
6676 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
6677 : :
6678 : : /* Process the component: at1p,at1p,... */
6679 : :
6680 : : /* Pass 1: find number of stereoatoms len */
6681 [ # # ]: 0 : if (*pbAbc == 1)
6682 : : {
6683 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++)
6684 : : {
6685 [ # # # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
6686 : 0 : (atomParity = (int)inchi_strtol(p, &p, 10),
6687 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= atomParity && atomParity <= AB_MAX_KNOWN_PARITY))
6688 : : {
6689 : : ; /* okay */
6690 : : }
6691 : : else
6692 : : {
6693 : 0 : ret = RI_ERR_SYNTAX;
6694 : 0 : goto exit_function;
6695 : : }
6696 [ # # ]: 0 : if (nAtom1 > pInChI[iComponent].nNumberOfAtoms)
6697 : : {
6698 : 0 : ret = RI_ERR_SYNTAX;
6699 : 0 : goto exit_function;
6700 : : }
6701 : : }
6702 : : }
6703 : : else
6704 : : {
6705 [ # # ]: 0 : for (p = pStart, iAtom = 0; p < pEnd; iAtom++, p += (*p == ','))
6706 : : {
6707 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
6708 : 0 : p = q + 1;
6709 [ # # ]: 0 : if (!nAtom1 ||
6710 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
6711 [ # # ]: 0 : !(r = strchr((char*)parity_type, *q))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
6712 : : {
6713 : 0 : ret = RI_ERR_SYNTAX;
6714 : 0 : goto exit_function;
6715 : : }
6716 : : }
6717 : : }
6718 [ # # ]: 0 : if (p != pEnd)
6719 : : {
6720 : 0 : ret = RI_ERR_SYNTAX;
6721 : 0 : goto exit_function;
6722 : : }
6723 : 0 : len = iAtom;
6724 : : /* Found len, the number of stereo centers in /t segment for component iComponent */
6725 : :
6726 : : #if ( ( FIX_GAF_2019_1==1 ) || ( FIX_GAF_2019_2==1 ) )
6727 [ # # # # ]: 0 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
6728 : : {
6729 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6730 : 0 : goto exit_function;
6731 : : }
6732 [ # # # # ]: 0 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
6733 : : {
6734 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6735 : 0 : goto exit_function;
6736 : : }
6737 : : #endif
6738 : :
6739 : : /* Allocate memory for pStereo */
6740 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
6741 [ # # ]: 0 : if (!*pStereo)
6742 : : {
6743 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
6744 : : {
6745 : 0 : ret = RI_ERR_ALLOC;
6746 : 0 : goto exit_function;
6747 : : }
6748 : : }
6749 [ # # # # ]: 0 : if (pStereo[0]->t_parity || pStereo[0]->nNumberOfStereoCenters ||
6750 [ # # ]: 0 : pStereo[0]->nNumber)
6751 : : {
6752 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6753 : 0 : goto exit_function;
6754 : : }
6755 : : /* Allocate sp3 stereo */
6756 [ # # ]: 0 : if (!(pStereo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0]))) ||
6757 [ # # ]: 0 : !(pStereo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nNumber[0])))) /* djb-rwth: cast operators added */
6758 : : {
6759 : : /* cleanup */
6760 [ # # ]: 0 : if (pStereo[0]->t_parity)
6761 : : {
6762 : : INCHI_HEAPCHK
6763 [ # # ]: 0 : inchi_free(pStereo[0]->t_parity);
6764 : 0 : pStereo[0]->t_parity = NULL;
6765 : : }
6766 [ # # ]: 0 : if (pStereo[0]->nNumber)
6767 : : {
6768 : : INCHI_HEAPCHK
6769 [ # # ]: 0 : inchi_free(pStereo[0]->nNumber);
6770 : 0 : pStereo[0]->nNumber = NULL;
6771 : : }
6772 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
6773 : 0 : goto exit_function;
6774 : : }
6775 : :
6776 : :
6777 : : /* Store stereocenters (pass 2) */
6778 : 0 : retf = SegmentSp3StoreStereoCenters(pbAbc, pStart, pEnd, pInChI[iComponent].nNumberOfAtoms, pStereo[0]);
6779 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6780 : : {
6781 : 0 : ret = RI_ERR_SYNTAX;
6782 : 0 : goto exit_function;
6783 : : }
6784 : :
6785 : : /* Treat multiplier-covered components */
6786 : 0 : retf = SegmentSp3CopyMultiplierCovered(mpy_component, iComponent, pInChI, bIso, nCpyType);
6787 [ # # ]: 0 : if (retf == RI_ERR_SYNTAX)
6788 : : {
6789 : 0 : ret = RI_ERR_SYNTAX;
6790 : 0 : goto exit_function;
6791 : : }
6792 : :
6793 : 0 : end_main_cycle:
6794 : 0 : iComponent += mpy_component;
6795 [ # # ]: 0 : if (*pEnd)
6796 : : {
6797 : 0 : pStart = pEnd + 1;
6798 : 0 : continue;
6799 : : }
6800 : : else
6801 : : {
6802 : 0 : break;
6803 : : }
6804 : :
6805 : : } /* Cycle over components */
6806 : :
6807 [ # # ]: 0 : if (nNumComponents != iComponent)
6808 : : {
6809 : : /* Not all components treated, that's an error */
6810 : 0 : ret = RI_ERR_SYNTAX;
6811 : 0 : goto exit_function;
6812 : : }
6813 : : /* At this moment, INChI_Stereo pInChI[k].Stereo provides stereocenter parity info for k-th component
6814 : : pInChI[k].Stereo.
6815 : : nNumber[nNumberOfStereoCenters] cano numbers
6816 : : t_parity[nNumberOfStereoCenters] tetrahedral atom parities
6817 : : */
6818 : :
6819 : :
6820 : 0 : ret = iComponent + 1;
6821 : :
6822 : 0 : exit_function:
6823 : :
6824 : 0 : return ret;
6825 : : }
6826 : :
6827 : :
6828 : : /****************************************************************************
6829 : : Parse "/b" InChI layer
6830 : : ****************************************************************************/
6831 : 1 : int ParseSegmentSp2(const char* str,
6832 : : int bMobileH,
6833 : : INChI* pInpInChI[],
6834 : : int ppnNumComponents[],
6835 : : int state,
6836 : : int* pbAbc)
6837 : : {
6838 : : /* Pass 1: count bonds and find actual numbers of atom */
6839 : : int i, mpy_component, val, len_limit;
6840 : : int nNumComponents, iComponent, len, iBond;
6841 : : AT_NUMB nAtom1, nAtom2;
6842 : : int bondParity;
6843 : : const char* p, * q, * t, * pStart, * pEnd, * r;
6844 : 1 : int ret = 0;
6845 : 1 : INChI* pInChI = pInpInChI[bMobileH];
6846 : 1 : INChI* pInChIFrom = NULL;
6847 : : /*
6848 : : INChI_Stereo *Stereo = NULL;
6849 : : INChI_Stereo *StereoOther = NULL;
6850 : : */
6851 : 1 : INChI_Stereo** pStereo = NULL;
6852 : :
6853 : 1 : const char mult_type[] = "mnMNe";
6854 : 1 : const char parity_type[] = "-+u?";
6855 : 1 : int bIsoTo, bIsoFrom, nCpyType = CPY_SP2;
6856 [ + - - + ]: 1 : int bIso = (state == IST_MOBILE_H_ISO_SP2 || state == IST_FIXED_H_ISO_SP2);
6857 : 1 : int base = 10;
6858 : 1 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
6859 : :
6860 [ + - - + : 1 : if (!bIso && state != IST_MOBILE_H_SP2 && state != IST_FIXED_H_SP2)
- - ]
6861 : : {
6862 : 0 : return RI_ERR_PROGR; /* program error */
6863 : : }
6864 : :
6865 [ + - ]: 1 : if (str[0] != 'b')
6866 : : {
6867 : 1 : return 0;
6868 : : }
6869 : :
6870 : 0 : pStart = (char*)str + 1;
6871 : 0 : iComponent = 0;
6872 : 0 : nNumComponents = ppnNumComponents[bMobileH];
6873 : :
6874 [ # # ]: 0 : if (!*pStart)
6875 : : {
6876 : : /* create empty sp2 segment which means no sp2 */
6877 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
6878 : : {
6879 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
6880 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
6881 [ # # # # : 0 : if (*pStereo && (pStereo[0]->b_parity || pStereo[0]->nNumberOfStereoBonds ||
# # ]
6882 [ # # # # ]: 0 : pStereo[0]->nBondAtom1 || pStereo[0]->nBondAtom2))
6883 : : {
6884 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6885 : 0 : goto exit_function;
6886 : : }
6887 : : /* allocate empty sp2 stereo */
6888 : 0 : ret = CopySegment(pIsoInChI, NULL, CPY_SP2, bIso, -1);
6889 [ # # ]: 0 : if (ret < 0)
6890 : : {
6891 : 0 : goto exit_function;
6892 : : }
6893 : : }
6894 : 0 : ret = nNumComponents + 1;
6895 : 0 : goto exit_function;
6896 : : }
6897 : :
6898 : : while (1)
6899 : : {
6900 : : /* Cycle over components */
6901 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
6902 : : {
6903 : 0 : pEnd = pStart + strlen(pStart);
6904 : : }
6905 : :
6906 : : /* djb-rwth: condition for if block had to be rewritten -- GH issue #09, thanks to Istvan Ori */
6907 [ # # ]: 0 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
6908 : : {
6909 : 0 : val = (int)inchi_strtol(pStart, &q, 10);
6910 : 0 : if_cnd = isdigit(*pStart);
6911 : :
6912 : : }
6913 : : else
6914 : : {
6915 : 0 : val = 1;
6916 : 0 : q = pStart;
6917 : 0 : if_cnd = 1;
6918 : : }
6919 : :
6920 : :
6921 [ # # # # : 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 */
# # ]
6922 : : {
6923 : : /* process the abbreviation */
6924 : 0 : ret = 0;
6925 : : #if (FIX_DALKE_BUGS == 1)
6926 : : /* djb-rwth: fixing GH issue #59.2 */
6927 : : if ((iComponent + val >= INT_MIN) && (iComponent + val <= INT_MAX))
6928 : : {
6929 [ # # ]: 0 : if ((iComponent + val > nNumComponents))
6930 : : {
6931 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6932 : 0 : goto exit_function;
6933 : : }
6934 : : }
6935 : : else
6936 : : {
6937 : : ret = BNS_PROGRAM_ERR;
6938 : : goto exit_function;
6939 : : }
6940 : : #endif
6941 [ # # # ]: 0 : switch (bMobileH)
6942 : : {
6943 : 0 : case TAUT_YES:
6944 [ # # ]: 0 : switch (state)
6945 : : {
6946 : 0 : case IST_MOBILE_H_ISO_SP2:
6947 [ # # ]: 0 : if (*q == 'm')
6948 : : {
6949 : : /* copy from mobile H to isotopic mobile H */
6950 : 0 : pInChIFrom = pInChI;
6951 : 0 : bIsoTo = 1;
6952 : 0 : bIsoFrom = 0;
6953 : : }
6954 : : else
6955 : : {
6956 [ # # ]: 0 : if (*q == 'e')
6957 : : {
6958 : : /* copy from mobile H to isotopic mobile H */
6959 : 0 : pInChIFrom = pInChI;
6960 : 0 : bIsoTo = 1;
6961 : 0 : bIsoFrom = -1; /* empty */
6962 : : }
6963 : : else
6964 : : {
6965 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6966 : : }
6967 : : }
6968 : 0 : break;
6969 : 0 : default:
6970 : 0 : ret = RI_ERR_SYNTAX;
6971 : 0 : break;
6972 : : }
6973 : 0 : break;
6974 : 0 : case TAUT_NON:
6975 [ # # # ]: 0 : switch (state)
6976 : : {
6977 : 0 : case IST_FIXED_H_SP2:
6978 [ # # ]: 0 : if (*q == 'm')
6979 : : {
6980 : : /* copy from mobile H to fixed H */
6981 : : #if ( FIX_GAF_2019_2==1 )
6982 [ # # ]: 0 : int inum = ALT_TAUT(bMobileH);
6983 : 0 : pInChIFrom = pInpInChI[inum];
6984 : : #else
6985 : : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
6986 : : #endif
6987 : 0 : bIsoTo = 0;
6988 : 0 : bIsoFrom = 0;
6989 : : }
6990 : : else
6991 : : {
6992 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
6993 : : }
6994 : 0 : break;
6995 : 0 : case IST_FIXED_H_ISO_SP2:
6996 [ # # ]: 0 : if (*q == 'm')
6997 : : {
6998 : : /* copy from mobile H to fixed isotopic H */
6999 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
7000 : 0 : bIsoTo = 1;
7001 : 0 : bIsoFrom = 0;
7002 : : }
7003 : : else
7004 : : {
7005 [ # # ]: 0 : if (*q == 'M')
7006 : : {
7007 : : /* copy from isotopic mobile H to fixed isotopic H */
7008 [ # # ]: 0 : pInChIFrom = pInpInChI[ALT_TAUT(bMobileH)];
7009 : 0 : bIsoTo = 1;
7010 : 0 : bIsoFrom = 1;
7011 : : }
7012 : : else
7013 : : {
7014 [ # # ]: 0 : if (*q == 'n')
7015 : : {
7016 : : /* copy from fixed H to fixed isotopic H */
7017 : 0 : pInChIFrom = pInChI;
7018 : 0 : bIsoTo = 1;
7019 : 0 : bIsoFrom = 0;
7020 : : }
7021 : : else
7022 : : {
7023 [ # # ]: 0 : if (*q == 'e')
7024 : : {
7025 : : /* copy from mobile H to isotopic mobile H */
7026 : 0 : pInChIFrom = pInChI;
7027 : 0 : bIsoTo = 1;
7028 : 0 : bIsoFrom = -1; /* empty */
7029 : : }
7030 : : else
7031 : : {
7032 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7033 : : }
7034 : : }
7035 : : }
7036 : : }
7037 : 0 : break;
7038 : 0 : default:
7039 : 0 : ret = RI_ERR_SYNTAX;
7040 : 0 : break;
7041 : : }
7042 : 0 : break;
7043 : :
7044 : 0 : default:
7045 : 0 : ret = RI_ERR_SYNTAX;
7046 : 0 : break;
7047 : : }
7048 [ # # ]: 0 : if (ret < 0)
7049 : : {
7050 : 0 : goto exit_function;
7051 : : }
7052 : : /* copy */
7053 [ # # ]: 0 : for (i = 0; i < val; i++)
7054 : : {
7055 : : #if ( FIX_GAF_2019_2==1 )
7056 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
7057 : : {
7058 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7059 : 0 : goto exit_function;
7060 : : }
7061 [ # # # # ]: 0 : if (NULL == pInChIFrom || NULL == pInChIFrom + iComponent + i) /* djb-rwth: ignoring GCC warning */
7062 : : {
7063 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7064 : 0 : goto exit_function;
7065 : : }
7066 : :
7067 [ # # # # ]: 0 : if ((pInChIFrom[iComponent + i].nNumberOfAtoms <= 0) || (pInChIFrom[iComponent + i].nNumberOfAtoms > MAX_ATOMS))
7068 : : {
7069 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7070 : 0 : goto exit_function;
7071 : : }
7072 : : #endif
7073 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, bIsoTo, bIsoFrom);
7074 [ # # ]: 0 : if (!ret)
7075 : : {
7076 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7077 : : }
7078 [ # # ]: 0 : if (ret < 0)
7079 : : {
7080 : 0 : goto exit_function;
7081 : : }
7082 : : }
7083 : 0 : mpy_component = val;
7084 : 0 : goto end_main_cycle;
7085 : : }
7086 : : else
7087 : : /* regular multiplier */
7088 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
7089 : : {
7090 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
7091 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7092 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
7093 : : {
7094 : 0 : ret = RI_ERR_SYNTAX;
7095 : 0 : goto exit_function;
7096 : : }
7097 : : #endif
7098 [ # # ]: 0 : if (p != q)
7099 : : {
7100 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7101 : 0 : goto exit_function;
7102 : : }
7103 : :
7104 : 0 : p++; /* move to the 1st character of the component */
7105 : : }
7106 : : else
7107 : : {
7108 : 0 : mpy_component = 1;
7109 : 0 : p = pStart;
7110 : : }
7111 : : #if (FIX_DALKE_BUGS == 1)
7112 [ # # ]: 0 : if (iComponent + mpy_component > nNumComponents)
7113 : : {
7114 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7115 : 0 : goto exit_function;
7116 : : }
7117 : : #endif
7118 : 0 : pStart = p;
7119 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
7120 : : {
7121 : : /* check if compressed InChI */
7122 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
7123 : : }
7124 [ # # ]: 0 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
7125 [ # # ]: 0 : if (*pbAbc == 1)
7126 : : {
7127 : : /* process the componnt: at1-at2p,at1-at2p,... */
7128 : : /* pass 1: find number of stereobonds */
7129 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++)
7130 : : {
7131 : : /* atoms 1, 2, and parity */
7132 [ # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7133 [ # # # # ]: 0 : (nAtom2 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7134 : 0 : (bondParity = (int)inchi_strtol(p, &p, 10),
7135 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= bondParity && bondParity <= AB_MAX_KNOWN_PARITY))
7136 : : {
7137 : : ; /* okay */
7138 : : }
7139 : : else
7140 : : {
7141 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7142 : 0 : goto exit_function;
7143 : : }
7144 [ # # ]: 0 : if (nAtom1 <= nAtom2 ||
7145 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms)
7146 : : {
7147 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7148 : 0 : goto exit_function;
7149 : : }
7150 : : }
7151 : : }
7152 : : else
7153 : : {
7154 : : /* process the componnt: at1-at2p,at1-at2p,... */
7155 : : /* pass 1: find number of stereobonds */
7156 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++, p += (*p == ','))
7157 : : {
7158 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
7159 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7160 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
7161 : : {
7162 : 0 : ret = RI_ERR_SYNTAX;
7163 : 0 : goto exit_function;
7164 : : }
7165 : : #endif
7166 [ # # ]: 0 : if (*q != '-')
7167 : : {
7168 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7169 : 0 : goto exit_function;
7170 : : }
7171 : 0 : p = q + 1;
7172 : 0 : nAtom2 = (AT_NUMB)inchi_strtol(p, &q, 10);
7173 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7174 [ # # ]: 0 : if (nAtom2 > MAX_ATOMS || nAtom2 < 0)
7175 : : {
7176 : 0 : ret = RI_ERR_SYNTAX;
7177 : 0 : goto exit_function;
7178 : : }
7179 : : #endif
7180 [ # # # # : 0 : if (!nAtom1 || !nAtom2 ||
# # ]
7181 : 0 : nAtom1 <= nAtom2 ||
7182 [ # # ]: 0 : nAtom1 > pInChI[iComponent].nNumberOfAtoms ||
7183 [ # # ]: 0 : !(r = strchr((char*)parity_type, *q))) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7184 : : {
7185 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7186 : 0 : goto exit_function;
7187 : : }
7188 : 0 : p = q + 1;
7189 : : }
7190 : : }
7191 : :
7192 [ # # ]: 0 : if (p != pEnd)
7193 : : {
7194 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7195 : 0 : goto exit_function;
7196 : : }
7197 : 0 : len = iBond;
7198 : :
7199 : : #if ( FIX_GAF_2019_2==1 )
7200 [ # # # # ]: 0 : if ((iComponent > nNumComponents - 1) || (iComponent < 0))
7201 : : {
7202 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7203 : 0 : goto exit_function;
7204 : : }
7205 [ # # # # ]: 0 : if (pInChI[iComponent].nNumberOfAtoms <= 0 || pInChI[iComponent].nNumberOfAtoms > MAX_ATOMS)
7206 : : {
7207 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7208 : 0 : goto exit_function;
7209 : : }
7210 : : #endif
7211 : :
7212 : : /* memory allocation */
7213 [ # # ]: 0 : pStereo = bIso ? &pInChI[iComponent].StereoIsotopic : &pInChI[iComponent].Stereo;
7214 [ # # ]: 0 : if (!*pStereo)
7215 : : {
7216 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
7217 : : {
7218 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
7219 : 0 : goto exit_function;
7220 : : }
7221 : : }
7222 [ # # # # ]: 0 : if (pStereo[0]->b_parity || pStereo[0]->nNumberOfStereoBonds ||
7223 [ # # # # ]: 0 : pStereo[0]->nBondAtom1 || pStereo[0]->nBondAtom2)
7224 : : {
7225 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: bonds have already been allocated */
7226 : 0 : goto exit_function;
7227 : : }
7228 : : /* allocate sp2 stereo */
7229 : 0 : len_limit = len + 1;
7230 [ # # ]: 0 : if (!(pStereo[0]->b_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->b_parity[0]))) ||
7231 [ # # ]: 0 : !(pStereo[0]->nBondAtom1 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nBondAtom1[0]))) ||
7232 [ # # ]: 0 : !(pStereo[0]->nBondAtom2 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pStereo[0]->nBondAtom2[0])))) /* djb-rwth: cast operators added */
7233 : : {
7234 : : /* cleanup */
7235 [ # # ]: 0 : if (pStereo[0]->b_parity)
7236 : : {
7237 : : INCHI_HEAPCHK
7238 [ # # ]: 0 : inchi_free(pStereo[0]->b_parity);
7239 : 0 : pStereo[0]->b_parity = NULL;
7240 : : }
7241 [ # # ]: 0 : if (pStereo[0]->nBondAtom1)
7242 : : {
7243 : : INCHI_HEAPCHK
7244 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom1);
7245 : 0 : pStereo[0]->nBondAtom1 = NULL;
7246 : : }
7247 [ # # ]: 0 : if (pStereo[0]->nBondAtom2)
7248 : : {
7249 : : INCHI_HEAPCHK
7250 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom2);
7251 : 0 : pStereo[0]->nBondAtom2 = NULL;
7252 : : }
7253 : : INCHI_HEAPCHK
7254 : 0 : ret = RI_ERR_ALLOC; /* memory allocation failed */
7255 : 0 : goto exit_function;
7256 : : }
7257 : :
7258 : : /* pass 2: store stereobonds */
7259 [ # # ]: 0 : if (*pbAbc == 1)
7260 : : {
7261 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++)
7262 : : {
7263 [ # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7264 [ # # # # ]: 0 : (nAtom2 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
7265 : 0 : (bondParity = (int)inchi_strtol(p, &p, 10),
7266 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= bondParity && bondParity <= AB_MAX_KNOWN_PARITY))
7267 : : {
7268 : : ; /* okay */
7269 : : }
7270 : : else
7271 : : {
7272 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7273 : 0 : goto exit_function;
7274 : : }
7275 : 0 : pStereo[0]->b_parity[iBond] = bondParity;
7276 : 0 : pStereo[0]->nBondAtom1[iBond] = nAtom1;
7277 : 0 : pStereo[0]->nBondAtom2[iBond] = nAtom2;
7278 : :
7279 [ # # ]: 0 : if (iBond &&
7280 [ # # ]: 0 : !(pStereo[0]->nBondAtom1[iBond - 1] < nAtom1 ||
7281 [ # # ]: 0 : (pStereo[0]->nBondAtom1[iBond - 1] == nAtom1 &&
7282 [ # # ]: 0 : pStereo[0]->nBondAtom2[iBond - 1] < nAtom2))) /* djb-rwth: addressing LLVM warning */
7283 : : {
7284 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: wrong bond order */
7285 : 0 : goto exit_function;
7286 : : }
7287 : : }
7288 : : }
7289 : : else
7290 : : {
7291 [ # # ]: 0 : for (p = pStart, iBond = 0; p < pEnd; iBond++, p += (*p == ','))
7292 : : {
7293 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
7294 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7295 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
7296 : : {
7297 : 0 : ret = RI_ERR_SYNTAX;
7298 : 0 : goto exit_function;
7299 : : }
7300 : : #endif
7301 [ # # ]: 0 : if (*q != '-')
7302 : : {
7303 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7304 : 0 : goto exit_function;
7305 : : }
7306 : 0 : p = q + 1;
7307 : 0 : nAtom2 = (AT_NUMB)inchi_strtol(p, &q, 10);
7308 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7309 [ # # ]: 0 : if (nAtom2 > MAX_ATOMS || nAtom2 < 0)
7310 : : {
7311 : 0 : ret = RI_ERR_SYNTAX;
7312 : 0 : goto exit_function;
7313 : : }
7314 : : #endif
7315 [ # # ]: 0 : if (!(r = strchr((char*)parity_type, *q)))
7316 : : {
7317 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7318 : 0 : goto exit_function;
7319 : : }
7320 : 0 : p = q + 1;
7321 : 0 : bondParity = (int)(r - parity_type) + 1;
7322 : : /* djb-rwth: preventing buffer overrun */
7323 [ # # ]: 0 : if (iBond < len_limit)
7324 : : {
7325 : 0 : pStereo[0]->b_parity[iBond] = bondParity;
7326 : 0 : pStereo[0]->nBondAtom1[iBond] = nAtom1;
7327 : 0 : pStereo[0]->nBondAtom2[iBond] = nAtom2;
7328 : : }
7329 : : else
7330 : : {
7331 : 0 : ret = RI_ERR_PROGR;
7332 : 0 : goto exit_function;
7333 : : }
7334 : :
7335 [ # # ]: 0 : if (iBond &&
7336 [ # # ]: 0 : !(pStereo[0]->nBondAtom1[iBond - 1] < nAtom1 ||
7337 [ # # ]: 0 : (pStereo[0]->nBondAtom1[iBond - 1] == nAtom1 &&
7338 [ # # ]: 0 : pStereo[0]->nBondAtom2[iBond - 1] < nAtom2))) /* djb-rwth: addressing LLVM warning */
7339 : : {
7340 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: wrong bond order */
7341 : 0 : goto exit_function;
7342 : : }
7343 : : }
7344 : : }
7345 : 0 : pStereo[0]->nNumberOfStereoBonds = iBond;
7346 : :
7347 [ # # ]: 0 : if (p != pEnd)
7348 : : {
7349 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7350 : 0 : goto exit_function;
7351 : : }
7352 : :
7353 : : /* multiplier */
7354 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
7355 : : {
7356 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, bIso, bIso);
7357 [ # # ]: 0 : if (ret < 0)
7358 : : {
7359 : 0 : goto exit_function;
7360 : : }
7361 : : }
7362 : :
7363 : 0 : end_main_cycle:
7364 : 0 : iComponent += mpy_component;
7365 [ # # ]: 0 : if (*pEnd)
7366 : : {
7367 : 0 : pStart = pEnd + 1;
7368 : 0 : continue;
7369 : : }
7370 : : else
7371 : : {
7372 : 0 : break;
7373 : : }
7374 : : }
7375 [ # # ]: 0 : if (nNumComponents != iComponent)
7376 : : {
7377 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7378 : 0 : goto exit_function;
7379 : : }
7380 : 0 : ret = iComponent + 1;
7381 : :
7382 : 0 : exit_function:
7383 : :
7384 : 0 : return ret;
7385 : : }
7386 : :
7387 : :
7388 : : /****************************************************************************
7389 : : Parse "/p" InChI layer
7390 : : ****************************************************************************/
7391 : 1 : int ParseSegmentProtons(const char* str,
7392 : : int bMobileH,
7393 : : REM_PROTONS nNumProtons[],
7394 : : int ppnNumComponents[])
7395 : : {
7396 : : /* Pass 1: count bonds and find actual numbers of atom */
7397 : : int val;
7398 : : const char* q, * pStart, * pEnd;
7399 : : int ret;
7400 : :
7401 [ + - ]: 1 : if (str[0] != 'p')
7402 : : {
7403 : 1 : return 0;
7404 : : }
7405 : :
7406 : 0 : pStart = (char*)str + 1;
7407 : :
7408 : : while (1)
7409 : : {
7410 : : /* cycle over components */
7411 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
7412 : : {
7413 : 0 : pEnd = pStart + strlen(pStart);
7414 : : }
7415 : :
7416 [ # # # # ]: 0 : if (pStart[0] == '+' && isdigit(UCINT pStart[1]))
7417 : : {
7418 : 0 : val = (int)inchi_strtol(pStart + 1, &q, 10);
7419 : : }
7420 : : else
7421 : : {
7422 [ # # # # ]: 0 : if (pStart[0] == '-' && isdigit(UCINT pStart[1]))
7423 : : {
7424 : 0 : val = -(int)inchi_strtol(pStart + 1, &q, 10);
7425 : : }
7426 : : else
7427 : : {
7428 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7429 : 0 : goto exit_function;
7430 : : }
7431 : : }
7432 [ # # ]: 0 : if (!val)
7433 : : {
7434 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7435 : 0 : goto exit_function;
7436 : : }
7437 : 0 : nNumProtons[bMobileH].nNumRemovedProtons = val;
7438 [ # # # # ]: 0 : if (*pEnd || q != pEnd)
7439 : : {
7440 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
7441 : 0 : goto exit_function;
7442 : : }
7443 : : else
7444 : : {
7445 : : break;
7446 : : }
7447 : : }
7448 : 0 : ret = 1;
7449 : :
7450 : 0 : exit_function:
7451 : :
7452 : 0 : return ret;
7453 : : }
7454 : :
7455 : :
7456 : : /****************************************************************************
7457 : : Parse "/z" InChI layer
7458 : : ****************************************************************************/
7459 : 1 : int ParseSegmentPolymer(const char* str,
7460 : : int bMobileH,
7461 : : REM_PROTONS nNumProtons[],
7462 : : int ppnNumComponents[],
7463 : : int na_total,
7464 : : int nb_total,
7465 : : int bInchi2Struct,
7466 : : OAD_Polymer** ppPolymer,
7467 : : OAD_V3000** ppV3000)
7468 : : {
7469 : : const char* p, * q, * pStart, * pEnd, * p0;
7470 : 1 : char comma = ',', dot = '.', dash = '-', lt_par = '(', rt_par = ')';
7471 : : int iunit, val, ret, prev, is_range, pdn_limit;
7472 : 1 : int curr_atom, type = -1, subtype = -1, conn = -1;
7473 : : AT_NUMB num_atom;
7474 : : INT_ARRAY alist;
7475 : 1 : OAD_Polymer* pd = NULL;
7476 : :
7477 [ + - ]: 1 : if (str[0] != 'z')
7478 : : {
7479 : 1 : return 0;
7480 : : }
7481 : :
7482 [ # # ]: 0 : if (IntArray_Alloc(&alist, 4))
7483 : : {
7484 : 0 : return RI_ERR_ALLOC;
7485 : : }
7486 : :
7487 [ # # ]: 0 : if (*ppPolymer)
7488 : : {
7489 : 0 : OAD_Polymer_Free(*ppPolymer);
7490 : : }
7491 : :
7492 : 0 : pd = *ppPolymer = (OAD_Polymer*)
7493 : 0 : inchi_calloc(1, sizeof(OAD_Polymer));
7494 : 0 : (*ppPolymer)->pzz = NULL;
7495 : :
7496 [ # # ]: 0 : if (!pd)
7497 : : {
7498 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7499 : : }
7500 : :
7501 : :
7502 [ # # ]: 0 : if (!bInchi2Struct)
7503 : : {
7504 : 0 : ret = RI_ERR_SYNTAX; goto exit_function;
7505 : : }
7506 : :
7507 : : /* Count units */
7508 : 0 : pd->n = 1;
7509 : 0 : p = (char*)str + 1;
7510 [ # # ]: 0 : while ((p = strchr(p, ';'))) /* djb-rwth: addressing LLVM warning */
7511 : : {
7512 : 0 : p++;
7513 : 0 : pd->n++;
7514 : : }
7515 : 0 : pd->units = (OAD_PolymerUnit**)
7516 : 0 : inchi_calloc(pd->n, sizeof(OAD_PolymerUnit*));
7517 : 0 : pdn_limit = pd->n;
7518 [ # # ]: 0 : if (!pd->units)
7519 : : {
7520 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7521 : : }
7522 : :
7523 : 0 : pStart = (char*)str;
7524 : 0 : pStart++;
7525 [ # # ]: 0 : if (!pStart)
7526 : : {
7527 : 0 : ret = RI_ERR_PROGR;
7528 : 0 : goto exit_function;
7529 : : }
7530 : :
7531 : 0 : iunit = 0;
7532 : : /* djb-rwth: fixing oss-fuzz issue #67678 */
7533 [ # # # # ]: 0 : while (pStart && (*pStart))
7534 : : {
7535 : 0 : OAD_PolymerUnit* unit = NULL;
7536 : :
7537 [ # # ]: 0 : if (*pStart == ';')
7538 : : {
7539 : 0 : pStart++;
7540 : : }
7541 : :
7542 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
7543 : : {
7544 : 0 : pEnd = pStart + strlen(pStart);
7545 : : }
7546 [ # # ]: 0 : if (!isdigit(UCINT pStart[0]))
7547 : : {
7548 : 0 : ret = RI_ERR_SYNTAX;
7549 : 0 : goto exit_function;
7550 : : }
7551 : 0 : val = (int)inchi_strtol(pStart + 0, &q, 10);
7552 : 0 : type = val / 100;
7553 : 0 : subtype = (val - (type * 100)) / 10;
7554 : 0 : conn = (val - (type * 100 + subtype * 10));
7555 [ # # ]: 0 : if (*q != '-')
7556 : : {
7557 : 0 : ret = RI_ERR_SYNTAX;
7558 : 0 : goto exit_function;
7559 : : }
7560 : : #if ( FIX_OSS_FUZZ_30162_30343==1 )
7561 [ # # ]: 0 : if (val < 100) /* type should always be non-zero followed by subtype and conn, like 101 or 200 */
7562 : : {
7563 : 0 : ret = RI_ERR_SYNTAX;
7564 : 0 : goto exit_function;
7565 : : }
7566 : : #endif
7567 : :
7568 : : #if ( FIX_GAF_2020_25741==1 )
7569 : : {
7570 : 0 : int valid_unit = 0;
7571 [ # # # # : 0 : if (type == POLYMER_STY_NON || type == POLYMER_STY_SRU || type == POLYMER_STY_MON ||
# # # # ]
7572 [ # # # # : 0 : type == POLYMER_STY_COP || type == POLYMER_STY_MOD || type == POLYMER_STY_CRO ||
# # ]
7573 : : type == POLYMER_STY_MER)
7574 : : {
7575 [ # # # # : 0 : if (subtype == POLYMER_SST_NON || subtype == POLYMER_SST_ALT ||
# # ]
7576 [ # # ]: 0 : subtype == POLYMER_SST_RAN || subtype == POLYMER_SST_BLK)
7577 : : {
7578 [ # # # # : 0 : if (conn == POLYMER_CONN_NON || conn == POLYMER_CONN_HT ||
# # ]
7579 [ # # ]: 0 : conn == POLYMER_CONN_HH || conn == POLYMER_CONN_EU)
7580 : : {
7581 : 0 : valid_unit = 1;
7582 : : }
7583 : : }
7584 : : }
7585 [ # # ]: 0 : if (!valid_unit)
7586 : : {
7587 : 0 : ret = RI_ERR_SYNTAX;
7588 : 0 : goto exit_function;
7589 : : }
7590 : : }
7591 : : #endif
7592 : :
7593 : 0 : q++;
7594 : 0 : prev = 0;
7595 : 0 : is_range = 0;
7596 [ # # # # ]: 0 : for (p = q, curr_atom = 0; p < pEnd && *p != '('; curr_atom++)
7597 : : {
7598 : 0 : num_atom = (AT_NUMB)inchi_strtol(p, &p, 10);
7599 : : #if ( ( CHECK_STRTOL_ATNUMB==1 ) || ( FIX_GAF_2019_2==1 ) )
7600 [ # # ]: 0 : if (num_atom > na_total || num_atom < 0)
7601 : : {
7602 : 0 : ret = RI_ERR_SYNTAX;
7603 : 0 : goto exit_function;
7604 : : }
7605 : : #endif
7606 [ # # # # ]: 0 : if (!num_atom || num_atom > na_total)
7607 : : {
7608 : 0 : ret = RI_ERR_SYNTAX; goto exit_function;
7609 : : }
7610 [ # # ]: 0 : if (is_range)
7611 : : {
7612 : : int a;
7613 [ # # ]: 0 : for (a = prev + 1; a <= num_atom; a++)
7614 : : {
7615 [ # # ]: 0 : if (0 != IntArray_Append(&alist, a))
7616 : : {
7617 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7618 : : }
7619 : : }
7620 : 0 : is_range = 0;
7621 : 0 : prev = 0;
7622 : : }
7623 : : else
7624 : : {
7625 [ # # ]: 0 : if (0 != IntArray_Append(&alist, num_atom))
7626 : : {
7627 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7628 : : }
7629 : 0 : prev = num_atom;
7630 : : }
7631 [ # # ]: 0 : if (*p == '-')
7632 : : {
7633 : 0 : p++;
7634 : 0 : is_range = 1;
7635 : : }
7636 [ # # ]: 0 : else if (*p == ',')
7637 : : {
7638 : 0 : p++;
7639 : : }
7640 : : }
7641 : :
7642 [ # # ]: 0 : if (alist.used)
7643 : : {
7644 : 0 : unit = OAD_PolymerUnit_New(4, /* maxatoms */
7645 : : 0, /* maxbonds=0 for now */
7646 : : iunit + 1, /* id */
7647 : : iunit + 1, /* label */
7648 : : type,
7649 : : subtype,
7650 : : conn,
7651 : : "", /* smt */
7652 : : alist.used,
7653 : : &alist,
7654 : : 0, /* blist.used */
7655 : : NULL, /* &blist */
7656 : : 0, /* nlinks */
7657 : : NULL /* **links */
7658 : : );
7659 : :
7660 [ # # ]: 0 : if (!unit)
7661 : : {
7662 : 0 : ret = RI_ERR_ALLOC; goto exit_function;
7663 : : }
7664 : : /* djb-rwth: preventing buffer overrun */
7665 [ # # ]: 0 : if (iunit < pdn_limit)
7666 : : {
7667 : 0 : pd->units[iunit] = unit;
7668 : : }
7669 : : else
7670 : : {
7671 : 0 : ret = RI_ERR_PROGR;
7672 : 0 : goto exit_function;
7673 : : }
7674 : 0 : IntArray_Reset(&alist);
7675 : 0 : iunit++;
7676 : : }
7677 : :
7678 [ # # ]: 0 : if (*p == lt_par)
7679 : 0 : {
7680 : : /* Structure-based representn, read crossing bonds information */
7681 : 0 : const int nothing = 0, endgroups = 1, stars = 2, stars_ring = 3, stars_bond = 4, stars_atom = 5;
7682 : 0 : int have = nothing;
7683 : 0 : int res, ib, err = 0; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7684 : : INT_ARRAY numlist;
7685 : :
7686 [ # # ]: 0 : if (IntArray_Alloc(&numlist, 4))
7687 : : {
7688 : 0 : ret = RI_ERR_ALLOC;
7689 : 0 : goto exit_function;
7690 : : }
7691 : :
7692 : 0 : p0 = p;
7693 [ # # ]: 0 : while (*(++p))
7694 : : {
7695 [ # # ]: 0 : if (*p == '-')
7696 : : {
7697 : 0 : have = endgroups; break;
7698 : : }
7699 [ # # ]: 0 : if (*p == ',')
7700 : : {
7701 : 0 : have = stars; break;
7702 : : }
7703 : : }
7704 [ # # ]: 0 : if (have == stars)
7705 : : {
7706 [ # # ]: 0 : while (*(++p))
7707 : : {
7708 [ # # ]: 0 : if (*p == ',')
7709 : : {
7710 : 0 : have = stars_ring; break;
7711 : : }
7712 [ # # ]: 0 : if (*p == '.')
7713 : : {
7714 : 0 : have = stars_bond; break;
7715 : : }
7716 [ # # ]: 0 : if (*p == ')')
7717 : : {
7718 : 0 : have = stars_atom; break;
7719 : : }
7720 : : }
7721 : : }
7722 : 0 : p = p0;
7723 : :
7724 [ # # ]: 0 : if (unit) /* djb-rwth: fixing a NULL pointer dereference */
7725 : : {
7726 : 0 : unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
7727 [ # # ]: 0 : if (have == endgroups)
7728 : : {
7729 : : /* Read end groups notation */
7730 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dash, comma, &res);
7731 [ # # # # ]: 0 : if (res == 1 && numlist.used == 2)
7732 : : {
7733 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dash, rt_par, &res);
7734 : : }
7735 [ # # # # ]: 0 : if (res == 1 && numlist.used == 4)
7736 : : {
7737 : 0 : pStart = p + 1;
7738 : 0 : unit->nb = 2;
7739 : 0 : unit->blist = (int*)inchi_calloc(2 * (long long)unit->nb, sizeof(int)); /* djb-rwth: cast operator added */
7740 [ # # ]: 0 : if (!unit->blist)
7741 : : {
7742 : 0 : ret = RI_ERR_ALLOC; IntArray_Free(&numlist); goto exit_function;
7743 : : }
7744 : 0 : unit->blist[0] = numlist.item[0]; unit->blist[1] = numlist.item[1];
7745 : 0 : unit->blist[2] = numlist.item[2]; unit->blist[3] = numlist.item[3];
7746 : 0 : unit->cap1 = numlist.item[0]; /* just for GAF check belows */
7747 : 0 : unit->cap2 = numlist.item[2];
7748 : 0 : IntArray_Free(&numlist);
7749 : 0 : continue;
7750 : : }
7751 : : }
7752 [ # # # # ]: 0 : else if (have == stars_ring ||
7753 [ # # ]: 0 : have == stars_bond ||
7754 : : have == stars_atom)
7755 : : {
7756 : : /* Read star atoms - frame shiftable bonds notation */
7757 : 0 : IntArray_Reset(&numlist);
7758 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, comma, dash, &res);
7759 [ # # # # ]: 0 : if (res != 1 || numlist.used != 2)
7760 : : {
7761 : 0 : ret = RI_ERR_SYNTAX; IntArray_Free(&numlist); goto exit_function;
7762 : : }
7763 : : /* OK, we got star atom numbers */
7764 [ # # ]: 0 : if (have == stars_ring)
7765 : : {
7766 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, comma, rt_par, &res);
7767 [ # # # # ]: 0 : if (res != 1 || numlist.used < 4)
7768 : : {
7769 : 0 : ret = RI_ERR_SYNTAX;
7770 : 0 : IntArray_Free(&numlist);
7771 : 0 : goto exit_function;
7772 : : }
7773 : 0 : unit->cyclizable = CLOSING_SRU_RING;
7774 : 0 : unit->nbkbonds = (numlist.used - 2) / 2;
7775 : : }
7776 [ # # ]: 0 : else if (have == stars_bond)
7777 : : {
7778 : 0 : p = ParseSegmentReadDelimitedNumbers(p, pEnd, &numlist, dot, rt_par, &res);
7779 [ # # # # ]: 0 : if (res != 1 || numlist.used < 4)
7780 : : {
7781 : 0 : ret = RI_ERR_SYNTAX;
7782 : 0 : IntArray_Free(&numlist);
7783 : 0 : goto exit_function;
7784 : : }
7785 : 0 : unit->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;
7786 : 0 : unit->nbkbonds = 1;
7787 : : }
7788 [ # # ]: 0 : else if (have == stars_atom)
7789 : : {
7790 : 0 : int num = inchi_strtol(++p, &p, 10);
7791 : : #if ( ( CHECK_STRTOL_ATNUMB==1 ) || ( FIX_GAF_2019_2==1 ) )
7792 [ # # # # ]: 0 : if (num > na_total || num < 0)
7793 : : {
7794 : 0 : IntArray_Free(&numlist);
7795 : 0 : ret = RI_ERR_SYNTAX;
7796 : 0 : goto exit_function;
7797 : : }
7798 : : #endif
7799 [ # # ]: 0 : if (*p != rt_par)
7800 : : {
7801 : 0 : ret = RI_ERR_SYNTAX;
7802 : 0 : IntArray_Free(&numlist);
7803 : 0 : goto exit_function;
7804 : : }
7805 : 0 : IntArray_Append(&numlist, num);
7806 : 0 : unit->cyclizable = CLOSING_SRU_DIRADICAL;
7807 : 0 : unit->nbkbonds = 1;
7808 : : }
7809 : : }
7810 : : else
7811 : : {
7812 : 0 : ret = RI_ERR_SYNTAX; IntArray_Free(&numlist); goto exit_function;
7813 : : }
7814 : :
7815 : 0 : unit->cap1 = numlist.item[0];
7816 : 0 : unit->cap2 = numlist.item[1];
7817 : :
7818 [ # # ]: 0 : if (unit->bkbonds)
7819 : : {
7820 : 0 : imat_free(unit->maxbkbonds, unit->bkbonds);
7821 : 0 : unit->bkbonds = NULL;
7822 : : }
7823 : 0 : unit->maxbkbonds = inchi_max(unit->maxbkbonds, unit->nbkbonds);
7824 : 0 : err = imat_new(unit->maxbkbonds, 2, &(unit->bkbonds)); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
7825 [ # # ]: 0 : for (ib = 0; ib < unit->nbkbonds; ib++)
7826 : : {
7827 : 0 : unit->bkbonds[ib][0] = numlist.item[ib * 2 + 2];
7828 [ # # ]: 0 : if (numlist.used != 3)
7829 : : {
7830 : 0 : unit->bkbonds[ib][1] = numlist.item[ib * 2 + 3];
7831 : : }
7832 : : else
7833 : : {
7834 : 0 : unit->bkbonds[ib][1] = unit->bkbonds[ib][0];
7835 : : }
7836 : : }
7837 [ # # ]: 0 : if (unit->nbkbonds > 0)
7838 : : {
7839 : : /*unit->cyclizable = 1;*/
7840 : 0 : unit->cap1 = numlist.item[0];
7841 : 0 : unit->cap2 = numlist.item[1];
7842 : : }
7843 : : }
7844 : :
7845 : 0 : pStart = p + 1;
7846 : 0 : IntArray_Free(&numlist);
7847 : 0 : continue;
7848 : : }
7849 : :
7850 [ # # ]: 0 : if (*p == ';')
7851 : : {
7852 : 0 : p++;
7853 : : }
7854 : 0 : q = p;
7855 : 0 : pStart = p;
7856 : : }
7857 : :
7858 : 0 : pd->really_do_frame_shift = 1;
7859 : 0 : pd->frame_shift_scheme = FSS_STARS_CYCLED;
7860 : 0 : pd->treat = POLYMERS_MODERN;
7861 : 0 : pd->is_in_reconn = 0;
7862 : :
7863 : : /*OAD_Polymer_DebugTrace( pd );*/
7864 : :
7865 : 0 : ret = pd->n;
7866 : :
7867 : 0 : exit_function:
7868 : :
7869 : 0 : IntArray_Free(&alist);
7870 [ # # # # : 0 : if (ret == RI_ERR_ALLOC || ret == RI_ERR_SYNTAX || ret == RI_ERR_PROGR)
# # ]
7871 : : {
7872 : : /*FreeExtOrigAtData( pd, pv );*/
7873 : : }
7874 : : #if ( FIX_GAF_2019_2==1 )
7875 : : else
7876 : : {
7877 [ # # ]: 0 : if (pd)
7878 : : {
7879 : 0 : int iu, ipsb, maxats = na_total + pd->n_pzz;
7880 [ # # ]: 0 : for (iu = 0; iu < pd->n; iu++)
7881 : : {
7882 : : int astar1, astar2;
7883 : : #if ( FIX_OSS_FUZZ_25604==1 )
7884 [ # # ]: 0 : if (NULL == pd->units[iu])
7885 : : {
7886 : 0 : ret = RI_ERR_SYNTAX;
7887 : 0 : break;
7888 : : }
7889 : : #endif
7890 : 0 : astar1 = pd->units[iu]->cap1;
7891 : 0 : astar2 = pd->units[iu]->cap2;
7892 [ # # ]: 0 : if (0 == pd->units[iu]->nb)
7893 : : {
7894 : 0 : continue;
7895 : : }
7896 [ # # ]: 0 : if (ret == RI_ERR_SYNTAX)
7897 : : {
7898 : 0 : break;
7899 : : }
7900 [ # # # # : 0 : if (astar1 > maxats || astar1 <= 0 || astar2 > maxats || astar2 <= 0)
# # # # ]
7901 : : {
7902 : 0 : ret = RI_ERR_SYNTAX;
7903 : 0 : break;
7904 : : }
7905 [ # # ]: 0 : for (ipsb = 0; ipsb < pd->units[iu]->nbkbonds; ipsb++)
7906 : : {
7907 : : int a1psb, a2psb;
7908 : 0 : a1psb = pd->units[iu]->bkbonds[ipsb][0];
7909 : 0 : a2psb = pd->units[iu]->bkbonds[ipsb][1];
7910 [ # # # # : 0 : if (a1psb > maxats || a1psb <= 0 || a2psb > maxats || a2psb <= 0)
# # # # ]
7911 : : {
7912 : 0 : ret = RI_ERR_SYNTAX;
7913 : 0 : break;
7914 : : }
7915 : : }
7916 : : }
7917 : : }
7918 : : }
7919 : : #endif
7920 : :
7921 : 0 : return ret;
7922 : : }
7923 : :
7924 : : /****************************************************************************
7925 : : Read sequence of integer numbers from str into growing int array numlist
7926 : : until NULL, EOL or 'c_stop' symbol occurred, whichever is the first.
7927 : : Numbers are assumed to be delimited with commas.
7928 : :
7929 : : NB: on success, returns 1.
7930 : : ****************************************************************************/
7931 : 0 : const char* ParseSegmentReadDelimitedNumbers(const char* str,
7932 : : const char* pEnd,
7933 : : INT_ARRAY* numlist,
7934 : : char c_delim,
7935 : : char c_stop,
7936 : : int* ret)
7937 : : {
7938 : : const char* p, * pStart;
7939 : 0 : int num, curr_atom = 0;
7940 : :
7941 : 0 : *ret = 1;
7942 : :
7943 [ # # ]: 0 : if (!str)
7944 : : {
7945 : 0 : *ret = -1;
7946 : 0 : return NULL;
7947 : : }
7948 : :
7949 : 0 : pStart = (char*)(str + 1);
7950 : 0 : p = pStart;
7951 [ # # ]: 0 : while (*pStart)
7952 : : {
7953 [ # # # # ]: 0 : for (p = pStart, curr_atom = 0; p < pEnd && *p != c_stop; curr_atom++)
7954 : : {
7955 : 0 : num = (AT_NUMB)inchi_strtol(p, &p, 10);
7956 : : #if ( CHECK_STRTOL_ATNUMB==1 )
7957 [ # # # # ]: 0 : if (num > MAX_ATOMS || num < 0)
7958 : : {
7959 : 0 : *ret = RI_ERR_SYNTAX;
7960 : 0 : return p;
7961 : : }
7962 : : #endif
7963 : : {
7964 [ # # ]: 0 : if (0 != IntArray_Append(numlist, num))
7965 : : {
7966 : 0 : *ret = RI_ERR_SYNTAX;
7967 : 0 : return p;
7968 : : }
7969 : : }
7970 [ # # ]: 0 : if (*p == c_delim)
7971 : : {
7972 : 0 : p++;
7973 : : }
7974 [ # # ]: 0 : else if (*p == c_stop)
7975 : : {
7976 : 0 : return p;
7977 : : }
7978 : : else
7979 : : {
7980 : 0 : *ret = -1; return NULL;
7981 : : }
7982 : : }
7983 [ # # ]: 0 : if (*p == c_stop)
7984 : : {
7985 : 0 : return p;
7986 : : }
7987 : : }
7988 : :
7989 : 0 : return p;
7990 : : }
7991 : :
7992 : :
7993 : :
7994 : : /****************************************************************************
7995 : : Parse "/q" InChI layer
7996 : : ****************************************************************************/
7997 : 1 : int ParseSegmentCharge(const char* str,
7998 : : int bMobileH,
7999 : : INChI* pInpInChI[],
8000 : : int ppnNumComponents[])
8001 : : {
8002 : : /* Pass 1: count bonds and find actual numbers of atom */
8003 : : int i, mpy_component, val;
8004 : : int nNumComponents, iComponent;
8005 : : const char* p, * q, * t, * pStart, * pEnd;
8006 : : int ret;
8007 : 1 : INChI* pInChI = pInpInChI[bMobileH];
8008 : 1 : const char mult_type[] = "mnMNe";
8009 : 1 : int if_cnd = 1; /* djb-rwth: needed for some if condition restructuring */
8010 : :
8011 [ - + ]: 1 : if (str[0] != 'q')
8012 : : {
8013 : 0 : return 0;
8014 : : }
8015 : :
8016 : 1 : pStart = (char*)str + 1;
8017 : 1 : iComponent = 0;
8018 : 1 : nNumComponents = ppnNumComponents[bMobileH];
8019 : :
8020 [ + - - - ]: 1 : if (!*pStart && bMobileH == TAUT_NON)
8021 : : {
8022 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
8023 : : {
8024 : 0 : pInChI[i].nTotalCharge = NO_VALUE_INT;
8025 : : }
8026 : 0 : return nNumComponents + 1;
8027 : : }
8028 : :
8029 : : while (1)
8030 : : {
8031 : : /* cycle over components */
8032 [ + - ]: 1 : if (!(pEnd = strchr(pStart, ';')))
8033 : : {
8034 : 1 : pEnd = pStart + strlen(pStart);
8035 : : }
8036 : :
8037 : : /* djb-rwth: condition for if block had to be rewritten */
8038 [ + - ]: 1 : if ((int)inchi_strtol(pStart, &q, 10) > 0)
8039 : : {
8040 : 1 : val = (int)inchi_strtol(pStart, &q, 10);
8041 : 1 : if_cnd = isdigit(UCINT * pStart);
8042 : :
8043 : : }
8044 : : else
8045 : : {
8046 : 0 : val = 1;
8047 : 0 : q = pStart;
8048 : 0 : if_cnd = 1;
8049 : : }
8050 : :
8051 : :
8052 [ - + - - : 1 : 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 */
- - ]
8053 : : {
8054 : : /* process the abbreviation */
8055 : :
8056 [ # # # ]: 0 : switch (bMobileH)
8057 : : {
8058 : 0 : case TAUT_YES:
8059 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8060 : 0 : goto exit_function;
8061 : 0 : case TAUT_NON:
8062 [ # # ]: 0 : if (*q != 'm' ||
8063 [ # # ]: 0 : iComponent + val > nNumComponents ||
8064 [ # # ]: 0 : iComponent + val > ppnNumComponents[TAUT_YES])
8065 : : {
8066 : :
8067 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8068 : 0 : goto exit_function;
8069 : : }
8070 [ # # ]: 0 : for (i = 0; i < val; i++)
8071 : : {
8072 : : /* avoid 0 which means "omitted" */
8073 : 0 : pInChI[iComponent + i].nTotalCharge = pInpInChI[TAUT_YES][iComponent + i].nTotalCharge ?
8074 [ # # ]: 0 : pInpInChI[TAUT_YES][iComponent + i].nTotalCharge :
8075 : : NO_VALUE_INT;
8076 : : }
8077 : 0 : mpy_component = val;
8078 : 0 : goto end_main_cycle;
8079 : 0 : default:
8080 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8081 : 0 : goto exit_function;
8082 : : }
8083 : : }
8084 : : else
8085 : : {
8086 [ - + - - ]: 1 : if ((p = strchr(pStart, '*')) && p < pEnd)
8087 : : {
8088 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
8089 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8090 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
8091 : : {
8092 : 0 : ret = RI_ERR_SYNTAX;
8093 : 0 : goto exit_function;
8094 : : }
8095 : : #endif
8096 [ # # ]: 0 : if (p != q)
8097 : : {
8098 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8099 : 0 : goto exit_function;
8100 : : }
8101 : 0 : p++;
8102 : : }
8103 : : else
8104 : : {
8105 : 1 : mpy_component = 1;
8106 : 1 : p = pStart;
8107 : : }
8108 : : }
8109 : : #if ( FIX_DALKE_BUGS == 1 )
8110 [ + - - + ]: 1 : if (mpy_component + iComponent > nNumComponents || mpy_component <= 0)
8111 : : {
8112 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: too many components in charge layer */
8113 : 0 : goto exit_function;
8114 : : }
8115 : : #endif
8116 : 1 : pStart = p;
8117 [ + - ]: 1 : if (pStart < pEnd)
8118 : : {
8119 [ + - + - ]: 1 : if (pStart[0] == '+' && isdigit(UCINT pStart[1]))
8120 : : {
8121 : 1 : val = (int)inchi_strtol(pStart + 1, &q, 10);
8122 : 1 : pStart = q;
8123 : : }
8124 : : else
8125 : : {
8126 [ # # # # ]: 0 : if (pStart[0] == '-' && isdigit(UCINT pStart[1]))
8127 : : {
8128 : 0 : val = -(int)inchi_strtol(pStart + 1, &q, 10);
8129 : 0 : pStart = q;
8130 : : }
8131 : : else
8132 : : {
8133 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8134 : 0 : goto exit_function;
8135 : : }
8136 : : }
8137 : : #if ( FIX_DALKE_BUGS == 1 )
8138 [ + - - + ]: 1 : if (val < -256 || val > 256)
8139 : : {
8140 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8141 : 0 : goto exit_function;
8142 : : }
8143 : : #endif
8144 [ - + ]: 1 : if (!val)
8145 : : {
8146 [ # # ]: 0 : if (pStart != pEnd)
8147 : : {
8148 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8149 : 0 : goto exit_function;
8150 : : }
8151 [ # # ]: 0 : if (bMobileH == TAUT_NON)
8152 : : {
8153 : 0 : val = NO_VALUE_INT; /* avoid 0 which means "omitted" */
8154 : : }
8155 : : }
8156 : : }
8157 : : else
8158 : : {
8159 : 0 : val = NO_VALUE_INT;
8160 : : }
8161 [ + + ]: 2 : for (i = 0; i < mpy_component; i++)
8162 : : {
8163 : 1 : pInChI[iComponent + i].nTotalCharge = val;
8164 : : }
8165 : :
8166 : 1 : end_main_cycle:
8167 : 1 : iComponent += mpy_component;
8168 [ - + ]: 1 : if (*pEnd)
8169 : : {
8170 : 0 : pStart = pEnd + 1;
8171 : 0 : continue;
8172 : : }
8173 : : else
8174 : : {
8175 : 1 : break;
8176 : : }
8177 : : }
8178 : :
8179 [ - + ]: 1 : if (nNumComponents != iComponent)
8180 : : {
8181 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8182 : 0 : goto exit_function;
8183 : : }
8184 : 1 : ret = iComponent + 1;
8185 : :
8186 : 1 : exit_function:
8187 : :
8188 : 1 : return ret;
8189 : : }
8190 : :
8191 : :
8192 : : /****************************************************************************
8193 : : Parse "/h" InChI layer
8194 : : ****************************************************************************/
8195 : 2 : int ParseSegmentMobileH(const char* str,
8196 : : int bMobileH,
8197 : : INChI* pInpInChI[],
8198 : : int pnNumComponents[],
8199 : : int* pbAbc)
8200 : : {
8201 : : #define nNum_H( ICOMPONENT ) ((bMobileH==TAUT_YES)? pInChI[ICOMPONENT].nNum_H : pInChI[ICOMPONENT].nNum_H_fixed)
8202 : :
8203 : : /* Pass 1: count bonds and find actual numbers of atom */
8204 : :
8205 : 2 : int i, mpy_component, num_H, num_Minus, val, num_Atoms, numCtAtoms, tg_alloc_len, len, len2, k = 0;
8206 : : int num_H_component, num_H_formula, num_taut_H_component, num_H_InChI, ret2;
8207 : : int nNumComponents, iComponent, lenTautomer, tg_pos_Tautomer, iTGroup; /* djb-rwth: removing redundant variables */
8208 : : const char* p, * q, * h, * t, * p1, * pTaut, * pStart, * pEnd;
8209 : : int curAtom, nxtAtom; /* djb-rwth: fixing coverity ID #499563 */
8210 [ + - ]: 2 : int state, ret, nAltMobileH = ALT_TAUT(bMobileH); /* djb-rwth: removing redundant variables */
8211 : 2 : INChI* pInChI = pInpInChI[bMobileH];
8212 : 2 : INChI* pAltInChI = pInpInChI[nAltMobileH];
8213 : 2 : int base = 10;
8214 : :
8215 : 2 : num_H = -999; /* impossible value */
8216 : 2 : num_Minus = -999; /* impossible value */
8217 : 2 : tg_pos_Tautomer = -999; /* impossible value */
8218 : :
8219 : : /* number of immobile H is always allocated; immobile H are present in M layer only */
8220 : 2 : nNumComponents = pnNumComponents[bMobileH];
8221 : :
8222 : : /* djb-rwth: fixing oss-fuzz issues #66985, #66718, #43512, #43456, #43420, #42774, #34772, #30156 */
8223 : :
8224 [ + + ]: 4 : for (i = 0; i < nNumComponents; i++)
8225 : : {
8226 : 2 : len = pInChI[i].nNumberOfAtoms;
8227 [ - + - - ]: 2 : if (bMobileH == TAUT_NON && i < pnNumComponents[nAltMobileH])
8228 : : {
8229 [ # # ]: 0 : if (len < pAltInChI[i].nNumberOfAtoms)
8230 : : {
8231 : 0 : len = pAltInChI[i].nNumberOfAtoms;
8232 [ # # ]: 0 : if (pInChI[i].nNum_H)
8233 : : {
8234 [ # # ]: 0 : inchi_free(pInChI[i].nNum_H);
8235 : 0 : pInChI[i].nNum_H = NULL;
8236 : : }
8237 : : }
8238 : : }
8239 : 2 : len++;
8240 [ + - ]: 2 : if (!pInChI[i].nNum_H)
8241 : : {
8242 : 2 : S_CHAR* pi_nnh2 = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H[0]));
8243 [ - + ]: 2 : if (!pi_nnh2)
8244 : : {
8245 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8246 : 0 : goto exit_function;
8247 : : }
8248 : 2 : pInChI[i].nNum_H = pi_nnh2;
8249 : : /* pi_nnh2_init = true; */
8250 : : }
8251 : : /* copy immobile H from Mobile-H layer to Fixed-H layer */
8252 [ - + - - ]: 2 : if (bMobileH == TAUT_NON && i < pnNumComponents[nAltMobileH])
8253 : : {
8254 : 0 : S_CHAR* pai_nnh = (S_CHAR*)inchi_realloc(pAltInChI[i].nNum_H, len * sizeof(pAltInChI[0].nNum_H[0]));
8255 [ # # ]: 0 : if (pai_nnh)
8256 : : {
8257 : 0 : S_CHAR* pi_nnh1 = NULL; /* copied from below to satisfy C syntax 2024-09-01 DT */
8258 : 0 : pAltInChI[i].nNum_H = pai_nnh;
8259 : : /*if (!pi_nnh2_init)
8260 : : {
8261 : : */
8262 : 0 : pi_nnh1 = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H[0]));
8263 [ # # ]: 0 : if (!pi_nnh1)
8264 : : {
8265 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8266 : 0 : goto exit_function;
8267 : : }
8268 : 0 : memcpy(pi_nnh1, pai_nnh, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0])); /* djb-rwth: cast operator added */
8269 : : /* djb-rwth: alternative solution
8270 : : k = memcpy_custom(&pi_nnh1[i], pAltInChI[i].nNum_H, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0]))
8271 : : if (k)
8272 : : {
8273 : : ret = RI_ERR_ALLOC;
8274 : : goto exit_function;
8275 : : }
8276 : : */
8277 : 0 : pInChI[i].nNum_H = pi_nnh1;
8278 : : /*
8279 : : }
8280 : : else
8281 : : {
8282 : : memcpy(pi_nnh2, pai_nnh, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0])); * djb-rwth: cast operator added *
8283 : : * djb-rwth: alternative solution *
8284 : : k = memcpy_custom(&pi_nnh2[i], pAltInChI[i].nNum_H, ((long long)len - 1) * sizeof(pInChI[0].nNum_H[0]))
8285 : : if (k)
8286 : : {
8287 : : ret = RI_ERR_ALLOC;
8288 : : goto exit_function;
8289 : : }
8290 : :
8291 : : }
8292 : : */
8293 : : }
8294 : : else
8295 : : {
8296 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8297 : 0 : goto exit_function;
8298 : : }
8299 : : }
8300 : : }
8301 : :
8302 [ + + ]: 2 : if (str[0] != 'h')
8303 : : {
8304 : 1 : return 0;
8305 : : }
8306 : :
8307 : : /* Read Hydrogen info in 1 pass */
8308 : :
8309 : 1 : pStart = (char*)str + 1;
8310 : 1 : iComponent = 0;
8311 : 1 : nNumComponents = pnNumComponents[bMobileH];
8312 : :
8313 : : while (1)
8314 : : {
8315 : : /* cycle over components */
8316 [ + - ]: 1 : if (!(pEnd = strchr(pStart, ';')))
8317 : : {
8318 : 1 : pEnd = pStart + strlen(pStart);
8319 : : }
8320 [ - + - - ]: 1 : if ((p = strchr(pStart, '*')) && p < pEnd)
8321 : : {
8322 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
8323 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8324 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
8325 : : {
8326 : 0 : ret = RI_ERR_SYNTAX;
8327 : 0 : goto exit_function;
8328 : : }
8329 : : #endif
8330 : : #if ( FIX_DALKE_BUGS == 1 )
8331 [ # # # # ]: 0 : if (p != q || !isdigit(UCINT* pStart)) /* prevent non-positive multipliers */
8332 : : #else
8333 : : if (p != q)
8334 : : #endif
8335 : : {
8336 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8337 : 0 : goto exit_function;
8338 : : }
8339 : 0 : p++;
8340 : : }
8341 : : else
8342 : : {
8343 : 1 : mpy_component = 1;
8344 : 1 : p = pStart;
8345 : : }
8346 : 1 : pStart = p;
8347 : : /* Pass 1.1 parse a component */
8348 : : /* djb-rwth: removing redundant code */
8349 : : /* djb-rwth: removing redundant code */
8350 : : /* djb-rwth: removing redundant code */
8351 : 1 : curAtom = 0; /* djb-rwth: ignoring LLVM warning: value used */
8352 : 1 : numCtAtoms = pInChI[iComponent].nNumberOfAtoms;
8353 [ - + - - ]: 1 : if (bMobileH == TAUT_NON && iComponent < pnNumComponents[nAltMobileH])
8354 : : {
8355 : 0 : numCtAtoms = pAltInChI[iComponent].nNumberOfAtoms;
8356 : : }
8357 : :
8358 [ + - - + ]: 1 : if (p < pEnd && *pbAbc == -1)
8359 : : {
8360 : : /* check if compressed InChI */
8361 [ # # # # ]: 0 : *pbAbc = (*p == ',' || isupper(UCINT* p)) ? 1 : 0;
8362 : : }
8363 [ - + ]: 1 : base = (*pbAbc == 1) ? ALPHA_BASE : 10;
8364 : :
8365 : : /* immobile H */
8366 [ - + ]: 1 : t = pTaut = (*pbAbc == 1) ? strchr(p, ',') : strchr(p, '('); /* locate the first tautomer group character */
8367 : :
8368 [ - + - - ]: 1 : if (t && bMobileH == TAUT_NON)
8369 : : {
8370 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8371 : 0 : goto exit_function;
8372 : : }
8373 [ - + - - ]: 1 : if (!pTaut || pTaut > pEnd)
8374 : : {
8375 : 1 : pTaut = pEnd;
8376 : 1 : t = NULL; /* found no tautomeric group for this component */
8377 : : }
8378 : : /* djb-rwth: fixing oss-fuzz issue #69489 */
8379 [ + + + - ]: 2 : for (i = 0; (i < mpy_component) && (iComponent + i < nNumComponents); i++)
8380 : : {
8381 [ - + ]: 1 : if (bMobileH == TAUT_NON)
8382 : : {
8383 : : /* allocate nNum_H_fixed */
8384 [ # # ]: 0 : if (pInChI[iComponent + i].nNum_H_fixed)
8385 : : {
8386 : 0 : ret = RI_ERR_PROGR; /* program error */
8387 : 0 : goto exit_function;
8388 : : }
8389 [ # # ]: 0 : if (iComponent + i < pnNumComponents[nAltMobileH])
8390 : : {
8391 : 0 : len = inchi_max(pInChI[iComponent + i].nNumberOfAtoms, pAltInChI[iComponent + i].nNumberOfAtoms) + 1;
8392 : : }
8393 : : else
8394 : : {
8395 : 0 : len = pInChI[iComponent + i].nNumberOfAtoms + 1;
8396 : : }
8397 : 0 : pInChI[iComponent + i].nNum_H_fixed = (S_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nNum_H_fixed[0]));
8398 [ # # ]: 0 : if (!pInChI[iComponent + i].nNum_H_fixed)
8399 : : {
8400 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8401 : 0 : goto exit_function;
8402 : : }
8403 : : /* compare nAtom */
8404 [ # # ]: 0 : if (iComponent + i < pnNumComponents[nAltMobileH])
8405 : : {
8406 : 0 : len2 = inchi_min(pInChI[iComponent + i].nNumberOfAtoms, pAltInChI[iComponent + i].nNumberOfAtoms);
8407 [ # # # # ]: 0 : if (pInChI[iComponent + i].nAtom && len2)
8408 : : {
8409 : : /* check */
8410 [ # # ]: 0 : if (memcmp(pInChI[iComponent + i].nAtom, pAltInChI[iComponent + i].nAtom, len2 * sizeof(pInChI[0].nAtom[0])))
8411 : : {
8412 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8413 : 0 : goto exit_function;
8414 : : }
8415 : : }
8416 : : /* allocate and copy atom if bridging H are present */
8417 [ # # ]: 0 : if (pInChI[iComponent + i].nNumberOfAtoms < pAltInChI[iComponent + i].nNumberOfAtoms)
8418 : : {
8419 [ # # ]: 0 : if (pInChI[iComponent + i].nAtom)
8420 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
8421 [ # # ]: 0 : if (!(pInChI[iComponent + i].nAtom = (U_CHAR*)inchi_calloc(len, sizeof(pInChI[0].nAtom[0]))))
8422 : : {
8423 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8424 : 0 : goto exit_function;
8425 : : }
8426 [ # # ]: 0 : if (len > 1)
8427 : : {
8428 : 0 : memcpy(pInChI[iComponent + i].nAtom, pAltInChI[iComponent + i].nAtom, ((long long)len - 1) * sizeof(pInChI[0].nAtom[0])); /* djb-rwth: cast operator added */
8429 : : }
8430 : : /* correct number of atoms including bridging H */
8431 : 0 : pInChI[iComponent + i].nNumberOfAtoms = pAltInChI[iComponent + i].nNumberOfAtoms;
8432 : : }
8433 : : }
8434 : : }
8435 : : }
8436 : :
8437 [ - + ]: 1 : if (*pbAbc == 1)
8438 : : {
8439 : : /* read numbers of H: XnYn... or XYn... */
8440 : 0 : p = pStart;
8441 : 0 : tg_alloc_len = 0;
8442 : 0 : num_H_component = num_taut_H_component = 0;
8443 [ # # ]: 0 : while (p < pTaut)
8444 : : {
8445 : : /* syntax check: atom number */
8446 [ # # # # ]: 0 : if (!*p || !isupper(UCINT* p))
8447 : : {
8448 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8449 : 0 : goto exit_function;
8450 : : }
8451 [ # # ]: 0 : if ((curAtom = nxtAtom = (int)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
8452 : : {
8453 : 0 : p = q;
8454 [ # # ]: 0 : if (isupper(UCINT* p))
8455 : : {
8456 : 0 : nxtAtom = (int)inchi_strtol(p, &q, base);
8457 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8458 [ # # # # ]: 0 : if (nxtAtom > MAX_ATOMS || nxtAtom < 0)
8459 : : {
8460 : 0 : ret = RI_ERR_SYNTAX;
8461 : 0 : goto exit_function;
8462 : : }
8463 : : #endif
8464 : 0 : p = q;
8465 : : }
8466 : : }
8467 [ # # # # : 0 : if (curAtom <= 0 || curAtom > nxtAtom ||
# # ]
8468 [ # # ]: 0 : nxtAtom > numCtAtoms || p > pTaut)
8469 : : {
8470 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8471 : 0 : goto exit_function;
8472 : : }
8473 : : /* number of H, may be negative */
8474 [ # # # # ]: 0 : if (!(num_H = (int)inchi_strtol(p, &q, 10)) || q > pTaut)
8475 : : {
8476 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8477 : 0 : goto exit_function;
8478 : : }
8479 : 0 : p = q;
8480 : : /* set number of H */
8481 : : /* djb-rwth: fixing oss-fuzz issue #38399 */
8482 [ # # # # : 0 : if (((bMobileH == TAUT_YES) && pInChI[iComponent].nNum_H) || ((bMobileH != TAUT_YES) && pInChI[iComponent].nNum_H_fixed))
# # # # ]
8483 : : {
8484 [ # # ]: 0 : for (i = curAtom; i <= nxtAtom; i++)
8485 : : {
8486 [ # # ]: 0 : nNum_H(iComponent)[i - 1] = num_H;
8487 : 0 : num_H_component += num_H;
8488 : : }
8489 : : }
8490 : : }
8491 [ # # ]: 0 : if (p != pTaut)
8492 : : {
8493 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8494 : 0 : goto exit_function;
8495 : : }
8496 : : }
8497 : : else
8498 : : {
8499 : : /* read numbers of H: 1-2,3H2,4,5H3 */
8500 : 1 : p = pStart;
8501 : 1 : tg_alloc_len = 0;
8502 : 1 : num_H_component = num_taut_H_component = 0;
8503 : : #if ( FIX_GAF_2019_1==1 )
8504 : : {
8505 : : char invalid;
8506 : 1 : const char* str1 = str + 1;
8507 [ - + ]: 1 : if (bMobileH == TAUT_NON) /* FixedH layer "/h"*/
8508 : : {
8509 : 0 : invalid = str1[strspn(str1, "0123456789hDHT-,;()*")];
8510 : : }
8511 : : else /* Main layer (mobileH) "/h"*/
8512 : : {
8513 : 1 : invalid = str1[strspn(str1, "0123456789DHT-,;()*")];
8514 : : }
8515 [ - + ]: 1 : if (invalid != '\0')
8516 : : {
8517 : 0 : ret = RI_ERR_SYNTAX;
8518 : 0 : goto exit_function;
8519 : : }
8520 : : }
8521 : : #endif
8522 [ + - ]: 1 : while (p < pTaut)
8523 : : {
8524 : : /* syntax check: atom number */
8525 [ + - - + ]: 1 : if (!*p || !isdigit(UCINT* p))
8526 : : {
8527 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8528 : 0 : goto exit_function;
8529 : : }
8530 : : /* number of H */
8531 : 1 : h = p + strcspn(p, "Hh");
8532 : : /*h = strchr( p, 'H' );*/
8533 [ + - - + ]: 1 : if (!*h || h >= pTaut)
8534 : : {
8535 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8536 : 0 : goto exit_function;
8537 : : /*
8538 : : p = pTaut;
8539 : : h = NULL;
8540 : : break; */ /* no more H found */
8541 : : }
8542 [ - + - - ]: 1 : num_H = (*h == 'H') ? 1 : (*h == 'h') ? -1 : 0;
8543 [ - + ]: 1 : if (!num_H)
8544 : : {
8545 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8546 : 0 : goto exit_function;
8547 : : }
8548 [ - + - - ]: 1 : if (h[1] && isdigit(UCINT h[1]))
8549 : : {
8550 : 0 : num_H *= (int)inchi_strtol(h + 1, &p1, 10);
8551 : : }
8552 : : else
8553 : : {
8554 : 1 : p1 = h + 1; /* next set of immobile H */
8555 : : }
8556 [ - + ]: 1 : if (*p1 == ',')
8557 : : {
8558 : 0 : p1++; /* next H-subsegment; otherwise (H or ; or end of the segment */
8559 : : }
8560 : : /* list of atoms that have num_H */
8561 [ + - ]: 1 : while (p < h)
8562 : : {
8563 [ + - - + ]: 1 : if (!*p || !isdigit(UCINT* p))
8564 : : {
8565 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8566 : 0 : goto exit_function;
8567 : : }
8568 : 1 : nxtAtom = curAtom = (int)inchi_strtol(p, &q, 10);
8569 [ - + ]: 1 : if (*q == '-')
8570 : : {
8571 : 0 : nxtAtom = (int)inchi_strtol(q + 1, &q, 10);
8572 : : #if ( CHECK_STRTOL_ATNUMB==1 )
8573 [ # # # # ]: 0 : if (nxtAtom > MAX_ATOMS || nxtAtom < 0)
8574 : : {
8575 : 0 : ret = RI_ERR_SYNTAX;
8576 : 0 : goto exit_function;
8577 : : }
8578 : : #endif
8579 : : }
8580 : : /* consitency check */
8581 [ - + - - : 1 : if (curAtom <= 0 || curAtom > numCtAtoms ||
- - ]
8582 [ # # ]: 0 : nxtAtom < curAtom || nxtAtom > numCtAtoms)
8583 : : {
8584 : 1 : ret = RI_ERR_SYNTAX; /* syntax error */
8585 : 1 : goto exit_function;
8586 : : }
8587 : : /* set number of H */
8588 : : /* djb-rwth: fixing oss-fuzz issue #38399 */
8589 [ # # # # : 0 : if (((bMobileH == TAUT_YES) && pInChI[iComponent].nNum_H) || ((bMobileH != TAUT_YES) && pInChI[iComponent].nNum_H_fixed))
# # # # ]
8590 : : {
8591 [ # # ]: 0 : for (i = curAtom; i <= nxtAtom; i++)
8592 : : {
8593 [ # # ]: 0 : nNum_H(iComponent)[i - 1] = num_H;
8594 : 0 : num_H_component += num_H;
8595 : : }
8596 : : }
8597 : : /* move to the next atom number if any */
8598 : 0 : p = q;
8599 [ # # ]: 0 : if (*p == ',')
8600 : : {
8601 : 0 : p++;
8602 : : }
8603 : : }
8604 : :
8605 [ # # ]: 0 : if (p == h)
8606 : : {
8607 : 0 : p = p1;
8608 : : }
8609 : : else
8610 : : {
8611 [ # # ]: 0 : if (p == pTaut)
8612 : : {
8613 : 0 : break;
8614 : : }
8615 : : else
8616 : : {
8617 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8618 : 0 : goto exit_function;
8619 : : }
8620 : : }
8621 : : }
8622 : : }
8623 : :
8624 : : INCHI_HEAPCHK
8625 : : /* ) -> (, H, N, [-, N,], AtNum,... AtNum) */
8626 : 0 : lenTautomer = 0;
8627 [ # # ]: 0 : if ((p = t)) /* djb-rwth: addressing LLVM warning */
8628 : : {
8629 [ # # ]: 0 : if (*pbAbc == 1)
8630 : : {
8631 : : /* tautomeric groups: pass 1 */
8632 : 0 : iTGroup = 0;
8633 : 0 : state = ')'; /* init as if the prev. t-group just ended */ /* djb-rwth: ignoring LLVM warning: value used */
8634 : 0 : num_Atoms = 0;
8635 : : /* Tautomeric info storage */
8636 : : /* NumGroups; ((NumAt+2, NumH, Num(-), At1..AtNumAt),...); {INCHI_T_NUM_MOVABLE = 2} */
8637 : : /* Allocated length: [5*nNumberOfAtoms/2+1], see Alloc_INChI(...) */
8638 [ # # ]: 0 : if (*p == ',')
8639 : : { /* start t-group */
8640 : 0 : p++;
8641 : : }
8642 : : else
8643 : : {
8644 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8645 : 0 : goto exit_function;
8646 : : }
8647 [ # # ]: 0 : while (p < pEnd)
8648 : : {
8649 : : /* start t-group */
8650 [ # # # # : 0 : if (!isdigit(UCINT* p) || !(num_H = (int)inchi_strtol(p, &q, 10)) || q > pEnd)
# # ]
8651 : : {
8652 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8653 : 0 : goto exit_function;
8654 : : }
8655 : 0 : p = q;
8656 : 0 : num_Minus = 0;
8657 [ # # ]: 0 : if (*p == '-')
8658 : : {
8659 : 0 : p++;
8660 [ # # ]: 0 : if (isdigit(UCINT* p))
8661 : : {
8662 : 0 : num_Minus = (int)inchi_strtol(p, &q, 10);
8663 : 0 : p = q;
8664 : : }
8665 : : else
8666 : : {
8667 : 0 : num_Minus = 1;
8668 : : }
8669 : : }
8670 [ # # ]: 0 : if (p >= pEnd)
8671 : : {
8672 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8673 : 0 : goto exit_function;
8674 : : }
8675 [ # # ]: 0 : if (!tg_alloc_len)
8676 : : {
8677 : : /*
8678 : : --- header ---
8679 : : [num_t_groups]
8680 : : --- one t-group: ---
8681 : : [len=group length no including this value]
8682 : : [num_H]
8683 : : [num_(-)]
8684 : : [Endpoint(1),...,Endpoint(len-2)]
8685 : : --- next t-group ---
8686 : : ...
8687 : :
8688 : : Max. size = 1 + 3*max_num_t_groups + max_num_endpoints
8689 : :
8690 : : max_num_t_groups = num_at/2
8691 : : max_num_endpoints = num_at
8692 : :
8693 : : Max. size = 1 + 3*(num_at/2) + num_at = 1 + (5*num_at)/2
8694 : : 5 = 3 + INCHI_T_NUM_MOVABLE = 3 + num_types_of_attachments
8695 : :
8696 : : This does not include zero termination!
8697 : :
8698 : : */
8699 : 0 : tg_alloc_len = ((3 + INCHI_T_NUM_MOVABLE) * pInChI[iComponent].nNumberOfAtoms) / 2 + 1;
8700 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
8701 : : {
8702 : 0 : pInChI[iComponent + i].nTautomer = (AT_NUMB*)inchi_calloc((long long)tg_alloc_len + 1, sizeof(pInChI->nTautomer[0])); /* djb-rwth: cast operator added */
8703 [ # # ]: 0 : if (!pInChI[iComponent + i].nTautomer)
8704 : : {
8705 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8706 : 0 : goto exit_function;
8707 : : }
8708 : 0 : pInChI[iComponent + i].lenTautomer = 0;
8709 : : }
8710 : 0 : tg_pos_Tautomer = 1; /* number atoms (NumAt+2) position */
8711 : : }
8712 : : else
8713 : : {
8714 : : /* next t-group */
8715 : 0 : tg_pos_Tautomer = lenTautomer;
8716 : : }
8717 [ # # ]: 0 : if (tg_pos_Tautomer + 3 >= tg_alloc_len)
8718 : : {
8719 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8720 : 0 : goto exit_function;
8721 : : }
8722 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 1] = num_H;
8723 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 2] = num_Minus;
8724 : 0 : lenTautomer = tg_pos_Tautomer + 3; /* first atom number position */
8725 : 0 : num_taut_H_component += num_H;
8726 : :
8727 [ # # # # ]: 0 : while (p < pEnd && isupper(UCINT* p))
8728 : : {
8729 : : /* read list of tautomeric atoms */
8730 : 0 : val = (int)inchi_strtol(p, &q, base);
8731 [ # # # # ]: 0 : if (lenTautomer >= tg_alloc_len || val > numCtAtoms)
8732 : : {
8733 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8734 : 0 : goto exit_function;
8735 : : }
8736 : 0 : num_Atoms++;
8737 : 0 : pInChI[iComponent].nTautomer[lenTautomer++] = val;
8738 : 0 : p = q;
8739 : : }
8740 [ # # # # : 0 : if (!num_Atoms || (p < pEnd && !isdigit(UCINT * p))) /* djb-rwth: addressing LLVM warning */
# # ]
8741 : : {
8742 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8743 : 0 : goto exit_function;
8744 : : }
8745 : 0 : iTGroup++;
8746 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer] = lenTautomer - tg_pos_Tautomer - 1; /* length of the rest of the t-group */
8747 : 0 : pInChI[iComponent].lenTautomer = lenTautomer;
8748 : : }
8749 [ # # # # ]: 0 : if (!iTGroup || p != pEnd)
8750 : : {
8751 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8752 : 0 : goto exit_function;
8753 : : }
8754 : 0 : pInChI[iComponent].nTautomer[0] = iTGroup;
8755 : : }
8756 : : else
8757 : : {
8758 : : /* tautomeric groups: pass 1 */
8759 : 0 : iTGroup = 0;
8760 : 0 : state = ')'; /* init as if the prev. t-group just ended */
8761 : 0 : num_Atoms = 0;
8762 : : /* Tautomeric info storage */
8763 : : /* NumGroups; ((NumAt+2, NumH, Num(-), At1..AtNumAt),...); {INCHI_T_NUM_MOVABLE = 2} */
8764 : : /* Allocated length: [5*nNumberOfAtoms/2+1], see Alloc_INChI(...) */
8765 [ # # ]: 0 : while (p < pEnd)
8766 : : {
8767 : : /* t-group */
8768 [ # # # # : 0 : switch (*p)
# # ]
8769 : : {
8770 : 0 : case '(': /* start t-group */
8771 [ # # ]: 0 : switch (state)
8772 : : {
8773 : 0 : case ')':
8774 : 0 : state = *p++;
8775 : 0 : num_H = 0;
8776 : 0 : num_Minus = 0;
8777 : 0 : continue;
8778 : 0 : default:
8779 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8780 : 0 : goto exit_function;
8781 : : }
8782 : 0 : case ')': /* end t-group */
8783 [ # # ]: 0 : switch (state)
8784 : : {
8785 : 0 : case 'A': /* previuos was atom number */
8786 [ # # ]: 0 : if (!tg_alloc_len)
8787 : : {
8788 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8789 : 0 : goto exit_function;
8790 : : }
8791 : 0 : iTGroup++;
8792 : 0 : state = *p++;
8793 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer] = lenTautomer - tg_pos_Tautomer - 1; /* length of the rest of the t-group */
8794 : 0 : pInChI[iComponent].lenTautomer = lenTautomer;
8795 : 0 : continue;
8796 : 0 : default:
8797 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8798 : 0 : goto exit_function;
8799 : : }
8800 : 0 : case 'H': /* number of H */
8801 [ # # ]: 0 : switch (state)
8802 : : {
8803 : 0 : case '(':
8804 : 0 : state = *p++;
8805 : 0 : num_H = 1;
8806 : 0 : continue;
8807 : 0 : default:
8808 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8809 : 0 : goto exit_function;
8810 : : }
8811 : 0 : case '-': /* number of (-) */
8812 [ # # ]: 0 : switch (state)
8813 : : {
8814 : 0 : case 'N': /* previous was number of H */
8815 : : case 'H': /* previous was H */
8816 : 0 : state = *p++;
8817 : 0 : num_Minus = 1;
8818 : 0 : continue;
8819 : 0 : default:
8820 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8821 : 0 : goto exit_function;
8822 : : }
8823 : 0 : case ',':
8824 [ # # # ]: 0 : switch (state)
8825 : : {
8826 : 0 : case 'N': /* previous was number of H */
8827 : : case 'H': /* previous was H */
8828 : : case '-': /* previuos was - */
8829 : : case 'M': /* previous was number of (-) */
8830 : : /* the next must be the first tautomeric atom number; save num_H & num_Minus */
8831 [ # # # # ]: 0 : if (num_H <= 0 && num_Minus <= 0)
8832 : : {
8833 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8834 : 0 : goto exit_function;
8835 : : }
8836 [ # # ]: 0 : if (!tg_alloc_len)
8837 : : {
8838 : : /*
8839 : : --- header ---
8840 : : [num_t_groups]
8841 : : --- one t-group: ---
8842 : : [len=group length no including this value]
8843 : : [num_H]
8844 : : [num_(-)]
8845 : : [Endpoint(1),...,Endpoint(len-2)]
8846 : : --- next t-group ---
8847 : : ...
8848 : :
8849 : : Max. size = 1 + 3*max_num_t_groups + max_num_endpoints
8850 : :
8851 : : max_num_t_groups = num_at/2
8852 : : max_num_endpoints = num_at
8853 : :
8854 : : Max. size = 1 + 3*(num_at/2) + num_at = 1 + (5*num_at)/2
8855 : : 5 = 3 + INCHI_T_NUM_MOVABLE = 3 + num_types_of_attachments
8856 : :
8857 : : This does not include zero termination!
8858 : :
8859 : : */
8860 : 0 : tg_alloc_len = ((3 + INCHI_T_NUM_MOVABLE) * pInChI[iComponent].nNumberOfAtoms) / 2 + 1;
8861 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
8862 : : {
8863 : : /* djb-rwth: fixing oss-fuzz issue #68314 */
8864 : 0 : AT_NUMB* pinchi_icint = (AT_NUMB*)inchi_calloc((long long)tg_alloc_len + 1, sizeof(pInChI->nTautomer[0])); /* djb-rwth: cast operator added */
8865 [ # # ]: 0 : if (!pinchi_icint)
8866 : : {
8867 : 0 : ret = RI_ERR_ALLOC; /* allocation error */
8868 : 0 : goto exit_function;
8869 : : }
8870 : 0 : pInChI[iComponent + i].nTautomer = pinchi_icint;
8871 : 0 : pInChI[iComponent + i].lenTautomer = 0;
8872 : : }
8873 : 0 : tg_pos_Tautomer = 1; /* number atoms (NumAt+2) position */
8874 : : }
8875 : : else
8876 : : {
8877 : : /* next t-group */
8878 : 0 : tg_pos_Tautomer = lenTautomer;
8879 : : }
8880 [ # # ]: 0 : if (tg_pos_Tautomer + 3 >= tg_alloc_len)
8881 : : {
8882 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8883 : 0 : goto exit_function;
8884 : : }
8885 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 1] = num_H;
8886 : 0 : pInChI[iComponent].nTautomer[tg_pos_Tautomer + 2] = num_Minus;
8887 : 0 : lenTautomer = tg_pos_Tautomer + 3; /* first atom number position */
8888 : : /* djb-rwth: fixing GH issue #59.1 */
8889 : : if (num_H >= INT_MIN && num_H <= INT_MAX) /* djb-rwth: addressing coverity ID #499582 -- boundary check is required */
8890 : : {
8891 : 0 : num_taut_H_component += num_H;
8892 : : }
8893 : : else
8894 : : {
8895 : : ret = BNS_PROGRAM_ERR;
8896 : : goto exit_function;
8897 : : }
8898 : 0 : state = *p++;
8899 : 0 : continue;
8900 : 0 : case 'A':
8901 : : /* previuos was atom number */
8902 : 0 : state = *p++;
8903 : 0 : continue;
8904 : 0 : default:
8905 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8906 : 0 : goto exit_function;
8907 : : }
8908 : 0 : default:
8909 [ # # ]: 0 : if (isdigit(UCINT* p))
8910 : : {
8911 : 0 : val = (int)inchi_strtol(p, &q, 10);
8912 [ # # ]: 0 : if (val <= 0)
8913 : : {
8914 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8915 : 0 : goto exit_function;
8916 : : }
8917 : 0 : p = q;
8918 [ # # # # ]: 0 : switch (state)
8919 : : {
8920 : 0 : case 'H':
8921 : 0 : num_H = val;
8922 : 0 : state = 'N';
8923 : 0 : continue;
8924 : 0 : case '-':
8925 : 0 : num_Minus = val;
8926 : 0 : state = 'M';
8927 : 0 : continue;
8928 : 0 : case ',':
8929 [ # # # # ]: 0 : if (lenTautomer >= tg_alloc_len || val > numCtAtoms)
8930 : : {
8931 : 0 : ret = RI_ERR_PROGR; /* wrong tautomer array length */
8932 : 0 : goto exit_function;
8933 : : }
8934 : 0 : num_Atoms++;
8935 : 0 : pInChI[iComponent].nTautomer[lenTautomer++] = val;
8936 : 0 : state = 'A';
8937 : 0 : continue;
8938 : 0 : default:
8939 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8940 : 0 : goto exit_function;
8941 : : }
8942 : : }
8943 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8944 : 0 : goto exit_function;
8945 : : }
8946 : : }
8947 [ # # # # ]: 0 : if (!iTGroup || state != ')')
8948 : : {
8949 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8950 : 0 : goto exit_function;
8951 : : }
8952 : 0 : pInChI[iComponent].nTautomer[0] = iTGroup;
8953 : : }
8954 : : }
8955 : : /* check num_H in components; for bMobileH=TAUT_NON, pInChI->nNum_H_fixed[] has not been added to pInChI->nNum_H[] yet */
8956 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI + iComponent, &num_H_formula)) ||
8957 : 0 : 0 > (ret2 = GetInChINumH(pInChI + iComponent, &num_H_InChI)))
8958 : : {
8959 : 0 : ret = ret2;
8960 : 0 : goto exit_function;
8961 : : }
8962 [ # # # # ]: 0 : if (num_H_formula != num_H_InChI + (bMobileH == TAUT_NON ? num_H_component : 0))
8963 : : {
8964 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8965 : 0 : goto exit_function;
8966 : : }
8967 : :
8968 : : /* duplicate according to multiplication */
8969 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
8970 : : {
8971 : : #if ( FIX_GAF_2019_2==1 )
8972 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
8973 : : {
8974 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8975 : 0 : goto exit_function;
8976 : : }
8977 : :
8978 [ # # # # ]: 0 : if ((pInChI[iComponent + i].nNumberOfAtoms <= 0) || (pInChI[iComponent + i].nNumberOfAtoms > MAX_ATOMS))
8979 : : {
8980 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
8981 : 0 : goto exit_function;
8982 : : }
8983 : : #endif
8984 : : /* djb-rwth: fixing oss-fuzz issue #69699 */
8985 [ # # # # ]: 0 : if (nNum_H(iComponent)) /* djb-rwth: fixing GH issues #27/#28 */
8986 : : {
8987 [ # # # # ]: 0 : memcpy(nNum_H(iComponent + i), nNum_H(iComponent), pInChI[iComponent + i].nNumberOfAtoms * sizeof(nNum_H(0)[0]));
8988 : : }
8989 : : /*
8990 : : memcpy( pInChI[iComponent+i].nNum_H, pInChI[iComponent].nNum_H,
8991 : : pInChI[iComponent+i].nNumberOfAtoms * sizeof(pInChI[0].nNum_H[0]) );
8992 : : */
8993 [ # # # # : 0 : if (pInChI[iComponent + i].nTautomer && pInChI[iComponent].nTautomer && pInChI[iComponent].lenTautomer)
# # ]
8994 : : {
8995 : 0 : memcpy(pInChI[iComponent + i].nTautomer, pInChI[iComponent].nTautomer,
8996 : 0 : pInChI[iComponent].lenTautomer * sizeof(pInChI[0].nTautomer[0]));
8997 : 0 : pInChI[iComponent + i].lenTautomer = pInChI[iComponent].lenTautomer;
8998 : : }
8999 : : /* check num_H in components */
9000 [ # # # # ]: 0 : if (0 > (ret2 = GetInChIFormulaNumH(pInChI + iComponent + i, &num_H_formula)) ||
9001 : 0 : 0 > (ret2 = GetInChINumH(pInChI + iComponent + i, &num_H_InChI)))
9002 : : {
9003 : 0 : ret = ret2;
9004 : 0 : goto exit_function;
9005 : : }
9006 [ # # # # ]: 0 : if (num_H_formula != num_H_InChI + (bMobileH == TAUT_NON ? num_H_component : 0))
9007 : : {
9008 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9009 : 0 : goto exit_function;
9010 : : }
9011 : : }
9012 : :
9013 : : /* prepare for the next component */
9014 : 0 : iComponent += i;
9015 [ # # ]: 0 : if (*pEnd)
9016 : : {
9017 : : #if (FIX_DALKE_BUGS == 1)
9018 : : /* prevent crash on extra trailing ';' */
9019 [ # # ]: 0 : if (iComponent >= nNumComponents)
9020 : : {
9021 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: extra component */
9022 : 0 : goto exit_function;
9023 : : }
9024 : : #endif
9025 : 0 : pStart = pEnd + 1;
9026 : : }
9027 : : else
9028 : : {
9029 : 0 : break;
9030 : : }
9031 : : }
9032 : :
9033 [ # # ]: 0 : if (nNumComponents != iComponent)
9034 : : {
9035 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9036 : 0 : goto exit_function;
9037 : : }
9038 : 0 : ret = iComponent + 1;
9039 : :
9040 : 1 : exit_function:
9041 : : INCHI_HEAPCHK
9042 : :
9043 : 1 : return ret;
9044 : : }
9045 : :
9046 : :
9047 : : /****************************************************************************
9048 : : Parse "/c" InChI layer
9049 : : ****************************************************************************/
9050 : 2 : int ParseSegmentConnections(const char* str,
9051 : : int bMobileH,
9052 : : INChI** pInpInChI,
9053 : : int* pnNumComponents,
9054 : : int* pbAbc,
9055 : : int* nb_total)
9056 : : {
9057 : : #define LAST_AT_LEN 256
9058 : : /* Pass 1: count bonds and find actual numbers of atom */
9059 : : int i, j, k, m, c, mpy_component;
9060 : : int nNumComponents, iComponent, nNumAtoms, nNumBonds, lenConnTable; /* djb-rwth: removing redundant variables */
9061 : : const char* p, * q, * pStart, * pEnd;
9062 : : AT_NUMB last_atom[LAST_AT_LEN], curAtom, maxAtom;
9063 : : int num_open, state, ret, base;
9064 : 2 : INChI* pInChI = *pInpInChI;
9065 : : LINKED_BONDS LB;
9066 : 2 : LINKED_BONDS* pLB = &LB; /* a list of linked lists of bonds, for each atom */
9067 : : AT_NUMB neighbor[MAXVAL];
9068 : 2 : int bPrevVersion = -1;
9069 : :
9070 : 2 : *nb_total = 0;
9071 : 2 : iComponent = 0;
9072 : 2 : LB.pBond = NULL; /* djb-rwth: initialization required to avoid garbage values */
9073 [ + - ]: 2 : if (str[0] != 'c')
9074 : : {
9075 [ - + - - ]: 2 : if (!pInChI && !*pnNumComponents)
9076 : 0 : {
9077 : 0 : int lenFormula = 1;
9078 : : /* component has no formula; allocate InChI */
9079 : 0 : lenConnTable = 0;
9080 : 0 : nNumComponents = 1;
9081 : : /* allocate InChI */
9082 [ # # ]: 0 : if (!(pInChI = *pInpInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))
9083 : : {
9084 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9085 : : }
9086 : : /* allocate empty formula */
9087 : 0 : pInChI[iComponent].szHillFormula = (char*)inchi_calloc((long long)lenFormula + 1, sizeof(pInChI[0].szHillFormula[0])); /* djb-rwth: cast operator added */
9088 [ # # ]: 0 : if (!pInChI[iComponent].szHillFormula)
9089 : : {
9090 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9091 : 0 : goto exit_function;
9092 : : }
9093 : : /* allocate empty connection table */
9094 : 0 : pInChI[iComponent].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9095 [ # # ]: 0 : if (!pInChI[iComponent].nConnTable)
9096 : : {
9097 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9098 : 0 : goto exit_function;
9099 : : }
9100 : 0 : pInChI[iComponent].lenConnTable = lenConnTable;
9101 : 0 : *pnNumComponents = nNumComponents;
9102 : : }
9103 : : else
9104 : : {
9105 : 2 : lenConnTable = 1;
9106 : 2 : nNumComponents = *pnNumComponents;
9107 [ + + ]: 4 : for (i = 0; i < nNumComponents; i++)
9108 : : {
9109 : : /* allocate 1 atom connection table */
9110 [ + - ]: 2 : if (pInChI) /* djb-rwth: fixing a NULL pointer dereference */
9111 : : {
9112 [ - + ]: 2 : if (pInChI[i].nConnTable)
9113 : : {
9114 [ # # ]: 0 : inchi_free(pInChI[i].nConnTable);
9115 : : }
9116 : 2 : pInChI[i].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9117 [ - + ]: 2 : if (!pInChI[i].nConnTable)
9118 : : {
9119 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9120 : 0 : goto exit_function;
9121 : : }
9122 : 2 : pInChI[i].nConnTable[0] = 1;
9123 : 2 : pInChI[i].lenConnTable = lenConnTable;
9124 : : }
9125 : : }
9126 : : }
9127 : 2 : return 0;
9128 : : }
9129 : :
9130 : : /* Pass 1. Re-Count atoms, count bonds */
9131 : :
9132 : 0 : pStart = (char*)str + 1;
9133 : 0 : nNumComponents = *pnNumComponents;
9134 : : #if (FIX_DALKE_BUGS == 1)
9135 : : /* prevent crash on too many components */
9136 [ # # ]: 0 : if (nNumComponents > MAX_ATOMS)
9137 : : {
9138 : 0 : ret = RI_ERR_SYNTAX; /* syntax error: extra component */
9139 : 0 : goto exit_function;
9140 : : }
9141 : : #endif
9142 : 0 : memset(pLB, 0, sizeof(pLB[0])); /* djb-rwth: memset_s C11/Annex K variant? */
9143 : :
9144 : : while (1)
9145 : : {
9146 : : /* cycle over components */
9147 [ # # ]: 0 : if (!(pEnd = strchr(pStart, ';')))
9148 : : {
9149 : 0 : pEnd = pStart + strlen(pStart);
9150 : : }
9151 [ # # # # ]: 0 : if ((p = strchr(pStart, '*')) && p < pEnd)
9152 : : {
9153 : 0 : mpy_component = (int)inchi_strtol(pStart, &q, 10);
9154 : : #if ( CHECK_STRTOL_ATNUMB==1 )
9155 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
9156 : : {
9157 : 0 : ret = RI_ERR_SYNTAX;
9158 : 0 : goto exit_function;
9159 : : }
9160 : : #endif
9161 [ # # ]: 0 : if (p != q
9162 : : #if (FIX_DALKE_BUGS == 1)
9163 [ # # ]: 0 : || !isdigit(UCINT * pStart)
9164 : : #endif
9165 : : )
9166 : : {
9167 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9168 : 0 : goto exit_function;
9169 : : }
9170 : 0 : p++;
9171 : : }
9172 : : else
9173 : : {
9174 : 0 : mpy_component = 1;
9175 : 0 : p = pStart;
9176 : : }
9177 : : #if (FIX_DALKE_BUGS == 1)
9178 [ # # ]: 0 : if (iComponent + mpy_component > MAX_ATOMS)
9179 : : {
9180 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9181 : 0 : goto exit_function;
9182 : : }
9183 : : #endif
9184 : 0 : pStart = p;
9185 : : /* Pass 1.1 parse a component */
9186 : 0 : num_open = 0;
9187 : 0 : memset(last_atom, 0, sizeof(last_atom)); /* djb-rwth: memset_s C11/Annex K variant? */
9188 : 0 : state = '\0'; /* initial state */
9189 : 0 : maxAtom = 0;
9190 : 0 : nNumBonds = 0;
9191 : : /* djb-rwth: removing redundant code */
9192 [ # # # # ]: 0 : if (p < pEnd && *pbAbc == -1)
9193 : : {
9194 : : /* check if compressed InChI */
9195 : 0 : *pbAbc = isupper(UCINT * p) ? 1 : 0;
9196 : : }
9197 [ # # ]: 0 : base = *pbAbc ? ALPHA_BASE : 10;
9198 : :
9199 [ # # ]: 0 : if (*pbAbc == 1)
9200 : : {
9201 : 0 : nNumAtoms = 1;
9202 [ # # ]: 0 : while (p < pEnd)
9203 : : {
9204 [ # # ]: 0 : if (*p == '-')
9205 : : {
9206 [ # # ]: 0 : if (bPrevVersion == -1)
9207 : : {
9208 : : /* previous InChI version */
9209 : 0 : bPrevVersion = 1;
9210 : : }
9211 : : else
9212 [ # # ]: 0 : if (bPrevVersion != 1)
9213 : : {
9214 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9215 : 0 : goto exit_function;
9216 : : }
9217 : 0 : nNumAtoms--;
9218 : 0 : p++;
9219 : : }
9220 [ # # ]: 0 : if (isdigit(UCINT * p))
9221 : : {
9222 [ # # ]: 0 : if (bPrevVersion == -1)
9223 : : {
9224 : : /* curreny InChI, version 1 */
9225 : 0 : bPrevVersion = 0;
9226 : : }
9227 : : else
9228 [ # # ]: 0 : if (bPrevVersion != 0)
9229 : : {
9230 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9231 : 0 : goto exit_function;
9232 : : }
9233 : 0 : nNumAtoms -= inchi_strtol(p, &p, 10); /* bypass digits */
9234 : : }
9235 [ # # # # ]: 0 : if (*p != '-' && (curAtom = (AT_NUMB)inchi_strtol(p, &q, base)))
9236 : : {
9237 : 0 : nNumAtoms++;
9238 : 0 : nNumBonds++;
9239 : 0 : p = q;
9240 [ # # ]: 0 : if (maxAtom < curAtom)
9241 : 0 : maxAtom = curAtom;
9242 : : }
9243 : : else
9244 : : {
9245 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9246 : 0 : goto exit_function;
9247 : : }
9248 : : }
9249 [ # # # # ]: 0 : if (maxAtom < nNumAtoms && nNumBonds)
9250 : : {
9251 : 0 : maxAtom = nNumAtoms;
9252 : : }
9253 : : }
9254 : : else
9255 : : {
9256 [ # # ]: 0 : while (p < pEnd)
9257 : : {
9258 : : /* atom number */
9259 : 0 : c = UCINT * p++;
9260 [ # # ]: 0 : switch (c)
9261 : : {
9262 : 0 : case '(':
9263 : : case ')':
9264 : : case ',':
9265 : : case '-':
9266 [ # # ]: 0 : if (state != 'N')
9267 : : {
9268 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9269 : 0 : goto exit_function;
9270 : : }
9271 : 0 : state = c;
9272 : 0 : num_open += (c == '(') - (c == ')');
9273 [ # # ]: 0 : if (num_open < 0)
9274 : : {
9275 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9276 : 0 : goto exit_function;
9277 : : }
9278 : 0 : break;
9279 : 0 : default:
9280 [ # # # # ]: 0 : if (isdigit(c) && (curAtom = (AT_NUMB)inchi_strtol(p - 1, &q, 10)))
9281 : : {
9282 : 0 : p = q;
9283 [ # # # ]: 0 : switch (state)
9284 : : {
9285 : 0 : case '(':
9286 : : case ')':
9287 : : case ',':
9288 : : case '-':
9289 : 0 : nNumBonds++;
9290 : 0 : case '\0':
9291 [ # # ]: 0 : if (maxAtom < curAtom)
9292 : 0 : maxAtom = curAtom;
9293 : 0 : state = 'N';
9294 : 0 : break;
9295 : 0 : default:
9296 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9297 : 0 : goto exit_function;
9298 : : }
9299 : : }
9300 : : else
9301 : : {
9302 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9303 : 0 : goto exit_function;
9304 : : }
9305 : 0 : break;
9306 : : }
9307 : : }
9308 [ # # ]: 0 : if (num_open)
9309 : : {
9310 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9311 : 0 : goto exit_function;
9312 : : /* syntax error: parentheses do not match */
9313 : : }
9314 : : }
9315 : 0 : (*nb_total) += nNumBonds;
9316 : :
9317 : : /* Save the results and allocate memory */
9318 : 0 : nNumAtoms = (int)maxAtom; /* 0 if empty connection table and no bonds present */
9319 : 0 : lenConnTable = nNumAtoms + nNumBonds;
9320 : :
9321 : : /* connection table format: At1[,Neigh11,Neigh12,...],At2[,Neigh21,Neigh22,...],AtN[NeighN1,NeighN2,...] */
9322 : : /* where AtK > NeighK1 > NeighK2,...; At(K) < At(K+1); the length = num.atoms + num.bonds */
9323 [ # # ]: 0 : for (i = 0; i < mpy_component; i++)
9324 : : {
9325 : : #if ( FIX_GAF_2019_2==1 )
9326 [ # # # # ]: 0 : if ((iComponent + i > nNumComponents - 1) || (iComponent + i < 0))
9327 : : {
9328 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9329 : 0 : goto exit_function;
9330 : : }
9331 [ # # # # ]: 0 : if (pInChI[iComponent + i].nNumberOfAtoms <= 0 || pInChI[iComponent + i].nNumberOfAtoms > MAX_ATOMS)
9332 : : {
9333 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9334 : 0 : goto exit_function;
9335 : : }
9336 : : #endif
9337 : : /* check number of atoms: the difference may be due to bridging H */
9338 [ # # ]: 0 : if ((j = pInChI[iComponent + i].nNumberOfAtoms) < nNumAtoms)
9339 : : {
9340 : : /* reallocate */
9341 : 0 : U_CHAR* nAtomTmp = (U_CHAR*)inchi_malloc((long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
9342 [ # # ]: 0 : if (!nAtomTmp)
9343 : : {
9344 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9345 : 0 : goto exit_function;
9346 : : }
9347 : 0 : memcpy(nAtomTmp, pInChI[iComponent + i].nAtom, sizeof(nAtomTmp[0]) * j);
9348 [ # # ]: 0 : while (j < nNumAtoms)
9349 : : {
9350 : 0 : nAtomTmp[j++] = EL_NUMBER_H; /* bridging H */
9351 : : }
9352 : 0 : nAtomTmp[j] = '\0';
9353 : : INCHI_HEAPCHK
9354 [ # # ]: 0 : if (pInChI[iComponent + i].nAtom)
9355 : : {
9356 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
9357 : : }
9358 : 0 : pInChI[iComponent + i].nAtom = nAtomTmp;
9359 : 0 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtoms;
9360 : : }
9361 : : else
9362 : : {
9363 [ # # # # : 0 : if (j > nNumAtoms && (lenConnTable || j != 1))
# # ]
9364 : : {
9365 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9366 : 0 : goto exit_function;
9367 : : }
9368 : : }
9369 : : /* allocate connection table */
9370 [ # # ]: 0 : if (pInChI[iComponent + i].nConnTable)
9371 : : {
9372 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nConnTable);
9373 : : }
9374 [ # # # # : 0 : if (!nNumAtoms && !nNumBonds && !lenConnTable)
# # ]
9375 : : {
9376 : 0 : lenConnTable = 1; /* one atom, no bonds */
9377 : : }
9378 : 0 : pInChI[iComponent + i].nConnTable = (AT_NUMB*)inchi_calloc((long long)lenConnTable + 1, sizeof(pInChI[0].nConnTable[0])); /* djb-rwth: cast operator added */
9379 [ # # ]: 0 : if (!pInChI[iComponent + i].nConnTable)
9380 : : {
9381 : 0 : ret = RI_ERR_ALLOC; /* allocation failure */
9382 : 0 : goto exit_function;
9383 : : }
9384 : 0 : pInChI[iComponent + i].lenConnTable = lenConnTable;
9385 : : }
9386 : :
9387 : : /* Pass 1.2 parse a component and extract the bonds */
9388 : 0 : num_open = 0;
9389 : 0 : memset(last_atom, 0, sizeof(last_atom)); /* djb-rwth: memset_s C11/Annex K variant? */
9390 : 0 : state = '\0'; /* initial state */
9391 : : /* djb-rwth: removing redundant code */
9392 : 0 : p = pStart;
9393 : 0 : pLB->len = 0;
9394 : :
9395 [ # # ]: 0 : if (*pbAbc == 1)
9396 : : {
9397 : : /* compressed */
9398 : : int num_neigh;
9399 : 0 : num_open = 0;
9400 : 0 : last_atom[num_open] = 2;
9401 [ # # ]: 0 : while (p < pEnd)
9402 : : {
9403 [ # # ]: 0 : if (last_atom[num_open] > maxAtom)
9404 : : {
9405 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9406 : 0 : goto exit_function;
9407 : : }
9408 [ # # ]: 0 : if (isupper(UCINT * p))
9409 : : {
9410 : 0 : curAtom = (AT_NUMB)inchi_strtol(p, &q, base);
9411 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9412 : : {
9413 : 0 : goto exit_function;
9414 : : }
9415 : 0 : p = q;
9416 [ # # ]: 0 : if (bPrevVersion == 1)
9417 : : {
9418 [ # # # # ]: 0 : while (p < pEnd && *p == '-')
9419 : : {
9420 : 0 : p++;
9421 [ # # ]: 0 : if ((curAtom = (AT_NUMB)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
9422 : : {
9423 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9424 : : {
9425 : 0 : goto exit_function;
9426 : : }
9427 : 0 : p = q;
9428 : : }
9429 : : else
9430 : : {
9431 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9432 : 0 : goto exit_function;
9433 : : }
9434 : : }
9435 : : }
9436 : : else
9437 : : {
9438 [ # # # # ]: 0 : if (bPrevVersion == 0 && isdigit(*p))
9439 : : {
9440 : 0 : num_neigh = (int)inchi_strtol(p, &q, 10);
9441 : 0 : p = q;
9442 [ # # # # ]: 0 : while (num_neigh-- && p < pEnd)
9443 : : {
9444 [ # # ]: 0 : if ((curAtom = (AT_NUMB)inchi_strtol(p, &q, base))) /* djb-rwth: addressing LLVM warning */
9445 : : {
9446 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9447 : : {
9448 : 0 : goto exit_function;
9449 : : }
9450 : 0 : p = q;
9451 : : }
9452 : : else
9453 : : {
9454 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9455 : 0 : goto exit_function;
9456 : : }
9457 : : }
9458 : : }
9459 : : }
9460 : 0 : last_atom[num_open]++;
9461 : : }
9462 : : else
9463 : : {
9464 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9465 : 0 : goto exit_function;
9466 : : }
9467 : : }
9468 : : }
9469 : : else
9470 : : {
9471 [ # # ]: 0 : while (p < pEnd)
9472 : : {
9473 : : /* each atom number except the first means a new bond */
9474 : 0 : c = UCINT * p++;
9475 [ # # ]: 0 : switch (c)
9476 : : {
9477 : 0 : case '(':
9478 : : case ')':
9479 : : case ',':
9480 : : case '-':
9481 [ # # ]: 0 : switch (state)
9482 : : {
9483 : 0 : case 'N':
9484 : 0 : state = c;
9485 : 0 : break;
9486 : 0 : default:
9487 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9488 : 0 : goto exit_function;
9489 : : }
9490 : 0 : break;
9491 : 0 : default:
9492 [ # # # # ]: 0 : if (isdigit(c) && (curAtom = (AT_NUMB)inchi_strtol(p - 1, &q, 10)))
9493 : : {
9494 : 0 : p = q;
9495 [ # # # # : 0 : switch (state)
# # ]
9496 : : {
9497 : 0 : case '\0':
9498 : 0 : last_atom[num_open] = curAtom;
9499 : 0 : state = 'N';
9500 : 0 : break;
9501 : 0 : case '(':
9502 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9503 : : {
9504 : 0 : goto exit_function;
9505 : : }
9506 [ # # ]: 0 : if (++num_open >= LAST_AT_LEN)
9507 : : {
9508 : 0 : ret = RI_ERR_PROGR; /* program error: buffer overflow */
9509 : 0 : goto exit_function;
9510 : : }
9511 : 0 : last_atom[num_open] = curAtom;
9512 : 0 : state = 'N';
9513 : 0 : break;
9514 : :
9515 : 0 : case ')':
9516 [ # # ]: 0 : if (!num_open)
9517 : : {
9518 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9519 : 0 : goto exit_function;
9520 : : }
9521 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[--num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9522 : : {
9523 : 0 : goto exit_function;
9524 : : }
9525 : 0 : last_atom[num_open] = curAtom;
9526 : 0 : state = 'N';
9527 : 0 : break;
9528 : :
9529 : 0 : case ',':
9530 [ # # ]: 0 : if (!num_open)
9531 : : {
9532 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9533 : 0 : goto exit_function;
9534 : : }
9535 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open - 1], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9536 : : {
9537 : 0 : goto exit_function;
9538 : : }
9539 : 0 : last_atom[num_open] = curAtom;
9540 : 0 : state = 'N';
9541 : 0 : break;
9542 : 0 : case '-':
9543 [ # # ]: 0 : if ((ret = AddLinkedBond(last_atom[num_open], curAtom, (AT_NUMB)nNumAtoms, pLB))) /* djb-rwth: addressing LLVM warning */
9544 : : {
9545 : 0 : goto exit_function;
9546 : : }
9547 : 0 : last_atom[num_open] = curAtom;
9548 : 0 : state = 'N';
9549 : 0 : break;
9550 : 0 : default:
9551 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9552 : 0 : goto exit_function;
9553 : : }
9554 : : }
9555 : : else
9556 : : {
9557 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9558 : 0 : goto exit_function;
9559 : : }
9560 : 0 : break;
9561 : : }
9562 : : }
9563 : : }
9564 : :
9565 : : /* Store the bonds in connection table */
9566 [ # # ]: 0 : if (lenConnTable > 1)
9567 : : {
9568 [ # # ]: 0 : for (i = 0, m = 0; i < nNumAtoms; i++)
9569 : : {
9570 : 0 : k = 0;
9571 : :
9572 [ # # ]: 0 : if (!pLB->pBond)
9573 : : {
9574 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9575 : 0 : goto exit_function;
9576 : : }
9577 : :
9578 [ # # ]: 0 : if ((j = pLB->pBond[i + 1].prev)) /* djb-rwth: addressing LLVM warning */
9579 : : {
9580 [ # # ]: 0 : while (k < MAXVAL)
9581 : : {
9582 : 0 : neighbor[k++] = pLB->pBond[j].neigh;
9583 [ # # ]: 0 : if (j == i + 1)
9584 : 0 : break;
9585 : 0 : j = pLB->pBond[j].prev;
9586 : : }
9587 : : }
9588 [ # # ]: 0 : if (j != i + 1)
9589 : : {
9590 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9591 : 0 : goto exit_function;
9592 : : }
9593 : :
9594 : : /* sort the neighbors */
9595 : :
9596 : 0 : insertions_sort_AT_NUMB(neighbor, k);
9597 : :
9598 [ # # ]: 0 : if (m == pInChI[iComponent].lenConnTable)
9599 : : {
9600 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9601 : 0 : goto exit_function;
9602 : : }
9603 : :
9604 : : #if ( FIX_GAF_2020_25726==1 )
9605 [ # # ]: 0 : for (j = 1; j < k; j++)
9606 : : {
9607 [ # # ]: 0 : if (neighbor[j] == neighbor[j - 1])
9608 : : {
9609 : 0 : ret = RI_ERR_SYNTAX; /* syntax error - same nbr twice, i.e. multiple bond between same atoms */
9610 : 0 : goto exit_function;
9611 : : }
9612 : : }
9613 : : #endif
9614 : 0 : pInChI[iComponent].nConnTable[m++] = i + 1; /* atom number */
9615 [ # # # # ]: 0 : for (j = 0; j < k && (int)neighbor[j] <= i; j++)
9616 : : {
9617 [ # # ]: 0 : if (m == pInChI[iComponent].lenConnTable)
9618 : : {
9619 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
9620 : 0 : goto exit_function;
9621 : : }
9622 : 0 : pInChI[iComponent].nConnTable[m++] = neighbor[j];
9623 : : }
9624 : : }
9625 [ # # ]: 0 : if (m != lenConnTable)
9626 : : {
9627 : 0 : ret = RI_ERR_PROGR; /* program error */
9628 : 0 : goto exit_function;
9629 : : }
9630 : : }
9631 : : else
9632 : : {
9633 : 0 : pInChI[iComponent].nConnTable[0] = 1; /* single atom */
9634 : : }
9635 : :
9636 : : /* Duplicate if needed */
9637 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
9638 : : {
9639 : : /*
9640 : : if ( pInChI[iComponent+i].nConnTable ) {
9641 : : inchi_free( pInChI[iComponent+i].nConnTable );
9642 : : }
9643 : : pInChI[iComponent+i].nConnTable = (AT_NUMB *)inchi_calloc( lenConnTable+1, sizeof(pInChI[0].nConnTable[0]) );
9644 : : if ( !pInChI[iComponent+i].nConnTable ) {
9645 : : ret = RI_ERR_ALLOC;
9646 : : goto exit_function;
9647 : : }
9648 : : */
9649 [ # # # # ]: 0 : if (!pInChI[iComponent + i].nConnTable || pInChI[iComponent + i].lenConnTable != lenConnTable)
9650 : : {
9651 : 0 : ret = RI_ERR_PROGR;
9652 : 0 : goto exit_function;
9653 : : }
9654 : 0 : memcpy(pInChI[iComponent + i].nConnTable, pInChI[iComponent].nConnTable, lenConnTable * sizeof(pInChI[0].nConnTable[0]));
9655 : : }
9656 : : /* prepare for the next connection table */
9657 : 0 : iComponent += i;
9658 [ # # ]: 0 : if (*pEnd)
9659 : 0 : pStart = pEnd + 1;
9660 : : else
9661 : 0 : break;
9662 : : /* We must check if we have already read as many components as we have in the fragment. */
9663 : : /* If yes, then we break, because anything else that might follow cannot be useful information. */
9664 : : /* There are files with a trailing ";" that would cause a problem (memory allocation bug) if we did not do this. */
9665 [ # # ]: 0 : if (iComponent == nNumComponents)
9666 : 0 : break;
9667 : : }
9668 : 0 : ret = iComponent;
9669 : :
9670 : 0 : exit_function:
9671 : :
9672 [ # # ]: 0 : if (pLB->pBond)
9673 : : {
9674 : : INCHI_HEAPCHK
9675 [ # # ]: 0 : inchi_free(pLB->pBond);
9676 : : }
9677 : :
9678 : 0 : return ret;
9679 : : #undef LAST_AT_LEN
9680 : : }
9681 : :
9682 : :
9683 : : /****************************************************************************/
9684 : 0 : int nFillOutProtonMobileH(INChI* pInChI)
9685 : : {
9686 : 0 : int len = 1;
9687 : 0 : pInChI->bDeleted = 1;
9688 : : /* formula */
9689 [ # # ]: 0 : if (!pInChI->szHillFormula &&
9690 [ # # ]: 0 : !(pInChI->szHillFormula = (char*)inchi_calloc((long long)len + 1, sizeof(pInChI->szHillFormula[0])))) /* djb-rwth: cast operator added */
9691 : : {
9692 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9693 : : }
9694 : 0 : strcpy(pInChI->szHillFormula, "H");
9695 : 0 : pInChI->nNumberOfAtoms = 1;
9696 : :
9697 : : /* atoms */
9698 [ # # ]: 0 : if (!pInChI->nAtom &&
9699 [ # # ]: 0 : !(pInChI->nAtom = (U_CHAR*)inchi_calloc((long long)len + 1, sizeof(pInChI->nAtom[0])))) /* djb-rwth: cast operator added */
9700 : : {
9701 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9702 : : }
9703 : 0 : pInChI->nAtom[0] = 1;
9704 : : /* charge */
9705 : 0 : pInChI->nTotalCharge = 1;
9706 : : /* connection table */
9707 [ # # ]: 0 : if (!pInChI->nConnTable &&
9708 [ # # ]: 0 : !(pInChI->nConnTable = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pInChI->nConnTable[0])))) /* djb-rwth: cast operator added */
9709 : : {
9710 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9711 : : }
9712 : 0 : pInChI->nConnTable[0] = 1;
9713 : 0 : pInChI->lenConnTable = len;
9714 : : /* tautomer */
9715 [ # # ]: 0 : if (!pInChI->nTautomer &&
9716 [ # # ]: 0 : !(pInChI->nTautomer = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pInChI->nTautomer[0])))) /* djb-rwth: cast operator added */
9717 : : {
9718 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9719 : : }
9720 : : /* nNum_H */
9721 [ # # ]: 0 : if (!pInChI->nNum_H &&
9722 [ # # ]: 0 : !(pInChI->nNum_H = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pInChI->nNum_H[0])))) /* djb-rwth: cast operator added */
9723 : : {
9724 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9725 : : }
9726 : 0 : pInChI->nNum_H[0] = 0;
9727 : :
9728 : 0 : pInChI->nTautomer[0] = 0;
9729 : 0 : pInChI->lenTautomer = 1;
9730 : :
9731 : 0 : return 0;
9732 : : }
9733 : :
9734 : :
9735 : : /****************************************************************************/
9736 : 0 : int nProtonCopyIsotopicInfo(INChI* pInChI_to, INChI* pInChI_from)
9737 : : {
9738 [ # # ]: 0 : if (pInChI_from->nNumberOfIsotopicAtoms)
9739 : : {
9740 [ # # ]: 0 : if (pInChI_to->nNumberOfIsotopicAtoms &&
9741 [ # # ]: 0 : pInChI_from->nNumberOfIsotopicAtoms > pInChI_to->nNumberOfIsotopicAtoms)
9742 : : {
9743 : :
9744 [ # # ]: 0 : inchi_free(pInChI_to->IsotopicAtom);
9745 : 0 : pInChI_to->IsotopicAtom = NULL;
9746 : 0 : pInChI_to->nNumberOfIsotopicAtoms = 0;
9747 : : }
9748 [ # # ]: 0 : if (!pInChI_to->IsotopicAtom &&
9749 : 0 : !(pInChI_to->IsotopicAtom =
9750 [ # # ]: 0 : (INChI_IsotopicAtom*)inchi_calloc(pInChI_from->nNumberOfIsotopicAtoms,
9751 : : sizeof(pInChI_to->IsotopicAtom[0]))))
9752 : : {
9753 : 0 : return RI_ERR_ALLOC;
9754 : : }
9755 : 0 : pInChI_to->nNumberOfIsotopicAtoms = pInChI_from->nNumberOfIsotopicAtoms;
9756 : 0 : memcpy(pInChI_to->IsotopicAtom, pInChI_from->IsotopicAtom,
9757 : 0 : pInChI_from->nNumberOfIsotopicAtoms * sizeof(pInChI_to->IsotopicAtom[0]));
9758 : : }
9759 : : else
9760 : : {
9761 [ # # ]: 0 : if (pInChI_to->IsotopicAtom)
9762 : : {
9763 [ # # ]: 0 : inchi_free(pInChI_to->IsotopicAtom);
9764 : : }
9765 : 0 : pInChI_to->IsotopicAtom = NULL;
9766 : 0 : pInChI_to->nNumberOfIsotopicAtoms = 0;
9767 : : }
9768 : :
9769 : 0 : return 0;
9770 : : }
9771 : :
9772 : :
9773 : : /****************************************************************************
9774 : : Parse InChI formula layer
9775 : : ****************************************************************************/
9776 : 2 : int ParseSegmentFormula(const char* str,
9777 : : int bMobileH,
9778 : : INChI* pInpInChI[],
9779 : : int pnNumComponents[],
9780 : : int* na_total)
9781 : : {
9782 : : int i, j, mpy_component, mpy_atom, len, el_number;
9783 [ + - ]: 2 : int nNumComponents = 0, iComponent, nNumAtoms, nNumAtomsAndH, iAtom, nNumH, nAltMobileH = ALT_TAUT(bMobileH);
9784 : : const char* p, * q, * e, * pStart, * pEnd;
9785 : : INChI* pInChI;
9786 : : char szEl[3];
9787 : : #if ( FIX_GAF_2019_2==1 )
9788 : : /* hack: state passed in *na_total (will be updated in ParseSegmentFormula anyway) */
9789 : 2 : int state = *na_total;
9790 : : #endif
9791 : 2 : nNumAtoms = -999; /* impossible value */
9792 : 2 : *na_total = 0;
9793 : :
9794 : : /* Pass 1. Count components */
9795 : :
9796 : 2 : pStart = (char*)str;
9797 : : while (1)
9798 : : {
9799 [ + - ]: 2 : if (!(pEnd = strchr(pStart, '.')))
9800 : : {
9801 : 2 : pEnd = pStart + strlen(pStart);
9802 : : }
9803 : 2 : p = pStart;
9804 [ - + ]: 2 : if (isdigit(*p))
9805 : : {
9806 : 0 : mpy_component = (int)inchi_strtol(p, &q, 10);
9807 : 0 : p = q;
9808 : : }
9809 : : else
9810 : : {
9811 : 2 : mpy_component = 1;
9812 : : }
9813 [ - + ]: 2 : if (!mpy_component)
9814 : : {
9815 : 0 : break;
9816 : : }
9817 [ - + ]: 2 : if (!isupper(UCINT * p))
9818 : : {
9819 : 0 : break; /* not a formula layer */
9820 : : }
9821 [ - + ]: 2 : if (pEnd == p)
9822 : : {
9823 : 0 : break; /* zero length formula */
9824 : : }
9825 : 2 : nNumComponents += mpy_component;
9826 [ - + ]: 2 : if (*pEnd)
9827 : : {
9828 : 0 : pStart = pEnd + 1;
9829 : : }
9830 : : else
9831 : : {
9832 : 2 : break;
9833 : : }
9834 : : }
9835 : 2 : pnNumComponents[bMobileH] = nNumComponents;
9836 : : #if ( FIX_GAF_2019_1==1 )
9837 [ - + ]: 2 : if (nNumComponents > MAX_ATOMS)
9838 : : {
9839 : 0 : pnNumComponents[bMobileH] = 0;
9840 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9841 : : }
9842 : : /* pnNumComponents was not reset to 0 which results
9843 : : in attempt then to free() garbage at
9844 : : Free_INChI_Stereo ( <-- Free_INChI_Members <-- FreeInpInChI ) */
9845 : : #elif ( FIX_DALKE_BUGS == 1 )
9846 : : if (nNumComponents > MAX_ATOMS)
9847 : : {
9848 : : return RI_ERR_SYNTAX; /* syntax error */
9849 : : }
9850 : : #endif
9851 : : /* exit or error check */
9852 [ - + ]: 2 : if (!nNumComponents)
9853 : : {
9854 : : #if ( FIX_GAF_2019_2==1 )
9855 : 0 : int low_case = 0;
9856 [ # # ]: 0 : if (*pStart)
9857 : : {
9858 : 0 : low_case = islower(UCINT * pStart);
9859 : : }
9860 [ # # # # ]: 0 : if (!*pStart || low_case) {
9861 [ # # ]: 0 : if (low_case)
9862 : : {
9863 [ # # ]: 0 : if (state == IST_MOBILE_H_FORMULA)
9864 : : {
9865 [ # # # # ]: 0 : if (*pStart != 'q' && *pStart != 'p')
9866 : : {
9867 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9868 : : }
9869 : : }
9870 : : /*
9871 : : else if (state == IST_FIXED_H_FORMULA)
9872 : : {
9873 : : if (*pStart != 'h' && *pStart != 'i' && *pStart != 'b' && *pStart != 'q' && *pStart != 'p')
9874 : : {
9875 : : return RI_ERR_SYNTAX;
9876 : : }
9877 : : }*/
9878 : : }
9879 : : #else
9880 : : if (!*pStart || islower(UCINT * pStart)) {
9881 : : #endif
9882 : :
9883 : : INCHI_HEAPCHK
9884 [ # # # # ]: 0 : if (bMobileH == TAUT_NON && 0 < (nNumComponents = pnNumComponents[nAltMobileH]))
9885 : : {
9886 : : /* allocate InChI */
9887 : 0 : pInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI));
9888 [ # # ]: 0 : if (!(pInChI))
9889 : : {
9890 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9891 : : }
9892 : 0 : pInpInChI[bMobileH] = pInChI;
9893 : 0 : pnNumComponents[bMobileH] = nNumComponents;
9894 : : /* djb-rwth: fixing oss-fuzz issue #66985, #66718 */
9895 : : /* U_CHAR** piibmi_na = (U_CHAR**)inchi_malloc(nNumComponents * sizeof(U_CHAR*));
9896 : : char** piibmi_shf = (char**)inchi_malloc(nNumComponents * sizeof(char*)); */
9897 [ # # ]: 0 : for (i = 0; i < nNumComponents; i++)
9898 : : {
9899 : 0 : U_CHAR* piibmi_na = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
9900 : 0 : char* piibmi_shf = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
9901 : : /* copy number of atoms */
9902 : 0 : len = pInpInChI[bMobileH][i].nNumberOfAtoms = pInpInChI[nAltMobileH][i].nNumberOfAtoms;
9903 : : /* copy atoms */
9904 : 0 : len = (len + 1) * sizeof(pInpInChI[0][0].nAtom[0]);
9905 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nAtom)
9906 : : {
9907 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].nAtom);
9908 : : }
9909 : 0 : piibmi_na = (U_CHAR*)inchi_malloc(((long long)len + 1) * sizeof(pInpInChI[0][0].nAtom[0]));
9910 [ # # ]: 0 : if (piibmi_na) /* djb-rwth: cast operator added; addressing LLVM warning */
9911 : : {
9912 : 0 : memcpy(piibmi_na, pInpInChI[nAltMobileH][i].nAtom, len);
9913 : 0 : piibmi_na[len] = 0;
9914 : 0 : pInpInChI[bMobileH][i].nAtom = piibmi_na;
9915 : : }
9916 : : else
9917 : : {
9918 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9919 : : }
9920 : : /* copy Hill formula */
9921 : 0 : len = (int)strlen(pInpInChI[nAltMobileH][i].szHillFormula) + 1;
9922 [ # # ]: 0 : if (pInpInChI[bMobileH][i].szHillFormula)
9923 : : {
9924 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].szHillFormula);
9925 : : }
9926 : 0 : piibmi_shf = (char*)inchi_malloc((inchi_max(len, 2)) * sizeof(char));
9927 [ # # ]: 0 : if (piibmi_shf) /* djb-rwth: addressing LLVM warning */
9928 : : {
9929 : 0 : memcpy(piibmi_shf, pInpInChI[nAltMobileH][i].szHillFormula, len);
9930 : 0 : pInpInChI[bMobileH][i].szHillFormula = piibmi_shf;
9931 : : }
9932 : : else
9933 : : {
9934 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9935 : : }
9936 : : }
9937 : : }
9938 : : else
9939 : : {
9940 [ # # ]: 0 : if (bMobileH == TAUT_YES)
9941 : : {
9942 : : int ret;
9943 : : /* allocate InChI */
9944 : 0 : nNumComponents = 1;
9945 : : /* InChI */
9946 : 0 : pnNumComponents[bMobileH] = nNumComponents;
9947 [ # # ]: 0 : if (!(pInChI = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))
9948 : : {
9949 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9950 : : }
9951 : 0 : pInpInChI[bMobileH] = pInChI;
9952 : 0 : ret = nFillOutProtonMobileH(pInChI);
9953 [ # # ]: 0 : if (ret < 0)
9954 : : {
9955 : 0 : return ret;
9956 : : }
9957 : : }
9958 : : }
9959 : 0 : return 0;
9960 : : }
9961 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9962 : : }
9963 : :
9964 [ - + ]: 2 : if (*pEnd)
9965 : : {
9966 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9967 : : }
9968 : :
9969 : : /* allocate InChI */
9970 [ - + ]: 2 : if (!((sizeof(INChI) > 0) && (pInpInChI[bMobileH] = (INChI*)inchi_calloc(nNumComponents, sizeof(INChI))))) /* djb-rwth: fixing GH issue #58 */
9971 : : {
9972 : 0 : return RI_ERR_ALLOC; /* alloc failure */
9973 : : }
9974 : 2 : pInChI = pInpInChI[bMobileH];
9975 : :
9976 : : /* Pass 2. Count elements, save formulas and elements */
9977 : 2 : pStart = (char*)str;
9978 : 2 : iComponent = 0;
9979 : : while (1)
9980 : : {
9981 [ + - ]: 2 : if (!(pEnd = strchr(pStart, '.')))
9982 : : {
9983 : 2 : pEnd = pStart + strlen(pStart);
9984 : : }
9985 : 2 : p = pStart;
9986 [ - + ]: 2 : if (isdigit(UCINT * p))
9987 : : {
9988 : 0 : mpy_component = (int)inchi_strtol(p, &q, 10);
9989 : : #if ( CHECK_STRTOL_ATNUMB==1 )
9990 [ # # # # ]: 0 : if (mpy_component > MAX_ATOMS || mpy_component < 0)
9991 : : {
9992 : 0 : return RI_ERR_SYNTAX; /* syntax error */
9993 : : }
9994 : : #endif
9995 : 0 : p = q;
9996 : : }
9997 : : else
9998 : : {
9999 : 2 : mpy_component = 1;
10000 : : }
10001 : : #if ( FIX_DALKE_BUGS == 1 )
10002 [ - + ]: 2 : if (iComponent + mpy_component > MAX_ATOMS)
10003 : : {
10004 : : #if ( FIX_GAF_2019_1==1 )
10005 : 0 : nNumComponents = 0; /* djb-rwth: ignoring LLVM warning: value used */
10006 : : #endif
10007 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10008 : : }
10009 : : #endif
10010 : 2 : len = (int)(pEnd - p);
10011 [ + + ]: 4 : for (i = 0; i < mpy_component; i++)
10012 : : {
10013 [ - + ]: 2 : if (iComponent + i >= nNumComponents)
10014 : : {
10015 : 0 : return RI_ERR_SYNTAX;
10016 : : }
10017 [ - + ]: 2 : if (pInChI[iComponent + i].szHillFormula)
10018 : : {
10019 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].szHillFormula);
10020 : : }
10021 : 2 : pInChI[iComponent + i].szHillFormula = (char*)inchi_malloc(inchi_max((long long)len, 1) + 1); /* djb-rwth: cast operator added */
10022 [ + - ]: 2 : if (pInChI[iComponent + i].szHillFormula) /* djb-rwth: fixing a NULL pointer dereference */
10023 : : {
10024 : 2 : memcpy(pInChI[iComponent].szHillFormula, p, len);
10025 : 2 : pInChI[iComponent + i].szHillFormula[len] = '\0';
10026 : : }
10027 : : else
10028 : : {
10029 : 0 : return RI_ERR_ALLOC; /* djb-rwth: memory could not be allocated */
10030 : : }
10031 [ + - ]: 2 : if (!i)
10032 : : {
10033 : : /* Pass 2.1 Parse formula and count atoms except H */
10034 : 2 : nNumAtoms = 0;
10035 : 2 : nNumH = 0;
10036 : : /* djb-rwth: removing redundant code */
10037 : 2 : e = pInChI[iComponent].szHillFormula;
10038 [ + - + + ]: 4 : while (e && *e) /* djb-rwth: fixing a NULL pointer dereference */
10039 : : {
10040 [ - + ]: 2 : if (!isupper(UCINT * e))
10041 : : {
10042 : 0 : return RI_ERR_SYNTAX;
10043 : : }
10044 : 2 : j = 0;
10045 : 2 : szEl[j++] = *e++;
10046 [ - + - - ]: 2 : if (*e && islower(UCINT * e))
10047 : 0 : szEl[j++] = *e++;
10048 : 2 : szEl[j++] = '\0';
10049 [ - + - - ]: 2 : if (*e && isdigit(UCINT * e))
10050 : : {
10051 : 0 : mpy_atom = (int)inchi_strtol(e, &q, 10);
10052 : : #if ( CHECK_STRTOL_ATNUMB==1 )
10053 [ # # # # ]: 0 : if (mpy_atom > MAX_ATOMS || mpy_atom < 0)
10054 : : {
10055 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10056 : : }
10057 : : #endif
10058 : 0 : e = q;
10059 : : }
10060 : : else
10061 : : {
10062 : 2 : mpy_atom = 1;
10063 : : }
10064 [ - + ]: 2 : if (!mpy_atom)
10065 : : {
10066 : 0 : return RI_ERR_SYNTAX;
10067 : : }
10068 [ + + + - ]: 2 : if (szEl[0] == 'H' && !szEl[1])
10069 : : {
10070 : 1 : nNumH += mpy_atom;
10071 : 1 : continue; /* ignore H in counting number of atoms */
10072 : : }
10073 : 1 : nNumAtoms += mpy_atom;
10074 : : }
10075 : : #if ( FIX_DALKE_BUGS == 1 )
10076 [ - + ]: 2 : if (nNumAtoms > MAX_ATOMS)
10077 : : {
10078 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10079 : : }
10080 : : #endif
10081 : 2 : (*na_total) += mpy_component * nNumAtoms;
10082 : :
10083 [ + + ]: 2 : nNumAtomsAndH = nNumAtoms ? nNumAtoms : (nNumH > 0);
10084 : 2 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtomsAndH;
10085 [ - + ]: 2 : if (pInChI[iComponent + i].nAtom)
10086 : : {
10087 [ # # ]: 0 : inchi_free(pInChI[iComponent + i].nAtom);
10088 : : }
10089 : 2 : pInChI[iComponent + i].nAtom = (U_CHAR*)inchi_malloc(((long long)nNumAtomsAndH + 1) * sizeof(pInChI[0].nAtom[0])); /* djb-rwth: cast operator added */
10090 [ - + ]: 2 : if (!pInChI[iComponent + i].nAtom)
10091 : : {
10092 : 0 : return RI_ERR_ALLOC; /* failed allocation */
10093 : : }
10094 : : /* Pass 2.2 Store elements; this assumes no bridging H. Bridging H will be found in connection table, /c */
10095 : 2 : iAtom = 0;
10096 [ + + ]: 2 : if (nNumAtoms > 0)
10097 : : {
10098 : 1 : e = pInChI[iComponent + i].szHillFormula;
10099 [ + + ]: 2 : while (*e)
10100 : : {
10101 [ - + ]: 1 : if (!isupper(UCINT * e))
10102 : : {
10103 : 0 : return RI_ERR_SYNTAX;
10104 : : }
10105 : 1 : j = 0;
10106 : 1 : szEl[j++] = *e++;
10107 [ - + - - ]: 1 : if (*e && islower(UCINT * e))
10108 : 0 : szEl[j++] = *e++;
10109 : 1 : szEl[j++] = '\0';
10110 [ - + - - ]: 1 : if (*e && isdigit(UCINT * e))
10111 : : {
10112 : 0 : mpy_atom = (int)inchi_strtol(e, &q, 10);
10113 : : #if ( CHECK_STRTOL_ATNUMB==1 )
10114 [ # # # # ]: 0 : if (mpy_atom > MAX_ATOMS || mpy_atom < 0)
10115 : : {
10116 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10117 : : }
10118 : : #endif
10119 : 0 : e = q;
10120 : : }
10121 : : else
10122 : : {
10123 : 1 : mpy_atom = 1;
10124 : : }
10125 [ - + ]: 1 : if (!mpy_atom)
10126 : : {
10127 : 0 : return RI_ERR_SYNTAX;
10128 : : }
10129 [ - + - - ]: 1 : if (szEl[0] == 'H' && !szEl[1])
10130 : 0 : continue; /* ignore H */
10131 : 1 : el_number = get_periodic_table_number(szEl);
10132 [ - + ]: 1 : if (el_number == ERR_ELEM)
10133 : : {
10134 : 0 : return RI_ERR_SYNTAX; /* wrong element */
10135 : : }
10136 [ + + ]: 2 : while (mpy_atom--)
10137 : : {
10138 [ - + ]: 1 : if (iAtom >= nNumAtoms)
10139 : : {
10140 : 0 : return RI_ERR_PROGR; /* program error */
10141 : : }
10142 : 1 : pInChI[iComponent + i].nAtom[iAtom++] = (U_CHAR)el_number;
10143 : : }
10144 : : }
10145 : : }
10146 : : else
10147 : : {
10148 [ + - ]: 1 : if (nNumH > 0)
10149 : : {
10150 : 1 : pInChI[iComponent + i].nAtom[iAtom++] = EL_NUMBER_H;
10151 : 1 : nNumAtoms = 1;
10152 : : }
10153 : : }
10154 : 2 : pInChI[iComponent + i].nAtom[iAtom] = '\0';
10155 [ - + ]: 2 : if (nNumAtoms != iAtom)
10156 : : {
10157 : 0 : return RI_ERR_PROGR; /* program error */
10158 : : }
10159 : : }
10160 : : else
10161 : : {
10162 : 0 : U_CHAR* pci1 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10163 : : /* Copy duplicated formula */
10164 : 0 : strcpy(pInChI[iComponent + i].szHillFormula, pInChI[iComponent].szHillFormula); /* djb-rwth: unresolved issue -- revision required? */
10165 : : /* Copy atoms in the duplicated formula */
10166 : 0 : pInChI[iComponent + i].nNumberOfAtoms = nNumAtoms;
10167 : : /* djb-rwth: fixing oss-fuzz issue #43420, #34772 */
10168 : 0 : pci1 = (U_CHAR*)inchi_malloc((long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
10169 [ # # ]: 0 : if (!pci1)
10170 : : {
10171 : 0 : return RI_ERR_ALLOC; /* failed allocation */
10172 : : }
10173 : 0 : pInChI[iComponent + i].nAtom = pci1;
10174 : 0 : memcpy(pci1, pInChI[iComponent].nAtom, (long long)nNumAtoms + 1); /* djb-rwth: cast operator added */
10175 : : }
10176 : : }
10177 : 2 : iComponent += i;
10178 [ - + ]: 2 : if (*pEnd)
10179 : : {
10180 [ # # ]: 0 : if (*pEnd != '.')
10181 : : {
10182 : 0 : return RI_ERR_SYNTAX; /* syntax error */
10183 : : }
10184 : 0 : pStart = pEnd + 1;
10185 : : }
10186 : : else
10187 : : {
10188 : 2 : break;
10189 : : }
10190 : : }
10191 : :
10192 [ - + ]: 2 : if (iComponent != nNumComponents)
10193 : : {
10194 : 0 : return RI_ERR_PROGR; /* program error */
10195 : : }
10196 [ - + ]: 2 : if (bMobileH == TAUT_NON)
10197 : : {
10198 : : /* at this point the exact number of atoms including bridging H is known from TAUT_YES */
10199 [ # # # # ]: 0 : for (i = 0; i < nNumComponents && i < pnNumComponents[nAltMobileH]; i++)
10200 : : {
10201 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nNumberOfAtoms < (len = pInpInChI[nAltMobileH][i].nNumberOfAtoms))
10202 : : {
10203 : : /* there are bridging H in this component */
10204 [ # # ]: 0 : if (pInpInChI[nAltMobileH][i].nAtom)
10205 : : {
10206 : 0 : U_CHAR* nAtom = (U_CHAR*)inchi_malloc(((long long)len + 1) * sizeof(nAtom[0])); /* djb-rwth: cast operator added */
10207 [ # # ]: 0 : if (!nAtom)
10208 : : {
10209 : 0 : return RI_ERR_ALLOC;
10210 : : }
10211 : 0 : memcpy(nAtom, pInpInChI[nAltMobileH][i].nAtom, len * sizeof(nAtom[0]));
10212 : 0 : nAtom[len] = 0;
10213 [ # # ]: 0 : if (pInpInChI[bMobileH][i].nAtom)
10214 : : {
10215 [ # # ]: 0 : inchi_free(pInpInChI[bMobileH][i].nAtom);
10216 : : }
10217 : 0 : pInpInChI[bMobileH][i].nAtom = nAtom;
10218 : : }
10219 : 0 : pInpInChI[bMobileH][i].nNumberOfAtoms = len;
10220 : : }
10221 : : }
10222 : : }
10223 : :
10224 : 2 : return nNumComponents + 1;
10225 : : }
10226 : :
10227 : :
10228 : : /****************************************************************************/
10229 : 0 : int CopySegment(INChI* pInChITo,
10230 : : INChI* pInChIFrom,
10231 : : int SegmentType,
10232 : : int bIsotopicTo,
10233 : : int bIsotopicFrom)
10234 : : {
10235 : 0 : int ret = RI_ERR_ALLOC;
10236 : : int len;
10237 : :
10238 [ # # # # ]: 0 : if (SegmentType == CPY_SP2 ||
10239 [ # # ]: 0 : SegmentType == CPY_SP3 ||
10240 [ # # ]: 0 : SegmentType == CPY_SP3_M ||
10241 : : SegmentType == CPY_SP3_S)
10242 : : {
10243 : 0 : INChI_Stereo** pstereoTo = NULL;
10244 [ # # ]: 0 : INChI_Stereo* stereoFrom = bIsotopicFrom == 1 ? pInChIFrom->StereoIsotopic :
10245 [ # # ]: 0 : bIsotopicFrom == 0 ? pInChIFrom->Stereo : NULL;
10246 [ # # # # ]: 0 : if (stereoFrom || bIsotopicFrom < 0)
10247 : : {
10248 [ # # ]: 0 : if (SegmentType == CPY_SP2)
10249 : : {
10250 : : #if ( FIX_GAF_2019_1==1 )
10251 [ # # ]: 0 : if (bIsotopicFrom >= 0 &&
10252 [ # # # # ]: 0 : (pInChIFrom->nNumberOfAtoms > MAX_ATOMS || pInChIFrom->nNumberOfAtoms < 0))
10253 : : {
10254 : 0 : ret = RI_ERR_SYNTAX;
10255 : 0 : goto exit_function;
10256 : : }
10257 : : #endif
10258 [ # # ]: 0 : if (bIsotopicFrom < 0 ||
10259 [ # # ]: 0 : (stereoFrom->b_parity &&
10260 [ # # ]: 0 : stereoFrom->nBondAtom1 &&
10261 [ # # ]: 0 : stereoFrom->nBondAtom2)) /* djb-rwth: addressing LLVM warning */
10262 : : {
10263 : 0 : S_CHAR* pst0_bp = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10264 : 0 : AT_NUMB* pst0_nba1 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10265 : 0 : AT_NUMB* pst0_nba2 = NULL; /* copied from below to obey C syntax - 2024-09-01 DT */
10266 : :
10267 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : stereoFrom->nNumberOfStereoBonds;
10268 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10269 [ # # ]: 0 : if (!pstereoTo[0])
10270 : : {
10271 : : /* djb-rwth: fixing oss-fuzz issue #66985 */
10272 : 0 : INChI_Stereo* pst0 = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo));
10273 : 0 : pstereoTo[0] = pst0;
10274 [ # # ]: 0 : if (!pst0)
10275 : : {
10276 : 0 : goto exit_function;
10277 : : }
10278 : : }
10279 [ # # # # ]: 0 : if (pstereoTo[0]->nNumberOfStereoBonds > 0 || pstereoTo[0]->b_parity ||
10280 [ # # # # ]: 0 : pstereoTo[0]->nBondAtom1 || pstereoTo[0]->nBondAtom2)
10281 : : {
10282 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10283 : 0 : goto exit_function;
10284 : : }
10285 : : /* allocate sp2 stereo */
10286 : : /* djb-rwth: fixing oss-fuzz issue #66985 */
10287 : : /* djb-rwth: cast operators added */
10288 : 0 : pst0_bp = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->b_parity[0]));
10289 : 0 : pst0_nba1 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom1[0]));
10290 : 0 : pst0_nba2 = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom2[0]));
10291 : 0 : pstereoTo[0]->b_parity = pst0_bp;
10292 : 0 : pstereoTo[0]->nBondAtom1 = pst0_nba1;
10293 : 0 : pstereoTo[0]->nBondAtom2 = pst0_nba2;
10294 [ # # # # : 0 : if (!pst0_bp || !pst0_nba1 || !pst0_nba2)
# # ]
10295 : : {
10296 : : /* cleanup */
10297 [ # # ]: 0 : if (pst0_bp)
10298 : : {
10299 : : INCHI_HEAPCHK
10300 [ # # ]: 0 : inchi_free(pst0_bp);
10301 : 0 : pst0_bp = NULL;
10302 : : }
10303 [ # # ]: 0 : if (pst0_nba1)
10304 : : {
10305 : : INCHI_HEAPCHK
10306 [ # # ]: 0 : inchi_free(pst0_nba1);
10307 : 0 : pst0_nba1 = NULL;
10308 : : }
10309 [ # # ]: 0 : if (pstereoTo[0]->nBondAtom2)
10310 : : {
10311 : : INCHI_HEAPCHK
10312 [ # # ]: 0 : inchi_free(pst0_nba2);
10313 : 0 : pst0_nba2 = NULL;
10314 : : }
10315 : : INCHI_HEAPCHK
10316 : 0 : goto exit_function;
10317 : : }
10318 : : /* copy stereo */
10319 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10320 : : {
10321 : : #if ( FIX_GAF_2019_1==1 )
10322 [ # # # # ]: 0 : if (pInChIFrom->nNumberOfAtoms > MAX_ATOMS || pInChIFrom->nNumberOfAtoms < 0)
10323 : : {
10324 : 0 : ret = RI_ERR_SYNTAX;
10325 : 0 : goto exit_function;
10326 : : }
10327 : : #endif
10328 : 0 : memcpy(pst0_bp, stereoFrom->b_parity, ((long long)len + 1) * sizeof(pst0_bp[0])); /* djb-rwth: cast operator added */
10329 : 0 : memcpy(pst0_nba1, stereoFrom->nBondAtom1, ((long long)len + 1) * sizeof(pst0_nba1[0])); /* djb-rwth: cast operator added */
10330 : 0 : memcpy(pst0_nba2, stereoFrom->nBondAtom2, ((long long)len + 1) * sizeof(pst0_nba2[0])); /* djb-rwth: cast operator added */
10331 : : }
10332 : 0 : pstereoTo[0]->nNumberOfStereoBonds = len;
10333 : :
10334 : 0 : return len + 1;
10335 : : }
10336 : : else
10337 : : {
10338 : 0 : return 0;
10339 : : }
10340 : : }
10341 : : else
10342 : : {
10343 [ # # ]: 0 : if (SegmentType == CPY_SP3)
10344 : : {
10345 [ # # ]: 0 : if (bIsotopicFrom < 0 ||
10346 [ # # ]: 0 : (stereoFrom->t_parity &&
10347 [ # # ]: 0 : stereoFrom->nNumber)) /* djb-rwth: addressing LLVM warning */
10348 : : {
10349 : :
10350 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : stereoFrom->nNumberOfStereoCenters;
10351 : :
10352 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10353 [ # # ]: 0 : if (!pstereoTo[0])
10354 : : {
10355 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10356 : : {
10357 : 0 : goto exit_function;
10358 : : }
10359 : : }
10360 [ # # # # ]: 0 : if (pstereoTo[0]->nNumberOfStereoCenters > 0 || pstereoTo[0]->t_parity ||
10361 [ # # ]: 0 : pstereoTo[0]->nNumber)
10362 : : {
10363 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10364 : 0 : goto exit_function;
10365 : : }
10366 : : /* allocate sp3 stereo */
10367 [ # # ]: 0 : if (!(pstereoTo[0]->t_parity = (S_CHAR*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->b_parity[0]))) ||
10368 [ # # ]: 0 : !(pstereoTo[0]->nNumber = (AT_NUMB*)inchi_calloc((long long)len + 1, sizeof(pstereoTo[0]->nBondAtom1[0])))) /* djb-rwth: cast operators added */
10369 : : {
10370 : : /* cleanup */
10371 [ # # ]: 0 : if (pstereoTo[0]->t_parity)
10372 : : {
10373 [ # # ]: 0 : inchi_free(pstereoTo[0]->t_parity);
10374 : 0 : pstereoTo[0]->t_parity = NULL;
10375 : : }
10376 [ # # ]: 0 : if (pstereoTo[0]->nNumber)
10377 : : {
10378 [ # # ]: 0 : inchi_free(pstereoTo[0]->nNumber);
10379 : 0 : pstereoTo[0]->nNumber = NULL;
10380 : : }
10381 : 0 : goto exit_function;
10382 : : }
10383 : : /* copy stereo */
10384 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10385 : : {
10386 : 0 : memcpy(pstereoTo[0]->t_parity, stereoFrom->t_parity, ((long long)len + 1) * sizeof(pstereoTo[0]->t_parity[0])); /* djb-rwth: cast operator added */
10387 : 0 : memcpy(pstereoTo[0]->nNumber, stereoFrom->nNumber, ((long long)len + 1) * sizeof(pstereoTo[0]->nNumber[0])); /* djb-rwth: cast operator added */
10388 : : }
10389 : 0 : pstereoTo[0]->nNumberOfStereoCenters = len;
10390 : 0 : return len + 1;
10391 : : }
10392 : : else
10393 : : {
10394 : 0 : return 0;
10395 : : }
10396 : : }
10397 : : else
10398 : : {
10399 [ # # ]: 0 : if (SegmentType == CPY_SP3_M)
10400 : : {
10401 [ # # ]: 0 : pstereoTo = bIsotopicTo ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10402 [ # # ]: 0 : if (!pstereoTo[0])
10403 : : {
10404 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10405 : : {
10406 : 0 : goto exit_function;
10407 : : }
10408 : : }
10409 [ # # # # ]: 0 : if (pstereoTo[0]->nCompInv2Abs && NO_VALUE_INT != pstereoTo[0]->nCompInv2Abs)
10410 : : {
10411 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10412 : 0 : goto exit_function;
10413 : : }
10414 [ # # ]: 0 : if (bIsotopicFrom < 0)
10415 : : {
10416 : 0 : pstereoTo[0]->nCompInv2Abs = 0;
10417 : : }
10418 : : else
10419 : : {
10420 : 0 : pstereoTo[0]->nCompInv2Abs = stereoFrom->nCompInv2Abs;
10421 : : }
10422 : 0 : return 1;
10423 : : }
10424 : : else
10425 : : {
10426 : : /* use bTrivialInv to save /s1, /s2, /s3 */
10427 [ # # ]: 0 : if (SegmentType == CPY_SP3_S)
10428 : : {
10429 [ # # ]: 0 : pstereoTo = bIsotopicFrom ? &pInChITo->StereoIsotopic : &pInChITo->Stereo;
10430 [ # # ]: 0 : if (!pstereoTo[0])
10431 : : {
10432 [ # # ]: 0 : if (!(pstereoTo[0] = (INChI_Stereo*)inchi_calloc(1, sizeof(**pstereoTo))))
10433 : : {
10434 : 0 : goto exit_function;
10435 : : }
10436 : : }
10437 [ # # ]: 0 : if (pstereoTo[0]->bTrivialInv)
10438 : : {
10439 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10440 : 0 : goto exit_function;
10441 : : }
10442 [ # # ]: 0 : if (stereoFrom) /* djb-rwth: fixing a NULL pointer dereference */
10443 : 0 : pstereoTo[0]->bTrivialInv = stereoFrom->bTrivialInv;
10444 [ # # ]: 0 : if (bIsotopicFrom < 0)
10445 : : {
10446 : 0 : pstereoTo[0]->bTrivialInv = 0;
10447 : : }
10448 : : else
10449 : : {
10450 : 0 : pstereoTo[0]->bTrivialInv = stereoFrom->bTrivialInv;
10451 : : }
10452 : 0 : return 1;
10453 : : }
10454 : : }
10455 : : }
10456 : : }
10457 : : }
10458 : :
10459 : 0 : return 0; /* nothing to copy */
10460 : : }
10461 : :
10462 [ # # ]: 0 : else if (SegmentType == CPY_ISO_AT)
10463 : : {
10464 : 0 : int nNumberOfIsotopicAtoms = pInChIFrom->nNumberOfIsotopicAtoms;
10465 : 0 : INChI_IsotopicAtom** pIsotopicAtomTo = NULL;
10466 : 0 : INChI_IsotopicAtom* IsotopicAtomFrom = pInChIFrom->IsotopicAtom;
10467 [ # # # # ]: 0 : if (bIsotopicFrom < 0 || IsotopicAtomFrom)
10468 : : {
10469 [ # # ]: 0 : len = (bIsotopicFrom < 0) ? 0 : nNumberOfIsotopicAtoms;
10470 : : #if ( FIX_GAF_2019_3==1 )
10471 [ # # ]: 0 : if (pInChITo->nNumberOfIsotopicAtoms < 1)
10472 : : {
10473 : : /* forcibly free iso-related memory and set to NULL */
10474 [ # # # # ]: 0 : qzfree(pInChITo->IsotopicAtom);
10475 : : }
10476 : : #endif
10477 : 0 : pIsotopicAtomTo = &pInChITo->IsotopicAtom;
10478 [ # # ]: 0 : if (!*pIsotopicAtomTo)
10479 : : {
10480 [ # # ]: 0 : if (!(*pIsotopicAtomTo = (INChI_IsotopicAtom*)inchi_calloc((long long)len + 1, sizeof(**pIsotopicAtomTo)))) /* djb-rwth: cast operator added */
10481 : : {
10482 : 0 : goto exit_function;
10483 : : }
10484 : : }
10485 [ # # ]: 0 : if (pInChITo->nNumberOfIsotopicAtoms)
10486 : : {
10487 : 0 : ret = RI_ERR_SYNTAX; /* stereo already exists */
10488 : 0 : goto exit_function;
10489 : : }
10490 [ # # # # ]: 0 : if (bIsotopicFrom >= 0 && len)
10491 : : {
10492 : 0 : memcpy(*pIsotopicAtomTo, IsotopicAtomFrom, ((long long)len + 1) * sizeof(**pIsotopicAtomTo)); /* djb-rwth: cast operator added */
10493 : : }
10494 : 0 : pInChITo->nNumberOfIsotopicAtoms = len;
10495 : 0 : return len + 1;
10496 : : }
10497 : :
10498 : 0 : return 0;
10499 : : }
10500 : :
10501 : 0 : ret = RI_ERR_PROGR; /* program error */
10502 : :
10503 : 0 : exit_function:
10504 : :
10505 : 0 : return ret;
10506 : : }
10507 : :
10508 : :
10509 : : /****************************************************************************
10510 : : Sort neighbors in ascending order
10511 : : ****************************************************************************/
10512 : 0 : int insertions_sort_AT_NUMB(AT_NUMB* base, int num)
10513 : : {
10514 : : AT_NUMB* i, * j, * pk, tmp;
10515 : 0 : int k, num_trans = 0;
10516 [ # # ]: 0 : for (k = 1, pk = base; k < num; k++, pk++)
10517 : : {
10518 [ # # # # ]: 0 : for (j = (i = pk) + 1, tmp = *j; j > base && *i > tmp; j = i, i--)
10519 : : {
10520 : 0 : *j = *i;
10521 : 0 : num_trans++;
10522 : : }
10523 : 0 : *j = tmp;
10524 : : }
10525 : :
10526 : 0 : return num_trans;
10527 : : }
10528 : :
10529 : :
10530 : : /****************************************************************************/
10531 : 46 : int getInChIChar(INCHI_IOSTREAM* pInp)
10532 : : {
10533 [ + - ]: 46 : if (pInp->type == INCHI_IOS_TYPE_STRING)
10534 : : {
10535 : : /* input from string */
10536 [ + + ]: 46 : if (pInp->s.nPtr < pInp->s.nUsedLength)
10537 : : {
10538 : 45 : return (int)pInp->s.pStr[pInp->s.nPtr++];
10539 : : }
10540 : 1 : return RI_ERR_EOF;
10541 : : }
10542 : : else
10543 : : {
10544 : : /* input from plain file */
10545 : : int c;
10546 : : #if ( defined(_MSC_VER)&&defined(_WIN32) || defined(__BORLANDC__)&&defined(__WIN32__) || defined(__GNUC__)&&defined(__MINGW32__)&&defined(_WIN32) )
10547 : : do
10548 : : {
10549 : : c = getc(pInp->f);
10550 : : if (c == EOF)
10551 : : {
10552 : : c = RI_ERR_EOF;
10553 : : break;
10554 : : }
10555 : : } while (c == '\r');
10556 : : #else
10557 : 0 : c = getc(pInp->f);
10558 [ # # ]: 0 : if (c == EOF)
10559 : : {
10560 : 0 : c = RI_ERR_EOF;
10561 : : }
10562 : : #endif
10563 : 0 : return c;
10564 : : }
10565 : : }
10566 : :
10567 : :
10568 : : /****************************************************************************/
10569 : 46 : int AddInChIChar(INCHI_IOSTREAM* pInp,
10570 : : SEGM_LINE* Line,
10571 : : const char* pszToken)
10572 : : {
10573 : 46 : int c = getInChIChar(pInp);
10574 : : /*
10575 : : while ( c == '\r' ) {
10576 : : c = getInChIChar( pInp );
10577 : : }
10578 : : */
10579 : :
10580 : : INCHI_HEAPCHK
10581 : :
10582 [ + + ]: 46 : if (Line->len + 2 >= Line->len_alloc)
10583 : : {
10584 : 2 : char* str = (char*)inchi_calloc((long long)Line->len_alloc + SEGM_LINE_ADD, sizeof(str[0])); /* djb-rwth: cast operator added */
10585 : : INCHI_HEAPCHK
10586 [ + - ]: 2 : if (str)
10587 : : {
10588 [ - + - - ]: 2 : if (Line->len > 0 && Line->str)
10589 : : {
10590 : 0 : memcpy(str, Line->str, sizeof(str[0]) * Line->len);
10591 : 0 : Line->len_alloc += SEGM_LINE_ADD;
10592 [ # # ]: 0 : inchi_free(Line->str);
10593 : : INCHI_HEAPCHK
10594 : : }
10595 : : else
10596 : : {
10597 : 2 : Line->len_alloc += SEGM_LINE_ADD;
10598 : : }
10599 : 2 : Line->str = str;
10600 : : }
10601 : : else
10602 : : {
10603 : 0 : c = RI_ERR_ALLOC; /* fatal error */
10604 : 0 : goto exit_function;
10605 : : }
10606 : : }
10607 : : INCHI_HEAPCHK
10608 [ - + ]: 46 : if (c < 0)
10609 : : {
10610 : 0 : Line->str[Line->len] = '\0';
10611 : : INCHI_HEAPCHK
10612 : 0 : c = RI_ERR_SYNTAX; /* fatal error: wrong char */
10613 : 0 : goto exit_function;
10614 : : }
10615 : :
10616 [ + + + + ]: 46 : if (c && strchr(pszToken, c)) /* /\ */
10617 : : {
10618 : 5 : Line->str[Line->len] = '\0';
10619 : : INCHI_HEAPCHK
10620 : 5 : c = -(c + 2);
10621 : 5 : goto exit_function;
10622 : : }
10623 [ + + - + ]: 41 : else if (!c && !Line->len)
10624 : : {
10625 : 0 : Line->str[Line->len] = c;
10626 : : INCHI_HEAPCHK
10627 : : }
10628 : : else
10629 : : {
10630 : 41 : Line->str[Line->len++] = c;
10631 : : INCHI_HEAPCHK
10632 : : }
10633 : :
10634 : 46 : exit_function:
10635 : :
10636 : : INCHI_HEAPCHK
10637 : :
10638 : 46 : return c; /* djb-rwth: addressing coverity ID #499500 -- c = getInChIChar(pInp) cannot be tainted */
10639 : : }
10640 : :
10641 : : /****************************************************************************/
10642 : 7 : int nGetInChISegment(INCHI_IOSTREAM* pInp,
10643 : : SEGM_LINE* Line,
10644 : : const char* pszToken)
10645 : : {
10646 : : int c;
10647 : 7 : Line->len = 0;
10648 [ + + ]: 46 : while (0 < (c = AddInChIChar(pInp, Line, pszToken)))
10649 : : {
10650 : : ;
10651 : : }
10652 [ + + ]: 7 : if (c < -2)
10653 : : {
10654 : 5 : c = -(c + 2);
10655 : : }
10656 : 7 : Line->c = c;
10657 : :
10658 : 7 : return c;
10659 : : }
10660 : :
10661 : :
10662 : : /****************************************************************************
10663 : : Add one more bond to the linked lists for both neighbors
10664 : : ****************************************************************************/
10665 : 0 : int AddLinkedBond(AT_NUMB at1,
10666 : : AT_NUMB at2,
10667 : : AT_NUMB num_at,
10668 : : LINKED_BONDS* pLB)
10669 : : {
10670 : 0 : int nReqLen = inchi_max(2 * num_at + 2, pLB->len + 2);
10671 : : AT_NUMB prev;
10672 : : #if ( FIX_GAF_2019_2==1 )
10673 : : {
10674 [ # # # # : 0 : if (at2 > num_at || at1 > num_at || at1 < 0 || at2<0 || num_at>MAX_ATOMS)
# # ]
10675 : : {
10676 : 0 : return RI_ERR_SYNTAX;
10677 : : }
10678 : : }
10679 : : #endif
10680 [ # # ]: 0 : if (pLB->len_alloc <= nReqLen)
10681 : : {
10682 : : /*int nNewLen = nReqLen + (nReqLen + LINKED_BOND_ADD - 1)%LINKED_BOND_ADD + LINKED_BOND_ADD;*/
10683 : 0 : int nNewLen = nReqLen - nReqLen % LINKED_BOND_ADD + 2 * LINKED_BOND_ADD;
10684 : 0 : ONE_LINKED_BOND* pBond = (ONE_LINKED_BOND*)inchi_calloc(nNewLen, sizeof(pBond[0]));
10685 [ # # ]: 0 : if (!pBond)
10686 : : {
10687 : 0 : return RI_ERR_ALLOC; /* allocation error */
10688 : : }
10689 [ # # # # ]: 0 : if (pLB->pBond && pLB->len)
10690 : : {
10691 : 0 : memcpy(pBond, pLB->pBond, pLB->len * sizeof(pBond[0]));
10692 : : }
10693 [ # # ]: 0 : if (pLB->pBond)
10694 [ # # ]: 0 : inchi_free(pLB->pBond);
10695 : 0 : pLB->pBond = pBond;
10696 : 0 : pLB->len_alloc = nNewLen;
10697 : : }
10698 [ # # ]: 0 : if (!pLB->len)
10699 : : {
10700 : 0 : pLB->len = num_at + 1;
10701 : 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? */
10702 : : }
10703 : :
10704 : 0 : prev = pLB->pBond[at1].prev; /* position of the last neighbor of at1 in the pLB->pBond */
10705 [ # # ]: 0 : if (!prev)
10706 : : {
10707 : 0 : pLB->pBond[at1].neigh = at2;
10708 : 0 : pLB->pBond[at1].prev = at1;
10709 : : }
10710 : : else
10711 : : {
10712 : 0 : pLB->pBond[pLB->len].neigh = at2;
10713 : 0 : pLB->pBond[pLB->len].prev = prev;
10714 : 0 : pLB->pBond[at1].prev = pLB->len++;
10715 : : }
10716 : :
10717 : 0 : prev = pLB->pBond[at2].prev; /* position of the last neighbor of at2 in the pLB->pBond */
10718 [ # # ]: 0 : if (!prev)
10719 : : {
10720 : 0 : pLB->pBond[at2].neigh = at1;
10721 : 0 : pLB->pBond[at2].prev = at2;
10722 : : }
10723 : : else
10724 : : {
10725 : 0 : pLB->pBond[pLB->len].neigh = at1;
10726 : 0 : pLB->pBond[pLB->len].prev = prev;
10727 : 0 : pLB->pBond[at2].prev = pLB->len++;
10728 : : }
10729 : :
10730 : 0 : return 0;
10731 : : }
10732 : :
10733 : :
10734 : : /****************************************************************************
10735 : : PrepareSaveOptBits
10736 : : ****************************************************************************/
10737 : 0 : void PrepareSaveOptBits(INPUT_PARMS* ip,
10738 : : INCHI_IOSTREAM* pLog,
10739 : : const long num_inp,
10740 : : const char* szCurHdr,
10741 : : int input_has_save_opt,
10742 : : unsigned char input_save_opt_bits,
10743 : : unsigned char* save_opt_bits)
10744 : : {
10745 : :
10746 [ # # ]: 0 : if (!input_has_save_opt)
10747 : : {
10748 : : /* Does not allow to create SaveOpt if the source lacks appendix */
10749 : 0 : ip->bINChIOutputOptions &= ~INCHI_OUT_SAVEOPT;
10750 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10751 : : {
10752 : 0 : inchi_ios_eprint(pLog,
10753 : : "Warning: ignore SaveOpt request for SaveOpt-less input, %s\n",
10754 : : szCurHdr);
10755 : : }
10756 : : else
10757 : : {
10758 : 0 : inchi_ios_eprint(pLog,
10759 : : "Warning: ignore SaveOpt request for SaveOpt-less input, Structure %ld\n",
10760 : : num_inp);
10761 : : }
10762 : : }
10763 : : else
10764 : : {
10765 : : /* Analyze existing and prepare new SaveOpt appendix */
10766 : : /* djb-rwth: addressing coverity ID #499490 -- these are variable initialisers setting values to 0 */
10767 : 0 : int input_save_opt_has_recmet = input_save_opt_bits & SAVE_OPT_RECMET;
10768 : 0 : int input_save_opt_has_fixedh = input_save_opt_bits & SAVE_OPT_FIXEDH;
10769 : 0 : int input_save_opt_has_suu = input_save_opt_bits & SAVE_OPT_SUU;
10770 : 0 : int input_save_opt_has_sluud = input_save_opt_bits & SAVE_OPT_SLUUD;
10771 : 0 : int input_save_opt_has_ket = input_save_opt_bits & SAVE_OPT_KET;
10772 : 0 : int input_save_opt_has_15t = input_save_opt_bits & SAVE_OPT_15T;
10773 : 0 : int input_save_opt_has_pt_22_00 = input_save_opt_bits & SAVE_OPT_PT_22_00;
10774 : 0 : int input_save_opt_has_pt_16_00 = input_save_opt_bits & SAVE_OPT_PT_16_00;
10775 : 0 : int input_save_opt_has_pt_06_00 = input_save_opt_bits & SAVE_OPT_PT_06_00;
10776 : 0 : int input_save_opt_has_pt_39_00 = input_save_opt_bits & SAVE_OPT_PT_39_00;
10777 : 0 : int input_save_opt_has_pt_13_00 = input_save_opt_bits & SAVE_OPT_PT_13_00;
10778 : 0 : int input_save_opt_has_pt_18_00 = input_save_opt_bits & SAVE_OPT_PT_18_00;
10779 : :
10780 [ # # ]: 0 : if (0 != (ip->bTautFlags & TG_FLAG_RECONNECT_COORD))
10781 : : {
10782 : : /* RecMet requested */
10783 [ # # ]: 0 : if (input_save_opt_has_recmet)
10784 : : {
10785 : 0 : *save_opt_bits |= SAVE_OPT_RECMET;
10786 : : }
10787 : : else
10788 : : {
10789 : 0 : ip->bTautFlags &= ~TG_FLAG_RECONNECT_COORD;
10790 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10791 : : {
10792 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o RecMet - ignoring RecMet request, %s\n", szCurHdr);
10793 : : }
10794 : : else
10795 : : {
10796 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o RecMet - ignoring RecMet request, Structure %ld\n", num_inp);
10797 : : }
10798 : : }
10799 : : }
10800 : :
10801 [ # # ]: 0 : if (0 != (ip->nMode & REQ_MODE_BASIC))
10802 : : {
10803 : : /* FixedH requested */
10804 [ # # ]: 0 : if (input_save_opt_has_fixedh)
10805 : : {
10806 : 0 : *save_opt_bits |= SAVE_OPT_FIXEDH;
10807 : : }
10808 : : else
10809 : : {
10810 : 0 : ip->nMode &= ~REQ_MODE_BASIC;
10811 [ # # # # ]: 0 : if (szCurHdr && szCurHdr[0])
10812 : : {
10813 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o FixedH - ignoring FixedH request, %s\n", szCurHdr);
10814 : : }
10815 : : else
10816 : : {
10817 : 0 : inchi_ios_eprint(pLog, "Warning: input created w/o FixedH - ignoring FixedH request, Structure %ld\n", num_inp);
10818 : : }
10819 : : }
10820 : : }
10821 : :
10822 : : /* Copy from source SaveOpt those bits which we do not touch */
10823 : : /* while converting InChI: SUU SLUUD KET 15T */
10824 [ # # ]: 0 : if (input_save_opt_has_suu)
10825 : : {
10826 : 0 : *save_opt_bits |= SAVE_OPT_SUU;
10827 : : }
10828 [ # # ]: 0 : if (input_save_opt_has_sluud)
10829 : : {
10830 : 0 : *save_opt_bits |= SAVE_OPT_SLUUD;
10831 : : }
10832 [ # # ]: 0 : if (input_save_opt_has_ket)
10833 : : {
10834 : 0 : *save_opt_bits |= SAVE_OPT_KET;
10835 : : }
10836 [ # # ]: 0 : if (input_save_opt_has_15t)
10837 : : {
10838 : 0 : *save_opt_bits |= SAVE_OPT_15T;
10839 : : }
10840 : :
10841 [ # # ]: 0 : if (input_save_opt_has_pt_22_00)
10842 : 0 : *save_opt_bits |= SAVE_OPT_PT_22_00;
10843 [ # # ]: 0 : if (input_save_opt_has_pt_16_00)
10844 : 0 : *save_opt_bits |= SAVE_OPT_PT_16_00;
10845 [ # # ]: 0 : if (input_save_opt_has_pt_06_00)
10846 : 0 : *save_opt_bits |= SAVE_OPT_PT_06_00;
10847 [ # # ]: 0 : if (input_save_opt_has_pt_39_00)
10848 : 0 : *save_opt_bits |= SAVE_OPT_PT_39_00;
10849 [ # # ]: 0 : if (input_save_opt_has_pt_13_00)
10850 : 0 : *save_opt_bits |= SAVE_OPT_PT_13_00;
10851 [ # # ]: 0 : if (input_save_opt_has_pt_18_00)
10852 : 0 : *save_opt_bits |= SAVE_OPT_PT_18_00;
10853 : :
10854 : : /* Check if /SNon requested and turn OFF stereo bits if so */
10855 [ # # ]: 0 : if (!(ip->nMode & REQ_MODE_STEREO))
10856 : : {
10857 : 0 : *save_opt_bits &= ~SAVE_OPT_SUU;
10858 : 0 : *save_opt_bits &= ~SAVE_OPT_SLUUD;
10859 : : }
10860 : : }
10861 : :
10862 : 0 : return;
10863 : : }
10864 : :
10865 : :
10866 : : /****************************************************************************/
10867 : 2 : void TreatErrorsInReadInChIString(int nReadStatus,
10868 : : int nErr,
10869 : : int pState,
10870 : : INPUT_PARMS* ip,
10871 : : INCHI_IOSTREAM* pOut,
10872 : : INCHI_IOSTREAM* pLog,
10873 : : long* num_inp,
10874 : : long* num_errors,
10875 : : long* num_processed,
10876 : : char** pstrHdr,
10877 : : char** pszCurHdr,
10878 : : InpInChI* pOneInput)
10879 : : {
10880 [ + + + - ]: 2 : int bInChI2Struct = (ip->bReadInChIOptions & READ_INCHI_TO_STRUCTURE) && ip->nInputType == INPUT_INCHI;
10881 : :
10882 : : /* InChI could not be read */
10883 [ - + - - : 2 : if (nReadStatus == RI_ERR_EOF && nErr == 0 && pState == 0) /* && !(*pstrHdr) ) */
- - ]
10884 : : {
10885 : : /*if ( !(*pstrHdr) ) */
10886 : : ;/*inchi_ios_eprint( pLog, "\nEnd of file detected after structure %ld. \n", *num_inp );*/
10887 : : }
10888 : : else
10889 : : {
10890 : : /* Output InChI parsing error message */
10891 : : char szHdrSimulation[128];
10892 : : char szMsg2[1024];
10893 : 2 : (*num_inp)++;
10894 : 2 : sprintf(szHdrSimulation, "Structure: %ld", *num_inp);
10895 : 2 : getInchiStateReadErr(pState, szMsg2);
10896 : :
10897 : : #ifdef TARGET_EXE_STANDALONE
10898 : : if (pOneInput->polymer &&
10899 : : bInChI2Struct &&
10900 : : !(ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
10901 : : {
10902 : : inchi_ios_eprint(pLog, "%s Skipping polymer InChI (only conversion to Molfile is available, use OutputSDF option)\n",
10903 : : *pstrHdr ? *pstrHdr : szHdrSimulation);
10904 : : }
10905 : : else
10906 : : #endif
10907 : : {
10908 [ + + - + ]: 2 : if (!bInChI2Struct &&
10909 [ # # ]: 0 : (pState == IST_MOBILE_H_POLYMER && !ip->bPolymers))
10910 : : {
10911 : : /* TO DO: implement InChI2InChI for polymers in a way similar to InChI2Struct
10912 : : thru an external (to ReadWriteInchi) loop */
10913 : 0 : inchi_ios_eprint(pLog, "%s Skipping polymer InChI for conversion of InChI to InChI\n",
10914 [ # # ]: 0 : *pstrHdr ? *pstrHdr : szHdrSimulation);
10915 : : }
10916 : : else
10917 : : {
10918 : 4 : inchi_ios_eprint(pLog, "\n%s %s (%d) in %s (%d)\n",
10919 [ - + ]: 2 : *pstrHdr ? *pstrHdr : szHdrSimulation,
10920 : : getInchiErrName(nErr), nErr,
10921 : : szMsg2, pState);
10922 : : }
10923 : : }
10924 : :
10925 [ - + ]: 2 : if (ip->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR)
10926 : : {
10927 [ # # ]: 0 : if (!(ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY))
10928 : : {
10929 [ # # ]: 0 : inchi_ios_eprint(pOut, "%s\n", *pstrHdr ? *pstrHdr : szHdrSimulation);
10930 [ # # ]: 0 : if (ip->bINChIOutputOptions & INCHI_OUT_STDINCHI)
10931 : : {
10932 : 0 : inchi_ios_eprint(pOut, "InChI=1S//\n");
10933 : : }
10934 : : else
10935 : : {
10936 : 0 : inchi_ios_eprint(pOut, "InChI=1//\n");
10937 : : }
10938 : : }
10939 : : }
10940 : :
10941 [ + + ]: 2 : if (0 != (ip->bReadInChIOptions & READ_INCHI_TO_STRUCTURE))
10942 : :
10943 : 1 : (*num_errors)++;
10944 : 2 : (*num_processed)++;
10945 : : }
10946 [ - + ]: 2 : if (*pstrHdr)
10947 : : {
10948 [ # # ]: 0 : inchi_free(*pstrHdr);
10949 : 0 : *pstrHdr = NULL;
10950 : : }
10951 [ - + ]: 2 : if (*pszCurHdr)
10952 : : {
10953 [ # # ]: 0 : inchi_free(*pszCurHdr);
10954 : 0 : *pszCurHdr = NULL;
10955 : : }
10956 : :
10957 : 2 : FreeInpInChI(pOneInput);
10958 : :
10959 : 2 : return;
10960 : : }
10961 : :
10962 : :
10963 : : /*
10964 : : InChi --> InChI string(s)
10965 : : */
10966 : :
10967 : :
10968 : : /****************************************************************************/
10969 : 0 : int ConvertInChI2InChI(INPUT_PARMS* ip,
10970 : : InpInChI* pOneInput,
10971 : : INCHI_IOSTREAM* pOut,
10972 : : INCHI_IOSTREAM* pLog,
10973 : : STRUCT_DATA* sd,
10974 : : int num_components[INCHI_NUM],
10975 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
10976 : : char** pszCurHdr,
10977 : : long num_inp,
10978 : : long* num_errors,
10979 : : unsigned char save_opt_bits,
10980 : : inchiTime* pulTStart,
10981 : : long* ulProcessingTime,
10982 : : struct tagINCHI_CLOCK* ic,
10983 : : struct tagCANON_GLOBALS* pCG)
10984 : : {
10985 : : int ret, tmp;
10986 : :
10987 : 0 : InchiTimeGet(pulTStart);
10988 : :
10989 : 0 : tmp = ip->bNoStructLabels;
10990 : 0 : ip->bNoStructLabels = 1;
10991 : : INCHI_HEAPCHK
10992 : 0 : ip->pSdfValue = NULL;
10993 : 0 : ip->pSdfLabel = NULL;
10994 : :
10995 : : #if ( FIX_DALKE_BUGS == 1 )
10996 : 0 : SetHillFormFromInChI(pOneInput);
10997 : : #endif
10998 : :
10999 : 0 : ret = OutputInChIAsRequested(pCG, pOut, pLog, ip, sd,
11000 : : pOneInput, num_components,
11001 : : nModeProtonIsoExchgH,
11002 : : num_inp, save_opt_bits);
11003 : :
11004 : : #if ( !defined(TARGET_API_LIB) && defined(TARGET_EXE_STANDALONE) )
11005 : :
11006 : : /* Calculate InChIKey if requested */
11007 : : /* However, do not calculate/write it if this function is called from within dll */
11008 : : {
11009 : : char ik_string[256]; /* Resulting InChIKey string */
11010 : : int ik_ret = 0; /* InChIKey-calc result code */
11011 : : int xhash1, xhash2;
11012 : : char szXtra1[65], szXtra2[65];
11013 : :
11014 : : inchi_ios_flush2(pLog, stderr);
11015 : :
11016 : : /* post-1.02b addition - correctly treat tabbed output with InChIKey */
11017 : : if (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT)
11018 : : {
11019 : : if (ip->bCalcInChIHash != INCHIHASH_NONE)
11020 : : {
11021 : : if (pOut->s.pStr)
11022 : : {
11023 : : if (pOut->s.nUsedLength > 0)
11024 : : {
11025 : : if (pOut->s.pStr[pOut->s.nUsedLength - 1] == '\n')
11026 : : { /* replace LF with TAB */
11027 : : pOut->s.pStr[pOut->s.nUsedLength - 1] = '\t';
11028 : : }
11029 : : }
11030 : : }
11031 : : }
11032 : : }
11033 : :
11034 : : if (ip->bCalcInChIHash == INCHIHASH_NONE)
11035 : : {
11036 : : /* inchi_ios_flush(pOut); */
11037 : : }
11038 : : else
11039 : : {
11040 : : char* buf = NULL;
11041 : : size_t slen = pOut->s.nUsedLength;
11042 : : extract_inchi_substring(&buf, pOut->s.pStr, slen);
11043 : :
11044 : : if (NULL != buf)
11045 : : {
11046 : : xhash1 = xhash2 = 0;
11047 : : if ((ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1) ||
11048 : : (ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2))
11049 : : {
11050 : : xhash1 = 1;
11051 : : }
11052 : : if ((ip->bCalcInChIHash == INCHIHASH_KEY_XTRA2) ||
11053 : : (ip->bCalcInChIHash == INCHIHASH_KEY_XTRA1_XTRA2))
11054 : : {
11055 : : xhash2 = 1;
11056 : : }
11057 : :
11058 : : ik_ret = GetINCHIKeyFromINCHI(buf,
11059 : : xhash1,
11060 : : xhash2,
11061 : : ik_string,
11062 : : szXtra1,
11063 : : szXtra2);
11064 : : inchi_free(buf);
11065 : : }
11066 : : else
11067 : : {
11068 : : ik_ret = INCHIKEY_NOT_ENOUGH_MEMORY;
11069 : : }
11070 : :
11071 : :
11072 : : if (ik_ret == INCHIKEY_OK)
11073 : : {
11074 : : inchi_ios_print(pOut, "InChIKey=%-s\n", ik_string);
11075 : : }
11076 : : else
11077 : : {
11078 : : inchi_ios_print(pLog, "Warning (Could not compute InChIKey: ", num_inp);
11079 : : switch (ik_ret)
11080 : : {
11081 : : case INCHIKEY_UNKNOWN_ERROR:
11082 : : inchi_ios_print(pLog, "unresolved error)");
11083 : : break;
11084 : : case INCHIKEY_EMPTY_INPUT:
11085 : : inchi_ios_print(pLog, "got an empty string)");
11086 : : break;
11087 : : case INCHIKEY_INVALID_INCHI_PREFIX:
11088 : : case INCHIKEY_INVALID_INCHI:
11089 : : case INCHIKEY_INVALID_STD_INCHI:
11090 : : inchi_ios_print(pLog, "no valid InChI string found)");
11091 : : break;
11092 : : case INCHIKEY_NOT_ENOUGH_MEMORY:
11093 : : inchi_ios_print(pLog, "not enough memory to treat the string)");
11094 : : break;
11095 : : default:inchi_ios_print(pLog, "internal program error)");
11096 : : break;
11097 : : }
11098 : :
11099 : : inchi_ios_print(pLog, " structure #%-lu.\n", num_inp);
11100 : : if (ip->bINChIOutputOptions & INCHI_OUT_TABBED_OUTPUT)
11101 : : {
11102 : : inchi_ios_print(pOut, "\n");
11103 : : }
11104 : : } /* if (ip->bCalcInChIHash!=INCHIHASH_NONE) */
11105 : :
11106 : : inchi_ios_flush(pOut);
11107 : : inchi_ios_flush2(pLog, stderr);
11108 : : }
11109 : : } /* Calculate InChIKey if requested */
11110 : : #endif
11111 : :
11112 : 0 : ip->bNoStructLabels = tmp;
11113 : :
11114 : : #ifndef TARGET_API_LIB
11115 : : if (ret < 0)
11116 : : {
11117 : :
11118 : : if (*pszCurHdr && (*pszCurHdr)[0])
11119 : : {
11120 : : inchi_ios_eprint(pLog, "Error %d creating InChI string %s\n", ret, *pszCurHdr);
11121 : : }
11122 : : else
11123 : : {
11124 : : inchi_ios_eprint(pLog, "Error %d creating InChI string, Structure %ld\n", ret, num_inp);
11125 : : }
11126 : : if (ip->bINChIOutputOptions2 & INCHI_OUT_INCHI_GEN_ERROR)
11127 : : {/* inchi_ios_eprint( pOut, "InChICreationError!\n"); *//* emit err string */
11128 : : if (ip->bINChIOutputOptions & INCHI_OUT_STDINCHI)
11129 : : {
11130 : : inchi_ios_eprint(pOut, "InChI=1S//\n");
11131 : : }
11132 : : else
11133 : : {
11134 : : inchi_ios_eprint(pOut, "InChI=1//\n");
11135 : : }
11136 : : }
11137 : :
11138 : : (*num_errors)++;
11139 : : }
11140 : :
11141 : : #if ( !defined(TARGET_API_LIB) && !defined(TARGET_EXE_STANDALONE) )
11142 : : else
11143 : : if (*pszCurHdr && (*pszCurHdr)[0])
11144 : : {
11145 : : inchi_fprintf(stderr, "%s\r", *pszCurHdr);
11146 : : }
11147 : : #endif
11148 : : #endif
11149 : :
11150 : :
11151 [ # # ]: 0 : if (*pszCurHdr)
11152 : : {
11153 [ # # ]: 0 : inchi_free(*pszCurHdr);
11154 : 0 : *pszCurHdr = NULL;
11155 : : }
11156 : :
11157 : : INCHI_HEAPCHK
11158 : :
11159 : 0 : * ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11160 : :
11161 : 0 : return ret;
11162 : : }
11163 : :
11164 : :
11165 : : /* InChi --> Structure (presented as AuxInfo or MolFile) */
11166 : :
11167 : :
11168 : : /****************************************************************************/
11169 : 0 : int ConvertInChI2Struct(ICHICONST INPUT_PARMS* ip_inp,
11170 : : INPUT_PARMS* ip,
11171 : : InpInChI* pOneInput,
11172 : : inp_ATOM** at,
11173 : : int* num_at,
11174 : : OAD_Polymer** polymer,
11175 : : OAD_V3000** v3000,
11176 : : INCHI_IOSTREAM* pOut,
11177 : : INCHI_IOSTREAM* pLog,
11178 : : STRUCT_DATA* sd,
11179 : : int num_components[INCHI_NUM],
11180 : : MODE_PIXH nModeProtonIsoExchgH[INCHI_NUM],
11181 : : char** pszCurHdr,
11182 : : char* szMsg,
11183 : : int nMsgLen,
11184 : : char szMessage[MAX_MSG_LEN],
11185 : : int nInitLenMessage,
11186 : : int nMessageLen,
11187 : : int input_is_stdinchi,
11188 : : int bHasSomeReconnected,
11189 : : int bHasSomeFixedH,
11190 : : int bHasMetal,
11191 : : int nModeFlagsStereo,
11192 : : int bTautFlags,
11193 : : int bReqNonTaut,
11194 : : unsigned long WarningFlags[2][2],
11195 : : long num_inp,
11196 : : long* num_errors,
11197 : : unsigned char save_opt_bits,
11198 : : inchiTime* pulTStart,
11199 : : long* ulProcessingTime,
11200 : : struct tagINCHI_CLOCK* ic,
11201 : : struct tagCANON_GLOBALS* pCG)
11202 : : {
11203 : : int ret, i, j;
11204 : : SRM srm; /* rules how to handle bonds to metal atoms */
11205 : : StrFromINChI* pStruct[INCHI_NUM][TAUT_NUM];
11206 : :
11207 : 0 : int bINChIOutputOptions = /* djb-rwth: ignoring LLVM warning: variable used */
11208 : : #if ( I2S_MODIFY_OUTPUT != 1 )
11209 : : 0;
11210 : : #else
11211 : : /* transfer user's InChI output options to serialization 10-12-2007 */
11212 : : ip_inp->bINChIOutputOptions&
11213 : : (
11214 : : INCHI_OUT_NO_AUX_INFO | /* do not output Aux Info */
11215 : : INCHI_OUT_SHORT_AUX_INFO | /* output short version of Aux Info */
11216 : : INCHI_OUT_ONLY_AUX_INFO | /* output only Aux Info */
11217 : : /* INCHI_OUT_EMBED_REC |*/ /* embed reconnected INChI into disconnected INChI */
11218 : : INCHI_OUT_SDFILE_ONLY | /* save input data in a Molfile instead of creating INChI */
11219 : : INCHI_OUT_PLAIN_TEXT | /* output plain text INChI */
11220 : : INCHI_OUT_PLAIN_TEXT_COMMENTS | /* output plain text annotation */
11221 : : /* INCHI_OUT_WINCHI_WINDOW |*/ /* output into wINChI text window */
11222 : : INCHI_OUT_TABBED_OUTPUT | /* tab-delimited (only for plain text) */
11223 : : INCHI_OUT_SDFILE_ATOMS_DT | /* SDfile output H isotopes as D and T */
11224 : : INCHI_OUT_SDFILE_SPLIT | /* Split SDfile into components */
11225 : : 0
11226 : : );
11227 : : #endif
11228 : :
11229 : : /* Preliminaries */
11230 : 0 : InchiTimeGet(pulTStart);
11231 : :
11232 [ # # ]: 0 : if (input_is_stdinchi)
11233 : : {
11234 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_STDINCHI)
11235 : : {
11236 : 0 : bINChIOutputOptions |= INCHI_OUT_STDINCHI;
11237 : : }
11238 : : }
11239 : : else
11240 : : {
11241 [ # # ]: 0 : if (ip_inp->bINChIOutputOptions & INCHI_OUT_SAVEOPT)
11242 : : {
11243 : 0 : bINChIOutputOptions |= INCHI_OUT_SAVEOPT;
11244 : : }
11245 : : }
11246 : :
11247 : 0 : memset(pStruct, 0, sizeof(pStruct)); /* djb-rwth: memset_s C11/Annex K variant? */
11248 : :
11249 : 0 : SetUpSrm(&srm); /* structure restore parms */
11250 : :
11251 : : /* Eliminate Fixed-H InChI that are exactly same as the corresponding Mobile-H structures */
11252 : 0 : RemoveFixHInChIIdentical2MobH(pOneInput);
11253 : :
11254 : : /* Recheck layers after thee elimination; get optional stereo flags */
11255 : 0 : ret = DetectInpInchiCreationOptions(pOneInput, &bHasSomeReconnected,
11256 : : &bHasMetal, &bHasSomeFixedH,
11257 : : &nModeFlagsStereo, &bTautFlags);
11258 [ # # ]: 0 : if (ret < 0)
11259 : : {
11260 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen,
11261 : : "Error in detecting input InChI options", "; ");
11262 : 0 : (*num_errors)++;
11263 : 0 : goto dealloc;
11264 : : }
11265 : :
11266 [ # # # # ]: 0 : if (bHasSomeFixedH && !bReqNonTaut)
11267 : : {
11268 : 0 : bHasSomeFixedH = 0;
11269 : : }
11270 : :
11271 : : /* Set stereo flags */
11272 : 0 : ip->nMode &= ~(REQ_MODE_STEREO |
11273 : : REQ_MODE_ISO_STEREO |
11274 : : REQ_MODE_RELATIVE_STEREO |
11275 : : REQ_MODE_RACEMIC_STEREO |
11276 : : REQ_MODE_CHIR_FLG_STEREO |
11277 : : REQ_MODE_SB_IGN_ALL_UU |
11278 : : REQ_MODE_SC_IGN_ALL_UU);
11279 : :
11280 : 0 : ip->nMode |= nModeFlagsStereo;
11281 : :
11282 : : /* Remove Phosphine and Arsine Stereo Flags */
11283 : 0 : ip->bTautFlags &= ~TG_FLAG_PHOSPHINE_STEREO;
11284 : 0 : ip->bTautFlags &= ~TG_FLAG_ARSINE_STEREO;
11285 : 0 : ip->bTautFlags &= ~TG_FLAG_FIX_SP3_BUG;
11286 : :
11287 : 0 : ip->bTautFlags |= bTautFlags;
11288 : :
11289 : : /* Mark Disconnected InChI components that are exactly came as Reconnected ones */
11290 : : /* Disconnected will have a negative number of the reconnected component */
11291 : : /* Reconnected will have a positive number of the disconnected component */
11292 : :
11293 : 0 : MarkDisconectedIdenticalToReconnected(pOneInput);
11294 : :
11295 : : /*****************************************************************************/
11296 : : /* Pay attention to: */
11297 : : /* 1) .nLink < 0 in Disonnected which means InChI is same as in Reconnected */
11298 : : /* The component in Reconnected has .nLink pointing to the Disconnected; */
11299 : : /* each .nLink = (1+component index) or -(1+component index) */
11300 : : /* In the future .nLink>0 in Disconnected shall point to the Reconnectrd */
11301 : : /* component from which it was created */
11302 : : /* 2) Currently reversed structures from Disconnected components are created */
11303 : : /* and abandoned if Reconnected layer exists */
11304 : : /* 3) Connect/disconnect H depends on the presence of atom/bond parity */
11305 : : /* The combined Mobile/Fixed-H parity should be set for Fixed-H components*/
11306 : : /* 4) No comparison of the Disconnected layer is done if Reconnected exists */
11307 : : /* 5) Reading InChI was not fully tested in case one component has stereo in */
11308 : : /* both Mobile-H and Fixed-H layers while another component has stereo */
11309 : : /* only in Mobile-H layer */
11310 : : /*****************************************************************************/
11311 : :
11312 : :
11313 : : /* Main conversion InChI->Structure for each component and */
11314 : : /* after that pStruct[iRec][iMobH][iComponent].at2 is the structure, */
11315 : : /* pStruct[iRec][iMobH][iComponent].RevInChI full InChI for the structure */
11316 : : /* In case of both Fixed-H and Mobile-H layers the results are in iMobH=0 */
11317 : : /* In case of only Mobile-H/Main layer the results are in iMobH=1 */
11318 : :
11319 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11320 : :
11321 : 0 : sd->ulStructTime = 0;
11322 : :
11323 : 0 : ret = AllInchiToStructure(ic, pCG, ip, sd, num_inp, *pszCurHdr, &srm, bHasSomeFixedH, pStruct, pOneInput);
11324 : :
11325 : 0 : ulProcessingTime += sd->ulStructTime;
11326 : 0 : InchiTimeGet(pulTStart);
11327 : :
11328 : : /* ret < 0 is error code; ret > 0 is number of errors */
11329 : : /* in pStruct[iInchiRec][iMobileH][iComponent].nError */
11330 [ # # ]: 0 : if (ret)
11331 : : {
11332 : : #if ( FIX_GAF_2019_1==1 )
11333 [ # # ]: 0 : if (ret > 0)
11334 : : {
11335 : 0 : ret = RI_ERR_PROGR;
11336 : : }
11337 : : #endif
11338 : : /* conversion error */
11339 : 0 : (*num_errors)++;
11340 : 0 : goto dealloc;
11341 : : }
11342 : :
11343 : : /* Attempt to fix the numumber of removed protons in case of Mobile-H */
11344 [ # # ]: 0 : if (!pOneInput->nNumProtons[INCHI_BAS][TAUT_YES].pNumProtons &&
11345 [ # # ]: 0 : !pOneInput->nNumProtons[INCHI_REC][TAUT_YES].pNumProtons)
11346 : : {
11347 : 0 : ret = AddProtonAndIsoHBalanceToMobHStruct(ic, pCG, ip, sd, num_inp, bHasSomeFixedH, *pszCurHdr, pStruct, pOneInput);
11348 : :
11349 [ # # ]: 0 : if (ret < 0)
11350 : : {
11351 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Add/Remove protons error", "; ");
11352 : 0 : (*num_errors)++;
11353 : 0 : goto dealloc;
11354 : : }
11355 : : }
11356 : :
11357 : : /* Compare InChI from the Reversed Structure to the original input InChI */
11358 : 0 : ret = CompareAllOrigInchiToRevInChI(pStruct, pOneInput, bHasSomeFixedH, num_inp, *pszCurHdr);
11359 [ # # ]: 0 : if (ret < 0)
11360 : : {
11361 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "InChI compare error", "; ");
11362 : 0 : (*num_errors)++;
11363 : 0 : goto dealloc;
11364 : : }
11365 : :
11366 : : /* Compare disconnected versions */
11367 : 0 : ret = CompareAllDisconnectedOrigInchiToRevInChI(pStruct, pOneInput,
11368 : : bHasSomeFixedH, num_inp, *pszCurHdr);
11369 [ # # ]: 0 : if (ret < 0)
11370 : : {
11371 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "InChI compare2 error", "; ");
11372 : 0 : (*num_errors)++;
11373 : 0 : goto dealloc;
11374 : : }
11375 : :
11376 [ # # ]: 0 : if (WarningFlags)
11377 : : {
11378 [ # # ]: 0 : for (i = 0; i < 2; i++)
11379 : : {
11380 [ # # ]: 0 : for (j = 0; j < TAUT_NUM; j++)
11381 : : {
11382 : 0 : WarningFlags[i][j] = (unsigned long)pOneInput->CompareInchiFlags[i][j];
11383 : : }
11384 : : }
11385 : : }
11386 : :
11387 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11388 : :
11389 : : #ifndef COMPILE_ANSI_ONLY
11390 : : ret = DisplayStructureComponents(pCG, ip, sd, num_inp, *pszCurHdr, &srm, bReqNonTaut, pStruct, pOneInput);
11391 : : if (ret < 0)
11392 : : {
11393 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Display structure error", "; ");
11394 : : }
11395 : : #endif
11396 : :
11397 : :
11398 : 0 : InchiTimeGet(pulTStart);
11399 : :
11400 : 0 : ret = MergeStructureComponents(ip, sd, num_inp, *pszCurHdr, &srm, bReqNonTaut, pStruct, pOneInput);
11401 : :
11402 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11403 : :
11404 [ # # ]: 0 : if (ret < 0)
11405 : : {
11406 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Merge Components error", "; ");
11407 : 0 : (*num_errors)++;
11408 : 0 : goto dealloc;
11409 : : }
11410 : :
11411 : :
11412 : : #ifdef TARGET_API_LIB
11413 : : /*------------- for debug only -------------------
11414 : : InchiTimeGet(&ulTStart);
11415 : : ret = OutputInChIOutOfStrFromINChI( ic, pCG,
11416 : : ip, sd, num_inp, 0,
11417 : : pOut, pLog, &OneInput,
11418 : : save_opt_bits);
11419 : : ulProcessingTime += InchiTimeElapsed( ic, pulTStart);
11420 : : if ( ret < 0 )
11421 : : {
11422 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Restored structure to InChI conversion failed", "; ");
11423 : : goto dealloc;
11424 : : }
11425 : : -------------------------------------------------*/
11426 [ # # # # ]: 0 : if (at && num_at)
11427 : : {
11428 : 0 : *at = pOneInput->atom;
11429 : 0 : *num_at = pOneInput->num_atoms;
11430 : 0 : pOneInput->atom = NULL;
11431 : 0 : *polymer = pOneInput->polymer;
11432 : 0 : pOneInput->polymer = NULL;
11433 : 0 : *v3000 = pOneInput->v3000;
11434 : 0 : pOneInput->v3000 = NULL;
11435 : : }
11436 : : #else
11437 : :
11438 : : InchiTimeGet(pulTStart);
11439 : :
11440 : : ret = OutputInChIOutOfStrFromINChI(ic, pCG, ip, sd, num_inp, bINChIOutputOptions,
11441 : : pOut, NULL, pOneInput, bHasSomeFixedH, save_opt_bits);
11442 : :
11443 : : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11444 : :
11445 : : if (ret < 0)
11446 : : {
11447 : : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Restored structure to InChI conversion error", "; ");
11448 : : (*num_errors)++;
11449 : : goto dealloc;
11450 : : }
11451 : : #endif
11452 : :
11453 [ # # ]: 0 : if (szMessage)
11454 : : {
11455 : 0 : int len, retcomp = 0, retcomp1 = 0;
11456 : 0 : InchiTimeGet(pulTStart);
11457 : 0 : retcomp = FillOutCompareMessage(szMessage, nMessageLen, pOneInput->CompareInchiFlags[0]);
11458 : :
11459 [ # # # # ]: 0 : if (pOneInput->CompareInchiFlags[1][0] || pOneInput->CompareInchiFlags[1][1])
11460 : : {
11461 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "Disconnected: ", "; ");
11462 : 0 : retcomp1 = FillOutCompareMessage(szMessage, nMessageLen, pOneInput->CompareInchiFlags[1]);
11463 : : }
11464 : : /* add a metal warning */
11465 [ # # # # ]: 0 : if (bHasMetal && nInitLenMessage < (len = (int)strlen(szMessage)))
11466 : : {
11467 : 0 : char szMetal[] = " (Metal compound)";
11468 : : int shift;
11469 [ # # ]: 0 : if (len + (int)sizeof(szMetal) > nMessageLen)
11470 : : {
11471 : 0 : len = nMessageLen - (int)sizeof(szMetal);
11472 : : }
11473 : 0 : shift = nInitLenMessage + (int)sizeof(szMetal) - 1;
11474 : 0 : memmove(szMessage + shift, szMessage + nInitLenMessage, ((long long)len - nInitLenMessage) * sizeof(szMessage[0])); /* djb-rwth: cast operator added */
11475 : 0 : memcpy(szMessage + nInitLenMessage, szMetal, sizeof(szMetal) - sizeof(szMessage[0]));
11476 : 0 : szMessage[shift + len - nInitLenMessage] = '\0';
11477 : : }
11478 : :
11479 : 0 : retcomp = inchi_min(retcomp, retcomp1);
11480 : :
11481 [ # # ]: 0 : if (retcomp < 0 &&
11482 [ # # ]: 0 : (ip_inp->bINChIOutputOptions2 & INCHI_OUT_MISMATCH_AS_ERROR)
11483 : : )
11484 : : {
11485 : 0 : ret = RI_ERR_MISMATCH;
11486 : : /* AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "* Treated as error by user supplied option", "; "); */
11487 : 0 : (*num_errors)++;
11488 : 0 : goto dealloc;
11489 : : }
11490 : :
11491 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart);
11492 : : }
11493 : :
11494 : 0 : ret = 0;
11495 : :
11496 : 0 : dealloc:
11497 : : /* Deallocate */
11498 [ # # ]: 0 : if (ret)
11499 : : {
11500 [ # # ]: 0 : if (ret < 0)
11501 : : {
11502 [ # # ]: 0 : if (ret == CT_USER_QUIT_ERR)
11503 : : {
11504 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Terminated by the user*", "; ");
11505 : : }
11506 : : else
11507 : : {
11508 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Conversion failed*", "; ");
11509 : : }
11510 : : }
11511 : : else
11512 : : {
11513 : : int iRec, iMob, iComp, nComp, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11514 : : char szTemp[128];
11515 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, "*Conversion failed on component(s)", "; ");
11516 : 0 : len = (int)strlen(szMessage); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11517 [ # # ]: 0 : for (iRec = 0; iRec < INCHI_NUM; iRec++)
11518 : : {
11519 [ # # ]: 0 : for (iMob = bHasSomeFixedH ? TAUT_NON : TAUT_YES; iMob < TAUT_NUM; iMob++)
11520 : : {
11521 : 0 : nComp = pOneInput->nNumComponents[iRec][iMob];
11522 [ # # ]: 0 : if (!pStruct[iRec][iMob])
11523 : : {
11524 : 0 : continue;
11525 : : }
11526 [ # # ]: 0 : for (iComp = 0; iComp < nComp; iComp++)
11527 : : {
11528 [ # # ]: 0 : if (pStruct[iRec][iMob][iComp].nError)
11529 : : {
11530 : 0 : char* szFormula = pOneInput->pInpInChI[iRec][iMob][iComp].szHillFormula;
11531 [ # # ]: 0 : sprintf(szTemp,
11532 : : #if ( FIX_DALKE_BUGS == 1 )
11533 : : " %s%s%d(%.96s)",
11534 : : #else
11535 : : " %s%s%d(%s)",
11536 : : #endif
11537 [ # # # # ]: 0 : !bHasSomeReconnected ? "" : iRec ? "R" : "D",
11538 [ # # # # ]: 0 : !bHasSomeFixedH ? "" : iMob ? "M" : "F",
11539 : : iComp + 1, szFormula ? szFormula : "???");
11540 : 0 : AddOneMsg(szMessage, (int)strlen(szMessage), nMessageLen, szTemp, NULL);
11541 : : }
11542 : : }
11543 : : }
11544 : : }
11545 : : } /* if ( ret > 0 ) */
11546 : : } /* if ( ret ) */
11547 : :
11548 : :
11549 : 0 : InchiTimeGet(pulTStart);
11550 : :
11551 : : /* Print one structure report */
11552 [ # # # # : 0 : if (szMessage && szMsg && nMsgLen > 1) /* djb-rwth: additional condition for szMessage */
# # ]
11553 : : {
11554 [ # # ]: 0 : int len = inchi_min((int)strlen(szMessage), nMsgLen - 1);
11555 [ # # ]: 0 : if (len > 0)
11556 : : {
11557 : 0 : memcpy(szMsg, szMessage, len);
11558 : 0 : szMsg[len] = '\0';
11559 : : }
11560 : : else
11561 : : {
11562 : 0 : szMsg[0] = '\0';
11563 : : }
11564 : : }
11565 : :
11566 [ # # # # ]: 0 : if (szMessage && (nInitLenMessage < (int)strlen(szMessage))) /* djb-rwth: additional condition for szMessage */
11567 : : {
11568 : 0 : inchi_ios_eprint(pLog, "%s\n", szMessage);
11569 : : }
11570 : : #ifndef TARGET_API_LIB
11571 : : else
11572 : : {
11573 : : /*^^^inchi_ios_eprint( stderr, "%s\r", szMessage );*/
11574 : : inchi_fprintf(stderr, "%s\r", szMessage);
11575 : : }
11576 : : #endif
11577 : :
11578 : 0 : FreeStrFromINChI(pStruct, pOneInput->nNumComponents);
11579 : 0 : FreeInpInChI(pOneInput);
11580 [ # # ]: 0 : if (*pszCurHdr)
11581 : : {
11582 [ # # ]: 0 : inchi_free(*pszCurHdr);
11583 : 0 : *pszCurHdr = NULL;
11584 : : }
11585 : :
11586 : : INCHI_HEAPCHK
11587 : :
11588 : 0 : ulProcessingTime += InchiTimeElapsed(ic, pulTStart); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
11589 : :
11590 : 0 : return ret;
11591 : : }
11592 : :
11593 : :
11594 : : /****************************************************************************/
11595 : 1 : int DetectAndExposePolymerInternals(INCHI_IOSTREAM* is)
11596 : : {
11597 : 1 : int i, j, elindex, ret = 0, nheavy = 0,
11598 : 1 : nstars = 0, zlen = 0, star0 = 0, i_last_sym,
11599 : 1 : slen = 0, i2 = 0, ninsert = 0, kinsert, lead_pos, nc, ntimes, nc_max;
11600 : : const char* p, * pz, * pz2, * pr, * pend, * q;
11601 : 1 : char prev_layer_symbol = '0';
11602 : 1 : char element[3], * tmpstr = NULL, * edited_s = NULL;
11603 : 1 : int* insert_pos = NULL; /* inserts go before insert_pos[k] */
11604 : 1 : char* s = NULL, * s2 = NULL;
11605 : : int slength;
11606 : :
11607 : 1 : slength = is->s.nUsedLength;
11608 : 1 : s = (char*)inchi_calloc(2 * (long long)slength + 32, sizeof(char)); /* djb-rwth: cast operator added */
11609 [ - + ]: 1 : if (!s)
11610 : : {
11611 : 0 : goto endf;
11612 : : }
11613 : :
11614 : : /* Remove but save a tail (AuxInfo, InChIKey, etc.) if any */
11615 : 1 : strcpy(s, is->s.pStr);
11616 [ + + ]: 23 : for (i = 0; i < slength; i++)
11617 : : {
11618 [ - + ]: 22 : if (isspace(UCINT s[i]))
11619 : : {
11620 : 0 : i2 = i;
11621 : 0 : break;
11622 : : }
11623 : : }
11624 [ - + ]: 1 : if (i2)
11625 : : {
11626 : 0 : s2 = (char*)inchi_calloc((long long)slength - (long long)i2 + 2, sizeof(char)); /* djb-rwth: cast operators added */
11627 [ # # ]: 0 : if (!s2) goto endf;
11628 : 0 : strcpy(s2, s + i2);
11629 : 0 : s[i2] = '\0';
11630 : : }
11631 : :
11632 : 1 : i_last_sym = strlen(s) - 1;
11633 : 1 : p = strstr(s, "InChI=1");
11634 [ - + ]: 1 : if (!p)
11635 : : {
11636 : 0 : goto endf;
11637 : : }
11638 : :
11639 : 1 : pz = strstr(p, "/z");
11640 [ + - ]: 1 : if (!pz)
11641 : : {
11642 : 1 : goto endf;
11643 : : }
11644 : 0 : pz++;
11645 : :
11646 : : /* Check formula */
11647 : 0 : p = strchr(p, '/');
11648 [ # # ]: 0 : if (!p) /* djb-rwth: fixing coverity ID #499505 */
11649 : : {
11650 : 0 : goto endf;
11651 : : }
11652 : 0 : p++;
11653 : 0 : pend = strchr(p, '/');
11654 : 0 : ntimes = 1;
11655 [ # # ]: 0 : while (p != pend)
11656 : : {
11657 [ # # ]: 0 : if (isdigit(*p))
11658 : : {
11659 : 0 : ntimes = (int)inchi_strtol(p, &q, 10);
11660 : : #if ( CHECK_STRTOL_ATNUMB==1 )
11661 [ # # # # ]: 0 : if (ntimes > MAX_ATOMS || ntimes < 0)
11662 : : {
11663 : : #if (FIX_GAF_2020_25607 == 1)
11664 : 0 : ret = RI_ERR_SYNTAX;
11665 : 0 : goto endf;
11666 : : #else
11667 : : return RI_ERR_SYNTAX; /* syntax error */
11668 : : #endif
11669 : : }
11670 : : #endif
11671 : 0 : p = q;
11672 : : }
11673 : : else
11674 : : {
11675 [ # # ]: 0 : if (*p == '.')
11676 : : {
11677 : 0 : ntimes = 1;
11678 : : }
11679 : : }
11680 : :
11681 [ # # ]: 0 : if (!isupper(UCINT * p))
11682 : : {
11683 : 0 : ret = -1;
11684 : 0 : goto endf;
11685 : : }
11686 : :
11687 : 0 : j = 0;
11688 : 0 : element[j++] = *p++;
11689 [ # # # # ]: 0 : if (*p && islower(UCINT * p))
11690 : : {
11691 : 0 : element[j++] = *p++;
11692 : : }
11693 : 0 : element[j++] = '\0';
11694 [ # # # # ]: 0 : if (*p && isdigit(UCINT * p))
11695 : : {
11696 : 0 : elindex = (int)inchi_strtol(p, &q, 10);
11697 : : #if ( CHECK_STRTOL_ATNUMB==1 )
11698 [ # # # # ]: 0 : if (elindex > MAX_ATOMS || elindex < 0)
11699 : : {
11700 : : #if (FIX_GAF_2020_25607 == 1)
11701 : 0 : ret = RI_ERR_SYNTAX;
11702 : 0 : goto endf;
11703 : : #else
11704 : : return RI_ERR_SYNTAX; /* syntax error */
11705 : : #endif
11706 : :
11707 : : }
11708 : : #endif
11709 : 0 : p = q;
11710 : : }
11711 : : else
11712 : : {
11713 : 0 : elindex = 1;
11714 : : }
11715 [ # # ]: 0 : if (!elindex)
11716 : : {
11717 : 0 : ret = -1;
11718 : 0 : goto endf;
11719 : : }
11720 : : #if ( FIX_GAF_2019_2==1 )
11721 [ # # ]: 0 : if (ERR_ELEM == get_periodic_table_number(element))
11722 : : {
11723 : 0 : ret = -1;
11724 : 0 : goto endf;
11725 : : }
11726 : : #endif
11727 [ # # # # ]: 0 : if (element[0] != 'H' || element[1])
11728 : : {
11729 : 0 : nheavy += ntimes * elindex;
11730 : : }
11731 : :
11732 [ # # ]: 0 : if (*p == '.')
11733 : : {
11734 : 0 : p++;
11735 : : }
11736 : : }
11737 : :
11738 : : #if ( FIX_GAF_2019_2==1 )
11739 : 0 : insert_pos = (int*)inchi_calloc((long long)is->s.nUsedLength + 1, sizeof(int)); /* djb-rwth: cast operator added */
11740 : : #else
11741 : : /* max num of insert positions is 2 in formulas + Npolymeric units, the latter may not be > nheavy */
11742 : : insert_pos = (int*)inchi_calloc(nheavy + 32, sizeof(int));
11743 : : #endif
11744 [ # # ]: 0 : if (!insert_pos)
11745 : : {
11746 : 0 : ret = -2;
11747 : 0 : goto endf;
11748 : : }
11749 : :
11750 : 0 : ninsert = 0;
11751 [ # # ]: 0 : if (pend)
11752 : : {
11753 : 0 : insert_pos[ninsert] = (int)(pend - s);
11754 : : }
11755 : : else
11756 : : {
11757 : 0 : insert_pos[ninsert] = i_last_sym;
11758 : : }
11759 : 0 : ninsert++;
11760 : :
11761 : : /* Check hidden stars */
11762 : 0 : lead_pos = (int)(pz - s);
11763 : 0 : pend = strchr(pz, '/');
11764 [ # # ]: 0 : if (pend)
11765 : : {
11766 : 0 : zlen = (int)(pend - pz);
11767 : : }
11768 : : else
11769 : : {
11770 : 0 : zlen = (int)strlen(pz);
11771 : : }
11772 : 0 : tmpstr = (char*)inchi_calloc((long long)zlen + 32, sizeof(char)); /* djb-rwth: cast operator added */
11773 [ # # ]: 0 : if (!tmpstr)
11774 : : {
11775 : 0 : ret = -2;
11776 : 0 : goto endf;
11777 : : }
11778 : 0 : memcpy(tmpstr, pz, zlen);
11779 : 0 : ret = DetectHiddenPolymerStuff(tmpstr, zlen, &ninsert, insert_pos, lead_pos, &nstars);
11780 [ # # ]: 0 : if (ret)
11781 : : {
11782 : 0 : goto endf;
11783 : : }
11784 [ # # ]: 0 : if (!nstars)
11785 : : {
11786 : 0 : goto endf;
11787 : : }
11788 : :
11789 : : /* Have second '/z' ? */
11790 : 0 : pr = strstr(s, "/r");
11791 [ # # ]: 0 : if (pr)
11792 : : {
11793 : 0 : pr++;
11794 : :
11795 : 0 : pend = strchr(pr, '/');
11796 [ # # ]: 0 : if (pend)
11797 : : {
11798 : 0 : insert_pos[ninsert] = (int)(pend - s);
11799 : : }
11800 : : else
11801 : : {
11802 : 0 : insert_pos[ninsert] = i_last_sym;
11803 : : }
11804 : 0 : ninsert++;
11805 : :
11806 : 0 : pz2 = strstr(pr, "/z");
11807 [ # # ]: 0 : if (pz2)
11808 : : {
11809 : 0 : pz2++;
11810 : 0 : lead_pos = (int)(pz2 - s);
11811 : 0 : pend = strchr(pz2, '/');
11812 [ # # ]: 0 : if (pend)
11813 : : {
11814 : 0 : zlen = (int)(pend - pz2);
11815 : : }
11816 : : else
11817 : : {
11818 : 0 : zlen = (int)strlen(pz2);
11819 : : }
11820 [ # # ]: 0 : if (tmpstr)
11821 : : {
11822 [ # # ]: 0 : inchi_free(tmpstr);
11823 : : }
11824 : 0 : tmpstr = (char*)inchi_calloc((long long)zlen + 32, sizeof(char)); /* djb-rwth: cast operator added */
11825 [ # # ]: 0 : if (!tmpstr)
11826 : : {
11827 : 0 : ret = -2;
11828 : 0 : goto endf;
11829 : : }
11830 : 0 : memcpy(tmpstr, pz2, zlen);
11831 : 0 : nstars = 0;
11832 : 0 : ret = DetectHiddenPolymerStuff(tmpstr, zlen, &ninsert, insert_pos, lead_pos, &nstars);
11833 [ # # ]: 0 : if (ret)
11834 : : {
11835 : 0 : goto endf;
11836 : : }
11837 : : }
11838 : : }
11839 : :
11840 : 0 : slen = (int)strlen(s);
11841 : 0 : edited_s = (char*)inchi_calloc((long long)slen * 100 + 32 * 10 * (long long)ninsert, sizeof(char)); /* high reservation */ /* djb-rwth: cast operator added */
11842 [ # # ]: 0 : if (!edited_s)
11843 : : {
11844 : 0 : ret = -2;
11845 : 0 : goto endf;
11846 : : }
11847 : :
11848 : : /* Edits */
11849 : 0 : nc = 0;
11850 : 0 : nc_max = slen * 100 + 32 * 10 * ninsert; /* djb-rwth: fixing oss-fuzz issue #384549256 */
11851 : 0 : kinsert = 0;
11852 : 0 : star0 = nheavy + 1;
11853 [ # # ]: 0 : for (i = 0; i < slen; i++)
11854 : : {
11855 [ # # # # ]: 0 : if (kinsert < ninsert && i == insert_pos[kinsert])
11856 : : {
11857 [ # # # # ]: 0 : if (kinsert == 0 || prev_layer_symbol == 'r')
11858 : : {
11859 : 0 : sprintf(tmpstr, ".%dZz", nstars);
11860 : 0 : star0 = nheavy + 1; /* reset star numbers pool */
11861 : 0 : prev_layer_symbol = '0'; /* avoid printing ';' also */
11862 : : }
11863 : : else
11864 : : {
11865 : 0 : sprintf(tmpstr, "%d,%d-", star0, star0 + 1);
11866 : 0 : star0 += 2;
11867 : : }
11868 : 0 : kinsert++;
11869 [ # # ]: 0 : for (j = 0; j < (int)strlen(tmpstr); j++)
11870 : : {
11871 [ # # ]: 0 : if (nc < nc_max)
11872 : : {
11873 : 0 : edited_s[nc] = tmpstr[j];
11874 : 0 : nc++;
11875 : : }
11876 : : }
11877 : : }
11878 : :
11879 [ # # # # ]: 0 : if ((i == i_last_sym) && (nc < nc_max))
11880 : : {
11881 : 0 : edited_s[nc++] = s[i];
11882 : : }
11883 : :
11884 [ # # # # ]: 0 : if (s[i] == '/' || i == i_last_sym)
11885 : : {
11886 [ # # # # ]: 0 : if (prev_layer_symbol != '0' &&
11887 [ # # ]: 0 : prev_layer_symbol != 'f' &&
11888 [ # # ]: 0 : prev_layer_symbol != 'z' &&
11889 [ # # ]: 0 : prev_layer_symbol != 'p' &&
11890 [ # # ]: 0 : prev_layer_symbol != 'r' &&
11891 : : prev_layer_symbol != 's'
11892 : : )
11893 : 0 : {
11894 : 0 : char addon = ';';
11895 [ # # ]: 0 : if (prev_layer_symbol == 'm')
11896 : : {
11897 : 0 : addon = '.';
11898 : : }
11899 [ # # ]: 0 : for (j = 0; j < nstars; j++)
11900 : : {
11901 [ # # ]: 0 : if (nc < nc_max)
11902 : : {
11903 : 0 : edited_s[nc++] = addon;
11904 : : }
11905 : : }
11906 : : }
11907 [ # # ]: 0 : else if (prev_layer_symbol == 'f')
11908 : : {
11909 [ # # # # ]: 0 : if (s[i - 1] != 'f' && s[i - 2] != '/')
11910 : : {
11911 : 0 : sprintf(tmpstr, ".%dZz", nstars);
11912 [ # # ]: 0 : for (j = 0; j < (int)strlen(tmpstr); j++)
11913 : : {
11914 [ # # ]: 0 : if (nc < nc_max)
11915 : : {
11916 : 0 : edited_s[nc] = tmpstr[j];
11917 : 0 : nc++;
11918 : : }
11919 : : }
11920 : : }
11921 : : }
11922 : :
11923 [ # # ]: 0 : if (i != i_last_sym)
11924 : : {
11925 : 0 : prev_layer_symbol = s[i + 1];
11926 : : }
11927 : : else
11928 : : {
11929 : 0 : break;
11930 : : }
11931 : : }
11932 [ # # ]: 0 : if (nc < nc_max)
11933 : : {
11934 : 0 : edited_s[nc] = s[i];
11935 : 0 : nc++;
11936 : : }
11937 : : }
11938 [ # # ]: 0 : if (nc < nc_max)
11939 : : {
11940 : 0 : edited_s[nc] = '\0';
11941 : : }
11942 : 0 : inchi_strbuf_close(&is->s);
11943 [ # # ]: 0 : inchi_ios_print(is, "%-s%-s\n", edited_s, s2 ? s2 : "");
11944 : :
11945 : 1 : endf:
11946 [ + - ]: 1 : if (s)
11947 : : {
11948 [ + - ]: 1 : inchi_free(s);
11949 : : }
11950 [ - + ]: 1 : if (s2)
11951 : : {
11952 [ # # ]: 0 : inchi_free(s2);
11953 : : }
11954 [ - + ]: 1 : if (edited_s)
11955 : : {
11956 [ # # ]: 0 : inchi_free(edited_s);
11957 : : }
11958 [ - + ]: 1 : if (tmpstr)
11959 : : {
11960 [ # # ]: 0 : inchi_free(tmpstr);
11961 : : }
11962 [ - + ]: 1 : if (insert_pos)
11963 : : {
11964 [ # # ]: 0 : inchi_free(insert_pos);
11965 : : }
11966 : :
11967 : 1 : return ret;
11968 : : }
11969 : :
11970 : :
11971 : : /****************************************************************************/
11972 : 0 : int DetectHiddenPolymerStuff(char* tmpstr,
11973 : : int tmpstrlen,
11974 : : int* ninsert,
11975 : : int* insert_pos,
11976 : : int insert_lead_offset,
11977 : : int* nstars)
11978 : : {
11979 : : char c;
11980 : 0 : int opened, skip, i, i0, closed, ret = 0;
11981 : :
11982 : 0 : *nstars = opened = skip = i0 = 0;
11983 : 0 : closed = 1;
11984 [ # # ]: 0 : for (i = 0; i < tmpstrlen; i++)
11985 : : {
11986 : 0 : c = tmpstr[i];
11987 : :
11988 [ # # ]: 0 : if (c == '(')
11989 : : {
11990 [ # # ]: 0 : if (!closed)
11991 : : {
11992 : 0 : ret = -3; goto endf;
11993 : : }
11994 : 0 : opened = 1;
11995 : 0 : skip = 0;
11996 : 0 : i0 = i;
11997 : : }
11998 [ # # ]: 0 : else if (c == ')')
11999 : : {
12000 [ # # ]: 0 : if (!opened)
12001 : : {
12002 : 0 : ret = -3; goto endf;
12003 : : }
12004 [ # # ]: 0 : if (!skip)
12005 : : {
12006 : 0 : (*nstars) += 2;
12007 : 0 : insert_pos[(*ninsert)] = i0 + 1 + insert_lead_offset;
12008 : 0 : (*ninsert)++;
12009 : : }
12010 : 0 : opened = 0;
12011 : : }
12012 [ # # ]: 0 : else if (c == '-')
12013 : : {
12014 : 0 : skip = 1;
12015 : : }
12016 : : }
12017 : :
12018 : 0 : endf:
12019 : 0 : return ret;
12020 : : }
12021 : :
12022 : :
12023 : : /****************************************************************************
12024 : : Create empty sp3 segment
12025 : : ****************************************************************************/
12026 : 0 : static int SegmentSp3CreateEmpty(const char* str,
12027 : : int bMobileH,
12028 : : INChI* pInpInChI[],
12029 : : int nNumComponents,
12030 : : int state,
12031 : : int* pbAbc)
12032 : : {
12033 : 0 : int ret = 0;
12034 : : int iComponent;
12035 : 0 : int len0 = 0;
12036 [ # # # # ]: 0 : int bIso = (state == IST_MOBILE_H_ISO_SP3 || state == IST_FIXED_H_ISO_SP3);
12037 : 0 : INChI_Stereo** pStereo = NULL;
12038 : 0 : INChI* pInChI = pInpInChI[bMobileH];
12039 : :
12040 [ # # ]: 0 : for (iComponent = 0; iComponent < nNumComponents; iComponent++)
12041 : : {
12042 : 0 : INChI* pIsoInChI = &pInChI[iComponent];
12043 [ # # ]: 0 : pStereo = bIso ? &pIsoInChI->StereoIsotopic : &pIsoInChI->Stereo;
12044 [ # # ]: 0 : if (!*pStereo)
12045 : : {
12046 [ # # ]: 0 : if (!(*pStereo = (INChI_Stereo*)inchi_calloc(1, sizeof(**pStereo))))
12047 : : {
12048 : 0 : return RI_ERR_ALLOC;
12049 : : }
12050 : : }
12051 : : /* allocate empty sp3 stereo */
12052 [ # # ]: 0 : if ((!pStereo[0]->b_parity &&
12053 [ # # ]: 0 : !(pStereo[0]->b_parity = (S_CHAR*)inchi_calloc((long long)len0 + 1, sizeof(pStereo[0]->b_parity[0])))) ||
12054 [ # # ]: 0 : (!pStereo[0]->nBondAtom1 &&
12055 [ # # ]: 0 : !(pStereo[0]->nBondAtom1 = (AT_NUMB*)inchi_calloc((long long)len0 + 1, sizeof(pStereo[0]->nBondAtom1[0])))) ||
12056 [ # # ]: 0 : (!pStereo[0]->nBondAtom2 &&
12057 [ # # ]: 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 */
12058 : : {
12059 : : /* cleanup */
12060 [ # # ]: 0 : if (pStereo[0]->b_parity)
12061 : : {
12062 : : INCHI_HEAPCHK
12063 [ # # ]: 0 : inchi_free(pStereo[0]->b_parity);
12064 : 0 : pStereo[0]->b_parity = NULL;
12065 : : }
12066 [ # # ]: 0 : if (pStereo[0]->nBondAtom1)
12067 : : {
12068 : : INCHI_HEAPCHK
12069 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom1);
12070 : 0 : pStereo[0]->nBondAtom1 = NULL;
12071 : : }
12072 [ # # ]: 0 : if (pStereo[0]->nBondAtom2)
12073 : : {
12074 : : INCHI_HEAPCHK
12075 [ # # ]: 0 : inchi_free(pStereo[0]->nBondAtom2);
12076 : 0 : pStereo[0]->nBondAtom2 = NULL;
12077 : : }
12078 : 0 : return RI_ERR_ALLOC;
12079 : : }
12080 : 0 : pStereo[0]->nCompInv2Abs = NO_VALUE_INT;
12081 : : }
12082 : 0 : ret = nNumComponents + 1;
12083 : :
12084 : 0 : return ret;
12085 : : }
12086 : :
12087 : :
12088 : : /****************************************************************************/
12089 : 0 : static int SegmentSp3StoreStereoCenters(int* pbAbc,
12090 : : const char* pStart,
12091 : : const char* pEnd,
12092 : : int pInChI_iComponent_nNumberOfAtoms,
12093 : : INChI_Stereo* PStereo_0)
12094 : : {
12095 : 0 : const char parity_type[] = "-+u?";
12096 : : const char* p, * q, * r;
12097 : : AT_NUMB nAtom1;
12098 : : int iAtom;
12099 : : int atomParity;
12100 : 0 : int base = 10;
12101 : :
12102 [ # # ]: 0 : if (*pbAbc == 1)
12103 : : {
12104 [ # # ]: 0 : for (p = (char*)pStart, iAtom = 0; p < pEnd; iAtom++)
12105 : : {
12106 [ # # # # ]: 0 : if ((nAtom1 = (AT_NUMB)inchi_strtol(p, &p, base)) &&
12107 : 0 : (atomParity = (int)inchi_strtol(p, &p, 10),
12108 [ # # # # ]: 0 : AB_MIN_KNOWN_PARITY <= atomParity && atomParity <= AB_MAX_KNOWN_PARITY))
12109 : : {
12110 : : ; /* okay */
12111 : : }
12112 : : else
12113 : : {
12114 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12115 : : }
12116 [ # # ]: 0 : if (nAtom1 > pInChI_iComponent_nNumberOfAtoms)
12117 : : {
12118 : 0 : return RI_ERR_SYNTAX;
12119 : : }
12120 : 0 : PStereo_0->t_parity[iAtom] = atomParity;
12121 : 0 : PStereo_0->nNumber[iAtom] = nAtom1;
12122 [ # # # # ]: 0 : if (iAtom && !(PStereo_0->nNumber[iAtom - 1] < nAtom1))
12123 : : {
12124 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12125 : : }
12126 : : }
12127 : : }
12128 : : else
12129 : : {
12130 [ # # ]: 0 : for (p = (char*)pStart, iAtom = 0; p < pEnd; iAtom++, p += (*p == ','))
12131 : : {
12132 : 0 : nAtom1 = (AT_NUMB)inchi_strtol(p, &q, 10);
12133 : : #if ( CHECK_STRTOL_ATNUMB==1 )
12134 [ # # ]: 0 : if (nAtom1 > MAX_ATOMS || nAtom1 < 0)
12135 : : {
12136 : 0 : return RI_ERR_SYNTAX;
12137 : : }
12138 : : #endif
12139 [ # # ]: 0 : if (!(r = strchr((char*)parity_type, *q)))
12140 : : {
12141 : 0 : return RI_ERR_SYNTAX; /* syntax error */
12142 : : }
12143 : 0 : p = q + 1;
12144 : 0 : atomParity = (int)(r - parity_type) + 1;
12145 : 0 : PStereo_0->t_parity[iAtom] = atomParity;
12146 : 0 : PStereo_0->nNumber[iAtom] = nAtom1;
12147 [ # # # # ]: 0 : if (iAtom && !(PStereo_0->nNumber[iAtom - 1] < nAtom1))
12148 : : {
12149 : 0 : return RI_ERR_SYNTAX;
12150 : : }
12151 : : }
12152 : : }
12153 : 0 : PStereo_0->nNumberOfStereoCenters = iAtom;
12154 : : /*if ( iAtom ) {*/
12155 : 0 : PStereo_0->nCompInv2Abs = NO_VALUE_INT; /* unknown yet */
12156 : :
12157 [ # # ]: 0 : if (p != pEnd)
12158 : : {
12159 : 0 : return RI_ERR_SYNTAX;
12160 : : }
12161 : :
12162 : 0 : return 0;
12163 : : }
12164 : :
12165 : :
12166 : : /****************************************************************************
12167 : : Treat multiplier-served components
12168 : : ****************************************************************************/
12169 : 0 : static int SegmentSp3CopyMultiplierCovered(int mpy_component,
12170 : : int iComponent,
12171 : : INChI* pInChI,
12172 : : int bIso,
12173 : : int nCpyType)
12174 : : {
12175 : 0 : int i, ret = 0;
12176 [ # # ]: 0 : for (i = 1; i < mpy_component; i++)
12177 : : {
12178 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, nCpyType, bIso, bIso);
12179 [ # # ]: 0 : if (!ret)
12180 : : {
12181 : 0 : ret = RI_ERR_SYNTAX;
12182 : : }
12183 [ # # ]: 0 : if (ret < 0)
12184 : : {
12185 : 0 : return ret;
12186 : : }
12187 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChI + iComponent, CPY_SP3_M, bIso, bIso);
12188 [ # # ]: 0 : if (!ret)
12189 : : {
12190 : 0 : ret = RI_ERR_SYNTAX;
12191 : : }
12192 [ # # ]: 0 : if (ret < 0)
12193 : : {
12194 : 0 : return ret;
12195 : : }
12196 : : }
12197 : :
12198 : 0 : return ret;
12199 : : }
12200 : :
12201 : :
12202 : : /****************************************************************************
12203 : : Process the abbreviation
12204 : : ****************************************************************************/
12205 : 0 : static int SegmentSp3ProcessAbbreviation(int* mpy_component,
12206 : : int iComponent,
12207 : : int nNumComponents,
12208 : : int val,
12209 : : const char* q,
12210 : : int state,
12211 : : int* pbAbc,
12212 : : int bMobileH,
12213 : : int nCpyType,
12214 : : INChI* pInChI,
12215 : : INChI* pInpInChI_ALT_TAUT_bMobileH)
12216 : : {
12217 : 0 : int i, bIsoTo = -1, bIsoFrom = -1;
12218 : 0 : int ret = 0;
12219 : 0 : INChI* pInChIFrom = NULL;
12220 : :
12221 : : #if (FIX_DALKE_BUGS == 1)
12222 [ # # ]: 0 : if (iComponent + val > nNumComponents)
12223 : : {
12224 : 0 : return RI_ERR_SYNTAX;
12225 : : }
12226 : : #endif
12227 : : #if (FIX_GAF_ISSUES==1)
12228 : : if (iComponent < 0)
12229 : : {
12230 : : return RI_ERR_SYNTAX;
12231 : : }
12232 : : #endif
12233 : :
12234 [ # # # ]: 0 : switch (bMobileH)
12235 : : {
12236 : 0 : case TAUT_YES:
12237 [ # # ]: 0 : switch (state)
12238 : : {
12239 : 0 : case IST_MOBILE_H_ISO_SP3:
12240 [ # # ]: 0 : if (*q == 'm')
12241 : : {
12242 : : /* copy from mobile H to isotopic mobile H */
12243 : 0 : pInChIFrom = pInChI;
12244 : 0 : bIsoTo = 1;
12245 : 0 : bIsoFrom = 0;
12246 : : }
12247 : : else
12248 : : {
12249 [ # # ]: 0 : if (*q == 'e')
12250 : : {
12251 : : /* copy from mobile H to isotopic mobile H */
12252 : 0 : pInChIFrom = pInChI;
12253 : 0 : bIsoTo = 1;
12254 : 0 : bIsoFrom = -1; /* empty */
12255 : : }
12256 : : else
12257 : : {
12258 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12259 : : }
12260 : : }
12261 : 0 : break;
12262 : 0 : default:
12263 : 0 : ret = RI_ERR_SYNTAX;
12264 : 0 : break;
12265 : : }
12266 : 0 : break;
12267 : 0 : case TAUT_NON:
12268 [ # # # ]: 0 : switch (state)
12269 : : {
12270 : 0 : case IST_FIXED_H_SP3:
12271 [ # # ]: 0 : if (*q == 'm')
12272 : : {
12273 : : /* copy from mobile H to fixed H */
12274 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12275 : 0 : bIsoTo = 0;
12276 : 0 : bIsoFrom = 0;
12277 : : }
12278 : : else
12279 : : {
12280 [ # # ]: 0 : if (*q == 'e')
12281 : : {
12282 : : /* copy from mobile H to isotopic mobile H */
12283 : 0 : pInChIFrom = pInChI; /* djb-rwth: addressing coverity ID #499498 -- definitely not a copy-paste error */
12284 : 0 : bIsoTo = 1;
12285 : 0 : bIsoFrom = -1; /* empty */
12286 : : }
12287 : : else
12288 : : {
12289 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12290 : : }
12291 : : }
12292 : 0 : break;
12293 : 0 : case IST_FIXED_H_ISO_SP3:
12294 [ # # ]: 0 : if (*q == 'm')
12295 : : {
12296 : : /* copy from mobile H to fixed isotopic H */
12297 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12298 : 0 : bIsoTo = 1;
12299 : 0 : bIsoFrom = 0;
12300 : : }
12301 : : else
12302 : : {
12303 [ # # ]: 0 : if (*q == 'M')
12304 : : {
12305 : : /* copy from isotopic mobile H to fixed isotopic H */
12306 : 0 : pInChIFrom = pInpInChI_ALT_TAUT_bMobileH;
12307 : 0 : bIsoTo = 1;
12308 : 0 : bIsoFrom = 1;
12309 : : }
12310 : : else
12311 : : {
12312 [ # # ]: 0 : if (*q == 'n')
12313 : : {
12314 : : /* copy from fixed H to fixed isotopic H */
12315 : 0 : pInChIFrom = pInChI;
12316 : 0 : bIsoTo = 1;
12317 : 0 : bIsoFrom = 0;
12318 : : }
12319 : : else
12320 : : {
12321 [ # # ]: 0 : if (*q == 'e')
12322 : : {
12323 : : /* copy from mobile H to isotopic mobile H */
12324 : 0 : pInChIFrom = pInChI;
12325 : 0 : bIsoTo = 1;
12326 : 0 : bIsoFrom = -1; /* empty */
12327 : : }
12328 : : else
12329 : : {
12330 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12331 : : }
12332 : : }
12333 : : }
12334 : : }
12335 : 0 : break;
12336 : 0 : default:
12337 : 0 : ret = RI_ERR_SYNTAX;
12338 : 0 : break;
12339 : : }
12340 : 0 : break;
12341 : :
12342 : 0 : default:
12343 : 0 : ret = RI_ERR_SYNTAX;
12344 : 0 : break;
12345 : : }
12346 : :
12347 [ # # ]: 0 : if (ret < 0)
12348 : : {
12349 : 0 : return ret;
12350 : : }
12351 : :
12352 : : /* copy */
12353 [ # # ]: 0 : for (i = 0; i < val; i++)
12354 : : {
12355 : : /* djb-rwth: fixing oss-fuzz issue #26540 */
12356 : 0 : ret = CopySegment(pInChI + iComponent + i, pInChIFrom + iComponent + i, nCpyType, bIsoTo, bIsoFrom);
12357 [ # # ]: 0 : if (!ret)
12358 : : {
12359 : 0 : ret = RI_ERR_SYNTAX; /* syntax error */
12360 : : }
12361 [ # # ]: 0 : if (ret < 0)
12362 : : {
12363 : 0 : return ret;
12364 : : }
12365 [ # # ]: 0 : if (bIsoFrom >= 0)
12366 : : {
12367 [ # # ]: 0 : INChI_Stereo* pStereoTo = bIsoTo ? pInChI[iComponent + i].StereoIsotopic : pInChI[iComponent + i].Stereo;
12368 [ # # ]: 0 : if (pStereoTo)
12369 : : {
12370 : 0 : pStereoTo->nCompInv2Abs = NO_VALUE_INT; /* in case there in no /m segment after this */
12371 : : }
12372 : : }
12373 : : }
12374 : :
12375 : 0 : *mpy_component = val;
12376 : :
12377 : 0 : return ret;
12378 : : }
12379 : :
12380 : :
12381 : : /* Internal: a generic parser/extractor interface */
12382 : 0 : int extract_from_inchi_string(char* sinchi, InpInChI* OneInput)
12383 : : {
12384 : 0 : int ret = _IS_OKAY;
12385 : :
12386 : 0 : char* strHdr = NULL;
12387 : : SEGM_LINE Line;
12388 : 0 : SEGM_LINE* pLine = &Line;
12389 : : int pState, nErr;
12390 : 0 : const int bInChI2Structure = 1, bReadCoord = 1;
12391 : : int input_is_stdinchi, input_has_save_opt;
12392 : : unsigned char input_save_opt_bits;
12393 : : int end_of_data_reached, read_inchi_ok;
12394 : : INCHI_IOSTREAM tmpinputstream;
12395 : 0 : INCHI_IOSTREAM* pInp = &tmpinputstream;
12396 : 0 : INCHI_MODE nMode = 0;
12397 : : /* djb-rwth: removing redundant code */
12398 : :
12399 : 0 : nMode = (INCHI_MODE)530462;
12400 : :
12401 : 0 : memset(OneInput, 0, sizeof(*OneInput)); /* djb-rwth: memset_s C11/Annex K variant? */
12402 : 0 : memset(pLine, 0, sizeof(pLine[0])); /* djb-rwth: memset_s C11/Annex K variant? */
12403 : 0 : OneInput->polymer = NULL; /* v. 1.05 added */
12404 : 0 : OneInput->v3000 = NULL;
12405 : 0 : inchi_ios_init(pInp, INCHI_IOS_TYPE_STRING, NULL);
12406 : 0 : inchi_ios_print(pInp, "%-s", sinchi);
12407 : :
12408 : 0 : ret = DetectAndExposePolymerInternals(pInp);
12409 [ # # ]: 0 : if (ret)
12410 : : {
12411 : 0 : ret = _IS_ERROR;
12412 : 0 : goto exit_function;
12413 : : }
12414 : : /*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+;;");*/
12415 : 0 : ret = InChILine2Data(pInp,
12416 : : pLine,
12417 : : &strHdr,
12418 : : &pState,
12419 : : &nErr,
12420 : 0 : OneInput->pInpInChI,
12421 : 0 : OneInput->nNumComponents,
12422 : 0 : OneInput->nNumProtons,
12423 : 0 : OneInput->s,
12424 : : bReadCoord,
12425 : : bInChI2Structure,
12426 : : nMode,
12427 : : &input_is_stdinchi,
12428 : : &input_has_save_opt,
12429 : : &input_save_opt_bits,
12430 : : &OneInput->polymer,
12431 : : &OneInput->v3000);
12432 : :
12433 [ # # # # ]: 0 : end_of_data_reached = ret == RI_ERR_EOL || ret == RI_ERR_EOF;
12434 [ # # # # ]: 0 : read_inchi_ok = end_of_data_reached && !nErr;
12435 [ # # ]: 0 : if (!read_inchi_ok)
12436 : : {
12437 : 0 : ret = _IS_ERROR;
12438 : 0 : goto exit_function;
12439 : : }
12440 : : else
12441 : : {
12442 : 0 : ret = _IS_OKAY;
12443 : : }
12444 : :
12445 : :
12446 : 0 : exit_function:
12447 [ # # ]: 0 : if (strHdr)
12448 : : {
12449 [ # # ]: 0 : inchi_free(strHdr);
12450 : 0 : strHdr = NULL;
12451 : : }
12452 [ # # ]: 0 : if (pLine->str)
12453 : : {
12454 [ # # ]: 0 : inchi_free(pLine->str);
12455 : : }
12456 : 0 : inchi_ios_close(pInp);
12457 : :
12458 : 0 : return ret;
12459 : : }
12460 : :
12461 : :
12462 : : /****************************************************************************
12463 : : Extract_stereo_info_from_inchi_string
12464 : : ****************************************************************************/
12465 : 0 : int extract_stereo_info_from_inchi_string(char* sinchi,
12466 : : int nat,
12467 : : int* orig,
12468 : : int* at_stereo_mark_orig)
12469 : : {
12470 : : InpInChI OneInput;
12471 : 0 : int ret = _IS_OKAY;
12472 : 0 : int icomponent, i, bReconn = 0, bMobileH = 1, at_offset_component = 0;
12473 : :
12474 : : /* 0 is INCHI_PARITY_NONE */
12475 : 0 : memset(at_stereo_mark_orig, 0, ((long long)nat + 1) * sizeof(int)); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
12476 : :
12477 : 0 : ret = extract_from_inchi_string(sinchi, &OneInput);
12478 [ # # # # ]: 0 : if (ret == _IS_ERROR || ret == _IS_FATAL)
12479 : : {
12480 : 0 : ret = _IS_ERROR;
12481 : 0 : goto exit_function;
12482 : : }
12483 : :
12484 : :
12485 : :
12486 [ # # ]: 0 : for (icomponent = 0; icomponent < OneInput.nNumComponents[bReconn][bMobileH]; icomponent++)
12487 : : {
12488 : 0 : INChI pI = OneInput.pInpInChI[bReconn][bMobileH][icomponent];
12489 [ # # ]: 0 : if (NULL == pI.Stereo)
12490 : : {
12491 : 0 : continue;
12492 : : }
12493 [ # # ]: 0 : for (i = 0; i < pI.Stereo->nNumberOfStereoCenters; i++)
12494 : : {
12495 : 0 : int icano = pI.Stereo->nNumber[i] + at_offset_component;
12496 : 0 : int iorig = orig[icano];
12497 : 0 : at_stereo_mark_orig[iorig] = pI.Stereo->t_parity[i];
12498 : : }
12499 : 0 : at_offset_component += pI.nNumberOfAtoms;
12500 : : }
12501 : :
12502 : 0 : exit_function:
12503 : 0 : FreeInpInChI(&OneInput);
12504 : :
12505 : 0 : return ret;
12506 : : }
12507 : :
12508 : :
12509 : : /****************************************************************************
12510 : : Extract all backbone bonds, in all units, from InChI string
12511 : : NB: as units are not 'inter-crossing' any bkbond belongs to some unique CRU
12512 : : ****************************************************************************/
12513 : 0 : int extract_all_backbone_bonds_from_inchi_string(char* sinchi,
12514 : : int* n_all_bkb_orig,
12515 : : int* orig,
12516 : : int* all_bkb_orig)
12517 : : {
12518 : : InpInChI OneInput;
12519 : 0 : int i, ret = _IS_OKAY;
12520 : :
12521 : 0 : ret = extract_from_inchi_string(sinchi, &OneInput);
12522 [ # # # # ]: 0 : if (ret == _IS_ERROR || ret == _IS_FATAL)
12523 : : {
12524 : 0 : ret = _IS_ERROR;
12525 : 0 : goto exit_function;
12526 : : }
12527 : :
12528 [ # # ]: 0 : for (i = 0; i < OneInput.polymer->n; i++)
12529 : : {
12530 : : int j;
12531 : 0 : OAD_PolymerUnit* u = OneInput.polymer->units[i];
12532 [ # # ]: 0 : for (j = 0; j < u->nbkbonds; j++)
12533 : : {
12534 : : int icano1, iorig1, icano2, iorig2;
12535 : 0 : icano1 = u->bkbonds[j][0];
12536 : 0 : iorig1 = orig[icano1];
12537 : 0 : icano2 = u->bkbonds[j][1];
12538 : 0 : iorig2 = orig[icano2];
12539 : :
12540 : 0 : all_bkb_orig[2 * (*n_all_bkb_orig)] = iorig1;
12541 : 0 : all_bkb_orig[2 * (*n_all_bkb_orig) + 1] = iorig2;
12542 : 0 : (*n_all_bkb_orig)++;
12543 : : }
12544 : : }
12545 : :
12546 : 0 : FreeInpInChI(&OneInput);
12547 : :
12548 : 0 : exit_function:
12549 : 0 : return ret;
12550 : : }
12551 : :
12552 : : #endif /* READ_INCHI_STRING */
|