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