Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : :
7 : : /*
8 : : Reading input data
9 : :
10 : : Prepare and make edits
11 : :
12 : : */
13 : :
14 : : #include <stdlib.h>
15 : : #include <string.h>
16 : : #include <stdarg.h>
17 : : #include <errno.h>
18 : : #include <limits.h>
19 : : #include <math.h>
20 : : #include <ctype.h>
21 : :
22 : : #include "mode.h"
23 : : #include "ichitime.h"
24 : : #ifndef COMPILE_ANSI_ONLY
25 : : #include <conio.h>
26 : : #endif
27 : :
28 : : #include "ichister.h"
29 : :
30 : : #include "ichimain.h"
31 : : #include "ichi_io.h"
32 : : #include "mol_fmt.h"
33 : : #include "inchi_api.h"
34 : : #include "readinch.h"
35 : : #ifdef TARGET_LIB_FOR_WINCHI
36 : : #include "../../../IChI_lib/src/ichi_lib.h"
37 : : #include "inchi_api.h"
38 : : #else
39 : : #include "inchi_gui.h"
40 : : #endif
41 : : #include "readinch.h"
42 : :
43 : : #include "ichirvrs.h"
44 : :
45 : : #include "bcf_s.h"
46 : :
47 : : /* Modified in-CRU stereoventer info */
48 : : typedef struct tagModSCenterInfo
49 : : {
50 : : int num; /* atnums are 0-based, internal ones */
51 : : int valence;
52 : : int n_stereo;
53 : : int nbr[MAXVAL];
54 : : int new_nbr[MAXVAL];
55 : : } ModSCenterInfo;
56 : :
57 : : typedef struct tagDiylFrag
58 : : {
59 : : int na; /* number of atoms */
60 : : int nb; /* number of bonds */
61 : : int end1; /* "starting" end */
62 : : int end2; /* "ending" end */
63 : : int *alist; /* list of atoms orig numbers */
64 : : int *xclist; /* list of atoms extended classes */
65 : : INCHI_IOS_STRING sig; /* string signature */
66 : : } DiylFrag;
67 : :
68 : : static DiylFrag* DiylFrag_New( int na, int e1nd, int end2, char *s );
69 : : static void DiylFrag_Free( DiylFrag *pfrag );
70 : : static void DiylFrag_MakeSignature( DiylFrag *pfrag, int nxc, int *xc, int *tmp );
71 : : static int DiylFrag_Diff( DiylFrag *pfrag1, DiylFrag *pfrag2 );
72 : : static void DiylFrag_DebugTrace( DiylFrag *pfrag );
73 : :
74 : : static int NDefStereoBonds( inp_ATOM *at, int iatom, int bOnlyPointedEndMatters );
75 : :
76 : : static void ModSCenter_Init( ModSCenterInfo *scinfo, inp_ATOM *at, int iatom );
77 : : static void ModSCenter_AddTo( ModSCenterInfo *scinfo, int iadd );
78 : : static void ModSCenter_DelFrom( ModSCenterInfo *scinfo, int idel );
79 : : static int ModSCenter_IsChanged( ModSCenterInfo *scinfo, inp_ATOM *at );
80 : :
81 : : static int GetFrameShiftInfoFrom105PlusInChI( char *sinchi, int *alist, int max_crossing );
82 : : /* static int IsPolymerRequiringEdits(ORIG_ATOM_DATA* orig_inp_data); */ /* djb-rwth: function definition not found*/
83 : : static int analyze_CRU_folding( ORIG_ATOM_DATA *orig_at_data,
84 : : int iunit,
85 : : int n_all_bkb,
86 : : int *all_bkb,
87 : : int nxclasses,
88 : : int *xc,
89 : : OAD_StructureEdits *ed );
90 : : static int count_colors_in_sequence( int *entries, int n_entries, int max_distinct, int *counts );
91 : : static int len_repeating_subsequence( int *color, int *color2, int n );
92 : :
93 : :
94 : :
95 : : /****************************************************************************
96 : : Get (the next) one portion of input data of any possible kind
97 : : (Molfile, InChI string, ...) from a sequential input stream
98 : : ****************************************************************************/
99 : 121 : int GetOneStructure( INCHI_CLOCK *ic,
100 : : STRUCT_DATA *sd,
101 : : INPUT_PARMS *ip,
102 : : char *szTitle,
103 : : INCHI_IOSTREAM *inp_file,
104 : : INCHI_IOSTREAM *log_file,
105 : : INCHI_IOSTREAM *out_file,
106 : : INCHI_IOSTREAM *prb_file,
107 : : ORIG_ATOM_DATA *orig_inp_data,
108 : : long *num_inp,
109 : : STRUCT_FPTRS *struct_fptrs )
110 : : {
111 : 121 : int nRet, inp_index, out_index, bUseFptr = ( NULL != struct_fptrs );
112 : :
113 : 121 : FreeOrigAtData( orig_inp_data );
114 : :
115 : : /* added for TARGET_LIB_FOR_WINCHI early EOF detection */
116 : 121 : inp_index = -1;
117 : 121 : out_index = -1;
118 : :
119 [ - + ]: 121 : if (struct_fptrs)
120 : : {
121 [ # # ]: 0 : if (inp_file->f == stdin)
122 : : {
123 : 0 : return _IS_FATAL;
124 : : }
125 [ # # ]: 0 : if (ip->nInputType == INPUT_CMLFILE)
126 : : {
127 : 0 : bUseFptr = 0;
128 : : }
129 : :
130 : : /* Initially allocate or increase length of struct_fptrs->fptr array */
131 [ # # # # ]: 0 : if (!struct_fptrs->fptr || struct_fptrs->len_fptr <= struct_fptrs->cur_fptr + 1)
132 : : {
133 : :
134 : : INCHI_FPTR *new_fptr = (INCHI_FPTR *)
135 : 0 : inchi_calloc( (long long)struct_fptrs->len_fptr + ADD_LEN_STRUCT_FPTRS, sizeof( new_fptr[0] ) ); /* djb-rwth: cast operator added */
136 : :
137 [ # # ]: 0 : if (new_fptr)
138 : : {
139 [ # # ]: 0 : if (struct_fptrs->fptr)
140 : : {
141 [ # # ]: 0 : if (struct_fptrs->len_fptr)
142 : : {
143 : 0 : memcpy(new_fptr, struct_fptrs->fptr, struct_fptrs->len_fptr * sizeof(new_fptr[0]));
144 : : }
145 [ # # ]: 0 : inchi_free( struct_fptrs->fptr );
146 : : }
147 : : else
148 : : {
149 : 0 : struct_fptrs->len_fptr = 0;
150 : 0 : struct_fptrs->cur_fptr = 0;
151 : 0 : struct_fptrs->max_fptr = 0;
152 : : }
153 : 0 : struct_fptrs->len_fptr += ADD_LEN_STRUCT_FPTRS;
154 : 0 : struct_fptrs->fptr = new_fptr;
155 : : }
156 : : else
157 : : {
158 : 0 : return _IS_FATAL; /* new_fptr allocation error */
159 : : }
160 : : }
161 : :
162 [ # # ]: 0 : if (struct_fptrs->fptr[struct_fptrs->cur_fptr] == EOF)
163 : : {
164 : 0 : return _IS_EOF;
165 : : }
166 : : else
167 : : {
168 : :
169 [ # # ]: 0 : if (bUseFptr)
170 : : {
171 [ # # ]: 0 : if (fseek( inp_file->f,
172 : 0 : struct_fptrs->fptr[struct_fptrs->cur_fptr],
173 : : SEEK_SET ))
174 : : {
175 : 0 : return _IS_FATAL;
176 : : }
177 [ # # ]: 0 : if (struct_fptrs->cur_fptr &&
178 [ # # ]: 0 : struct_fptrs->max_fptr <= struct_fptrs->cur_fptr)
179 : : {
180 : 0 : return _IS_FATAL;
181 : : }
182 : : }
183 : : else
184 : : {
185 : 0 : inp_index = struct_fptrs->fptr[struct_fptrs->cur_fptr];
186 : 0 : out_index = EOF;
187 : : }
188 : : }
189 : :
190 : 0 : *num_inp = struct_fptrs->cur_fptr; /* set structure count */
191 : : }
192 : :
193 : :
194 : 121 : nRet = ReadTheStructure( ic, sd, ip, inp_file, orig_inp_data, inp_index, &out_index );
195 : :
196 [ + - ]: 121 : if (!nRet)
197 : : {
198 [ + - - + : 121 : if (ip->nInputType == INPUT_INCHI_PLAIN || ip->nInputType == INPUT_MOLFILE || ip->nInputType == INPUT_SDFILE)
- - ]
199 : : {
200 [ - + ]: 121 : if (ip->lMolfileNumber)
201 : : {
202 : 0 : *num_inp = ip->lMolfileNumber;
203 : : }
204 : : else
205 : : {
206 : 121 : *num_inp += 1;
207 : : }
208 : : }
209 : : else
210 : : {
211 : 0 : *num_inp += 1;
212 : : }
213 : :
214 : 121 : nRet = TreatErrorsInReadTheStructure( sd, ip, LOG_MASK_ALL,
215 : : inp_file, log_file, out_file, prb_file,
216 : : orig_inp_data, num_inp );
217 : : }
218 : :
219 : : /************************************************************
220 : : Added for TARGET_LIB_FOR_WINCHI:
221 : : look ahead for end of file detection
222 : : ************************************************************/
223 [ - + ]: 121 : if ( inp_file->type == INCHI_IOS_TYPE_FILE &&
224 [ # # # # : 0 : inp_file->f && struct_fptrs && struct_fptrs->fptr &&
# # ]
225 [ # # ]: 0 : struct_fptrs->fptr[struct_fptrs->cur_fptr + 1] <= 0 )
226 : : {
227 : :
228 : 0 : int nRet2 = 0;
229 : 0 : INCHI_FPTR next_fptr = 0;
230 : : STRUCT_DATA sd2;
231 : :
232 [ # # # # ]: 0 : if (nRet != _IS_EOF && nRet != _IS_FATAL)
233 : : {
234 [ # # # # ]: 0 : if (inp_file->f == stdin || struct_fptrs->len_fptr <= struct_fptrs->cur_fptr + 1)
235 : : {
236 : 0 : return _IS_FATAL;
237 : : }
238 : : /* Get the next structure fptr */
239 [ # # ]: 0 : if (bUseFptr)
240 : : {
241 : 0 : next_fptr = ftell( inp_file->f );
242 : : }
243 : : else
244 : : {
245 : 0 : inp_index = out_index;
246 : 0 : out_index = EOF;
247 : : }
248 : :
249 : : /* Read the next structure */
250 : 0 : nRet2 = ReadTheStructure( ic, &sd2, ip, inp_file,
251 : : NULL, inp_index, &out_index );
252 : :
253 : : /* Restore fptr to the next structure */
254 [ # # ]: 0 : if (bUseFptr)
255 : : {
256 [ # # ]: 0 : if (next_fptr != -1L)
257 : : {
258 : 0 : fseek( inp_file->f, next_fptr, SEEK_SET );
259 : : }
260 : : }
261 : : }
262 : : else
263 : : {
264 : : /* Treat current fatal error as end of file */
265 : 0 : struct_fptrs->fptr[struct_fptrs->cur_fptr] = EOF;
266 : : }
267 : :
268 : : /* Next is end of file or fatal */
269 [ # # # # : 0 : if (nRet == _IS_EOF || nRet == _IS_FATAL ||
# # ]
270 [ # # ]: 0 : nRet2 == _IS_EOF || nRet2 == _IS_FATAL)
271 : : {
272 : 0 : struct_fptrs->fptr[struct_fptrs->cur_fptr + 1] = EOF;
273 : : }
274 : : else
275 : : {
276 [ # # ]: 0 : struct_fptrs->fptr[struct_fptrs->cur_fptr + 1] = bUseFptr ? sd->fPtrEnd : inp_index;
277 : : }
278 : :
279 : : /* Update struct_fptrs->max_fptr */
280 [ # # ]: 0 : if (struct_fptrs->max_fptr <= struct_fptrs->cur_fptr + 1)
281 : : {
282 : 0 : struct_fptrs->max_fptr = struct_fptrs->cur_fptr + 2;
283 : : }
284 : : }
285 : :
286 [ - - + ]: 121 : switch (nRet)
287 : : {
288 : 0 : case _IS_EOF:
289 : 0 : *num_inp -= 1;
290 : 0 : case _IS_FATAL:
291 : : case _IS_ERROR:
292 : : case _IS_SKIP:
293 : 0 : goto exit_function;
294 : : }
295 : :
296 : : /*
297 : : if ( !orig_inp_data->num_dimensions ) {
298 : : WarningMessage(sd->pStrErrStruct, "0D"); */ /* 0D-structure: no coordinates
299 : : }
300 : : */
301 : :
302 : 121 : exit_function:
303 : 121 : return nRet;
304 : : }
305 : :
306 : : /** @nnuk
307 : : ****************************************************************************
308 : : Build a component-local mask of polymer crossing-bond endpoints.
309 : :
310 : : The polymer crossing-bond list (OAD_PolymerUnit.blist) uses whole-structure,
311 : : 1-based atom numbering, whereas inp_cur_data contains only atoms from the
312 : : selected connected component. ExtractConnectedComponent() preserves the original
313 : : atom order within the component, allowing the corresponding local atom index to
314 : : be reconstructed.
315 : :
316 : : The mask is later consulted by remove_terminal_HDT() to preserve explicit
317 : : H/D/T atoms that participate in polymer crossing bonds.
318 : :
319 : : @param inp_cur_data chemical structure information for the current component
320 : : @param orig_inp_data chemical structure information for the whole structure
321 : : @param ip input parameters
322 : : @param component_number number of component in the chemical structure
323 : :
324 : : @return Return 0 on success or when no mask is required; return -1 on allocation
325 : : failure.
326 : : ****************************************************************************/
327 : 161 : static int BuildPolymerCrossingBondEndpointMask(INP_ATOM_DATA *inp_cur_data,
328 : : const ORIG_ATOM_DATA *orig_inp_data,
329 : : const INPUT_PARMS *ip,
330 : : int component_number)
331 : : {
332 : : int orig_idx;
333 : 161 : int local_idx = 0;
334 : : int unit_idx;
335 : : int endpoint_idx;
336 : :
337 [ + - + + ]: 161 : if (inp_cur_data->num_at <= 0 || ip->bPolymers == POLYMERS_NO ||
338 [ + - + - ]: 2 : !orig_inp_data->valid_polymer || !orig_inp_data->polymer ||
339 [ - + ]: 2 : orig_inp_data->polymer->n <= 0)
340 : : {
341 : 159 : return 0;
342 : : }
343 : :
344 : : /* No mask is needed if this component contains no explicit H/D/T atoms. */
345 [ + - ]: 10 : for (local_idx = 0; local_idx < inp_cur_data->num_at; local_idx++)
346 : : {
347 : 10 : const char *elname = inp_cur_data->at[local_idx].elname;
348 : :
349 [ + - + + : 10 : if (elname[1] == '\0' && (elname[0] == 'H' || elname[0] == 'D' || elname[0] == 'T'))
+ - + - ]
350 : : {
351 : : break;
352 : : }
353 : : }
354 : :
355 [ - + ]: 2 : if (local_idx == inp_cur_data->num_at)
356 : : {
357 : 0 : return 0;
358 : : }
359 : :
360 : 2 : local_idx = 0;
361 : :
362 : 2 : inp_cur_data->keep_explicit_HDT = (unsigned char *)inchi_calloc((long long)inp_cur_data->num_at, sizeof(inp_cur_data->keep_explicit_HDT[0]));
363 : :
364 [ - + ]: 2 : if (!inp_cur_data->keep_explicit_HDT)
365 : : {
366 : 0 : return -1;
367 : : }
368 : :
369 [ + + ]: 12 : for (orig_idx = 0; orig_idx < orig_inp_data->num_inp_atoms; orig_idx++)
370 : : {
371 [ - + ]: 10 : if (orig_inp_data->at[orig_idx].component != component_number)
372 : : {
373 : 0 : continue;
374 : : }
375 : :
376 : : /*
377 : : * The mask is consulted only for explicit H/D/T atoms by
378 : : * remove_terminal_HDT(), so heavy-atom and pseudoatom endpoints
379 : : * do not need to be marked.
380 : : */
381 [ + - ]: 10 : if (!(orig_inp_data->at[orig_idx].elname[1] == '\0' &&
382 [ + + ]: 10 : (orig_inp_data->at[orig_idx].elname[0] == 'H' ||
383 [ + - ]: 8 : orig_inp_data->at[orig_idx].elname[0] == 'D' ||
384 [ + - ]: 8 : orig_inp_data->at[orig_idx].elname[0] == 'T')))
385 : : {
386 : 8 : local_idx++;
387 : 8 : continue;
388 : : }
389 : :
390 [ + - ]: 2 : for (unit_idx = 0; unit_idx < orig_inp_data->polymer->n; unit_idx++)
391 : : {
392 : 2 : const OAD_PolymerUnit *u = orig_inp_data->polymer->units[unit_idx];
393 : :
394 [ + - - + ]: 2 : if (!u || !u->blist)
395 : : {
396 : 0 : continue;
397 : : }
398 : :
399 : : /*
400 : : * Each crossing bond contributes two atom numbers to blist.
401 : : * blist uses whole-structure, 1-based atom numbering.
402 : : */
403 [ + - ]: 8 : for (endpoint_idx = 0; endpoint_idx < 2 * u->nb; endpoint_idx++)
404 : : {
405 [ + + ]: 8 : if (u->blist[endpoint_idx] == orig_idx + 1)
406 : : {
407 : 2 : inp_cur_data->keep_explicit_HDT[local_idx] = 1;
408 : 2 : break;
409 : : }
410 : : }
411 : :
412 [ + - ]: 2 : if (inp_cur_data->keep_explicit_HDT[local_idx])
413 : : {
414 : 2 : break;
415 : : }
416 : : }
417 : :
418 : 2 : local_idx++;
419 : : }
420 : :
421 : 2 : return 0;
422 : : }
423 : :
424 : : /****************************************************************************
425 : : Extract one connected component from the input structure
426 : : ****************************************************************************/
427 : 161 : int GetOneComponent( INCHI_CLOCK *ic,
428 : : STRUCT_DATA *sd,
429 : : INPUT_PARMS *ip,
430 : : INCHI_IOSTREAM *log_file,
431 : : INCHI_IOSTREAM *out_file,
432 : : INP_ATOM_DATA *inp_cur_data,
433 : : ORIG_ATOM_DATA *orig_inp_data,
434 : : int i,
435 : : long num_inp )
436 : : {
437 : : inchiTime ulTStart;
438 : :
439 : 161 : InchiTimeGet( &ulTStart );
440 : :
441 : 161 : CreateInpAtomData( inp_cur_data, orig_inp_data->nCurAtLen[i], 0 );
442 : :
443 : 161 : inp_cur_data->num_at = ExtractConnectedComponent( orig_inp_data->at, orig_inp_data->num_inp_atoms, i + 1, inp_cur_data->at );
444 : :
445 [ - + ]: 161 : if (BuildPolymerCrossingBondEndpointMask(inp_cur_data, orig_inp_data, ip, i + 1) < 0)
446 : : {
447 : 0 : AddErrorMessage(sd->pStrErrStruct, "Out of memory while processing polymer data");
448 : :
449 : 0 : sd->nErrorCode = CT_OUT_OF_RAM;
450 : 0 : sd->nErrorType = _IS_FATAL;
451 : :
452 : 0 : sd->ulStructTime += InchiTimeElapsed(ic, &ulTStart);
453 : :
454 : 0 : return sd->nErrorType;
455 : : }
456 : :
457 : 161 : sd->ulStructTime += InchiTimeElapsed( ic, &ulTStart );
458 : :
459 : :
460 : : /* Error processing */
461 [ + - - + ]: 161 : if (inp_cur_data->num_at <= 0 || orig_inp_data->nCurAtLen[i] != inp_cur_data->num_at)
462 : : {
463 : : /* Log error message */
464 : 0 : AddErrorMessage( sd->pStrErrStruct, "Cannot extract Component" );
465 [ # # # # : 0 : inchi_ios_eprint( log_file, "%s #%d structure #%ld.%s%s%s%s\n", sd->pStrErrStruct, i + 1, num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
# # # # #
# # # # #
# # # # #
# # # #
# ]
466 [ # # # # ]: 0 : sd->nErrorCode = inp_cur_data->num_at < 0 ? inp_cur_data->num_at : ( orig_inp_data->nCurAtLen[i] != inp_cur_data->num_at ) ? CT_ATOMCOUNT_ERR : CT_UNKNOWN_ERR;
467 : : /* num_err ++; */
468 : 0 : sd->nErrorType = _IS_ERROR;
469 : : #ifdef TARGET_LIB_FOR_WINCHI
470 : : if (( ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
471 : : ( ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT ))
472 : : {
473 : : sd->nErrorType = ProcessStructError( out_file,
474 : : log_file,
475 : : sd->pStrErrStruct,
476 : : sd->nErrorType,
477 : : num_inp,
478 : : ip );
479 : : }
480 : : #endif
481 : : }
482 : :
483 : 161 : return sd->nErrorType;
484 : : }
485 : :
486 : :
487 : : /****************************************************************************
488 : : Read input data of any possible kind (Molfile, InChI string, ...)
489 : : ****************************************************************************/
490 : 121 : int ReadTheStructure( struct tagINCHI_CLOCK *ic,
491 : : STRUCT_DATA *sd,
492 : : INPUT_PARMS *ip,
493 : : INCHI_IOSTREAM *inp_file,
494 : : ORIG_ATOM_DATA *orig_inp_data,
495 : : /* the further is deprecated (CML support) */
496 : : int inp_index,
497 : : int *out_index )
498 : : {
499 : : inchiTime ulTStart;
500 : 121 : int nRet = 0, nRet2 = 0;
501 : 121 : int bGetOrigCoord = !( ip->bINChIOutputOptions &
502 : : ( INCHI_OUT_NO_AUX_INFO | INCHI_OUT_SHORT_AUX_INFO ) );
503 : :
504 : 121 : INCHI_MODE InpAtomFlags = 0;
505 : : /* NB: reading Molfile may set FLAG_INP_AT_CHIRAL bit */
506 : :
507 : 121 : int vABParityUnknown = AB_PARITY_UNDF;
508 : : /* vABParityUnknown holds actual value of an internal constant */
509 : : /* signifying unknown parity: either the same as for undefined */
510 : : /* parity (default==standard) or a specific one (non-std; */
511 : : /* requested by SLUUD switch). */
512 : :
513 [ - + ]: 121 : if (0 != ( ip->nMode & REQ_MODE_DIFF_UU_STEREO ))
514 : : {
515 : : /* Make labels for unknown and undefined stereo different */
516 : 0 : vABParityUnknown = AB_PARITY_UNKN;
517 : : }
518 : :
519 [ - + ]: 121 : if (ip->bLargeMolecules)
520 : : {
521 : 0 : InpAtomFlags |= FLAG_SET_INP_LARGE_MOLS;
522 : : }
523 : :
524 : 121 : memset( sd, 0, sizeof( *sd ) ); /* djb-rwth: memset_s C11/Annex K variant? */
525 : :
526 [ + - - ]: 121 : switch (ip->nInputType)
527 : : {
528 : :
529 : 121 : case INPUT_MOLFILE:
530 : : case INPUT_SDFILE:
531 : :
532 : : /* Read the original input structure from Molfile */
533 [ + - ]: 121 : if (orig_inp_data)
534 : : {
535 : :
536 [ - + - - ]: 121 : if (ip->pSdfValue && ip->pSdfValue[0])
537 : : {
538 : : /* Added 07-29-2003 to avoid inheriting exact value from prev.
539 : : structure and to make reference to a (bad) structure
540 : : with unknown ID Value */
541 : : char *p, *q; /* q shadows prev declaration of const char *q */
542 : : int n;
543 [ # # ]: 0 : if (( p = strrchr( ip->pSdfValue, '+' ) ) &&
544 [ # # ]: 0 : '[' == *( p - 1 ) &&
545 [ # # ]: 0 : 0 < ( n = strtol( p + 1, &q, 10 ) ) &&
546 [ # # ]: 0 : q[0] &&
547 [ # # ]: 0 : ']' == q[0] &&
548 [ # # ]: 0 : !q[1])
549 : : {
550 : 0 : sprintf(p + 1, "%d]", n + 1);
551 : : }
552 : : else
553 : : {
554 : 0 : strcat(ip->pSdfValue, " [+1]");
555 : : }
556 : : }
557 : :
558 : 121 : InchiTimeGet( &ulTStart );
559 : :
560 [ - + - - ]: 121 : if (inp_file->type == INCHI_IOS_TYPE_FILE && inp_file->f)
561 [ # # ]: 0 : sd->fPtrStart = ( inp_file->f == stdin ) ? -1 : ftell( inp_file->f );
562 : :
563 : :
564 : 121 : nRet2 = CreateOrigInpDataFromMolfile( inp_file,
565 : : orig_inp_data,
566 : : ip->bMergeAllInputStructures,
567 : : bGetOrigCoord,
568 : : ip->bDoNotAddH,
569 : : ip->bPolymers,
570 : : ip->bNPZz,
571 : 121 : ip->pSdfLabel,
572 : : ip->pSdfValue,
573 : : &ip->lSdfId,
574 : : &ip->lMolfileNumber,
575 : : &InpAtomFlags,
576 : : &sd->nStructReadError,
577 : 121 : sd->pStrErrStruct,
578 : : ip->bNoWarnings); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
579 : :
580 : :
581 : :
582 [ - + - - ]: 121 : if (!ip->bGetSdfileId || ip->lSdfId == 999999LU)
583 : : {
584 : 121 : ip->lSdfId = 0LU;
585 : : }
586 : :
587 [ - + - - ]: 121 : if (!ip->bGetMolfileNumber || ip->lMolfileNumber < 0)
588 : : {
589 : 121 : ip->lMolfileNumber = 0;
590 : : }
591 : :
592 [ - + - - ]: 121 : if (inp_file->type == INCHI_IOS_TYPE_FILE && inp_file->f)
593 : : {
594 [ # # ]: 0 : sd->fPtrEnd = ( inp_file->f == stdin ) ? -1 : ftell( inp_file->f );
595 : : }
596 : :
597 : 121 : sd->ulStructTime += InchiTimeElapsed( ic, &ulTStart );
598 : :
599 : : #if ( bRELEASE_VERSION == 0 )
600 : : sd->bExtract |= orig_inp_data->bExtract;
601 : : #endif
602 : :
603 : : /* 2004-11-16: added Molfile Chiral Flag Mode */
604 : : /* ********************************************
605 : : * Chiral flags are set in:
606 : : * - RunICHI.c -- ReadTheStructure()
607 : : * - e_IchiMain.c -- main()
608 : : * - inchi_dll.c -- ExtractOneStructure
609 : : **********************************************/
610 : :
611 : : /* 1. Highest precedence: Chiral Flag set by the user */
612 [ - + ]: 121 : if (ip->bChiralFlag & FLAG_SET_INP_AT_CHIRAL)
613 : : {
614 : 0 : InpAtomFlags = FLAG_INP_AT_CHIRAL; /* forced by the user */
615 : : }
616 [ - + ]: 121 : else if (ip->bChiralFlag & FLAG_SET_INP_AT_NONCHIRAL)
617 : : {
618 : 0 : InpAtomFlags = FLAG_INP_AT_NONCHIRAL; /* forced by the user */
619 : : }
620 [ + + - + ]: 121 : else if (( InpAtomFlags & FLAG_INP_AT_CHIRAL ) && ( InpAtomFlags & FLAG_INP_AT_NONCHIRAL )) /* djb-rwth: correcting &&->& for bitwise calculation? */
621 : : {
622 : 0 : InpAtomFlags &= ~FLAG_INP_AT_NONCHIRAL;
623 : : }
624 : :
625 : : /* Save requested flags in the AuxInfo */
626 : 121 : sd->bChiralFlag &= ~( FLAG_INP_AT_CHIRAL | FLAG_INP_AT_NONCHIRAL );
627 : 121 : sd->bChiralFlag |= InpAtomFlags & ( FLAG_INP_AT_CHIRAL | FLAG_INP_AT_NONCHIRAL );
628 : :
629 : : /* Quick fix: modify ip->nMode on the fly */
630 : :
631 : : /* 2. The user requested both Stereo AND Chiral flag */
632 [ - + - - ]: 121 : if (( ip->nMode & REQ_MODE_CHIR_FLG_STEREO ) && ( ip->nMode & REQ_MODE_STEREO ))
633 : : {
634 [ # # ]: 0 : if (InpAtomFlags & FLAG_INP_AT_CHIRAL)
635 : : {
636 : : /* structure has chiral flag or the user said it is chiral */
637 : 0 : ip->nMode &= ~( REQ_MODE_RELATIVE_STEREO | REQ_MODE_RACEMIC_STEREO );
638 : 0 : sd->bChiralFlag |= FLAG_INP_AT_CHIRAL; /* write AuxInfo as chiral */
639 : : }
640 : : else
641 : : {
642 : 0 : ip->nMode &= ~REQ_MODE_RACEMIC_STEREO;
643 : 0 : ip->nMode |= REQ_MODE_RELATIVE_STEREO;
644 : 0 : sd->bChiralFlag |= FLAG_INP_AT_NONCHIRAL; /* write AuxInfo as explicitly not chiral */
645 : : }
646 : : }
647 : : } /* if ( orig_inp_data ) */
648 : :
649 : : else /* !orig_inp_data */
650 : : {
651 : : /* read the next original structure */
652 : 0 : int nStructReadError = 0;
653 : :
654 [ # # ]: 0 : if (!ip->bMergeAllInputStructures)
655 : : {
656 : 0 : nRet2 = CreateOrigInpDataFromMolfile( inp_file,
657 : : NULL, /* *orig_at_data, */
658 : : 0, /* bMergeAllInputStructures */
659 : : 0, /* bGetOrigCoord */
660 : : 0, /* bDoNotAddH */
661 : : 0, /* ip->bPolymers */
662 : : 0, /* ip->bNPZz */
663 : : NULL, /* *pSdfLabel */
664 : : NULL, /* *pSdfValue */
665 : : NULL, /* *lSdfId */
666 : : NULL, /* *lMolfileNumber */
667 : : &InpAtomFlags, /*NULL, */
668 : : &nStructReadError,
669 : : NULL, /* *pStrErr */
670 : : 0);
671 : :
672 [ # # # # : 0 : if (nRet2 <= 0 && 10 < nStructReadError && nStructReadError < 20)
# # ]
673 : : {
674 : 0 : return _IS_EOF;
675 : : }
676 : : }
677 : : else
678 : : {
679 : 0 : return _IS_EOF;
680 : : }
681 : : }
682 : :
683 : 121 : break;
684 : :
685 : 0 : case INPUT_INCHI_PLAIN:
686 : : /* Read the original input data as text (InChI string ) */
687 [ # # ]: 0 : if (orig_inp_data)
688 : : {
689 [ # # # # ]: 0 : if (ip->pSdfValue && ip->pSdfValue[0])
690 : : {
691 : : /* Added 07-29-2003 to avoid inheriting exact value from prev. structure
692 : : and to make reference to a (bad) structure with unknown ID Value */
693 : : char *p, *q;
694 : : int n;
695 [ # # ]: 0 : if (( p = strrchr( ip->pSdfValue, '+' ) ) &&
696 [ # # ]: 0 : '[' == *( p - 1 ) &&
697 [ # # ]: 0 : 0 < ( n = strtol( p + 1, &q, 10 ) ) &&
698 [ # # ]: 0 : q[0] &&
699 [ # # ]: 0 : ']' == q[0] &&
700 [ # # ]: 0 : !q[1])
701 : : {
702 : 0 : sprintf(p + 1, "%d]", n + 1);
703 : : }
704 : : else
705 : : {
706 : 0 : strcat(ip->pSdfValue, " [+1]");
707 : : }
708 : : }
709 : :
710 : 0 : InchiTimeGet( &ulTStart );
711 : :
712 [ # # # # ]: 0 : if (inp_file->type == INCHI_IOS_TYPE_FILE && inp_file->f)
713 : : {
714 [ # # ]: 0 : sd->fPtrStart = ( inp_file->f == stdin ) ? -1 : ftell( inp_file->f );
715 : : }
716 : :
717 : :
718 : : /* Read and make internal molecular data */
719 : 0 : nRet2 = InchiToOrigAtom( inp_file,
720 : : orig_inp_data,
721 : : ip->bMergeAllInputStructures,
722 : : bGetOrigCoord,
723 : : ip->bDoNotAddH,
724 : : vABParityUnknown,
725 : : ip->nInputType,
726 : : ip->pSdfLabel,
727 : : ip->pSdfValue,
728 : 0 : (unsigned long *) &ip->lMolfileNumber,
729 : : &InpAtomFlags,
730 : : &sd->nStructReadError,
731 : 0 : sd->pStrErrStruct ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
732 : :
733 : : /*if ( !ip->bGetSdfileId || ip->lSdfId == 999999LU) ip->lSdfId = 0;*/
734 [ # # # # ]: 0 : if (inp_file->type == INCHI_IOS_TYPE_FILE && inp_file->f)
735 : : {
736 [ # # ]: 0 : sd->fPtrEnd = ( inp_file->f == stdin ) ? -1 : ftell( inp_file->f );
737 : : }
738 : :
739 : 0 : sd->ulStructTime += InchiTimeElapsed( ic, &ulTStart );
740 : :
741 : : #if ( bRELEASE_VERSION == 0 )
742 : : sd->bExtract |= orig_inp_data->bExtract;
743 : : #endif
744 : :
745 : : /* 2004-11-16: added Molfile Chiral Flag Mode */
746 [ # # ]: 0 : if (ip->bChiralFlag & FLAG_SET_INP_AT_CHIRAL)
747 : : {
748 : 0 : InpAtomFlags = FLAG_INP_AT_CHIRAL; /* forced by the user */
749 : : }
750 [ # # ]: 0 : else if (ip->bChiralFlag & FLAG_SET_INP_AT_NONCHIRAL)
751 : : {
752 : 0 : InpAtomFlags = FLAG_INP_AT_NONCHIRAL; /* forced by the user */
753 : : }
754 [ # # # # ]: 0 : else if (( InpAtomFlags & FLAG_INP_AT_CHIRAL ) && ( InpAtomFlags & FLAG_INP_AT_NONCHIRAL )) /* djb-rwth: correcting &&->& for bitwise calculation? */
755 : : {
756 : 0 : InpAtomFlags &= ~FLAG_INP_AT_NONCHIRAL;
757 : : }
758 : :
759 : 0 : sd->bChiralFlag |= InpAtomFlags; /* copy chiral flag to AuxInfo */
760 : :
761 : : /* Quick fix: modify ip->nMode on the fly */
762 [ # # # # ]: 0 : if (( ip->nMode & REQ_MODE_CHIR_FLG_STEREO ) && ( ip->nMode & REQ_MODE_STEREO ))
763 : : {
764 [ # # ]: 0 : if (InpAtomFlags & FLAG_INP_AT_CHIRAL)
765 : : {
766 : 0 : ip->nMode &= ~( REQ_MODE_RELATIVE_STEREO | REQ_MODE_RACEMIC_STEREO );
767 : : }
768 : : else
769 : : {
770 : 0 : ip->nMode &= ~REQ_MODE_RACEMIC_STEREO;
771 : 0 : ip->nMode |= REQ_MODE_RELATIVE_STEREO;
772 : : }
773 : : }
774 : : }
775 : : else
776 : : {
777 : : /* Read the next original structure */
778 : 0 : int nStructReadError = 0;
779 [ # # ]: 0 : if (!ip->bMergeAllInputStructures)
780 : : {
781 : 0 : nRet2 = InchiToOrigAtom( inp_file,
782 : : NULL, 0, 0, 0, 0,
783 : : ip->nInputType,
784 : : NULL, NULL, NULL, NULL,
785 : : &nStructReadError,
786 : : NULL );
787 [ # # # # : 0 : if (nRet2 <= 0 && 10 < nStructReadError && nStructReadError < 20)
# # ]
788 : : {
789 : 0 : return _IS_EOF;
790 : : }
791 : : }
792 : : else
793 : : {
794 : 0 : return _IS_EOF;
795 : : }
796 : : }
797 : 0 : break;
798 : :
799 : 0 : default:
800 : 0 : nRet = _IS_FATAL; /* wrong file type */
801 : : }
802 : :
803 : 121 : return nRet;
804 : : }
805 : :
806 : :
807 : : /****************************************************************************
808 : : Interpret and treat input reading errors/warnings
809 : : ****************************************************************************/
810 : 121 : int TreatErrorsInReadTheStructure( STRUCT_DATA *sd,
811 : : INPUT_PARMS *ip,
812 : : int nLogMask,
813 : : INCHI_IOSTREAM *inp_file,
814 : : INCHI_IOSTREAM *log_file,
815 : : INCHI_IOSTREAM *out_file,
816 : : INCHI_IOSTREAM *prb_file,
817 : : ORIG_ATOM_DATA *orig_inp_data,
818 : : long *num_inp )
819 : : {
820 : 121 : int nRet = _IS_OKAY;
821 : :
822 [ - + - - ]: 121 : if (10 < sd->nStructReadError && sd->nStructReadError < 20)
823 : : {
824 : : /* End of file */
825 [ # # ]: 0 : if (sd->pStrErrStruct[0])
826 : : {
827 [ # # # # : 0 : inchi_ios_eprint( log_file, "%s inp structure #%ld: End of file.%s%s%s%s \n", sd->pStrErrStruct, *num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
# # # # #
# # # # #
# # # # #
# # # #
# ]
828 : : }
829 : :
830 : 0 : inchi_ios_eprint( log_file, "End of file detected after structure #%ld. \n", *num_inp - 1 );
831 : :
832 : 0 : nRet = _IS_EOF;
833 : 0 : goto exit_function; /* end of file */
834 : : }
835 : :
836 : : /*(*num_inp) ++;*/
837 : :
838 [ - + ]: 121 : if (*num_inp < ip->first_struct_number)
839 : : {
840 : : /* Skip the structure */
841 : :
842 : : #if ( !defined(TARGET_API_LIB) && !defined(TARGET_EXE_STANDALONE) )
843 : : /* #ifndef TARGET_API_LIB */
844 : : if (log_file->f != stderr)
845 : : inchi_fprintf( stderr, "\rSkipping structure #%ld.%s%s%s%s...", *num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
846 : : #endif
847 : :
848 : 0 : nRet = sd->nErrorType = _IS_SKIP;
849 : 0 : goto exit_function;
850 : : }
851 : :
852 : 242 : sd->nErrorType = GetInpStructErrorType( ip, sd->nStructReadError,
853 : 121 : sd->pStrErrStruct,
854 : : orig_inp_data->num_inp_atoms );
855 : :
856 [ - + ]: 121 : if (sd->nErrorType == _IS_FATAL)
857 : : {
858 : : /* Fatal error */
859 [ # # ]: 0 : if (nLogMask & LOG_MASK_FATAL)
860 : : {
861 : 0 : inchi_ios_eprint( log_file, "Fatal Error %d (aborted; %s) inp structure #%ld.%s%s%s%s\n",
862 [ # # # # : 0 : sd->nStructReadError, sd->pStrErrStruct, *num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
# # # # #
# # # # #
# # # # #
# # # #
# ]
863 : : }
864 : :
865 : : #if ( bRELEASE_VERSION == 1 || EXTR_FLAGS == 0 )
866 : : /* djb-rwth: fixing oss-fuzz issue #27902 */
867 [ # # # # : 0 : if (prb_file && prb_file->f && 0L <= sd->fPtrStart && sd->fPtrStart < sd->fPtrEnd && !ip->bSaveAllGoodStructsAsProblem)
# # # # #
# ]
868 : : {
869 : 0 : MolfileSaveCopy( inp_file, sd->fPtrStart, sd->fPtrEnd, prb_file->f, *num_inp );
870 : : }
871 : : #endif
872 : : /* goto exit_function; */
873 : : }
874 : :
875 [ - + ]: 121 : if (sd->nErrorType == _IS_ERROR)
876 : : {
877 : : /* Non-fatal errors: do not produce INChI */
878 : :
879 : : /* 70 => too many atoms */
880 [ # # ]: 0 : if (nLogMask & LOG_MASK_ERR)
881 : : {
882 : 0 : inchi_ios_eprint( log_file, "Error %d (no %s; %s) inp structure #%ld.%s%s%s%s\n",
883 : 0 : sd->nStructReadError, ( ip->bINChIOutputOptions & INCHI_OUT_SDFILE_ONLY ) ? "Molfile" : INCHI_NAME,
884 [ # # # # : 0 : sd->pStrErrStruct, *num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
885 : : }
886 : :
887 : : #if ( bRELEASE_VERSION == 1 || EXTR_FLAGS == 0 )
888 [ # # # # : 0 : if (prb_file && prb_file->f && 0L <= sd->fPtrStart && sd->fPtrStart < sd->fPtrEnd && !ip->bSaveAllGoodStructsAsProblem)
# # # # #
# ]
889 : : {
890 : 0 : MolfileSaveCopy( inp_file, sd->fPtrStart, sd->fPtrEnd, prb_file->f, *num_inp ); /* djb-rwth: addressing coverity ID #499477 -- return values handled properly */
891 : : }
892 : : #endif
893 : : }
894 : :
895 [ + + ]: 121 : if (sd->nErrorType == _IS_WARNING)
896 : : {
897 : : /* Warnings: try to produce INChI */
898 : :
899 [ - + ]: 11 : if (nLogMask & LOG_MASK_WARN)
900 : : {
901 : 44 : inchi_ios_eprint( log_file, "Warning: (%s) inp structure #%ld.%s%s%s%s\n",
902 [ - + - - : 55 : sd->pStrErrStruct, *num_inp, SDF_LBL_VAL( ip->pSdfLabel, ip->pSdfValue ) );
- + - - -
+ - - - -
- - - + -
- - + -
- ]
903 : : }
904 : : }
905 : :
906 : :
907 : : #ifdef TARGET_LIB_FOR_WINCHI
908 : : if (( ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
909 : : ( ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT ))
910 : : {
911 : : if (sd->nErrorType != _IS_OKAY && sd->nErrorType != _IS_WARNING)
912 : : {
913 : : sd->nErrorType =
914 : : ProcessStructError( out_file, log_file, sd->pStrErrStruct, sd->nErrorType, *num_inp, ip );
915 : : }
916 : : }
917 : : #endif
918 : :
919 : 110 : exit_function:
920 [ + - + + ]: 121 : if (nRet <= _IS_OKAY && sd->nErrorType > 0)
921 : : {
922 : 11 : nRet = sd->nErrorType;
923 : : }
924 : :
925 : 121 : return nRet;
926 : : }
927 : :
928 : :
929 : : #ifdef TARGET_EXE_USING_API
930 : :
931 : :
932 : : /****************************************************************************/
933 : : int InchiToInchi_Input( INCHI_IOSTREAM *inp_file,
934 : : inchi_Input *orig_at_data,
935 : : int bMergeAllInputStructures,
936 : : int bDoNotAddH,
937 : : int vABParityUnknown,
938 : : INPUT_TYPE nInputType,
939 : : char *pSdfLabel,
940 : : char *pSdfValue,
941 : : unsigned long *lSdfId,
942 : : INCHI_MODE *pInpAtomFlags,
943 : : int *err,
944 : : char *pStrErr )
945 : : {
946 : : /* inp_ATOM *at = NULL; */
947 : : int num_dimensions_new;
948 : : int num_inp_bonds_new;
949 : : int num_inp_atoms_new;
950 : : int num_inp_0D_new;
951 : : inp_ATOM *at_new = NULL;
952 : : inp_ATOM *at_old = NULL;
953 : : inchi_Stereo0D *stereo0D_new = NULL;
954 : : inchi_Stereo0D *stereo0D_old = NULL;
955 : : int nNumAtoms = 0, nNumStereo0D = 0;
956 : : MOL_COORD *szCoordNew = NULL;
957 : : MOL_COORD *szCoordOld = NULL;
958 : : int i, j;
959 : : int max_num_at;
960 : :
961 : :
962 : : max_num_at = MAX_ATOMS;
963 : : if (*pInpAtomFlags & FLAG_SET_INP_LARGE_MOLS)
964 : : max_num_at = MAX_ATOMS_LARGE_MOL;
965 : :
966 : : if (pStrErr)
967 : : pStrErr[0] = '\0';
968 : :
969 : :
970 : : /*FreeOrigAtData( orig_at_data );*/
971 : : if (lSdfId)
972 : : *lSdfId = 0LU;
973 : :
974 : : do
975 : : {
976 : : at_old = orig_at_data ? orig_at_data->atom : NULL; /* save pointer to the previous allocation */
977 : :
978 : : stereo0D_old = orig_at_data ? orig_at_data->stereo0D : NULL;
979 : :
980 : : szCoordOld = NULL;
981 : :
982 : : num_inp_atoms_new =
983 : : InchiToinp_ATOM( inp_file, orig_at_data ? &stereo0D_new : NULL, &num_inp_0D_new,
984 : : bDoNotAddH, vABParityUnknown, nInputType,
985 : : orig_at_data ? &at_new : NULL, MAX_ATOMS,
986 : : &num_dimensions_new, &num_inp_bonds_new,
987 : : pSdfLabel, pSdfValue, lSdfId, pInpAtomFlags, err, pStrErr );
988 : :
989 : : if (num_inp_atoms_new <= 0 && !*err)
990 : : {
991 : : TREAT_ERR( *err, 0, "Empty structure" );
992 : : *err = 98;
993 : : }
994 : : else if (orig_at_data &&
995 : : !num_inp_atoms_new &&
996 : : 10 < *err && *err < 20 &&
997 : : orig_at_data->num_atoms > 0
998 : : && bMergeAllInputStructures)
999 : : {
1000 : : *err = 0; /* end of file */
1001 : : break;
1002 : : }
1003 : : else if (num_inp_atoms_new > 0 && orig_at_data)
1004 : : {
1005 : : /* merge pOrigDataTmp + orig_at_data => pOrigDataTmp; */
1006 : : nNumAtoms = num_inp_atoms_new + orig_at_data->num_atoms;
1007 : : nNumStereo0D = num_inp_0D_new + orig_at_data->num_stereo0D;
1008 : :
1009 : : if (nNumAtoms >= max_num_at) /*MAX_ATOMS ) */
1010 : : {
1011 : : TREAT_ERR( *err, 0, "Too many atoms [check 'LargeMolecules' switch]" );
1012 : : *err = 70;
1013 : : orig_at_data->num_atoms = -1;
1014 : : }
1015 : : else if (!at_old)
1016 : : {
1017 : : /* the first structure */
1018 : :
1019 : : orig_at_data->atom = at_new; at_new = NULL;
1020 : : orig_at_data->num_atoms = num_inp_atoms_new; num_inp_atoms_new = 0;
1021 : : orig_at_data->stereo0D = stereo0D_new; stereo0D_new = NULL;
1022 : : orig_at_data->num_stereo0D = num_inp_0D_new; num_inp_0D_new = 0;
1023 : : }
1024 : : else if (orig_at_data->atom = Createinp_ATOM( nNumAtoms ))
1025 : : {
1026 : : /* switch at_new <--> orig_at_data->at; */
1027 : :
1028 : : if (orig_at_data->num_atoms)
1029 : : {
1030 : : memcpy( orig_at_data->atom, at_old, orig_at_data->num_atoms * sizeof( orig_at_data->atom[0] ) );
1031 : : /* adjust numbering in the newly read structure */
1032 : : for (i = 0; i < num_inp_atoms_new; i++)
1033 : : {
1034 : : for (j = 0; j < at_new[i].num_bonds; j++)
1035 : : {
1036 : : at_new[i].neighbor[j] += orig_at_data->num_atoms;
1037 : : }
1038 : : }
1039 : : }
1040 : : Freeinp_ATOM( &at_old );
1041 : :
1042 : : /* copy newly read structure */
1043 : : memcpy( orig_at_data->atom + orig_at_data->num_atoms,
1044 : : at_new,
1045 : : num_inp_atoms_new * sizeof( orig_at_data->atom[0] ) );
1046 : :
1047 : : /* copy newly read 0D stereo */
1048 : : if (num_inp_0D_new > 0 && stereo0D_new)
1049 : : {
1050 : : if (orig_at_data->stereo0D = CreateInchi_Stereo0D( nNumStereo0D ))
1051 : : {
1052 : : int ncopy = orig_at_data->num_stereo0D * sizeof( orig_at_data->stereo0D[0] );
1053 : : memcpy( orig_at_data->stereo0D, stereo0D_old, ncopy );
1054 : :
1055 : : /* adjust numbering in the newly read structure */
1056 : : for (i = 0; i < num_inp_0D_new; i++)
1057 : : {
1058 : : if (stereo0D_new[i].central_atom >= 0)
1059 : : stereo0D_new[i].central_atom += orig_at_data->num_atoms;
1060 : :
1061 : : for (j = 0; j < 4; j++)
1062 : : stereo0D_new[i].neighbor[j] += orig_at_data->num_atoms;
1063 : : }
1064 : :
1065 : : FreeInchi_Stereo0D( &stereo0D_old );
1066 : :
1067 : : int ncopy = num_inp_0D_new * sizeof( orig_at_data->stereo0D[0] );
1068 : : memcpy( orig_at_data->stereo0D + orig_at_data->num_stereo0D,
1069 : : stereo0D_new,
1070 : : ncopy );
1071 : : }
1072 : : else
1073 : : {
1074 : : num_inp_0D_new = 0;
1075 : : TREAT_ERR( *err, 0, "Out of RAM" );
1076 : : *err = -1;
1077 : : }
1078 : : }
1079 : : else
1080 : : {
1081 : : num_inp_0D_new = 0;
1082 : : }
1083 : :
1084 : : /* update lengths */
1085 : : orig_at_data->num_atoms += num_inp_atoms_new;
1086 : : orig_at_data->num_stereo0D += num_inp_0D_new;
1087 : : }
1088 : : else
1089 : : {
1090 : : TREAT_ERR( *err, 0, "Out of RAM" );
1091 : : *err = -1;
1092 : : }
1093 : : }
1094 : : else if (num_inp_atoms_new > 0)
1095 : : {
1096 : : nNumAtoms += num_inp_atoms_new;
1097 : : }
1098 : :
1099 : : Freeinp_ATOM( &at_new );
1100 : : num_inp_atoms_new = 0;
1101 : : FreeInchi_Stereo0D( &stereo0D_new );
1102 : : num_inp_0D_new = 0;
1103 : : }
1104 : : while (!*err && bMergeAllInputStructures);
1105 : :
1106 : : /*
1107 : : if ( !*err )
1108 : : {
1109 : : orig_at_data->num_components =
1110 : : MarkDisconnectedComponents( orig_at_data );
1111 : : if ( orig_at_data->num_components == 0 )
1112 : : {
1113 : : TREAT_ERR (*err, 0, "No components found");
1114 : : *err = 99;
1115 : : }
1116 : : if ( orig_at_data->num_components < 0 )
1117 : : {
1118 : : TREAT_ERR (*err, 0, "Too many components");
1119 : : *err = 99;
1120 : : }
1121 : : }
1122 : : */
1123 : :
1124 : : if (szCoordNew)
1125 : : inchi_free( szCoordNew );
1126 : :
1127 : : if (at_new)
1128 : : inchi_free( at_new );
1129 : :
1130 : : /*
1131 : : if ( !*err )
1132 : : {
1133 : : if ( ReconcileAllCmlBondParities( orig_at_data->atom, orig_at_data->num_atoms ) )
1134 : : {
1135 : : TREAT_ERR (*err, 0, "Cannot reconcile stereobond parities");
1136 : : if (!orig_at_data->num_atoms)
1137 : : {
1138 : : *err = 1;
1139 : : }
1140 : : }
1141 : : }
1142 : : */
1143 : :
1144 : : if (*err)
1145 : : FreeInchi_Input( orig_at_data );
1146 : :
1147 : : if (*err && !( 10 < *err && *err < 20 ) && pStrErr && !pStrErr[0])
1148 : : {
1149 : : TREAT_ERR( *err, 0, "Unknown error" ); /* <BRKPT> */
1150 : : }
1151 : :
1152 : : return orig_at_data ? orig_at_data->num_atoms : nNumAtoms;
1153 : : }
1154 : :
1155 : : #endif /* #ifdef TARGET_EXE_USING_API */
1156 : :
1157 : :
1158 : : /****************************************************************************
1159 : : Read input InChI string and fill internal data structs
1160 : : ****************************************************************************/
1161 : 0 : int InchiToOrigAtom( INCHI_IOSTREAM *inp_molfile,
1162 : : ORIG_ATOM_DATA *orig_at_data,
1163 : : int bMergeAllInputStructures,
1164 : : int bGetOrigCoord,
1165 : : int bDoNotAddH,
1166 : : int vABParityUnknown,
1167 : : INPUT_TYPE nInputType,
1168 : : char *pSdfLabel,
1169 : : char *pSdfValue,
1170 : : unsigned long *lSdfId,
1171 : : INCHI_MODE *pInpAtomFlags,
1172 : : int *err,
1173 : : char *pStrErr )
1174 : : {
1175 : : int num_dimensions_new;
1176 : : int num_inp_bonds_new;
1177 : : int num_inp_atoms_new;
1178 : 0 : inp_ATOM *at_new = NULL;
1179 : 0 : inp_ATOM *at_old = NULL;
1180 : 0 : MOL_COORD *szCoordNew = NULL;
1181 : 0 : MOL_COORD *szCoordOld = NULL;
1182 : 0 : int nNumAtoms = 0;
1183 : : int i, j, max_num_at;
1184 : :
1185 : :
1186 : 0 : max_num_at = MAX_ATOMS;
1187 [ # # ]: 0 : if (!( *pInpAtomFlags & FLAG_SET_INP_LARGE_MOLS ))
1188 : : {
1189 : 0 : max_num_at = NORMALLY_ALLOWED_INP_MAX_ATOMS;
1190 : : }
1191 : :
1192 [ # # ]: 0 : if (pStrErr)
1193 : : {
1194 : 0 : pStrErr[0] = '\0';
1195 : : }
1196 : :
1197 : : /*FreeOrigAtData( orig_at_data );*/
1198 [ # # ]: 0 : if (lSdfId)
1199 : : {
1200 : 0 : *lSdfId = 0LU;
1201 : : }
1202 : :
1203 : : do
1204 : : {
1205 [ # # ]: 0 : at_old = orig_at_data ? orig_at_data->at : NULL; /* save pointer to the previous allocation */
1206 : :
1207 [ # # ]: 0 : szCoordOld = orig_at_data ? orig_at_data->szCoord : NULL;
1208 : :
1209 [ # # # # ]: 0 : num_inp_atoms_new = InchiToInpAtom( inp_molfile,
1210 [ # # ]: 0 : ( bGetOrigCoord && orig_at_data ) ? &szCoordNew : NULL,
1211 : : bDoNotAddH,
1212 : : vABParityUnknown,
1213 : : nInputType,
1214 : : orig_at_data ? &at_new : NULL,
1215 : : MAX_ATOMS,
1216 : : &num_dimensions_new,
1217 : : &num_inp_bonds_new,
1218 : : pSdfLabel,
1219 : : pSdfValue,
1220 : : lSdfId,
1221 : : pInpAtomFlags,
1222 : : err,
1223 : : pStrErr );
1224 : :
1225 [ # # # # ]: 0 : if (num_inp_atoms_new <= 0 && !*err)
1226 : : {
1227 : 0 : TREAT_ERR( *err, 0, "Empty structure" );
1228 : 0 : *err = 98;
1229 : : }
1230 [ # # # # ]: 0 : else if (orig_at_data && !num_inp_atoms_new &&
1231 [ # # # # ]: 0 : 10 < *err && *err < 20 &&
1232 [ # # # # ]: 0 : orig_at_data->num_inp_atoms > 0 &&
1233 : : bMergeAllInputStructures)
1234 : : {
1235 : 0 : *err = 0; /* end of file */
1236 : 0 : break;
1237 : : }
1238 [ # # # # ]: 0 : else if (num_inp_atoms_new > 0 && orig_at_data)
1239 : : {
1240 : : /* merge pOrigDataTmp + orig_at_data => pOrigDataTmp; */
1241 : 0 : nNumAtoms = num_inp_atoms_new + orig_at_data->num_inp_atoms;
1242 [ # # ]: 0 : if (nNumAtoms >= max_num_at) /*MAX_ATOMS ) */
1243 : : {
1244 : 0 : TREAT_ERR( *err, 0, "Too many atoms [check 'LargeMolecules' switch]" );
1245 : 0 : *err = 70;
1246 : 0 : orig_at_data->num_inp_atoms = -1;
1247 : : }
1248 [ # # ]: 0 : else if (!at_old)
1249 : : {
1250 : : /* the first structure */
1251 : 0 : orig_at_data->at = at_new;
1252 : 0 : orig_at_data->szCoord = szCoordNew;
1253 : 0 : at_new = NULL;
1254 : 0 : szCoordNew = NULL;
1255 : 0 : orig_at_data->num_inp_atoms = num_inp_atoms_new;
1256 : 0 : orig_at_data->num_inp_bonds = num_inp_bonds_new;
1257 : 0 : orig_at_data->num_dimensions = num_dimensions_new;
1258 : : }
1259 [ # # ]: 0 : else if (( orig_at_data->at = (inp_ATOM*) inchi_calloc( nNumAtoms, sizeof( inp_ATOM ) ) ) &&
1260 [ # # # # ]: 0 : ( !szCoordNew || ( orig_at_data->szCoord = (MOL_COORD *) inchi_calloc( nNumAtoms, sizeof( MOL_COORD ) ) ) ))
1261 : : {
1262 : : /* switch at_new <--> orig_at_data->at; */
1263 [ # # ]: 0 : if (orig_at_data->num_inp_atoms)
1264 : : {
1265 : 0 : memcpy(orig_at_data->at,
1266 : : at_old,
1267 : 0 : orig_at_data->num_inp_atoms * sizeof(orig_at_data->at[0]));
1268 : : /* adjust numbering in the newly read structure */
1269 [ # # ]: 0 : for (i = 0; i < num_inp_atoms_new; i++)
1270 : : {
1271 [ # # ]: 0 : if (at_new) /* djb-rwth: fixing a NULL pointer dereference */
1272 : : {
1273 [ # # ]: 0 : for (j = 0; j < at_new[i].valence; j++)
1274 : : {
1275 : 0 : at_new[i].neighbor[j] += orig_at_data->num_inp_atoms;
1276 : : }
1277 : 0 : at_new[i].orig_at_number += orig_at_data->num_inp_atoms; /* 12-19-2003 */
1278 : : }
1279 : : }
1280 [ # # # # ]: 0 : if (orig_at_data->szCoord && szCoordOld)
1281 : : {
1282 : 0 : memcpy(orig_at_data->szCoord,
1283 : : szCoordOld,
1284 : 0 : orig_at_data->num_inp_atoms * sizeof(MOL_COORD));
1285 : : }
1286 : : }
1287 [ # # ]: 0 : if (at_old)
1288 : : {
1289 : : /* inchi_free( at_old ); */ /* djb-rwth: avoiding the use of freed memory */
1290 : 0 : at_old = NULL;
1291 : : }
1292 [ # # ]: 0 : if (szCoordOld)
1293 : : {
1294 : : /* inchi_free( szCoordOld ); */ /* djb-rwth: avoiding the use of freed memory */
1295 : 0 : szCoordOld = NULL;
1296 : : }
1297 : : /* copy newly read structure */
1298 [ # # ]: 0 : if (at_new) /* djb-rwth: fixing a NULL pointer dereference */
1299 : 0 : memcpy(orig_at_data->at + orig_at_data->num_inp_atoms, at_new, num_inp_atoms_new * sizeof(orig_at_data->at[0]));
1300 [ # # # # ]: 0 : if (orig_at_data->szCoord && szCoordNew)
1301 : : {
1302 : 0 : memcpy(orig_at_data->szCoord + orig_at_data->num_inp_atoms,
1303 : : szCoordNew,
1304 : : num_inp_atoms_new * sizeof(MOL_COORD));
1305 : : }
1306 : : /* add other things */
1307 : 0 : orig_at_data->num_inp_atoms += num_inp_atoms_new;
1308 : 0 : orig_at_data->num_inp_bonds += num_inp_bonds_new;
1309 : 0 : orig_at_data->num_dimensions = inchi_max( num_dimensions_new, orig_at_data->num_dimensions );
1310 : : }
1311 : : else
1312 : : {
1313 : 0 : TREAT_ERR( *err, 0, "Out of RAM" );
1314 : 0 : *err = -1;
1315 : : }
1316 : : }
1317 [ # # ]: 0 : else if (num_inp_atoms_new > 0)
1318 : : {
1319 : 0 : nNumAtoms += num_inp_atoms_new;
1320 : : }
1321 [ # # ]: 0 : if (at_new)
1322 : : {
1323 : : /* inchi_free( at_new ); */ /* djb-rwth: avoiding the use of freed memory */
1324 : 0 : at_new = NULL;
1325 : : }
1326 : : }
1327 [ # # # # ]: 0 : while (!*err && bMergeAllInputStructures);
1328 : :
1329 : : /*
1330 : : if ( !*err ) {
1331 : : orig_at_data->num_components =
1332 : : MarkDisconnectedComponents( orig_at_data );
1333 : : if ( orig_at_data->num_components == 0 ) {
1334 : : TREAT_ERR (*err, 0, "No components found");
1335 : : *err = 99;
1336 : : }
1337 : : if ( orig_at_data->num_components < 0 ) {
1338 : : TREAT_ERR (*err, 0, "Too many components");
1339 : : *err = 99;
1340 : : }
1341 : : }
1342 : : */
1343 : :
1344 : : /* djb-rwth: avoiding the use of freed memory */
1345 : : /*
1346 : : if (szCoordNew)
1347 : : {
1348 : : inchi_free( szCoordNew );
1349 : : }
1350 : : if (at_new)
1351 : : {
1352 : : inchi_free( at_new );
1353 : : }
1354 : : */
1355 : :
1356 [ # # # # ]: 0 : if (!*err && orig_at_data)
1357 : : {
1358 [ # # ]: 0 : if (ReconcileAllCmlBondParities( orig_at_data->at,
1359 : : orig_at_data->num_inp_atoms, 0 ))
1360 : : {
1361 : 0 : TREAT_ERR( *err, 0, "Cannot reconcile stereobond parities" ); /* <BRKPT> */
1362 [ # # ]: 0 : if (!orig_at_data->num_dimensions)
1363 : : {
1364 : 0 : *err = 1;
1365 : : }
1366 : : }
1367 : : }
1368 : :
1369 [ # # ]: 0 : if (*err)
1370 : : {
1371 : 0 : FreeOrigAtData( orig_at_data );
1372 : : }
1373 : :
1374 [ # # # # : 0 : if (*err && !( 10 < *err && *err < 20 ) && pStrErr && !pStrErr[0])
# # # # #
# ]
1375 : : {
1376 : 0 : TREAT_ERR( *err, 0, "Unknown error" ); /* <BRKPT> */
1377 : : }
1378 : :
1379 [ # # ]: 0 : return orig_at_data ? orig_at_data->num_inp_atoms : nNumAtoms;
1380 : : }
1381 : :
1382 : :
1383 : : /****************************************************************************
1384 : : Returns 1 if bonds (a1,a2) and (b1,b2) are the same, -1 if atoms swapped,
1385 : : 0 if not the same
1386 : : ****************************************************************************/
1387 : 0 : int bIsSameBond(int a1, int a2, int b1, int b2)
1388 : : {
1389 [ # # # # ]: 0 : if (a1 == b1 && a2 == b2) return 1;
1390 [ # # # # ]: 0 : if (a1 == b2 && a2 == b1) return -1;
1391 : 0 : return 0;
1392 : : }
1393 : :
1394 : :
1395 : : /****************************************************************************
1396 : : Parse InChI and get a list of crossing bonds in z layer
1397 : : Return number of frame_shift_info triples or 0
1398 : : ****************************************************************************/
1399 : 0 : static int GetFrameShiftInfoFrom105PlusInChI(char *sinchi,
1400 : : int *frame_shift_info,
1401 : : int max_crossing)
1402 : : {
1403 : 0 : int k, c = 0, j, aindex = 0, iunit = 0;
1404 : : const char *p, *q;
1405 : :
1406 : 0 : p = strstr(sinchi, "/z"); /* must always be there */
1407 : :
1408 : : /* each frame_shift_info triple(iunit, iunit_a1, iunit_a2) contains,
1409 : : for each eligible frame-shiftable unit,
1410 : : iunit - unit_no
1411 : : iunit_a1, iunit_a2 - atom numbers for the senior bkbond
1412 : : note that iunit_a1 is more senior then iunit_a2
1413 : : */
1414 : :
1415 : : /* eligible unit has Z-layer pattern
1416 : : "range-of-numbers(number1,number2,nimbers...)"
1417 : : >=2 bkbonds in CRU; relink may be necessary to shift frame or swap bkbond atoms?
1418 : : OPTIONALLY DO NOT DO SWAP NOW?
1419 : : senior bkbond and right atoms order is (number1,number2)
1420 : : "range-of-numbers(number1.number2)"
1421 : : 1-bkbond CRU; relink may still be necessary to swap bkbond atoms so that
1422 : : more senior atom is connected to lesser-numbered Zz
1423 : : OPTIONALLY DO NOT DO SWAP NOW?
1424 : : senior atoms order in bkbond is (number1,number2)
1425 : : "range-of-numbers(number)" 1-atom CRU
1426 : : relink is not applicable, skip it
1427 : : */
1428 : :
1429 [ # # ]: 0 : while (p)
1430 : : {
1431 : 0 : int num[2] = { -1,-1 };
1432 : 0 : p = strstr(p + 2, "(");
1433 [ # # ]: 0 : if (!p)
1434 : : {
1435 : 0 : break;
1436 : : }
1437 : 0 : p++;
1438 : 0 : q = p;
1439 : 0 : j = 0;
1440 [ # # # # ]: 0 : while ((k = (int)inchi_strtol(p, &q, 10)) && j < 2)
1441 : : {
1442 : 0 : num[j] = k;
1443 : 0 : j++;
1444 : 0 : c = UCINT *q;
1445 [ # # # # ]: 0 : if (j==1 && c == '-') /* do not consider pattern "(cap-end, cap-end)" */
1446 : : {
1447 : 0 : goto find_next_unit;
1448 : : }
1449 [ # # ]: 0 : else if (c != ')')
1450 : : {
1451 : 0 : p = q + 1;
1452 : : }
1453 : : else
1454 : : {
1455 : 0 : goto find_next_unit;
1456 : : }
1457 : : }
1458 [ # # ]: 0 : if (j < 2)
1459 : : {
1460 : 0 : goto find_next_unit;
1461 : : }
1462 : 0 : frame_shift_info[3 * aindex] = iunit;
1463 : 0 : frame_shift_info[3 * aindex + 1] = num[0];
1464 : 0 : frame_shift_info[3 * aindex + 2] = num[1];
1465 : 0 : aindex++;
1466 [ # # ]: 0 : if (aindex >= max_crossing)
1467 : : {
1468 : 0 : break;
1469 : : }
1470 : :
1471 : 0 : find_next_unit:
1472 : 0 : p = strstr(p, ";");
1473 : 0 : iunit++;
1474 : : }
1475 : :
1476 : 0 : return aindex;
1477 : : }
1478 : :
1479 : :
1480 : : /****************************************************************************
1481 : : Parse AuxInfostring and get a list of original atom numbers orig[cano_num]
1482 : : ****************************************************************************/
1483 : 0 : int extract_orig_nums_from_auxinfo_string(char *saux, int *orig)
1484 : : {
1485 : 0 : int res = _IS_OKAY;
1486 : 0 : int k, c = 0, cano_num = 1 /*0*/;
1487 : : const char *p, *q;
1488 : :
1489 : 0 : p = strstr(saux, "/N:"); /* must always be there */
1490 [ # # # # : 0 : if (!p || !p[3] || !isdigit(UCINT p[3]))
# # ]
1491 : : {
1492 : 0 : res = _IS_ERROR;
1493 : 0 : goto exit_function;
1494 : : }
1495 : :
1496 : 0 : p += 3;
1497 : 0 : q = p;
1498 : :
1499 [ # # ]: 0 : while ((k = inchi_strtol(p, &q, 10))) /* djb-rwth: addressing LLVM warning */
1500 : : {
1501 : 0 : orig[cano_num++] = k/* - 1*/; /* 1-based numbers */
1502 [ # # # # ]: 0 : if ((c = UCINT *q) && c != '/') /* djb-rwth: addressing LLVM warning */
1503 : : {
1504 : 0 : p = q + 1;
1505 : : }
1506 : : else
1507 : : {
1508 : : break;
1509 : : }
1510 : : }
1511 : :
1512 : 0 : exit_function:
1513 : :
1514 : 0 : return res;
1515 : : }
1516 : :
1517 : :
1518 : : /****************************************************************************
1519 : : (currently, this function gets only the first list of E: )
1520 : : ****************************************************************************/
1521 : 0 : int extract_nonstereo_eq_classes_from_auxinfo_string( char *saux,
1522 : : int nat,
1523 : : int *orig,
1524 : : int *nclasses,
1525 : : int *eclass,
1526 : : int *eclass_by_origs)
1527 : : {
1528 : 0 : int res = _IS_OKAY;
1529 : 0 : int k, c = 0, cano_num = 1, orig_num = 1;
1530 : : const char *p, *q;
1531 : :
1532 : : /* Note that all atom and class numbers here are 1-based */
1533 : :
1534 : 0 : *nclasses = 0;
1535 : 0 : memset(eclass, -1, ((long long)nat+1) * sizeof(int)); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
1536 : 0 : memset(eclass_by_origs, -1, ((long long)nat+1) * sizeof(int)); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
1537 : :
1538 : 0 : p = strstr(saux, "/E:");
1539 [ # # ]: 0 : if (!p)
1540 : : {
1541 : : /* No "/E" means that all atoms are different */
1542 : 0 : return res;
1543 : : }
1544 : :
1545 : 0 : p += 3;
1546 : 0 : q = p;
1547 [ # # ]: 0 : while ((k = (AT_NUMB)inchi_strtol(p + 1, &q, 10))) /* djb-rwth: addressing LLVM warning */
1548 : : {
1549 : 0 : c = UCINT *q;
1550 [ # # ]: 0 : if (c == '/')
1551 : : {
1552 : 0 : break;
1553 : : }
1554 [ # # # # ]: 0 : else if (c == ',' || c == ')')
1555 : : {
1556 : 0 : eclass[k] = *nclasses;
1557 [ # # ]: 0 : if (c == ')')
1558 : : {
1559 : 0 : (*nclasses)++;
1560 : 0 : q++;
1561 : 0 : c = UCINT *q;
1562 [ # # ]: 0 : if (c == '/')
1563 : 0 : break;
1564 : : else
1565 : : ;
1566 : : }
1567 : 0 : p = q;
1568 : : }
1569 : : else
1570 : : {
1571 : 0 : return _IS_ERROR;
1572 : : }
1573 : : }
1574 : : /* NB: cano, origs start from 0 */
1575 [ # # ]: 0 : for (cano_num = 1; cano_num <= nat; cano_num++)
1576 : : {
1577 [ # # ]: 0 : if (eclass[cano_num] == -1) /* the atom is unique, add one more eq class for him */
1578 : : {
1579 : 0 : (*nclasses)++;
1580 : 0 : eclass[cano_num] = *nclasses;
1581 : : }
1582 : : }
1583 : :
1584 [ # # ]: 0 : for (cano_num = 1; cano_num <= nat; cano_num++)
1585 : : {
1586 : 0 : orig_num = orig[cano_num]; /* NB: cano, origs start from 0 */
1587 : 0 : eclass_by_origs[orig_num] = eclass[cano_num];
1588 : : }
1589 : :
1590 : 0 : return res;
1591 : : }
1592 : :
1593 : :
1594 : : /****************************************************************************
1595 : : Make a copy of the context of ProcessOneStructureEx or set a a new one
1596 : : ****************************************************************************/
1597 : 1 : int POSEContext_Init(POSEContext *context,
1598 : : STRUCT_DATA *sd, INPUT_PARMS *ip, char *szTitle,
1599 : : PINChI2 *pINChI2[INCHI_NUM], PINChI_Aux2 *pINChI_Aux2[INCHI_NUM],
1600 : : INCHI_IOSTREAM *inp_file, INCHI_IOSTREAM *log_file,
1601 : : INCHI_IOSTREAM *out_file, INCHI_IOSTREAM *prb_file,
1602 : : ORIG_ATOM_DATA *orig_inp_data, ORIG_ATOM_DATA *prep_inp_data,
1603 : : long num_inp, INCHI_IOS_STRING *strbuf, unsigned char save_opt_bits)
1604 : : {
1605 : 1 : char *sz = NULL;
1606 : 1 : int ret = _IS_OKAY, res = 0, i;
1607 : :
1608 : 1 : memset(context, 0, sizeof(*context)); /* djb-rwth: memset_s C11/Annex K variant? */
1609 : :
1610 [ - + ]: 1 : if (!sd)
1611 : : {
1612 : 0 : memset(&context->sd, 0, sizeof(context->sd)); /* djb-rwth: memset_s C11/Annex K variant? */
1613 : : }
1614 : : else
1615 : : {
1616 : 1 : memcpy(&context->sd, sd, sizeof(context->sd));
1617 : : }
1618 : :
1619 [ - + ]: 1 : if (!ip)
1620 : : {
1621 : 0 : memset(&context->ip, 0, sizeof(context->ip)); /* djb-rwth: memset_s C11/Annex K variant? */
1622 : : }
1623 : : else
1624 : : {
1625 : 1 : memcpy(&context->ip, ip, sizeof(context->ip));
1626 [ + + ]: 5 : for (i = 0; i < MAX_NUM_PATHS; i++)
1627 : : {
1628 [ - + ]: 4 : if (ip->path[i])
1629 : : {
1630 : 0 : sz = (char*)inchi_malloc((strlen(ip->path[i]) + 1) * sizeof(sz[0]));
1631 [ # # ]: 0 : if (!sz)
1632 : : {
1633 : 0 : ret = _IS_ERROR;
1634 : 0 : goto exit_function;
1635 : : }
1636 : 0 : strcpy(sz, context->ip.path[i]);
1637 : 0 : context->ip.path[i] = sz;
1638 : : }
1639 : : }
1640 : : }
1641 : :
1642 [ - + ]: 1 : if (strlen(szTitle))
1643 : : {
1644 : 0 : strcpy(context->szTitle, szTitle);
1645 : : }
1646 : : else
1647 : : {
1648 : 1 : context->szTitle[0] = '\0';
1649 : : }
1650 : :
1651 : : /* pINChI2, pINChI_Aux2: We do not fill/allocate elements of these structures */
1652 : : /* assuming that NULL's are there. If not just raise an error. */
1653 : :
1654 : 1 : context->pINChI2[0] = context->pINChI2[1] = NULL;
1655 [ + - + - : 1 : if (pINChI2 && (pINChI2[0] || pINChI2[1])) /* djb-rwth: condition corrected */
- + ]
1656 : : {
1657 : 0 : ret = _IS_ERROR;
1658 : 0 : goto exit_function;
1659 : : }
1660 : 1 : context->pINChI_Aux2[0] = context->pINChI_Aux2[1] = NULL;
1661 [ + - + - : 1 : if (pINChI_Aux2 && (pINChI_Aux2[0] || pINChI_Aux2[1])) /* djb-rwth: condition corrected */
- + ]
1662 : : {
1663 : 0 : ret = _IS_ERROR;
1664 : 0 : goto exit_function;
1665 : : }
1666 : :
1667 : 1 : context->out_file = context->inchi_file;
1668 : 1 : context->log_file = context->inchi_file + 1;
1669 : 1 : context->prb_file = context->inchi_file + 2;
1670 : : /* Initialize internal for this function output streams as string buffers */
1671 : 1 : inchi_ios_init(context->out_file, INCHI_IOS_TYPE_STRING, NULL);
1672 : 1 : inchi_ios_init(context->log_file, INCHI_IOS_TYPE_STRING, NULL);
1673 : 1 : inchi_ios_init(context->prb_file, INCHI_IOS_TYPE_STRING, NULL);
1674 : 1 : context->inp_file = NULL;
1675 [ + - ]: 1 : if (inp_file)
1676 : : {
1677 : 1 : context->inp_file = inp_file;
1678 : : }
1679 : :
1680 : 1 : context->orig_inp_data = &context->OrigAtData;
1681 : 1 : context->prep_inp_data = context->PrepAtData;
1682 : :
1683 [ + - ]: 1 : if (orig_inp_data)
1684 : : {
1685 : 1 : memset(context->orig_inp_data, 0, sizeof(*context->orig_inp_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1686 : 1 : res = OrigAtData_Duplicate(context->orig_inp_data, orig_inp_data);
1687 [ - + ]: 1 : if (res)
1688 : : {
1689 : 0 : ret = _IS_ERROR;
1690 : 0 : goto exit_function;
1691 : : }
1692 : : }
1693 : :
1694 [ + - ]: 1 : if (prep_inp_data)
1695 : : {
1696 : 1 : memset(context->prep_inp_data, 0, 2 * sizeof(*context->prep_inp_data)); /* djb-rwth: memset_s C11/Annex K variant? */
1697 : 1 : res = OrigAtData_Duplicate(context->prep_inp_data, prep_inp_data);
1698 [ - + ]: 1 : if (res)
1699 : : {
1700 : 0 : ret = _IS_ERROR;
1701 : 0 : goto exit_function;
1702 : : }
1703 : : }
1704 : :
1705 : : /* num_inp, strbuf, save_opt_bits */
1706 : 1 : context->num_inp = num_inp;
1707 : 1 : context->save_opt_bits = save_opt_bits;
1708 : 1 : context->strbuf = &context->temp_string_container;
1709 [ + - ]: 1 : if (strbuf)
1710 : : {
1711 : 1 : res = inchi_strbuf_create_copy(context->strbuf, strbuf);
1712 : : }
1713 : : else
1714 : : {
1715 : 0 : res = inchi_strbuf_init(context->strbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT);
1716 : : }
1717 [ + - ]: 1 : if (res == -1)
1718 : : {
1719 : 0 : ret = _IS_FATAL;
1720 : 0 : goto exit_function;
1721 : : }
1722 : :
1723 : 1 : exit_function:
1724 : :
1725 : 1 : return ret;
1726 : : }
1727 : :
1728 : :
1729 : : /****************************************************************************/
1730 : 1 : void POSEContext_Free(POSEContext *context)
1731 : : {
1732 : : int i;
1733 [ + + ]: 5 : for (i = 0; i < MAX_NUM_PATHS; i++)
1734 : : {
1735 [ - + ]: 4 : if (context->ip.path[i])
1736 : : {
1737 [ # # ]: 0 : inchi_free((void*)context->ip.path[i]);
1738 : : /* cast deliberately discards 'const' qualifier */
1739 : 0 : context->ip.path[i] = NULL;
1740 : : }
1741 : : }
1742 : 1 : FreeAllINChIArrays(context->pINChI2, context->pINChI_Aux2, context->sd.num_components);
1743 : 1 : if (context->inp_file)
1744 : : {
1745 : : ;
1746 : : }
1747 : : else
1748 : : {
1749 : : ;
1750 : : }
1751 : 1 : inchi_ios_close(context->out_file);
1752 : 1 : inchi_ios_close(context->log_file);
1753 : 1 : inchi_ios_close(context->prb_file);
1754 : 1 : FreeOrigAtData(context->orig_inp_data);
1755 : 1 : FreeOrigAtData(context->prep_inp_data);
1756 : 1 : FreeOrigAtData( context->prep_inp_data+1);
1757 : 1 : context->num_inp = 0;
1758 : 1 : context->save_opt_bits = 0;
1759 : 1 : inchi_strbuf_close(context->strbuf);
1760 : :
1761 : 1 : return;
1762 : : }
1763 : :
1764 : :
1765 : : /****************************************************************************/
1766 : 0 : void POSEContext_DebugPrint(POSEContext *context)
1767 : : {
1768 : : ITRACE_("\nDUMP OF POSEContext OBJECT");
1769 : : /* sd */
1770 : : ;
1771 : : /* ip */
1772 : : ;
1773 : : /* szTitle */
1774 : : ITRACE_("\n\tszTitle = %-s", context->szTitle);
1775 : : /* pINChI2, pINChI_Aux2 */
1776 : : /* inp_file, log_file, out_file, prb_file */
1777 : 0 : if (context->inp_file)
1778 : : {
1779 : : ;
1780 : : }
1781 : : else
1782 : : {
1783 : : ;
1784 : : }
1785 : 0 : if (context->log_file)
1786 : : {
1787 : : ;
1788 : : }
1789 : : else
1790 : : {
1791 : : ;
1792 : : }
1793 : 0 : if (context->out_file)
1794 : : {
1795 : : ;
1796 : : }
1797 : : else
1798 : : {
1799 : : ;
1800 : : }
1801 : 0 : if (context->prb_file)
1802 : : {
1803 : : ;
1804 : : }
1805 : : else
1806 : : {
1807 : : ;
1808 : : }
1809 : : /* orig_inp_data, prep_inp_data, */
1810 : : /* num_inp, strbuf, save_opt_bits */
1811 : : ITRACE_("\n\tnum_inp = %-ld, ", context->num_inp);
1812 : : ITRACE_("\n\tsave_opt_bits = 0x%x, ", context->save_opt_bits);
1813 : : ITRACE_("\n\tsave_opt_bits = 0x%x, ", context->save_opt_bits);
1814 : 0 : if (context->strbuf->nUsedLength > 0)
1815 : : {
1816 : : ITRACE_("\n\tstrbuf = %-s", context->strbuf->pStr);
1817 : : }
1818 : : else
1819 : : {
1820 : : ITRACE_("\n\tstrbuf = <empty>", context->strbuf);
1821 : : }
1822 : : ITRACE_("\n");
1823 : :
1824 : 0 : return;
1825 : : }
1826 : :
1827 : :
1828 : : /****************************************************************************/
1829 : 242 : int OAD_StructureEdits_Init(OAD_StructureEdits *ed)
1830 : : {
1831 : 242 : ed->del_side_chains = 0; /* by default, do not delete */
1832 : :
1833 : 242 : ed->del_atom = (INT_ARRAY *)inchi_calloc(1, sizeof(INT_ARRAY));
1834 [ - + ]: 242 : if (!ed->del_atom) goto exitf;
1835 [ - + ]: 242 : if (0 != IntArray_Alloc(ed->del_atom, 2)) goto exitf;
1836 : :
1837 : 242 : ed->del_bond = (INT_ARRAY *)inchi_calloc(1, sizeof(INT_ARRAY));
1838 [ - + ]: 242 : if (!ed->del_bond) goto exitf;
1839 [ - + ]: 242 : if (0 != IntArray_Alloc(ed->del_bond, 2)) goto exitf;
1840 : :
1841 : 242 : ed->new_bond = (INT_ARRAY *)inchi_calloc(1, sizeof(INT_ARRAY));
1842 [ - + ]: 242 : if (!ed->new_bond) goto exitf;
1843 [ - + ]: 242 : if (0 != IntArray_Alloc(ed->new_bond, 2)) goto exitf;
1844 : :
1845 : 242 : ed->mod_bond = (INT_ARRAY *)inchi_calloc(1, sizeof(INT_ARRAY));
1846 [ - + ]: 242 : if (!ed->mod_bond) goto exitf;
1847 [ - + ]: 242 : if (0 != IntArray_Alloc(ed->mod_bond, 12)) goto exitf;
1848 : :
1849 : 242 : ed->mod_coord = (INT_ARRAY *)inchi_calloc(1, sizeof(INT_ARRAY));
1850 [ - + ]: 242 : if (!ed->mod_coord) goto exitf;
1851 [ - + ]: 242 : if (0 != IntArray_Alloc(ed->mod_coord, 4)) goto exitf;
1852 : :
1853 : :
1854 : 242 : return 0;
1855 : :
1856 : 0 : exitf:
1857 : 0 : OAD_StructureEdits_Clear(ed);
1858 : 0 : return _IS_ERROR;
1859 : : }
1860 : :
1861 : :
1862 : : /****************************************************************************/
1863 : 242 : void OAD_StructureEdits_Clear(OAD_StructureEdits *ed)
1864 : : {
1865 [ + - ]: 242 : if (ed->del_atom)
1866 : : {
1867 : 242 : IntArray_Free(ed->del_atom);
1868 [ + - ]: 242 : inchi_free(ed->del_atom);
1869 : 242 : ed->del_atom = NULL;
1870 : : }
1871 [ + - ]: 242 : if (ed->del_bond)
1872 : : {
1873 : 242 : IntArray_Free(ed->del_bond);
1874 [ + - ]: 242 : inchi_free(ed->del_bond);
1875 : 242 : ed->del_bond = NULL;
1876 : : }
1877 [ + - ]: 242 : if (ed->mod_bond)
1878 : : {
1879 : 242 : IntArray_Free(ed->mod_bond);
1880 [ + - ]: 242 : inchi_free(ed->mod_bond);
1881 : 242 : ed->mod_bond = NULL;
1882 : : }
1883 [ + - ]: 242 : if (ed->new_bond)
1884 : : {
1885 : 242 : IntArray_Free(ed->new_bond);
1886 [ + - ]: 242 : inchi_free(ed->new_bond);
1887 : 242 : ed->new_bond = NULL;
1888 : : }
1889 [ + - ]: 242 : if (ed->mod_coord)
1890 : : {
1891 : 242 : IntArray_Free(ed->mod_coord);
1892 [ + - ]: 242 : inchi_free(ed->mod_coord);
1893 : 242 : ed->mod_coord = NULL;
1894 : : }
1895 : :
1896 : 242 : return;
1897 : : }
1898 : :
1899 : :
1900 : : /****************************************************************************/
1901 : 0 : void OAD_StructureEdits_DebugPrint(OAD_StructureEdits *ed)
1902 : : {
1903 : : ITRACE_("\n*****************************\nOAD_StructureEdits @ %-p\n*****************************", ed);
1904 : : ITRACE_("\nDel_side_chains :\t%-d\n", ed->del_side_chains);
1905 : : ITRACE_("Del_atom:\t%-s", ed->del_atom->used ? "" : "(empty)\n");
1906 : 0 : IntArray_DebugPrint(ed->del_atom);
1907 : : ITRACE_("Del_bond:\t%-s", ed->del_bond->used ? "" : "(empty)\n");
1908 : 0 : IntArray_DebugPrint(ed->del_bond);
1909 : : ITRACE_("New_bond:\t%-s", ed->new_bond->used ? "" : "(empty)\n");
1910 : 0 : IntArray_DebugPrint(ed->new_bond);
1911 : : ITRACE_("Mod_bond:\t%-s", ed->mod_bond->used ? "" : "(empty)\n");
1912 : 0 : IntArray_DebugPrint(ed->mod_bond);
1913 : : ITRACE_("Mod_coord:\t%-s", ed->mod_coord->used ? "" : "(empty)\n");
1914 : 0 : IntArray_DebugPrint(ed->mod_coord);
1915 : :
1916 : 0 : }
1917 : :
1918 : :
1919 : : /****************************************************************************
1920 : : Prepare CRU fold edits as suggested by the strings with preliminary
1921 : : generated interim (1.05+ flavoured) InChI and AuxInfo
1922 : : ****************************************************************************/
1923 : : /* djb-rwth: placed as global variables to avoid function buffer issues */
1924 : : int ec_opp[MAX_ATOMS], /* equivalence classes for atoms, in order of 1-based orig nums */
1925 : : ec_cano_opp[MAX_ATOMS], /* equivalence classes for atoms, in order of 1-based cano nums */
1926 : : at_stereo_mark_orig_opp[MAX_ATOMS], /* stereo parities, in order of 1-based orig nums */
1927 : : xc_opp[MAX_ATOMS]; /* Extended (stereo-aware) atom classes.
1928 : : There are 'n_ec' non-stereo atom equivalence classes
1929 : : For ec[i]=k, keep value k for no-stereo atoms while use
1930 : : (k + neclasses) for '-' parity
1931 : : (k + 2*neclasses) for '+' parity */
1932 : 0 : int OAD_Polymer_PrepareFoldCRUEdits( ORIG_ATOM_DATA *orig_at_data,
1933 : : char *sinchi_noedits,
1934 : : char *saux_noedits,
1935 : : char *sinchi,
1936 : : char *saux,
1937 : : OAD_StructureEdits *ed)
1938 : : {
1939 : 0 : int ret = _IS_OKAY;
1940 : : int i, j, k;
1941 : : int err;
1942 : : char pStrErr[STR_ERR_LEN];
1943 : 0 : int *orig = NULL;
1944 : 0 : int nat = orig_at_data->num_inp_atoms;
1945 : 0 : int neclasses = 0; /* No of constitutional equivalence classses for the atoms */
1946 : 0 : int nxclasses = 0; /* No of extended (stereo-aware) atom classses == 3*neclasses */
1947 : :
1948 : 0 : int *all_bkb_orig = NULL, n_all_bkb_orig = 0;
1949 : 0 : OAD_Polymer *p = orig_at_data->polymer;
1950 : 0 : int nu = orig_at_data->polymer->n;
1951 : :
1952 : : /* Extract cano_nums-->orig_nums mapping from AuxInfo AuxInfo Main Layer */
1953 : 0 : orig = (int*)inchi_calloc((long long)nat + 1, sizeof(int)); /* djb-rwth: cast operator added */
1954 [ # # ]: 0 : if (!orig)
1955 : : {
1956 : 0 : ret = _IS_ERROR;
1957 : 0 : goto exit_function;
1958 : : }
1959 : 0 : ret = extract_orig_nums_from_auxinfo_string(saux, orig);
1960 [ # # # # ]: 0 : if (ret != _IS_OKAY && ret != _IS_WARNING)
1961 : : {
1962 : 0 : ret = _IS_ERROR;
1963 : 0 : goto exit_function;
1964 : : }
1965 : : /* Extract non-stereo eq. classes data from AuxInfo */
1966 : 0 : ret = extract_nonstereo_eq_classes_from_auxinfo_string(saux, nat, orig, &neclasses, ec_cano_opp, ec_opp);
1967 [ # # # # ]: 0 : if (ret != _IS_OKAY && ret != _IS_WARNING)
1968 : : {
1969 : 0 : ret = _IS_ERROR;
1970 : 0 : goto exit_function;
1971 : : }
1972 [ # # ]: 0 : if (neclasses == 0)
1973 : : {
1974 : 0 : goto exit_function;
1975 : : }
1976 : : /* Extract stereocenter data from InChI */
1977 : :
1978 : : /*ret = extract_stereo_info_from_inchi_string(sinchi, nat, orig, at_stereo_mark_orig);*/
1979 : 0 : ret = extract_stereo_info_from_inchi_string(sinchi_noedits, nat, orig, at_stereo_mark_orig_opp);
1980 [ # # # # ]: 0 : if (ret != _IS_OKAY && ret != _IS_WARNING)
1981 : : {
1982 : 0 : ret = _IS_ERROR;
1983 : 0 : goto exit_function;
1984 : : }
1985 : : /* Make extended stereo-aware atom classes */
1986 : 0 : nxclasses = neclasses * 3;
1987 [ # # ]: 0 : for (i = 1; i <= nat; i++) /* orig # */
1988 : : {
1989 : 0 : int atom_class = ec_opp[i];
1990 : :
1991 [ # # ]: 0 : if (at_stereo_mark_orig_opp[i] == INCHI_PARITY_ODD)
1992 : : {
1993 : 0 : atom_class += neclasses;
1994 : : }
1995 [ # # ]: 0 : else if (at_stereo_mark_orig_opp[i] == INCHI_PARITY_EVEN)
1996 : : {
1997 : 0 : atom_class += 2 * neclasses;
1998 : : }
1999 : 0 : xc_opp[i] = atom_class;
2000 : : }
2001 : : /* Extract all backbone bonds, in all units, from InChI (z layer).
2002 : : NB: we assume that units are not 'inter-crossing' so
2003 : : any particular bkbond belongs to some unique CRU.
2004 : : */
2005 : 0 : all_bkb_orig = (int*)inchi_calloc(2 * ((long long)orig_at_data->num_inp_bonds + 1), sizeof(int)); /* djb-rwth: cast operator added */
2006 [ # # ]: 0 : if (!all_bkb_orig)
2007 : : {
2008 : 0 : ret = _IS_ERROR;
2009 : 0 : goto exit_function;
2010 : : }
2011 : 0 : memset(all_bkb_orig, 0, ((long long)orig_at_data->num_inp_bonds + 1) * sizeof(int)); /* djb-rwth: cast operator added; memset_s C11/Annex K variant? */
2012 : 0 : ret = extract_all_backbone_bonds_from_inchi_string(sinchi, &n_all_bkb_orig, orig, all_bkb_orig);
2013 [ # # # # ]: 0 : if (ret != _IS_OKAY && ret != _IS_WARNING)
2014 : : {
2015 : 0 : ret = _IS_ERROR;
2016 : 0 : goto exit_function;
2017 : : }
2018 : : /* just for case, remove those bkbonds which are not single (alternate may be here) */
2019 [ # # ]: 0 : for (k = n_all_bkb_orig - 1; k >= 0; k--)
2020 : : {
2021 : 0 : int orig1 = all_bkb_orig[2 * k];
2022 : 0 : int orig2 = all_bkb_orig[2 * k + 1];
2023 : 0 : int bond_type = Inp_Atom_GetBondType(orig_at_data->at, orig1 - 1, orig2 - 1);
2024 [ # # ]: 0 : if (bond_type > BOND_TYPE_SINGLE) /* not == intentionally, to keep -1 ("no bond") */
2025 : : {
2026 : : /* remove k-th bond and shift others to start of list */
2027 : : int kk;
2028 [ # # ]: 0 : for (kk = k; kk < n_all_bkb_orig; kk++)
2029 : : {
2030 : 0 : all_bkb_orig[2 * kk] = all_bkb_orig[2 * (kk + 1)];
2031 : 0 : all_bkb_orig[2 * kk + 1] = all_bkb_orig[2 * (kk + 1) + 1];
2032 : : }
2033 : 0 : all_bkb_orig[2 * n_all_bkb_orig] = 0;
2034 : 0 : all_bkb_orig[2 * n_all_bkb_orig + 1] = 0;
2035 : 0 : n_all_bkb_orig--;
2036 : : }
2037 : : }
2038 : :
2039 : 0 : err = OAD_ValidatePolymerAndPseudoElementData(orig_at_data,
2040 : : POLYMERS_MODERN,
2041 : : 1, /* ip->bNPZz,*/
2042 : : pStrErr,
2043 : : 0 /*ip->bNoWarnings*/);
2044 [ # # ]: 0 : if (err)
2045 : : {
2046 : 0 : goto exit_function;
2047 : : }
2048 : :
2049 : : /* For each unit analyze a possibility of folding (i.e., removal of excess in-CRU repeats) */
2050 [ # # ]: 0 : for (j = 0; j < nu; j++)
2051 : : {
2052 : 0 : OAD_PolymerUnit* u = p->units[j];
2053 : :
2054 [ # # ]: 0 : if (u->na < 2)
2055 : : {
2056 : 0 : goto nextj;
2057 : : }
2058 [ # # ]: 0 : if (u->nb < 2)
2059 : : {
2060 : 0 : goto nextj;
2061 : : }
2062 : : /* this is only for bi-star CRU's */
2063 [ # # ]: 0 : if (!u->cap1_is_undef)
2064 : : {
2065 : 0 : goto nextj;
2066 : : }
2067 [ # # ]: 0 : if (!u->cap2_is_undef)
2068 : : {
2069 : 0 : goto nextj;
2070 : : }
2071 : :
2072 : 0 : err = analyze_CRU_folding(orig_at_data, j,
2073 : : n_all_bkb_orig, all_bkb_orig,
2074 : : nxclasses, xc_opp,
2075 : : ed);
2076 [ # # ]: 0 : if (err)
2077 : : {
2078 : 0 : ret = inchi_max(_IS_WARNING, err);
2079 : 0 : goto nextj;
2080 : : }
2081 : :
2082 : 0 : nextj:;
2083 : : }
2084 : :
2085 : 0 : exit_function:
2086 [ # # ]: 0 : if (orig)
2087 : : {
2088 [ # # ]: 0 : inchi_free(orig);
2089 : : }
2090 [ # # ]: 0 : if (all_bkb_orig)
2091 : : {
2092 [ # # ]: 0 : inchi_free(all_bkb_orig);
2093 : : }
2094 : :
2095 : 0 : return ret;
2096 : : }
2097 : :
2098 : :
2099 : :
2100 : : /***************************************************************************/
2101 : 0 : DiylFrag* DiylFrag_New(int na, int end1, int end2, char *s)
2102 : : {
2103 : 0 : int err = 0;
2104 : :
2105 : 0 : DiylFrag *pfrag = NULL;
2106 : :
2107 : 0 : pfrag = (DiylFrag *)inchi_calloc(1, sizeof(DiylFrag));
2108 [ # # ]: 0 : if (NULL == pfrag)
2109 : : {
2110 : 0 : err = 1;
2111 : 0 : goto exit_function;
2112 : : }
2113 : :
2114 : 0 : pfrag->na = na;
2115 : 0 : pfrag->end1 = end1;
2116 : 0 : pfrag->end2 = end2;
2117 : 0 : pfrag->alist = NULL;
2118 : 0 : pfrag->xclist = NULL;
2119 : :
2120 [ # # ]: 0 : if (na > 0 )
2121 : : {
2122 : 0 : pfrag->alist = (int *)inchi_calloc(na, sizeof(int));
2123 : 0 : pfrag->xclist = (int *)inchi_calloc(na, sizeof(int));
2124 [ # # # # ]: 0 : if (!pfrag->alist || !pfrag->xclist)
2125 : : {
2126 : 0 : err = 2;
2127 : 0 : goto exit_function;
2128 : : }
2129 : : }
2130 : :
2131 : 0 : inchi_strbuf_printf(&pfrag->sig, "%-s", s);
2132 : :
2133 : 0 : exit_function:
2134 [ # # ]: 0 : if (err)
2135 : : {
2136 : 0 : DiylFrag_Free(pfrag);
2137 [ # # ]: 0 : inchi_free(pfrag); /* djb-rwth: addressing coverity ID #499507 */
2138 : 0 : return NULL;
2139 : : }
2140 : 0 : return pfrag;
2141 : : }
2142 : : /***************************************************************************/
2143 : 0 : void DiylFrag_Free(DiylFrag *pfrag)
2144 : : {
2145 [ # # ]: 0 : if (!pfrag)
2146 : : {
2147 : 0 : return;
2148 : : }
2149 [ # # ]: 0 : if (pfrag->alist)
2150 : : {
2151 [ # # ]: 0 : inchi_free(pfrag->alist);
2152 : 0 : pfrag->alist = NULL;
2153 : : }
2154 [ # # ]: 0 : if (pfrag->xclist)
2155 : : {
2156 [ # # ]: 0 : inchi_free(pfrag->xclist);
2157 : 0 : pfrag->xclist = NULL;
2158 : : }
2159 : 0 : inchi_strbuf_close(&pfrag->sig);
2160 : 0 : return;
2161 : : }
2162 : : /***************************************************************************/
2163 : 0 : void DiylFrag_MakeSignature(DiylFrag *pfrag,
2164 : : int nxc, /* n xclasses (molecule-wide) */
2165 : : int *xc, /* xclasses (molecule-wide) */
2166 : : int *cnt ) /* temp storage: counts of xclasses */
2167 : : {
2168 : : int i, k, nxc_frag; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2169 : :
2170 : 0 : inchi_strbuf_printf(&pfrag->sig, "%-d,%-d,%-d{", pfrag->na, xc[pfrag->end1], xc[pfrag->end2]);
2171 [ # # ]: 0 : for (i = 0; i < pfrag->na; i++)
2172 : : {
2173 : 0 : pfrag->xclist[i] = xc[pfrag->alist[i]];
2174 : : }
2175 : 0 : nxc_frag = count_colors_in_sequence(pfrag->xclist, pfrag->na, nxc+1, cnt); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2176 [ # # ]: 0 : for (k = 0; k < nxc; k++)
2177 : : {
2178 [ # # ]: 0 : if (cnt[k] > 0)
2179 : : {
2180 : : /* (xclass:cnt)*/
2181 : 0 : inchi_strbuf_printf(&pfrag->sig, "(%-d:%-d)", k, cnt[k]);
2182 : : }
2183 : : }
2184 : :
2185 : 0 : inchi_strbuf_printf(&pfrag->sig, "}");
2186 : :
2187 : 0 : return;
2188 : : }
2189 : : /***************************************************************************
2190 : : Compare two fragments and return 1 if they are different, 0 if equal
2191 : : ***************************************************************************/
2192 : 0 : int DiylFrag_Diff(DiylFrag *pfrag1, DiylFrag *pfrag2)
2193 : : {
2194 [ # # ]: 0 : if (pfrag1->na != pfrag2->na)
2195 : : {
2196 : 0 : return 1;
2197 : : }
2198 [ # # ]: 0 : if (pfrag1->nb != pfrag2->nb)
2199 : : {
2200 : 0 : return 1;
2201 : : }
2202 [ # # # # ]: 0 : if (pfrag1->sig.nUsedLength && pfrag2->sig.nUsedLength)
2203 : : {
2204 : 0 : int cmp = strcmp(pfrag1->sig.pStr, pfrag2->sig.pStr);
2205 : 0 : return cmp;
2206 : : }
2207 : :
2208 : 0 : return 0;
2209 : : }
2210 : : /****************************************************************************
2211 : : Debug print polymer data for a given SRU
2212 : : ****************************************************************************/
2213 : 0 : void DiylFrag_DebugTrace(DiylFrag *pfrag)
2214 : : {
2215 : : int k, na;
2216 : :
2217 [ # # ]: 0 : if (!pfrag)
2218 : : {
2219 : 0 : return;
2220 : : }
2221 : :
2222 : : ITRACE_("DiylFrag @ %-p ", pfrag);
2223 : 0 : na = pfrag->na;
2224 : : ITRACE_("\n\t%-d atoms. List of atoms and their xclasses : { ", na);
2225 [ # # ]: 0 : for (k = 0; k < na - 1; k++)
2226 : : {
2227 : : ITRACE_(" %-d(%-d), ", pfrag->alist[k], pfrag->xclist[k]);
2228 : : }
2229 : : ITRACE_(" %-d(%-d) }\n", pfrag->alist[na - 1], pfrag->xclist[na - 1]);
2230 : :
2231 : : ITRACE_("\tend1 = %-d, end2 = %-d, nb = %-d\n", pfrag->end1, pfrag->end2, pfrag->nb);
2232 : :
2233 : : ITRACE_("\tSignature = '%-s'\n", pfrag->sig.pStr);
2234 : :
2235 : 0 : return;
2236 : : }
2237 : :
2238 : :
2239 : : /***************************************************************************/
2240 : 0 : int analyze_CRU_folding(ORIG_ATOM_DATA *orig_at_data,
2241 : : int iunit,
2242 : : int n_all_bkb,
2243 : : int *all_bkb,
2244 : : int nxclasses,
2245 : : int *xc,
2246 : : OAD_StructureEdits *ed)
2247 : : {
2248 : 0 : int ret = _IS_OKAY;
2249 : : int err, i, j, k, m, fail, a1, a2;
2250 : 0 : int n_cuts = 0, n_frags = 0;
2251 : 0 : int n_frags_in_repeating_subunit = 0;
2252 : 0 : int n_fold, n_frag_classes = 0;
2253 : 0 : int subunit_last_atom, next_subunit_first_atom = 0;
2254 : 0 : int *cut = NULL; /* [ bkbond1at1, bkbond1at2, bkbond2at1,bkbond2at2, ... ]
2255 : : these are (atoms of) backbone bonds which are non-cyclic and non-multiple ('breakable') */
2256 : 0 : DiylFrag **frag=NULL; /* frag is divalent fragment surrounded by 'cut' bonds, so it may be a repeating CRU sub-unit */
2257 : 0 : int *frag_class=NULL; /* fragments are classified, by their signatures, to produce unique labelling;
2258 : : if the two fragments have the same class, they have the same signature and whence are equivalent */
2259 : 0 : int *frag_xc_counts = NULL; /* counts of xclass atoms in CRU, order of class numbers */
2260 : : char pStrErr[STR_ERR_LEN];
2261 : :
2262 : 0 : OAD_PolymerUnit *u = orig_at_data->polymer->units[iunit];
2263 : : ITRACE_("\n\n%-s\t\t%-s:%-d", "analyze_CRU_folding()", __FILE__,__LINE__);
2264 : :
2265 : 0 : pStrErr[0] = '\0'; /* djb-rwth: fixing coverity ID #499611; pStrErr is a dummy parameter in this function and is never used */
2266 : :
2267 : : /* Reserve space for frag-specific xclass counts */
2268 : 0 : frag_xc_counts = (int *)inchi_calloc((long long)nxclasses + 1, sizeof(int)); /* djb-rwth: cast operator added */
2269 [ # # ]: 0 : if (!frag_xc_counts)
2270 : : {
2271 : 0 : ret = _IS_ERROR;
2272 : 0 : goto exit_function;
2273 : : }
2274 : :
2275 : :
2276 : : /* Prepare list of cuts - backbone lying on the way from cap1 to cap2 */
2277 : 0 : cut = (int *)inchi_calloc(2 * (long long)n_all_bkb, sizeof(int)); /* djb-rwth: cast operator added */
2278 [ # # ]: 0 : if (!cut)
2279 : : {
2280 : 0 : ret = _IS_ERROR;
2281 : 0 : goto exit_function;
2282 : : }
2283 : :
2284 : 0 : OAD_PolymerUnit_DebugTrace(u);
2285 : 0 : OAD_CollectBackboneBonds(orig_at_data,
2286 : : u->na, u->alist,
2287 : : u->end_atom1, u->end_atom2,
2288 : : &(u->nbkbonds), u->bkbonds,
2289 : : &err, pStrErr);
2290 [ # # ]: 0 : if (err)
2291 : : {
2292 : 0 : ret = _IS_ERROR;
2293 : 0 : goto exit_function;
2294 : : }
2295 : 0 : OAD_PolymerUnit_DebugTrace(u);
2296 [ # # ]: 0 : if (u->nbkbonds < 1)
2297 : : {
2298 : 0 : goto exit_function;
2299 : : }
2300 : :
2301 : : /* Make 'cut' list from the bonds which are both in all_bkb and u->bkb
2302 : : (all_bkb eliminates bonds with order >1 and cyclic ones,
2303 : : but may contain artificial cyclizing bond)
2304 : : */
2305 [ # # ]: 0 : for (i = 0; i <u->nbkbonds; i++)
2306 : : {
2307 : 0 : a1 = u->bkbonds[i][0];
2308 : 0 : a2 = u->bkbonds[i][1];
2309 [ # # ]: 0 : for (j = 0; j < n_all_bkb; j++)
2310 : : {
2311 [ # # ]: 0 : if (bIsSameBond(a1, a2, all_bkb[2 * j], all_bkb[2 * j + 1]))
2312 : : {
2313 : 0 : cut[2 * n_cuts] = a1; /* djb-rwth: buffer overrun implicitly avoided in loop condition */
2314 : 0 : cut[2 * n_cuts + 1] = a2;
2315 : 0 : n_cuts++;
2316 : 0 : break;
2317 : : }
2318 : : }
2319 : : }
2320 [ # # ]: 0 : if (n_cuts < 1)
2321 : : {
2322 : : /* no valid sub-units is available */
2323 : 0 : goto exit_function;
2324 : : }
2325 : :
2326 : : /* Collect fragments */
2327 : 0 : n_frags = n_cuts + 1;
2328 : 0 : frag = (DiylFrag**) inchi_calloc(n_frags, sizeof(DiylFrag *));
2329 [ # # ]: 0 : if (!frag)
2330 : : {
2331 : 0 : ret = _IS_ERROR;
2332 : 0 : goto exit_function;
2333 : : }
2334 : 0 : frag_class = (int *) inchi_calloc(n_frags, sizeof(int));
2335 [ # # ]: 0 : if (!frag_class)
2336 : : {
2337 : 0 : ret = _IS_ERROR;
2338 : 0 : goto exit_function;
2339 : : }
2340 : 0 : n_frag_classes = 0;
2341 [ # # ]: 0 : for (i = 0; i < n_frags; i++)
2342 : : {
2343 : : /* Create fragment */
2344 : 0 : int forbidden[4], novel=1;
2345 : 0 : DiylFrag *pfrag = NULL;
2346 : :
2347 : : /* Calculate and store signature of the fragment */
2348 : : /*
2349 : : end_atom1...cut[i-1])---frag[i]---cut[i]---...end_atom2
2350 : : */
2351 [ # # ]: 0 : if (i == 0)
2352 : : {
2353 : 0 : a1 = u->end_atom1;
2354 : 0 : forbidden[0] = u->cap1;
2355 : : }
2356 : : else
2357 : : {
2358 : 0 : a1 = cut[2 * (i-1) + 1]; /* near end of prev cut */
2359 : 0 : forbidden[0] = cut[2 * (i - 1) ]; /* far end of prev cut */
2360 : : }
2361 : 0 : forbidden[1] = a1;
2362 [ # # ]: 0 : if (i==n_frags-1)
2363 : : {
2364 : 0 : a2 = u->end_atom2;
2365 : 0 : forbidden[2] = u->cap2;
2366 : : }
2367 : : else
2368 : : {
2369 : 0 : a2 = cut[2 * i]; /* near end of next cut */
2370 : 0 : forbidden[2] = cut[2 * i + 1]; /* far end of next cut */
2371 : : }
2372 : 0 : forbidden[3] = a2;
2373 : :
2374 : 0 : pfrag = DiylFrag_New(u->na, a1, a2, "");
2375 [ # # ]: 0 : if (!pfrag)
2376 : : {
2377 : 0 : ret = _IS_ERROR;
2378 : 0 : goto exit_function;
2379 : : }
2380 : 0 : frag[i] = pfrag;
2381 : :
2382 : 0 : ret = OAD_CollectReachableAtoms(orig_at_data, a1, 2, forbidden,
2383 : : &pfrag->na, pfrag->alist, &err, pStrErr);
2384 [ # # ]: 0 : if (ret==_IS_ERROR)
2385 : : {
2386 : 0 : goto exit_function;
2387 : : }
2388 : :
2389 : 0 : DiylFrag_MakeSignature(pfrag, nxclasses, xc, frag_xc_counts);
2390 : :
2391 : 0 : novel = 1;
2392 [ # # ]: 0 : for (j = 0; j < i; j++)
2393 : : {
2394 [ # # ]: 0 : if ( !DiylFrag_Diff(frag[i], frag[j]) )
2395 : : {
2396 : 0 : frag_class[i] = frag_class[j];
2397 : 0 : novel = 0;
2398 : 0 : break;
2399 : : }
2400 : : }
2401 [ # # ]: 0 : if (novel)
2402 : : {
2403 : 0 : frag_class[i] = n_frag_classes++;
2404 : : }
2405 : :
2406 : : ITRACE_("\nCANDIDATE CRU SUBUNIT %-d/%-d (CLASS #%-d)\t", i+1, n_frags, frag_class[i]);
2407 : 0 : DiylFrag_DebugTrace(pfrag);
2408 : : }
2409 : :
2410 [ # # ]: 0 : if (n_frag_classes == n_frags)
2411 : : {
2412 : : /* All classes are distinct ==> no repeats, folding is impossible, skip the CRU */
2413 : 0 : goto exit_function;
2414 : : }
2415 : :
2416 : 0 : n_frags_in_repeating_subunit = len_repeating_subsequence(frag_class, NULL, n_frags);
2417 [ # # ]: 0 : if (0 == n_frags_in_repeating_subunit)
2418 : : {
2419 : : /* valid repeating pattern not found */
2420 : 0 : goto exit_function;
2421 : : }
2422 : 0 : n_fold = n_frags / n_frags_in_repeating_subunit;
2423 [ # # # # ]: 0 : if (1==n_fold || (0!=n_frags%n_frags_in_repeating_subunit) )
2424 : : {
2425 : : /* valid repeating pattern not found */
2426 : 0 : goto exit_function;
2427 : : }
2428 : : ITRACE_("\n");
2429 : :
2430 : : /* {1...2}---{5...6}---{8...9} */
2431 : :
2432 : : ITRACE_("\n* Found %-d times foldable unit of %-d fragments\n* First repeating sub-unit formed by %-d-fragment backbone : ",
2433 : : n_fold, n_frags, n_frags_in_repeating_subunit);
2434 : :
2435 [ # # # # : 0 : for (k = 0; k < n_frags_in_repeating_subunit && n_frags_in_repeating_subunit < n_frags && frag[k]; k++) /* djb-rwth: fixing a NULL pointer dereference and buffer overflow */
# # ]
2436 : : {
2437 : : if (frag[k]->end1 == frag[k]->end2)
2438 : : {
2439 : : ITRACE_("-{%-d}-", frag[k]->end1, frag[k]->end2);
2440 : : }
2441 : : else
2442 : : {
2443 : : ITRACE_("-{%-d...%-d}-", frag[k]->end1, frag[k]->end2);
2444 : : }
2445 : : }
2446 : :
2447 : : ITRACE_("\n");
2448 : : ITRACE_("* Backbone pattern for %-d fragments that may be removed : ", n_frags - n_frags_in_repeating_subunit);
2449 [ # # ]: 0 : for (k = n_frags_in_repeating_subunit; k < n_frags; k++)
2450 : : {
2451 : : if (frag[k]->end1 == frag[k]->end2)
2452 : : {
2453 : : ITRACE_("-{%-d}-", frag[k]->end1, frag[k]->end2);
2454 : : }
2455 : : else
2456 : : {
2457 : : ITRACE_("-{%-d...%-d}-", frag[k]->end1, frag[k]->end2);
2458 : : }
2459 : : }
2460 : : ITRACE_("\n");
2461 : :
2462 : : /* Folding is possible, prepare the edits
2463 : : Keep the least in-CRU repeating subunit
2464 : : { frag[0] ... frag[n_frags_in_repeating_subunit-1] }
2465 : : and remove
2466 : : { frag[n_frags_in_repeating_subunit]...frag[n_frags-1] } and all side chain attached to that
2467 : :
2468 : : NB: which bond is modified and which is broke is important for applying these edits further!
2469 : : */
2470 : :
2471 : : /* Break bond from the subunit to the next fragment and replace an original
2472 : : bond to "right" cap with bond from the subunit "right" atom
2473 : : */
2474 : :
2475 : : /*djb-rwth: the whole block had to be rewritten to fix NULL pointer dereference */
2476 [ # # # # : 0 : if (n_frags_in_repeating_subunit < n_frags && frag[n_frags_in_repeating_subunit] && frag[n_frags_in_repeating_subunit - 1]) /* djb-rwth: fixing a NULL pointer dereference and buffer overflow */
# # ]
2477 : : {
2478 : 0 : subunit_last_atom = frag[n_frags_in_repeating_subunit - 1]->end2;
2479 : 0 : next_subunit_first_atom = frag[n_frags_in_repeating_subunit]->end1;
2480 : :
2481 : 0 : fail = 0;
2482 : 0 : fail += IntArray_Append(ed->del_bond, subunit_last_atom);
2483 : 0 : fail += IntArray_Append(ed->del_bond, next_subunit_first_atom);
2484 : :
2485 : 0 : fail += IntArray_Append(ed->mod_bond, u->end_atom2);
2486 : 0 : fail += IntArray_Append(ed->mod_bond, u->cap2);
2487 : 0 : fail += IntArray_Append(ed->mod_bond, subunit_last_atom);
2488 : 0 : fail += IntArray_Append(ed->mod_bond, u->cap2);
2489 : :
2490 [ # # ]: 0 : if (fail)
2491 : : {
2492 : 0 : ret = _IS_ERROR;
2493 : 0 : goto exit_function;
2494 : : }
2495 : : }
2496 : :
2497 : : /* Now collect all backbone atoms to be deleted (we will then delete the
2498 : : associated side chains also, but no need to reveal them at the moment) */
2499 : :
2500 [ # # ]: 0 : for (k = n_frags_in_repeating_subunit; k < n_frags; k++)
2501 : : {
2502 [ # # ]: 0 : if (frag[k]) /* djb-rwth: fixing a NULL pointer dereference */
2503 : : {
2504 [ # # ]: 0 : for (m = 0; m < frag[k]->na; m++)
2505 : : {
2506 : 0 : fail = IntArray_AppendIfAbsent(ed->del_atom, frag[k]->alist[m]);
2507 [ # # ]: 0 : if (fail)
2508 : : {
2509 : 0 : ret = _IS_ERROR;
2510 : 0 : goto exit_function;
2511 : : }
2512 : : }
2513 : : }
2514 : : }
2515 : : /* Care on atom coordinates: as bond to cap2 changes,
2516 : : we use coordinates of next_subunit_first_atom for cap2
2517 : : */
2518 : 0 : fail = 0;
2519 : 0 : fail += IntArray_Append(ed->mod_coord, next_subunit_first_atom);
2520 : 0 : fail += IntArray_Append(ed->mod_coord, u->cap2);
2521 [ # # ]: 0 : if (fail)
2522 : : {
2523 : 0 : ret = _IS_ERROR;
2524 : 0 : goto exit_function;
2525 : : }
2526 : :
2527 : 0 : exit_function:
2528 [ # # ]: 0 : if (cut)
2529 : : {
2530 [ # # ]: 0 : inchi_free(cut);
2531 : : }
2532 [ # # ]: 0 : if (frag)
2533 : : {
2534 [ # # ]: 0 : for (i = 0; i < n_frags; i++)
2535 : : {
2536 : 0 : DiylFrag_Free(frag[i]);
2537 [ # # ]: 0 : inchi_free(frag[i]);
2538 : : }
2539 [ # # ]: 0 : inchi_free(frag);
2540 : : }
2541 [ # # ]: 0 : if (frag_class)
2542 : : {
2543 [ # # ]: 0 : inchi_free(frag_class);
2544 : : }
2545 [ # # ]: 0 : if (frag_xc_counts)
2546 : : {
2547 [ # # ]: 0 : inchi_free(frag_xc_counts);
2548 : : }
2549 : :
2550 : 0 : return ret;
2551 : : }
2552 : :
2553 : : /***************************************************************************
2554 : : Return number of colors ncol<=maxcol in the sequence of n colored entries
2555 : : and counts of individiual colors
2556 : : ***************************************************************************/
2557 : 0 : int count_colors_in_sequence( int *color, int n, int maxcol, int *counts)
2558 : : {
2559 : 0 : int i, ncol=0;
2560 : 0 : memset(counts, 0, maxcol * sizeof(int)); /* djb-rwth: memset_s C11/Annex K variant? */
2561 [ # # ]: 0 : for (i = 0; i<n; i++)
2562 : : {
2563 : 0 : int colori = color[i];
2564 [ # # ]: 0 : if (colori < 0) /* removed orig atom (H D etc.) */
2565 : : {
2566 : 0 : continue;
2567 : : }
2568 [ # # ]: 0 : if (0==counts[colori ])
2569 : : {
2570 : 0 : ncol++;
2571 : : }
2572 : 0 : counts[ color[i] ]++;
2573 : : }
2574 : 0 : return ncol;
2575 : : }
2576 : :
2577 : :
2578 : : /***************************************************************************
2579 : : Find repeating starting subsequence in the sequence of n entries
2580 : : and return its length m
2581 : : each i-th entry, 0<i<m, is characterized by color[i] and optional color2[i]
2582 : : ***************************************************************************/
2583 : 0 : int len_repeating_subsequence(int *color, int *color2, int n)
2584 : : {
2585 : : int m, k;
2586 : :
2587 [ # # # # ]: 0 : if (n < 2 || !color)
2588 : : {
2589 : 0 : return 0;
2590 : : }
2591 : :
2592 [ # # ]: 0 : for (m = 0; m < (n + 1) / 2; m++)
2593 : : {
2594 [ # # ]: 0 : for (k = m + 1; k < n; k++)
2595 : : {
2596 [ # # ]: 0 : if (color[k] != color[k - m - 1])
2597 : : {
2598 : 0 : goto nextm;
2599 : : }
2600 [ # # # # ]: 0 : if (color2 && color2[k] != color2[k - m - 1])
2601 : : {
2602 : 0 : goto nextm;
2603 : : }
2604 : : }
2605 : 0 : return (m + 1);
2606 : 0 : nextm: ;
2607 : : }
2608 : :
2609 : 0 : return 0;
2610 : : }
2611 : :
2612 : :
2613 : : /****************************************************************************
2614 : : Prepare CRU edits suggested by the string containing preliminary generated
2615 : : interim (1.05+ flavoured) InChI and AuxInfo
2616 : : ****************************************************************************/
2617 : 0 : int OAD_Polymer_PrepareFrameShiftEdits( ORIG_ATOM_DATA *orig_at_data,
2618 : : char *sinchi,
2619 : : char *saux,
2620 : : OAD_StructureEdits *ed)
2621 : : {
2622 : 0 : int ret = _IS_OKAY;
2623 : 0 : int *orig = NULL, *frame_shift_info = NULL;
2624 : : int n_frame_shifts, j;
2625 : 0 : ModSCenterInfo *scinfo = NULL; /* 4 elements; [0]th for old_end1, [1] old_end2, [2] end1, [3] end2 */
2626 : :
2627 : 0 : OAD_Polymer *p = orig_at_data->polymer;
2628 : 0 : int nu = orig_at_data->polymer->n;
2629 : 0 : int nat = orig_at_data->num_inp_atoms;
2630 : :
2631 : : /* Extract cano_nums-->orig_nums mapping for InChI AuxInfo Main Layer */
2632 : 0 : orig = (int *)inchi_calloc((long long)nat + 1, sizeof(int)); /* djb-rwth: cast operator added */
2633 [ # # ]: 0 : if (!orig)
2634 : : {
2635 : 0 : ret = _IS_ERROR;
2636 : 0 : goto exit_function;
2637 : : }
2638 : 0 : ret = extract_orig_nums_from_auxinfo_string(saux, orig);
2639 [ # # # # ]: 0 : if (ret != _IS_OKAY && ret != _IS_WARNING)
2640 : : {
2641 : 0 : ret = _IS_ERROR;
2642 : 0 : goto exit_function;
2643 : : }
2644 : :
2645 : 0 : scinfo = (ModSCenterInfo *)inchi_calloc(4, sizeof(scinfo[0]));
2646 [ # # ]: 0 : if (!scinfo)
2647 : : {
2648 : 0 : ret = _IS_ERROR;
2649 : 0 : goto exit_function;
2650 : : }
2651 : :
2652 : :
2653 : : /* Parse InChI and extract, for each 'bistar' CRU, the senior bkbond (to frame-shift brackets to its ends) */
2654 : 0 : frame_shift_info = (int *)inchi_calloc(3 * ((long long)nu + 1), sizeof(int)); /* djb-rwth: cast operator added */
2655 [ # # ]: 0 : if (!frame_shift_info)
2656 : : {
2657 : 0 : ret = _IS_ERROR;
2658 : 0 : goto exit_function;
2659 : : }
2660 : 0 : n_frame_shifts = GetFrameShiftInfoFrom105PlusInChI(sinchi, frame_shift_info, nu);
2661 : : /* translate atom numbers to orig numbers */
2662 [ # # ]: 0 : for (j = 0; j < n_frame_shifts; j++)
2663 : : {
2664 : 0 : frame_shift_info[3 * j + 1] = orig[frame_shift_info[3 * j + 1]];
2665 : 0 : frame_shift_info[3 * j + 2] = orig[frame_shift_info[3 * j + 2]];
2666 : : }
2667 : :
2668 : : /* Collect OAD edits */
2669 [ # # ]: 0 : for (j = 0; j < n_frame_shifts; j++)
2670 : : {
2671 : 0 : OAD_PolymerUnit *u = NULL;
2672 : 0 : int k, iu = -1; /*int iu = frame_shift_info[3 * j];*/
2673 : 0 : int end1, cap1, cap1_is_star, end2, cap2, cap2_is_star, old_end1, old_end2, err, fail = 0;
2674 : :
2675 : 0 : end1 = frame_shift_info[3 * j + 1];
2676 : 0 : end2 = frame_shift_info[3 * j + 2];
2677 : :
2678 : : /* Find the unit to edit (== that unit whose alist contains the new end atoms) */
2679 [ # # ]: 0 : for (k = 0; k < p->n; k++)
2680 : : {
2681 : 0 : int ak, present=0;
2682 : :
2683 [ # # # # ]: 0 : if (NULL == p->units[k]->blist || p->units[k]->nb < 2 )
2684 : : {
2685 : : /* No crossing bonds in the unit */
2686 : 0 : continue;
2687 : : }
2688 : : /* Find the unit to edit (== that unit whose backbone contains the new end atoms)
2689 : : for (bk = 0; bk < p->units[k]->nbkbonds; bk++ )
2690 : : {
2691 : : if ( bIsSameBond(end1, end2, p->units[k]->bkbonds[bk][0], p->units[k]->bkbonds[bk][1] ) )
2692 : : {
2693 : : iu = k;
2694 : : break;
2695 : : }
2696 : : }*/
2697 [ # # ]: 0 : for (ak = 0; ak < p->units[k]->na; ak++ )
2698 : : {
2699 [ # # # # ]: 0 : if (p->units[k]->alist[ak] == end1 || p->units[k]->alist[ak] == end2)
2700 : : {
2701 : 0 : present++;
2702 : : }
2703 [ # # ]: 0 : if (present==2)
2704 : : {
2705 : 0 : iu = k;
2706 : 0 : break;
2707 : : }
2708 : : }
2709 : : }
2710 [ # # ]: 0 : if (iu < 0)
2711 : : {
2712 : : /* Unit to edit unexpectedly not found, that's an error */
2713 : 0 : ret = _IS_ERROR;
2714 : 0 : goto exit_function;
2715 : : }
2716 : :
2717 : 0 : u = p->units[iu];
2718 : :
2719 : 0 : OAD_PolymerUnit_FindEndsAndCaps(u, orig_at_data,
2720 : : &old_end1, &cap1, &cap1_is_star,
2721 : : &old_end2, &cap2, &cap2_is_star,
2722 : : &err, NULL);
2723 : :
2724 [ # # # # : 0 : if (!err && cap1_is_star && cap2_is_star && end1 && end2 && cap1 && cap2)
# # # # #
# # # #
# ]
2725 : : {
2726 : : /* find old CRU ends */
2727 [ # # ]: 0 : if (cap1 == u->blist[0]) old_end1 = u->blist[1];
2728 [ # # ]: 0 : else if (cap1 == u->blist[1]) old_end1 = u->blist[0];
2729 [ # # ]: 0 : else if (cap1 == u->blist[2]) old_end1 = u->blist[3];
2730 [ # # ]: 0 : else if (cap1 == u->blist[3]) old_end1 = u->blist[2];
2731 : : else /* something wrong */
2732 : 0 : continue;
2733 [ # # ]: 0 : if (cap2 == u->blist[0]) old_end2 = u->blist[1];
2734 [ # # ]: 0 : else if (cap2 == u->blist[1]) old_end2 = u->blist[0];
2735 [ # # ]: 0 : else if (cap2 == u->blist[2]) old_end2 = u->blist[3];
2736 [ # # ]: 0 : else if (cap2 == u->blist[3]) old_end2 = u->blist[2];
2737 : : else /* something wrong */
2738 : 0 : continue;
2739 : :
2740 [ # # # # : 0 : if (!old_end1 || !old_end2 || old_end1 == old_end2)
# # ]
2741 : : {
2742 : 0 : continue;
2743 : : }
2744 [ # # # # ]: 0 : if (bIsSameBond(old_end1, cap1, end1, cap1) && bIsSameBond(old_end2, cap2, end2, cap2))
2745 : : {
2746 : 0 : continue; /* ignore swaps for now */
2747 : : }
2748 : :
2749 : : /* If applicable, collect bonds to modify */
2750 : :
2751 : : /* Check if atoms involved in modifications are stereocenters (needs additional care) */
2752 : 0 : ModSCenter_Init(&scinfo[0], orig_at_data->at, old_end1 - 1);
2753 : 0 : ModSCenter_Init(&scinfo[1], orig_at_data->at, old_end2 - 1);
2754 : 0 : ModSCenter_Init(&scinfo[2], orig_at_data->at, end1 - 1);
2755 : 0 : ModSCenter_Init(&scinfo[3], orig_at_data->at, end2 - 1);
2756 : :
2757 : : /* djb-rwth: removing redundant code */
2758 [ # # ]: 0 : if (!bIsSameBond(old_end1, cap1, end1, cap1))
2759 : : {
2760 : : /* Modify bond: (old_end1-cap1) --> (end1-cap1) */
2761 : 0 : fail = 0;
2762 : 0 : fail += IntArray_Append(ed->mod_bond, old_end1);
2763 : 0 : fail += IntArray_Append(ed->mod_bond, cap1);
2764 : 0 : fail += IntArray_Append(ed->mod_bond, end1);
2765 : 0 : fail += IntArray_Append(ed->mod_bond, cap1);
2766 [ # # ]: 0 : if (fail)
2767 : : {
2768 : 0 : ret = _IS_ERROR;
2769 : 0 : goto exit_function;
2770 : : }
2771 : 0 : ModSCenter_DelFrom(&scinfo[0], cap1 - 1);
2772 : 0 : ModSCenter_AddTo(&scinfo[2], cap1-1 );
2773 : : }
2774 [ # # ]: 0 : if (!bIsSameBond(old_end2, cap2, end2, cap2))
2775 : : {
2776 : : /* Modify bond: (old_end2-cap2) --> (end2-cap2) */
2777 : 0 : fail = 0;
2778 : 0 : fail += IntArray_Append(ed->mod_bond, old_end2);
2779 : 0 : fail += IntArray_Append(ed->mod_bond, cap2);
2780 : 0 : fail += IntArray_Append(ed->mod_bond, end2);
2781 : 0 : fail += IntArray_Append(ed->mod_bond, cap2);
2782 [ # # ]: 0 : if (fail)
2783 : : {
2784 : 0 : ret = _IS_ERROR;
2785 : 0 : goto exit_function;
2786 : : }
2787 : 0 : ModSCenter_DelFrom(&scinfo[1], cap2 - 1);
2788 : 0 : ModSCenter_AddTo(&scinfo[3], cap2 - 1);
2789 : : }
2790 : : /* Modify bond: (end1-end2) --> (old_end1-old_end2) */
2791 : 0 : fail = 0;
2792 : 0 : fail += IntArray_Append(ed->mod_bond, end1);
2793 : 0 : fail += IntArray_Append(ed->mod_bond, end2);
2794 : 0 : fail += IntArray_Append(ed->mod_bond, old_end1);
2795 : 0 : fail += IntArray_Append(ed->mod_bond, old_end2);
2796 [ # # ]: 0 : if (fail)
2797 : : {
2798 : 0 : ret = _IS_ERROR;
2799 : 0 : goto exit_function;
2800 : : }
2801 : 0 : ModSCenter_DelFrom(&scinfo[2], end2 - 1);
2802 : 0 : ModSCenter_DelFrom(&scinfo[3], end1 - 1);
2803 : 0 : ModSCenter_AddTo(&scinfo[0], old_end2 - 1);
2804 : 0 : ModSCenter_AddTo(&scinfo[1], old_end1 - 1);
2805 : :
2806 : : }
2807 : :
2808 : : /* djb-rwth: n_flip and ModSCenter_IsChanged function completely redundant? -- discussion required */
2809 [ # # ]: 0 : if (orig_at_data->num_dimensions)
2810 : : {
2811 : : /* Check if we must flip stereocenter configuration */
2812 : : /* (ignore errrors signaled by returning -1) */
2813 : 0 : int n_flip = 0;
2814 [ # # ]: 0 : if (0 < ModSCenter_IsChanged(&scinfo[0], orig_at_data->at))
2815 : : {
2816 : 0 : n_flip++;
2817 : : }
2818 [ # # ]: 0 : if (0 < ModSCenter_IsChanged(&scinfo[1], orig_at_data->at))
2819 : : {
2820 : 0 : n_flip++;
2821 : : }
2822 [ # # ]: 0 : if (0 < ModSCenter_IsChanged(&scinfo[2], orig_at_data->at))
2823 : : {
2824 : 0 : n_flip++;
2825 : : }
2826 [ # # ]: 0 : if (0 < ModSCenter_IsChanged(&scinfo[3], orig_at_data->at))
2827 : : {
2828 : 0 : n_flip++;
2829 : : }
2830 : 0 : n_flip = 1;
2831 : : }
2832 : : }
2833 : :
2834 : 0 : exit_function:
2835 [ # # ]: 0 : if (orig)
2836 : : {
2837 [ # # ]: 0 : inchi_free(orig);
2838 : : }
2839 [ # # ]: 0 : if (frame_shift_info)
2840 : : {
2841 [ # # ]: 0 : inchi_free(frame_shift_info);
2842 : : }
2843 [ # # ]: 0 : if (scinfo)
2844 : : {
2845 [ # # ]: 0 : inchi_free(scinfo);
2846 : : }
2847 : :
2848 : 0 : return ret;
2849 : : }
2850 : :
2851 : : /****************************************************************************
2852 : : Initialize modifiable stereo center
2853 : : ****************************************************************************/
2854 : 0 : void ModSCenter_Init(ModSCenterInfo *scinfo, inp_ATOM *at, int iatom)
2855 : : {
2856 : : int i;
2857 : 0 : scinfo->num = iatom;
2858 : 0 : scinfo->valence = at[iatom].valence;
2859 : 0 : scinfo->n_stereo = NDefStereoBonds(at, iatom, 1); /* , bOnlyPointedEndMatters=1 */
2860 [ # # ]: 0 : for (i = 0; i < scinfo->valence; i++)
2861 : : {
2862 : 0 : scinfo->nbr[i] = at[iatom].neighbor[i];
2863 : 0 : scinfo->new_nbr[i] = scinfo->nbr[i];
2864 : : }
2865 : :
2866 : 0 : return;
2867 : : }
2868 : : /****************************************************************************/
2869 : 0 : int NDefStereoBonds(inp_ATOM *at, int iatom, int bOnlyPointedEndMatters)
2870 : : {
2871 : 0 : int i, n_stereo = 0;
2872 : : int stereo_value, stereo_type;
2873 [ # # ]: 0 : for (i = 0; i < at[iatom].valence; i++)
2874 : : {
2875 : 0 : stereo_value = at[iatom].bond_stereo[i];
2876 [ # # ]: 0 : if (bOnlyPointedEndMatters)
2877 : : {
2878 : : /* establish the stereo considering only the pointed end of stereo bond */
2879 : 0 : stereo_type = stereo_value;
2880 : : }
2881 : : else
2882 : : {
2883 : 0 : stereo_type = abs(stereo_value);
2884 : : }
2885 [ # # # # ]: 0 : if (stereo_type == STEREO_SNGL_UP || stereo_type == STEREO_SNGL_DOWN)
2886 : : {
2887 : 0 : n_stereo++;
2888 : : }
2889 : : }
2890 : 0 : return n_stereo;
2891 : : }
2892 : :
2893 : :
2894 : : /****************************************************************************
2895 : : Add atom to modifiable stereo center
2896 : : ****************************************************************************/
2897 : 0 : void ModSCenter_AddTo(ModSCenterInfo *scinfo, int iadd)
2898 : : {
2899 [ # # ]: 0 : if (!is_in_the_ilist(scinfo->new_nbr, iadd, scinfo->valence))
2900 : : {
2901 : 0 : scinfo->new_nbr[scinfo->valence] = iadd;
2902 : 0 : scinfo->valence++;
2903 : : }
2904 : 0 : return;
2905 : : }
2906 : : /****************************************************************************
2907 : : Delete atom from modifiable stereo center
2908 : : ****************************************************************************/
2909 : 0 : void ModSCenter_DelFrom(ModSCenterInfo *scinfo, int idel)
2910 : : {
2911 : : int i, j;
2912 [ # # ]: 0 : for (i = 0; i < scinfo->valence; i++)
2913 : : {
2914 [ # # ]: 0 : if (scinfo->nbr[i]==idel )
2915 : : {
2916 [ # # ]: 0 : for (j=i+1; j < scinfo->valence; j++)
2917 : : {
2918 : 0 : scinfo->new_nbr[j-1] = scinfo->new_nbr[j];
2919 : : }
2920 : 0 : scinfo->valence--;
2921 : 0 : return;
2922 : : }
2923 : : }
2924 : 0 : return;
2925 : : }
2926 : : /****************************************************************************
2927 : : Check if stereo configuration of modifiable stereo center changed
2928 : : ****************************************************************************/
2929 : : /* djb-rwth: n_flip and ModSCenter_IsChanged function completely redundant? -- discussion required */
2930 : 0 : int ModSCenter_IsChanged(ModSCenterInfo *scinfo, inp_ATOM *at)
2931 : : {
2932 : 0 : int i, ns, base1=-1, base2=-1, new_base2=-1, n_changed=0;
2933 : : double a[3], b[3], new_b[3], z[3], new_z[3], zz; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2934 : :
2935 [ # # ]: 0 : if (scinfo->n_stereo < 1)
2936 : : {
2937 : 0 : return 0;
2938 : : }
2939 [ # # ]: 0 : if (scinfo->valence != at[scinfo->num].valence )
2940 : : {
2941 : 0 : return -1; /* something went wrong */
2942 : : }
2943 : 0 : iisort(scinfo->nbr, scinfo->valence);
2944 : 0 : iisort(scinfo->new_nbr, scinfo->valence);
2945 : : /* Find the kept stereo base atom */
2946 [ # # ]: 0 : for (i = 0; i < at[scinfo->num].valence; i++)
2947 : : {
2948 [ # # ]: 0 : if ( is_in_the_ilist(scinfo->nbr, scinfo->new_nbr[i], scinfo->valence) )
2949 : : {
2950 : 0 : ns = NDefStereoBonds(at, scinfo->new_nbr[i], 0); /* bOnlyPointedEndMatters=0 */
2951 [ # # ]: 0 : if (ns==0)
2952 : : {
2953 : 0 : base1 = scinfo->new_nbr[i];
2954 : 0 : break;
2955 : : }
2956 : : }
2957 : : }
2958 [ # # ]: 0 : if (base1==-1)
2959 : : {
2960 : 0 : return -1; /* something went wrong */
2961 : : }
2962 : : /* Find the newly appeared stereo base atom */
2963 [ # # ]: 0 : for (i = 0; i < at[scinfo->num].valence; i++)
2964 : : {
2965 : : /*!!! TUT NADO NE TAK
2966 : : base2 tot, kogo net v new_nbr
2967 : : new_base2 - tot, kogo net v nbr
2968 : : */
2969 [ # # ]: 0 : if ( !is_in_the_ilist(scinfo->nbr, scinfo->new_nbr[i], scinfo->valence))
2970 : : {
2971 : 0 : ns = NDefStereoBonds(at, scinfo->nbr[i], 0);
2972 [ # # ]: 0 : if (ns == 0)
2973 : : {
2974 : 0 : new_base2 = scinfo->new_nbr[i];
2975 : 0 : base2 = scinfo->nbr[i];
2976 : 0 : n_changed++;
2977 : : }
2978 : : }
2979 : : }
2980 [ # # # # : 0 : if (n_changed > 1 || new_base2 == -1 || base2 == -1)
# # ]
2981 : : {
2982 : 0 : return -1; /* something went wrong */
2983 : : }
2984 : 0 : a[0] = at[base1].x - at[scinfo->num].x; a[1] = at[base1].y - at[scinfo->num].y; a[2] = at[base1].z - at[scinfo->num].z;
2985 : 0 : b[0] = at[base2].x - at[scinfo->num].x; b[1] = at[base2].y - at[scinfo->num].y; b[2] = at[base2].z - at[scinfo->num].z;
2986 : 0 : new_b[0] = at[new_base2].x - at[scinfo->num].x; new_b[1] = at[new_base2].y - at[scinfo->num].y; new_b[2] = at[new_base2].z - at[scinfo->num].z;
2987 : :
2988 : 0 : cross_prod3(a, b, z);
2989 : 0 : cross_prod3(a, new_b, new_z);
2990 : 0 : zz = dot_prod3(z, new_z); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2991 : :
2992 : 0 : return -1;
2993 : : }
|