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