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