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