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