Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <ctype.h>
8 : : #include <string.h>
9 : : #include <math.h>
10 : : #include <float.h>
11 : : #include <limits.h>
12 : :
13 : : #include "mode.h"
14 : : #include "mol_fmt.h"
15 : :
16 : : #include "ichierr.h"
17 : : #include "util.h"
18 : : #include "ichi_io.h"
19 : :
20 : : #include "bcf_s.h"
21 : : #include "stb_sprintf.h"
22 : :
23 : : /*
24 : : Molfile V3000 related procedures
25 : :
26 : : */
27 : :
28 : : static int get_actual_atom_number(int index, int n, int *orig, int *fin);
29 : :
30 : : /****************************************************************************
31 : : Init V3000 reader
32 : : ****************************************************************************/
33 : 57 : int MolfileV3000Init(MOL_FMT_CTAB *ctab,
34 : : char *pStrErr)
35 : : {
36 : 57 : int ret = 0;
37 : : int i;
38 : :
39 : : /* STAR ATOMS */
40 : 57 : ctab->v3000->n_star_atoms = 0;
41 : 57 : ctab->v3000->n_non_star_atoms = 0;
42 : :
43 [ + - ]: 57 : if (ctab->n_atoms)
44 : : {
45 : 57 : ctab->v3000->atom_index_orig = (int *)inchi_calloc(ctab->n_atoms, sizeof(int));
46 : 57 : ctab->v3000->atom_index_fin = (int *)inchi_calloc(ctab->n_atoms, sizeof(int));
47 [ + - + - ]: 57 : if (ctab->v3000->atom_index_orig && ctab->v3000->atom_index_fin) /* djb-rwth: fixing a NULL pointer dereference */
48 : : {
49 [ + + ]: 708 : for (i = 0; i < ctab->n_atoms; i++) /* protective */
50 : : {
51 : 651 : ctab->v3000->atom_index_orig[i] = -1;
52 : 651 : ctab->v3000->atom_index_fin[i] = -1;
53 : : }
54 : : }
55 : : }
56 : : else
57 : : {
58 : 0 : ctab->v3000->atom_index_orig = NULL;
59 : 0 : ctab->v3000->atom_index_fin = NULL;
60 : : }
61 : :
62 : : /* HAPTIC BONDS */
63 : 57 : ctab->v3000->n_haptic_bonds = 0;
64 : 57 : ctab->v3000->haptic_bonds = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
65 [ - + ]: 57 : if (!ctab->v3000->haptic_bonds)
66 : : {
67 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
68 : 0 : return -1;
69 : : }
70 : 57 : ret = NumLists_Alloc(ctab->v3000->haptic_bonds, 8);
71 [ - + ]: 57 : if (ret < 0)
72 : : {
73 : 0 : ctab->v3000->haptic_bonds = NULL;
74 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
75 : 0 : return -1;
76 : : }
77 : :
78 : : /* STEABS */
79 : 57 : ctab->v3000->n_steabs = 0;
80 : 57 : ctab->v3000->steabs = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
81 [ - + ]: 57 : if (!ctab->v3000->steabs)
82 : : {
83 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
84 : 0 : return -1;
85 : : }
86 : 57 : ret = NumLists_Alloc(ctab->v3000->steabs, 1);
87 [ - + ]: 57 : if (ret < 0)
88 : : {
89 : 0 : ctab->v3000->steabs = NULL;
90 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
91 : 0 : return -1;
92 : : }
93 : : /* STEREL */
94 : 57 : ctab->v3000->n_sterel = 0;
95 : 57 : ctab->v3000->sterel = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
96 [ - + ]: 57 : if (!ctab->v3000->sterel)
97 : : {
98 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
99 : 0 : return -1;
100 : : }
101 : 57 : ret = NumLists_Alloc(ctab->v3000->sterel, 4);
102 [ - + ]: 57 : if (ret < 0)
103 : : {
104 : 0 : ctab->v3000->sterel = NULL;
105 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
106 : 0 : return -1;
107 : : }
108 : : /* STERAC */
109 : 57 : ctab->v3000->n_sterac = 0;
110 : 57 : ctab->v3000->sterac = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
111 [ - + ]: 57 : if (!ctab->v3000->sterac)
112 : : {
113 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
114 : 0 : return -1;
115 : : }
116 : 57 : ret = NumLists_Alloc(ctab->v3000->sterac, 4);
117 [ - + ]: 57 : if (ret < 0)
118 : : {
119 : 0 : ctab->v3000->sterac = NULL;
120 : 0 : AddErrorMessage(pStrErr, "Out of RAM");
121 : 0 : return -1;
122 : : }
123 : :
124 : 57 : return ret;
125 : : }
126 : :
127 : : /****************************************************************************
128 : : Delete V3000 reader data
129 : : ****************************************************************************/
130 : 57 : int DeleteMolfileV3000Info(MOL_FMT_v3000 *v3000)
131 : : {
132 [ + - ]: 57 : if (v3000)
133 : : {
134 : :
135 [ + - ]: 57 : if (v3000->atom_index_orig)
136 : : {
137 [ + - ]: 57 : inchi_free(v3000->atom_index_orig);
138 : : }
139 : :
140 [ + - ]: 57 : if (v3000->atom_index_fin)
141 : : {
142 [ + - ]: 57 : inchi_free(v3000->atom_index_fin);
143 : : }
144 : :
145 [ + - ]: 57 : if (v3000->haptic_bonds)
146 : : {
147 : 57 : NumLists_Free(v3000->haptic_bonds);
148 : 57 : free(v3000->haptic_bonds);
149 : : }
150 : :
151 [ + - ]: 57 : if (v3000->steabs)
152 : : {
153 : 57 : NumLists_Free(v3000->steabs);
154 : 57 : free(v3000->steabs);
155 : : }
156 : :
157 [ + - ]: 57 : if (v3000->sterel)
158 : : {
159 : 57 : NumLists_Free(v3000->sterel);
160 : 57 : free(v3000->sterel);
161 : : }
162 : :
163 [ + - ]: 57 : if (v3000->sterac)
164 : : {
165 : 57 : NumLists_Free(v3000->sterac);
166 : 57 : free(v3000->sterac);
167 : : }
168 : :
169 [ + - ]: 57 : inchi_free(v3000);
170 : 57 : v3000 = NULL;
171 : : }
172 : :
173 : 57 : return 0;
174 : : }
175 : :
176 : : /****************************************************************************
177 : : Extended version of inchi_fgetsLf which is able of reading
178 : : concatenated lines (ending with '-') of V3000 Molfile.
179 : : Also removes "M V30 " prefix" and normalizes the rest of string
180 : : ****************************************************************************/
181 : 0 : char *inchi_fgetsLf_V3000(char *line, INCHI_IOSTREAM *inp_stream)
182 : : {
183 : 0 : char *p = NULL;
184 : 0 : int len = 0;
185 : :
186 : 0 : p = inchi_fgetsLf(line, MOL_FMT_V3000_INPLINELEN, inp_stream);
187 [ # # ]: 0 : if (!p)
188 : : {
189 : 0 : return NULL;
190 : : }
191 : :
192 : 0 : len = (int)strlen(p);
193 [ # # ]: 0 : if (len < 7)
194 : : {
195 : 0 : return NULL;
196 : : }
197 : :
198 [ # # ]: 0 : if (strncmp(p, "M V30 ", 7))
199 : : {
200 : 0 : return NULL;
201 : : }
202 : :
203 : 0 : p += 7;
204 : 0 : len = normalize_string(p); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
205 : :
206 : 0 : return p;
207 : : }
208 : :
209 : : /****************************************************************************
210 : : Read V3000 field.
211 : :
212 : : It is MolfileReadField updated for V3000.
213 : : It considers right whitespace as stop sign,
214 : : no predefined len is used.
215 : :
216 : : Returns -1 on error otherwise number of bytes read.
217 : :
218 : : NB: ASSUMES THAT STRING HAS BEEN NORMALIZED with normalize_string()
219 : :
220 : : TODO: treat strings with spaces in double quotes
221 : : ****************************************************************************/
222 : 7241 : int MolfileV3000ReadField(void *data,
223 : : int data_type,
224 : : char **line_ptr)
225 : : {
226 : 7241 : int nread = 0;
227 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
228 : 7241 : const int max_field_len = sizeof(field);
229 : 7241 : long ldata = 0L;
230 : 7241 : double ddata = 0.0;
231 : : char *p_end;
232 : :
233 : 7241 : memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
234 : :
235 : 7241 : nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
236 : :
237 [ + + + - ]: 7241 : switch (data_type)
238 : : {
239 : 710 : case MOL_FMT_STRING_DATA:
240 : : {
241 [ + - + - ]: 710 : if (nread && (nread <= ATOM_EL_LEN)) /* djb-rwth: fixing GHI #133 -- updated 28/09/2025 */
242 : : {
243 : 710 : mystrncpy((char *)data, field, nread + 1);
244 : : }
245 : : else
246 : : {
247 : 0 : ((char *)data)[0] = '\0';
248 : : }
249 : : }
250 : 710 : break;
251 : :
252 : 4578 : case MOL_FMT_CHAR_INT_DATA:
253 : : case MOL_FMT_SHORT_INT_DATA:
254 : : case MOL_FMT_LONG_INT_DATA:
255 : : case MOL_FMT_INT_DATA:
256 : : {
257 : : /* assume that field ends at first non-digit */
258 : 4578 : ldata = strtol(field, &p_end, 10);
259 : :
260 [ + + ]: 4578 : if (p_end == field)
261 : : {
262 : 3 : nread = 0;
263 : : }
264 : :
265 [ - + ]: 4578 : if (data_type == MOL_FMT_LONG_INT_DATA)
266 : : {
267 [ # # # # ]: 0 : if (LONG_MIN < ldata && ldata < LONG_MAX)
268 : : {
269 : 0 : *(long *)data = (long)ldata;
270 : : }
271 : : else
272 : : {
273 : 0 : *(long *)data = 0L;
274 : 0 : nread = -1;
275 : : }
276 : : }
277 [ + + ]: 4578 : else if (data_type == MOL_FMT_INT_DATA)
278 : : {
279 [ + - + - ]: 2321 : if (INT_MIN <= ldata && ldata <= INT_MAX) /* djb-rwth: addressing coverity ID #499496/499553 -- ldata check seems to be necessary */
280 : : {
281 : 2321 : *(int *)data = (int)ldata;
282 : : }
283 : : else
284 : : {
285 : 0 : *(int *)data = (int)0;
286 : 0 : nread = -1;
287 : : }
288 : : }
289 : :
290 [ + + ]: 2257 : else if (data_type == MOL_FMT_CHAR_INT_DATA)
291 : : {
292 [ + - + - ]: 1047 : if (SCHAR_MIN <= ldata && ldata <= SCHAR_MAX)
293 : : {
294 : 1047 : *(S_CHAR *)data = (S_CHAR)ldata;
295 : : }
296 : : else
297 : : {
298 : 0 : *(S_CHAR *)data = (S_CHAR)0;
299 : 0 : nread = -1;
300 : : }
301 : : }
302 : :
303 [ + - ]: 1210 : else if (data_type == MOL_FMT_SHORT_INT_DATA)
304 : : {
305 [ + - + - ]: 1210 : if (SHRT_MIN <= ldata && ldata <= SHRT_MAX)
306 : : {
307 : 1210 : *(S_SHORT *)data = (S_SHORT)ldata;
308 : : }
309 : : else
310 : : {
311 : 0 : *(S_SHORT *)data = (S_SHORT)0;
312 : 0 : nread = -1;
313 : : }
314 : : }
315 : : else
316 : : {
317 : 0 : nread = -1;
318 : : }
319 : : }
320 : 4578 : break; /* INT's */
321 : :
322 : 1953 : case MOL_FMT_DOUBLE_DATA:
323 : : case MOL_FMT_FLOAT_DATA:
324 : : {
325 : : /* assume that field ends at first non-digit */
326 : 1953 : ddata = strtod(field, &p_end);
327 : :
328 [ - + ]: 1953 : if (p_end == field)
329 : : {
330 : 0 : nread = 0;
331 : : }
332 : :
333 [ + - ]: 1953 : if (data_type == MOL_FMT_DOUBLE_DATA)
334 : : {
335 [ + - + - ]: 1953 : if (ddata != HUGE_VAL && /*ldata*/ ddata != -HUGE_VAL)
336 : : {
337 : 1953 : *(double *)data = ddata;
338 : : }
339 : : else
340 : : {
341 : 0 : *(double *)data = 0.0;
342 : 0 : nread = -1;
343 : : }
344 : : }
345 [ # # ]: 0 : else if (data_type == MOL_FMT_FLOAT_DATA)
346 : : {
347 [ # # ]: 0 : if (fabs(ddata) <= (double)FLT_MIN)
348 : : {
349 : 0 : *(float *)data = 0.0;
350 : : }
351 [ # # ]: 0 : else if (fabs(ddata) >= (double)FLT_MAX)
352 : : {
353 : 0 : *(float *)data = 0.0;
354 : 0 : nread = -1;
355 : : }
356 : : }
357 : : else
358 : : {
359 : 0 : *(float *)data = (float)ddata; /* djb-rwth: addressing coverity ID #499519 -- probably never reached */
360 : : }
361 : : }
362 : 1953 : break; /* REAL's */
363 : :
364 : 0 : default:
365 : 0 : nread = -1;
366 : : }
367 : :
368 : 7241 : return nread;
369 : : }
370 : :
371 : : /****************************************************************************
372 : : Read V3000 keyword.
373 : : TODO: treat strings with spaces in double quotes
374 : : ****************************************************************************/
375 : 416 : int MolfileV3000ReadKeyword(char *key,
376 : : char **line_ptr)
377 : : {
378 : 416 : int nread = 0;
379 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
380 : 416 : const int max_field_len = sizeof(field);
381 : :
382 : 416 : memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
383 : :
384 : 416 : nread = read_upto_delim(line_ptr, field, max_field_len, "= \t\n\v\f\r");
385 : :
386 [ + - ]: 416 : if (nread)
387 : : {
388 : 416 : mystrncpy(key, field, nread + 1);
389 : : /* consume '=' sign if present */
390 [ + - ]: 416 : if (*line_ptr)
391 : : {
392 [ + - ]: 416 : if (*line_ptr[0] == '=')
393 : : {
394 : 416 : *line_ptr = *line_ptr + 1;
395 : : }
396 : : }
397 : : }
398 : : else
399 : : {
400 : 0 : key[0] = '\0';
401 : : }
402 : :
403 : 416 : return nread;
404 : : }
405 : :
406 : : /****************************************************************************
407 : : Read V3000 head of CTab
408 : : ****************************************************************************/
409 : 57 : int MolfileV3000ReadCTABBeginAndCountsLine(MOL_FMT_CTAB *ctab,
410 : : INCHI_IOSTREAM *inp_file,
411 : : char *pStrErr)
412 : : {
413 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
414 : 57 : int err = 0, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
415 : 57 : int failed = 0;
416 : :
417 : : int nc;
418 : 57 : char *p = NULL, *line = NULL;
419 : : INCHI_IOSTREAM tmpin;
420 : 57 : INCHI_IOS_STRING *pin = &tmpin.s;
421 : 57 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
422 : :
423 : 57 : field[0] = '\0'; /* djb-rwth: adding zero termination */
424 : :
425 : : /* Check for proper start */
426 : :
427 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
428 : 57 : inchi_strbuf_reset(pin);
429 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
430 [ - + ]: 57 : if (nc < 1)
431 : : {
432 : 0 : p = NULL;
433 : : }
434 : : else
435 : : {
436 : 57 : p = line = pin->pStr;
437 : : }
438 [ + - - + ]: 57 : if (!p || strcmp(p, "BEGIN CTAB"))
439 : : {
440 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 CTab start marker");
441 : : }
442 : 57 : remove_one_lf(line);
443 : :
444 : : /* Reset all previosly read data from quasi-counts line */
445 : : /* (which contains only single meaningful value, 'V3000' marker */
446 : 57 : ctab->n_atoms = -1;
447 : 57 : ctab->n_bonds = -1;
448 : 57 : ctab->chiral_flag = -1;
449 : 57 : ctab->n_stext_entries = -1;
450 : : /* Relax stricthness of V3000 conformance: */
451 : : /* Do not check if '999' supplied, just use this. */
452 : 57 : ctab->n_property_lines = 999;
453 : :
454 : : /* Read counts line */
455 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
456 : 57 : inchi_strbuf_reset(pin);
457 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
458 [ - + ]: 57 : if (nc < 1)
459 : : {
460 : 0 : p = NULL;
461 : : }
462 : : else
463 : : {
464 : 57 : p = line = pin->pStr;
465 : : }
466 [ - + ]: 57 : if (!p)
467 : : {
468 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Cannot read V3000 counts line");
469 : : }
470 : 57 : remove_one_lf(line);
471 : :
472 : : /* Parse counts line */
473 : 57 : len = MolfileV3000ReadField(field, MOL_FMT_STRING_DATA, &p); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
474 [ - + ]: 57 : if (strcmp(field, "COUNTS"))
475 : : {
476 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Cannot read V3000 counts line");
477 : : }
478 : 57 : failed = 0;
479 [ - + ]: 57 : if (0 > MolfileV3000ReadField(&ctab->n_atoms, MOL_FMT_INT_DATA, &p))
480 : : {
481 : 0 : failed = 2;
482 : : }
483 [ - + ]: 57 : else if (0 > MolfileV3000ReadField(&ctab->n_bonds, MOL_FMT_INT_DATA, &p))
484 : : {
485 : 0 : failed = 1;
486 : : }
487 [ - + ]: 57 : else if (0 > MolfileV3000ReadField(&ctab->v3000->n_sgroups, MOL_FMT_INT_DATA, &p))
488 : : {
489 : 0 : failed = 1;
490 : : }
491 [ - + ]: 57 : else if (0 > MolfileV3000ReadField(&ctab->v3000->n_3d_constraints, MOL_FMT_INT_DATA, &p))
492 : : {
493 : 0 : failed = 1;
494 : : }
495 [ - + ]: 57 : else if (0 > MolfileV3000ReadField(&ctab->chiral_flag, MOL_FMT_CHAR_INT_DATA, &p))
496 : : {
497 : 0 : failed = 1;
498 : : }
499 : :
500 [ + - ]: 57 : if (failed)
501 : : {
502 : 0 : err = 3;
503 [ # # ]: 0 : if (failed == 2)
504 : : {
505 [ # # ]: 0 : TREAT_ERR(err, 3, "Number of atoms too large. V3000 counts line:");
506 : : }
507 : : else
508 : : {
509 : : /* too long input file line or other value min-max range mismatch */
510 [ # # ]: 0 : TREAT_ERR(err, 3, "Cannot interpret V3000 counts line:");
511 : : }
512 : 0 : dotify_non_printable_chars(line);
513 : 0 : AddErrorMessage(pStrErr, line);
514 : 0 : goto err_fin;
515 : : }
516 : :
517 : 57 : err_fin:
518 : 57 : inchi_strbuf_close(pin);
519 : :
520 : 57 : return err;
521 : : }
522 : :
523 : : /****************************************************************************
524 : : Read V3000 SGroup
525 : : ****************************************************************************/
526 : 0 : int MolfileV3000ReadSGroup(MOL_FMT_CTAB *ctab,
527 : : INCHI_IOSTREAM *inp_file,
528 : : int err,
529 : : char *pStrErr)
530 : : {
531 : : int nc;
532 : 0 : char *p = NULL, *line = NULL;
533 : : INCHI_IOSTREAM tmpin;
534 : 0 : INCHI_IOS_STRING *pin = &tmpin.s;
535 : :
536 : 0 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
537 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
538 : :
539 : : while (1)
540 : : {
541 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
542 : :
543 [ # # ]: 0 : if (nc < 1)
544 : : {
545 : 0 : p = NULL;
546 : : }
547 : : else
548 : : {
549 : 0 : p = line = pin->pStr;
550 : 0 : remove_one_lf(line);
551 : : }
552 [ # # # # ]: 0 : if (p && !strcmp(p, "END SGROUP"))
553 : : {
554 : 0 : inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
555 : 0 : return 0;
556 : : }
557 : : }
558 : :
559 : : /* if ( !p || strcmp(p, "END SGROUP") ) */
560 : : {
561 : : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 SGroup end marker");
562 : : }
563 : :
564 : : err_fin:
565 : :
566 : : inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
567 : : return err;
568 : : }
569 : :
570 : : /****************************************************************************
571 : : Read V3000 3DBlock
572 : : ****************************************************************************/
573 : 0 : int MolfileV3000Read3DBlock(MOL_FMT_CTAB *ctab,
574 : : INCHI_IOSTREAM *inp_file,
575 : : int err,
576 : : char *pStrErr)
577 : : {
578 : : int nc;
579 : 0 : char *p = NULL, *line = NULL;
580 : : INCHI_IOSTREAM tmpin;
581 : 0 : INCHI_IOS_STRING *pin = &tmpin.s;
582 : 0 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
583 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
584 : :
585 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
586 : :
587 [ # # ]: 0 : if (nc < 1)
588 : : {
589 : 0 : p = NULL;
590 : : }
591 : : else
592 : : {
593 : 0 : p = line = pin->pStr;
594 : : }
595 : 0 : remove_one_lf(line);
596 : :
597 [ # # # # ]: 0 : if (!p || strcmp(p, "END OBJ3D"))
598 : : {
599 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 3DBlock end marker");
600 : : }
601 : 0 : goto err_fin;
602 : :
603 : 0 : err_fin:
604 : :
605 : 0 : inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
606 : 0 : return err;
607 : : }
608 : :
609 : : /****************************************************************************
610 : : Read V3000 collections
611 : : ****************************************************************************/
612 : 37 : int MolfileV3000ReadCollections(MOL_FMT_CTAB *ctab,
613 : : INCHI_IOSTREAM *inp_file,
614 : : int err,
615 : : char *pStrErr)
616 : : {
617 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
618 : 37 : const int max_field_len = sizeof(field);
619 : 37 : int nread, len, n_coll = 0;
620 : 37 : int failed = 0;
621 : : int nc;
622 : 37 : char *p = NULL, *line = NULL;
623 : : INCHI_IOSTREAM tmpin;
624 : 37 : INCHI_IOS_STRING *pin = &tmpin.s;
625 : :
626 : 37 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
627 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
628 : :
629 : 37 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
630 : :
631 [ - + ]: 37 : if (nc < 1)
632 : : {
633 : 0 : p = NULL;
634 : : }
635 : : else
636 : : {
637 : 37 : p = line = pin->pStr;
638 : : }
639 : 37 : remove_one_lf(line);
640 : :
641 [ + - + + ]: 138 : while (p && strcmp(p, "END COLLECTION"))
642 : : {
643 : 101 : int stereo_kind = MOL_FMT_V3000_STENON;
644 : : /* stereo collection of interest */
645 : 101 : NUM_LISTS *ste_coll = NULL;
646 : :
647 : 101 : nread = read_upto_delim(&p, field, max_field_len, "/");
648 [ - + ]: 101 : if (nread < 6)
649 : : {
650 : 0 : failed = 1;
651 : 0 : break;
652 : : }
653 [ - + ]: 101 : if (strcmp(field, "MDLV30"))
654 : : {
655 : 0 : failed = 1;
656 : 0 : break;
657 : : }
658 : :
659 : 101 : nread = read_upto_delim(&p, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
660 [ + + ]: 101 : if (!strcmp(field, "/STEABS"))
661 : : {
662 : 23 : n_coll = 1;
663 : 23 : stereo_kind = MOL_FMT_V3000_STEABS;
664 : 23 : ste_coll = ctab->v3000->steabs;
665 : : }
666 [ + + ]: 78 : else if (!strcmp(field, "/STEREL"))
667 : : {
668 : : /* get number of collection */
669 [ - + ]: 31 : if (0 > MolfileV3000ReadField(&n_coll, MOL_FMT_CHAR_INT_DATA, &p))
670 : : {
671 : 0 : failed = 1;
672 : 0 : break;
673 : : }
674 : 31 : stereo_kind = MOL_FMT_V3000_STEREL;
675 : 31 : ste_coll = ctab->v3000->sterel;
676 : : }
677 [ + - ]: 47 : else if (!strcmp(field, "/STERAC"))
678 : : {
679 : : /* get number of collection */
680 [ - + ]: 47 : if (0 > MolfileV3000ReadField(&n_coll, MOL_FMT_CHAR_INT_DATA, &p))
681 : : {
682 : 0 : failed = 1;
683 : 0 : break;
684 : : }
685 : 47 : stereo_kind = MOL_FMT_V3000_STERAC;
686 : 47 : ste_coll = ctab->v3000->sterac;
687 : : }
688 : : else
689 : : {
690 : : ;
691 : : }
692 : :
693 [ + - ]: 101 : if (stereo_kind != MOL_FMT_V3000_STENON)
694 : : /* currently skip non-stereo collections */
695 : : {
696 : : /* consume atoms= */
697 [ + - ]: 101 : if ((len = MolfileV3000ReadKeyword(field, &p) > 0)) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
698 : : {
699 [ + - ]: 101 : if (!strcmp(field, "ATOMS"))
700 : : {
701 : 101 : int res, *num_list = NULL;
702 : :
703 [ - + ]: 101 : if (0 > MolfileV3000ReadStereoCollection(ctab, &p, &num_list, pStrErr))
704 : : {
705 : 0 : failed = 1;
706 : : }
707 [ - + ]: 101 : else if (!num_list)
708 : : {
709 : 0 : failed = 1;
710 : : }
711 : : else
712 : : {
713 : : int k, nnum;
714 : 101 : num_list[0] = n_coll;
715 : 101 : nnum = num_list[1];
716 [ + + ]: 125 : for (k = 2; k < nnum; k++)
717 : : {
718 : 24 : num_list[k] =
719 : 24 : get_actual_atom_number(num_list[k],
720 : 24 : ctab->v3000->n_non_star_atoms + ctab->v3000->n_star_atoms,
721 : 24 : ctab->v3000->atom_index_orig,
722 : 24 : ctab->v3000->atom_index_fin);
723 : : }
724 : 101 : res = NumLists_Append(ste_coll, num_list);
725 [ - + ]: 101 : if (res < 0)
726 : : {
727 : 0 : failed = 1;
728 : : }
729 : : else
730 : : {
731 [ + + ]: 101 : if (stereo_kind == MOL_FMT_V3000_STEABS)
732 : : {
733 : 23 : ctab->v3000->n_steabs++;
734 : 23 : ctab->v3000->n_collections++;
735 : : }
736 [ + + ]: 78 : else if (stereo_kind == MOL_FMT_V3000_STEREL)
737 : : {
738 : 31 : ctab->v3000->n_sterel++;
739 : 31 : ctab->v3000->n_collections++;
740 : : }
741 [ + - ]: 47 : else if (stereo_kind == MOL_FMT_V3000_STERAC)
742 : : {
743 : 47 : ctab->v3000->n_sterac++;
744 : 47 : ctab->v3000->n_collections++;
745 : : }
746 : : }
747 : : }
748 : : }
749 : : }
750 : : else
751 : : {
752 : 0 : failed = 1;
753 : 0 : break;
754 : : }
755 : : }
756 : :
757 : : /*next_line:*/
758 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
759 : 101 : inchi_strbuf_reset(pin);
760 : :
761 : 101 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
762 : :
763 [ - + ]: 101 : if (nc < 1)
764 : : {
765 : 0 : p = NULL;
766 : : }
767 : : else
768 : : {
769 : 101 : p = line = pin->pStr;
770 : 101 : remove_one_lf(line);
771 : : }
772 : : }
773 : :
774 [ - + ]: 37 : if (failed)
775 : : {
776 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
777 : 0 : inchi_strbuf_reset(pin);
778 : 0 : line = NULL; /* Reset line pointer since buffer was freed */
779 : :
780 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
781 : :
782 [ # # ]: 0 : if (nc < 1)
783 : : {
784 : 0 : p = NULL;
785 : : }
786 : : else
787 : : {
788 : 0 : p = line = pin->pStr;
789 : 0 : remove_one_lf(line);
790 : : }
791 : : }
792 : :
793 [ - + ]: 37 : if (!p)
794 : : {
795 : 0 : failed = 1;
796 : : }
797 : :
798 [ + - ]: 37 : if (failed)
799 : : {
800 : 0 : err = 7;
801 [ # # ]: 0 : TREAT_ERR(err, 7, "Cannot interpret V3000 collection line(s)"); /* djb-rwth: addressing coverity ID #499531 -- TREAT_ERR properly used */
802 [ # # ]: 0 : if (line)
803 : : {
804 : 0 : dotify_non_printable_chars(line);
805 : 0 : AddErrorMessage(pStrErr, line);
806 : : }
807 : 0 : goto err_fin;
808 : : }
809 : :
810 : : // /* Error: No V3000 Collection end marker */
811 : : // if (ctab->v3000->n_steabs ||
812 : : // ctab->v3000->n_sterel ||
813 : : // ctab->v3000->n_sterac)
814 : : // {
815 : : // AddErrorMessage(pStrErr, "V3000 enhanced stereo read/stored but ignored");
816 : : // }
817 : :
818 : 37 : err_fin:
819 : :
820 : 37 : inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
821 : 37 : return err;
822 : : }
823 : :
824 : : /****************************************************************************
825 : : Read V3000 atoms
826 : : ****************************************************************************/
827 : 57 : int MolfileV3000ReadAtomsBlock(MOL_FMT_CTAB *ctab,
828 : : INCHI_IOSTREAM *inp_file,
829 : : int err,
830 : : char *pStrErr)
831 : : {
832 : : int i;
833 : : /* djb-rwth: removing redundant variables */
834 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
835 : 57 : int nc, failed = 0;
836 : 57 : char *p = NULL, *line = NULL;
837 : : INCHI_IOSTREAM tmpin;
838 : 57 : INCHI_IOS_STRING *pin = &tmpin.s;
839 : 57 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
840 : :
841 : : /* Check for proper start */
842 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
843 : :
844 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
845 : :
846 [ - + ]: 57 : if (nc < 1)
847 : : {
848 : 0 : p = NULL;
849 : : }
850 : : else
851 : : {
852 : 57 : p = line = pin->pStr;
853 : : }
854 [ + - - + ]: 57 : if (!p || strcmp(p, "BEGIN ATOM"))
855 : : {
856 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Atom block start marker");
857 : : }
858 : 57 : remove_one_lf(line);
859 : :
860 : 57 : ctab->v3000->n_non_star_atoms = 0;
861 [ + + ]: 708 : for (i = 0; i < ctab->n_atoms; i++)
862 : : {
863 : 651 : int ii = -1;
864 : :
865 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
866 : 651 : inchi_strbuf_reset(pin);
867 : :
868 : 651 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
869 : :
870 [ - + ]: 651 : if (nc < 1)
871 : : {
872 : 0 : p = NULL;
873 : : }
874 : : else
875 : : {
876 : 651 : p = line = pin->pStr;
877 : : }
878 [ - + ]: 651 : if (!p)
879 : : {
880 [ # # ]: 0 : if (!err)
881 : : {
882 [ # # ]: 0 : TREAT_ERR(err, 2, "Cannot read V3000 atom block line");
883 : : }
884 : 0 : break;
885 : : }
886 : 651 : remove_one_lf(line);
887 : :
888 [ - + ]: 651 : if (err)
889 : : {
890 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
891 : : {
892 : 0 : err = -abs(err);
893 : 0 : break;
894 : : }
895 : 0 : continue; /* bypass the rest of the Atom block */
896 : : }
897 : :
898 [ + - ]: 651 : if (ctab->atoms)
899 : : {
900 : : int index, aamap; /* not used actually, just read them */
901 : : int len;
902 : : char symbol[6]; /* TODO: treat possibly long V3000 atom names */
903 : 651 : double fx = 0.0, fy = 0.0, fz = 0.0;
904 : : #ifdef GHI100_FIX
905 : : #if (SPRINTF_FLAG == 2)
906 : : char *fxs, *fys, *fzs;
907 : : int rfxs, rfys, rfzs;
908 : :
909 : : fxs = (char *)inchi_malloc((10 + 3) * sizeof(double));
910 : : fys = (char *)inchi_malloc((10 + 3) * sizeof(double));
911 : : fzs = (char *)inchi_malloc((10 + 3) * sizeof(double));
912 : :
913 : : if (fxs || fys || fzs)
914 : : {
915 : : failed = 1;
916 : : }
917 : : #endif
918 : : #endif
919 : 651 : symbol[0] = '\0'; /* djb-rwth: adding zero termination */
920 : :
921 : : /* Read positional parameters */
922 : 651 : failed = 0;
923 : :
924 [ - + ]: 651 : if (0 > MolfileV3000ReadField(&index, MOL_FMT_INT_DATA, &p))
925 : : {
926 : 0 : failed = 1;
927 : : }
928 [ - + ]: 651 : else if (0 > MolfileV3000ReadField(&symbol, MOL_FMT_STRING_DATA, &p))
929 : : {
930 : 0 : failed = 1;
931 : : }
932 [ - + ]: 651 : else if (0 > MolfileV3000ReadField(&fx, MOL_FMT_DOUBLE_DATA, &p))
933 : : {
934 : 0 : failed = 1;
935 : : }
936 [ - + ]: 651 : else if (0 > MolfileV3000ReadField(&fy, MOL_FMT_DOUBLE_DATA, &p))
937 : : {
938 : 0 : failed = 1;
939 : : }
940 [ - + ]: 651 : else if (0 > MolfileV3000ReadField(&fz, MOL_FMT_DOUBLE_DATA, &p))
941 : : {
942 : 0 : failed = 1;
943 : : }
944 [ - + ]: 651 : else if (0 > MolfileV3000ReadField(&aamap, MOL_FMT_INT_DATA, &p))
945 : : {
946 : 0 : failed = 1;
947 : : }
948 : :
949 [ - + ]: 651 : if (failed)
950 : : {
951 : :
952 : 0 : err = 4;
953 [ # # ]: 0 : TREAT_ERR(err, 4, "Cannot interpret V3000 atom block line:"); /* djb-rwth: addressing coverity ID #499547 -- TREAT_ERR properly used */
954 : 0 : dotify_non_printable_chars(line);
955 : 0 : AddErrorMessage(pStrErr, line);
956 : :
957 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
958 : : {
959 : 0 : err = -abs(err);
960 : 0 : break;
961 : : }
962 : 3 : continue; /* can't interpret a first half of atom block line */
963 : : }
964 : :
965 : : /* emulate V2000 coordinates substring */
966 [ + - ]: 651 : if (ctab->coords)
967 : : {
968 : : char szcoords[40];
969 : : #ifdef GHI100_FIX
970 : : #if (SPRINTF_FLAG == 2)
971 : : if (fxs)
972 : : {
973 : : rfxs = dbl2int(fxs, 10, -1, 'g', fx);
974 : : }
975 : : if (fys)
976 : : {
977 : : rfys = dbl2int(fys, 10, -1, 'g', fy);
978 : : }
979 : : if (fzs)
980 : : {
981 : : rfzs = dbl2int(fzs, 10, -1, 'g', fz);
982 : : }
983 : : if ((rfxs >= 0) && (rfys >= 0) && (rfzs >= 0))
984 : : {
985 : : sprintf(szcoords, "%s%s%s", fxs, fys, fzs);
986 : : }
987 : : else
988 : : {
989 : : failed = 1;
990 : : }
991 : : inchi_free(fxs);
992 : : inchi_free(fys);
993 : : inchi_free(fzs);
994 : : #elif (SPRINTF_FLAG == 2)
995 : : stbsp_sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
996 : : #else
997 : : sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
998 : : #endif
999 : : #endif
1000 : 651 : sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
1001 : 651 : strcpy(ctab->coords[i], szcoords);
1002 : : }
1003 : :
1004 [ + + ]: 651 : if (!strcmp(symbol, "*"))
1005 : : {
1006 : : /* ignore star atoms but save index info */
1007 : 3 : ctab->v3000->atom_index_orig[i] = index;
1008 : 3 : ctab->v3000->atom_index_fin[i] = -1;
1009 : 3 : ctab->v3000->n_star_atoms++;
1010 : 3 : continue;
1011 : : }
1012 : :
1013 : 648 : ctab->v3000->n_non_star_atoms++;
1014 : 648 : ctab->v3000->atom_index_orig[i] = index;
1015 : 648 : ctab->v3000->atom_index_fin[i] = ctab->v3000->n_non_star_atoms;
1016 : 648 : ii = ctab->v3000->n_non_star_atoms - 1;
1017 : :
1018 : 648 : mystrncpy(ctab->atoms[ii].symbol, symbol, sizeof(ctab->atoms[ii].symbol));
1019 [ + + - + ]: 648 : if (2 == strlen(ctab->atoms[ii].symbol) && isupper(UCINT ctab->atoms[ii].symbol[1]))
1020 : : {
1021 : 0 : ctab->atoms[ii].symbol[1] = (char)tolower(UCINT ctab->atoms[ii].symbol[1]); /* 5-4-99 DCh*/
1022 : : }
1023 : 648 : ctab->atoms[ii].fx = fx;
1024 : 648 : ctab->atoms[ii].fy = fy;
1025 : 648 : ctab->atoms[ii].fz = fz;
1026 : :
1027 : : /* Read key-val pairs if any */
1028 [ + + + - ]: 777 : while (p && (len = MolfileV3000ReadKeyword(field, &p)) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1029 : : {
1030 : :
1031 : : int itmp;
1032 : : char ctmp;
1033 : : char stmp[MOL_FMT_V3000_MAXFIELDLEN];
1034 : :
1035 : 129 : failed = 0;
1036 [ + + ]: 129 : if (!strcmp(field, "CHG"))
1037 : : {
1038 [ - + ]: 16 : if (0 > MolfileV3000ReadField(&ctab->atoms[ii].charge, MOL_FMT_CHAR_INT_DATA, &p))
1039 : : {
1040 : 0 : failed = 1;
1041 : : }
1042 : : }
1043 [ - + ]: 113 : else if (!strcmp(field, "RAD"))
1044 : : {
1045 [ # # ]: 0 : if (0 > MolfileV3000ReadField(&ctab->atoms[ii].radical, MOL_FMT_CHAR_INT_DATA, &p))
1046 : : {
1047 : 0 : failed = 1;
1048 : : }
1049 : : }
1050 [ + + ]: 113 : else if (!strcmp(field, "CFG"))
1051 : : {
1052 [ - + ]: 110 : if (0 > MolfileV3000ReadField(&ctab->atoms[ii].stereo_parity, MOL_FMT_CHAR_INT_DATA, &p))
1053 : : {
1054 : 0 : failed = 1;
1055 : : }
1056 : : }
1057 : :
1058 [ - + ]: 3 : else if (!strcmp(field, "MASS"))
1059 : : {
1060 : : /*
1061 : : Default = natural abundance
1062 : : A specified value indicates the absolute
1063 : : atomic weight of the designated atom.
1064 : : */
1065 : : S_SHORT iso_mass;
1066 [ # # ]: 0 : if (0 > MolfileV3000ReadField(&iso_mass, MOL_FMT_SHORT_INT_DATA, &p))
1067 : : {
1068 : 0 : failed = 1;
1069 : 0 : TREAT_ERR(err, 0, "Isotopic data not recognized:");
1070 : 0 : AddErrorMessage(pStrErr, line);
1071 : : /* ignore isotopic error for now */
1072 : : }
1073 : : else
1074 : : {
1075 : : /* What we read is an absolute isotopic mass, by V3000 spec.
1076 : : Adjust this to old convention for further processing:
1077 : : set 'ctab->atoms[ii].mass_difference' to 127
1078 : : if isotopic mass is the same as element mass
1079 : : in Periodic Table (rounded avg by all isotopes), 'atw'
1080 : : delta otherwise, the value of difference 'delta' = ( isotopic mass - 'atw')
1081 : : */
1082 : : int atw, delta;
1083 : 0 : atw = get_atomic_mass(ctab->atoms[ii].symbol);
1084 : 0 : delta = (int)iso_mass - atw;
1085 [ # # ]: 0 : ctab->atoms[ii].mass_difference = (char)(delta ? delta : ZERO_ATW_DIFF);
1086 : : }
1087 : : }
1088 : :
1089 [ + - ]: 3 : else if (!strcmp(field, "VAL"))
1090 : : {
1091 [ - + ]: 3 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1092 : : {
1093 : 0 : failed = 1;
1094 : : }
1095 : : else
1096 : : {
1097 : : /* adjust to old convention: was 15 for zero, now -1 for zero */
1098 [ - + ]: 3 : if (itmp == -1)
1099 : : {
1100 : 0 : ctmp = 15;
1101 : : }
1102 : : else
1103 : : {
1104 : 3 : ctmp = (char)itmp;
1105 : : }
1106 : 3 : ctab->atoms[ii].valence = ctmp;
1107 : : }
1108 : : }
1109 [ # # ]: 0 : else if (!strcmp(field, "HCOUNT"))
1110 : : {
1111 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1112 : : {
1113 : : ; /* skip query-related stuff */
1114 : : }
1115 : : }
1116 [ # # ]: 0 : else if (!strcmp(field, "STBOX"))
1117 : : {
1118 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1119 : : {
1120 : : ; /* skip for now */
1121 : : }
1122 : : }
1123 [ # # # # ]: 0 : else if (!strcmp(field, "INVRET") || !strcmp(field, "EXACHG"))
1124 : : {
1125 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1126 : : {
1127 : : ; /* skip reaction-related stuff */
1128 : : }
1129 : : }
1130 [ # # # # : 0 : else if (!strcmp(field, "SUBST") || !strcmp(field, "UNSAT") || !strcmp(field, "RBCNT"))
# # ]
1131 : : {
1132 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1133 : : {
1134 : : ; /* skip query-related stuff */
1135 : : }
1136 : : }
1137 [ # # ]: 0 : else if (!strcmp(field, "ATTCHPT"))
1138 : : {
1139 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1140 : : {
1141 : : ;
1142 : : }
1143 : : }
1144 [ # # ]: 0 : else if (!strcmp(field, "RGROUPS"))
1145 : : {
1146 : 0 : if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
1147 : : {
1148 : : ;
1149 : : }
1150 : : }
1151 [ # # ]: 0 : else if (!strcmp(field, "ATTCHORD"))
1152 : : {
1153 : 0 : if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
1154 : : {
1155 : : ;
1156 : : }
1157 : : }
1158 [ # # ]: 0 : else if (!strcmp(field, "CLASS"))
1159 : : {
1160 : 0 : if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
1161 : : {
1162 : : ;
1163 : : }
1164 : : }
1165 [ # # ]: 0 : else if (!strcmp(field, "SEQID"))
1166 : : {
1167 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1168 : : {
1169 : : ;
1170 : : }
1171 : : }
1172 : :
1173 [ - + ]: 129 : if (failed)
1174 : : {
1175 : 0 : err = 4;
1176 [ # # ]: 0 : TREAT_ERR(err, 4, "Cannot interpret V3000 atom block key-value pair");
1177 : 0 : dotify_non_printable_chars(line);
1178 : 0 : AddErrorMessage(pStrErr, line);
1179 : :
1180 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
1181 : : {
1182 : 0 : err = -abs(err);
1183 : 0 : break;
1184 : : }
1185 : 0 : continue;
1186 : : }
1187 : : }
1188 : : } /* if ( NULL != ctab->atoms ) */
1189 : : } /* for ( i = 0; i < ctab->n_atoms; i++ ) */
1190 : :
1191 [ + + ]: 57 : if (ctab->v3000->n_star_atoms)
1192 : : {
1193 : 2 : AddErrorMessage(pStrErr, "V3000 star atoms ignored if MolecularInorganics or NPZz parameter not used"); /* @nnuk : when using /MolecularInorganics or /NPZz, star atoms will not be ignored */
1194 : 2 : ctab->n_atoms = ctab->v3000->n_non_star_atoms;
1195 : : }
1196 : :
1197 : : /* Check for proper finish */
1198 : :
1199 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1200 : 57 : inchi_strbuf_reset(pin);
1201 : :
1202 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1203 : :
1204 [ - + ]: 57 : if (nc < 1)
1205 : : {
1206 : 0 : p = NULL;
1207 : : }
1208 : : else
1209 : : {
1210 : 57 : p = line = pin->pStr;
1211 : : }
1212 [ + - - + ]: 57 : if (!p || strcmp(p, "END ATOM"))
1213 : : {
1214 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Atom block end marker");
1215 : : }
1216 : 57 : remove_one_lf(line);
1217 : :
1218 : 57 : err_fin:
1219 : 57 : inchi_strbuf_close(pin);
1220 : :
1221 : 57 : return err;
1222 : : }
1223 : :
1224 : : /****************************************************************************
1225 : : Read V3000 bonds
1226 : : ****************************************************************************/
1227 : 57 : int MolfileV3000ReadBondsBlock(MOL_FMT_CTAB *ctab,
1228 : : INCHI_IOSTREAM *inp_file,
1229 : : int err,
1230 : : char *pStrErr)
1231 : : {
1232 : : int i;
1233 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
1234 : : int nc;
1235 : 57 : char *p = NULL, *line = NULL;
1236 : : INCHI_IOSTREAM tmpin;
1237 : 57 : INCHI_IOS_STRING *pin = &tmpin.s;
1238 : :
1239 [ - + ]: 57 : if (!ctab->n_bonds)
1240 : : {
1241 : 0 : return 0;
1242 : : }
1243 : 57 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
1244 : :
1245 : : /* Check for proper start */
1246 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1247 : :
1248 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1249 : :
1250 [ - + ]: 57 : if (nc < 1)
1251 : : {
1252 : 0 : p = NULL;
1253 : : }
1254 : : else
1255 : : {
1256 : 57 : p = line = pin->pStr;
1257 : : }
1258 [ + - - + ]: 57 : if (!p || strcmp(p, "BEGIN BOND"))
1259 : : {
1260 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Bond block start marker");
1261 : : }
1262 : 57 : remove_one_lf(line);
1263 : :
1264 : 57 : ctab->v3000->n_haptic_bonds = 0;
1265 : 57 : ctab->v3000->n_non_haptic_bonds = 0;
1266 : :
1267 [ + + ]: 662 : for (i = 0; i < ctab->n_bonds; i++)
1268 : : {
1269 : 605 : int is_haptic = 0;
1270 : :
1271 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1272 : 605 : inchi_strbuf_reset(pin);
1273 : :
1274 : 605 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1275 : :
1276 [ - + ]: 605 : if (nc < 1)
1277 : : {
1278 : 0 : p = NULL;
1279 : : }
1280 : : else
1281 : : {
1282 : 605 : p = line = pin->pStr;
1283 : : }
1284 [ - + ]: 605 : if (!p)
1285 : : {
1286 [ # # ]: 0 : if (!err)
1287 : : {
1288 [ # # ]: 0 : TREAT_ERR(err, 2, "Cannot read V3000 bond block line"); /* djb-rwth: addressing coverity ID #499565 -- TREAT_ERR properly used */
1289 : : }
1290 : 0 : break;
1291 : : }
1292 : 605 : remove_one_lf(line);
1293 : :
1294 [ - + ]: 605 : if (err)
1295 : : {
1296 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
1297 : : {
1298 : 0 : err = -abs(err);
1299 : 0 : break;
1300 : : }
1301 : 0 : continue;
1302 : : }
1303 : :
1304 [ + - ]: 605 : if (ctab->bonds)
1305 : : {
1306 : : int index, n_orig_at, len;
1307 : 605 : short int atnum1 = -1, atnum2 = -1;
1308 : 605 : char bond_type = 0, stereo = 0;
1309 : 605 : int failed = 0;
1310 : : /* djb-rwth: removing redundant variables */
1311 : :
1312 : 605 : n_orig_at = ctab->v3000->n_non_star_atoms + ctab->v3000->n_star_atoms;
1313 : :
1314 : : /* read positional parameters */
1315 [ - + ]: 605 : if (0 > MolfileV3000ReadField(&index, MOL_FMT_INT_DATA, &p))
1316 : : {
1317 : 0 : failed = 1;
1318 : : }
1319 [ - + ]: 605 : else if (0 > MolfileV3000ReadField(&bond_type, MOL_FMT_CHAR_INT_DATA, &p))
1320 : : {
1321 : 0 : failed = 1;
1322 : : }
1323 [ - + ]: 605 : else if (0 > MolfileV3000ReadField(&atnum1, MOL_FMT_SHORT_INT_DATA, &p))
1324 : : {
1325 : 0 : failed = 1;
1326 : : }
1327 [ - + ]: 605 : else if (0 > MolfileV3000ReadField(&atnum2, MOL_FMT_SHORT_INT_DATA, &p))
1328 : : {
1329 : 0 : failed = 1;
1330 : : }
1331 : :
1332 : 1210 : atnum1 = get_actual_atom_number(atnum1, n_orig_at,
1333 : 605 : ctab->v3000->atom_index_orig,
1334 : 605 : ctab->v3000->atom_index_fin);
1335 : :
1336 : 1210 : atnum2 = get_actual_atom_number(atnum2, n_orig_at,
1337 : 605 : ctab->v3000->atom_index_orig,
1338 : 605 : ctab->v3000->atom_index_fin);
1339 : :
1340 [ - + - - ]: 605 : if ((atnum1 < 0) && (atnum2 < 0))
1341 : : {
1342 : 0 : failed = 1;
1343 : : }
1344 : : /* djb-rwth: removing redundant code */
1345 : :
1346 [ - + ]: 605 : if (failed)
1347 : : {
1348 : :
1349 [ # # ]: 0 : if (!err)
1350 : : {
1351 : : /* can't interpret bonds block line */
1352 [ # # ]: 0 : TREAT_ERR(err, 4, "Cannot interpret V3000 bond block line:");
1353 : 0 : dotify_non_printable_chars(line);
1354 : 0 : AddErrorMessage(pStrErr, line);
1355 : : }
1356 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
1357 : : {
1358 : 0 : err = -abs(err);
1359 : 0 : break;
1360 : : }
1361 : : }
1362 : :
1363 : : /* TODO: treat new bond types 9 10 */
1364 : : /* read key-val pairs if any */
1365 [ + + + - ]: 791 : while (p && (len = MolfileV3000ReadKeyword(field, &p)) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1366 : : {
1367 : :
1368 : : int itmp;
1369 : : char stmp[MOL_FMT_V3000_MAXFIELDLEN];
1370 : 186 : failed = 0;
1371 : :
1372 [ + + ]: 186 : if (!strcmp(field, "CFG"))
1373 : : {
1374 [ - + ]: 181 : if (0 > MolfileV3000ReadField(&stereo, MOL_FMT_CHAR_INT_DATA, &p))
1375 : : {
1376 : 0 : failed = 1;
1377 : : }
1378 : : else
1379 : : {
1380 : : /* adjust stereo to old convention for wedges which was:
1381 : : 0 = not stereo, 1 = Up, 4 = Either, 6 = Down
1382 : : now:
1383 : : 0 = none (default), 1 = up, 2 = either, 3 = down
1384 : : */
1385 [ - + ]: 181 : if (stereo == 2)
1386 : : {
1387 : 0 : stereo = 4;
1388 : : }
1389 [ + + ]: 181 : else if (stereo == 3)
1390 : : {
1391 : 32 : stereo = 6;
1392 : : }
1393 : : }
1394 : : }
1395 [ - + ]: 5 : else if (!strcmp(field, "TOPO"))
1396 : : {
1397 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1398 : : {
1399 : : ; /* skip query-related stuff */
1400 : : }
1401 : : }
1402 [ - + ]: 5 : else if (!strcmp(field, "RXCTR"))
1403 : : {
1404 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1405 : : {
1406 : : ; /* skip reaction-related stuff */
1407 : : }
1408 : : }
1409 [ - + ]: 5 : else if (!strcmp(field, "STBOX"))
1410 : : {
1411 : 0 : if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
1412 : : {
1413 : : ; /* skip for now */
1414 : : }
1415 : : }
1416 [ + + ]: 5 : else if (!strcmp(field, "ENDPTS"))
1417 : : {
1418 : 3 : int res, *num_list = NULL;
1419 [ - + ]: 3 : if (0 > MolfileV3000ReadHapticBond(ctab, &p, &num_list, pStrErr))
1420 : : {
1421 : 0 : failed = 1;
1422 : : }
1423 [ - + ]: 3 : else if (!num_list)
1424 : : {
1425 : 0 : failed = 1;
1426 : : }
1427 : : else
1428 : : {
1429 : 3 : int existent_atom = atnum1;
1430 [ - + ]: 3 : if (existent_atom < 0)
1431 : : {
1432 : 0 : existent_atom = atnum2;
1433 : : }
1434 [ - + ]: 3 : if (existent_atom < 0) /* should not be here */
1435 : : {
1436 : 0 : failed = 1;
1437 : : }
1438 : : else
1439 : : {
1440 : : int k, nnum;
1441 : 3 : nnum = num_list[2];
1442 : 3 : num_list[1] = existent_atom;
1443 [ + + ]: 15 : for (k = 3; k < nnum + 3; k++) /* @nnuk : wrong mapping of endpoints (+3 added for full endpoints mapping for all haptic bonds) */
1444 : : {
1445 : 12 : num_list[k] = get_actual_atom_number(num_list[k],
1446 : : n_orig_at,
1447 : 12 : ctab->v3000->atom_index_orig,
1448 : 12 : ctab->v3000->atom_index_fin);
1449 : : }
1450 : 3 : res = NumLists_Append(ctab->v3000->haptic_bonds, num_list);
1451 [ - + ]: 3 : if (res < 0)
1452 : : {
1453 : 0 : failed = 1;
1454 : : }
1455 : : else
1456 : : {
1457 : 3 : is_haptic = 1;
1458 : : }
1459 : : }
1460 : : }
1461 : : /* djb-rwth: addressing coverity ID #499489 -- false positive as num_atoms allocated in MolfileV3000ReadHapticBond and returns a value in this block */
1462 : : }
1463 [ + - ]: 2 : else if (!strcmp(field, "DISP"))
1464 : : {
1465 : 2 : if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
1466 : : {
1467 : : ;
1468 : : }
1469 : : }
1470 [ # # ]: 0 : else if (!strcmp(field, "ATTACH"))
1471 : : {
1472 : 0 : if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
1473 : : {
1474 : : ;
1475 : : }
1476 : : }
1477 : :
1478 [ - + ]: 186 : if (failed)
1479 : : {
1480 [ # # ]: 0 : if (!err)
1481 : : {
1482 : : /* can't interpret bonds block line */
1483 [ # # ]: 0 : TREAT_ERR(err, 4, "Cannot interpret V3000 bond block line:");
1484 : 0 : dotify_non_printable_chars(line);
1485 : 0 : AddErrorMessage(pStrErr, line);
1486 : : }
1487 [ # # ]: 0 : if (!strcmp(line, SD_FMT_END_OF_DATA))
1488 : : {
1489 : 0 : err = -abs(err);
1490 : 0 : break;
1491 : : }
1492 : : }
1493 : : } /* while ( p && (len=MolfileV3000ReadKeyword(field, &p)) > 0 ) */
1494 : :
1495 [ + + ]: 605 : if (is_haptic)
1496 : 3 : {
1497 : 3 : int ii = ctab->v3000->n_haptic_bonds;
1498 : 3 : ctab->v3000->haptic_bonds->lists[ii][0] = bond_type;
1499 : 3 : ctab->v3000->n_haptic_bonds++;
1500 : 3 : continue;
1501 : : }
1502 : : else
1503 : : {
1504 : 602 : int ii = ctab->v3000->n_non_haptic_bonds;
1505 : 602 : ctab->bonds[ii].atnum1 = atnum1;
1506 : 602 : ctab->bonds[ii].atnum2 = atnum2;
1507 : 602 : ctab->bonds[ii].bond_type = bond_type;
1508 : 602 : ctab->bonds[ii].bond_stereo = stereo;
1509 : 602 : ctab->v3000->n_non_haptic_bonds++;
1510 : : }
1511 : : } /* if ctab->bonds */
1512 : : } /* for ( i = 0; i < ctab->n_bonds; i++ ) */
1513 : :
1514 [ + + ]: 57 : if (ctab->v3000->n_haptic_bonds)
1515 : : {
1516 : 2 : AddErrorMessage(pStrErr, "V3000 haptic bonds read/stored and ignored if MolecularInorganics or NPZz parameter is not used"); /* @nnuk : when using /MolecularInorganics or /NPZz, haptic bonds will not be ignored */
1517 : 2 : ctab->n_bonds = ctab->v3000->n_non_haptic_bonds;
1518 : : }
1519 : :
1520 : : /* Check for proper finish */
1521 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1522 : 57 : inchi_strbuf_reset(pin);
1523 : :
1524 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1525 : :
1526 [ - + ]: 57 : if (nc < 1)
1527 : : {
1528 : 0 : p = NULL;
1529 : : }
1530 : : else
1531 : : {
1532 : 57 : p = line = pin->pStr;
1533 : : }
1534 [ + - - + ]: 57 : if (!p || strcmp(p, "END BOND"))
1535 : : {
1536 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Bond block end marker");
1537 : : }
1538 : 57 : remove_one_lf(line);
1539 : :
1540 : 57 : err_fin:
1541 : :
1542 : 57 : inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
1543 : 57 : return err;
1544 : : }
1545 : :
1546 : : /****************************************************************************
1547 : : Convert atom index to the final consequitive atom number (starting from 1)
1548 : : Returns -1 for star atom or not found index
1549 : : ****************************************************************************/
1550 : 1246 : int get_actual_atom_number(int index, int n, int *orig, int *fin)
1551 : : {
1552 : : int i;
1553 [ + - ]: 14523 : for (i = 0; i < n; i++)
1554 : : {
1555 [ + + ]: 14523 : if (orig[i] == index)
1556 : : {
1557 : 1246 : return fin[i];
1558 : : }
1559 : : }
1560 : :
1561 : 0 : return -1;
1562 : : }
1563 : :
1564 : : /****************************************************************************
1565 : : Read V3000 tail of CTab
1566 : : ****************************************************************************/
1567 : 57 : int MolfileV3000ReadTailOfCTAB(MOL_FMT_CTAB *ctab,
1568 : : INCHI_IOSTREAM *inp_file,
1569 : : int err,
1570 : : char *pStrErr)
1571 : : {
1572 : 57 : int retcode = err;
1573 : : int nc;
1574 : 57 : char *p = NULL, *line = NULL;
1575 : : INCHI_IOSTREAM tmpin;
1576 : 57 : INCHI_IOS_STRING *pin = &tmpin.s;
1577 : 57 : inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
1578 : :
1579 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1580 : :
1581 : 57 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1582 : :
1583 [ - + ]: 57 : if (nc < 1)
1584 : : {
1585 : 0 : p = NULL;
1586 : : }
1587 : : else
1588 : : {
1589 : 57 : p = line = pin->pStr;
1590 : : }
1591 : 57 : remove_one_lf(line);
1592 : :
1593 [ + - - + ]: 57 : if (p && !strcmp(p, "BEGIN SGROUP"))
1594 : : {
1595 : 0 : retcode = MolfileV3000ReadSGroup(ctab, inp_file, retcode, pStrErr);
1596 [ # # ]: 0 : if (retcode)
1597 : : {
1598 : 0 : retcode += 70;
1599 [ # # ]: 0 : TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
1600 : : }
1601 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1602 : 0 : inchi_strbuf_reset(pin);
1603 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1604 [ # # ]: 0 : if (nc < 1)
1605 : : {
1606 : 0 : p = NULL;
1607 : : }
1608 : : else
1609 : : {
1610 : 0 : p = line = pin->pStr;
1611 : 0 : remove_one_lf(line);
1612 : : }
1613 : : }
1614 : :
1615 [ + - - + ]: 57 : if (p && !strcmp(p, "BEGIN OBJ3D"))
1616 : : {
1617 : 0 : retcode = MolfileV3000Read3DBlock(ctab, inp_file, retcode, pStrErr);
1618 [ # # ]: 0 : if (retcode)
1619 : : {
1620 : 0 : retcode += 70;
1621 [ # # ]: 0 : TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
1622 : : }
1623 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1624 : 0 : inchi_strbuf_reset(pin);
1625 : :
1626 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1627 [ # # ]: 0 : if (nc < 1)
1628 : : {
1629 : 0 : p = NULL;
1630 : : }
1631 : : else
1632 : : {
1633 : 0 : p = line = pin->pStr;
1634 : 0 : remove_one_lf(line);
1635 : : }
1636 : : }
1637 : :
1638 [ + - - + ]: 57 : while (p && !strcmp(p, "LINKNODE"))
1639 : : {
1640 : : /* skip for now */
1641 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1642 : 0 : inchi_strbuf_reset(pin);
1643 : :
1644 : 0 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1645 [ # # ]: 0 : if (nc < 1)
1646 : : {
1647 : 0 : p = NULL;
1648 : : }
1649 : : else
1650 : : {
1651 : 0 : p = line = pin->pStr;
1652 : 0 : remove_one_lf(line);
1653 : : }
1654 : : }
1655 : :
1656 : : /* Collections */
1657 [ + - + + ]: 94 : while (p && !strcmp(p, "BEGIN COLLECTION"))
1658 : : {
1659 : 37 : retcode = MolfileV3000ReadCollections(ctab, inp_file, retcode, pStrErr);
1660 [ - + ]: 37 : if (retcode)
1661 : : {
1662 : 0 : retcode += 70;
1663 [ # # ]: 0 : TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
1664 : : }
1665 : : /*p = inchi_fgetsLf_V3000( line, inp_file );*/
1666 : 37 : inchi_strbuf_reset(pin);
1667 : :
1668 : 37 : nc = get_V3000_input_line_to_strbuf(pin, inp_file);
1669 : :
1670 [ - + ]: 37 : if (nc < 1)
1671 : : {
1672 : 0 : p = NULL;
1673 : : }
1674 : : else
1675 : : {
1676 : 37 : p = line = pin->pStr;
1677 : 37 : remove_one_lf(line);
1678 : : }
1679 : : }
1680 : :
1681 [ + - - + ]: 57 : if (!p || strcmp(p, "END CTAB"))
1682 : : {
1683 [ # # ]: 0 : TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 CTAB end marker");
1684 : : }
1685 : :
1686 : 57 : remove_one_lf(line);
1687 : :
1688 : 57 : err_fin:
1689 : 57 : inchi_strbuf_close(pin);
1690 : :
1691 : 57 : return err;
1692 : : }
1693 : :
1694 : : /****************************************************************************
1695 : : Read haptic bond info
1696 : : ****************************************************************************/
1697 : 3 : int MolfileV3000ReadHapticBond(MOL_FMT_CTAB *ctab,
1698 : : char **line_ptr,
1699 : : int **num_list,
1700 : : char *pStrErr)
1701 : : {
1702 : 3 : int nread = 0;
1703 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
1704 : 3 : const int max_field_len = sizeof(field);
1705 : : char *p_end;
1706 : 3 : int i, nnum = 0;
1707 : :
1708 : 3 : *num_list = NULL;
1709 : :
1710 : 3 : memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
1711 : :
1712 : 3 : nread = read_upto_delim(line_ptr, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1713 [ - + ]: 3 : if (strcmp(field, "("))
1714 : : {
1715 : 0 : return -1;
1716 : : }
1717 : :
1718 : 3 : nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1719 : :
1720 : 3 : nnum = strtol(field, &p_end, 10);
1721 : :
1722 [ - + ]: 3 : if (p_end == field)
1723 : : {
1724 : 0 : return -1; /* paranoia */
1725 : : }
1726 [ - + ]: 3 : if (nnum < 0)
1727 : : {
1728 : 0 : return -1;
1729 : : }
1730 : :
1731 : 3 : *num_list = (int *)inchi_calloc((long long)nnum + 3, sizeof(int)); /* djb-rwth: cast operator added */
1732 : :
1733 [ - + ]: 3 : if (!*num_list)
1734 : : {
1735 : 0 : nread = -1;
1736 : 0 : goto ret;
1737 : : }
1738 : :
1739 : 3 : (*num_list)[0] = -1; /* will be bond type, to be filled by caller */
1740 : 3 : (*num_list)[1] = -1; /* will be atom number, to be filled by caller */
1741 : 3 : (*num_list)[2] = nnum;
1742 : :
1743 [ + + ]: 15 : for (i = 3; i < nnum + 3; i++)
1744 : : {
1745 [ - + ]: 12 : if (0 > MolfileV3000ReadField(&((*num_list)[i]), MOL_FMT_INT_DATA, line_ptr))
1746 : : {
1747 : 0 : nread = -1;
1748 : 0 : goto ret;
1749 : : }
1750 : : }
1751 : :
1752 : : /* ')' should have been consumed by strtol */
1753 : :
1754 : : /* check for ATTACH=ALL */
1755 : :
1756 : 3 : nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
1757 [ - + ]: 3 : if (nread > 0)
1758 : : {
1759 [ + - ]: 3 : if (strcmp(field, "ATTACH=ALL"))
1760 : : {
1761 : 0 : nread = -1;
1762 : 0 : goto ret;
1763 : : }
1764 : : }
1765 : :
1766 : 3 : ret:
1767 [ - + ]: 3 : if (nread < 0)
1768 : : {
1769 [ # # ]: 0 : if (*num_list)
1770 : : {
1771 [ # # ]: 0 : inchi_free(*num_list);
1772 : 0 : *num_list = NULL;
1773 : : }
1774 : : }
1775 : :
1776 : 3 : return nread;
1777 : : }
1778 : :
1779 : : /****************************************************************************
1780 : : Read V3000 stereo collection
1781 : : ****************************************************************************/
1782 : 101 : int MolfileV3000ReadStereoCollection(MOL_FMT_CTAB *ctab,
1783 : : char **line_ptr,
1784 : : int **num_list,
1785 : : char *pStrErr)
1786 : : {
1787 : 101 : int nread = 0;
1788 : : char field[MOL_FMT_V3000_MAXFIELDLEN];
1789 : 101 : const int max_field_len = sizeof(field);
1790 : : char *p_end;
1791 : 101 : int i, nnum = 0;
1792 : :
1793 : 101 : *num_list = NULL;
1794 : :
1795 : 101 : memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
1796 : :
1797 : 101 : nread = read_upto_delim(line_ptr, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1798 [ - + ]: 101 : if (strcmp(field, "("))
1799 : : {
1800 : 0 : return -1;
1801 : : }
1802 : :
1803 : 101 : nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
1804 : :
1805 : 101 : nnum = strtol(field, &p_end, 10);
1806 : :
1807 [ - + ]: 101 : if (p_end == field)
1808 : : {
1809 : 0 : return -1; /* paranoia */
1810 : : }
1811 [ - + ]: 101 : if (nnum < 0)
1812 : : {
1813 : 0 : return -1;
1814 : : }
1815 : :
1816 : 101 : *num_list = (int *)inchi_calloc((long long)nnum + 3, sizeof(int)); /* djb-rwth: cast operator added */
1817 : :
1818 [ - + ]: 101 : if (!*num_list)
1819 : : {
1820 : 0 : nread = -1;
1821 : 0 : goto ret;
1822 : : }
1823 : :
1824 : 101 : (*num_list)[0] = -1; /* reserved, may be filled by caller */
1825 : 101 : (*num_list)[1] = nnum;
1826 : :
1827 [ + + ]: 272 : for (i = 2; i < nnum + 2; i++)
1828 : : {
1829 [ - + ]: 171 : if (0 > MolfileV3000ReadField(&((*num_list)[i]), MOL_FMT_INT_DATA, line_ptr))
1830 : : {
1831 : 0 : nread = -1;
1832 : 0 : goto ret;
1833 : : }
1834 : : }
1835 : :
1836 : : /* ')' should have been consumed by strtol */
1837 : :
1838 : 101 : ret:
1839 [ - + ]: 101 : if (nread < 0)
1840 : : {
1841 [ # # ]: 0 : if (*num_list)
1842 : : {
1843 [ # # ]: 0 : inchi_free(*num_list);
1844 : 0 : *num_list = NULL;
1845 : : }
1846 : : }
1847 : :
1848 : 101 : return nread;
1849 : : }
1850 : :
1851 : : /****************************************************************************
1852 : : Returns -1 @ error
1853 : : ****************************************************************************/
1854 : 1830 : int get_V3000_input_line_to_strbuf(INCHI_IOS_STRING *buf,
1855 : : INCHI_IOSTREAM *inp_stream)
1856 : : {
1857 : 1830 : const int prefix_len = 7; /* "M V30 " */
1858 : 1830 : int old_used, crlf2lf = 1, preserve_lf = 0;
1859 : :
1860 : 1830 : inchi_strbuf_reset(buf);
1861 : :
1862 : 1830 : old_used = buf->nUsedLength;
1863 : : while (1)
1864 : : {
1865 : 1830 : inchi_strbuf_addline(buf, inp_stream, crlf2lf, preserve_lf);
1866 : :
1867 [ - + ]: 1830 : if (buf->nUsedLength - old_used < 8)
1868 : : {
1869 : 0 : return -1;
1870 : : }
1871 [ - + ]: 1830 : if (strncmp(buf->pStr + old_used, "M V30 ", prefix_len))
1872 : : {
1873 : 0 : return -1;
1874 : : }
1875 : :
1876 : 1830 : memmove((void *)(buf->pStr + old_used), (void *)(buf->pStr + old_used + prefix_len), (long long)buf->nUsedLength - (long long)old_used - (long long)prefix_len + 1); /* djb-rwth: cast operators added */ /* ricrogz: fixing memory overflow error */
1877 : 1830 : buf->nUsedLength -= prefix_len;
1878 : :
1879 [ + - ]: 1830 : if (buf->pStr[buf->nUsedLength - 1] != '-')
1880 : : {
1881 : 1830 : break;
1882 : : }
1883 : 0 : buf->pStr[--buf->nUsedLength] = '\0';
1884 : :
1885 : 0 : old_used = buf->nUsedLength;
1886 : : }
1887 : :
1888 : 1830 : remove_trailing_spaces(buf->pStr);
1889 : 1830 : buf->nUsedLength = strlen(buf->pStr);
1890 : :
1891 : 1830 : return buf->nUsedLength;
1892 : : }
|