Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : : #include <string.h>
42 : :
43 : : /*#define CHECK_WIN32_VC_HEAP*/
44 : :
45 : : #include "mode.h"
46 : :
47 : : #if ( READ_INCHI_STRING == 1 )
48 : :
49 : : #include "ichitime.h"
50 : : #include "ichicant.h"
51 : : #include "ichirvrs.h"
52 : :
53 : : #include "bcf_s.h"
54 : :
55 : : #define INC_ADD_EDGE 64
56 : :
57 : :
58 : : /****************************************************************************/
59 : 0 : int FixRestoredStructureStereo( struct tagCANON_GLOBALS *pCG,
60 : : INCHI_CLOCK *ic,
61 : : INCHI_MODE cmpInChI,
62 : : ICR *icr,
63 : : INCHI_MODE cmpInChI2,
64 : : ICR *icr2,
65 : : ICHICONST INPUT_PARMS *ip,
66 : : STRUCT_DATA *sd,
67 : : BN_STRUCT *pBNS,
68 : : BN_DATA *pBD,
69 : : StrFromINChI *pStruct,
70 : : inp_ATOM *at,
71 : : inp_ATOM *at2,
72 : : inp_ATOM *at3,
73 : : VAL_AT *pVA,
74 : : ALL_TC_GROUPS *pTCGroups,
75 : : T_GROUP_INFO **ppt_group_info,
76 : : inp_ATOM **ppat_norm,
77 : : inp_ATOM **ppat_prep,
78 : : INChI *pInChI[],
79 : : long num_inp,
80 : : int *pnNumRunBNS,
81 : : int *pnTotalDelta,
82 : : int forbidden_edge_mask,
83 : : int forbidden_stereo_edge_mask )
84 : : {
85 : : /*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
86 : : /* at2 should be the most recently restored atom, Fixed-H */
87 : 0 : int i, j, k, delta, max_success, cur_success, ret = 0; /* djb-rwth: removing redundant variables */
88 : : int err, iOrigInChI, iRevrInChI;
89 : : int j12, v1, v2, e, vRad;
90 : : BNS_VERTEX *pv1, *pv2, *pvRad;
91 : : BNS_EDGE *pe, *peRad;
92 : : EDGE_LIST AllChargeEdges, CurrEdges, NFlowerEdges, OtherNFlowerEdges, FixedStereoEdges, AllRadList;
93 : : EDGE_LIST TautMinusEdges[2]; /* 0 -> O & O(+), 1=> N & N(+) */
94 : :
95 : : Vertex vPathStart, vPathEnd;
96 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
97 : : INChI_Stereo *pStereoInChI, *pStereo2InChI, *pStereoRevrs, *pStereo2Revrs;
98 : :
99 : : /* Stereo */
100 : :
101 : : /* currently being processed layer */
102 : 0 : pStereoInChI = ( pInChI[0]->StereoIsotopic &&
103 : 0 : pInChI[0]->StereoIsotopic->nNumberOfStereoBonds +
104 [ # # ]: 0 : pInChI[0]->StereoIsotopic->nNumberOfStereoCenters )
105 : 0 : ? pInChI[0]->StereoIsotopic
106 [ # # ]: 0 : : pInChI[0]->Stereo;
107 : :
108 : : /* mobile-H layer in case of Fixed-H */
109 [ # # ]: 0 : pStereo2InChI = ( pStruct->bMobileH == TAUT_YES || !pInChI[1] ||
110 [ # # # # ]: 0 : !pInChI[1]->nNumberOfAtoms || pInChI[1]->bDeleted )
111 : : ? NULL
112 [ # # ]: 0 : : ( pInChI[1]->StereoIsotopic &&
113 : 0 : pInChI[1]->StereoIsotopic->nNumberOfStereoBonds +
114 [ # # ]: 0 : pInChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
115 [ # # ]: 0 : pInChI[1]->StereoIsotopic :
116 : 0 : pInChI[1]->Stereo;
117 : :
118 : : /* currently being processed layer */
119 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
120 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
121 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
122 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
123 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo;
124 : :
125 : : /* mobile-H layer in case of Fixed-H */
126 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
127 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
128 : : ? NULL
129 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
130 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
131 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
132 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
133 : 0 : pStruct->pOneINChI[1]->Stereo;
134 : :
135 : : INCHI_HEAPCHK
136 : :
137 : 0 : AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
138 : 0 : AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
139 : 0 : AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
140 : 0 : AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
141 : 0 : AllocEdgeList( &FixedStereoEdges, EDGE_LIST_CLEAR );
142 : 0 : AllocEdgeList( &AllRadList, EDGE_LIST_CLEAR );
143 : :
144 : 0 : AllocEdgeList( TautMinusEdges + 0, EDGE_LIST_CLEAR );
145 : 0 : AllocEdgeList( TautMinusEdges + 1, EDGE_LIST_CLEAR );
146 : :
147 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
148 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
149 : : {
150 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
151 : 0 : goto exit_function;
152 : : }
153 [ # # ]: 0 : if (err)
154 : : {
155 : 0 : ret = RI_ERR_ALLOC;
156 : 0 : goto exit_function;
157 : : }
158 : :
159 : 0 : cmpInChI2 = 0;
160 : :
161 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
162 : : {
163 : : /* these indexes are used to compare Mobile-H InChI */
164 [ # # # # : 0 : iOrigInChI = ( pInChI[1] && pInChI[1]->nNumberOfAtoms && !pInChI[1]->bDeleted ) ? 1 : 0;
# # ]
165 [ # # # # : 0 : iRevrInChI = ( pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted ) ? 1 : 0;
# # ]
166 : : }
167 : : else
168 : : {
169 : 0 : iOrigInChI = 0;
170 : 0 : iRevrInChI = 0;
171 : : }
172 : :
173 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
174 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
175 : : {
176 : : /* additional mobile-H compare in case of Fixed-H */
177 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
178 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
179 : : {
180 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
181 : 0 : goto exit_function;
182 : : }
183 [ # # ]: 0 : if (err)
184 : : {
185 : 0 : ret = RI_ERR_ALLOC;
186 : 0 : goto exit_function;
187 : : }
188 : : }
189 : :
190 [ # # # # ]: 0 : if (!( cmpInChI & IDIFF_SB ) && !( cmpInChI2 & IDIFF_SB ))
191 : : {
192 : 0 : goto exit_function;
193 : : }
194 : : /* need to temporarily remove fixing of stereogenic bonds */
195 [ # # ]: 0 : for (i = 0; i < pStruct->num_atoms; i++)
196 : : {
197 : 0 : pv1 = pBNS->vert + i;
198 [ # # ]: 0 : for (j = 0; j < at2[i].valence; j++)
199 : : {
200 : 0 : pe = pBNS->edge + ( e = pv1->iedge[j] );
201 [ # # ]: 0 : if (j == pe->neighbor1)
202 : : {
203 : : /* do not store same bond 2 times */
204 [ # # # # ]: 0 : if (( pe->forbidden & forbidden_stereo_edge_mask ) &&
205 : 0 : ( ret = AddToEdgeList( &FixedStereoEdges, e, INC_ADD_EDGE ) )) /* djb-rwth: ignoring LLVM warning as there should be no memory leak */
206 : : {
207 : : /* djb-rwth: fixing coverity ID #499482 */
208 : 0 : goto exit_function;
209 : : }
210 : : }
211 : : }
212 : : }
213 : :
214 : : /* djb-rwth: removing redundant code */
215 : 0 : cur_success = 0;
216 [ # # # # : 0 : if (( cmpInChI & IDIF_SB_MISS ) && ( !cmpInChI2 || ( cmpInChI2 & IDIF_SB_MISS ) ) &&
# # ]
217 [ # # ]: 0 : 0 < ( max_success = pBNS->tot_st_cap - pBNS->tot_st_flow ))
218 : : {
219 : : /*----------------------------------------------------*/
220 : : /* case 01: extra stereogenic bond, radical present */
221 : : /* X=N-O* => X=N=O and eliminate radical */
222 : : /*----------------------------------------------------*/
223 : : int aN;
224 : : BNS_VERTEX *pvO, *pvN;
225 : : BNS_EDGE *peNO;
226 : :
227 : 0 : RemoveForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
228 : :
229 [ # # # # ]: 0 : for (i = 0; i < icr->num_sb_in2_only && cur_success < max_success; i++)
230 : : {
231 : 0 : j12 = icr->sb_in2_only[i];
232 : 0 : pv1 = pBNS->vert + ( v1 = pStereoInChI->nBondAtom1[j12] - 1 );
233 : 0 : pv2 = pBNS->vert + ( v2 = pStereoInChI->nBondAtom2[j12] - 1 );
234 [ # # ]: 0 : for (k = 0; k < at2[v1].valence; k++)
235 : : {
236 : 0 : pe = pBNS->edge + ( e = pv1->iedge[k] );
237 [ # # ]: 0 : if (v2 == ( pe->neighbor12 ^ v1 ))
238 : 0 : break; /* the edge has been found */
239 : : }
240 [ # # ]: 0 : if (k >= at2[v1].valence) /* djb-rwth: addressing LLVM warning */
241 : : {
242 : 0 : ret = RI_ERR_SYNTAX;
243 : 0 : goto exit_function;
244 : : }
245 : : /* check v1 */
246 : 0 : pv1->st_edge.cap--;
247 : 0 : pv1->st_edge.flow--;
248 : 0 : pv2->st_edge.flow--;
249 : 0 : pe->flow--; /* new radical on v2 */
250 : : /* djb-rwth: removing redundant code */
251 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
252 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
253 : 0 : pv1->st_edge.cap++;
254 : 0 : pv1->st_edge.flow++;
255 : 0 : pv2->st_edge.flow++;
256 : 0 : pe->flow++; /* remove new radical on v2 */
257 : :
258 [ # # # # : 0 : if (ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && ( v2 == vPathStart || v2 == vPathEnd ))
# # # # ]
259 : : {
260 [ # # ]: 0 : vRad = ( v2 == vPathStart ) ? vPathEnd : vPathStart;
261 : : }
262 : : else
263 : : {
264 : 0 : pv2->st_edge.cap--;
265 : 0 : pv2->st_edge.flow--;
266 : 0 : pv1->st_edge.flow--;
267 : 0 : pe->flow--; /* new radical on v1 */
268 : 0 : vRad = NO_VERTEX;
269 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
270 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
271 : 0 : pv2->st_edge.cap++;
272 : 0 : pv2->st_edge.flow++;
273 : 0 : pv1->st_edge.flow++;
274 : 0 : pe->flow++; /* remove new radical on v1 */
275 [ # # # # : 0 : if (ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && ( v1 == vPathStart || v1 == vPathEnd ))
# # # # ]
276 : : {
277 [ # # ]: 0 : vRad = ( v1 == vPathStart ) ? vPathEnd : vPathStart;
278 : : }
279 : : }
280 [ # # ]: 0 : if (vRad == NO_VERTEX)
281 : : {
282 : 0 : continue; /* radical did not affect this bond */
283 : : }
284 : 0 : pvRad = pBNS->vert + vRad;
285 : : /* detect =N-O* */
286 [ # # # # ]: 0 : if (pVA[vRad].cNumValenceElectrons == 6 && at2[vRad].valence == 1 &&
287 [ # # ]: 0 : ( peRad = pBNS->edge + pvRad->iedge[0] )->flow == 0 &&
288 [ # # ]: 0 : pVA[aN = peRad->neighbor12 ^ vRad].cNumValenceElectrons == 5 &&
289 [ # # ]: 0 : at2[aN].valence == 2)
290 : : {
291 : : /*------------------------------------------------------------
292 : : Fix Metal disconnection/normalization inconsistency :
293 : : disconnected restored
294 : : R=N(+)-M R=N--M R=N + M R=N + M
295 : : | -> || -> || -> |
296 : : O(-) O O O* <- radical
297 : :
298 : : The correct R=N + M(+)
299 : : disconnection |
300 : : would be this: O(-)
301 : : --------------------------------------------------------------*/
302 : 0 : pvN = pBNS->vert + aN;
303 : 0 : pvO = pvRad;
304 : 0 : peNO = peRad;
305 : :
306 : : /* N-O* => N=O */
307 : 0 : peNO->flow++;
308 : 0 : pvO->st_edge.flow++;
309 : 0 : pvN->st_edge.cap++;
310 : 0 : pvN->st_edge.flow++;
311 : 0 : pBNS->tot_st_cap += 1;
312 : 0 : pBNS->tot_st_flow += 2;
313 : 0 : cur_success++;
314 : : }
315 : : else
316 : : {
317 : : /* all other radicals that affect stereo */
318 : 0 : delta = pvRad->st_edge.cap - pvRad->st_edge.flow;
319 : 0 : pvRad->st_edge.cap -= delta;
320 : 0 : pBNS->tot_st_cap -= delta;
321 : : }
322 : : }
323 : : /*exit_case_01:*/
324 : 0 : SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
325 [ # # ]: 0 : if (cur_success)
326 : : {
327 : : /* djb-rwth: removing redundant code */
328 : : /* recalculate InChI from the structure */
329 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
330 : : ppt_group_info, ppat_norm, ppat_prep ) ))
331 : : {
332 : 0 : goto exit_function;
333 : : }
334 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
335 : : {
336 : 0 : goto exit_function;
337 : : }
338 : : /*
339 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
340 : : goto exit_function;
341 : : }
342 : : */
343 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
344 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
345 : : {
346 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
347 : 0 : goto exit_function;
348 : : }
349 [ # # ]: 0 : if (err)
350 : : {
351 : 0 : ret = RI_ERR_ALLOC;
352 : 0 : goto exit_function;
353 : : }
354 : 0 : cmpInChI2 = 0;
355 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
356 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
357 : : {
358 : : /* additional mobile-H compare in case of Fixed-H */
359 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
360 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
361 : : {
362 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
363 : 0 : goto exit_function;
364 : : }
365 [ # # ]: 0 : if (err)
366 : : {
367 : 0 : ret = RI_ERR_ALLOC;
368 : 0 : goto exit_function;
369 : : }
370 : : }
371 : :
372 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
373 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
374 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
375 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
376 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo;
377 : :
378 : :
379 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
380 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
381 : : ? NULL
382 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
383 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
384 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
385 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
386 : 0 : pStruct->pOneINChI[1]->Stereo;
387 : : }
388 : : }
389 : :
390 : : /* djb-rwth: removing redundant code */
391 [ # # # # ]: 0 : if (!( cmpInChI & IDIF_SB_MISS ) && ( cmpInChI2 & IDIF_SB_MISS ) &&
392 [ # # ]: 0 : icr2->num_sb_in2_only &&
393 [ # # ]: 0 : 0 < ( pBNS->tot_st_cap - pBNS->tot_st_flow )) /* djb-rwth: removing redundant code */
394 : : {
395 : : /*----------------------------------------------------*/
396 : : /* case 02: missing stereogenic bond in Mobile-H only */
397 : : /* X=N-O* => X=N=O and eliminate radical */
398 : : /*----------------------------------------------------*/
399 : : int retC, ret2C, retS, ret2S;
400 : : /* djb-rwth: removing redundant variables */
401 : : ICR icr_Prev, icr2_Prev;
402 : :
403 : : /* blind attepmt */
404 : 0 : icr_Prev = *icr;
405 : 0 : icr2_Prev = *icr2;
406 : : /* djb-rwth: removing redundant code */
407 [ # # ]: 0 : for (i = AllRadList.num_edges = 0; i < pStruct->num_atoms; i++)
408 : : {
409 [ # # # # ]: 0 : if (pBNS->vert[i].st_edge.cap - pBNS->vert[i].st_edge.flow == 1 &&
410 : 0 : ( ret = AddToEdgeList( &AllRadList, i, INC_ADD_EDGE ) ))
411 : : {
412 : 0 : goto exit_function;
413 : : }
414 : : }
415 [ # # ]: 0 : for (i = 0; i < AllRadList.num_edges; i++)
416 : : {
417 : 0 : j = AllRadList.pnEdges[i];
418 : 0 : pBNS->vert[j].st_edge.cap -= 1;
419 : 0 : pBNS->tot_st_cap -= 1;
420 : : }
421 : : /*-------------------------------------------------*/
422 : : /* re-create InChI and see whether it looks better */
423 : : /*-------------------------------------------------*/
424 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
425 : : ppt_group_info, ppat_norm, ppat_prep ) ))
426 : : {
427 : 0 : goto exit_function;
428 : : }
429 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
430 : : {
431 : 0 : goto exit_function;
432 : : }
433 : : /*
434 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
435 : : goto exit_function;
436 : : }
437 : : */
438 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
439 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
440 : : {
441 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
442 : 0 : goto exit_function;
443 : : }
444 [ # # ]: 0 : if (err)
445 : : {
446 : 0 : ret = RI_ERR_ALLOC;
447 : 0 : goto exit_function;
448 : : }
449 : 0 : cmpInChI2 = 0;
450 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
451 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
452 : : {
453 : : /* additional mobile-H compare in case of Fixed-H */
454 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
455 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
456 : : {
457 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
458 : 0 : goto exit_function;
459 : : }
460 [ # # ]: 0 : if (err)
461 : : {
462 : 0 : ret = RI_ERR_ALLOC;
463 : 0 : goto exit_function;
464 : : }
465 : : }
466 : 0 : retC = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_CONSTIT );
467 : 0 : retS = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_STEREO );
468 : 0 : ret2C = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_CONSTIT );
469 : 0 : ret2S = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_STEREO );
470 : :
471 [ # # # # ]: 0 : if (0 >= retC &&
472 [ # # ]: 0 : 0 >= retS &&
473 [ # # ]: 0 : 0 >= ret2C &&
474 : : 0 > ret2S)
475 : : {
476 : : ; /* accept */
477 : : }
478 : : else
479 : : {
480 : : /* reject */
481 [ # # ]: 0 : for (i = 0; i < AllRadList.num_edges; i++)
482 : : {
483 : 0 : j = AllRadList.pnEdges[i];
484 : 0 : pBNS->vert[j].st_edge.cap += 1;
485 : 0 : pBNS->tot_st_cap += 1;
486 : : }
487 : :
488 : : /*-------------------------------------------------*/
489 : : /* re-create InChI-- return to previous state */
490 : : /*-------------------------------------------------*/
491 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
492 : : ppt_group_info, ppat_norm, ppat_prep ) ))
493 : : {
494 : 0 : goto exit_function;
495 : : }
496 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
497 : : {
498 : 0 : goto exit_function;
499 : : }
500 : : /*
501 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
502 : : goto exit_function;
503 : : }
504 : : */
505 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
506 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
507 : : {
508 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
509 : 0 : goto exit_function;
510 : : }
511 [ # # ]: 0 : if (err)
512 : : {
513 : 0 : ret = RI_ERR_ALLOC;
514 : 0 : goto exit_function;
515 : : }
516 : 0 : cmpInChI2 = 0;
517 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
518 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
519 : : {
520 : : /* additional mobile-H compare in case of Fixed-H */
521 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
522 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
523 : : {
524 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
525 : 0 : goto exit_function;
526 : : }
527 [ # # ]: 0 : if (err)
528 : : {
529 : 0 : ret = RI_ERR_ALLOC;
530 : 0 : goto exit_function;
531 : : }
532 : : }
533 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
534 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
535 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters ) ?
536 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
537 : :
538 : :
539 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
540 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted ) ?
541 [ # # ]: 0 : NULL :
542 : 0 : ( pStruct->pOneINChI[1]->StereoIsotopic &&
543 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
544 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
545 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
546 : 0 : pStruct->pOneINChI[1]->Stereo;
547 : : }
548 : : /*exit_case_02:;*/
549 : : }
550 : :
551 : 0 : cur_success = 0;
552 [ # # # # ]: 0 : if (pStruct->bMobileH == TAUT_NON && ( cmpInChI & IDIF_SB_EXTRA_UNDF ) &&
553 [ # # ]: 0 : pStruct->endpoint)
554 : : {
555 : : /*------------------------------------------------------*/
556 : : /* case 03: extra stereogenic bond in Fixed-H only */
557 : : /* in Mobile-H this bond is not stereogenic. */
558 : : /* Since this bond parity is not known, it is UNDEFINED */
559 : : /*------------------------------------------------------*/
560 : : int bDone, num_endpoints;
561 : :
562 : 0 : TautMinusEdges[0].num_edges = 0;
563 : 0 : TautMinusEdges[1].num_edges = 0;
564 : 0 : AllChargeEdges.num_edges = 0;
565 : : /* in1 => in restored structure; in2 => in original InChI */
566 [ # # ]: 0 : for (i = 0; i < icr->num_sb_undef_in1_only; i++)
567 : : {
568 : 0 : j12 = icr->sb_undef_in1_only[i];
569 : 0 : pv1 = pBNS->vert + ( v1 = pStereoRevrs->nBondAtom1[j12] - 1 );
570 : 0 : pv2 = pBNS->vert + ( v2 = pStereoRevrs->nBondAtom2[j12] - 1 ); /* djb-rwth: ignoring LLVM warning: variable used */
571 : :
572 [ # # ]: 0 : if (pStereo2Revrs)
573 : : {
574 : : /* reject if it is extra in Mobile-H also */
575 [ # # ]: 0 : if (icr2->num_sb_undef_in1_only)
576 : : {
577 [ # # ]: 0 : for (j = 0; j < icr2->num_sb_undef_in1_only; j++)
578 : : {
579 : 0 : k = icr2->sb_undef_in1_only[j];
580 [ # # ]: 0 : if (v1 == pStereo2Revrs->nBondAtom1[k] &&
581 [ # # ]: 0 : v2 == pStereo2Revrs->nBondAtom2[k])
582 : : {
583 : 0 : break;
584 : : }
585 : : }
586 [ # # ]: 0 : if (j < icr->num_sb_in1_only)
587 : : {
588 : 0 : continue; /* extra stereobond in Mobile H also */
589 : : }
590 : : }
591 : : }
592 : : /* reject if it is a stereobond in Mobile-H also */
593 [ # # # # ]: 0 : if (pStereo2InChI && pStereo2InChI->nNumberOfStereoBonds)
594 : : {
595 [ # # ]: 0 : for (j = 0; j < pStereo2InChI->nNumberOfStereoBonds; j++)
596 : : {
597 [ # # ]: 0 : if (v1 == pStereo2InChI->nBondAtom1[j] &&
598 [ # # ]: 0 : v2 == pStereo2InChI->nBondAtom1[j])
599 : : {
600 : 0 : break;
601 : : }
602 : : }
603 [ # # ]: 0 : if (j < pStereo2InChI->nNumberOfStereoBonds)
604 : : {
605 : 0 : continue; /* ignore this extra stereo bond: it is in Mobile-H */
606 : : }
607 : : }
608 : : /* find the edge between v1 and v2 */
609 [ # # ]: 0 : for (k = 0; k < at2[v1].valence; k++)
610 : : {
611 : 0 : pe = pBNS->edge + ( e = pv1->iedge[k] );
612 [ # # ]: 0 : if (v2 == ( pe->neighbor12 ^ v1 ))
613 : 0 : break; /* the edge has been found */
614 : : }
615 [ # # ]: 0 : if (k >= at2[v1].valence) /* djb-rwth: addressing LLVM warning */
616 : : {
617 : 0 : ret = RI_ERR_SYNTAX;
618 : 0 : goto exit_function;
619 : : }
620 : : /* Fix all charges except negative charges on tautomeric endpoints */
621 [ # # # # : 0 : if (!AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges)
# # ]
622 : : {
623 [ # # ]: 0 : for (j = 0; j < pStruct->num_atoms; j++)
624 : : {
625 [ # # # # ]: 0 : if (( k = pVA[j].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
626 : : {
627 [ # # ]: 0 : if (!pStruct->endpoint[j])
628 : : {
629 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
630 : : {
631 : 0 : goto exit_function;
632 : : }
633 : : }
634 : : else
635 [ # # ]: 0 : if (pVA[j].cNumValenceElectrons == 6)
636 : : {
637 : : /* O */
638 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 0, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
639 : : {
640 : 0 : goto exit_function;
641 : : }
642 : : }
643 : : else
644 : : {
645 : : /* N */
646 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 1, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
647 : : {
648 : 0 : goto exit_function;
649 : : }
650 : : }
651 : : }
652 [ # # # # ]: 0 : if (( k = pVA[j].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
653 : : {
654 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
655 : : {
656 : 0 : goto exit_function;
657 : : }
658 : : /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
659 [ # # # # : 0 : if (pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
# # ]
660 : 0 : NO_VERTEX != ( k = GetChargeFlowerUpperEdge( pBNS, pVA, k ) ))
661 : : {
662 : :
663 [ # # # # ]: 0 : if (!pBNS->edge[j].forbidden && pBNS->edge[k].flow)
664 : : {
665 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
666 : : {
667 : 0 : goto exit_function;
668 : : }
669 : : }
670 : : }
671 : : }
672 : : }
673 : : }
674 [ # # ]: 0 : if (!pe->flow)
675 : 0 : continue;
676 : : /* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
677 : 0 : SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
678 [ # # # # ]: 0 : for (k = 1, bDone = 0; k < 4 && !bDone; k++)
679 : : {
680 : : /* fix tautomeric charges */
681 : 0 : num_endpoints = ( TautMinusEdges + 0 )->num_edges + ( TautMinusEdges + 1 )->num_edges;
682 [ # # ]: 0 : if (k == 2)
683 : : {
684 : : /* fix charges on O */
685 : 0 : SetForbiddenEdgeMask( pBNS, TautMinusEdges + 0, forbidden_edge_mask );
686 : 0 : num_endpoints -= ( TautMinusEdges + 0 )->num_edges;
687 : : }
688 [ # # ]: 0 : if (k == 1)
689 : : {
690 : 0 : SetForbiddenEdgeMask( pBNS, TautMinusEdges + 1, forbidden_edge_mask );
691 : 0 : num_endpoints -= ( TautMinusEdges + 1 )->num_edges;
692 : : }
693 [ # # ]: 0 : if (num_endpoints >= 2)
694 : : {
695 : 0 : delta = 1;
696 : 0 : pv1 = pBNS->vert + ( v1 = pe->neighbor1 );
697 : 0 : pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 );
698 : :
699 : 0 : pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
700 : 0 : pe->flow -= delta; /* decrement stereobond order */
701 : 0 : pv1->st_edge.flow -= delta;
702 : 0 : pv2->st_edge.flow -= delta;
703 : 0 : pBNS->tot_st_flow -= 2 * delta;
704 : :
705 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
706 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
707 : :
708 [ # # # # : 0 : if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) ||
# # ]
709 [ # # # # : 0 : (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 0) /* djb-rwth: addressing LLVM warnings */
# # ]
710 : : {
711 : : /* Negative charge has been moved, no change in number of charges */
712 : 0 : ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
713 [ # # ]: 0 : if (ret > 0)
714 : : {
715 : 0 : ( *pnNumRunBNS )++;
716 : 0 : cur_success++; /* 01 */
717 : 0 : bDone = 1;
718 : : }
719 : : }
720 : : else
721 : : {
722 : 0 : pe->forbidden &= ~forbidden_edge_mask;
723 : 0 : pe->flow += delta;
724 : 0 : pv1->st_edge.flow += delta;
725 : 0 : pv2->st_edge.flow += delta;
726 : 0 : pBNS->tot_st_flow += 2 * delta;
727 : : }
728 : : }
729 : : /* unfix tautomeric charges */
730 [ # # ]: 0 : if (k == 2)
731 : 0 : RemoveForbiddenEdgeMask( pBNS, TautMinusEdges + 0, forbidden_edge_mask );
732 [ # # ]: 0 : if (k == 1)
733 : 0 : RemoveForbiddenEdgeMask( pBNS, TautMinusEdges + 1, forbidden_edge_mask );
734 : : }
735 : 0 : RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
736 : : }
737 : : /*exit_case_03:*/
738 [ # # ]: 0 : if (cur_success)
739 : : {
740 : : /* djb-rwth: removing redundant code */
741 : : /* recalculate InChI from the structure */
742 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
743 : : ppt_group_info, ppat_norm, ppat_prep ) ))
744 : : {
745 : 0 : goto exit_function;
746 : : }
747 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
748 : : {
749 : 0 : goto exit_function;
750 : : }
751 : : /*
752 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
753 : : goto exit_function;
754 : : }
755 : : */
756 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
757 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
758 : : {
759 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
760 : 0 : goto exit_function;
761 : : }
762 [ # # ]: 0 : if (err)
763 : : {
764 : 0 : ret = RI_ERR_ALLOC;
765 : 0 : goto exit_function;
766 : : }
767 : 0 : cmpInChI2 = 0;
768 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
769 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
770 : : {
771 : : /* additional mobile-H compare in case of Fixed-H */
772 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
773 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
774 : : {
775 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
776 : 0 : goto exit_function;
777 : : }
778 [ # # ]: 0 : if (err)
779 : : {
780 : 0 : ret = RI_ERR_ALLOC;
781 : 0 : goto exit_function;
782 : : }
783 : : }
784 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
785 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
786 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
787 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
788 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo;
789 : :
790 : :
791 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
792 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
793 : : ? NULL
794 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
795 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
796 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
797 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
798 : 0 : pStruct->pOneINChI[1]->Stereo;
799 : : }
800 : : }
801 : :
802 : 0 : cur_success = 0;
803 [ # # ]: 0 : if (( cmpInChI & IDIF_SB_EXTRA_UNDF ))
804 : : {
805 : : /*------------------------------------------------------*/
806 : : /* case 04: extra stereogenic bond */
807 : : /* Since this bond parity is not known, it is UNDEFINED */
808 : : /*------------------------------------------------------*/
809 : : int bDone, num_endpoints;
810 : :
811 : 0 : TautMinusEdges[0].num_edges = 0;
812 : 0 : TautMinusEdges[1].num_edges = 0;
813 : 0 : AllChargeEdges.num_edges = 0;
814 : : /* in1 => in restored structure; in2 => in original InChI */
815 [ # # ]: 0 : for (i = 0; i < icr->num_sb_undef_in1_only; i++)
816 : : {
817 : 0 : j12 = icr->sb_undef_in1_only[i];
818 : 0 : pv1 = pBNS->vert + ( v1 = pStereoRevrs->nBondAtom1[j12] - 1 );
819 : 0 : pv2 = pBNS->vert + ( v2 = pStereoRevrs->nBondAtom2[j12] - 1 ); /* djb-rwth: ignoring LLVM warning: variable used */
820 : :
821 : : /* djb-rwth: fixing oss-fuzz issue #67650 */
822 : 0 : pe = pBNS->edge + (e = pv1->iedge[0]); /* djb-rwth: proper initialisation required to avoid garbage values */
823 : : /* find the edge between v1 and v2 */
824 [ # # ]: 0 : for (k = 0; k < at2[v1].valence; k++)
825 : : {
826 : 0 : pe = pBNS->edge + ( e = pv1->iedge[k] );
827 [ # # ]: 0 : if (v2 == ( pe->neighbor12 ^ v1 ))
828 : 0 : break; /* the edge has been found */
829 : : }
830 [ # # ]: 0 : if (k == at2[v1].valence)
831 : : {
832 : 0 : ret = RI_ERR_SYNTAX;
833 : 0 : goto exit_function;
834 : : }
835 [ # # ]: 0 : if (pStereo2Revrs)
836 : : {
837 : : /* reject if it is not extra in Mobile-H also */
838 [ # # ]: 0 : if (icr2->num_sb_undef_in1_only)
839 : : {
840 [ # # ]: 0 : for (j = 0; j < icr2->num_sb_undef_in1_only; j++)
841 : : {
842 : 0 : k = icr2->sb_undef_in1_only[j];
843 [ # # ]: 0 : if (v1 == pStereo2Revrs->nBondAtom1[k] &&
844 [ # # ]: 0 : v2 == pStereo2Revrs->nBondAtom2[k])
845 : : {
846 : 0 : break;
847 : : }
848 : : }
849 [ # # ]: 0 : if (j == icr->num_sb_in1_only)
850 : : {
851 : 0 : continue; /* extra stereobond only in Fixed-H, not in Mobile H also */
852 : : }
853 : : }
854 : : }
855 : :
856 : : /* Fix all charges except negative charges on tautomeric endpoints */
857 [ # # # # : 0 : if (!AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges)
# # ]
858 : : {
859 [ # # ]: 0 : for (j = 0; j < pStruct->num_atoms; j++)
860 : : {
861 [ # # # # ]: 0 : if (( k = pVA[j].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
862 : : {
863 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
864 : : {
865 : 0 : goto exit_function;
866 : : }
867 : : }
868 [ # # # # ]: 0 : if (( k = pVA[j].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
869 : : {
870 [ # # # # : 0 : int bMayBeUnfixed = !at2[j].num_H && !( pStruct->endpoint && pStruct->endpoint[j] );
# # ]
871 [ # # # # ]: 0 : if ((bMayBeUnfixed && pVA[j].cNumValenceElectrons == 6) ||
872 [ # # # # ]: 0 : (pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber > 1)) /* djb-rwth: addressing LLVM warning */
873 : : {
874 : : /* O & P */
875 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 0, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
876 : : {
877 : 0 : goto exit_function;
878 : : }
879 : : }
880 : : else
881 : : {
882 [ # # ]: 0 : if (bMayBeUnfixed &&
883 [ # # # # ]: 0 : pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1)
884 : : {
885 : : /* N */
886 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 1, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
887 : : {
888 : 0 : goto exit_function;
889 : : }
890 : : }
891 : : else
892 : : {
893 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
894 : : {
895 : 0 : goto exit_function;
896 : : }
897 : : }
898 : : }
899 : : /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
900 [ # # # # : 0 : if (pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
# # ]
901 : 0 : NO_VERTEX != ( k = GetChargeFlowerUpperEdge( pBNS, pVA, k ) ))
902 : : {
903 [ # # # # ]: 0 : if (!pBNS->edge[j].forbidden && pBNS->edge[k].flow)
904 : : {
905 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
906 : : {
907 : 0 : goto exit_function;
908 : : }
909 : : }
910 : : }
911 : : }
912 : : }
913 : : }
914 [ # # ]: 0 : if (!pe->flow)
915 : 0 : continue;
916 : : /* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
917 : 0 : SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
918 [ # # # # ]: 0 : for (k = 1, bDone = 0; k < 4 && !bDone; k++)
919 : : {
920 : : /* fix positive charges on heteroatoms */
921 : 0 : num_endpoints = ( TautMinusEdges + 0 )->num_edges + ( TautMinusEdges + 1 )->num_edges;
922 [ # # ]: 0 : if (k == 2)
923 : : {
924 : : /* fix charges on O */
925 : 0 : SetForbiddenEdgeMask( pBNS, TautMinusEdges + 0, forbidden_edge_mask );
926 : 0 : num_endpoints -= ( TautMinusEdges + 0 )->num_edges;
927 : : }
928 [ # # ]: 0 : if (k == 1)
929 : : {
930 : : /* fix charges on N */
931 : 0 : SetForbiddenEdgeMask( pBNS, TautMinusEdges + 1, forbidden_edge_mask );
932 : 0 : num_endpoints -= ( TautMinusEdges + 1 )->num_edges;
933 : : }
934 [ # # ]: 0 : if (num_endpoints >= 2)
935 : : {
936 : 0 : delta = 1;
937 : 0 : pv1 = pBNS->vert + ( v1 = pe->neighbor1 );
938 : 0 : pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 );
939 : :
940 : 0 : pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
941 : 0 : pe->flow -= delta; /* decrement stereobond order */
942 : 0 : pv1->st_edge.flow -= delta;
943 : 0 : pv2->st_edge.flow -= delta;
944 : 0 : pBNS->tot_st_flow -= 2 * delta;
945 : :
946 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
947 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
948 : :
949 [ # # # # : 0 : if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) ||
# # ]
950 [ # # # # : 0 : (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 0) /* djb-rwth: addressing LLVM warnings */
# # ]
951 : : {
952 : : /* Negative charge has been moved, no change in number of charges */
953 : 0 : ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
954 [ # # ]: 0 : if (ret > 0)
955 : : {
956 : 0 : ( *pnNumRunBNS )++;
957 : 0 : cur_success++; /* 01 */
958 : 0 : bDone = 1;
959 : : }
960 : : }
961 : : else
962 : : {
963 : 0 : pe->forbidden &= ~forbidden_edge_mask;
964 : 0 : pe->flow += delta;
965 : 0 : pv1->st_edge.flow += delta;
966 : 0 : pv2->st_edge.flow += delta;
967 : 0 : pBNS->tot_st_flow += 2 * delta;
968 : : }
969 : : }
970 : : /* unfix tautomeric charges */
971 [ # # ]: 0 : if (k == 2)
972 : 0 : RemoveForbiddenEdgeMask( pBNS, TautMinusEdges + 0, forbidden_edge_mask );
973 [ # # ]: 0 : if (k == 1)
974 : 0 : RemoveForbiddenEdgeMask( pBNS, TautMinusEdges + 1, forbidden_edge_mask );
975 : : }
976 : 0 : RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
977 : : }
978 : : /*exit_case_04:*/
979 [ # # ]: 0 : if (cur_success)
980 : : {
981 : : /* djb-rwth: removing redundant code */
982 : : /* recalculate InChI from the structure */
983 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
984 : : ppt_group_info, ppat_norm, ppat_prep ) ))
985 : : {
986 : 0 : goto exit_function;
987 : : }
988 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
989 : : {
990 : 0 : goto exit_function;
991 : : }
992 : : /*
993 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
994 : : goto exit_function;
995 : : }
996 : : */
997 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
998 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
999 : : {
1000 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1001 : 0 : goto exit_function;
1002 : : }
1003 [ # # ]: 0 : if (err)
1004 : : {
1005 : 0 : ret = RI_ERR_ALLOC;
1006 : 0 : goto exit_function;
1007 : : }
1008 : 0 : cmpInChI2 = 0;
1009 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1010 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
1011 : : {
1012 : : /* additional mobile-H compare in case of Fixed-H */
1013 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1014 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1015 : : {
1016 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1017 : 0 : goto exit_function;
1018 : : }
1019 [ # # ]: 0 : if (err)
1020 : : {
1021 : 0 : ret = RI_ERR_ALLOC;
1022 : 0 : goto exit_function;
1023 : : }
1024 : : }
1025 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
1026 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1027 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
1028 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
1029 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo;
1030 : :
1031 : :
1032 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1033 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
1034 : : ? NULL
1035 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
1036 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1037 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
1038 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
1039 : 0 : pStruct->pOneINChI[1]->Stereo;
1040 : : }
1041 : : }
1042 : :
1043 : 0 : cur_success = 0;
1044 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_YES &&
1045 [ # # ]: 0 : ( cmpInChI & IDIF_SB_EXTRA_UNDF &&
1046 [ # # ]: 0 : !pStruct->ti.num_t_groups )
1047 : : /*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/)
1048 : : {
1049 : : /*----------------------------------------------------------*/
1050 : : /* case 05: extra stereogenic bond on =NH2(+), (B, Mobile-H)*/
1051 : : /* H H */
1052 : : /* original: N(+)=-N< -> N--==N/ */
1053 : : /* (A) H */
1054 : : /* double bond is marked as */
1055 : : /* not stereogenic due to */
1056 : : /* its change during proton */
1057 : : /* removal => No Stereo bond */
1058 : : /* (=NH may be tautomeric) */
1059 : : /* */
1060 : : /* H H */
1061 : : /* original: N=-N(+)< -> N--==N/ */
1062 : : /* (B) H */
1063 : : /* double bond was not */
1064 : : /* changed during proton */
1065 : : /* In Fixed-H this bond removal => Undef Stereo */
1066 : : /* may not be stereogenic (=NH is not tautomeric) */
1067 : : /* (a) due to (+) movement */
1068 : : /* (b) due to symmetry (2H), even if isotopic */
1069 : : /* */
1070 : : /* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
1071 : : /* respectively */
1072 : : /* Mobile-H: Add H(+) to =NH and move the charge to =N- */
1073 : : /* to eliminate Undef stereo */
1074 : : /* Move charge from N to -NH2 to create */
1075 : : /* Undef Stereo */
1076 : : /* Since this bond parity is not known, it is UNDEFINED */
1077 : : /* */
1078 : : /* Solution: Add H(+) to =NH and move charge to -N= */
1079 : : /* */
1080 : : /*----------------------------------------------------------*/
1081 : : int aN, aC, i1, i2, vPlusMinus;
1082 : 0 : AllChargeEdges.num_edges = 0;
1083 : : /* in1 => in restored structure; in2 => in original InChI */
1084 [ # # ]: 0 : for (i = 0; i < icr->num_sb_undef_in1_only; i++)
1085 : : {
1086 : 0 : j12 = icr->sb_undef_in1_only[i];
1087 : 0 : pv1 = pBNS->vert + ( v1 = pStereoRevrs->nBondAtom1[j12] - 1 );
1088 : 0 : pv2 = pBNS->vert + ( v2 = pStereoRevrs->nBondAtom2[j12] - 1 ); /* djb-rwth: ignoring LLVM warning: variable used */
1089 : : /* indicators of -NH: */
1090 [ # # # # ]: 0 : i1 = at2[v1].valence == 1 && at2[v1].num_H == 1 && !at2[v1].endpoint &&
1091 [ # # # # : 0 : pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
# # ]
1092 [ # # # # ]: 0 : i2 = at2[v2].valence == 1 && at2[v2].num_H == 1 && !at2[v2].endpoint &&
1093 [ # # # # : 0 : pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
# # ]
1094 [ # # # # : 0 : if ((!i1 && !i2) || (i1 && i2)) /* djb-rwth: addressing LLVM warnings */
# # # # ]
1095 : : {
1096 : 0 : continue;
1097 : : }
1098 : : /* find the edge between v1 and v2 */
1099 [ # # ]: 0 : for (k = 0; k < at2[v1].valence; k++)
1100 : : {
1101 : 0 : pe = pBNS->edge + ( e = pv1->iedge[k] );
1102 [ # # ]: 0 : if (v2 == ( pe->neighbor12 ^ v1 ))
1103 : : {
1104 : 0 : break; /* the edge has been found */
1105 : : }
1106 : : }
1107 [ # # ]: 0 : if (k == at2[v1].valence)
1108 : : {
1109 : 0 : ret = RI_ERR_SYNTAX;
1110 : 0 : goto exit_function;
1111 : : }
1112 [ # # ]: 0 : if (pe->flow != 1)
1113 : : {
1114 : 0 : continue; /* already charged */
1115 : : }
1116 [ # # ]: 0 : aN = i1 ? v1 : v2; /* -NH atom */
1117 [ # # ]: 0 : aC = i1 ? v2 : v1; /* neighbor */
1118 : : /* Replace =NH with -NH2
1119 : : Create such a charge on some -N< that may be moved to NH2 to remove H(+):
1120 : : transformation:
1121 : : from: HN=C-=-N=(+vert)-Y=(+super)-(+/-)
1122 : : to: 2HN-C*-=-N=(+vert)-Y=(+super)-(+/-)*
1123 : : Run BNS to obtain:
1124 : : 2HN-C=-=N(+)-(+vert)=Y-(+super)=(+/-)
1125 : : */
1126 : 0 : vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 0 );
1127 [ # # ]: 0 : if (NO_VERTEX == vPlusMinus)
1128 : : {
1129 : 0 : break; /* cannot do anything */
1130 : : }
1131 : : /* increase edges to -Y-(+/-)-Y- capacities */
1132 : 0 : delta = 1;
1133 [ # # ]: 0 : for (i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1++)
1134 : : {
1135 : 0 : i2 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
1136 [ # # ]: 0 : for (k = 0; k < pBNS->vert[i2].num_adj_edges; k++)
1137 : : {
1138 : 0 : pBNS->edge[pBNS->vert[i2].iedge[k]].cap += delta;
1139 : : }
1140 : : }
1141 : : /* Fix all charges except (+) on -N< */
1142 [ # # ]: 0 : if (!AllChargeEdges.num_edges)
1143 : : {
1144 [ # # ]: 0 : for (j = 0; j < pStruct->num_atoms; j++)
1145 : : {
1146 [ # # # # ]: 0 : if (( k = pVA[j].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
1147 : : {
1148 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1149 : : {
1150 : 0 : goto exit_function;
1151 : : }
1152 : : }
1153 [ # # # # ]: 0 : if (( k = pVA[j].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
1154 : : {
1155 [ # # # # ]: 0 : if (pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
1156 [ # # # # ]: 0 : !at2[j].num_H && at2[j].valence == 3 &&
1157 [ # # # # : 0 : !( at2[j].endpoint || (pStruct->endpoint && pStruct->endpoint[j]) )) /* djb-rwth: addressing LLVM warning */
# # ]
1158 : : {
1159 : : ; /* do not fix -N< or =N(+)< */
1160 : : }
1161 : : else
1162 : : {
1163 : : /* all others */
1164 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 0, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1165 : : {
1166 : 0 : goto exit_function;
1167 : : }
1168 : : }
1169 : : /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
1170 [ # # # # : 0 : if (pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
# # ]
1171 : 0 : NO_VERTEX != ( k = GetChargeFlowerUpperEdge( pBNS, pVA, k ) ))
1172 : : {
1173 [ # # # # ]: 0 : if (!pBNS->edge[j].forbidden && pBNS->edge[k].flow)
1174 : : {
1175 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1176 : : {
1177 : 0 : goto exit_function;
1178 : : }
1179 : : }
1180 : : }
1181 : : }
1182 : : }
1183 : : }
1184 : : /* Make bond to =NH single, add radical to aC */
1185 : 0 : pe->flow -= delta; /* make single bond */
1186 : 0 : pBNS->vert[aN].st_edge.flow -= delta;
1187 : 0 : pBNS->vert[aN].st_edge.cap -= delta; /* avoid radical on N */
1188 : 0 : pBNS->vert[aC].st_edge.flow -= delta; /* create radical on C */
1189 : 0 : pBNS->vert[vPlusMinus].st_edge.cap += delta; /* create radical on (+/-) */
1190 : 0 : pBNS->tot_st_flow -= 2 * delta;
1191 : : /* fix C-NH bond */
1192 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1193 : : {
1194 : 0 : goto exit_function;
1195 : : }
1196 : : /* pBNS->tot_st_cap is unchanged */
1197 : : /* find all aC edges except pe to fix them */
1198 : : /* 2. Check whether it would work and do if it would */
1199 : 0 : SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1200 : 0 : pe->cap++;
1201 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1202 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1203 : :
1204 [ # # # # : 0 : if (ret == 1 && ( (vPathEnd == vPlusMinus && vPathStart == aC) ||
# # ]
1205 [ # # # # : 0 : (vPathEnd == aC && vPathStart == vPlusMinus) ) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */
# # ]
1206 : : {
1207 : : /* Negative charge has been moved, no change in number of charges */
1208 : 0 : ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1209 [ # # ]: 0 : if (ret > 0)
1210 : : {
1211 : 0 : ( *pnNumRunBNS )++;
1212 : : /* 3. Add H to -NH and register increaded charge */
1213 : 0 : pStruct->at[aN].num_H++;
1214 : 0 : pTCGroups->total_charge++;
1215 : 0 : cur_success++; /* 01 */
1216 : : }
1217 : : }
1218 : : else
1219 : : {
1220 : 0 : pe->flow += delta; /* make single bond */
1221 : 0 : pBNS->vert[aN].st_edge.flow += delta;
1222 : 0 : pBNS->vert[aN].st_edge.cap += delta; /* avoid radical on N */
1223 : 0 : pBNS->vert[aC].st_edge.flow += delta; /* create radical on C */
1224 : 0 : pBNS->vert[vPlusMinus].st_edge.cap -= delta; /* create radical on (+/-) */
1225 : 0 : pBNS->tot_st_flow += 2 * delta;
1226 : 0 : RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1227 : 0 : AllChargeEdges.num_edges--; /* remove pe from the list */
1228 : 0 : CurrEdges.num_edges = 0;
1229 : 0 : continue; /* should not happen */
1230 : : }
1231 : 0 : RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1232 : 0 : AllChargeEdges.num_edges--; /* remove pe from the list */
1233 : 0 : CurrEdges.num_edges = 0;
1234 : : }
1235 : : /*exit_case_05:*/
1236 [ # # ]: 0 : if (cur_success)
1237 : : {
1238 : : /* djb-rwth: removing redundant code */
1239 : : /* recalculate InChI from the structure */
1240 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1241 : : ppt_group_info, ppat_norm, ppat_prep ) ))
1242 : : {
1243 : 0 : goto exit_function;
1244 : : }
1245 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
1246 : : {
1247 : 0 : goto exit_function;
1248 : : }
1249 : : /*
1250 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1251 : : goto exit_function;
1252 : : }
1253 : : */
1254 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
1255 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1256 : : {
1257 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1258 : 0 : goto exit_function;
1259 : : }
1260 [ # # ]: 0 : if (err)
1261 : : {
1262 : 0 : ret = RI_ERR_ALLOC;
1263 : 0 : goto exit_function;
1264 : : }
1265 : 0 : cmpInChI2 = 0;
1266 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1267 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
1268 : : {
1269 : : /* additional mobile-H compare in case of Fixed-H */
1270 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1271 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1272 : : {
1273 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1274 : 0 : goto exit_function;
1275 : : }
1276 [ # # ]: 0 : if (err)
1277 : : {
1278 : 0 : ret = RI_ERR_ALLOC;
1279 : 0 : goto exit_function;
1280 : : }
1281 : : }
1282 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
1283 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1284 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
1285 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
1286 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo; /* djb-rwth: ignoring LLVM warning: variable used */
1287 : :
1288 : :
1289 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1290 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
1291 : : ? NULL
1292 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
1293 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1294 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
1295 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
1296 : 0 : pStruct->pOneINChI[1]->Stereo;
1297 : : }
1298 : : }
1299 : :
1300 : 0 : cur_success = 0;
1301 [ # # # # ]: 0 : if (pStruct->bMobileH == TAUT_NON && pStereo2Revrs /* added check 2006-04-05 */ &&
1302 [ # # ]: 0 : ( cmpInChI2 & IDIF_SB_EXTRA_UNDF &&
1303 [ # # ]: 0 : !pStruct->ti.num_t_groups )
1304 : : /*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/)
1305 : : {
1306 : : /*----------------------------------------------------------*/
1307 : : /* case 06: extra stereogenic bond on =NH2(+), (B, Fixed-H) */
1308 : : /* H H =========== */
1309 : : /* original: N(+)=-N< -> N--==N(+)< */
1310 : : /* (A) H H */
1311 : : /* double bond in Mobile-H */
1312 : : /* layer has Undef stereo */
1313 : : /* */
1314 : : /* */
1315 : : /* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
1316 : : /* respectively */
1317 : : /* Mobile-H: Add H(+) to =NH and move the charge to =N- */
1318 : : /* to eliminate Undef stereo */
1319 : : /* Move charge from N to -NH2 to create */
1320 : : /* Undef Stereo */
1321 : : /* Since this bond parity is not known, it is UNDEFINED */
1322 : : /* */
1323 : : /* Solution: Move (+) from -NH2(+) to othe -N< */
1324 : : /* */
1325 : : /*----------------------------------------------------------*/
1326 : : int aN, i1, i2, ePlus; /* djb-rwth: removing redundant variables */
1327 : : BNS_EDGE *pePlus;
1328 : 0 : AllChargeEdges.num_edges = 0;
1329 : : /* in1 => in restored structure; in2 => in original InChI */
1330 [ # # ]: 0 : for (i = 0; i < icr2->num_sb_undef_in1_only; i++)
1331 : : {
1332 : 0 : j12 = icr2->sb_undef_in1_only[i];
1333 : 0 : pv1 = pBNS->vert + ( v1 = pStereo2Revrs->nBondAtom1[j12] - 1 );
1334 : 0 : pv2 = pBNS->vert + ( v2 = pStereo2Revrs->nBondAtom2[j12] - 1 ); /* djb-rwth: ignoring LLVM warning: variable used */
1335 : : /* indicators of -NH: */
1336 [ # # # # ]: 0 : i1 = at2[v1].valence == 1 && at2[v1].num_H == 2 && !at2[v1].endpoint &&
1337 [ # # # # : 0 : pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
# # ]
1338 [ # # # # ]: 0 : i2 = at2[v2].valence == 1 && at2[v2].num_H == 2 && !at2[v2].endpoint &&
1339 [ # # # # : 0 : pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
# # ]
1340 [ # # # # : 0 : if ((!i1 && !i2) || (i1 && i2)) /* djb-rwth: addressing LLVM warnings */
# # # # ]
1341 : : {
1342 : 0 : continue;
1343 : : }
1344 : : /* find the edge between v1 and v2 */
1345 [ # # ]: 0 : for (k = 0; k < at2[v1].valence; k++)
1346 : : {
1347 : 0 : pe = pBNS->edge + ( e = pv1->iedge[k] ); /* djb-rwth: ignoring LLVM warning: variable used */
1348 [ # # ]: 0 : if (v2 == ( pe->neighbor12 ^ v1 ))
1349 : 0 : break; /* the edge has been found */
1350 : : }
1351 [ # # ]: 0 : if (k >= at2[v1].valence) /* djb-rwth: addressing LLVM warning */
1352 : : {
1353 : 0 : ret = RI_ERR_SYNTAX;
1354 : 0 : goto exit_function;
1355 : : }
1356 [ # # ]: 0 : if (pe->flow != 1)
1357 : : {
1358 : 0 : continue; /* already charged */
1359 : : }
1360 [ # # ]: 0 : aN = i1 ? v1 : v2; /* -NH atom */
1361 : : /* djb-rwth: removing redundant code */
1362 [ # # ]: 0 : if (0 > ( ePlus = pVA[aN].nCPlusGroupEdge - 1 ) ||
1363 [ # # ]: 0 : ( pePlus = pBNS->edge + ePlus )->flow || /* must be (+) charged */
1364 [ # # ]: 0 : pePlus->forbidden)
1365 : : {
1366 : 0 : continue;
1367 : : }
1368 : : /* Move (+) from =NH2(+) to some other -N<
1369 : : */
1370 : : /* Fix all charges except (+) on -N< */
1371 [ # # ]: 0 : if (!AllChargeEdges.num_edges)
1372 : : {
1373 [ # # ]: 0 : for (j = 0; j < pStruct->num_atoms; j++)
1374 : : {
1375 [ # # # # ]: 0 : if (( k = pVA[j].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
1376 : : {
1377 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1378 : : {
1379 : 0 : goto exit_function;
1380 : : }
1381 : : }
1382 [ # # # # ]: 0 : if (( k = pVA[j].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[k].forbidden)
1383 : : {
1384 [ # # # # ]: 0 : if (pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
1385 [ # # # # ]: 0 : !at2[j].num_H && at2[j].valence == 3 &&
1386 [ # # # # : 0 : !( at2[j].endpoint || (pStruct->endpoint && pStruct->endpoint[j]) )) /* djb-rwth: addressing LLVM warning */
# # ]
1387 : : {
1388 : : ; /* do not fix -N< or =N(+)< */
1389 : : }
1390 : : else
1391 : : {
1392 : : /* all others */
1393 [ # # ]: 0 : if ((ret = AddToEdgeList( TautMinusEdges + 0, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1394 : : {
1395 : 0 : goto exit_function;
1396 : : }
1397 : : }
1398 : : /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
1399 [ # # # # : 0 : if (pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
# # ]
1400 : 0 : NO_VERTEX != ( k = GetChargeFlowerUpperEdge( pBNS, pVA, k ) ))
1401 : : {
1402 [ # # # # ]: 0 : if (!pBNS->edge[j].forbidden && pBNS->edge[k].flow)
1403 : : {
1404 [ # # ]: 0 : if ((ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */
1405 : : {
1406 : 0 : goto exit_function;
1407 : : }
1408 : : }
1409 : : }
1410 : : }
1411 : : }
1412 : : }
1413 : : /* pePlus edge is already fixed; unfix it */
1414 : : /* To decrement (+) on =NH2(+) decrement its double bond order */
1415 : : /* djb-rwth: removing redundant code */
1416 [ # # ]: 0 : if (!pe->flow)
1417 : 0 : continue;
1418 : 0 : pv1 = pBNS->vert + ( v1 = pe->neighbor1 );
1419 : 0 : pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 );
1420 : :
1421 : 0 : delta = 1;
1422 : 0 : pe->flow -= delta;
1423 : 0 : pv1->st_edge.flow -= delta;
1424 : 0 : pv2->st_edge.flow -= delta;
1425 : 0 : pBNS->tot_st_flow -= 2 * delta;
1426 : :
1427 : 0 : pe->forbidden |= forbidden_edge_mask;
1428 : 0 : pePlus->forbidden &= ~forbidden_edge_mask;
1429 : :
1430 : 0 : ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1431 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1432 : :
1433 [ # # # # : 0 : if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) ||
# # ]
1434 [ # # # # : 0 : (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 0) /* djb-rwth: addressing LLVM warnings */
# # ]
1435 : : {
1436 : : /* (+)charge was just moved, no change in number of charges */
1437 : 0 : ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1438 [ # # ]: 0 : if (ret > 0)
1439 : : {
1440 : 0 : ( *pnNumRunBNS )++;
1441 : 0 : cur_success++; /* 01 */
1442 : : }
1443 : : }
1444 : : else
1445 : : {
1446 : 0 : pe->flow += delta; /* roll back */
1447 : 0 : pv1->st_edge.flow += delta;
1448 : 0 : pv2->st_edge.flow += delta;
1449 : 0 : pBNS->tot_st_flow += 2 * delta;
1450 : : }
1451 : 0 : pe->forbidden &= ~forbidden_edge_mask;
1452 : 0 : RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1453 : : }
1454 : : /*exit_case_06:*/
1455 [ # # ]: 0 : if (cur_success)
1456 : : {
1457 : : /* djb-rwth: removing redundant code */
1458 : : /* recalculate InChI from the structure */
1459 [ # # ]: 0 : if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1460 : : ppt_group_info, ppat_norm, ppat_prep ) ))
1461 : : {
1462 : 0 : goto exit_function;
1463 : : }
1464 [ # # ]: 0 : if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */
1465 : : {
1466 : 0 : goto exit_function;
1467 : : }
1468 : : /*
1469 : : if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1470 : : goto exit_function;
1471 : : }
1472 : : */
1473 : 0 : cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr2, &err );
1474 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1475 : : {
1476 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1477 : 0 : goto exit_function;
1478 : : }
1479 [ # # ]: 0 : if (err)
1480 : : {
1481 : 0 : ret = RI_ERR_ALLOC;
1482 : 0 : goto exit_function;
1483 : : }
1484 : : /* djb-rwth: removing redundant code */
1485 : 0 : memset( icr2, 0, sizeof( *icr2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1486 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
1487 : : {
1488 : : /* additional mobile-H compare in case of Fixed-H */
1489 : 0 : cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1490 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1491 : : {
1492 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1493 : 0 : goto exit_function;
1494 : : }
1495 [ # # ]: 0 : if (err)
1496 : : {
1497 : 0 : ret = RI_ERR_ALLOC;
1498 : 0 : goto exit_function;
1499 : : }
1500 : : }
1501 : 0 : pStereoRevrs = ( pStruct->pOneINChI[0]->StereoIsotopic &&
1502 : 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1503 [ # # ]: 0 : pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters )
1504 : 0 : ? pStruct->pOneINChI[0]->StereoIsotopic
1505 [ # # ]: 0 : : pStruct->pOneINChI[0]->Stereo; /* djb-rwth: ignoring LLVM warning: variable used */
1506 : :
1507 : :
1508 [ # # ]: 0 : pStereo2Revrs = ( pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1509 [ # # # # ]: 0 : !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted )
1510 : : ? NULL
1511 [ # # ]: 0 : : ( pStruct->pOneINChI[1]->StereoIsotopic &&
1512 : 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1513 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters ) ?
1514 [ # # ]: 0 : pStruct->pOneINChI[1]->StereoIsotopic :
1515 : 0 : pStruct->pOneINChI[1]->Stereo; /* djb-rwth: ignoring LLVM warning: variable used */
1516 : : }
1517 : : }
1518 : :
1519 : :
1520 : 0 : exit_function:
1521 : 0 : SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
1522 : 0 : AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
1523 : 0 : AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
1524 : 0 : AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
1525 : 0 : AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
1526 : 0 : AllocEdgeList( &FixedStereoEdges, EDGE_LIST_FREE );
1527 : 0 : AllocEdgeList( &AllRadList, EDGE_LIST_FREE ); /* eliminate memory leak */
1528 : 0 : AllocEdgeList( TautMinusEdges + 0, EDGE_LIST_FREE );
1529 : 0 : AllocEdgeList( TautMinusEdges + 1, EDGE_LIST_FREE );
1530 : :
1531 : 0 : return ret;
1532 : : }
1533 : : #endif
|