Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <ctype.h>
8 : : #include <string.h>
9 : : #include <math.h>
10 : : #include <float.h>
11 : : #include <limits.h>
12 : :
13 : : #include "mode.h"
14 : : #include "mol_fmt.h"
15 : :
16 : : #include "ichierr.h"
17 : : #include "util.h"
18 : : #include "ichi_io.h"
19 : : #include "strutil.h"
20 : :
21 : : #include "bcf_s.h"
22 : :
23 : : /*
24 : : MolFile related procedures - 1
25 : :
26 : :
27 : : */
28 : :
29 : :
30 : :
31 : : /*
32 : : Local functions; static
33 : : */
34 : : /* MOL V2000 */
35 : : static int MolfileReadSTextBlock( MOL_FMT_CTAB* ctab, INCHI_IOSTREAM *inp_file,
36 : : int err, char *pStrErr );
37 : : static int MolfileReadPropBlock( MOL_FMT_CTAB* ctab, MOL_FMT_HEADER_BLOCK *pHdr,
38 : : INCHI_IOSTREAM *inp_file,
39 : : int treat_polymers,
40 : : int err, char *pStrErr,
41 : : int bNoWarnings );
42 : : static int MolfileReadSgroupOfPolymer( MOL_FMT_CTAB* ctab,
43 : : MOL_FMT_HEADER_BLOCK *pHdr,
44 : : INCHI_IOSTREAM *inp_file,
45 : : char line[MOL_FMT_INPLINELEN],
46 : : char *szType, char *p,
47 : : int err, char *pStrErr );
48 : : static int MolfileTreatPseudoElementAtoms( MOL_FMT_CTAB* ctab,
49 : : int pseudos_allowed,
50 : : int *err,
51 : : char *pStrErr );
52 : :
53 : :
54 : : /****************************************************************************
55 : : Read MOL-format data from SD or MOL file
56 : : ****************************************************************************/
57 : 121 : MOL_FMT_DATA* ReadMolfile( INCHI_IOSTREAM *inp_file,
58 : : MOL_FMT_HEADER_BLOCK *OnlyHeaderBlock,
59 : : MOL_FMT_CTAB *OnlyCTab,
60 : : int bGetOrigCoord,
61 : : int treat_polymers,
62 : : int treat_NPZz,
63 : : char *pname,
64 : : int lname,
65 : : unsigned long *Id,
66 : : const char *pSdfLabel,
67 : : char *pSdfValue,
68 : : int *err,
69 : : char *pStrErr,
70 : : int bNoWarnings )
71 : : {
72 : : MOL_FMT_DATA* mfdata;
73 : :
74 [ - + - - ]: 121 : if (pname && lname)
75 : : {
76 : 0 : pname[0] = '\0';
77 : : }
78 [ + - ]: 121 : if (Id)
79 : : {
80 : 121 : *Id = 0LU; /* ignore for now */
81 : : }
82 : :
83 : 121 : mfdata = MolfileReadDataLines( inp_file, OnlyHeaderBlock, OnlyCTab,
84 : : bGetOrigCoord, treat_polymers,
85 : : err, pStrErr, bNoWarnings );
86 : :
87 [ - + ]: 121 : if (*err < 0)
88 : : {
89 : : /* read OK, and end of data encountered */
90 : 0 : *err = -*err;
91 : : }
92 : : else
93 : : {
94 : : /* unnecessary extra data may have present in SDF; skip them for now */
95 : 121 : int ret_skip_extras = SDFileSkipExtraData( inp_file, Id, NULL, 0,
96 : : pname, lname, *err,
97 : : pSdfLabel, pSdfValue,
98 : : pStrErr, bNoWarnings);
99 : :
100 : :
101 [ - + ]: 121 : if (ret_skip_extras)
102 : : {
103 : : /* important to continue to the next good structure */
104 : 0 : *err = ret_skip_extras;
105 : : }
106 : : }
107 : :
108 : : /* Treat star/Zz atoms if present.
109 : : This first-line treating affects only Molfile input.
110 : : No direct input in API calls, no InChI strings.
111 : : These will be processed on checking internal data structs.
112 : : */
113 [ + - ]: 121 : if (mfdata)
114 : : {
115 : 121 : int nzz = 0; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
116 [ + + - + ]: 121 : int pseudos_allowed = (treat_NPZz == 1) || (treat_polymers != POLYMERS_NO);
117 : 121 : nzz = MolfileTreatPseudoElementAtoms( &mfdata->ctab,
118 : : pseudos_allowed,
119 : : err,
120 : : pStrErr ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
121 : : }
122 : :
123 : 121 : return mfdata;
124 : : }
125 : :
126 : :
127 : : /****************************************************************************
128 : : Read data lines completely ingnore STEXT block, queries, and 3D features
129 : : ****************************************************************************/
130 : 121 : MOL_FMT_DATA * MolfileReadDataLines( INCHI_IOSTREAM *inp_file,
131 : : MOL_FMT_HEADER_BLOCK *OnlyHeaderBlock,
132 : : MOL_FMT_CTAB *OnlyCTab,
133 : : int bGetOrigCoord,
134 : : int treat_polymers,
135 : : int *err,
136 : : char *pStrErr,
137 : : int bNoWarnings )
138 : : {
139 : : int n_alloc_atoms;
140 : 121 : MOL_FMT_CTAB ctab, *pCtab = NULL;
141 : 121 : MOL_FMT_HEADER_BLOCK *pHdr = NULL;
142 : 121 : MOL_FMT_DATA *mfdata = NULL;
143 : : int retcode, prevcode;
144 : 121 : int data_ended = 0, should_read_all = 0;
145 : :
146 [ + - ]: 121 : if (!OnlyHeaderBlock)
147 : : {
148 : 121 : should_read_all = 1;
149 : : }
150 : :
151 : : /* djb-rwth: removing redundant code */
152 : : /* djb-rwth: addressing coverity ID #499502 -- TREAT_ERR_AND_FIN properly used in all cases */
153 : 121 : *err = 0;
154 : :
155 [ + - ]: 121 : if (should_read_all)
156 : : {
157 : :
158 : 121 : mfdata = (MOL_FMT_DATA*) inchi_calloc( 1, sizeof( MOL_FMT_DATA ) );
159 [ - + ]: 121 : if (!mfdata)
160 : : {
161 : 0 : retcode = 1;
162 : 0 : AddErrorMessage( pStrErr, "Out of RAM" );
163 : 0 : goto err_fin;
164 : : }
165 : :
166 : 121 : pHdr = &mfdata->hdr;
167 : 121 : pCtab = &mfdata->ctab;
168 : : }
169 : : else
170 : : {
171 : 0 : pHdr = OnlyHeaderBlock;
172 [ # # ]: 0 : pCtab = OnlyCTab ? OnlyCTab : &ctab;
173 : 0 : memset( pHdr, 0, sizeof( MOL_FMT_HEADER_BLOCK ) ); /* djb-rwth: memset_s C11/Annex K variant? */
174 : 0 : memset( pCtab, 0, sizeof( MOL_FMT_CTAB ) ); /* djb-rwth: memset_s C11/Annex K variant? */
175 : : }
176 : :
177 : 121 : pCtab->bonds = NULL;
178 : 121 : pCtab->atoms = NULL;
179 : 121 : pCtab->coords = NULL;
180 : 121 : pCtab->v3000 = NULL;
181 : :
182 : : /* Header lines */
183 : 121 : retcode = MolfileReadHeaderLines( pHdr, inp_file, pStrErr );
184 [ - + ]: 121 : if (retcode)
185 : : {
186 : : /* most likely end of file */
187 : 0 : retcode += 10;
188 : 0 : goto err_fin;
189 : : }
190 : :
191 : : /* Read counts line and also check if we deal with V3000 Molfile */
192 : 121 : retcode = MolfileReadCountsLine( pCtab, inp_file, pStrErr );
193 [ - + ]: 121 : if (retcode)
194 : : {
195 : 0 : retcode += 20;
196 : 0 : goto err_fin;
197 : : }
198 : :
199 [ + + ]: 121 : if (pCtab->v3000)
200 : : {
201 : :
202 : : /* In V3000, the previously read counts should be neglected
203 : : and new counts line (1st in Ctab) should be read preceded
204 : : by "M V30 BEGIN CTAB" */
205 : :
206 : 57 : retcode = MolfileV3000ReadCTABBeginAndCountsLine( pCtab, inp_file, pStrErr );
207 [ - + ]: 57 : if (retcode)
208 : : {
209 : 0 : retcode += 70;
210 [ # # ]: 0 : TREAT_ERR_AND_FIN( retcode, 1, err_fin, pStrErr );
211 : : }
212 : :
213 : 57 : retcode = MolfileV3000Init( pCtab, pStrErr );
214 [ - + ]: 57 : if (retcode)
215 : : {
216 : 0 : retcode += 70;
217 [ # # ]: 0 : TREAT_ERR_AND_FIN( retcode, 1, err_fin, pStrErr );
218 : : }
219 : : }
220 : :
221 : : /* Atomic block */
222 [ + - ]: 121 : if (should_read_all)
223 : : {
224 : 121 : n_alloc_atoms = inchi_max( mfdata->ctab.n_atoms, 1 );
225 : 121 : mfdata->ctab.atoms = (MOL_FMT_ATOM*)
226 : 121 : inchi_calloc( n_alloc_atoms, sizeof( MOL_FMT_ATOM ) );
227 [ - + ]: 121 : if (!mfdata->ctab.atoms)
228 : : {
229 : 0 : retcode = 2;
230 [ # # ]: 0 : TREAT_ERR_AND_FIN( retcode, 2, err_fin, "Out of RAM" );
231 : : }
232 : :
233 [ + - ]: 121 : if (bGetOrigCoord)
234 : : {
235 : 121 : mfdata->ctab.coords = (MOL_COORD*)
236 : 121 : inchi_calloc( n_alloc_atoms, sizeof( MOL_COORD ) );
237 [ - + ]: 121 : if (!mfdata->ctab.coords)
238 : : {
239 : 0 : retcode = 2;
240 [ # # ]: 0 : TREAT_ERR_AND_FIN( retcode, 2, err_fin, "Out of RAM" );
241 : : }
242 : : }
243 : : }
244 : :
245 [ + + ]: 121 : if (!pCtab->v3000)
246 : : {
247 : 64 : retcode = MolfileReadAtomsBlock( pCtab, inp_file, retcode, pStrErr );
248 : : }
249 : : else
250 : : {
251 : 57 : retcode = MolfileV3000ReadAtomsBlock( pCtab, inp_file, retcode, pStrErr );
252 : : }
253 [ - + ]: 121 : if (retcode)
254 : : {
255 [ # # ]: 0 : if (retcode < 0)
256 : : {
257 : 0 : retcode = -retcode;
258 : 0 : data_ended = 1;
259 : : }
260 : 0 : retcode += 30;
261 : : /* goto err_fin; */
262 : : }
263 : :
264 : : /* Bonds block */
265 [ + - + - ]: 121 : if (should_read_all && retcode < 30)
266 : : {
267 [ + - ]: 121 : if (!data_ended)
268 : : {
269 : 121 : int n_alloc_bonds = inchi_max( mfdata->ctab.n_bonds, 1 );
270 : 121 : mfdata->ctab.bonds = (MOL_FMT_BOND *)
271 : 121 : inchi_calloc( n_alloc_bonds, sizeof( MOL_FMT_BOND ) );
272 [ - + ]: 121 : if (!mfdata->ctab.bonds)
273 : : {
274 : : /* can't allocate bonds structure */
275 : 0 : retcode = 3;
276 [ # # ]: 0 : TREAT_ERR_AND_FIN( retcode, 3, err_fin, "Out of RAM" );
277 : : }
278 : : }
279 : : }
280 : :
281 : 121 : prevcode = retcode;
282 [ + - ]: 121 : if (!data_ended)
283 : : {
284 [ + + ]: 121 : if (!pCtab->v3000)
285 : : {
286 : 64 : retcode = MolfileReadBondsBlock( pCtab, inp_file, retcode, pStrErr );
287 : : }
288 : : else
289 : : {
290 : 57 : retcode = MolfileV3000ReadBondsBlock( pCtab, inp_file, retcode, pStrErr );
291 : : }
292 [ - + ]: 121 : if (retcode)
293 : : {
294 [ # # ]: 0 : if (retcode < 0)
295 : : {
296 : 0 : retcode = -retcode;
297 : 0 : data_ended = 1;
298 : : }
299 : 0 : retcode = prevcode ? prevcode
300 [ # # ]: 0 : : retcode + 40;
301 : : }
302 : :
303 : :
304 : : /* SGroup, 3D, link line(s), collections, END CTAB */
305 [ + + ]: 121 : if (pCtab->v3000)
306 : : {
307 : 57 : retcode = MolfileV3000ReadTailOfCTAB( pCtab, inp_file, retcode, pStrErr );
308 [ - + ]: 57 : if (retcode)
309 : : {
310 [ # # ]: 0 : if (retcode < 0)
311 : : {
312 : 0 : retcode = -retcode;
313 : 0 : data_ended = 1;
314 : : }
315 [ # # ]: 0 : retcode = prevcode ? prevcode : retcode + 70;
316 : : }
317 : : }
318 : : }
319 : 121 : prevcode = retcode;
320 : :
321 : : /* SText */
322 [ + - ]: 121 : if (!data_ended)
323 : : {
324 : 121 : retcode = MolfileReadSTextBlock( pCtab, inp_file, retcode, pStrErr );
325 [ - + ]: 121 : if (retcode)
326 : : {
327 [ # # ]: 0 : retcode = prevcode ? prevcode : retcode + 50;
328 : : }
329 : : }
330 : 121 : prevcode = retcode;
331 : :
332 : : /* Prop block */
333 [ + - ]: 121 : if (!data_ended)
334 : : {
335 : 121 : retcode = MolfileReadPropBlock( pCtab, pHdr, inp_file, treat_polymers, retcode, pStrErr, bNoWarnings );
336 : :
337 [ - + ]: 121 : if (retcode)
338 : : {
339 [ # # ]: 0 : if (retcode < 0)
340 : : {
341 : 0 : retcode = -retcode;
342 : 0 : data_ended = 1;
343 : : }
344 [ # # ]: 0 : retcode = prevcode ? prevcode : retcode + 60;
345 : : }
346 : : }
347 : :
348 : : /* Check that all valences are in allowed range ( <=MAXVAL, currently 20 ) */
349 : : if (1)
350 : : #ifdef TARGET_LIB_FOR_WINCHI
351 : : if (pCtab && pCtab->atoms)
352 : : #endif
353 : : {
354 : :
355 : : int i;
356 [ + + ]: 923 : for (i = 0; i < pCtab->n_atoms; i++)
357 : : {
358 [ + - ]: 802 : if (pCtab->atoms) /* djb-rwth: fixing a NULL pointer dereference */
359 : : {
360 [ - + ]: 802 : if (pCtab->atoms[i].valence > MAXVAL)
361 : : {
362 : 0 : retcode = 70 + 9;
363 : 0 : TREAT_ERR( retcode, 0, "Too large input atomic valence" );
364 : 0 : break;
365 : : }
366 : : }
367 : : }
368 : : #if ( FIX_CURE53_ISSUE_NULL_DEREFERENCE_MAKE_A_COPY_OF_T_GROUP_INFO==1 || defined(FIX_IMPOSSIBLE_H_ISOTOPE_BUG) )
369 : : /* Do not eat H isotopes other than [H,D,T] */
370 [ + + ]: 923 : for (i = 0; i < pCtab->n_atoms; i++)
371 : : {
372 [ + - ]: 802 : if (pCtab->atoms) /* djb-rwth: fixing a NULL pointer dereference */
373 : : {
374 : 802 : int dmass = pCtab->atoms[i].mass_difference;
375 [ + + - + : 802 : if ((!strcmp(pCtab->atoms[i].symbol, "H") && dmass != 0 && dmass != 1 && dmass != 2 && dmass != 127) ||
- - - - -
- ]
376 [ - + - - : 802 : (!strcmp(pCtab->atoms[i].symbol, "D") && dmass != 0 && dmass != 1 && dmass != -1) ||
- - - - ]
377 [ - + - - : 802 : (!strcmp(pCtab->atoms[i].symbol, "T") && dmass != 0 && dmass != -1 && dmass != -2))
- - - - ]
378 : : {
379 : 0 : retcode = 70 + 8;
380 : 0 : TREAT_ERR(retcode, 0, "Unacceptable isotope of hydrogen");
381 : 0 : break;
382 : : }
383 : : }
384 : : }
385 : : #endif
386 : : }
387 : :
388 : 121 : err_fin:
389 [ - + ]: 121 : *err = data_ended ? -retcode : retcode;
390 : :
391 [ + - ]: 121 : if (should_read_all)
392 : : {
393 [ - + ]: 121 : if (retcode)
394 : : {
395 : 0 : mfdata = FreeMolfileData( mfdata ); /* delete all results */
396 : : }
397 : 121 : return mfdata;
398 : : }
399 : : else
400 : : {
401 [ # # ]: 0 : if (retcode)
402 : : {
403 : 0 : return NULL;
404 : : }
405 : : else
406 : : {
407 : 0 : return (MOL_FMT_DATA*) OnlyHeaderBlock;
408 : : }
409 : : }
410 : : }
411 : :
412 : :
413 : : /****************************************************************************
414 : : Read Molfile header
415 : : ****************************************************************************/
416 : 121 : int MolfileReadHeaderLines( MOL_FMT_HEADER_BLOCK *hdr,
417 : : INCHI_IOSTREAM *inp_file,
418 : : char *pStrErr )
419 : : {
420 : : /* All input lines can have up to 80 characters */
421 : : /* Header Block */
422 : :
423 : : char line[MOL_FMT_INPLINELEN]; /* + cr +lf +zero termination + reserve */
424 : 121 : int err = 0, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
425 : 121 : const int line_len = sizeof( line );
426 : : char *p;
427 : :
428 : :
429 : : /* Header line #1: name */
430 : 121 : p = inchi_fgetsLf( line, line_len, inp_file );
431 [ - + ]: 121 : if (!p)
432 : : {
433 : : /* can't read the input file line */
434 : 0 : err = 1;
435 : : /* AddErrorMessage( pStrErr, "Can't read header block name line" ); */
436 : 0 : goto err_fin;
437 : : }
438 : :
439 : 121 : remove_one_lf( line );
440 : :
441 : : /* -- Disabled to relax strictness: allow > 80 chars names. */
442 : : /*
443 : : if ( line[MOL_FMT_MAXLINELEN] )
444 : : {
445 : : //err = 2; too long line
446 : : goto err_fin;
447 : : }
448 : : */
449 : :
450 : 121 : len = MolfileReadField( hdr->molname,
451 : : sizeof( hdr->molname ) - 1,
452 : : MOL_FMT_STRING_DATA,
453 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
454 : :
455 : : /* Header line #2 */
456 : 121 : p = inchi_fgetsLf( line, line_len, inp_file );
457 [ - + ]: 121 : if (!p)
458 : : {
459 : : /* can't read the input file line */
460 : 0 : err = 3;
461 : : /* AddErrorMessage( pStrErr, "Can't read header block line 2" ); */
462 : 0 : goto err_fin;
463 : : }
464 : :
465 : 121 : remove_one_lf( line );
466 : :
467 : : /* -- Disabled to relax strictness: allow > 80 chars names. */
468 : : /*
469 : : if ( line[MOL_FMT_MAXLINELEN] )
470 : : {
471 : : err = 4; too long input file line
472 : : goto err_fin;
473 : : }
474 : : */
475 : :
476 : 121 : len = MolfileReadField( hdr->user_initls,
477 : : sizeof( hdr->user_initls ) - 1,
478 : : MOL_FMT_STRING_DATA,
479 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
480 : 121 : len = MolfileReadField( hdr->prog_name,
481 : : sizeof( hdr->prog_name ) - 1,
482 : : MOL_FMT_STRING_DATA,
483 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
484 : :
485 : : /*------------ Relax strictness -----------------------*/
486 : 121 : len = MolfileReadField( &hdr->month, 2, MOL_FMT_CHAR_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
487 : 121 : len = MolfileReadField( &hdr->day, 2, MOL_FMT_CHAR_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
488 : 121 : len = MolfileReadField( &hdr->year, 2, MOL_FMT_CHAR_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
489 : 121 : len = MolfileReadField( &hdr->hour, 2, MOL_FMT_CHAR_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
490 : 121 : len = MolfileReadField( &hdr->minute, 2, MOL_FMT_CHAR_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
491 : 121 : len = MolfileReadField( hdr->dim_code, sizeof( hdr->dim_code ) - 1, MOL_FMT_STRING_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
492 : 121 : len = MolfileReadField( &hdr->scaling_factor1, 2, MOL_FMT_SHORT_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
493 : 121 : len = MolfileReadField( &hdr->scaling_factor2, 10, MOL_FMT_DOUBLE_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
494 : 121 : len = MolfileReadField( &hdr->energy, 12, MOL_FMT_DOUBLE_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
495 : 121 : len = MolfileReadField( &hdr->internal_regno, 6, MOL_FMT_LONG_INT_DATA, &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
496 : :
497 : : /* Save the whole line 2 */
498 : 121 : p = line;
499 : 121 : len = MolfileReadField( hdr->line2,
500 : : sizeof( hdr->line2 ) - 1,
501 : : MOL_FMT_STRING_DATA,
502 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
503 : :
504 : : /* Header line #3: comment */
505 : 121 : p = inchi_fgetsLf( line, line_len, inp_file );
506 : :
507 [ - + ]: 121 : if (!p)
508 : : {
509 : 0 : err = 7; /* can't read the line */
510 : : /* AddErrorMessage( pStrErr, "Can't read header block comment line" ); */
511 : 0 : goto err_fin;
512 : : }
513 : 121 : remove_one_lf( line );
514 : : /* -- Disabled to relax strictness: allow > 80 chars comments.
515 : : if ( line[MOL_FMT_MAXLINELEN] ){
516 : : err = 8; too long line
517 : : goto err_fin;
518 : : }
519 : : */
520 : 121 : len = MolfileReadField( hdr->comment,
521 : : sizeof( hdr->comment ) - 1,
522 : : MOL_FMT_STRING_DATA,
523 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
524 : :
525 : 121 : err_fin:
526 : :
527 : 121 : return err;
528 : : }
529 : :
530 : :
531 : : /****************************************************************************
532 : : Read counts line
533 : : ****************************************************************************/
534 : 121 : int MolfileReadCountsLine( MOL_FMT_CTAB* ctab,
535 : : INCHI_IOSTREAM *inp_file,
536 : : char *pStrErr )
537 : : {
538 : : char *p;
539 : : char line[MOL_FMT_INPLINELEN];
540 : 121 : const int line_len = sizeof( line );
541 : 121 : int err = 0, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
542 : :
543 : : /* djb-rwth: addressing coverity ID #499502 -- TREAT_ERR properly used in all cases */
544 : :
545 : 121 : p = inchi_fgetsLf( line, line_len, inp_file );
546 : :
547 [ - + ]: 121 : if (!p)
548 : : {
549 [ # # ]: 0 : TREAT_ERR_AND_FIN( err, 1, err_fin, "Cannot read counts line" );
550 : : /* can't read the input file line */
551 : : }
552 : :
553 : 121 : remove_one_lf( line );
554 : :
555 [ - + ]: 121 : if (line[MOL_FMT_MAXLINELEN])
556 : : {
557 : 0 : TREAT_ERR( err, 0, "Too long counts line" ); /* too long input file line */
558 : : }
559 : :
560 [ + - ]: 121 : if (0 > MolfileReadField( &ctab->n_atoms, 3, MOL_FMT_SHORT_INT_DATA, &p ) /* V2000 only: short int */
561 [ + - ]: 121 : || 0 > MolfileReadField( &ctab->n_bonds, 3, MOL_FMT_SHORT_INT_DATA, &p ) /* V2000 only: short int */
562 : :
563 : : #if ( MOL_FMT_QUERY == MOL_FMT_PRESENT )
564 : : || 0 > MolfileReadField( &ctab->n_atom_lists, 3, MOL_FMT_SHORT_INT_DATA, &p )
565 : : #else
566 [ + - ]: 121 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
567 : : #endif
568 : :
569 [ + - ]: 121 : || 0 > MolfileReadField( NULL, /*obsolete*/ 3, MOL_FMT_JUMP_TO_RIGHT, &p )
570 [ + - ]: 121 : || 0 > MolfileReadField( &ctab->chiral_flag, 3, MOL_FMT_CHAR_INT_DATA, &p )
571 [ + - ]: 121 : || 0 > MolfileReadField( &ctab->n_stext_entries, 3, MOL_FMT_SHORT_INT_DATA, &p )
572 : :
573 : : #if ( MOL_FMT_CPSS == MOL_FMT_PRESENT )
574 : : || 0 > MolfileReadField( &ctab->n_reaction_components_plus_1, 3, MOL_FMT_SHORT_INT_DATA, &p )
575 : : || 0 > MolfileReadField( &ctab->n_reactants, 3, MOL_FMT_SHORT_INT_DATA, &p )
576 : : || 0 > MolfileReadField( &ctab->n_products, 3, MOL_FMT_SHORT_INT_DATA, &p )
577 : : || 0 > MolfileReadField( &ctab->n_intermediates, 3, MOL_FMT_SHORT_INT_DATA, &p )
578 : : #else
579 [ + - ]: 121 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
580 [ + - ]: 121 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
581 [ + - ]: 121 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
582 [ + - ]: 121 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
583 : : #endif
584 : :
585 [ - + ]: 121 : || 0 > MolfileReadField( &ctab->n_property_lines, 3, MOL_FMT_SHORT_INT_DATA, &p ))
586 : : {
587 : 0 : err = 3; /* can't interpret counts line */
588 [ # # ]: 0 : TREAT_ERR( err, 3, "Cannot interpret counts line:" ); /* too long input file line */
589 : 0 : dotify_non_printable_chars( line );
590 : 0 : AddErrorMessage( pStrErr, line );
591 : 0 : goto err_fin;
592 : : }
593 : :
594 : : /* Get CTFile version (V2000 or other) */
595 : 121 : len = MolfileReadField( ctab->version_string,
596 : : sizeof( ctab->version_string ) - 1,
597 : : MOL_FMT_STRING_DATA,
598 : : &p ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
599 : :
600 : : /* Allocate additional space if V3000 */
601 [ + + ]: 121 : if (!strcmp( ctab->version_string, "V3000" ))
602 : : {
603 : 57 : ctab->v3000 = (MOL_FMT_v3000*) inchi_calloc( 1, sizeof( MOL_FMT_v3000 ) );
604 : :
605 [ - + ]: 57 : if (!ctab->v3000)
606 : : {
607 : 0 : AddErrorMessage( pStrErr, "Out of RAM" );
608 : 0 : return -1;
609 : : }
610 : : }
611 : : else
612 : 64 : ctab->v3000 = NULL; /* paranoia */
613 : :
614 : : /* Polymer Sgroups */
615 : 121 : MolFmtSgroups_Alloc( &( ctab->sgroups ), 1 );
616 : :
617 : 121 : err_fin:
618 : :
619 : 121 : return err;
620 : : }
621 : :
622 : :
623 : : /****************************************************************************
624 : : Read V2000 atomic block
625 : : ****************************************************************************/
626 : 64 : int MolfileReadAtomsBlock( MOL_FMT_CTAB* ctab,
627 : : INCHI_IOSTREAM *inp_file,
628 : : int err,
629 : : char *pStrErr )
630 : : {
631 : : char *p;
632 : : char line[MOL_FMT_INPLINELEN];
633 : 64 : const int line_len = sizeof( line );
634 : : int i;
635 : : S_SHORT chg;
636 : : static const S_SHORT charge_val[] = { 0, 3, 2, 1, 'R', -1, -2, -3 };
637 : :
638 : : /* djb-rwth: addressing coverity ID #499580 -- TREAT_ERR properly used in all cases */
639 [ + + ]: 218 : for (i = 0; i < ctab->n_atoms; i++)
640 : : {
641 : 154 : p = inchi_fgetsLf( line, line_len, inp_file );
642 : :
643 [ - + ]: 154 : if (!p)
644 : : {
645 [ # # ]: 0 : if (!err)
646 : : {
647 [ # # ]: 0 : TREAT_ERR( err, 2, "Cannot read atom block line" );
648 : : }
649 : 0 : break;
650 : : }
651 : :
652 : 154 : remove_one_lf( line );
653 : :
654 : :
655 [ - + ]: 154 : if (line[MOL_FMT_MAXLINELEN])
656 : : {
657 : 0 : TREAT_ERR( err, 0, "Too long atom block line" );
658 : : }
659 [ - + ]: 154 : if (err)
660 : : {
661 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
662 : : {
663 : 0 : err = -abs( err );
664 : 0 : break;
665 : : }
666 : 0 : continue; /* bypass the rest of the Atom block */
667 : : }
668 : :
669 [ + - ]: 154 : if (NULL != ctab->coords)
670 : : {
671 : 154 : mystrncpy( ctab->coords[i], p, 31 ); /* original coordinates */
672 : : }
673 : :
674 [ + - ]: 154 : if (NULL != ctab->atoms)
675 : : {
676 [ + - ]: 154 : if (0 > MolfileReadField( &ctab->atoms[i].fx, 10, MOL_FMT_DOUBLE_DATA, &p )
677 [ + - ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].fy, 10, MOL_FMT_DOUBLE_DATA, &p )
678 [ + - ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].fz, 10, MOL_FMT_DOUBLE_DATA, &p )
679 [ + - ]: 154 : || 0 > MolfileReadField( NULL, /* undescribed in article*/ 1, MOL_FMT_JUMP_TO_RIGHT, &p )
680 [ + - ]: 154 : || 0 == MolfileReadField( &ctab->atoms[i].symbol, 3, MOL_FMT_STRING_DATA, &p ) /* was sizeof(ctab->atoms[0].symbol)-1 */
681 [ + - ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].mass_difference, 2, MOL_FMT_CHAR_INT_DATA, &p )
682 [ + - ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].charge, 3, MOL_FMT_CHAR_INT_DATA, &p )
683 [ + - ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].stereo_parity, 3, MOL_FMT_CHAR_INT_DATA, &p )
684 : :
685 : : #if ( MOL_FMT_QUERY == MOL_FMT_PRESENT )
686 : : || 0 > MolfileReadField( &ctab->atoms[i].H_count_plus_1, 3, MOL_FMT_CHAR_INT_DATA, &p )
687 : : || 0 > MolfileReadField( &ctab->atoms[i].stereo_care, 3, MOL_FMT_CHAR_INT_DATA, &p )
688 : : #else
689 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
690 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
691 : : #endif
692 : :
693 [ - + ]: 154 : || 0 > MolfileReadField( &ctab->atoms[i].valence, 3, MOL_FMT_CHAR_INT_DATA, &p ))
694 : : {
695 : :
696 : 0 : err = 4;
697 [ # # ]: 0 : TREAT_ERR( err, 4, "Cannot interpret atom block line:" );
698 : 0 : dotify_non_printable_chars( line );
699 : 0 : AddErrorMessage( pStrErr, line );
700 : :
701 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
702 : : {
703 : 0 : err = -abs( err );
704 : 0 : break;
705 : : }
706 : 0 : continue; /* can't interpret a first half of atom block line */
707 : : }
708 : :
709 : :
710 [ + + - + ]: 154 : if (2 == strlen( ctab->atoms[i].symbol ) && isupper( UCINT ctab->atoms[i].symbol[1] ))
711 : : {
712 : 0 : ctab->atoms[i].symbol[1] = (char) tolower( UCINT ctab->atoms[i].symbol[1] ); /* 5-4-99 DCh*/
713 : : }
714 : :
715 [ + - - + ]: 154 : if (( chg = (S_SHORT) ctab->atoms[i].charge ) < 0 || chg >= (int) ( sizeof( charge_val ) / sizeof( charge_val[0] ) ))
716 : : {
717 : : /* ctab->atoms[i].charge = 0; */ /* error; ignore for now */
718 : 0 : ctab->atoms[i].charge = (S_CHAR) ( 4 - chg ); /* allow greater charges to accommodate NCI structures. 8-20-2002 */
719 : 0 : ctab->atoms[i].radical = 0;
720 : : }
721 [ - + ]: 154 : else if ('R' == ( chg = charge_val[chg] ))
722 : : {
723 : 0 : ctab->atoms[i].charge = 0;
724 : 0 : ctab->atoms[i].radical = RADICAL_DOUBLET;
725 : : }
726 : : else
727 : : {
728 : 154 : ctab->atoms[i].charge = (S_CHAR) chg; /* actual charge value */
729 : 154 : ctab->atoms[i].radical = 0;
730 : : }
731 : :
732 [ + - ]: 154 : if (
733 : :
734 : : #if ( MOL_FMT_CPSS == MOL_FMT_PRESENT )
735 : : 0 > MolfileReadField( &ctab->atoms[i].H0_designator, 3, MOL_FMT_CHAR_INT_DATA, &p )
736 : : || 0 > MolfileReadField( &ctab->atoms[i].reaction_component_type, 3, MOL_FMT_CHAR_INT_DATA, &p )
737 : : || 0 > MolfileReadField( &ctab->atoms[i].reaction_component_num, 3, MOL_FMT_CHAR_INT_DATA, &p )
738 : : #else
739 : 154 : 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
740 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
741 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
742 : : #endif
743 : :
744 : : #if ( MOL_FMT_REACT == MOL_FMT_PRESENT )
745 : : || 0 > MolfileReadField( &ctab->atoms[i].atom_atom_mapping_num, 3, MOL_FMT_SHORT_INT_DATA, &p )
746 : : || 0 > MolfileReadField( &ctab->atoms[i].reaction_component_type, 3, MOL_FMT_CHAR_INT_DATA, &p )
747 : : #else
748 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
749 [ + - ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
750 : : #endif
751 : :
752 : : #if ( MOL_FMT_REACT == MOL_FMT_PRESENT || MOL_FMT_QUERY == MOL_FMT_PRESENT )
753 : : || 0 > MolfileReadField( &ctab->atoms[i].exact_change_flag, 3, MOL_FMT_CHAR_INT_DATA, &p )
754 : : #else
755 [ - + ]: 154 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
756 : : #endif
757 : :
758 : : )
759 : : {
760 : 0 : err = 5; /* can't interpret a second half of atom block line */
761 : :
762 [ # # ]: 0 : TREAT_ERR( err, 5, "Cannot interpret atom block line:" );
763 : 0 : dotify_non_printable_chars( line );
764 : 0 : AddErrorMessage( pStrErr, line );
765 : :
766 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
767 : : {
768 : 0 : err = -abs( err );
769 : 0 : break;
770 : : }
771 : 0 : continue;
772 : : }
773 : : }
774 : : }
775 : :
776 : : /* err_fin: */
777 : :
778 : 64 : return err;
779 : : }
780 : :
781 : :
782 : : /****************************************************************************
783 : : Read V2000 bonds block
784 : : ****************************************************************************/
785 : 64 : int MolfileReadBondsBlock( MOL_FMT_CTAB* ctab,
786 : : INCHI_IOSTREAM *inp_file,
787 : : int err,
788 : : char *pStrErr )
789 : : {
790 : : char *p;
791 : : char line[MOL_FMT_INPLINELEN];
792 : 64 : const int line_len = sizeof( line );
793 : : int i;
794 : :
795 : : #if 0
796 : : if (NULL == ctab->bonds)
797 : : {
798 : : err = 1;
799 : : goto err_fin; /*internal error: memory has not been allocated for bonds structure*/
800 : : }
801 : : #endif
802 : :
803 : : /* djb-rwth: addressing coverity ID #499538 -- TREAT_ERR properly used in all cases */
804 [ + + ]: 158 : for (i = 0; i < ctab->n_bonds; i++)
805 : : {
806 : 94 : p = inchi_fgetsLf( line, line_len, inp_file );
807 : :
808 [ - + ]: 94 : if (!p)
809 : : {
810 [ # # ]: 0 : if (!err)
811 : : {
812 [ # # ]: 0 : TREAT_ERR( err, 2, "Cannot read bond block line" );
813 : : }
814 : 0 : break;
815 : : }
816 : :
817 : 94 : remove_one_lf( line );
818 : :
819 [ - + ]: 94 : if (line[MOL_FMT_MAXLINELEN])
820 : : {
821 [ # # ]: 0 : err = err ? err : 3; /* too long input file line */
822 : : }
823 : :
824 [ - + ]: 94 : if (err)
825 : : {
826 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
827 : : {
828 : 0 : err = -abs( err );
829 : 0 : break;
830 : : }
831 : 0 : continue;
832 : : }
833 : :
834 [ + - ]: 94 : if (ctab->bonds)
835 : : {
836 : :
837 [ + - ]: 94 : if (0 > MolfileReadField( &ctab->bonds[i].atnum1, 3, MOL_FMT_SHORT_INT_DATA, &p )
838 [ + - ]: 94 : || 0 > MolfileReadField( &ctab->bonds[i].atnum2, 3, MOL_FMT_SHORT_INT_DATA, &p )
839 [ + - ]: 94 : || 0 > MolfileReadField( &ctab->bonds[i].bond_type, 3, MOL_FMT_CHAR_INT_DATA, &p )
840 [ + - ]: 94 : || 0 > MolfileReadField( &ctab->bonds[i].bond_stereo, 3, MOL_FMT_CHAR_INT_DATA, &p )
841 : :
842 : : #if ( MOL_FMT_QUERY == MOL_FMT_PRESENT )
843 : : || 0 > MolfileReadField( &ctab->bonds[i].cBondTopology, 3, MOL_FMT_CHAR_INT_DATA, &p ) /* ring/chain */
844 : : #else
845 [ + - ]: 94 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
846 : : #endif
847 : :
848 : : #if ( MOL_FMT_REACT == MOL_FMT_PRESENT )
849 : : || 0 > MolfileReadField( &ctab->bonds[i].cReactingCenterStatus, 3, MOL_FMT_CHAR_INT_DATA, &p )
850 : : #else
851 [ - + ]: 94 : || 0 > MolfileReadField( NULL, 3, MOL_FMT_JUMP_TO_RIGHT, &p )
852 : : #endif
853 : :
854 : : )
855 : : {
856 : :
857 [ # # ]: 0 : if (!err)
858 : : {
859 : : /* can't interpret bonds block line */
860 [ # # ]: 0 : TREAT_ERR( err, 4, "Cannot interpret bond block line:" );
861 : 0 : dotify_non_printable_chars( line );
862 : 0 : AddErrorMessage( pStrErr, line );
863 : : }
864 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
865 : : {
866 : 0 : err = -abs( err );
867 : 0 : break;
868 : : }
869 : : }
870 : : }
871 : : }
872 : :
873 : : /* err_fin: */
874 : :
875 : 64 : return err;
876 : : }
877 : :
878 : :
879 : : /****************************************************************************
880 : : Read SText
881 : : ****************************************************************************/
882 : 121 : int MolfileReadSTextBlock( MOL_FMT_CTAB* ctab,
883 : : INCHI_IOSTREAM *inp_file,
884 : : int err,
885 : : char *pStrErr )
886 : : {
887 : : /* just pass by all stext enties without attemp to interpret them */
888 : : char *p;
889 : : char line[MOL_FMT_INPLINELEN];
890 : 121 : const int line_len = sizeof( line );
891 : : S_SHORT i;
892 : :
893 [ - + ]: 121 : for (i = 0; i < 2 * ctab->n_stext_entries; i++)
894 : : {
895 : 0 : p = inchi_fgetsLf( line, line_len, inp_file );
896 [ # # ]: 0 : if (!p)
897 : : {
898 [ # # ]: 0 : if (!err)
899 : : {
900 [ # # ]: 0 : TREAT_ERR_AND_FIN( err, 2, err_fin, "Cannot read STEXT block line" ); /* djb-rwth: addressing coverity ID #499517 -- TREAT_ERR_AND_FIN properly used */
901 : : }
902 : 0 : break;
903 : : /* can't read the input file line */
904 : : }
905 : :
906 : : /*
907 : : remove_one_lf( line );
908 : : if ( line[MOL_FMT_MAXLINELEN] ){
909 : : TREAT_ERR( err, 2, "Warning: Too long STEXT block line");
910 : : too long input file line
911 : : }
912 : : */
913 : : }
914 : :
915 : 121 : err_fin:
916 : :
917 : 121 : return err;
918 : : }
919 : :
920 : :
921 : :
922 : : /****************************************************************************
923 : : Read properties block
924 : : ****************************************************************************/
925 : 121 : int MolfileReadPropBlock( MOL_FMT_CTAB* ctab,
926 : : MOL_FMT_HEADER_BLOCK *pHdr,
927 : : INCHI_IOSTREAM *inp_file,
928 : : int treat_polymers,
929 : : int err,
930 : : char *pStrErr,
931 : : int bNoWarnings )
932 : : {
933 : : enum { MULTI_LINE_MODE_NO_MODE, MULTI_LINE_MODE_ISIS_ALIAS };
934 : : char *p;
935 : : char line[MOL_FMT_INPLINELEN];
936 : 121 : const int line_len = sizeof( line );
937 : 121 : int nMultiLineMode = MULTI_LINE_MODE_NO_MODE, nAtomNumber = 0;
938 : : S_SHORT i, j;
939 : : char charM[2];
940 : : char szBlank[3];
941 : : char szType[4];
942 : 121 : S_SHORT skip_lines = 0;
943 : : S_SHORT num_entries;
944 : 121 : S_SHORT num_atoms = ctab->n_atoms;
945 : :
946 : 121 : int charge_encountered = 0;
947 : 121 : int radical_encountered = 0;
948 : 121 : int isotope_encountered = 0;
949 : 121 : int polymer_occurred = 0;
950 : :
951 : 121 : szType[0] = '\0'; /* djb-rwth: adding zero termination */
952 : 121 : int debug_polymers = 0;
953 : : #if ( DEBUG_POLYMERS == 1 )
954 : : debug_polymers = 1;
955 : : #elif ( DEBUG_POLYMERS == 2 )
956 : : debug_polymers = 2;
957 : : #endif
958 : :
959 : :
960 [ + - - - ]: 131 : for (i = 0; ctab->version_string[0] ? 1 : ( i < ctab->n_property_lines ); i++)
961 : : {
962 : : /* the last line should be M END */
963 : :
964 : : /* ctab->version_string[0] == 0:
965 : : exactly ctab->n_property_lines lines including M END */
966 : : /* ctab->version_string[0] != 0:
967 : : read until M END line was encountered */
968 : :
969 : 131 : p = inchi_fgetsLf( line, line_len, inp_file );
970 : : /* djb-rwth: addressing coverity ID #499577 -- TREAT_ERR properly used in all cases */
971 [ - + ]: 131 : if (!p)
972 : : {
973 [ # # ]: 0 : if (!err)
974 : : {
975 [ # # ]: 0 : TREAT_ERR( err, 2, "Cannot read properties block line" );
976 : : }
977 : 0 : goto err_fin;
978 : : }
979 : :
980 : 131 : remove_one_lf( line );
981 : :
982 [ - + ]: 131 : if (line[MOL_FMT_MAXLINELEN])
983 : : {
984 [ # # ]: 0 : TREAT_ERR( err, 3, "Too long properties block line" );
985 : 0 : continue;
986 : : }
987 : :
988 [ - + ]: 131 : if (skip_lines > 0)
989 : : {
990 : 0 : skip_lines--;
991 : 0 : continue;
992 : : }
993 : :
994 : : /* alias */
995 [ - + - - ]: 131 : if (nMultiLineMode == MULTI_LINE_MODE_ISIS_ALIAS && nAtomNumber)
996 : 0 : {
997 : : int len;
998 : :
999 : 0 : nMultiLineMode = MULTI_LINE_MODE_NO_MODE;
1000 [ # # ]: 0 : if (0 >= ( len = normalize_string( p ) ))
1001 : : {
1002 : 0 : nAtomNumber = 0;
1003 : 0 : continue;
1004 : : }
1005 : :
1006 [ # # # # ]: 0 : if (0 < len && len < (int) ( sizeof( ctab->atoms->symbol ) ))
1007 : : {
1008 : : int nCharge, nRad;
1009 : :
1010 : 0 : MOL_FMT_ATOM* atom = ctab->atoms + nAtomNumber - 1;
1011 : : /* ctab->atoms[nAtomNumber-1].atom_aliased_flag = 1; */
1012 : : /* extract radicals & charges */
1013 : :
1014 : 0 : extract_charges_and_radicals( p, &nRad, &nCharge );
1015 : :
1016 : : /* Aliased atom cannot have charge, radical & mass difference */
1017 : : /* in the atom table or "M CHG", "M RAD", "M ISO" */
1018 : : /* if ( nCharge ) */
1019 : 0 : atom->charge = (S_CHAR) nCharge;
1020 : : /* if ( nRad ) */
1021 : 0 : atom->radical = (char) nRad;
1022 : :
1023 [ # # # # ]: 0 : if (1 == len && 'D' == p[0])
1024 : : {
1025 : : /* H isotope */
1026 : 0 : p[0] = 'H';
1027 : 0 : atom->mass_difference = 1;
1028 : : }
1029 : : else
1030 : : {
1031 [ # # # # ]: 0 : if (1 == len && 'T' == p[0])
1032 : : {
1033 : : /* H isotope */
1034 : :
1035 : 0 : p[0] = 'H';
1036 : 0 : atom->mass_difference = 2;
1037 : : }
1038 : : else
1039 : : {
1040 : 0 : atom->mass_difference = 0;
1041 : : }
1042 : : }
1043 [ # # ]: 0 : if (strlen( p ) < sizeof( ctab->atoms[0].symbol ))
1044 : : {
1045 : 0 : strcpy(atom->symbol, p);
1046 : : }
1047 : : else
1048 : : {
1049 : 0 : strcpy(atom->symbol, "???");
1050 : : }
1051 : 0 : atom->atom_aliased_flag++;
1052 : : }
1053 : : /* else if( 0 < len )
1054 : : {
1055 : : ^^^ Just too long alias name.
1056 : : For consistency with parsing {H,D,T}-containing alias names, this
1057 : : would result in issuing error rather than ignoring... However,
1058 : : for compatibility reasons, the 'ignore' behavior remained intact.
1059 : : }
1060 : : */
1061 : :
1062 : 0 : skip_lines = 0;
1063 : 0 : nAtomNumber = 0;
1064 : 0 : continue;
1065 : : }
1066 : :
1067 [ + - ]: 131 : if (1 != MolfileReadField( charM, sizeof( charM ) - 1, MOL_FMT_STRING_DATA, &p )
1068 [ + - ]: 131 : || 0 != MolfileReadField( szBlank, sizeof( szBlank ) - 1, MOL_FMT_STRING_DATA, &p ) /* must contain 0 bytes */
1069 [ - + ]: 131 : || 0 >= MolfileReadField( szType, sizeof( szType ) - 1, MOL_FMT_STRING_DATA, &p ) /* must contain 3 bytes */
1070 : : )
1071 : : {
1072 [ # # ]: 0 : if (!strcmp( line, SD_FMT_END_OF_DATA ))
1073 : : {
1074 [ # # ]: 0 : err = err ? -abs( err ) : -4;
1075 : 0 : break;
1076 : : }
1077 : 0 : continue; /* ignore because cannot recognize */
1078 : : }
1079 : :
1080 [ - + ]: 131 : if (charM[0] == 'V')
1081 : : {
1082 : 0 : skip_lines = 0; /* ISIS/Desktop Atom Value: one-line property */
1083 : 0 : continue;
1084 : : }
1085 : :
1086 [ - + ]: 131 : if (charM[0] == 'G')
1087 : : {
1088 : 0 : skip_lines = 1; /* ISIS/Desktop Group abbreviation: two-line property */
1089 : 0 : continue;
1090 : : }
1091 : :
1092 [ - + ]: 131 : if (charM[0] == 'A')
1093 : : {
1094 [ # # ]: 0 : if (NULL != ctab->atoms &&
1095 [ # # ]: 0 : 0 < ( nAtomNumber = (int) strtol( szType, NULL, 10 ) ) &&
1096 [ # # ]: 0 : nAtomNumber <= ctab->n_atoms)
1097 : : {
1098 : : /* Atom Alias [ISIS/Desktop] two-line property */
1099 : 0 : nMultiLineMode = MULTI_LINE_MODE_ISIS_ALIAS;
1100 : 0 : continue;
1101 : : }
1102 : : else
1103 : : {
1104 : 0 : nAtomNumber = 0;
1105 : 0 : skip_lines = 1;
1106 : 0 : continue;
1107 : : }
1108 : : }
1109 : :
1110 [ - + - - ]: 131 : if (charM[0] == 'S' && !strcmp( szType, "SKP" ))
1111 : : { /* skip lines */
1112 [ # # ]: 0 : if (0 >= MolfileReadField( &skip_lines, 3, MOL_FMT_SHORT_INT_DATA, &p ))
1113 : : {
1114 : 0 : skip_lines = 0;
1115 : : }
1116 : 0 : continue;
1117 : : }
1118 : :
1119 [ - + ]: 131 : if (charM[0] != 'M')
1120 : : {
1121 : : /* cannot recognize a line */
1122 : 0 : continue;
1123 : : }
1124 : :
1125 [ - + ]: 131 : if (!strcmp( szType, "REG" ))
1126 : 0 : {
1127 : : int len;
1128 : 0 : p = p + strspn( p, " " );
1129 : 0 : len = strcspn( p, " " );
1130 : 0 : len = inchi_min( len, MOL_FMT_MAX_VALUE_LEN );
1131 : 0 : MolfileReadField( &pHdr->internal_regno, len, MOL_FMT_LONG_INT_DATA, &p );
1132 : 0 : continue;
1133 : : }
1134 : :
1135 [ + + ]: 131 : if (!strcmp( szType, "END" ))
1136 : : {
1137 [ + - ]: 121 : if (ctab->version_string[0])
1138 : : {
1139 : 121 : break; /* end of property lines */
1140 : : }
1141 : 0 : continue;
1142 : : }
1143 : :
1144 [ - + ]: 10 : if (NULL == ctab->atoms)
1145 : : {
1146 : 0 : continue; /* ignore because the user requested to bypass all this stuff */
1147 : : }
1148 : :
1149 : : /* Charge: Generic */
1150 [ + + + - ]: 12 : if (!strcmp( szType, "CHG" ) &&
1151 : 2 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1152 [ + - + - ]: 2 : 1 <= num_entries && num_entries <= 8)
1153 : 2 : {
1154 : :
1155 : : S_SHORT atoms[8];
1156 : : S_SHORT charges[8];
1157 : :
1158 [ + - + - ]: 2 : if (!charge_encountered && !radical_encountered)
1159 : : {
1160 : : /* first charge or radical record clears all Atom Block */
1161 : : /* entered charge and radical data to zeroes */
1162 : 2 : charge_encountered = -1;
1163 : : }
1164 [ + + ]: 6 : for (j = 0; j < num_entries; j++)
1165 : : {
1166 [ + - + - ]: 8 : if (0 > MolfileReadField( &atoms[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1167 : 4 : 0 > MolfileReadField( &charges[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1168 [ + - + - ]: 4 : atoms[j] <= 0 || atoms[j] > num_atoms ||
1169 [ + - - + ]: 4 : charges[j] < -15 || charges[j] > 15)
1170 : : {
1171 : 0 : goto charge_error;
1172 : : }
1173 : : }
1174 [ + - ]: 2 : if (charge_encountered == -1)
1175 : : {
1176 [ + + ]: 6 : for (j = 0; j < num_atoms; j++)
1177 : : {
1178 [ + - ]: 4 : if (!ctab->atoms[j].atom_aliased_flag) /* do not clear aliased atoms.*/
1179 : : {
1180 : 4 : ctab->atoms[j].charge = ctab->atoms[j].radical = '\0';
1181 : : }
1182 : : }
1183 : 2 : charge_encountered = 1;
1184 : : }
1185 [ + + ]: 6 : for (j = 0; j < num_entries; j++)
1186 : : {
1187 [ + - ]: 4 : if (!ctab->atoms[atoms[j] - 1].atom_aliased_flag) /* do not change aliased atoms.*/
1188 : : {
1189 : 4 : ctab->atoms[atoms[j] - 1].charge = (S_CHAR) charges[j];
1190 : : }
1191 : : }
1192 : 2 : continue;
1193 : 0 : charge_error:
1194 : 0 : TREAT_ERR( err, 0, "Charge not recognized:" );
1195 : 0 : dotify_non_printable_chars( line );
1196 : 0 : AddErrorMessage( pStrErr, line );
1197 : 0 : continue; /* ignore for now */
1198 : : }
1199 : :
1200 : : /* Radical: Generic */
1201 [ - + - - ]: 8 : if (!strcmp( szType, "RAD" ) &&
1202 : 0 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1203 [ # # # # ]: 0 : 1 <= num_entries && num_entries <= 8)
1204 : 0 : {
1205 : :
1206 : : S_SHORT atoms[8];
1207 : : S_SHORT radicals[8];
1208 : :
1209 [ # # # # ]: 0 : if (!charge_encountered && !radical_encountered)
1210 : : {
1211 : : /* first charge or radical record clears all Atom Block */
1212 : : /* entered charge and radical data to zeroes */
1213 : 0 : radical_encountered = -1;
1214 : : }
1215 [ # # ]: 0 : for (j = 0; j < num_entries; j++)
1216 : : {
1217 [ # # # # ]: 0 : if (0 > MolfileReadField( &atoms[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1218 : 0 : 0 > MolfileReadField( &radicals[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1219 [ # # # # ]: 0 : atoms[j] <= 0 || atoms[j] > num_atoms ||
1220 [ # # # # ]: 0 : radicals[j] < 0 || radicals[j] > 3)
1221 : : {
1222 : 0 : goto radical_error;
1223 : : }
1224 : : }
1225 [ # # ]: 0 : if (radical_encountered == -1)
1226 : : {
1227 [ # # ]: 0 : for (j = 0; j < num_atoms; j++)
1228 : : {
1229 [ # # ]: 0 : if (!ctab->atoms[j].atom_aliased_flag) /* do not clear aliased atoms. 5-3-99 DCh */
1230 : 0 : ctab->atoms[j].charge = ctab->atoms[j].radical = '\0';
1231 : : }
1232 : 0 : radical_encountered = 1;
1233 : : }
1234 [ # # ]: 0 : for (j = 0; j < num_entries; j++)
1235 : : {
1236 [ # # ]: 0 : if (!ctab->atoms[atoms[j] - 1].atom_aliased_flag)
1237 : : {
1238 : : /* do not change aliased atoms. 5-3-99 DCh */
1239 : 0 : ctab->atoms[atoms[j] - 1].radical = (S_CHAR) radicals[j];
1240 : : }
1241 : : }
1242 : 0 : continue;
1243 : 0 : radical_error:
1244 : 0 : TREAT_ERR( err, 0, "Radical not recognized:" );
1245 : 0 : dotify_non_printable_chars( line );
1246 : 0 : AddErrorMessage( pStrErr, line );
1247 : 0 : continue; /* ignore error for now */
1248 : : }
1249 : :
1250 : : /* Isotope: Generic */
1251 [ - + - - ]: 8 : if (!strcmp( szType, "ISO" ) &&
1252 : 0 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1253 [ # # # # ]: 0 : 1 <= num_entries && num_entries <= 8)
1254 : 0 : {
1255 : :
1256 : : S_SHORT atoms[8];
1257 : : S_SHORT iso_mass[8]; /* contains istotope mass number, not difference. 7-14-00 DCh. */
1258 : :
1259 [ # # ]: 0 : if (!isotope_encountered)
1260 : : {
1261 : : /* first charge or radical record clears all Atom Block */
1262 : : /* entered charge and radical data to zeroes */
1263 : 0 : isotope_encountered = -1;
1264 : : }
1265 [ # # ]: 0 : for (j = 0; j < num_entries; j++)
1266 : : {
1267 [ # # # # ]: 0 : if (0 > MolfileReadField( &atoms[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1268 : 0 : 0 > MolfileReadField( &iso_mass[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1269 [ # # # # ]: 0 : atoms[j] <= 0 || atoms[j] > num_atoms
1270 : : /*|| iso_mass[j] < -18 || iso_mass[j] > 12*/)
1271 : : {
1272 : : /* goto isotope_error; */
1273 : 0 : atoms[j] = -1; /* flag error */
1274 : 0 : TREAT_ERR( err, 0, "Isotopic data not recognized:" );
1275 : 0 : dotify_non_printable_chars( line );
1276 : 0 : AddErrorMessage( pStrErr, line );
1277 : 0 : continue; /* ignore isotopic error for now */
1278 : : }
1279 : : }
1280 : :
1281 [ # # ]: 0 : if (isotope_encountered == -1)
1282 : : {
1283 [ # # ]: 0 : for (j = 0; j < num_atoms; j++)
1284 : : {
1285 : : /*if ( !ctab->atoms[j].atom_aliased_flag )*/ /* clear even aliased atoms */
1286 : 0 : ctab->atoms[j].mass_difference = 0;
1287 : : }
1288 : 0 : isotope_encountered = 1;
1289 : : }
1290 [ # # ]: 0 : for (j = 0; j < num_entries; j++)
1291 : : {
1292 [ # # ]: 0 : if (atoms[j] <= 0)
1293 : : {
1294 : 0 : continue; /* ignore isotopic error for now */
1295 : : }
1296 : :
1297 : : if (1 /* !ctab->atoms[atoms[j]-1].atom_aliased_flag */)
1298 : : {
1299 : 0 : char *at = ctab->atoms[atoms[j] - 1].symbol;
1300 [ # # # # : 0 : if (at[1] || (at[0] != 'D' && at[0] != 'T')) /* djb-rwth: addressing LLVM warning */
# # ]
1301 : : { /* D & T cannot have ISO */
1302 : : /* need atomic weight to calculate isotope difference. 7-14-00 DCh. */
1303 : :
1304 : : int atw, atw_diff;
1305 : : /*
1306 : : NB: According to CTFile specification, difference should be in
1307 : : [-18; +12] range, not in [-19; +19] as is checked below. */
1308 [ # # # # ]: 0 : if (( atw = get_atomic_mass( at ) ) && abs( atw_diff = (int) iso_mass[j] - atw ) < 20)
1309 : : {
1310 [ # # ]: 0 : ctab->atoms[atoms[j] - 1].mass_difference = (char) ( atw_diff ? atw_diff : ZERO_ATW_DIFF );
1311 : : }
1312 : : }
1313 : : }
1314 : : }
1315 : 0 : continue;
1316 : : }
1317 : :
1318 : : /* Sgroup, polymeric */
1319 [ + + ]: 8 : if ( !strcmp( szType, "STY" ) ||
1320 [ + - ]: 7 : !strcmp( szType, "SST" ) ||
1321 [ + + ]: 7 : !strcmp( szType, "SLB" ) ||
1322 [ + + ]: 6 : !strcmp( szType, "SCN" ) ||
1323 [ + + ]: 5 : !strcmp( szType, "SAL" ) ||
1324 [ + + ]: 4 : !strcmp( szType, "SBL" ) ||
1325 [ + + ]: 3 : !strcmp( szType, "SDI" ) ||
1326 [ - + ]: 1 : !strcmp( szType, "SMT" ) ||
1327 [ # # ]: 0 : !strcmp( szType, "SBT" ))
1328 : : {
1329 : : int result;
1330 [ - + ]: 8 : if (!treat_polymers)
1331 : : {
1332 : 0 : polymer_occurred = 1;
1333 : 0 : continue;
1334 : : }
1335 : 8 : result = MolfileReadSgroupOfPolymer( ctab, pHdr, inp_file, line, szType, p, err, pStrErr );
1336 [ - + ]: 8 : if (result != 0)
1337 : : {
1338 [ # # # # ]: 0 : TREAT_ERR( err, result, "Could not interpret Molfile polymer data:" );
1339 : 0 : dotify_non_printable_chars( line );
1340 : 0 : AddErrorMessage( pStrErr, line );
1341 : 0 : continue;
1342 : : }
1343 : : }
1344 : : }
1345 : :
1346 : 0 : err_fin:
1347 [ + + - + ]: 121 : if (!treat_polymers && polymer_occurred)
1348 : : {
1349 : : /* for compatibility reasons, inchi-1 by default
1350 : : ignores polymer related lines (as v. 1.04 did) */
1351 [ # # ]: 0 : if (!bNoWarnings)
1352 : : {
1353 : 0 : WarningMessage( pStrErr, "Ignore polymer data" );
1354 : : }
1355 : : }
1356 : :
1357 [ + + - + ]: 121 : if (( ctab->sgroups.used > 0 ) && ( debug_polymers > 1 ))
1358 : : {
1359 : : ITRACE_( "\n* THE FOLLOWING %-d POLYMER SGROUP(S) WERE RECOGNISED *\n", ctab->sgroups.used );
1360 [ # # ]: 0 : for (i = 0; i < ctab->sgroups.used; i++)
1361 : : {
1362 : 0 : char *sty[] = { "NON", "SRU", "MON", "COP", "MOD", "XL", "MER" };
1363 : 0 : char *sst[] = { "NON", "ALT", "RAN", "BLK" };
1364 : 0 : char *con[] = { "NON", "HT", "HH", "EU" };
1365 : :
1366 : : ITRACE_( "\n* GROUP %-d\n", i );
1367 : : ITRACE_( "* \tindex=%-d\n", ctab->sgroups.group[i]->id );
1368 : : ITRACE_( "* \ttype=%-d %-s\n", ctab->sgroups.group[i]->type, sty[ctab->sgroups.group[i]->type] );
1369 : 0 : if (ctab->sgroups.group[i]->subtype > -1)
1370 : : ITRACE_( "* \tsubtype=%-d %-s\n", ctab->sgroups.group[i]->subtype, sst[ctab->sgroups.group[i]->subtype] );
1371 : 0 : if (ctab->sgroups.group[i]->conn)
1372 : : ITRACE_( "* \tconnection_type=%-d %-s\n", ctab->sgroups.group[i]->conn,
1373 : : con[ctab->sgroups.group[i]->conn] );
1374 : : ITRACE_( "* \tlabel=%-d\n", ctab->sgroups.group[i]->label );
1375 : : ITRACE_( "* \t%-d atoms:\t", ctab->sgroups.group[i]->alist.used );
1376 : 0 : IntArray_DebugPrint( &( ctab->sgroups.group[i]->alist ) );
1377 : : ITRACE_( "* \t%-d bonds:\t", ctab->sgroups.group[i]->blist.used );
1378 : 0 : IntArray_DebugPrint( &( ctab->sgroups.group[i]->blist ) );
1379 : : ITRACE_( "\n" );
1380 : : }
1381 : : }
1382 : :
1383 : 121 : return err;
1384 : : }
1385 : :
1386 : :
1387 : : /****************************************************************************
1388 : : Parse polymer SGroups of Molfile
1389 : : ****************************************************************************/
1390 : 8 : int MolfileReadSgroupOfPolymer( MOL_FMT_CTAB* ctab,
1391 : : MOL_FMT_HEADER_BLOCK *pHdr,
1392 : : INCHI_IOSTREAM *inp_file,
1393 : : char line[MOL_FMT_INPLINELEN],
1394 : : char *szType,
1395 : : char *p,
1396 : : int err,
1397 : : char *pStrErr )
1398 : : {
1399 : : S_SHORT num_entries;
1400 : 8 : S_SHORT num_atoms = ctab->n_atoms;
1401 : 8 : S_SHORT num_bonds = ctab->n_bonds;
1402 : 8 : int j, index = -1, ret;
1403 : : char stmp[4], stmplong[81];
1404 : 8 : S_SHORT sg_nums[8], sg_num = -1, sg_atoms[15], sg_bonds[15], tmp;
1405 : 8 : int q, fail = 0, len;
1406 : : /* djb-rwth: removing redundant variables */
1407 : : #if ( DEBUG_POLYMERS == 1 )
1408 : : debug_polymers = 1;
1409 : : #elif ( DEBUG_POLYMERS == 2 )
1410 : : debug_polymers = 2;
1411 : : #endif
1412 : : /* djb-rwth: removing redundant code */
1413 : :
1414 : : /* Check for possible lead codes */
1415 : :
1416 : : /* STY - Sgroup type
1417 : : Polymer-related recognized types are:
1418 : : SRU = SRU type,
1419 : : MON = monomer,
1420 : : COP = copolymer,
1421 : : MER = Mer type,
1422 : : MOD
1423 : : CRO
1424 : : */
1425 [ + + ]: 9 : if ( !strcmp( szType, "STY" )
1426 [ + - ]: 1 : && 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p )
1427 [ + - + - ]: 1 : && 1 <= num_entries && num_entries <= 8 )
1428 : : {
1429 [ + + ]: 2 : for (j = 0; j < num_entries; j++)
1430 : : {
1431 [ + - - + ]: 2 : fail = 0 > MolfileReadField( &sg_nums[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1432 : 1 : 0 > MolfileReadField( stmp, 4, MOL_FMT_STRING_DATA, &p );
1433 [ + - ]: 1 : if (!fail)
1434 : : {
1435 : 1 : int type = MOL_FMT_M_STY_NON;
1436 : :
1437 : 1 : lrtrim( stmp, &len );
1438 : :
1439 [ + - ]: 1 : if (!strcmp( stmp, "SRU" ))
1440 : : {
1441 : 1 : type = MOL_FMT_M_STY_SRU;
1442 : : }
1443 [ # # ]: 0 : else if (!strcmp( stmp, "MON" ))
1444 : : {
1445 : 0 : type = MOL_FMT_M_STY_MON;
1446 : : }
1447 [ # # ]: 0 : else if (!strcmp( stmp, "COP" ))
1448 : : {
1449 : 0 : type = MOL_FMT_M_STY_COP;
1450 : : }
1451 [ # # ]: 0 : else if (!strcmp( stmp, "MOD" ))
1452 : : {
1453 : 0 : type = MOL_FMT_M_STY_MOD;
1454 : : }
1455 [ # # ]: 0 : else if (!strcmp( stmp, "CRO" ))
1456 : : {
1457 : 0 : type = MOL_FMT_M_STY_CRO;
1458 : : }
1459 [ # # ]: 0 : else if (!strcmp( stmp, "MER" ))
1460 : : {
1461 : 0 : type = MOL_FMT_M_STY_MER;
1462 : : }
1463 : : else
1464 : : {
1465 : 0 : fail = 1;
1466 : : }
1467 [ + - ]: 1 : if (!fail)
1468 : : {
1469 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_nums[j], &( ctab->sgroups ) );
1470 [ + - ]: 1 : if (-1 == index)
1471 : : {
1472 : 1 : ret = MolFmtSgroups_Append( &ctab->sgroups, sg_nums[j], type );
1473 [ - + ]: 1 : if (0 != ret)
1474 : 0 : fail = 1;
1475 : : else
1476 : 1 : index = ctab->sgroups.used - 1;
1477 : : }
1478 : : else
1479 : : {
1480 : 0 : ctab->sgroups.group[index]->type = type;
1481 : : }
1482 [ + - ]: 1 : if (!fail)
1483 : : {
1484 [ + + ]: 5 : for (q = 0; q < 4; q++)
1485 : : {
1486 : 4 : ctab->sgroups.group[index]->xbr1[q] = -777777.777;
1487 : 4 : ctab->sgroups.group[index]->xbr2[q] = -777777.777;
1488 : : }
1489 : 1 : ctab->sgroups.group[index]->smt[0] = '\0';
1490 : : }
1491 : : }
1492 : : }
1493 [ - + ]: 1 : if (fail)
1494 : : {
1495 : 0 : err = 5;
1496 : 0 : goto err_exit;
1497 : : }
1498 : : }
1499 : : }
1500 : : /*
1501 : : SST - Polymer Sgroup subtypes:
1502 : : ALT = alternating,
1503 : : RAN = random,
1504 : : BLK = block
1505 : : */
1506 [ - + - - ]: 7 : else if (!strcmp( szType, "SST" ) &&
1507 : 0 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1508 [ # # # # ]: 0 : 1 <= num_entries && num_entries <= 8)
1509 : : {
1510 [ # # ]: 0 : for (j = 0; j < num_entries; j++)
1511 : : {
1512 [ # # # # ]: 0 : fail = 0 > MolfileReadField( &sg_nums[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1513 : 0 : 0 > MolfileReadField( stmp, 4, MOL_FMT_STRING_DATA, &p );
1514 [ # # ]: 0 : if (!fail)
1515 : : {
1516 : 0 : index = MolFmtSgroups_GetIndexBySgroupId( sg_nums[j], &( ctab->sgroups ) );
1517 [ # # ]: 0 : if (-1 == index)
1518 : : {
1519 : 0 : fail = 1;
1520 : : }
1521 : : }
1522 [ # # ]: 0 : if (!fail)
1523 : : {
1524 : 0 : ctab->sgroups.group[index]->subtype = MOL_FMT_M_SST_NON;
1525 : 0 : lrtrim( stmp, &len );
1526 [ # # ]: 0 : if (!strcmp( stmp, "ALT" ))
1527 : : {
1528 : 0 : ctab->sgroups.group[index]->subtype = MOL_FMT_M_SST_ALT;
1529 : : }
1530 [ # # ]: 0 : else if (!strcmp( stmp, "RAN" ))
1531 : : {
1532 : 0 : ctab->sgroups.group[index]->subtype = MOL_FMT_M_SST_RAN;
1533 : : }
1534 [ # # ]: 0 : else if (!strcmp( stmp, "BLO" ))
1535 : : {
1536 : 0 : ctab->sgroups.group[index]->subtype = MOL_FMT_M_SST_BLK;
1537 : : }
1538 [ # # ]: 0 : else if (!strcmp( stmp, "BLK" ))
1539 : : {
1540 : 0 : ctab->sgroups.group[index]->subtype = MOL_FMT_M_SST_BLK;
1541 : : }
1542 : : else
1543 : : {
1544 : 0 : fail = 1;
1545 : 0 : break;
1546 : : }
1547 : : }
1548 : : }
1549 [ # # ]: 0 : if (fail)
1550 : : {
1551 : 0 : err = 6;
1552 : 0 : goto err_exit;
1553 : : }
1554 : : }
1555 : : /* SLB - Sgroup Labels */
1556 [ + + + - ]: 8 : else if (!strcmp( szType, "SLB" ) &&
1557 : 1 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1558 [ + - + - ]: 1 : 1 <= num_entries && num_entries <= 8)
1559 : : {
1560 [ + + ]: 2 : for (j = 0; j < num_entries; j++)
1561 : : {
1562 : 1 : fail = 0 > MolfileReadField( &sg_nums[j], 0, MOL_FMT_SHORT_INT_DATA, &p )
1563 [ + - - + ]: 1 : || 0 > MolfileReadField( &tmp, 0, MOL_FMT_SHORT_INT_DATA, &p );
1564 [ + - ]: 1 : if (!fail)
1565 : : {
1566 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_nums[j], &( ctab->sgroups ) );
1567 [ - + ]: 1 : if (-1 == index)
1568 : : {
1569 : 0 : fail = 1;
1570 : : }
1571 : : }
1572 [ + - ]: 1 : if (!fail)
1573 : : {
1574 : 1 : ctab->sgroups.group[index]->label = tmp;
1575 : : }
1576 : : }
1577 [ - + ]: 1 : if (fail)
1578 : : {
1579 : 0 : err = 7;
1580 : 0 : goto err_exit;
1581 : : }
1582 : : }
1583 : : /* SCN - Sgroup Connectivity
1584 : : HH = head-to-head,
1585 : : HT = head-to-tail,
1586 : : EU = either unknown.
1587 : : Left justified.
1588 : : */
1589 [ + + + - ]: 8 : else if (!strcmp( szType, "SCN" ) &&
1590 : 1 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ) &&
1591 [ + - + - ]: 1 : 1 <= num_entries && num_entries <= 8)
1592 : : {
1593 [ + + ]: 2 : for (j = 0; j < num_entries; j++)
1594 : : {
1595 : 1 : fail = 0 > MolfileReadField( &sg_nums[j], 0, MOL_FMT_SHORT_INT_DATA, &p )
1596 [ + - - + ]: 1 : || 0 > MolfileReadField( stmp, 4, MOL_FMT_STRING_DATA, &p );
1597 [ + - ]: 1 : if (!fail)
1598 : : {
1599 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_nums[j], &( ctab->sgroups ) );
1600 [ - + ]: 1 : if (-1 == index)
1601 : : {
1602 : 0 : fail = 1;
1603 : : }
1604 : : }
1605 [ + - ]: 1 : if (!fail)
1606 : : {
1607 : 1 : ctab->sgroups.group[index]->conn = MOL_FMT_M_CONN_NON;
1608 : 1 : lrtrim( stmp, &len );
1609 [ + - ]: 1 : if (!strcmp( stmp, "HT" ))
1610 : : {
1611 : 1 : ctab->sgroups.group[index]->conn = MOL_FMT_M_CONN_HT;
1612 : : }
1613 [ # # ]: 0 : else if (!strcmp( stmp, "HH" ))
1614 : : {
1615 : 0 : ctab->sgroups.group[index]->conn = MOL_FMT_M_CONN_HH;
1616 : : }
1617 [ # # ]: 0 : else if (!strcmp( stmp, "EU" ))
1618 : : {
1619 : 0 : ctab->sgroups.group[index]->conn = MOL_FMT_M_CONN_EU;
1620 : : }
1621 : : else
1622 : : {
1623 : 0 : fail = 1; /* NB: we do not allow explicit different abbreviation - but note that */
1624 : : /* totally skipping SCN line is allowed ("EU" will be inserted further) */
1625 : : }
1626 : : }
1627 [ - + ]: 1 : if (fail)
1628 : : {
1629 : 0 : err = 8;
1630 : 0 : goto err_exit;
1631 : : }
1632 : : }
1633 : : }
1634 : : /* SAL - Sgroup atoms list */
1635 [ + + ]: 5 : else if (!strcmp( szType, "SAL" ))
1636 : : {
1637 [ + - + - ]: 2 : if (0 < MolfileReadField( &sg_num, 4, MOL_FMT_SHORT_INT_DATA, &p ) &&
1638 : 1 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ))
1639 : : {
1640 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_num, &( ctab->sgroups ) );
1641 [ - + ]: 1 : if (-1 == index)
1642 : : {
1643 : 0 : fail = 1;
1644 : : }
1645 [ + - ]: 1 : if (!fail)
1646 : : {
1647 [ + + ]: 4 : for (j = 0; j < num_entries; j++)
1648 : : {
1649 [ + - ]: 3 : if (0 > MolfileReadField( &sg_atoms[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1650 [ + - - + ]: 3 : sg_atoms[j] <= 0 || sg_atoms[j] > num_atoms)
1651 : : {
1652 : 0 : fail = 1;
1653 : 0 : break;
1654 : : }
1655 : : }
1656 : : }
1657 [ + - ]: 1 : if (!fail)
1658 : : {
1659 [ + + ]: 4 : for (j = 0; j < num_entries; j++)
1660 : : {
1661 [ - + ]: 3 : if (0 != IntArray_Append( &( ctab->sgroups.group[index]->alist ), sg_atoms[j] ))
1662 : : {
1663 : 0 : fail = 1;
1664 : 0 : break;
1665 : : }
1666 : : }
1667 : : }
1668 : : }
1669 : : else
1670 : : {
1671 : 0 : fail = 1;
1672 : : }
1673 [ - + ]: 1 : if (fail)
1674 : : {
1675 : 0 : err = 9;
1676 : 0 : goto err_exit;
1677 : : }
1678 : : }
1679 : : /* SBL - Sgroup bonds list */
1680 [ + + ]: 4 : else if (!strcmp( szType, "SBL" ))
1681 : : {
1682 [ + - + - ]: 2 : if (0 < MolfileReadField( &sg_num, 4, MOL_FMT_SHORT_INT_DATA, &p ) &&
1683 : 1 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ))
1684 : : {
1685 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_num, &( ctab->sgroups ) );
1686 [ - + ]: 1 : if (-1 == index)
1687 : : {
1688 : 0 : fail = 1;
1689 : : }
1690 [ + - ]: 1 : if (!fail)
1691 : : {
1692 [ + + ]: 3 : for (j = 0; j < num_entries; j++)
1693 : : {
1694 [ + - ]: 2 : if (0 > MolfileReadField( &sg_bonds[j], 0, MOL_FMT_SHORT_INT_DATA, &p ) ||
1695 [ + - - + ]: 2 : sg_bonds[j] <= 0 || sg_bonds[j] > num_bonds)
1696 : : {
1697 : 0 : fail = 1;
1698 : 0 : break;
1699 : : }
1700 : : }
1701 : : }
1702 [ + - ]: 1 : if (!fail)
1703 : : {
1704 [ + + ]: 3 : for (j = 0; j < num_entries; j++)
1705 : : {
1706 [ - + ]: 2 : if (0 != IntArray_Append( &( ctab->sgroups.group[index]->blist ), sg_bonds[j] ))
1707 : : {
1708 : 0 : fail = 1;
1709 : 0 : break;
1710 : : }
1711 : : }
1712 : : }
1713 : : }
1714 : : else
1715 : : {
1716 : 0 : fail = 1;
1717 : : }
1718 [ - + ]: 1 : if (fail)
1719 : : {
1720 : 0 : err = 10;
1721 : 0 : goto err_exit;
1722 : : }
1723 : : }
1724 : : /* SDI */
1725 [ + + ]: 3 : else if (!strcmp( szType, "SDI" ))
1726 : : {
1727 : : double x[4];
1728 : :
1729 [ + - + - ]: 4 : if (0 < MolfileReadField( &sg_num, 4, MOL_FMT_SHORT_INT_DATA, &p ) &&
1730 : 2 : 0 < MolfileReadField( &num_entries, 3, MOL_FMT_SHORT_INT_DATA, &p ))
1731 : : {
1732 : 2 : index = MolFmtSgroups_GetIndexBySgroupId( sg_num, &( ctab->sgroups ) );
1733 [ - + ]: 2 : if (-1 == index)
1734 : : {
1735 : 0 : fail = 1;
1736 : : }
1737 [ - + ]: 2 : else if (num_entries != 4)
1738 : : {
1739 : 0 : fail = 1;
1740 : : }
1741 [ + - ]: 2 : if (!fail)
1742 : : {
1743 [ + + ]: 10 : for (j = 0; j < num_entries; j++)
1744 : : {
1745 [ - + ]: 8 : if (0 > MolfileReadField( &x[j], 0, MOL_FMT_DOUBLE_DATA, &p ))
1746 : : {
1747 : 0 : fail = 1;
1748 : 0 : break;
1749 : : }
1750 : : }
1751 : : }
1752 [ + - ]: 2 : if (!fail)
1753 : : {
1754 [ + + ]: 2 : if (fabs( -fabs( ctab->sgroups.group[index]->xbr1[0] ) + 777777.777 ) < 1.e-7) /* brkt1 coords not yet here */
1755 : : {
1756 [ + + ]: 5 : for (q = 0; q < 4; q++)
1757 : : {
1758 : 4 : ctab->sgroups.group[index]->xbr1[q] = x[q];
1759 : : }
1760 : : }
1761 : : else
1762 : : {
1763 [ + + ]: 5 : for (q = 0; q < 4; q++)
1764 : : {
1765 : 4 : ctab->sgroups.group[index]->xbr2[q] = x[q];
1766 : : }
1767 : : }
1768 : : }
1769 : : }
1770 : : else
1771 : : {
1772 : 0 : fail = 1;
1773 : : }
1774 [ - + ]: 2 : if (fail)
1775 : : {
1776 : 0 : err = 11;
1777 : 0 : goto err_exit;
1778 : : }
1779 : : }
1780 : : /* SMT - Sgroup Subscript */
1781 [ + - ]: 1 : else if (!strcmp( szType, "SMT" ))
1782 : : {
1783 : 1 : index = -1;
1784 [ + - + - ]: 2 : if (0 < MolfileReadField( &sg_num, 4, MOL_FMT_SHORT_INT_DATA, &p ) &&
1785 : 1 : 0 < MolfileReadField( stmplong, 80, MOL_FMT_STRING_DATA, &p ))
1786 : : {
1787 : 1 : index = MolFmtSgroups_GetIndexBySgroupId( sg_num, &( ctab->sgroups ) );
1788 : : }
1789 [ - + ]: 1 : if (-1 == index)
1790 : : {
1791 : 0 : fail = 1;
1792 : : }
1793 [ + - ]: 1 : if (!fail)
1794 : : {
1795 : 1 : lrtrim( stmplong, &len );
1796 : 1 : strcpy(ctab->sgroups.group[index]->smt, stmplong);
1797 : : }
1798 [ - + ]: 1 : if (fail)
1799 : : {
1800 : 0 : err = 11;
1801 : 0 : goto err_exit;
1802 : : }
1803 : : }
1804 : :
1805 : :
1806 : : ITRACE_( "\n" );
1807 : 8 : return 0;
1808 : :
1809 : 0 : err_exit:
1810 : 0 : MolFmtSgroups_Free( &ctab->sgroups );
1811 : :
1812 : 0 : return err; /* ignore polymeric error for now */
1813 : : }
1814 : :
1815 : :
1816 : : /****************************************************************************
1817 : :
1818 : : Pseudoelement treatment
1819 : :
1820 : : If allowed: "*" ===> "Zz"
1821 : :
1822 : : If disabled: fills err and pStrErr
1823 : :
1824 : : ****************************************************************************/
1825 : 121 : static int MolfileTreatPseudoElementAtoms( MOL_FMT_CTAB* ctab,
1826 : : int pseudos_allowed,
1827 : : int *err,
1828 : : char *pStrErr )
1829 : : {
1830 : 121 : int i, nzz = 0;
1831 : :
1832 : : /* djb-rwth: addressing coverity ID #499499 -- TREAT_ERR properly used in all cases */
1833 : :
1834 [ + + ]: 923 : for (i = 0; i < ctab->n_atoms; i++)
1835 : : {
1836 : 802 : int is_zz = 0, is_star = 0;
1837 : :
1838 : : /* Zy is specifically disabled */
1839 [ - + ]: 802 : if (!strcmp(ctab->atoms[i].symbol, "Zy"))
1840 : : {
1841 [ # # ]: 0 : TREAT_ERR( *err, ( 70 + 6 ), "Invalid element(s):" );
1842 [ # # ]: 0 : TREAT_ERR( *err, ( 70 + 6 ), ctab->atoms[i].symbol );
1843 : : }
1844 : :
1845 : 802 : is_star = !strcmp( ctab->atoms[i].symbol, "*" );
1846 [ + - ]: 802 : if (!is_star)
1847 : : {
1848 : 802 : is_zz = !strcmp( ctab->atoms[i].symbol, "Zz" );
1849 : : }
1850 : :
1851 [ + - - + ]: 802 : if (is_star || is_zz)
1852 : : {
1853 : 0 : nzz++;
1854 [ # # ]: 0 : if (0== pseudos_allowed)
1855 : : {
1856 : : /* Pseudoelements totally disabled */
1857 [ # # ]: 0 : TREAT_ERR( *err, ( 70 + 6 ), "Invalid element(s):" );
1858 [ # # ]: 0 : TREAT_ERR( *err, ( 70 + 6 ), ctab->atoms[i].symbol );
1859 : : }
1860 : : else
1861 : : {
1862 : : /* That's allowed, if it's star then convert to Zz */
1863 [ # # ]: 0 : if (is_star)
1864 : : {
1865 : 0 : mystrncpy( ctab->atoms[i].symbol, "Zz", sizeof( "Zz" ) );
1866 : : }
1867 : : }
1868 : : }
1869 : : }
1870 : :
1871 : 121 : return nzz;
1872 : : }
|