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