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 <string.h>
43 : : #include <math.h>
44 : :
45 : : #include "mode.h"
46 : : #include "mol_fmt.h"
47 : : #include "ichierr.h"
48 : : #include "util.h"
49 : : #include "strutil.h"
50 : : #include "inchi_api.h"
51 : :
52 : : #include "bcf_s.h"
53 : :
54 : : #include "logging.h" /*(@nnuk : Nauman Ullah Khan) :: Needed for logging functionality*/
55 : :
56 : : /*
57 : : Convert input molecular data to internal representation
58 : :
59 : : */
60 : :
61 : : /* Local prototypes */
62 : :
63 : : int ReadMolfileToInpAtoms(INCHI_IOSTREAM *inp_file,
64 : : int bDoNotAddH, inp_ATOM **at,
65 : : MOL_COORD **szCoord,
66 : : OAD_Polymer **polymer,
67 : : OAD_V3000 **v3000,
68 : : int treat_polymers,
69 : : int treat_NPZz,
70 : : int max_num_at,
71 : : int *num_dimensions,
72 : : int *num_bonds,
73 : : const char *pSdfLabel,
74 : : char *pSdfValue,
75 : : unsigned long *Id,
76 : : long *lMolfileNumber,
77 : : INCHI_MODE *pInpAtomFlags,
78 : : int *err,
79 : : char *pStrErr,
80 : : int bNoWarnings);
81 : : inp_ATOM *MakeInpAtomsFromMolfileData(MOL_FMT_DATA *mfdata,
82 : : int *num_atoms,
83 : : int *num_bonds,
84 : : inp_ATOM *at_inp,
85 : : int bDoNotAddH,
86 : : int *err,
87 : : char *pStrErr);
88 : : int SetInpAtomsXYZ(MOL_FMT_DATA *mfdata,
89 : : int num_atoms,
90 : : inp_ATOM *at,
91 : : int *err,
92 : : char *pStrErr);
93 : : void calculate_valences(MOL_FMT_DATA *mfdata,
94 : : inp_ATOM *at,
95 : : int *num_atoms,
96 : : int bDoNotAddH,
97 : : int *err,
98 : : char *pStrErr);
99 : :
100 : : int SetExtOrigAtDataByMolfileExtInput(MOL_FMT_DATA *mfdata,
101 : : OAD_Polymer **polymer,
102 : : OAD_V3000 **v3000,
103 : : char *pStrErr);
104 : :
105 : : /****************************************************************************
106 : : Create OrigInpData From Molfile
107 : : ****************************************************************************/
108 : 54 : int CreateOrigInpDataFromMolfile(INCHI_IOSTREAM *inp_file,
109 : : ORIG_ATOM_DATA *orig_at_data,
110 : : int bMergeAllInputStructures,
111 : : int bGetOrigCoord,
112 : : int bDoNotAddH,
113 : : int treat_polymers,
114 : : int treat_NPZz,
115 : : const char *pSdfLabel,
116 : : char *pSdfValue,
117 : : unsigned long *lSdfId,
118 : : long *lMolfileNumber,
119 : : INCHI_MODE *pInpAtomFlags,
120 : : int *err,
121 : : char *pStrErr,
122 : : int bNoWarnings)
123 : : {
124 : : int i, j, max_num_at;
125 : 54 : int num_dimensions_new = 0; /* djb-rwth: initialisation required to avoid garbage values */
126 : : int num_inp_bonds_new;
127 : : int num_inp_atoms_new;
128 : 54 : int nNumAtoms = 0;
129 : 54 : inp_ATOM *at_new = NULL;
130 : 54 : inp_ATOM *at_old = NULL;
131 : 54 : MOL_COORD *szCoordNew = NULL;
132 : 54 : MOL_COORD *szCoordOld = NULL;
133 : 54 : OAD_Polymer *polymer = NULL;
134 : 54 : OAD_V3000 *v3000 = NULL;
135 : :
136 [ + - ]: 54 : if (pStrErr)
137 : : {
138 : 54 : pStrErr[0] = '\0';
139 : : }
140 : :
141 : : /* NB: currently (v. 1.04) legacy CLI option "MERGE" is unsupported
142 : : so the loop below is always a single pass */
143 : 54 : max_num_at = MAX_ATOMS;
144 [ + - ]: 54 : if (!(*pInpAtomFlags & FLAG_SET_INP_LARGE_MOLS))
145 : : {
146 : 54 : max_num_at = NORMALLY_ALLOWED_INP_MAX_ATOMS;
147 : : }
148 : :
149 : : do /* while ( !*err && bMergeAllInputStructures ) */
150 : : {
151 : :
152 [ + - ]: 54 : at_old = orig_at_data ? orig_at_data->at : NULL; /* save pointer to the previous allocation */
153 : :
154 [ + - ]: 54 : szCoordOld = orig_at_data ? orig_at_data->szCoord : NULL;
155 : :
156 [ + - + - ]: 108 : num_inp_atoms_new = ReadMolfileToInpAtoms(inp_file, bDoNotAddH,
157 : : orig_at_data ? &at_new : NULL,
158 [ + - ]: 54 : (bGetOrigCoord && orig_at_data) ? &szCoordNew : NULL,
159 : : &polymer, &v3000,
160 : : treat_polymers, treat_NPZz,
161 : : max_num_at, &num_dimensions_new, &num_inp_bonds_new,
162 : : pSdfLabel, pSdfValue, lSdfId, lMolfileNumber,
163 : : pInpAtomFlags, err, pStrErr, bNoWarnings);
164 : :
165 [ - + - - ]: 54 : if (num_inp_atoms_new <= 0 && !*err)
166 : : {
167 : 0 : TREAT_ERR(*err, 0, "Empty structure");
168 : 0 : *err = 98;
169 : : }
170 [ + - - + ]: 54 : else if (orig_at_data && !num_inp_atoms_new &&
171 [ # # # # ]: 0 : 10 < *err && *err < 20 &&
172 [ # # # # ]: 0 : orig_at_data->num_inp_atoms > 0 &&
173 : : bMergeAllInputStructures)
174 : : {
175 : 0 : *err = 0; /* end of file */
176 : 0 : break;
177 : : }
178 [ + - + - ]: 54 : else if (num_inp_atoms_new > 0 && orig_at_data)
179 : : {
180 : : /* merge pOrigDataTmp + orig_at_data => pOrigDataTmp; */
181 : 54 : nNumAtoms = num_inp_atoms_new + orig_at_data->num_inp_atoms;
182 [ - + ]: 54 : if (nNumAtoms >= max_num_at) /*MAX_ATOMS ) */
183 : : {
184 : 0 : TREAT_ERR(*err, 0, "Too many atoms [did you forget 'LargeMolecules' switch?]");
185 : 0 : *err = 70;
186 : 0 : orig_at_data->num_inp_atoms = -1;
187 : : }
188 [ + - ]: 54 : else if (!at_old)
189 : : {
190 : : /* the first structure */
191 : 54 : orig_at_data->at = at_new;
192 : 54 : orig_at_data->szCoord = szCoordNew;
193 : 54 : at_new = NULL;
194 : 54 : szCoordNew = NULL;
195 : 54 : orig_at_data->num_inp_atoms = num_inp_atoms_new;
196 : 54 : orig_at_data->num_inp_bonds = num_inp_bonds_new;
197 : 54 : orig_at_data->num_dimensions = num_dimensions_new;
198 : : /* v 1.05 */
199 : 54 : orig_at_data->polymer = polymer;
200 : 54 : orig_at_data->v3000 = v3000;
201 : 54 : polymer = NULL;
202 : 54 : v3000 = NULL;
203 : : }
204 [ # # ]: 0 : else if ((orig_at_data->at = (inp_ATOM *)inchi_calloc(nNumAtoms, sizeof(inp_ATOM))) &&
205 [ # # # # ]: 0 : (!szCoordNew || (orig_at_data->szCoord = (MOL_COORD *)inchi_calloc(nNumAtoms, sizeof(MOL_COORD)))))
206 : : {
207 : : /* switch at_new <--> orig_at_data->at; */
208 [ # # ]: 0 : if (orig_at_data->num_inp_atoms)
209 : : {
210 : 0 : memcpy(orig_at_data->at, at_old, orig_at_data->num_inp_atoms * sizeof(orig_at_data->at[0]));
211 : : /* adjust numbering in the newly read structure */
212 [ # # ]: 0 : for (i = 0; i < num_inp_atoms_new; i++)
213 : : {
214 [ # # ]: 0 : if (at_new) /* djb-rwth: fixing a NULL pointer dereference */
215 : : {
216 [ # # ]: 0 : for (j = 0; j < at_new[i].valence; j++)
217 : : {
218 : 0 : at_new[i].neighbor[j] += orig_at_data->num_inp_atoms;
219 : : }
220 : 0 : at_new[i].orig_at_number += orig_at_data->num_inp_atoms; /* 12-19-2003 */
221 : : }
222 : : }
223 [ # # # # ]: 0 : if (orig_at_data->szCoord && szCoordOld)
224 : 0 : memcpy(orig_at_data->szCoord, szCoordOld, orig_at_data->num_inp_atoms * sizeof(MOL_COORD));
225 : : }
226 [ # # ]: 0 : if (at_old)
227 : : {
228 [ # # ]: 0 : inchi_free(at_old);
229 : 0 : at_old = NULL;
230 : : }
231 [ # # ]: 0 : if (szCoordOld)
232 : : {
233 [ # # ]: 0 : inchi_free(szCoordOld);
234 : 0 : szCoordOld = NULL;
235 : : }
236 : :
237 : : /* Copy newly read structure */
238 [ # # ]: 0 : if (at_new) /* djb-rwth: fixing a NULL pointer dereference */
239 : 0 : memcpy(orig_at_data->at + orig_at_data->num_inp_atoms, at_new, num_inp_atoms_new * sizeof(orig_at_data->at[0]));
240 [ # # # # ]: 0 : if (orig_at_data->szCoord && szCoordNew)
241 : : {
242 : 0 : memcpy(orig_at_data->szCoord + orig_at_data->num_inp_atoms,
243 : : szCoordNew,
244 : : num_inp_atoms_new * sizeof(MOL_COORD));
245 : : }
246 : :
247 : : /* Add other things */
248 : 0 : orig_at_data->num_inp_atoms += num_inp_atoms_new;
249 : 0 : orig_at_data->num_inp_bonds += num_inp_bonds_new;
250 : 0 : orig_at_data->num_dimensions = inchi_max(num_dimensions_new, orig_at_data->num_dimensions);
251 : : /* v 1.05 */
252 : 0 : orig_at_data->polymer = polymer;
253 : 0 : orig_at_data->v3000 = v3000;
254 : : }
255 : : else
256 : : {
257 : 0 : TREAT_ERR(*err, 0, "Out of RAM");
258 : 0 : *err = -1;
259 : : }
260 : : }
261 [ # # ]: 0 : else if (num_inp_atoms_new > 0)
262 : : {
263 : 0 : nNumAtoms += num_inp_atoms_new;
264 : : }
265 : :
266 [ - + ]: 54 : if (at_new)
267 : : {
268 [ # # ]: 0 : inchi_free(at_new);
269 : 0 : at_new = NULL;
270 : : }
271 [ - + ]: 54 : if (polymer)
272 : : {
273 [ # # ]: 0 : inchi_free(polymer);
274 : 0 : polymer = NULL;
275 : : }
276 [ - + ]: 54 : if (v3000)
277 : : {
278 [ # # ]: 0 : inchi_free(v3000);
279 : 0 : v3000 = NULL;
280 : : }
281 : :
282 [ + - - + ]: 54 : } while (!*err && bMergeAllInputStructures);
283 : :
284 [ - + ]: 54 : if (szCoordNew)
285 : : {
286 [ # # ]: 0 : inchi_free(szCoordNew);
287 : : }
288 [ - + ]: 54 : if (at_new)
289 : : {
290 [ # # ]: 0 : inchi_free(at_new);
291 : : }
292 : :
293 [ - + ]: 54 : if (*err)
294 : : {
295 : 0 : FreeOrigAtData(orig_at_data);
296 : : }
297 : :
298 [ - + - - : 54 : if (*err && !(10 < *err && *err < 20) && pStrErr && !pStrErr[0])
- - - - -
- ]
299 : : {
300 : 0 : TREAT_ERR(*err, 0, "Unknown error"); /* <BRKPT> */
301 : : }
302 : :
303 [ + - ]: 54 : return orig_at_data ? orig_at_data->num_inp_atoms : nNumAtoms;
304 : : }
305 : :
306 : : /****************************************************************************
307 : : ReadMolfileToInpAtoms
308 : : ****************************************************************************/
309 : 54 : int ReadMolfileToInpAtoms(INCHI_IOSTREAM *inp_file,
310 : : int bDoNotAddH,
311 : : inp_ATOM **at,
312 : : MOL_COORD **szCoord,
313 : : OAD_Polymer **polymer,
314 : : OAD_V3000 **v3000,
315 : : int treat_polymers,
316 : : int treat_NPZz,
317 : : int max_num_at,
318 : : int *num_dimensions,
319 : : int *num_bonds,
320 : : const char *pSdfLabel,
321 : : char *pSdfValue,
322 : : unsigned long *Id,
323 : : long *lMolfileNumber,
324 : : INCHI_MODE *pInpAtomFlags,
325 : : int *err,
326 : : char *pStrErr,
327 : : int bNoWarnings)
328 : : {
329 : 54 : int num_atoms = 0;
330 : 54 : MOL_FMT_DATA *mfdata = NULL;
331 : : MOL_FMT_HEADER_BLOCK OnlyHeaderBlock,
332 : 54 : *pOnlyHeaderBlock = NULL,
333 : : *pHdr;
334 : : MOL_FMT_CTAB OnlyCTab,
335 : 54 : *pOnlyCTab = NULL;
336 : 54 : char cSdfValueFirstChar = 0;
337 : :
338 [ + - ]: 54 : if (at)
339 : : {
340 : 54 : pOnlyHeaderBlock = NULL;
341 [ - + - - ]: 54 : if (*at && max_num_at)
342 : : {
343 : 0 : memset(*at, 0, max_num_at * sizeof(inp_ATOM)); /* djb-rwth: memset_s C11/Annex K variant? */
344 : : }
345 [ + - - + ]: 54 : if (szCoord && *szCoord)
346 : : {
347 [ # # ]: 0 : inchi_free(*szCoord);
348 : 0 : *szCoord = NULL;
349 : : }
350 : : }
351 : : else
352 : : {
353 : 0 : pOnlyHeaderBlock = &OnlyHeaderBlock;
354 : 0 : pOnlyCTab = &OnlyCTab;
355 : : }
356 : :
357 [ - + ]: 54 : if (pSdfValue)
358 : : {
359 : 0 : cSdfValueFirstChar = pSdfValue[0];
360 : 0 : pSdfValue[0] = '\0';
361 : : }
362 : :
363 : : /* Read mol-formatted file (MOL or SD) block */
364 : 54 : mfdata = ReadMolfile(inp_file, pOnlyHeaderBlock, pOnlyCTab, NULL != szCoord,
365 : : treat_polymers, treat_NPZz,
366 : : NULL, 0,
367 : : Id, pSdfLabel, pSdfValue, err, pStrErr, bNoWarnings);
368 : :
369 [ + - ]: 54 : pHdr = (mfdata && !pOnlyHeaderBlock)
370 : : ? &mfdata->hdr
371 [ + - - - ]: 108 : : (!mfdata && pOnlyHeaderBlock) ? pOnlyHeaderBlock
372 [ # # ]: 0 : : NULL;
373 : :
374 [ + - + - ]: 54 : if (lMolfileNumber && pHdr)
375 : : {
376 : 54 : *lMolfileNumber = MolfileExtractStrucNum(pHdr);
377 : : }
378 : :
379 [ - + - - : 54 : if (pSdfValue && !pSdfValue[0] &&
- - ]
380 [ # # # # ]: 0 : pSdfLabel && pSdfLabel[0] &&
381 : : pHdr)
382 : : {
383 [ # # ]: 0 : if (!inchi_stricmp(pSdfLabel, "MolfileName"))
384 : : {
385 : 0 : mystrncpy(pSdfValue, pHdr->molname, MAX_SDF_VALUE + 1);
386 : 0 : lrtrim(pSdfValue, NULL);
387 : : }
388 [ # # ]: 0 : else if (!inchi_stricmp(pSdfLabel, "MolfileLine2"))
389 : : {
390 : 0 : mystrncpy(pSdfValue, pHdr->line2, MAX_SDF_VALUE + 1);
391 : 0 : lrtrim(pSdfValue, NULL);
392 : : }
393 [ # # ]: 0 : else if (!inchi_stricmp(pSdfLabel, "MolfileComment"))
394 : : {
395 : 0 : mystrncpy(pSdfValue, pHdr->comment, MAX_SDF_VALUE + 1);
396 : 0 : lrtrim(pSdfValue, NULL);
397 : : }
398 [ # # # # ]: 0 : else if (!inchi_stricmp(pSdfLabel, "MolfileIntRegNo") && pHdr->internal_regno)
399 : : {
400 : 0 : sprintf(pSdfValue, "%ld", pHdr->internal_regno);
401 : : }
402 : :
403 [ # # ]: 0 : if (!pSdfValue[0])
404 : : {
405 : 0 : pSdfValue[0] = cSdfValueFirstChar;
406 : : }
407 : : }
408 : :
409 [ + - + - : 54 : if (mfdata && at && !*err)
+ - ]
410 : : {
411 : : /* (*at) either points to already allocated memory or NULL */
412 [ + - ]: 54 : if (mfdata->ctab.n_atoms <= max_num_at)
413 : : {
414 : :
415 : 54 : *at = MakeInpAtomsFromMolfileData(mfdata, &num_atoms, num_bonds,
416 : : *at, bDoNotAddH, err, pStrErr);
417 : :
418 [ + - ]: 54 : if (*err >= 0)
419 : : {
420 : 54 : *num_dimensions = SetInpAtomsXYZ(mfdata, num_atoms,
421 : : *at, err, pStrErr);
422 : :
423 [ + - ]: 54 : if (szCoord)
424 : : {
425 : 54 : *szCoord = mfdata->ctab.coords;
426 : 54 : mfdata->ctab.coords = NULL;
427 : : }
428 : :
429 : : /* Check that all atoms nos of Hs are in allowed range ( <=MAXVAL, currently 20 ) */
430 : : if (1)
431 : : {
432 : : int i;
433 [ + + ]: 673 : for (i = 0; i < num_atoms; i++)
434 : : {
435 [ - + ]: 619 : if ((*at)[i].num_iso_H[0] + (*at)[i].num_iso_H[1] + (*at)[i].num_iso_H[2] > MAXVAL)
436 : : {
437 : 0 : *err = 70 + 8;
438 : 0 : TREAT_ERR(*err, 0, "Too many hydrogens at heavy atom");
439 : 0 : num_atoms = -1;
440 : 0 : break;
441 : : }
442 : : }
443 : : }
444 : :
445 [ + - ]: 54 : if (!*err)
446 : : {
447 : 54 : *err = SetExtOrigAtDataByMolfileExtInput(mfdata, polymer, v3000, pStrErr);
448 [ - + ]: 54 : if (*err)
449 : : {
450 : : /*TREAT_ERR (*err, 0, "Error while getting extended Molfile input");*/
451 : 0 : *err = 80;
452 : 0 : num_atoms = -1;
453 : : }
454 : : }
455 : : }
456 : : else
457 : : {
458 [ # # ]: 0 : if (*err == -2) /* unk element */
459 : : {
460 : 0 : *err = 90;
461 : 0 : num_atoms = -1;
462 : : }
463 : : }
464 : : }
465 : : else
466 : : {
467 : : /* non-affordable struct size */
468 : 0 : TREAT_ERR(*err, 0, "Too many atoms [did you forget 'LargeMolecules' switch?]");
469 : 0 : *err = 70;
470 : 0 : num_atoms = -1;
471 : : }
472 : :
473 [ - + ]: 54 : if (*err > 0)
474 : : {
475 : 0 : *err += 100;
476 : : }
477 : :
478 : : /* 11-16-2004: use Chiral flag */
479 [ + - + - : 54 : if (num_atoms > 0 && at && *at && mfdata && pInpAtomFlags)
+ - + - +
- ]
480 : : {
481 [ + + ]: 54 : if (mfdata->ctab.chiral_flag)
482 : : {
483 : 7 : *pInpAtomFlags |= FLAG_INP_AT_CHIRAL;
484 : : }
485 : : else
486 : : {
487 : 47 : *pInpAtomFlags |= FLAG_INP_AT_NONCHIRAL;
488 : : }
489 : : }
490 : : }
491 : :
492 [ # # ]: 0 : else if (!at)
493 : : {
494 : 0 : num_atoms = pOnlyCTab->n_atoms;
495 : : }
496 : :
497 [ + - ]: 54 : if (!pOnlyHeaderBlock)
498 : : {
499 : 54 : FreeMolfileData(mfdata);
500 : : }
501 : :
502 : 54 : return num_atoms;
503 : : }
504 : :
505 : : /****************************************************************************
506 : : Make Inp Atoms From Molfile Data
507 : : ****************************************************************************/
508 : 54 : inp_ATOM *MakeInpAtomsFromMolfileData(MOL_FMT_DATA *mfdata,
509 : : int *num_atoms,
510 : : int *num_bonds,
511 : : inp_ATOM *at_inp,
512 : : int bDoNotAddH,
513 : : int *err,
514 : : char *pStrErr)
515 : : {
516 : 54 : inp_ATOM *at = NULL;
517 : : /* char *bond_stereo = NULL; */
518 : : AT_NUMB *p1, *p2;
519 : : int i, a1, a2, n1, n2, bonds, iso_atw_diff;
520 : : char bond_stereo, bond_type;
521 : :
522 : 54 : *err = 0;
523 : :
524 : 54 : *num_atoms = mfdata->ctab.n_atoms;
525 : 54 : *num_bonds = 0;
526 : :
527 : : /*(@nnuk : Nauman Ullah Khan) */
528 : : LOG_NO_ARGS("\n############### (L579:mol2atom.c) ################\n");
529 : : LOG_MULT_ARGS("Number of atoms : %d\n", *num_atoms);
530 : : LOG_NO_ARGS("####################################################\n");
531 : :
532 [ - + ]: 54 : if (MolfileHasNoChemStruc(mfdata))
533 : : {
534 : 0 : goto exit_function;
535 : : }
536 : :
537 : : /* Allocate memory if necessary */
538 [ - + ]: 54 : if (at_inp)
539 : : {
540 : 0 : at = at_inp;
541 : : }
542 : : else
543 : : {
544 : 54 : at = CreateInpAtom(*num_atoms);
545 [ - + ]: 54 : if (!at)
546 : : {
547 : 0 : *err = -1;
548 [ # # ]: 0 : TREAT_ERR_AND_FIN(*err, -1, exit_function, "Out of RAM");
549 : : }
550 : : }
551 : :
552 : : /* Copy atoms info */
553 : :
554 : : /*(@nnuk : Nauman Ullah Khan) */
555 : : LOG_NO_ARGS("\n##################### Atoms Data #########################\n");
556 : :
557 [ + + ]: 673 : for (i = 0; i < *num_atoms; i++)
558 : : {
559 : :
560 : 619 : mystrncpy(at[i].elname, mfdata->ctab.atoms[i].symbol, sizeof(at->elname));
561 : : /* at[i].chem_bonds_valence = mfdata->ctab.atoms[i].valence; */
562 : : /* MOLfile valence; will change */
563 : :
564 : 619 : at[i].orig_at_number = (AT_NUMB)(i + 1);
565 : 619 : at[i].iso_atw_diff = mfdata->ctab.atoms[i].mass_difference;
566 : 619 : at[i].charge = mfdata->ctab.atoms[i].charge;
567 : 619 : at[i].radical = mfdata->ctab.atoms[i].radical;
568 : :
569 : : /* see SetInpAtomXYZ()
570 : : at[i].x = mfdata->ctab.atoms[i].fx;
571 : : at[i].y = mfdata->ctab.atoms[i].fy;
572 : : at[i].z = mfdata->ctab.atoms[i].fz;
573 : : */
574 : :
575 : 619 : iso_atw_diff = mfdata->ctab.atoms[i].mass_difference;
576 : :
577 [ + - - + ]: 619 : at[i].iso_atw_diff = iso_atw_diff == ZERO_ATW_DIFF
578 : : ? 1
579 : 0 : : iso_atw_diff > 0 ? iso_atw_diff + 1
580 : : : iso_atw_diff;
581 : :
582 : : #if (SINGLET_IS_TRIPLET == 1)
583 [ - + ]: 619 : if (at[i].radical == RADICAL_SINGLET)
584 : : {
585 : 0 : at[i].radical = RADICAL_TRIPLET;
586 : : }
587 : : #endif
588 : : #if (bRELEASE_VERSION != 1)
589 : : if (isdigit(at[i].elname[0]))
590 : : { /* for testing */
591 : : mystrncpy(at[i].elname, "C", sizeof(at->elname));
592 : : }
593 : : #endif
594 : :
595 [ - + ]: 619 : if (ERR_ELEM == (n1 = get_periodic_table_number(at[i].elname)))
596 : : {
597 : : /* Case when elname contains more than 1 element: extract number of H if possible */
598 : 0 : at[i].num_H = extract_H_atoms(at[i].elname, at[i].num_iso_H);
599 : :
600 [ # # # # ]: 0 : if (!at[i].elname[0] && NUMH(at, i))
601 : : {
602 : : /* alias contains only H. Added 2004-07-21, fixed 2004-07-22
603 : : * move the heaviest isotope to the "central atom"
604 : : * Note: this must be consistent with H-H treatment in remove_terminal_HDT()
605 : : */
606 : 0 : strcpy(at[i].elname, "H");
607 [ # # ]: 0 : if (NUM_ISO_H(at, i))
608 : : {
609 : : int j;
610 [ # # ]: 0 : for (j = NUM_H_ISOTOPES - 1; 0 <= j; j--)
611 : : {
612 [ # # ]: 0 : if (at[i].num_iso_H[j])
613 : : {
614 : 0 : at[i].num_iso_H[j]--;
615 : 0 : at[i].iso_atw_diff = 1 + j;
616 : 0 : break;
617 : : }
618 : : }
619 : : }
620 : : else
621 : : {
622 : 0 : at[i].num_H--;
623 : : }
624 : : }
625 [ # # ]: 0 : if (ERR_ELEM == (n1 = get_periodic_table_number(at[i].elname)))
626 : : {
627 : 0 : n1 = 0;
628 : : }
629 : : } /* if ( ERR_ELEM == */
630 : :
631 : 619 : at[i].el_number = (U_CHAR)n1;
632 [ - + ]: 619 : if (!n1)
633 : : {
634 : 0 : *err = -2;
635 [ # # ]: 0 : TREAT_ERR(*err, -2, "Unknown element(s):");
636 [ # # ]: 0 : TREAT_ERR_AND_FIN(*err, -2, exit_function, at[i].elname);
637 : : }
638 : : else
639 : : {
640 : : /* replace explicit D or T with isotopic H (added 2003-06-02) */
641 [ + + + - ]: 619 : if ((int)EL_NUMBER_H == n1 && !at[i].iso_atw_diff)
642 : : {
643 [ - - + ]: 1 : switch (at[i].elname[0])
644 : : {
645 : 0 : case 'D':
646 : 0 : at[i].iso_atw_diff = 2;
647 : 0 : mystrncpy(at[i].elname, "H", sizeof(at->elname));
648 : 0 : break;
649 : 0 : case 'T':
650 : 0 : at[i].iso_atw_diff = 3;
651 : 0 : mystrncpy(at[i].elname, "H", sizeof(at->elname));
652 : 0 : break;
653 : : }
654 : : }
655 : : }
656 : :
657 : : /*(@nnuk : Nauman Ullah Khan) */
658 : : LOG_NO_ARGS("\n############################## (L714:mol2atom.c) #####################################\n");
659 : : LOG_MULT_ARGS("Atom %d: element=%s, x=%f, y=%f, z=%f, chrg=%d, rad=%d, iso=%d\n", i, at[i].elname, at[i].x, at[i].y, at[i].z, at[i].charge, at[i].radical, at[i].iso_atw_diff);
660 : : LOG_NO_ARGS("########################################################################################\n");
661 : :
662 : : } /* eof copy atom info */
663 : :
664 : : /*---------------- stereo information notes. ------------------------
665 : :
666 : : Currently: 1. stereo sign
667 : : ========= --------------
668 : : MOLfile (atom number = MOLfile atom number - 1, no stdata as an intermediate)
669 : : | if mfdata->ctab.bonds[i].atnum1 < mfdata->ctab.bonds[i].atnum2
670 : : v then
671 : : inp_ATOM stereo > 0
672 : : else
673 : : stereo < 0
674 : :
675 : : 2. neighbor z-coordinate
676 : : ------------------------
677 : : neighbor z-coord > 0 for Up if sign(stdata_bond_no) = sign(at[i].neighbor[j]-i)
678 : :
679 : : --------------------------------------------------------------------*/
680 : :
681 : : /* Copy bond info */
682 : :
683 : : LOG_NO_ARGS("\n######################### Bonds Data ###############################\n");
684 : :
685 [ + + ]: 622 : for (i = 0, bonds = 0; i < mfdata->ctab.n_bonds; i++)
686 : : {
687 : :
688 : 568 : bond_stereo = mfdata->ctab.bonds[i].bond_stereo;
689 : 568 : bond_type = mfdata->ctab.bonds[i].bond_type;
690 : :
691 : 568 : a1 = mfdata->ctab.bonds[i].atnum1 - 1;
692 : 568 : a2 = mfdata->ctab.bonds[i].atnum2 - 1;
693 : :
694 [ + - + - : 568 : if (a1 < 0 || a1 >= *num_atoms ||
+ - ]
695 [ + - - + ]: 568 : a2 < 0 || a2 >= *num_atoms ||
696 : : a1 == a2)
697 : : {
698 : 0 : *err |= 1; /* bond for impossible atom number(s); ignored */
699 : 0 : TREAT_ERR(*err, 0, "Bond to nonexistent atom");
700 : 0 : continue;
701 : : }
702 : :
703 : : /* check for multiple bonds between same atoms */
704 : 568 : p1 = is_in_the_list(at[a1].neighbor, (AT_NUMB)a2, at[a1].valence);
705 : 568 : p2 = is_in_the_list(at[a2].neighbor, (AT_NUMB)a1, at[a2].valence);
706 : :
707 : : /*(@nnuk : Nauman Ullah Khan) */
708 : : LOG_NO_ARGS("\n################## (L771:mol2atom.c) ##################\n");
709 : : LOG_MULT_ARGS("Valence = %d\n", at[i].valence);
710 : : LOG_NO_ARGS("#########################################################\n");
711 : :
712 [ + - - + : 568 : if ((p1 || p2) && (p1 || at[a1].valence < MAXVAL) && (p2 || at[a2].valence < MAXVAL))
- - - - -
- - - ]
713 : : {
714 [ # # ]: 0 : n1 = p1 ? (p1 - at[a1].neighbor) : at[a1].valence++;
715 [ # # ]: 0 : n2 = p2 ? (p2 - at[a2].neighbor) : at[a2].valence++;
716 : 0 : TREAT_ERR(*err, 0, "Multiple bonds between two atoms");
717 : 0 : *err |= 2; /* multiple bonds between atoms */
718 : : }
719 [ + - + - : 568 : else if (!p1 && !p2 && at[a1].valence < MAXVAL && at[a2].valence < MAXVAL)
+ - + - ]
720 : : {
721 : 568 : n1 = at[a1].valence++;
722 : 568 : n2 = at[a2].valence++;
723 : 568 : bonds++;
724 : : }
725 : : else
726 : 0 : {
727 : : char szMsg[64];
728 : 0 : *err |= 4; /* too large number of bonds. Some bonds ignored. */
729 : 0 : sprintf(szMsg, "Atom '%s' has more than %d bonds",
730 [ # # ]: 0 : at[a1].valence >= MAXVAL ? at[a1].elname : at[a2].elname, MAXVAL);
731 : 0 : TREAT_ERR(*err, 0, szMsg);
732 : 0 : continue;
733 : : }
734 : :
735 : : /* (@nnuk) : Bond type 9 (coordinative bond) recognized by InChI now */
736 [ + - - + : 568 : if (bond_type < MIN_INPUT_BOND_TYPE || (bond_type > MAX_INPUT_BOND_TYPE && bond_type != COORDINATIVE_BOND))
- - ]
737 : : {
738 : : char szBondType[16];
739 : 0 : sprintf(szBondType, "%d", bond_type);
740 : 0 : bond_type = 1;
741 : 0 : TREAT_ERR(*err, 0, "Unrecognized bond type:");
742 : 0 : TREAT_ERR(*err, 0, szBondType);
743 : 0 : *err |= 8; /* Unrecognized Bond type replaced with single bond */
744 : : }
745 : :
746 : : /* bond type */
747 [ + - + - ]: 568 : if (n1 < MAXVAL && n2 < MAXVAL) /* djb-rwth: buffer overrun prevention */
748 : : {
749 : 568 : at[a1].bond_type[n1] = at[a2].bond_type[n2] = bond_type;
750 : :
751 : : /* connection */
752 : 568 : at[a1].neighbor[n1] = (AT_NUMB)a2;
753 : 568 : at[a2].neighbor[n2] = (AT_NUMB)a1;
754 : :
755 : : /* stereo */
756 [ - + ]: 568 : if (bond_stereo == INPUT_STEREO_DBLE_EITHER /* 3 */)
757 : : {
758 : 0 : at[a1].bond_stereo[n1] =
759 : 0 : at[a2].bond_stereo[n2] =
760 : : STEREO_DBLE_EITHER;
761 : : }
762 [ + + + - ]: 568 : else if (bond_stereo == INPUT_STEREO_SNGL_UP || /* 1 */
763 [ + + ]: 420 : bond_stereo == INPUT_STEREO_SNGL_EITHER || /* 4 */
764 : : bond_stereo == INPUT_STEREO_SNGL_DOWN /* 6 */)
765 : 179 : {
766 : : char cStereo;
767 [ + - + - ]: 179 : switch (bond_stereo)
768 : : {
769 : 148 : case INPUT_STEREO_SNGL_UP:
770 : 148 : cStereo = STEREO_SNGL_UP;
771 : 148 : break;
772 : 0 : case INPUT_STEREO_SNGL_EITHER:
773 : 0 : cStereo = STEREO_SNGL_EITHER;
774 : 0 : break;
775 : 31 : case INPUT_STEREO_SNGL_DOWN:
776 : 31 : cStereo = STEREO_SNGL_DOWN;
777 : 31 : break;
778 : : }
779 : 179 : at[a1].bond_stereo[n1] = cStereo; /* >0: the wedge (pointed) end is at this atom, a1 */
780 : 179 : at[a2].bond_stereo[n2] = -cStereo; /* <0: the wedge (pointed) end is at the opposite atom, a1 */
781 : : }
782 [ - + ]: 389 : else if (bond_stereo)
783 : : {
784 : 0 : *err |= 16; /* Ignored unrecognized Bond stereo */
785 : 0 : TREAT_ERR(*err, 0, "Unrecognized bond stereo");
786 : 0 : continue;
787 : : }
788 : : }
789 : :
790 : : /*(@nnuk : Nauman Ullah Khan) */
791 : : LOG_NO_ARGS("\n################ (L862:mol2atom.c) ##################\n");
792 : : LOG_MULT_ARGS("Bond %d: atom1=%d, atom2=%d, type=%d, stereo=%d\n", i, a1, a2, bond_type, bond_stereo);
793 : : LOG_NO_ARGS("#######################################################\n");
794 : :
795 : : } /* eof copy bond info */
796 : :
797 : 54 : *num_bonds = bonds;
798 : :
799 : : /* (@nnuk) : Handling haptic bonds */
800 [ + + + + ]: 54 : if (mfdata->ctab.v3000 && mfdata->ctab.v3000->n_haptic_bonds > 0 &&
801 [ + - + - ]: 2 : mfdata->ctab.v3000->haptic_bonds && mfdata->ctab.v3000->haptic_bonds->lists)
802 : : {
803 [ + + ]: 5 : for (i = 0; i < mfdata->ctab.v3000->n_haptic_bonds; i++)
804 : : {
805 : 3 : int* list = mfdata->ctab.v3000->haptic_bonds->lists[i];
806 [ - + ]: 3 : if (!list)
807 : : {
808 : 0 : TREAT_ERR(*err, 0, "Null haptic bond list");
809 : 0 : continue;
810 : : }
811 : :
812 : 3 : int bond_type = list[0];
813 : 3 : int central_atom = list[1];
814 : 3 : int endpoint_count = list[2];
815 : 3 : int central_idx = central_atom - 1;
816 : :
817 : 3 : int endpoints_added = 0;
818 : :
819 [ + + ]: 15 : for (int j = 0; j < endpoint_count; j++)
820 : : {
821 : 12 : int n_endpoint = list[3 + j];
822 : 12 : int endpoint_idx = n_endpoint - 1;
823 : :
824 : 12 : int central_at_num = at[central_idx].valence;
825 : 12 : int endpoint_at_num = at[endpoint_idx].valence;
826 : :
827 : 12 : p1 = is_in_the_list(at[central_idx].neighbor, (AT_NUMB)endpoint_idx, central_at_num);
828 : 12 : p2 = is_in_the_list(at[endpoint_idx].neighbor, (AT_NUMB)central_idx, endpoint_at_num);
829 : :
830 [ + - - + ]: 12 : if (central_at_num >= MAXVAL || endpoint_at_num >= MAXVAL)
831 : : {
832 : 0 : fprintf(stderr, "Atom number exceeded when trying to add haptic bond between atoms %d and %d\n", central_idx, endpoint_idx);
833 : 0 : continue;
834 : : }
835 : :
836 : 12 : at[central_idx].neighbor[central_at_num] = endpoint_idx;
837 : 12 : at[central_idx].bond_type[central_at_num] = COORDINATIVE_BOND;
838 : 12 : at[central_idx].bond_stereo[central_at_num] = 0;
839 : 12 : at[central_idx].valence++;
840 : :
841 : 12 : at[endpoint_idx].neighbor[endpoint_at_num] = central_idx;
842 : 12 : at[endpoint_idx].bond_type[endpoint_at_num] = COORDINATIVE_BOND;
843 : 12 : at[endpoint_idx].bond_stereo[endpoint_at_num] = 0;
844 : 12 : at[endpoint_idx].valence++;
845 : :
846 : 12 : bonds++;
847 : 12 : endpoints_added++;
848 : : }
849 : : }
850 : :
851 : 2 : *num_bonds = bonds;
852 : : }
853 : :
854 : : /* special valences */
855 : 54 : calculate_valences(mfdata, at, num_atoms, bDoNotAddH, err, pStrErr);
856 : :
857 : 54 : exit_function:;
858 : :
859 : 54 : return at;
860 : : }
861 : :
862 : : /****************************************************************************/
863 : 54 : void calculate_valences(MOL_FMT_DATA *mfdata,
864 : : inp_ATOM *at,
865 : : int *num_atoms,
866 : : int bDoNotAddH,
867 : : int *err,
868 : : char *pStrErr)
869 : : {
870 : : int bNonMetal;
871 : : int a1, a2, n1, n2, valence;
872 : : AT_NUMB *p1;
873 : 54 : int* coord_bonds_count = NULL; /* (@nnuk) :: Array to track coordination bonds for non - metals */
874 : :
875 : : /* (@nnuk) :: Allocate memory for coordination bonds count */
876 : 54 : coord_bonds_count = (int*)inchi_calloc(*num_atoms, sizeof(int));
877 [ - + ]: 54 : if (!coord_bonds_count)
878 : : {
879 : 0 : *err = -1;
880 : 0 : TREAT_ERR(*err, 0, "Memory allocation failed for coord_bonds_count");
881 : 0 : return;
882 : : }
883 : :
884 : : /* (@nnuk : Nauman Ullah Khan)
885 : : * Count coordination bonds (type 9) for each non-metal atom
886 : : * Iterates through all atoms and their bonds to identify coordination bonds
887 : : * and tracks count per non-metal atom in coord_bonds_count array
888 : : */
889 [ + + ]: 673 : for (a1 = 0; a1 < *num_atoms; a1++)
890 : : {
891 [ + + ]: 619 : if (!is_el_a_metal(at[a1].el_number))
892 : : {
893 [ + + ]: 1740 : for (n1 = 0; n1 < at[a1].valence; n1++)
894 : : {
895 [ + + ]: 1128 : if (at[a1].bond_type[n1] == COORDINATIVE_BOND)
896 : : {
897 : 12 : coord_bonds_count[a1]++;
898 : : }
899 : : }
900 : : }
901 : : }
902 : :
903 : : /* special valences */
904 : :
905 [ + + ]: 162 : for (bNonMetal = 0; bNonMetal < 2; bNonMetal++)
906 : : {
907 [ + + ]: 1346 : for (a1 = 0; a1 < *num_atoms; a1++)
908 : : {
909 : : int num_bond_type[MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE + 1],
910 : : bond_type,
911 : : bHasMetalNeighbor;
912 : : /* should the "!=" be replaced with "==" ??? */
913 [ + + ]: 1238 : if (bNonMetal == is_el_a_metal(at[a1].el_number))
914 : : {
915 : : /* first process all metals, after that all non-metals */
916 : 619 : continue;
917 : : }
918 : :
919 : 619 : memset(num_bond_type, 0, sizeof(num_bond_type)); /* djb-rwth: memset_s C11/Annex K variant? */
920 : :
921 : : /* valence = at[a1].chem_bonds_valence; */ /* save atom valence if available */
922 : : /* 2006-08-31: fix for uncharged >N(IV)- in an aromatic ring */
923 : :
924 : 619 : valence =
925 [ + - ]: 619 : (mfdata && mfdata->ctab.atoms) ? mfdata->ctab.atoms[a1].valence
926 [ + - ]: 1238 : : at[a1].chem_bonds_valence;
927 : :
928 : 619 : at[a1].chem_bonds_valence = 0;
929 : 619 : bHasMetalNeighbor = 0;
930 [ + + ]: 1779 : for (n1 = 0; n1 < at[a1].valence; n1++)
931 : : {
932 : 1160 : bond_type = at[a1].bond_type[n1] - MIN_INPUT_BOND_TYPE;
933 [ + - + + ]: 1160 : if (bond_type < 0 || bond_type > MAX_INPUT_BOND_TYPE - MIN_INPUT_BOND_TYPE)
934 : : {
935 : 24 : bond_type = 0;
936 : 24 : TREAT_ERR(*err, 0, "Unknown bond type or a COORDINATIVE BOND (9) in MOLfile assigned as a single bond"); /* @nnuk : Coordinative bond is accepted now and is assigned as a single bond */
937 : : }
938 : 1160 : num_bond_type[bond_type]++;
939 : : /* -- too a radical solution -- removed from next to ver 1.12B --- */
940 : : }
941 : :
942 : 619 : for (n1 = 0;
943 [ + + + - ]: 2476 : MIN_INPUT_BOND_TYPE + n1 <= 3 &&
944 : : MIN_INPUT_BOND_TYPE + n1 <= MAX_INPUT_BOND_TYPE;
945 : 1857 : n1++)
946 : : {
947 : : /* add all bond orders except for "aromatic" bonds */
948 : 1857 : at[a1].chem_bonds_valence += (MIN_INPUT_BOND_TYPE + n1) * num_bond_type[n1];
949 : : }
950 : :
951 : 619 : n2 = 0; /* djb-rwth: ignoring LLVM warning: value used */
952 : 619 : if (MIN_INPUT_BOND_TYPE <= BOND_TYPE_ALTERN &&
953 : : BOND_TYPE_ALTERN <= MAX_INPUT_BOND_TYPE &&
954 [ - + ]: 619 : (n2 = num_bond_type[BOND_TYPE_ALTERN - MIN_INPUT_BOND_TYPE]))
955 : : {
956 : : /* accept input aromatic bonds for now */
957 [ # # # ]: 0 : switch (n2)
958 : : {
959 : 0 : case 2:
960 : 0 : at[a1].chem_bonds_valence += 3; /* =A- */
961 : 0 : break;
962 : 0 : case 3:
963 : 0 : at[a1].chem_bonds_valence += 4; /* =A< */
964 : 0 : break;
965 : 0 : default:
966 : : /* if 1 or >= 4 aromatic bonds then replace */
967 : : /* such bonds with single bonds */
968 : : /* and detect an error in the input structure */
969 [ # # ]: 0 : for (n1 = 0; n1 < at[a1].valence; n1++)
970 : : {
971 [ # # ]: 0 : if (at[a1].bond_type[n1] == BOND_TYPE_ALTERN)
972 : : {
973 : 0 : a2 = at[a1].neighbor[n1];
974 : 0 : p1 = is_in_the_list(at[a2].neighbor, (AT_NUMB)a1,
975 : 0 : at[a2].valence);
976 [ # # ]: 0 : if (p1)
977 : : {
978 : 0 : at[a1].bond_type[n1] =
979 : 0 : at[a2].bond_type[p1 - at[a2].neighbor] = BOND_TYPE_SINGLE;
980 : : }
981 : : else
982 : : {
983 : 0 : *err = -2; /* Program error */
984 : 0 : TREAT_ERR(*err, 0, "Program error interpreting MOLfile");
985 : 0 : return; /* no structure */
986 : : }
987 : : }
988 : : }
989 : :
990 : 0 : at[a1].chem_bonds_valence += n2;
991 : 0 : *err |= 32;
992 : 0 : TREAT_ERR(*err, 0, "Atom has 1 or more than 3 aromatic bonds");
993 : 0 : n2 = 0;
994 : 0 : break;
995 : : }
996 : : }
997 : :
998 [ - + - - ]: 619 : if (n2 && !valence)
999 : 0 : {
1000 : : /* atom has aromatic bonds AND the chemical valence is not known */
1001 : :
1002 : 0 : int num_H = NUMH(at, a1);
1003 : : /* bug fix 2006-08-25: aliased H result in num_H > 0 */
1004 : : /* => wrong call to detect_unusual_el_valence() */
1005 : 0 : int chem_valence = at[a1].chem_bonds_valence /*+ num_H*/;
1006 : :
1007 : : int bUnusualValenceArom =
1008 : 0 : detect_unusual_el_valence((int)at[a1].el_number, at[a1].charge,
1009 : 0 : at[a1].radical, chem_valence,
1010 : 0 : num_H, at[a1].valence);
1011 : : int bUnusualValenceNoArom =
1012 : 0 : detect_unusual_el_valence((int)at[a1].el_number, at[a1].charge,
1013 : 0 : at[a1].radical, chem_valence - 1,
1014 : 0 : num_H, at[a1].valence);
1015 : :
1016 : : #if (CHECK_AROMBOND2ALT == 1)
1017 [ # # # # ]: 0 : if (bUnusualValenceArom &&
1018 [ # # ]: 0 : !bUnusualValenceNoArom &&
1019 : 0 : 0 == nBondsValToMetal(at, a1))
1020 : : #else
1021 : : if (bUnusualValenceArom && !bUnusualValenceNoArom)
1022 : : #endif
1023 : : {
1024 : : /* typically NH in 5-member aromatic ring */
1025 : 0 : at[a1].chem_bonds_valence--;
1026 : : }
1027 : : }
1028 [ - + - - ]: 619 : else if (n2 && valence)
1029 : : {
1030 : : /* atom has aromatic bonds AND the chemical valence is known */
1031 : 0 : int num_H = NUMH(at, a1);
1032 : 0 : int chem_valence = at[a1].chem_bonds_valence + num_H;
1033 [ # # ]: 0 : if (valence == chem_valence - 1)
1034 : : {
1035 : : /* typically NH in 5-member aromatic ring */
1036 : 0 : at[a1].chem_bonds_valence--;
1037 : : }
1038 : : }
1039 : :
1040 : : /* Set number of hydrogen atoms */
1041 [ + - ]: 619 : if (mfdata)
1042 : : {
1043 : 619 : int additional_H = coord_bonds_count[a1];
1044 : :
1045 : 619 : int newValence = -1;
1046 : :
1047 [ + + + + ]: 619 : if (!is_el_a_metal(at[a1].el_number) && additional_H)
1048 : : {
1049 : : /*If the atom is a non - metal and has coordination bonds, adjust valence* /
1050 : : /* (@fbaensch) : Get new valence based on element number, charge, and valence defined in input file */
1051 : 12 : newValence = get_el_valence(at[a1].el_number, at[a1].charge, mfdata->ctab.atoms[a1].valence);
1052 : 12 : newValence += additional_H;
1053 : : }
1054 : : else
1055 : : {
1056 : : /* If the atom is a metal or has no coordination bonds, use the valence defined in input file */
1057 : 607 : newValence = mfdata->ctab.atoms[a1].valence;
1058 : : }
1059 : :
1060 : 619 : at[a1].num_H = get_num_H(at[a1].elname,
1061 : 619 : at[a1].num_H,
1062 : 619 : at[a1].num_iso_H,
1063 : 619 : at[a1].charge, at[a1].radical,
1064 : 619 : at[a1].chem_bonds_valence,
1065 : : /*mfdata->ctab.atoms[a1].valence,*/
1066 : : newValence, /* instead of valence */ /* (@Felix Bänsch)(@Gerd Blanke)(@nnuk) : The valence stated in the mol file is considerd here. A value of 0 means use default value for this element. */
1067 : 619 : mfdata->ctab.atoms[a1].atom_aliased_flag,
1068 : : bDoNotAddH,
1069 : : bHasMetalNeighbor);
1070 : : }
1071 : : }
1072 : : } /* for ( bNonMetal = ... */
1073 : :
1074 : : /* (@nnuk) : Free allocated memory */
1075 : 54 : free(coord_bonds_count);
1076 : :
1077 : 54 : return;
1078 : : }
1079 : :
1080 : : /****************************************************************************/
1081 : 54 : int SetInpAtomsXYZ(MOL_FMT_DATA *mfdata,
1082 : : int num_atoms,
1083 : : inp_ATOM *at,
1084 : : int *err,
1085 : : char *pStrErr)
1086 : : {
1087 : 54 : int i, num_dimensions = 0;
1088 : :
1089 : : #if (NORMALIZE_INP_COORD == 1)
1090 : : int do_scale_xyz = 1;
1091 : : #else
1092 : 54 : int do_scale_xyz = 0;
1093 : : #endif
1094 : : double x0, y0, z0, xmin, ymin, zmin, scaler;
1095 : :
1096 : 54 : num_dimensions = MolfileGetXYZDimAndNormFactors(mfdata, do_scale_xyz,
1097 : : &x0, &y0, &z0,
1098 : : &xmin, &ymin, &zmin,
1099 : : &scaler, err, pStrErr);
1100 : :
1101 [ - + ]: 54 : if (num_dimensions == 0)
1102 : : {
1103 : 0 : goto exit_function;
1104 : : }
1105 : :
1106 [ + + ]: 673 : for (i = 0; i < num_atoms; i++)
1107 : : {
1108 : :
1109 : 619 : double x = mfdata->ctab.atoms[i].fx;
1110 : 619 : double y = mfdata->ctab.atoms[i].fy;
1111 : 619 : double z = mfdata->ctab.atoms[i].fz;
1112 : :
1113 [ + - ]: 619 : if (!do_scale_xyz)
1114 : : {
1115 : 619 : at[i].x = x;
1116 : 619 : at[i].y = y;
1117 : 619 : at[i].z = z;
1118 : : }
1119 : : else
1120 : : {
1121 : 0 : x = (x - xmin) * scaler + x0;
1122 : 0 : y = (y - ymin) * scaler + y0;
1123 : 0 : z = (z - zmin) * scaler + z0;
1124 : : /* floor() behavior is not well defined for negative arguments.
1125 : : * Use positive arguments only to get nearest integer.
1126 : : */
1127 [ # # ]: 0 : at[i].x = (x >= 0.0) ? (int)floor(x + 0.5) : -(int)floor(-x + 0.5);
1128 [ # # ]: 0 : at[i].y = (y >= 0.0) ? (int)floor(y + 0.5) : -(int)floor(-y + 0.5);
1129 [ # # ]: 0 : at[i].z = (z >= 0.0) ? (int)floor(z + 0.5) : -(int)floor(-z + 0.5);
1130 : : }
1131 : : }
1132 : :
1133 : 54 : exit_function:;
1134 : :
1135 : 54 : return num_dimensions;
1136 : : }
1137 : :
1138 : : /****************************************************************************/
1139 : 271 : inp_ATOM *CreateInpAtom(int num_atoms)
1140 : : {
1141 : 271 : void *p = NULL;
1142 [ + - ]: 271 : if (num_atoms >= 0)
1143 : : {
1144 : 271 : p = inchi_calloc(num_atoms, sizeof(inp_ATOM));
1145 : : }
1146 : :
1147 : : // void *p = inchi_calloc(num_atoms, sizeof(inp_ATOM));
1148 : 271 : return (inp_ATOM *)p;
1149 : : }
1150 : :
1151 : : /****************************************************************************/
1152 : 1384 : void FreeInpAtom(inp_ATOM **at)
1153 : : {
1154 [ + - + + ]: 1384 : if (at && *at)
1155 : : {
1156 [ + - ]: 325 : inchi_free(*at);
1157 : 325 : *at = NULL;
1158 : : }
1159 : :
1160 : 1384 : return;
1161 : : }
1162 : :
1163 : : /****************************************************************************/
1164 : 417 : void FreeInpAtomData(INP_ATOM_DATA *inp_at_data)
1165 : : {
1166 [ + - ]: 417 : if (inp_at_data)
1167 : : {
1168 : 417 : FreeInpAtom(&inp_at_data->at);
1169 : 417 : FreeInpAtom(&inp_at_data->at_fixed_bonds);
1170 : 417 : memset(inp_at_data, 0, sizeof(*inp_at_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1171 : : }
1172 : :
1173 : 417 : return;
1174 : : }
1175 : :
1176 : : /****************************************************************************/
1177 : 138 : int CreateInpAtomData(INP_ATOM_DATA *inp_at_data,
1178 : : int num_atoms,
1179 : : int create_at_fixed_bonds)
1180 : : {
1181 : 138 : FreeInpAtomData(inp_at_data);
1182 : :
1183 [ + - + + ]: 138 : if ((inp_at_data->at = CreateInpAtom(num_atoms)) &&
1184 [ + - ]: 69 : (!create_at_fixed_bonds || (inp_at_data->at_fixed_bonds = CreateInpAtom(num_atoms))))
1185 : : {
1186 : 138 : inp_at_data->num_at = num_atoms;
1187 : 138 : return 1;
1188 : : }
1189 : :
1190 : 0 : FreeInpAtomData(inp_at_data);
1191 : :
1192 : 0 : return 0;
1193 : : }
1194 : :
1195 : : /****************************************************************************/
1196 : 334 : void FreeCompAtomData(COMP_ATOM_DATA *inp_at_data)
1197 : : {
1198 : 334 : FreeInpAtom(&inp_at_data->at);
1199 : :
1200 [ + + ]: 334 : if (inp_at_data->nOffsetAtAndH)
1201 : : {
1202 [ + - ]: 9 : inchi_free(inp_at_data->nOffsetAtAndH);
1203 : : }
1204 : 334 : memset(inp_at_data, 0, sizeof(*inp_at_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1205 : 334 : }
1206 : :
1207 : : #ifndef TARGET_API_LIB
1208 : :
1209 : : /****************************************************************************/
1210 : : int CreateCompAtomData(COMP_ATOM_DATA *inp_at_data,
1211 : : int num_atoms,
1212 : : int num_components,
1213 : : int bIntermediateTaut)
1214 : : {
1215 : : FreeCompAtomData(inp_at_data);
1216 : :
1217 : : if ((inp_at_data->at = CreateInpAtom(num_atoms)) &&
1218 : : (num_components <= 1 || bIntermediateTaut ||
1219 : : (inp_at_data->nOffsetAtAndH = (AT_NUMB *)inchi_calloc(2 * ((long long)num_components + 1), sizeof(inp_at_data->nOffsetAtAndH[0]))))) /* djb-rwth: cast operator added */
1220 : : {
1221 : : inp_at_data->num_at = num_atoms;
1222 : : inp_at_data->num_components = (num_components > 1) ? num_components : 0;
1223 : : return 1;
1224 : : }
1225 : :
1226 : : FreeCompAtomData(inp_at_data);
1227 : :
1228 : : return 0;
1229 : : }
1230 : : #endif
1231 : :
1232 : : #ifndef COMPILE_ANSI_ONLY
1233 : :
1234 : : /****************************************************************************/
1235 : : void FreeInfAtom(inf_ATOM **at)
1236 : : {
1237 : : if (at && *at)
1238 : : {
1239 : : inchi_free(*at);
1240 : : *at = NULL;
1241 : : }
1242 : : return;
1243 : : }
1244 : :
1245 : : /****************************************************************************/
1246 : : inf_ATOM *CreateInfAtom(int num_atoms)
1247 : : {
1248 : : return (inf_ATOM *)inchi_calloc(num_atoms, sizeof(inf_ATOM));
1249 : : }
1250 : :
1251 : : /****************************************************************************/
1252 : : void FreeInfoAtomData(INF_ATOM_DATA *inf_at_data)
1253 : : {
1254 : : FreeInfAtom(&inf_at_data->at);
1255 : : if (inf_at_data->pStereoFlags)
1256 : : {
1257 : : inchi_free(inf_at_data->pStereoFlags);
1258 : : }
1259 : : memset(inf_at_data, 0, sizeof(*inf_at_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1260 : :
1261 : : return;
1262 : : }
1263 : :
1264 : : /****************************************************************************/
1265 : : int CreateInfoAtomData(INF_ATOM_DATA *inf_at_data,
1266 : : int num_atoms,
1267 : : int num_components)
1268 : : {
1269 : : FreeInfoAtomData(inf_at_data);
1270 : :
1271 : : memset(inf_at_data, 0, sizeof(*inf_at_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1272 : :
1273 : : if ((inf_at_data->at = CreateInfAtom(num_atoms)) &&
1274 : : (num_components <= 1 ||
1275 : : (inf_at_data->pStereoFlags = (AT_NUMB *)inchi_calloc((long long)num_components + 1, sizeof(inf_at_data->pStereoFlags[0]))) /* djb-rwth: cast operator added */
1276 : : ))
1277 : : {
1278 : : inf_at_data->num_at = num_atoms;
1279 : : inf_at_data->num_components = num_components;
1280 : : return 1;
1281 : : }
1282 : :
1283 : : FreeInfoAtomData(inf_at_data);
1284 : :
1285 : : return 0;
1286 : : }
1287 : :
1288 : : /****************************************************************************/
1289 : : int AllocateInfoAtomData(INF_ATOM_DATA *inf_at_data,
1290 : : int num_atoms,
1291 : : int num_components)
1292 : : {
1293 : : if ((inf_at_data->at = CreateInfAtom(num_atoms))) /* djb-rwth: addressing LLVM warning */
1294 : : {
1295 : : if (num_components > 1 &&
1296 : : !(inf_at_data->pStereoFlags = (AT_NUMB *)inchi_calloc((long long)num_components + 1, sizeof(inf_at_data->pStereoFlags[0])))) /* djb-rwth: cast operator added */
1297 : : {
1298 : : FreeInfAtom(&inf_at_data->at);
1299 : : return 0;
1300 : : }
1301 : : return 1;
1302 : : }
1303 : :
1304 : : return 0;
1305 : : }
1306 : :
1307 : : /****************************************************************************/
1308 : : int DuplicateInfoAtomData(INF_ATOM_DATA *inf_at_data_to,
1309 : : const INF_ATOM_DATA *inf_at_data_from)
1310 : : {
1311 : : *inf_at_data_to = *inf_at_data_from;
1312 : :
1313 : : if (AllocateInfoAtomData(inf_at_data_to, inf_at_data_from->num_at, inf_at_data_from->num_components))
1314 : : {
1315 : : memcpy(inf_at_data_to->at, inf_at_data_from->at,
1316 : : inf_at_data_from->num_at * sizeof(inf_at_data_to->at[0]));
1317 : : if (inf_at_data_to->pStereoFlags && inf_at_data_from->pStereoFlags)
1318 : : {
1319 : : memcpy(inf_at_data_to->pStereoFlags, inf_at_data_from->pStereoFlags,
1320 : : ((long long)inf_at_data_from->num_components + 1) * sizeof(inf_at_data_to->pStereoFlags[0])); /* djb-rwth: cast operator added */
1321 : : }
1322 : : return 1;
1323 : : }
1324 : :
1325 : : return 0;
1326 : : }
1327 : : #endif /* COMPILE_ANSI_ONLY */
1328 : :
1329 : : /****************************************************************************/
1330 : 216 : void FreeOrigAtData(ORIG_ATOM_DATA *orig_at_data)
1331 : : {
1332 [ - + ]: 216 : if (!orig_at_data)
1333 : : {
1334 : 0 : return;
1335 : : }
1336 : :
1337 : 216 : FreeInpAtom(&orig_at_data->at);
1338 : :
1339 [ + + ]: 216 : if (orig_at_data->nCurAtLen)
1340 : : {
1341 [ + - ]: 54 : inchi_free(orig_at_data->nCurAtLen);
1342 : : }
1343 : :
1344 [ + + ]: 216 : if (orig_at_data->nOldCompNumber)
1345 : : {
1346 [ + - ]: 54 : inchi_free(orig_at_data->nOldCompNumber);
1347 : : }
1348 : :
1349 [ + + ]: 216 : if (orig_at_data->szCoord)
1350 : : {
1351 [ + - ]: 12 : inchi_free(orig_at_data->szCoord);
1352 : : }
1353 : :
1354 [ - + ]: 216 : if (orig_at_data->nEquLabels)
1355 : : {
1356 [ # # ]: 0 : inchi_free(orig_at_data->nEquLabels);
1357 : : }
1358 : :
1359 [ - + ]: 216 : if (orig_at_data->nSortedOrder)
1360 : : {
1361 [ # # ]: 0 : inchi_free(orig_at_data->nSortedOrder);
1362 : : }
1363 : :
1364 : : /* v 1.05 */
1365 : 216 : FreeExtOrigAtData(orig_at_data->polymer, orig_at_data->v3000);
1366 : :
1367 : 216 : memset(orig_at_data, 0, sizeof(*orig_at_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1368 : :
1369 : 216 : return;
1370 : : }
1371 : :
1372 : : /****************************************************************************
1373 : : Free v. 1.05 extensions stuff
1374 : : ****************************************************************************/
1375 : 216 : void FreeExtOrigAtData(OAD_Polymer *pd, OAD_V3000 *v3k)
1376 : : {
1377 : : int k;
1378 : :
1379 : 216 : OAD_Polymer_Free(pd);
1380 : 216 : pd = NULL;
1381 : :
1382 [ + + ]: 216 : if (v3k)
1383 : : {
1384 [ + - ]: 96 : if (v3k->atom_index_orig)
1385 : : {
1386 [ + - ]: 96 : inchi_free(v3k->atom_index_orig);
1387 : 96 : v3k->atom_index_orig = NULL;
1388 : : }
1389 [ + - ]: 96 : if (v3k->atom_index_fin)
1390 : : {
1391 [ + - ]: 96 : inchi_free(v3k->atom_index_fin);
1392 : 96 : v3k->atom_index_fin = NULL;
1393 : : }
1394 [ + + + - ]: 96 : if (v3k->n_haptic_bonds && v3k->lists_haptic_bonds)
1395 : : {
1396 [ + + ]: 10 : for (k = 0; k < v3k->n_haptic_bonds; k++)
1397 [ + - ]: 6 : if (v3k->lists_haptic_bonds[k])
1398 : : {
1399 [ + - ]: 6 : inchi_free(v3k->lists_haptic_bonds[k]);
1400 : 6 : v3k->lists_haptic_bonds[k] = NULL;
1401 : : }
1402 [ + - ]: 4 : inchi_free(v3k->lists_haptic_bonds);
1403 : 4 : v3k->lists_haptic_bonds = NULL;
1404 : : }
1405 [ + + + - ]: 96 : if (v3k->n_steabs && v3k->lists_steabs)
1406 : : {
1407 [ + + ]: 92 : for (k = 0; k < v3k->n_steabs; k++)
1408 [ + - ]: 46 : if (v3k->lists_steabs[k])
1409 : : {
1410 [ + - ]: 46 : inchi_free(v3k->lists_steabs[k]);
1411 : 46 : v3k->lists_steabs[k] = NULL;
1412 : : }
1413 [ + - ]: 46 : inchi_free(v3k->lists_steabs);
1414 : 46 : v3k->lists_steabs = NULL;
1415 : : }
1416 [ + + + - ]: 96 : if (v3k->n_sterel && v3k->lists_sterel)
1417 : : {
1418 [ + + ]: 96 : for (k = 0; k < v3k->n_sterel; k++)
1419 [ + - ]: 62 : if (v3k->lists_sterel[k])
1420 : : {
1421 [ + - ]: 62 : inchi_free(v3k->lists_sterel[k]);
1422 : 62 : v3k->lists_sterel[k] = NULL;
1423 : : }
1424 [ + - ]: 34 : inchi_free(v3k->lists_sterel);
1425 : 34 : v3k->lists_sterel = NULL;
1426 : : }
1427 [ + + + - ]: 96 : if (v3k->n_sterac && v3k->lists_sterac)
1428 : : {
1429 [ + + ]: 146 : for (k = 0; k < v3k->n_sterac; k++)
1430 [ + - ]: 94 : if (v3k->lists_sterac[k])
1431 : : {
1432 [ + - ]: 94 : inchi_free(v3k->lists_sterac[k]);
1433 : 94 : v3k->lists_sterac[k] = NULL;
1434 : : }
1435 [ + - ]: 52 : inchi_free(v3k->lists_sterac);
1436 : 52 : v3k->lists_sterac = NULL;
1437 : : }
1438 : 96 : memset(v3k, 0, sizeof(*v3k)); /* djb-rwth: memset_s C11/Annex K variant? */
1439 [ + - ]: 96 : inchi_free(v3k);
1440 : : }
1441 : :
1442 : 216 : return;
1443 : : }
1444 : :
1445 : : /****************************************************************************/
1446 : :
1447 : 54 : int SetExtOrigAtDataByMolfileExtInput(MOL_FMT_DATA *mfdata,
1448 : : OAD_Polymer **ppPolymer,
1449 : : OAD_V3000 **ppV3000,
1450 : : char *pStrErr)
1451 : : {
1452 : 54 : int k, m, err = 0;
1453 : 54 : OAD_V3000 *pv = NULL;
1454 : 54 : int nsgroups = mfdata->ctab.sgroups.used;
1455 : :
1456 : : /* djb-rwth: addressing coverity ID #499476 -- TREAT_ERR properly used in all cases */
1457 : : /* Polymers */
1458 [ - + ]: 54 : if (nsgroups > 0)
1459 : : {
1460 : : /* Prepare OAD_Polymer container */
1461 : 0 : *ppPolymer = (OAD_Polymer *)inchi_calloc(1, sizeof(OAD_Polymer));
1462 [ # # ]: 0 : if (!(*ppPolymer))
1463 : : {
1464 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1465 : 0 : goto exit_function;
1466 : : }
1467 : :
1468 : : /* Convert Molfile's Sgroup's to OAD_PolymerUnit's */
1469 : 0 : (*ppPolymer)->units = (OAD_PolymerUnit **)inchi_calloc(nsgroups, sizeof((*ppPolymer)->units[0]));
1470 [ # # ]: 0 : if (!(*ppPolymer)->units)
1471 : : {
1472 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1473 : 0 : goto exit_function;
1474 : : }
1475 : 0 : memset((*ppPolymer)->units, 0, sizeof(*(*ppPolymer)->units)); /* djb-rwth: memset_s C11/Annex K variant? */
1476 : :
1477 : 0 : (*ppPolymer)->n = nsgroups;
1478 : 0 : (*ppPolymer)->is_in_reconn = 0;
1479 : 0 : (*ppPolymer)->pzz = NULL;
1480 : 0 : (*ppPolymer)->edit_repeats = 0;
1481 : 0 : (*ppPolymer)->really_do_frame_shift = 0;
1482 : 0 : (*ppPolymer)->frame_shift_scheme = FSS_STARS_CYCLED;
1483 : 0 : (*ppPolymer)->treat = POLYMERS_MODERN;
1484 : :
1485 [ # # ]: 0 : for (k = 0; k < nsgroups; k++)
1486 : : {
1487 : 0 : int q = 0;
1488 : 0 : MOL_FMT_SGROUP *groupk = mfdata->ctab.sgroups.group[k];
1489 : :
1490 : 0 : OAD_PolymerUnit *unitk = (*ppPolymer)->units[k] = (OAD_PolymerUnit *)inchi_calloc(1, sizeof(OAD_PolymerUnit));
1491 : :
1492 [ # # ]: 0 : if (!unitk)
1493 : : {
1494 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1495 : 0 : goto exit_function;
1496 : : }
1497 : :
1498 : 0 : memset(unitk, 0, sizeof(*unitk)); /* djb-rwth: memset_s C11/Annex K variant? */
1499 : 0 : unitk->id = groupk->id;
1500 : 0 : unitk->type = groupk->type;
1501 : 0 : unitk->subtype = groupk->subtype;
1502 : 0 : unitk->conn = groupk->conn;
1503 : 0 : unitk->label = groupk->label;
1504 : :
1505 [ # # ]: 0 : for (q = 0; q < 4; q++)
1506 : : {
1507 : 0 : unitk->xbr1[q] = groupk->xbr1[q];
1508 : 0 : unitk->xbr2[q] = groupk->xbr2[q];
1509 : : }
1510 : 0 : strcpy(unitk->smt, groupk->smt);
1511 : 0 : unitk->na = groupk->alist.used;
1512 : 0 : unitk->alist = (int *)inchi_calloc(unitk->na, sizeof(int));
1513 [ # # ]: 0 : if (!unitk->alist)
1514 : : {
1515 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1516 : 0 : goto exit_function;
1517 : : }
1518 [ # # ]: 0 : for (m = 0; m < unitk->na; m++)
1519 : : {
1520 : 0 : unitk->alist[m] = groupk->alist.item[m];
1521 : : }
1522 : 0 : unitk->nb = groupk->blist.used;
1523 [ # # ]: 0 : if (unitk->nb > 0)
1524 : : {
1525 : 0 : unitk->blist = (int *)inchi_calloc(2 * (long long)unitk->nb, sizeof(int)); /* djb-rwth: cast operator added */
1526 [ # # ]: 0 : if (!unitk->blist)
1527 : : {
1528 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1529 : 0 : goto exit_function;
1530 : : }
1531 [ # # ]: 0 : for (m = 0; m < groupk->blist.used; m++)
1532 : : {
1533 : : int ib, ia1, ia2;
1534 : 0 : ib = groupk->blist.item[m];
1535 [ # # # # ]: 0 : if (ib < 1 || ib > mfdata->ctab.n_bonds)
1536 : : {
1537 [ # # ]: 0 : TREAT_ERR(err, 9004, "Polymer unit in Molfile refers to invalid bond");
1538 : 0 : goto exit_function;
1539 : : }
1540 : 0 : ia1 = mfdata->ctab.bonds[ib - 1].atnum1;
1541 : 0 : ia2 = mfdata->ctab.bonds[ib - 1].atnum2;
1542 : 0 : unitk->blist[2 * m] = ia1;
1543 : 0 : unitk->blist[2 * m + 1] = ia2;
1544 [ # # ]: 0 : if (!strcmp(mfdata->ctab.atoms[ia1 - 1].symbol, "H") ||
1545 [ # # ]: 0 : !strcmp(mfdata->ctab.atoms[ia2 - 1].symbol, "H"))
1546 : : {
1547 [ # # ]: 0 : TREAT_ERR(err, 9002, "Hydrogen as polymer end group is not supported");
1548 : 0 : goto exit_function;
1549 : : }
1550 : : }
1551 : : }
1552 : : else
1553 : : {
1554 : 0 : unitk->blist = NULL;
1555 : : }
1556 : : }
1557 : : }
1558 : :
1559 : : /* V3000 Extensions */
1560 [ + + ]: 54 : if (mfdata->ctab.v3000)
1561 : : {
1562 : : int nn;
1563 : 48 : MOL_FMT_v3000 *mpv = mfdata->ctab.v3000;
1564 : :
1565 : 48 : *ppV3000 = (OAD_V3000 *)inchi_calloc(1, sizeof(OAD_V3000));
1566 : 48 : pv = *ppV3000;
1567 [ - + ]: 48 : if (!pv)
1568 : : {
1569 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1570 : 0 : goto exit_function;
1571 : : }
1572 : 48 : memset(pv, 0, sizeof(*pv)); /* djb-rwth: memset_s C11/Annex K variant? */
1573 : :
1574 : 48 : pv->n_collections = mpv->n_collections;
1575 : 48 : pv->n_haptic_bonds = mpv->n_haptic_bonds;
1576 : 48 : pv->n_non_haptic_bonds = mpv->n_non_haptic_bonds;
1577 : 48 : pv->n_sgroups = mpv->n_sgroups;
1578 : 48 : pv->n_non_star_atoms = mpv->n_non_star_atoms;
1579 : 48 : pv->n_star_atoms = mpv->n_star_atoms;
1580 : 48 : pv->n_steabs = mpv->n_steabs;
1581 : 48 : pv->n_sterac = mpv->n_sterac;
1582 : 48 : pv->n_sterel = mpv->n_sterel;
1583 : 48 : pv->n_3d_constraints = mpv->n_3d_constraints;
1584 : :
1585 [ + - ]: 48 : if (mpv->atom_index_orig)
1586 : : {
1587 : 48 : pv->atom_index_orig = (int *)inchi_calloc(mfdata->ctab.n_atoms, sizeof(int));
1588 [ - + ]: 48 : if (NULL == pv->atom_index_orig)
1589 : : {
1590 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1591 : 0 : goto exit_function;
1592 : : }
1593 : 48 : memcpy(pv->atom_index_orig, mpv->atom_index_orig, mfdata->ctab.n_atoms);
1594 : : }
1595 [ + - ]: 48 : if (mpv->atom_index_fin)
1596 : : {
1597 : 48 : pv->atom_index_fin = (int *)inchi_calloc(mfdata->ctab.n_atoms, sizeof(int));
1598 [ - + ]: 48 : if (NULL == pv->atom_index_fin)
1599 : : {
1600 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1601 : 0 : goto exit_function;
1602 : : }
1603 : 48 : memcpy(pv->atom_index_fin, mpv->atom_index_fin, mfdata->ctab.n_atoms);
1604 : : }
1605 [ + + + - ]: 48 : if (mpv->n_haptic_bonds && mpv->haptic_bonds)
1606 : : {
1607 : 2 : pv->lists_haptic_bonds = (int **)inchi_calloc(mpv->n_haptic_bonds, sizeof(int *));
1608 [ - + ]: 2 : if (NULL == pv->lists_haptic_bonds)
1609 : : {
1610 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1611 : 0 : goto exit_function;
1612 : : }
1613 [ + + ]: 5 : for (m = 0; m < mpv->n_haptic_bonds; m++)
1614 : : {
1615 : 3 : int *lst = NULL;
1616 : 3 : int *mol_lst = mpv->haptic_bonds->lists[m];
1617 : 3 : nn = mol_lst[2] + 3;
1618 : 3 : lst = pv->lists_haptic_bonds[m] = (int *)inchi_calloc(nn, sizeof(int));
1619 [ - + ]: 3 : if (NULL == lst)
1620 : : {
1621 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1622 : 0 : goto exit_function;
1623 : : }
1624 [ + + ]: 24 : for (k = 0; k < nn; k++)
1625 : : {
1626 : 21 : lst[k] = mol_lst[k];
1627 : : }
1628 : : }
1629 : : }
1630 [ + + + - ]: 48 : if (mpv->n_steabs && mpv->steabs)
1631 : : {
1632 : 23 : pv->lists_steabs = (int **)inchi_calloc(mpv->n_steabs, sizeof(int *));
1633 [ - + ]: 23 : if (NULL == pv->lists_steabs)
1634 : : {
1635 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1636 : 0 : goto exit_function;
1637 : : }
1638 [ + + ]: 46 : for (m = 0; m < mpv->n_steabs; m++)
1639 : : {
1640 : 23 : int *lst = NULL;
1641 : 23 : int *mol_lst = mpv->steabs->lists[m];
1642 : 23 : nn = mol_lst[1] + 2;
1643 : 23 : lst = pv->lists_steabs[m] = (int *)inchi_calloc(nn, sizeof(int));
1644 [ - + ]: 23 : if (NULL == lst)
1645 : : {
1646 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1647 : 0 : goto exit_function;
1648 : : }
1649 [ + + ]: 119 : for (k = 0; k < nn; k++)
1650 : : {
1651 : 96 : lst[k] = mol_lst[k];
1652 : : }
1653 : : }
1654 : : }
1655 [ + + + - ]: 48 : if (mpv->n_sterac && mpv->sterac)
1656 : : {
1657 : 26 : pv->lists_sterac = (int **)inchi_calloc(mpv->n_sterac, sizeof(int *));
1658 [ - + ]: 26 : if (NULL == pv->lists_sterac)
1659 : : {
1660 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1661 : 0 : goto exit_function;
1662 : : }
1663 [ + + ]: 73 : for (m = 0; m < mpv->n_sterac; m++)
1664 : : {
1665 : 47 : int *lst = NULL;
1666 : 47 : int *mol_lst = mpv->sterac->lists[m];
1667 : 47 : nn = mol_lst[1] + 2;
1668 : 47 : lst = pv->lists_sterac[m] = (int *)inchi_calloc(nn, sizeof(int));
1669 [ - + ]: 47 : if (NULL == lst)
1670 : : {
1671 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1672 : 0 : goto exit_function;
1673 : : }
1674 [ + + ]: 211 : for (k = 0; k < nn; k++)
1675 : : {
1676 : 164 : lst[k] = mol_lst[k];
1677 : : }
1678 : : }
1679 : : }
1680 [ + + - + ]: 48 : if (mpv->n_sterel && mpv->sterel)
1681 : : {
1682 : 17 : pv->lists_sterel = (int **)inchi_calloc(mpv->n_sterel, sizeof(int *));
1683 [ - + ]: 17 : if (NULL == pv->lists_sterel)
1684 : : {
1685 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1686 : 0 : goto exit_function;
1687 : : }
1688 [ + + ]: 48 : for (m = 0; m < mpv->n_sterel; m++)
1689 : : {
1690 : 31 : int *lst = NULL;
1691 : 31 : int *mol_lst = mpv->sterel->lists[m];
1692 : 31 : nn = mol_lst[1] + 2;
1693 : 31 : lst = pv->lists_sterel[m] = (int *)inchi_calloc(nn, sizeof(int));
1694 [ - + ]: 31 : if (NULL == lst)
1695 : : {
1696 [ # # ]: 0 : TREAT_ERR(err, 9001, "Out of RAM");
1697 : 0 : goto exit_function;
1698 : : }
1699 [ + + ]: 144 : for (k = 0; k < nn; k++)
1700 : : {
1701 : 113 : lst[k] = mol_lst[k];
1702 : : }
1703 : : }
1704 : : }
1705 : : }
1706 : :
1707 : 54 : exit_function:
1708 [ - + ]: 54 : if (err)
1709 : : {
1710 : 0 : FreeExtOrigAtData((*ppPolymer), pv);
1711 : 0 : *ppPolymer = NULL;
1712 : : }
1713 : :
1714 : 54 : return err;
1715 : : }
|