Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <ctype.h>
9 : : #include <limits.h>
10 : :
11 : : #include "mode.h"
12 : : #include "ichimain.h"
13 : : #include "ichimake.h"
14 : : #include "ichi_io.h"
15 : :
16 : : #include "bcf_s.h"
17 : :
18 : : /****************************************************************************/
19 : 62 : int Eql_INChI_Stereo( INChI_Stereo *s1,
20 : : int eql1,
21 : : INChI_Stereo *s2,
22 : : int eql2,
23 : : int bRelRac )
24 : : {
25 : 62 : int inv1 = 0, inv2 = 0, len;
26 : :
27 [ - + ]: 62 : if (!s1)
28 : : {
29 : 0 : return 0;
30 : : }
31 : : #if ( REL_RAC_STEREO_IGN_1_SC == 1 )
32 : : #else
33 : 62 : bRelRac = 0;
34 : : #endif
35 : :
36 [ - + ]: 62 : if (EQL_SP2 == eql1)
37 : : {
38 [ # # # # : 0 : if (( len = s1->nNumberOfStereoBonds ) > 0 && s1->b_parity && s1->nBondAtom1 && s1->nBondAtom2)
# # # # ]
39 : : {
40 [ # # ]: 0 : if (!s2)
41 : : {
42 [ # # ]: 0 : if (EQL_EXISTS == eql2)
43 : : {
44 : : /* find whether double bond stereo exists*/
45 : 0 : return 1;
46 : : }
47 : 0 : return 0;
48 : : }
49 [ # # ]: 0 : if (EQL_SP2 == eql2 &&
50 [ # # # # : 0 : len == s2->nNumberOfStereoBonds && s2->b_parity && s2->nBondAtom1 && s2->nBondAtom2 &&
# # # # ]
51 [ # # ]: 0 : !memcmp( s1->nBondAtom1, s2->nBondAtom1, len * sizeof( s1->nBondAtom1[0] ) ) &&
52 [ # # ]: 0 : !memcmp( s1->nBondAtom2, s2->nBondAtom2, len * sizeof( s1->nBondAtom2[0] ) ) &&
53 [ # # ]: 0 : !memcmp( s1->b_parity, s2->b_parity, len * sizeof( s1->b_parity[0] ) ))
54 : : {
55 : 0 : return 1;
56 : : }
57 : : }
58 : 0 : return 0;
59 : : }
60 : :
61 : : else
62 : : {
63 [ + + + - ]: 62 : if (( eql1 == EQL_SP3 || ( inv1 = ( eql1 == EQL_SP3_INV ) ) ) &&
64 [ + + ]: 62 : ( len = s1->nNumberOfStereoCenters ) > ( bRelRac ? 1 : 0 )) /* djb-rwth: addressing coverity ID #499484 -- bRelRac does not have to be 0 */
65 : : {
66 : :
67 : : S_CHAR *t_parity1, *t_parity2;
68 : : AT_NUMB *nNumber1, *nNumber2;
69 [ + + ]: 60 : if (inv1)
70 : : {
71 [ + - ]: 51 : if (s1->nCompInv2Abs)
72 : : {
73 : 51 : t_parity1 = s1->t_parityInv;
74 : 51 : nNumber1 = s1->nNumberInv;
75 : : }
76 : : else
77 : : {
78 : 0 : return 0;
79 : : }
80 : : }
81 : : else
82 : : {
83 : 9 : t_parity1 = s1->t_parity;
84 : 9 : nNumber1 = s1->nNumber;
85 : : }
86 [ + - + - ]: 60 : if (t_parity1 && nNumber1)
87 : : {
88 [ - + ]: 60 : if (!s2)
89 : : {
90 [ # # # # : 0 : if (EQL_EXISTS == eql2 && ( !inv1 || s1->nCompInv2Abs ))
# # ]
91 : : {
92 : : /* the 1st sp3 (inverted if requested) stereo exists*/
93 : 0 : return 1;
94 : : }
95 : 0 : return 0; /* both sp3 do not exist */
96 : : }
97 [ - + - - ]: 60 : if (( eql2 == EQL_SP3 || ( inv2 = ( eql2 == EQL_SP3_INV ) ) ) &&
98 [ + + ]: 60 : len == s2->nNumberOfStereoCenters)
99 : : {
100 [ - + ]: 57 : if (inv2)
101 : : {
102 [ # # # # ]: 0 : if (s2->nCompInv2Abs && s1->nCompInv2Abs)
103 : : {
104 : 0 : t_parity2 = s2->t_parityInv;
105 : 0 : nNumber2 = s2->nNumberInv;
106 : : }
107 : : else
108 : : {
109 : : /* if one sp3 is inverted then another should have non-trivial inverted stereo */
110 : 0 : return 0;
111 : : }
112 : : }
113 : : else
114 : : {
115 [ + + - + ]: 57 : if (inv1 && !s2->nCompInv2Abs)
116 : : {
117 : : /* if one sp3 is inverted then another should have non-trivial inverted stereo */
118 : 0 : return 0;
119 : : }
120 : 57 : t_parity2 = s2->t_parity;
121 : 57 : nNumber2 = s2->nNumber;
122 : : }
123 [ + - + - ]: 57 : if (t_parity2 && nNumber2)
124 : : {
125 [ + + ]: 57 : if (inv1 ^ inv2)
126 : : {
127 : : int i, num_inv;
128 [ + + ]: 187 : for (i = 0, num_inv = 0; i < len; i++)
129 : : {
130 [ - + ]: 149 : if (nNumber1[i] != nNumber2[i])
131 : 0 : break;
132 [ + - + + ]: 149 : if (ATOM_PARITY_WELL_DEF( t_parity1[i] ) &&
133 [ + - + - ]: 136 : ATOM_PARITY_WELL_DEF( t_parity2[i] ))
134 : : {
135 [ + + ]: 136 : if (3 == t_parity1[i] + t_parity2[i])
136 : : {
137 : 123 : num_inv++;
138 : : }
139 : : else
140 : : {
141 : 13 : break;
142 : : }
143 : : }
144 : : else
145 [ - + ]: 13 : if (t_parity1[i] != t_parity2[i])
146 : : {
147 : 0 : break;
148 : : }
149 : : }
150 [ + + + - ]: 51 : return ( len == i && num_inv > 0 );
151 : : }
152 : : else
153 : : {
154 [ + - ]: 12 : return !memcmp( t_parity1, t_parity2, len * sizeof( t_parity1[0] ) ) &&
155 [ + + ]: 6 : !memcmp( nNumber1, nNumber2, len * sizeof( nNumber1[0] ) );
156 : : }
157 : : }
158 : : }
159 : : }
160 : : }
161 : : }
162 : :
163 : 5 : return 0;
164 : : }
165 : :
166 : :
167 : : /****************************************************************************/
168 : 0 : int Eql_INChI_Isotopic( INChI *i1, INChI *i2 )
169 : : {
170 : 0 : int eq = i1
171 [ # # ]: 0 : && i2
172 [ # # ]: 0 : && !i1->bDeleted
173 [ # # ]: 0 : && !i2->bDeleted
174 [ # # # # ]: 0 : && ( i1->nNumberOfIsotopicAtoms > 0 || i1->nNumberOfIsotopicTGroups > 0 )
175 [ # # ]: 0 : && i1->nNumberOfIsotopicAtoms == i2->nNumberOfIsotopicAtoms
176 [ # # ]: 0 : && i1->nNumberOfIsotopicTGroups == i2->nNumberOfIsotopicTGroups
177 [ # # ]: 0 : && ( !i1->nNumberOfIsotopicAtoms ||
178 [ # # # # ]: 0 : (i1->IsotopicAtom && i2->IsotopicAtom &&
179 : 0 : !memcmp( i1->IsotopicAtom, i2->IsotopicAtom,
180 [ # # ]: 0 : i1->nNumberOfIsotopicAtoms * sizeof( i1->IsotopicAtom[0] ) )) )
181 [ # # # # ]: 0 : && ( !i1->nNumberOfIsotopicTGroups ||
182 [ # # # # ]: 0 : (i1->IsotopicTGroup && i2->IsotopicTGroup &&
183 : 0 : !memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup,
184 [ # # ]: 0 : i1->nNumberOfIsotopicTGroups * sizeof( i1->IsotopicAtom[0] )) )
185 : : ); /* djb-rwth: addressing LLVM warnings */
186 : :
187 : 0 : return eq;
188 : : }
189 : :
190 : :
191 : : /****************************************************************************/
192 : 46 : int Eql_INChI_Aux_Equ( INChI_Aux *a1, int eql1, INChI_Aux *a2, int eql2 )
193 : : {
194 : 46 : int t1 = 0, t2 = 0, len = 0;
195 : 46 : AT_NUMB *n1 = NULL, *n2 = NULL;
196 [ + + - + ]: 46 : if (!a1 || !a2)
197 : : {
198 : 23 : return 0;
199 : : }
200 : 23 : t1 = ( eql1 & EQL_EQU_TG );
201 : 23 : t2 = ( eql2 & EQL_EQU_TG );
202 [ + + + - ]: 23 : if (t1 && t2)
203 : : {
204 [ + + + - : 5 : if (( len = a1->nNumberOfTGroups ) > 0 && len == a2->nNumberOfTGroups && !a1->bDeleted && !a2->bDeleted)
+ - + - ]
205 : : {
206 [ - + ]: 1 : if (eql1 & EQL_EQU_ISO)
207 : : {
208 [ # # ]: 0 : if (a1->bIsIsotopic)
209 : : {
210 : 0 : n1 = a1->nConstitEquIsotopicTGroupNumbers;
211 : : }
212 : : }
213 : : else
214 : : {
215 : 1 : n1 = a1->nConstitEquTGroupNumbers;
216 : : }
217 [ - + ]: 1 : if (eql2 & EQL_EQU_ISO)
218 : : {
219 [ # # ]: 0 : if (a2->bIsIsotopic)
220 : : {
221 : 0 : n2 = a2->nConstitEquIsotopicTGroupNumbers;
222 : : }
223 : : }
224 : : else
225 : : {
226 : 1 : n2 = a2->nConstitEquTGroupNumbers;
227 : : }
228 : : }
229 : : }
230 : : else
231 [ + - + - ]: 18 : if (!t1 && !t2)
232 : : {
233 [ + - + + : 18 : if (( len = a1->nNumberOfAtoms ) > 0 && len == a2->nNumberOfAtoms && !a1->bDeleted && !a2->bDeleted)
+ - + - ]
234 : : {
235 [ - + ]: 7 : if (eql1 & EQL_EQU_ISO)
236 : : {
237 [ # # ]: 0 : if (a1->bIsIsotopic)
238 : : {
239 : 0 : n1 = a1->nConstitEquIsotopicNumbers;
240 : : }
241 : : }
242 : : else
243 : : {
244 : 7 : n1 = a1->nConstitEquNumbers;
245 : : }
246 [ - + ]: 7 : if (eql2 & EQL_EQU_ISO)
247 : : {
248 [ # # ]: 0 : if (a2->bIsIsotopic)
249 : : {
250 : 0 : n2 = a2->nConstitEquIsotopicNumbers;
251 : : }
252 : : }
253 : : else
254 : : {
255 : 7 : n2 = a2->nConstitEquNumbers;
256 : : }
257 : : }
258 : : }
259 [ + + + - : 23 : if (n1 && n2 && !memcmp( n1, n2, len * sizeof( n1[0] ) ) && bHasEquString( n1, len ))
+ - + + ]
260 : : {
261 : 3 : return 1;
262 : : }
263 : :
264 : 20 : return 0;
265 : : }
266 : :
267 : :
268 : :
269 : : /****************************************************************************/
270 : 0 : int Eql_INChI_Aux_Num( INChI_Aux *a1, int eql1, INChI_Aux *a2, int eql2 )
271 : : {
272 : : int len;
273 : 0 : AT_NUMB *n1 = NULL, *n2 = NULL;
274 [ # # # # ]: 0 : if (!a1 || !a2)
275 : : {
276 : 0 : return 0;
277 : : }
278 [ # # # # : 0 : if (( len = a1->nNumberOfAtoms ) <= 0 || len != a2->nNumberOfAtoms || a1->bDeleted || a2->bDeleted)
# # # # ]
279 : : {
280 : 0 : return 0;
281 : : }
282 [ # # # # ]: 0 : if ((( eql1 & EQL_NUM_ISO ) && !a1->bIsIsotopic) ||
283 [ # # # # ]: 0 : (( eql2 & EQL_NUM_ISO ) && !a2->bIsIsotopic)) /* djb-rwth: addressing LLVM warnings */
284 : : {
285 : 0 : return 0;
286 : : }
287 : :
288 [ # # # # : 0 : switch (eql1)
# ]
289 : : {
290 : 0 : case EQL_NUM:
291 : 0 : n1 = a1->nOrigAtNosInCanonOrd;
292 : 0 : break;
293 : 0 : case EQL_NUM_ISO:
294 : 0 : n1 = a1->nIsotopicOrigAtNosInCanonOrd;
295 : 0 : break;
296 : 0 : case EQL_NUM_INV:
297 : 0 : n1 = a1->nOrigAtNosInCanonOrdInv;
298 : 0 : break;
299 : 0 : case ( EQL_NUM_INV | EQL_NUM_ISO ):
300 : 0 : n1 = a1->nIsotopicOrigAtNosInCanonOrdInv;
301 : 0 : break;
302 : 0 : default:
303 : 0 : return 0;
304 : : }
305 : :
306 [ # # # # : 0 : switch (eql2)
# ]
307 : : {
308 : 0 : case EQL_NUM:
309 : 0 : n2 = a2->nOrigAtNosInCanonOrd;
310 : 0 : break;
311 : 0 : case EQL_NUM_ISO:
312 : 0 : n2 = a2->nIsotopicOrigAtNosInCanonOrd;
313 : 0 : break;
314 : 0 : case EQL_NUM_INV:
315 : 0 : n2 = a2->nOrigAtNosInCanonOrdInv;
316 : 0 : break;
317 : 0 : case ( EQL_NUM_INV | EQL_NUM_ISO ):
318 : 0 : n2 = a2->nIsotopicOrigAtNosInCanonOrdInv;
319 : 0 : break;
320 : 0 : default:
321 : 0 : return 0;
322 : : }
323 : :
324 [ # # # # : 0 : if (n1 && n2 && !memcmp( n1, n2, len * sizeof( n1[0] ) ))
# # ]
325 : : {
326 : 0 : return 1;
327 : : }
328 : :
329 : 0 : return 0;
330 : : }
331 : :
332 : :
333 : : /****************************************************************************/
334 : 185 : int bHasOrigInfo( ORIG_INFO *OrigInfo, int num_atoms )
335 : : {
336 : 185 : int i, bFound = 0;
337 [ + - + - ]: 185 : if (OrigInfo && num_atoms > 0)
338 : : {
339 [ + + + + ]: 1054 : for (i = 0; !bFound && i < num_atoms; i++)
340 : : {
341 : 869 : bFound |= ( 0 != OrigInfo[i].cCharge ) ||
342 [ + + + - ]: 1726 : ( 0 != OrigInfo[i].cRadical ) ||
343 [ + + ]: 857 : ( 0 != OrigInfo[i].cUnusualValence );
344 : : }
345 : : }
346 : :
347 : 185 : return bFound;
348 : : }
349 : :
350 : :
351 : : /****************************************************************************/
352 : 32 : int EqlOrigInfo( INChI_Aux *a1, INChI_Aux *a2 )
353 : : {
354 [ + + + + : 24 : int ret = a1 && a2 && a1->nNumberOfAtoms == a2->nNumberOfAtoms &&
+ + ]
355 [ + + + - ]: 58 : bHasOrigInfo( a1->OrigInfo, a1->nNumberOfAtoms ) && a2->OrigInfo &&
356 [ - + ]: 2 : !memcmp( a1->OrigInfo, a2->OrigInfo, a1->nNumberOfAtoms * sizeof( a1->OrigInfo[0] ) );
357 : :
358 : 32 : return ret;
359 : : }
360 : :
361 : :
362 : : /****************************************************************************/
363 : 222 : int bHasEquString( AT_NUMB *LinearCT, int nLenCT )
364 : : {
365 : : /* produce output string; */
366 : : int i, k;
367 [ + + ]: 222 : if (!LinearCT)
368 : : {
369 : 7 : return 0;
370 : : }
371 [ + + ]: 946 : for (k = 0; k < nLenCT; k++)
372 : : {
373 : : /* find the first equivalence number */
374 [ + + ]: 787 : if (k != (int) LinearCT[k] - 1)
375 : : {
376 : 731 : continue;
377 : : }
378 [ + - ]: 112 : for (i = k; i < nLenCT; i++)
379 : : {
380 [ - + ]: 112 : if (k != (int) LinearCT[i] - 1)
381 : : {
382 : 0 : continue;
383 : : }
384 [ + + ]: 112 : if (k < i)
385 : : {
386 : 56 : return 1;
387 : : }
388 : : }
389 : : }
390 : :
391 : 159 : return 0;
392 : : }
393 : :
394 : :
395 : : /****************************************************************************/
396 : 426 : int MakeMult( int mult,
397 : : const char *szTailingDelim,
398 : : INCHI_IOS_STRING *buf,
399 : : int nCtMode,
400 : : int *bOverflow )
401 : : {
402 : : char szValue[2048];
403 : 426 : int len = 0, len_delim, n;
404 : :
405 [ + + - + ]: 426 : if (mult == 1 || *bOverflow)
406 : : {
407 : 387 : return 0;
408 : : }
409 [ - + ]: 39 : if (nCtMode & CT_MODE_ABC_NUMBERS)
410 : : {
411 : 0 : len += MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, mult );
412 : : }
413 : : else
414 : : {
415 : 39 : len += MakeDecNumber( szValue, ( int )sizeof( szValue ), NULL, mult );
416 : : }
417 : 39 : len_delim = (int) strlen( szTailingDelim );
418 : :
419 [ + - ]: 39 : if (len + len_delim < ( int )sizeof( szValue ))
420 : : {
421 : 39 : strcpy(szValue + len, szTailingDelim);
422 : 39 : n = inchi_strbuf_printf( buf, "%s", szValue );
423 [ - + ]: 39 : if (-1 == n) *bOverflow |= 1;
424 : 39 : return n;
425 : : /*
426 : : len += len_delim;
427 : : if ( len < nLen_szLinearCT )
428 : : {
429 : : strcpy( szLinearCT, szValue );
430 : : return len;
431 : : }*/
432 : : }
433 : :
434 : 0 : *bOverflow |= 1;
435 : :
436 : 0 : return 0;
437 : : }
438 : :
439 : : /**
440 : : * @brief Adds the number to the string buffer.
441 : : *
442 : : * @param number Input number to be added
443 : : * @param szTailingDelim Pointer to the trailing delimiter string
444 : : * @param buf Pointer to the output string buffer
445 : : * @param nCtMode Mode flag for string representation
446 : : * @param bOverflow Pointer to overflow flag
447 : : * @return Returns the number of characters added to the buffer
448 : : */
449 : 163 : int MakeNumber_EnhStereo( int number,
450 : : const char *szTailingDelim,
451 : : INCHI_IOS_STRING *buf,
452 : : int nCtMode,
453 : : int *bOverflow )
454 : : {
455 : : char szValue[2048];
456 : 163 : int len = 0;
457 : : int len_delim;
458 : : int n;
459 : :
460 [ - + ]: 163 : if (*bOverflow)
461 : : {
462 : 0 : return 0;
463 : : }
464 [ - + ]: 163 : if (nCtMode & CT_MODE_ABC_NUMBERS)
465 : : {
466 : 0 : len += MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, number );
467 : : }
468 : : else
469 : : {
470 : 163 : len += MakeDecNumber( szValue, ( int )sizeof( szValue ), NULL, number );
471 : : }
472 : 163 : len_delim = (int) strlen( szTailingDelim );
473 : :
474 [ + - ]: 163 : if (len + len_delim < ( int )sizeof( szValue ))
475 : : {
476 : 163 : strcpy(szValue + len, szTailingDelim);
477 : 163 : n = inchi_strbuf_printf( buf, "%s", szValue );
478 [ - + ]: 163 : if (-1 == n) *bOverflow |= 1;
479 : 163 : return n;
480 : : }
481 : :
482 : 0 : *bOverflow |= 1;
483 : :
484 : 0 : return 0;
485 : : }
486 : :
487 : :
488 : : /****************************************************************************/
489 : : /**
490 : : * @brief Adds the delimiter to the string buffer if it is not empty and there is no overflow.
491 : : *
492 : : * @param szTailingDelim Pointer to the trailing delimiter string
493 : : * @param buf Pointer to the output string buffer
494 : : * @param bOverflow Pointer to overflow flag
495 : : * @return Returns the number of characters added to the buffer, or 0 if the delimiter is empty or there is an overflow
496 : : */
497 : 613 : int MakeDelim( const char *szTailingDelim,
498 : : INCHI_IOS_STRING *buf,
499 : : int *bOverflow )
500 : : {
501 : : int n;
502 [ + - + - : 613 : if (!szTailingDelim || !*szTailingDelim || *bOverflow)
- + ]
503 : : {
504 : 0 : return 0;
505 : : }
506 : :
507 : 613 : n = inchi_strbuf_printf( buf, szTailingDelim );
508 [ - + ]: 613 : if (-1 == n)
509 : : {
510 : 0 : *bOverflow |= 1;
511 : : }
512 : :
513 : 613 : return n;
514 : : /*
515 : : len_delim = (int) strlen(szTailingDelim);
516 : : if ( len_delim < nLen_szLinearCT ) {
517 : : strcpy( szLinearCT, szTailingDelim );
518 : : return len_delim;
519 : : }
520 : : *bOverflow |= 1;
521 : : return 0;
522 : : */
523 : : }
524 : :
525 : :
526 : : /****************************************************************************/
527 : 35 : int MakeEqStr( const char *szTailingDelim,
528 : : int mult,
529 : : INCHI_IOS_STRING *buf,
530 : : int *bOverflow )
531 : : {
532 : 35 : int n = 0, n0;
533 : : char szValue[2048];
534 : :
535 [ + - + - : 35 : if (!szTailingDelim || !*szTailingDelim || *bOverflow)
- + ]
536 : : {
537 : 0 : return 0;
538 : : }
539 : :
540 : 35 : n0 = buf->nUsedLength;
541 : :
542 [ + + ]: 35 : if (mult != 1)
543 : : {
544 : 3 : n = MakeDecNumber( szValue, ( int )sizeof( szValue ), NULL, mult );
545 [ - + ]: 3 : if (-1 == n)
546 : : {
547 : 0 : *bOverflow |= 1;
548 : 0 : return -1;
549 : : }
550 : : }
551 [ + + ]: 35 : if (n > 0)
552 : : {
553 : 3 : n = inchi_strbuf_printf( buf, "%-s", szValue );
554 [ - + ]: 3 : if (-1 == n) *bOverflow |= 1;
555 : : }
556 : 35 : n = inchi_strbuf_printf( buf, "%-s", szTailingDelim );
557 [ - + ]: 35 : if (-1 == n)
558 : : {
559 : 0 : *bOverflow |= 1;
560 : : }
561 : :
562 : 35 : return ( buf->nUsedLength - n0 );
563 : : }
564 : :
565 : :
566 : : /****************************************************************************
567 : : Prepare InChI atomic numbers substring (connections, for InChI)
568 : : nCtMode = 0: full
569 : : 1: censored CT (no orphans)
570 : : 2: compressed CT (Abs numbers)
571 : : ****************************************************************************/
572 : 70 : int MakeCtStringNew( CANON_GLOBALS *pCG,
573 : : AT_NUMB *LinearCT,
574 : : int nLenCT,
575 : : int bAddDelim,
576 : : S_CHAR *nNum_H,
577 : : int num_atoms,
578 : : INCHI_IOS_STRING *strbuf,
579 : : int nCtMode,
580 : : int *bOverflow )
581 : : {
582 : : /* produce output string; */
583 : 70 : int nUsedLength0 = 0, nLen = 0, len, i, bOvfl = *bOverflow;
584 : : char szValue[2048];
585 : : int nValue, nDelim, num_H;
586 : 70 : AT_NUMB *nDfsOrderCT = NULL;
587 : 70 : int bNoNum_H = ( NULL == nNum_H );
588 : : int nNumRingClosures;
589 : 70 : int bAbcNumbers = ( 0 != ( nCtMode & CT_MODE_ABC_NUMBERS ) );
590 : 70 : int bPredecessors = ( 0 != ( nCtMode & CT_MODE_PREDECESSORS ) );
591 [ - + - - : 70 : int bCountRingClosures = bAbcNumbers && bPredecessors && ( nCtMode & CT_MODE_ABC_NUM_CLOSURES );
- - ]
592 : :
593 [ - + ]: 70 : if (nLenCT <= 1)
594 : : {
595 : 0 : return 0; /* no atoms or a single atom: no connection table */
596 : : }
597 : :
598 : 70 : nUsedLength0 = strbuf->nUsedLength;
599 : :
600 : : /* make array containing connection string data */
601 [ - + ]: 70 : if (!( nDfsOrderCT = GetDfsOrder4CT( pCG, LinearCT, nLenCT,
602 : : nNum_H, num_atoms, nCtMode ) ))
603 : : {
604 : 0 : ( *bOverflow )++;
605 : 0 : return 0;
606 : : }
607 : :
608 : : /* add connection table string */
609 [ + - - + ]: 70 : if (!bOvfl && bAddDelim)
610 : : {
611 : 0 : inchi_strbuf_printf( strbuf, "," );
612 : : }
613 : :
614 [ + - ]: 70 : if (!bOvfl)
615 : : {
616 : 70 : nNumRingClosures = 0;
617 [ + + ]: 727 : for (i = 0; nDfsOrderCT[i]/* && nLen < nLen_szLinearCT*/; i += 3)
618 : : {
619 [ + - ]: 657 : nValue = ( nDfsOrderCT[i] > MAX_ATOMS ) ? 0 : nDfsOrderCT[i];
620 [ - + ]: 657 : num_H = nDfsOrderCT[i + 1] ? nDfsOrderCT[i + 1] - 16 : 0;
621 : 657 : nDelim = nDfsOrderCT[i + 2];
622 : 657 : len = 0;
623 : : /* delimiter */
624 [ - + ]: 657 : if (bPredecessors)
625 : : {
626 [ # # ]: 0 : if (bCountRingClosures)
627 : : {
628 [ # # # # : 0 : if (nDelim == '-' && i > 3 && bNoNum_H)
# # ]
629 : : {
630 [ # # ]: 0 : if (!nNumRingClosures)
631 : : {
632 : : int j;
633 [ # # # # ]: 0 : for (j = i; nDfsOrderCT[j] && '-' == nDfsOrderCT[j + 2]; j += 3)
634 : : {
635 : 0 : nNumRingClosures++;
636 : : }
637 [ # # ]: 0 : if (nNumRingClosures)
638 : : {
639 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, nNumRingClosures );
640 : : }
641 : 0 : nNumRingClosures--;
642 : : }
643 : : else
644 : : {
645 : 0 : nNumRingClosures--;
646 : : }
647 : : }
648 : : else
649 : : {
650 : 0 : nNumRingClosures = 0;
651 : : }
652 : : }
653 [ # # # # : 0 : else if (nDelim && !( bAbcNumbers && nDelim == ',' ))
# # ]
654 : : {
655 [ # # # # ]: 0 : if (nNum_H || i > 3)
656 : : {
657 : 0 : szValue[len++] = nDelim;
658 : : }
659 : : }
660 : : }
661 : : else
662 : : {
663 [ + + - + : 657 : if (nDelim && !( bAbcNumbers && nDelim == '-' ))
- - ]
664 : : {
665 : 587 : szValue[len++] = nDelim;
666 : : }
667 : : }
668 [ - + ]: 657 : if (bAbcNumbers)
669 : : {
670 [ # # # # ]: 0 : if (nValue || i)
671 : : {
672 : : /* the 1st value may be zero in case of presdecessor list */
673 : 0 : len += MakeAbcNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, nValue );
674 : : }
675 [ # # ]: 0 : if (num_H)
676 : : {
677 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, num_H );
678 : : }
679 : : }
680 : : else
681 : : {
682 [ - + - - ]: 657 : if (nValue || i)
683 : : {
684 : : /* the 1st value may be zero in case of presdecessor list */
685 : 657 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, nValue );
686 : : }
687 [ - + ]: 657 : if (num_H)
688 : : {
689 : 0 : szValue[len] = 'H';
690 : 0 : len++;
691 [ # # ]: 0 : if (num_H > 1)
692 : : {
693 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, num_H );
694 : : }
695 : : }
696 : : }
697 : :
698 [ + - ]: 657 : if (len > 0)
699 : : {
700 : 657 : inchi_strbuf_printf( strbuf, "%s", szValue );
701 : : }
702 : : }
703 : : }
704 : :
705 : 70 : *bOverflow |= bOvfl;
706 [ + - ]: 70 : if (nDfsOrderCT)
707 : : {
708 [ + - ]: 70 : inchi_free( nDfsOrderCT );
709 : : }
710 : :
711 : 70 : nLen = strbuf->nUsedLength - nUsedLength0;
712 : :
713 : 70 : return nLen;
714 : : }
715 : :
716 : :
717 : : /****************************************************************************
718 : : Prepare InChI atomic numbers substring (for AuxInfo)
719 : :
720 : : nCtMode = 0: full
721 : : 1: censored CT (no orphans)
722 : : 2: compressed CT (Abs numbers)
723 : : ****************************************************************************/
724 : 163 : int MakeCtStringOld( AT_NUMB *LinearCT,
725 : : int nLenCT,
726 : : int bAddDelim,
727 : : INCHI_IOS_STRING *strbuf,
728 : : int nCtMode,
729 : : int *bOverflow )
730 : : {
731 : : /* produce output string; */
732 : 163 : int nUsedLength0 = 0, nLen = 0, len, i, bLessThanPrev, bOvfl = *bOverflow;
733 : 163 : AT_NUMB nMax = 0;
734 : : char szValue[2048];
735 : 163 : int nValue, bNext = 0;
736 : :
737 : 163 : nUsedLength0 = strbuf->nUsedLength;
738 : :
739 : : /* add connection table string */
740 [ + - + - : 163 : if (!( nCtMode & CT_MODE_ABC_NUMBERS ) && !bOvfl && bAddDelim)
- + ]
741 : : {
742 : 0 : inchi_strbuf_printf( strbuf, "," );
743 : : /*
744 : : if ( nLen_szLinearCT > 1 ) {
745 : : strcpy( szLinearCT, "," );
746 : : nLen ++;
747 : : } else {
748 : : bOvfl = 1;
749 : : }*/
750 : : }
751 [ + - ]: 163 : if (!bOvfl)
752 : : {
753 [ + + ]: 983 : for (i = 0; i < nLenCT/* && nLen < nLen_szLinearCT*/; i++)
754 : : {
755 : 820 : bLessThanPrev = 0;
756 [ - + - - ]: 820 : if (!( nCtMode & CT_MODE_NO_ORPHANS ) || ( ( bLessThanPrev = LinearCT[i] < nMax ) ||
757 [ # # # # ]: 0 : (i + 1 < nLenCT && LinearCT[i + 1] < ( nMax = LinearCT[i] )) )) /* djb-rwth: addressing LLVM warning */
758 : : {
759 : 820 : nValue = LinearCT[i];
760 [ - + ]: 820 : if (nCtMode & CT_MODE_ABC_NUMBERS)
761 : : {
762 [ # # # # ]: 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), ( !bNext && bAddDelim ) ? ITEM_DELIMETER : NULL, nValue );
763 : : }
764 : : else
765 : : {
766 [ - + ]: 820 : if (nCtMode & CT_MODE_NO_ORPHANS)
767 : : {
768 : : /* censored CT */
769 : : /* output '-' as a delimiter to show a bonding for decimal output of the connection table */
770 [ # # ]: 0 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), bLessThanPrev ? "-" : ITEM_DELIMETER, nValue );
771 : : }
772 : : else
773 : : {
774 [ + + ]: 820 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), i ? ITEM_DELIMETER : NULL, nValue );
775 : : }
776 : : }
777 [ + - ]: 820 : if (len > 0)
778 : : {
779 : 820 : inchi_strbuf_printf( strbuf, "%s", szValue );
780 : 820 : bNext++;
781 : : }
782 : :
783 : : /*if ( 0 <= len && nLen+len < nLen_szLinearCT) {
784 : : if ( len ) {
785 : : strcpy( szLinearCT+nLen, szValue );
786 : : nLen += len;
787 : : bNext ++;
788 : : }
789 : : } else {
790 : : bOvfl = 1;
791 : : break;
792 : : }*/
793 : : }
794 : : }
795 : : }
796 : 163 : *bOverflow |= bOvfl;
797 : :
798 : 163 : nLen = strbuf->nUsedLength - nUsedLength0;
799 : :
800 : 163 : return nLen;
801 : : }
802 : :
803 : :
804 : : /****************************************************************************
805 : : MakeHString( ... )
806 : :
807 : : nCtMode = 0: decimal
808 : : 2: compressed CT (Abc numbers)
809 : : ****************************************************************************/
810 : 89 : int MakeHString( int bAddDelim,
811 : : S_CHAR *LinearCT,
812 : : int nLenCT,
813 : : INCHI_IOS_STRING *strbuf,
814 : : int nCtMode,
815 : : int *bOverflow )
816 : : {
817 : : #define INIT_MIN_NUM_H (-4)
818 : : #define INIT_MAX_NUM_H 16
819 : : #define INIT_LEN_NUM_H (INIT_MAX_NUM_H - INIT_MIN_NUM_H + 1)
820 : :
821 : : /* produce output string; */
822 : 89 : int nUsedLength0 = 0, nLen = 0, len, i, iFirst, nVal, bOvfl = *bOverflow;
823 : : char szValue[2048];
824 : : const char *pH;
825 : 89 : int bNext = 0;
826 : :
827 : 89 : nUsedLength0 = strbuf->nUsedLength;
828 : :
829 : : /* add connection table string */
830 [ + - + - : 89 : if (!( nCtMode & CT_MODE_ABC_NUMBERS ) && !bOvfl && bAddDelim)
- + ]
831 : : {
832 : 0 : inchi_strbuf_printf( strbuf, "," );
833 : : /*if ( nLen_szLinearCT > 1 ) {
834 : : strcpy( szLinearCT, "," );
835 : : nLen ++;
836 : : } else {
837 : : bOvfl = 1;
838 : : }*/
839 : : }
840 [ + - + - : 89 : if (!bOvfl && 0 < nLenCT && LinearCT)
+ - ]
841 : : {
842 [ + - ]: 89 : if (nCtMode & CT_MODE_EQL_H_TOGETHER)
843 : : {
844 : 89 : int curMinH = INIT_MIN_NUM_H;
845 : 89 : int curMaxH = INIT_MAX_NUM_H;
846 : 89 : int curLenH = INIT_LEN_NUM_H;
847 : : int nInitNumH[INIT_LEN_NUM_H];
848 : 89 : int *nNumH = nInitNumH;
849 : : int numAt, curNumH;
850 : : int j, bOutOfRange, tot_num_no_H;
851 : : /* count atoms H */
852 : : do
853 : : {
854 : 89 : bOutOfRange = 0;
855 : 89 : tot_num_no_H = 0; /* number of atoms that have no H */
856 : 89 : memset( nNumH, 0, curLenH * sizeof( nNumH[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
857 [ + + ]: 729 : for (i = 0; i < nLenCT; i++)
858 : : {
859 : 640 : curNumH = LinearCT[i];
860 [ - + ]: 640 : if (curNumH < curMinH)
861 : : {
862 : 0 : curMinH = curNumH;
863 : 0 : bOutOfRange++;
864 : : }
865 : : else
866 : : {
867 [ - + ]: 640 : if (curNumH > curMaxH)
868 : : {
869 : 0 : curMaxH = curNumH;
870 : 0 : bOutOfRange++;
871 : : }
872 : : else
873 [ + - ]: 640 : if (!bOutOfRange)
874 : : {
875 : 640 : nNumH[curNumH - curMinH] ++;
876 : : }
877 : : }
878 : 640 : tot_num_no_H += !curNumH;
879 : : }
880 [ + + ]: 89 : if (tot_num_no_H == nLenCT)
881 : : {
882 : 5 : return nLen; /* empty string */
883 : : }
884 [ - + ]: 84 : if (bOutOfRange)
885 : : {
886 : : /* for debug only */
887 [ # # ]: 0 : if (nNumH != nInitNumH)
888 : : {
889 : 0 : *bOverflow |= 1;
890 [ # # ]: 0 : inchi_free( nNumH );
891 : 0 : return nLen;
892 : : }
893 : : /* end debug */
894 : 0 : curLenH = curMaxH - curMinH + 1;
895 : 0 : nNumH = (int*) inchi_malloc( curLenH * sizeof( nNumH[0] ) );
896 [ # # ]: 0 : if (!nNumH)
897 : : {
898 : 0 : *bOverflow |= 1;
899 : 0 : return nLen;
900 : : }
901 : : }
902 : : }
903 [ - + ]: 84 : while (bOutOfRange); /* the loop may be executed 1 or 2 times only */
904 : :
905 [ + + ]: 1848 : for (curNumH = curMinH; curNumH <= curMaxH; curNumH++)
906 : : {
907 : 1764 : numAt = nNumH[curNumH - curMinH]; /* number of atoms that have curNumH atoms H */
908 [ + + + + ]: 1764 : if (!numAt || !curNumH)
909 : : {
910 : 1595 : continue; /* no atom has this number of H or number of H = 0 */
911 : : }
912 : 169 : j = 0;
913 [ + + + + ]: 726 : while (j < nLenCT && numAt)
914 : : {
915 [ + + ]: 557 : if (curNumH == LinearCT[j])
916 : : {
917 : 207 : iFirst = ++j;
918 : 207 : numAt--;
919 [ + + + + : 491 : for (; j < nLenCT && curNumH == LinearCT[j] && numAt; j++)
+ - ]
920 : : {
921 : 284 : numAt--;
922 : : }
923 [ - + ]: 207 : if (nCtMode & CT_MODE_ABC_NUMBERS)
924 : : {
925 : 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, iFirst );
926 : : }
927 : : else
928 : : {
929 [ + + ]: 207 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), bNext ? ITEM_DELIMETER : NULL, iFirst );
930 : 207 : bNext++; /* add a delimiter (comma) before all except the first */
931 : : }
932 [ + + ]: 207 : if (iFirst < j)
933 : : {
934 : : /* output last canonical number */
935 [ - + ]: 112 : if (nCtMode & CT_MODE_ABC_NUMBERS)
936 : : {
937 : 0 : len += MakeAbcNumber( szValue + len, ( int )sizeof( szValue ), NULL, j );
938 : : }
939 : : else
940 : : {
941 : 112 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, "-", j );
942 : : }
943 : : }
944 [ + + - + ]: 207 : if (!numAt || ( nCtMode & CT_MODE_ABC_NUMBERS ))
945 : : {
946 : : /* add number of H */
947 : : /* output number of H */
948 : 169 : nVal = curNumH;
949 [ - + ]: 169 : if (nCtMode & CT_MODE_ABC_NUMBERS)
950 : : {
951 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, nVal );
952 : : }
953 : : else
954 : : {
955 [ + - ]: 169 : pH = nVal > 0 ? "H" : "h";
956 : 169 : nVal = abs( nVal );
957 [ + + ]: 169 : if (nVal > 1)
958 : : {
959 : 106 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, pH, nVal );
960 : : }
961 : : else
962 : : {
963 : 63 : strcpy(szValue + len, pH);
964 : 63 : len++;
965 : : }
966 : : }
967 : : }
968 : : /* add to the output */
969 [ + - ]: 207 : if (len > 0)
970 : : {
971 : 207 : inchi_strbuf_printf( strbuf, "%-s", szValue );
972 : 207 : bNext++;
973 : : }
974 : : /*
975 : : if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
976 : : if ( len ) {
977 : : strcpy( szLinearCT+nLen, szValue );
978 : : nLen += len;
979 : : bNext ++;
980 : : }
981 : : } else {
982 : : bOvfl = 1;
983 : : break;
984 : : }*/
985 : : }
986 : : else
987 : : {
988 : 350 : j++;
989 : : }
990 : : }
991 : : }
992 [ - + ]: 84 : if (nNumH != nInitNumH)
993 : : {
994 [ # # ]: 0 : inchi_free( nNumH );
995 : : }
996 : : }
997 : : else
998 : : {
999 : 0 : iFirst = 0;
1000 [ # # ]: 0 : for (i = iFirst + 1; i <= nLenCT/* && nLen < nLen_szLinearCT*/; i++)
1001 : : {
1002 [ # # # # ]: 0 : if (i < nLenCT && LinearCT[i] == LinearCT[iFirst])
1003 : : {
1004 : 0 : continue;
1005 : : }
1006 : : /* output identical values located at i = iFirst..i-1 */
1007 [ # # ]: 0 : if (LinearCT[iFirst])
1008 : : { /* output only non-zero values */
1009 : : /* first canonical number */
1010 : 0 : nVal = LinearCT[iFirst];
1011 : 0 : iFirst++;
1012 [ # # ]: 0 : if (nCtMode & CT_MODE_ABC_NUMBERS)
1013 : : {
1014 : 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, iFirst );
1015 : : }
1016 : : else
1017 : : {
1018 [ # # ]: 0 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), bNext ? ITEM_DELIMETER : NULL, iFirst );
1019 : : }
1020 [ # # ]: 0 : if (iFirst < i)
1021 : : {
1022 : : /* output last canonical number */
1023 [ # # ]: 0 : if (nCtMode & CT_MODE_ABC_NUMBERS)
1024 : : {
1025 : 0 : len += MakeAbcNumber( szValue + len, ( int )sizeof( szValue ), NULL, i );
1026 : : }
1027 : : else
1028 : : {
1029 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, "-", i );
1030 : : }
1031 : : }
1032 : : /* output number of H */
1033 [ # # ]: 0 : if (nCtMode & CT_MODE_ABC_NUMBERS)
1034 : : {
1035 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, nVal );
1036 : : }
1037 : : else
1038 : : {
1039 [ # # ]: 0 : pH = nVal > 0 ? "H" : "h";
1040 : 0 : nVal = abs( nVal );
1041 [ # # ]: 0 : if (nVal > 1)
1042 : : {
1043 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, pH, nVal );
1044 : : }
1045 : : else
1046 : : {
1047 : 0 : strcpy(szValue + len, pH); /* djb-rwth: GCC 14 false positive */
1048 : 0 : len++;
1049 : : }
1050 : : }
1051 [ # # ]: 0 : if (0 <= len/* && nLen+len < nLen_szLinearCT*/)
1052 : : {
1053 [ # # ]: 0 : if (len)
1054 : : {
1055 : 0 : inchi_strbuf_printf( strbuf, "%-s", szValue );
1056 : : /*strcpy( szLinearCT+nLen, szValue );
1057 : : nLen += len;*/
1058 : 0 : bNext++;
1059 : : }
1060 : : }
1061 : : else
1062 : : {
1063 : 0 : bOvfl = 1;
1064 : 0 : break;
1065 : : }
1066 : : }
1067 : 0 : iFirst = i;
1068 : : }
1069 : : }
1070 : : }
1071 : 84 : *bOverflow |= bOvfl;
1072 : :
1073 : 84 : nLen = strbuf->nUsedLength - nUsedLength0;
1074 : 84 : return nLen;
1075 : :
1076 : : #undef INIT_MIN_NUM_H
1077 : : #undef INIT_MAX_NUM_H
1078 : : #undef INIT_LEN_NUM_H
1079 : : }
1080 : :
1081 : :
1082 : : /****************************************************************************
1083 : : Prepare InChI atomic numbers substring
1084 : :
1085 : : nCtMode = 0: full
1086 : : 1: censored CT (no orphans, that CT should
1087 : : have only atoms with neighbors)
1088 : : 2: compressed CT (Abc numbers)
1089 : : ****************************************************************************/
1090 : 163 : int MakeCtString( CANON_GLOBALS *pCG,
1091 : : AT_NUMB *LinearCT,
1092 : : int nLenCT,
1093 : : int bAddDelim,
1094 : : S_CHAR *nNum_H,
1095 : : int num_atoms,
1096 : : INCHI_IOS_STRING *strbuf,
1097 : : int nCtMode,
1098 : : int *bOverflow )
1099 : : {
1100 : :
1101 [ - + - - ]: 163 : if (!nNum_H || !( nCtMode & CT_MODE_NO_ORPHANS ))
1102 : : {
1103 : 163 : return MakeCtStringOld( LinearCT, nLenCT, bAddDelim, strbuf, nCtMode, bOverflow );
1104 : : }
1105 : : else
1106 : : {
1107 : 0 : return MakeCtStringNew( pCG, LinearCT, nLenCT, bAddDelim, nNum_H,
1108 : : num_atoms, strbuf, nCtMode, bOverflow );
1109 : : }
1110 : : }
1111 : :
1112 : :
1113 : : /****************************************************************************
1114 : : MakeTautString( )
1115 : :
1116 : : nCtMode = 0: full: decimal-only, with parentheses around t-groups
1117 : : 2: compressed CT: do not add comma before the output string if bAddDelim != 0
1118 : : do not add parentheses around t-groups
1119 : : atom canon numbers an Abc
1120 : : LinearCT format:
1121 : : N = number of tautomeric groups
1122 : : n = number of endpoints + 1 in a tautomeric group #1
1123 : : next INCHI_T_NUM_MOVABLE lines (any after the first non-zero):
1124 : : h = number of hydrogen atoms in the tautomeric group
1125 : : m = number of negative charges
1126 : : ... (the rest of the INCHI_T_NUM_MOVABLE has not been established, ignore them)
1127 : : c(1) = canonical number of the first atom in the t-group
1128 : : ...
1129 : : c(n-1) = canonical number of the last atom in the t-group
1130 : :
1131 : : ****************************************************************************/
1132 : 89 : int MakeTautString( AT_NUMB *LinearCT,
1133 : : int nLenCT,
1134 : : int bAddDelim,
1135 : : INCHI_IOS_STRING *strbuf,
1136 : : int nCtMode,
1137 : : int *bOverflow )
1138 : : {
1139 : : /* produce output string; */
1140 : 89 : int nUsedLength0 = 0, nLen = 0, len, i, bOvfl = *bOverflow;
1141 : : char szValue[2048];
1142 : : const char *p;
1143 : : int nValue, nGroupLen, iGroupOutputCount, bCompressed;
1144 : : /* make tautomer string */
1145 [ + + + - : 89 : if (!nLenCT || !LinearCT || !*LinearCT)
+ + ]
1146 : : {
1147 : 83 : return nLen;
1148 : : }
1149 : :
1150 : 6 : nUsedLength0 = strbuf->nUsedLength;
1151 : :
1152 : 6 : bCompressed = ( nCtMode & CT_MODE_ABC_NUMBERS );
1153 [ + - + - : 6 : if (!bCompressed && !bOvfl && bAddDelim)
+ + ]
1154 : : {
1155 : 1 : inchi_strbuf_printf( strbuf, "%s", COMMA_EXTRA_SPACE );
1156 : : /*if ( nLen_szLinearCT > 1+LEN_EXTRA_SPACE ) {
1157 : : strcpy( szLinearCT, COMMA_EXTRA_SPACE);
1158 : : nLen += 1+LEN_EXTRA_SPACE;
1159 : : } else {
1160 : : bOvfl = 1;
1161 : : }*/
1162 : : }
1163 : 6 : LinearCT++; /* bypass number of tautomeric groups */
1164 : 6 : nLenCT--;
1165 : :
1166 [ + - ]: 6 : if (!bOvfl)
1167 : : {
1168 [ + + ]: 55 : for (i = nGroupLen = iGroupOutputCount = 0; i < nLenCT/* && nLen < nLen_szLinearCT*/; i++)
1169 : : {
1170 : 49 : nValue = (int) LinearCT[i];
1171 [ + + ]: 49 : if (nGroupLen == iGroupOutputCount)
1172 : : {
1173 : 9 : nGroupLen = nValue;
1174 : 9 : iGroupOutputCount = 0;
1175 : : /* group delimiter (uncompressed) */
1176 [ + - ]: 9 : if (!bCompressed)
1177 : : {
1178 [ + + ]: 9 : if (!i)
1179 : : {
1180 : 6 : strcpy( szValue, "(" );
1181 : 6 : len = 1;
1182 : : }
1183 : : else
1184 : : {
1185 : 3 : strcpy( szValue, ")(" );
1186 : 3 : len = 2;
1187 : : }
1188 : : }
1189 : : else
1190 : : {
1191 : 0 : len = 0;
1192 : : }
1193 : : }
1194 : : else
1195 : : {
1196 [ - + - - ]: 40 : if (bCompressed && iGroupOutputCount >= INCHI_T_NUM_MOVABLE)
1197 : : {
1198 : : /* compressed canon number in Abc */
1199 : 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, nValue );
1200 : 0 : iGroupOutputCount++;
1201 : : }
1202 : : else
1203 : : {
1204 : : /* always output number of hydrogen atoms as a decimal */
1205 : : /* output leading space if: */
1206 : : /* (a) this is the first output value in compressed mode (i==1 && bCompressed) */
1207 : : /* (b) this is not the first output value in non-compressed mode ( iGroupOutputCount && !bCompressed) */
1208 [ - + ]: 40 : if (bCompressed)
1209 : : {
1210 : 0 : p = NULL;
1211 : 0 : len = 0;
1212 [ # # # # ]: 0 : switch (iGroupOutputCount)
1213 : : {
1214 : 0 : case 0:
1215 [ # # ]: 0 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), ( i == 1 ) ? ITEM_DELIMETER : NULL, nValue );
1216 : 0 : break;
1217 : 0 : case 1:
1218 : 0 : p = "-";
1219 : 0 : break;
1220 : 0 : case 2:
1221 : 0 : p = "+";
1222 : 0 : break;
1223 : : }
1224 [ # # ]: 0 : if (p)
1225 : : {
1226 [ # # # ]: 0 : switch (nValue)
1227 : : {
1228 : 0 : case 0:
1229 : 0 : len = 0;
1230 : 0 : break;
1231 : 0 : case 1:
1232 : 0 : strcpy(szValue, p);
1233 : 0 : len = (int) strlen( szValue );
1234 : 0 : break;
1235 : 0 : default:
1236 : 0 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), p, nValue );
1237 : 0 : break;
1238 : : }
1239 : : }
1240 : : }
1241 : : else
1242 : : {
1243 [ + + ]: 40 : if (iGroupOutputCount >= INCHI_T_NUM_MOVABLE)
1244 : : {
1245 : : /* canonical number of the atom in the tautomeric group */
1246 : 22 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), ITEM_DELIMETER, nValue );
1247 : : }
1248 : : else
1249 : : {
1250 : 18 : p = NULL;
1251 : 18 : len = 0;
1252 [ + + ]: 18 : if (nValue)
1253 : : {
1254 [ + - - - ]: 9 : switch (iGroupOutputCount)
1255 : : {
1256 : 9 : case 0:
1257 : 9 : p = "H";
1258 : 9 : break;
1259 : 0 : case 1:
1260 : 0 : p = "-";
1261 : 0 : break;
1262 : 0 : case 2:
1263 : 0 : p = "+";
1264 : 0 : break;
1265 : : }
1266 [ + - ]: 9 : if (p)
1267 : : {
1268 : : /* number of hydrogens */
1269 [ + + ]: 9 : if (nValue == 1)
1270 : : {
1271 : 7 : strcpy(szValue, p);
1272 : 7 : len = (int) strlen( szValue );
1273 : : }
1274 : : else
1275 : : {
1276 : 2 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), p, nValue );
1277 : : }
1278 : : }
1279 : : }
1280 : : }
1281 : : }
1282 : 40 : iGroupOutputCount++;
1283 : : }
1284 : : }
1285 : :
1286 [ + + ]: 49 : if (len > 0)
1287 : : {
1288 : 40 : inchi_strbuf_printf( strbuf, "%s", szValue );
1289 : : }
1290 : : /*if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
1291 : : if ( len ) {
1292 : : strcpy( szLinearCT+nLen, szValue );
1293 : : nLen += len;
1294 : : }
1295 : : } else {
1296 : : bOvfl = 1;
1297 : : break;
1298 : : }*/
1299 : : }
1300 : :
1301 [ + - + - : 6 : if (!bOvfl && !bCompressed && i)
+ - ]
1302 : : {
1303 : 6 : inchi_strbuf_printf( strbuf, ")" );
1304 : : /*if ( nLen + 1 < nLen_szLinearCT ) {
1305 : : strcpy( szLinearCT+nLen, ")" );
1306 : : nLen ++;
1307 : : } else {
1308 : : bOvfl = 1;
1309 : : }*/
1310 : : }
1311 : : }
1312 : 6 : *bOverflow |= bOvfl;
1313 : :
1314 : 6 : nLen = strbuf->nUsedLength - nUsedLength0;
1315 : :
1316 : 6 : return nLen;
1317 : : }
1318 : :
1319 : :
1320 : : /****************************************************************************
1321 : : MakeCRVString( ... )
1322 : :
1323 : : nCtMode = 0: full
1324 : : 2: compressed CT
1325 : : 22+3s3: 22=canon. number; +3=charge; s=singlet (d=doublet, t=triplet, s is omitted if valence=0), 3 = valence
1326 : : 22+3.3, (charge, valence) 22.3 (valence) 22t3 (triplet, valence)
1327 : : Ab+3t4: Ab=canon. number; +3=charge or "." t=triplet (or s, d), 4=valence
1328 : : ****************************************************************************/
1329 : 12 : int MakeCRVString( ORIG_INFO *OrigInfo,
1330 : : int nLenCT,
1331 : : int bAddDelim,
1332 : : INCHI_IOS_STRING *strbuf,
1333 : : int nCtMode,
1334 : : int *bOverflow )
1335 : : {
1336 : : /* produce output string; */
1337 : 12 : int nUsedLength0 = 0, nLen = 0, len, k, bAbcNumbers;
1338 : 12 : int bOvfl = *bOverflow;
1339 : 12 : char szValue[2048] = { 0 };
1340 : 12 : int bNext = 0;
1341 : 12 : bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
1342 : :
1343 : 12 : nUsedLength0 = strbuf->nUsedLength;
1344 : :
1345 : : /* add connection table string */
1346 [ + - - + ]: 12 : if (!bOvfl && bAddDelim)
1347 : : {
1348 : 0 : inchi_strbuf_printf( strbuf, ", " );
1349 : : /*if ( nLen_szLinearCT > 2 ) {
1350 : : strcpy( szLinearCT, ", " );
1351 : : nLen += 2;
1352 : : } else {
1353 : : bOvfl = 1;
1354 : : }*/
1355 : : }
1356 : :
1357 [ + - + + ]: 101 : for (k = 0; !bOvfl && k < nLenCT/* && nLen < nLen_szLinearCT*/; k++)
1358 : : {
1359 : : /* find the next non-empty entry */
1360 [ + + + - : 89 : if (OrigInfo[k].cCharge || OrigInfo[k].cRadical || OrigInfo[k].cUnusualValence)
+ + ]
1361 : : {
1362 [ - + ]: 15 : if (bAbcNumbers)
1363 : : {
1364 : : /*
1365 : : 3 items: Ad+3d4 (canon. numb=Ad, charge=+3, doublet, valence = 4
1366 : : 2 items: Ad.d4 Ad+3.4 Ad+3d
1367 : : 1 item: Ad+3 Ad.d Ad4
1368 : :
1369 : : dot output before radical: no charge, radical is present
1370 : : dot before valence: charge is present, no radical, valence is present
1371 : : */
1372 : 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), NULL, k + 1 );
1373 : :
1374 : : /* charge */
1375 [ # # ]: 0 : if (OrigInfo[k].cCharge)
1376 : : {
1377 [ # # ]: 0 : if (OrigInfo[k].cCharge > 0)
1378 : : {
1379 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, "+", OrigInfo[k].cCharge );
1380 : : }
1381 : : else
1382 : : {
1383 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, OrigInfo[k].cCharge );
1384 : : }
1385 : : }
1386 : : /* radical */
1387 [ # # ]: 0 : if (OrigInfo[k].cRadical)
1388 : : {
1389 [ # # ]: 0 : if (!OrigInfo[k].cCharge)
1390 : : {
1391 [ # # ]: 0 : if (len >= 2047) /* djb-rwth: fixing coverity ID #499515 */
1392 : : {
1393 : 0 : len = 2047;
1394 : 0 : goto early_break;
1395 : : }
1396 [ # # ]: 0 : else if (len < 0) /* djb-rwth: fixing coverity ID #500400 */
1397 : : {
1398 : 0 : len = 0;
1399 : 0 : goto early_break;
1400 : : }
1401 : : else
1402 : : {
1403 : 0 : szValue[len] = '.';
1404 : 0 : len++;
1405 : : }
1406 : : }
1407 [ # # ]: 0 : if (len >= 2047) /* djb-rwth: fixing coverity ID #499515 */
1408 : : {
1409 : 0 : len = 2047;
1410 : 0 : goto early_break;
1411 : : }
1412 [ # # ]: 0 : else if (len < 0) /* djb-rwth: fixing coverity ID #500382 */
1413 : : {
1414 : 0 : len = 0;
1415 : 0 : goto early_break;
1416 : : }
1417 : : else
1418 : : {
1419 [ # # # ]: 0 : switch (OrigInfo[k].cRadical)
1420 : : {
1421 : 0 : case 1:
1422 : : /* djb-rwth: fixing coverity ID #499515 -- false positive, len tested for overflow */
1423 : 0 : szValue[len] = 'd';
1424 : 0 : len++;
1425 : 0 : break;
1426 : 0 : case 2:
1427 : 0 : szValue[len] = 't';
1428 : 0 : len++;
1429 : 0 : break;
1430 : 0 : default:
1431 : 0 : szValue[len] = 'u';
1432 : 0 : len++;
1433 : 0 : break;
1434 : : }
1435 : : }
1436 : : }
1437 : : /* valence */
1438 [ # # ]: 0 : if (OrigInfo[k].cUnusualValence)
1439 : : {
1440 [ # # # # ]: 0 : if (OrigInfo[k].cCharge && !OrigInfo[k].cRadical)
1441 : : {
1442 [ # # ]: 0 : if (len >= 2047) /* djb-rwth: fixing coverity ID #499515 */
1443 : : {
1444 : 0 : len = 2047;
1445 : 0 : goto early_break;
1446 : : }
1447 [ # # ]: 0 : else if (len < 0) /* djb-rwth: fixing coverity ID #500382 */
1448 : : {
1449 : 0 : len = 0;
1450 : 0 : goto early_break;
1451 : : }
1452 : : else
1453 : : {
1454 : 0 : szValue[len] = '.';
1455 : 0 : len++;
1456 : : }
1457 : : }
1458 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, OrigInfo[k].cUnusualValence );
1459 : : }
1460 : : }
1461 : : else
1462 : : {
1463 : : /*
1464 : : 3 items: 22+3d4 (canon. numb=22, charge=+3, doublet, valence = 4
1465 : : 2 items: 22d4 22+3.4 22+3d
1466 : : 1 item: 22+3 22d 22.4
1467 : :
1468 : : dot output before valence:
1469 : : (a) charge, no radical, valence
1470 : : (b) no charge, no radical, valence
1471 : : that is, whenever valence is present and no radical
1472 : : */
1473 [ + + ]: 15 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), bNext ? ITEM_DELIMETER : NULL, k + 1 );
1474 : : /* charge */
1475 [ + + ]: 15 : if (OrigInfo[k].cCharge)
1476 : : {
1477 [ - + ]: 6 : if (OrigInfo[k].cCharge > 0)
1478 : : {
1479 : 0 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, "+", OrigInfo[k].cCharge );
1480 : : }
1481 : : else
1482 : : {
1483 : 6 : len += MakeDecNumber( szValue + len, ( int )sizeof( szValue ) - len, NULL, OrigInfo[k].cCharge );
1484 : : }
1485 : : }
1486 : : /* radical */
1487 [ - + ]: 15 : if (OrigInfo[k].cRadical)
1488 : : {
1489 [ # # ]: 0 : if (len >= 2047) /* djb-rwth: fixing coverity ID #499515 */
1490 : : {
1491 : 0 : len = 2047;
1492 : 0 : goto early_break;
1493 : : }
1494 [ # # ]: 0 : else if (len < 0) /* djb-rwth: fixing coverity ID #500382 */
1495 : : {
1496 : 0 : len = 0;
1497 : 0 : goto early_break;
1498 : : }
1499 : : else
1500 : : {
1501 [ # # # ]: 0 : switch (OrigInfo[k].cRadical)
1502 : : {
1503 : 0 : case 1:
1504 : 0 : szValue[len] = 'd'; /* djb-rwth: GCC 14 false positive */
1505 : 0 : len++;
1506 : 0 : break;
1507 : 0 : case 2:
1508 : 0 : szValue[len] = 't';
1509 : 0 : len++;
1510 : 0 : break;
1511 : 0 : default:
1512 : 0 : szValue[len] = 'u';
1513 : 0 : len++;
1514 : 0 : break;
1515 : : }
1516 : : }
1517 : : }
1518 : : /* valence */
1519 [ + + ]: 15 : if (OrigInfo[k].cUnusualValence)
1520 : : {
1521 [ + - ]: 9 : if (!OrigInfo[k].cRadical)
1522 : : {
1523 [ - + ]: 9 : if (len >= 2047) /* djb-rwth: fixing coverity ID #499515 */
1524 : : {
1525 : 0 : len = 2047;
1526 : 0 : goto early_break;
1527 : : }
1528 [ - + ]: 9 : else if (len < 0) /* djb-rwth: fixing coverity ID #500382 */
1529 : : {
1530 : 0 : len = 0;
1531 : 0 : goto early_break;
1532 : : }
1533 : : else
1534 : : {
1535 : 9 : szValue[len] = '.';
1536 : 9 : len++;
1537 : : }
1538 : : }
1539 : 9 : len += MakeDecNumber(szValue + len, (int)sizeof(szValue) - len, NULL, OrigInfo[k].cUnusualValence);
1540 : : }
1541 : : }
1542 : : }
1543 : : else
1544 : : {
1545 : 74 : len = 0;
1546 : : }
1547 : :
1548 : 89 : early_break:
1549 [ + + ]: 89 : if (len)
1550 : : {
1551 : 15 : szValue[len] = '\0';
1552 : 15 : inchi_strbuf_printf( strbuf, "%s", szValue );
1553 : 15 : bNext++;
1554 : 15 : szValue[0] = '\0';
1555 : : }
1556 : : /*if ( len && nLen+len < nLen_szLinearCT ) {
1557 : : strcpy( szLinearCT+nLen, szValue );
1558 : : nLen += len;
1559 : : bNext ++;
1560 : : } else
1561 : : if ( len ) {
1562 : : bOvfl = 1;
1563 : : break;
1564 : : }*/
1565 : : }
1566 : 12 : *bOverflow |= bOvfl;
1567 : :
1568 : 12 : nLen = strbuf->nUsedLength - nUsedLength0;
1569 : :
1570 : 12 : return nLen;
1571 : : }
1572 : :
1573 : :
1574 : : /****************************************************************************
1575 : : MakeEquString( ... )
1576 : :
1577 : : nCtMode = 0: full
1578 : : 2: compressed CT
1579 : : ****************************************************************************/
1580 : 25 : int MakeEquString( AT_NUMB *LinearCT,
1581 : : int nLenCT,
1582 : : int bAddDelim,
1583 : : INCHI_IOS_STRING *strbuf,
1584 : : int nCtMode,
1585 : : int *bOverflow )
1586 : : {
1587 : : /* produce output string; */
1588 : 25 : int nUsedLength0 = 0, nLen = 0, len, i, k, bAbcNumbers; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1589 : 25 : int bOvfl = *bOverflow;
1590 : : char szValue[2048];
1591 : 25 : int bNext = 0;
1592 : :
1593 : 25 : nUsedLength0 = strbuf->nUsedLength;
1594 : :
1595 : 25 : bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
1596 : : /* add connection table string */
1597 [ + - - + ]: 25 : if (!bOvfl && bAddDelim)
1598 : : {
1599 : 0 : inchi_strbuf_printf( strbuf, ", " );
1600 : : /*if ( nLen_szLinearCT > 2 ) {
1601 : : strcpy( szLinearCT, ", " );
1602 : : nLen += 2;
1603 : : } else {
1604 : : bOvfl = 1;
1605 : : }*/
1606 : : }
1607 [ + - + + ]: 241 : for (k = 0; !bOvfl && k < nLenCT/* && nLen < nLen_szLinearCT*/; k++)
1608 : : {
1609 : : /* find the first equivalence number */
1610 [ + + ]: 216 : if (k != (int) LinearCT[k] - 1)
1611 : : {
1612 : 149 : continue;
1613 : : }
1614 [ + + ]: 882 : for (i = k; i < nLenCT/* && nLen < nLen_szLinearCT*/; i++)
1615 : : {
1616 [ + + ]: 815 : if (k != (int) LinearCT[i] - 1)
1617 : : {
1618 : 657 : continue;
1619 : : }
1620 : : /* equivalence number: a minimal canon_number out of a group of equivalent atoms */
1621 : : /* is at canon_number-1 position of each equivalent atom. */
1622 [ - + ]: 158 : if (bAbcNumbers)
1623 : : {
1624 [ # # # # ]: 0 : len = MakeAbcNumber( szValue, ( int )sizeof( szValue ), ( i == k && bNext ) ? ITEM_DELIMETER : NULL, i + 1 ); /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1625 : : }
1626 : : else
1627 : : {
1628 [ + + ]: 158 : len = MakeDecNumber( szValue, ( int )sizeof( szValue ), ( i == k ) ? "(" : ITEM_DELIMETER, i + 1 ); /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1629 : : }
1630 : 158 : inchi_strbuf_printf( strbuf, "%s", szValue );
1631 : 158 : bNext++;
1632 : : /*if ( 0 <= len && nLen+len < nLen_szLinearCT ) {
1633 : : strcpy( szLinearCT+nLen, szValue );
1634 : : nLen += len;
1635 : : bNext ++;
1636 : : } else
1637 : : if ( 0 > len ) {
1638 : : bOvfl = 1;
1639 : : break;
1640 : : }*/
1641 : : }
1642 : 67 : inchi_strbuf_printf( strbuf, ")" );
1643 : : /*if ( !bOvfl && !bAbcNumbers ) {
1644 : : if ( nLen + 2 < nLen_szLinearCT ) {
1645 : : strcpy( szLinearCT+nLen, ")" );
1646 : : nLen ++;
1647 : : } else {
1648 : : bOvfl = 1;
1649 : : }
1650 : : }*/
1651 : : }
1652 : 25 : *bOverflow |= bOvfl;
1653 : :
1654 : 25 : nLen = strbuf->nUsedLength - nUsedLength0;
1655 : :
1656 : 25 : return nLen;
1657 : : }
1658 : :
1659 : :
1660 : : /****************************************************************************
1661 : : MakeIsoAtomString( ... )
1662 : :
1663 : : nCtMode = 0: full
1664 : : 2: compressed CT
1665 : : ****************************************************************************/
1666 : 0 : int MakeIsoAtomString( INChI_IsotopicAtom *IsotopicAtom,
1667 : : int nNumberOfIsotopicAtoms,
1668 : : INCHI_IOS_STRING *strbuf,
1669 : : int nCtMode,
1670 : : int *bOverflow )
1671 : : {
1672 : : /* produce output string; */
1673 : 0 : int nUsedLength0 = 0, nLen = 0, len, tot_len, ret, i, j, bOvfl = *bOverflow;
1674 : : char szValue[2048];
1675 : : char *p;
1676 : : int nValue;
1677 : 0 : int bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
1678 : : static const char letter[] = "itdh";
1679 : : static const char *h[] = { "T", "D", "H" };
1680 : : static const char *sign[] = { "-", "+" };
1681 : :
1682 : 0 : nUsedLength0 = strbuf->nUsedLength;
1683 : :
1684 [ # # ]: 0 : if (!bOvfl)
1685 : : {
1686 [ # # ]: 0 : for (i = 0; i < nNumberOfIsotopicAtoms/* && nLen < nLen_szLinearCT*/; i++)
1687 : : {
1688 : 0 : p = szValue;
1689 : 0 : tot_len = 0;
1690 [ # # ]: 0 : for (j = 0; j < 5; j++)
1691 : : {
1692 : 0 : len = 0;
1693 [ # # # # : 0 : switch (j)
# # ]
1694 : : {
1695 : 0 : case 0:
1696 : 0 : nValue = (int) IsotopicAtom[i].nAtomNumber;
1697 : 0 : break;
1698 : 0 : case 1:
1699 : 0 : nValue = (int) IsotopicAtom[i].nIsoDifference;
1700 : 0 : break;
1701 : 0 : case 2:
1702 : 0 : nValue = (int) IsotopicAtom[i].nNum_T;
1703 : 0 : break;
1704 : 0 : case 3:
1705 : 0 : nValue = (int) IsotopicAtom[i].nNum_D;
1706 : 0 : break;
1707 : 0 : case 4:
1708 : 0 : nValue = (int) IsotopicAtom[i].nNum_H;
1709 : 0 : break;
1710 : : }
1711 [ # # ]: 0 : if (!j)
1712 : : {
1713 : : /* atom canonical number */
1714 [ # # # # ]: 0 : len = ( bAbcNumbers ? MakeAbcNumber : MakeDecNumber )
1715 : : ( p, ( int )sizeof( szValue ) - tot_len,
1716 [ # # ]: 0 : bAbcNumbers ? NULL : ( i ? ITEM_DELIMETER : EXTRA_SPACE ), nValue
1717 : : );
1718 : : }
1719 : : else
1720 : : {
1721 [ # # ]: 0 : if (bAbcNumbers)
1722 : : {
1723 : : /* Abc output */
1724 [ # # # ]: 0 : switch (j)
1725 : : {
1726 : 0 : case 1: /* nIsoDifference */
1727 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, NULL, nValue );
1728 : 0 : break;
1729 : 0 : case 2: /* nNum_T */
1730 : : case 3: /* nNum_D */
1731 : : case 4: /* nNum_H */
1732 [ # # ]: 0 : if (nValue)
1733 : : {
1734 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len > 1)
1735 : : {
1736 : 0 : p[len++] = letter[j - 1];
1737 [ # # ]: 0 : if (1 == nValue)
1738 : : {
1739 : 0 : p[len] = '\0';
1740 : : }
1741 : : else
1742 : : {
1743 : 0 : ret = MakeDecNumber( p + len, ( int )sizeof( szValue ) - tot_len - len, NULL, nValue );
1744 [ # # ]: 0 : len = ( ret >= 0 ) ? len + ret : ret;
1745 : : }
1746 : : }
1747 : : else
1748 : : {
1749 : 0 : len = -1; /* overflow */
1750 : : }
1751 : : }
1752 : : }
1753 : : }
1754 : : else
1755 : : {
1756 [ # # ]: 0 : if (nValue)
1757 : : {
1758 [ # # ]: 0 : if (j == 1)
1759 : : {
1760 : : /* Decimal output */
1761 : : /* signed isotopic mass difference */
1762 : 0 : int subtract = ( nValue > 0 );
1763 : : /* (n = mass difference) > 0 corresponds to nValue = n+1 */
1764 : : /* subtract 1 from it so that mass difference for 35Cl or 12C is zero */
1765 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, sign[nValue >= 0], abs( nValue - subtract ) );
1766 : : }
1767 : : else
1768 : : {
1769 : : /* hydrogen isotope */
1770 [ # # ]: 0 : if (nValue != 1)
1771 : : {
1772 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, h[j - 2], nValue );
1773 : : }
1774 : : else
1775 : : {
1776 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len > 1)
1777 : : {
1778 : 0 : strcpy(p, h[j - 2]);
1779 : 0 : len = 1;
1780 : : }
1781 : : else
1782 : : {
1783 : 0 : len = -1; /* overflow */
1784 : : }
1785 : : }
1786 : : }
1787 : : }
1788 : : else
1789 : : {
1790 : 0 : continue; /* do not write zeroes */
1791 : : }
1792 : : }
1793 : : }
1794 [ # # ]: 0 : if (len < 0)
1795 : : {
1796 : 0 : bOvfl = 1;
1797 : 0 : break;
1798 : : }
1799 : 0 : tot_len += len;
1800 : 0 : p += len;
1801 : : }
1802 : 0 : inchi_strbuf_printf( strbuf, "%s", szValue );
1803 : : /*if ( nLen+tot_len < nLen_szLinearCT )
1804 : : {
1805 : : memcpy( szLinearCT+nLen, szValue, tot_len+1 );
1806 : : nLen += tot_len;
1807 : : }
1808 : : else
1809 : : {
1810 : : bOvfl = 1;
1811 : : break;
1812 : : }*/
1813 : : }
1814 : : }
1815 : 0 : *bOverflow |= bOvfl;
1816 : :
1817 : 0 : nLen = strbuf->nUsedLength - nUsedLength0;
1818 : :
1819 : 0 : return nLen;
1820 : : }
1821 : :
1822 : :
1823 : : /****************************************************************************/
1824 : 0 : int MakeIsoTautString( INChI_IsotopicTGroup *IsotopicTGroup,
1825 : : int nNumberOfIsotopicTGroups,
1826 : : INCHI_IOS_STRING *strbuf,
1827 : : int nCtMode,
1828 : : int *bOverflow )
1829 : : {
1830 : : /* produce output string; */
1831 : 0 : int nUsedLength0 = 0, nLen = 0, len, tot_len, i, j, bOvfl = *bOverflow;
1832 : : /* djb-rwth: removing redundant variables */
1833 : : char szValue[2048];
1834 : : char *p;
1835 : : int nValue;
1836 : 0 : int bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
1837 : : static const char letter[] = "tdh";
1838 : : static const char *h[] = { "T", "D", "H" };
1839 : :
1840 : 0 : nUsedLength0 = strbuf->nUsedLength;
1841 : :
1842 : : /* add connection table string */
1843 : : /* djb-rwth: removing redundant code */
1844 [ # # ]: 0 : if (!bOvfl)
1845 : : {
1846 [ # # ]: 0 : for (i = 0; i < nNumberOfIsotopicTGroups/* && nLen < nLen_szLinearCT*/; i++)
1847 : : {
1848 : 0 : p = szValue;
1849 : 0 : tot_len = 0;
1850 [ # # ]: 0 : for (j = 0; j < 4; j++)
1851 : : {
1852 [ # # # # : 0 : switch (j)
# ]
1853 : : {
1854 : 0 : case 0:
1855 : 0 : nValue = (int) IsotopicTGroup[i].nTGroupNumber;
1856 : 0 : break;
1857 : 0 : case 1:
1858 : 0 : nValue = (int) IsotopicTGroup[i].nNum_T;
1859 : 0 : break;
1860 : 0 : case 2:
1861 : 0 : nValue = (int) IsotopicTGroup[i].nNum_D;
1862 : 0 : break;
1863 : 0 : case 3:
1864 : 0 : nValue = (int) IsotopicTGroup[i].nNum_H;
1865 : 0 : break;
1866 : : }
1867 [ # # ]: 0 : if (!j)
1868 : : {
1869 : : /* atom canonical number */
1870 [ # # # # ]: 0 : len = ( bAbcNumbers ? MakeAbcNumber : MakeDecNumber )
1871 : : ( p, ( int )sizeof( szValue ) - tot_len,
1872 [ # # ]: 0 : bAbcNumbers ? NULL : ( i ? ITEM_DELIMETER : EXTRA_SPACE ),
1873 : : nValue
1874 : : );
1875 : : }
1876 : : else
1877 [ # # ]: 0 : if (nValue)
1878 : : {
1879 [ # # ]: 0 : if (bAbcNumbers)
1880 : : {
1881 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, NULL, nValue );
1882 [ # # ]: 0 : if (len > 0)
1883 : : { /* make sure overflow has not happened */
1884 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len - len > 1)
1885 : : {
1886 : 0 : p[len++] = letter[j - 1];
1887 : 0 : p[len] = '\0';
1888 : : }
1889 : : else
1890 : : {
1891 : 0 : len = -1; /* overflow */
1892 : : }
1893 : : }
1894 : : }
1895 : : else
1896 : : {
1897 : : /* hydrogen isotope */
1898 [ # # ]: 0 : if (nValue != 1)
1899 : : {
1900 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, h[j - 1], nValue );
1901 : : }
1902 : : else
1903 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len > 1)
1904 : : {
1905 : 0 : strcpy(p, h[j - 1]);
1906 : 0 : len = 1;
1907 : : }
1908 : : else
1909 : : {
1910 : 0 : len = -1; /* overflow */
1911 : : }
1912 : : }
1913 : : }
1914 : : else
1915 : : {
1916 : 0 : continue; /* do not write zeroes */
1917 : : }
1918 [ # # ]: 0 : if (len < 0)
1919 : : {
1920 : 0 : bOvfl = 1;
1921 : 0 : break;
1922 : : }
1923 : 0 : p += len;
1924 : 0 : tot_len += len;
1925 : : }
1926 : 0 : inchi_strbuf_printf( strbuf, "%s", szValue );
1927 : : /*if ( nLen+tot_len < nLen_szLinearCT ) {
1928 : : memcpy( szLinearCT+nLen, szValue, tot_len+1 );
1929 : : nLen += tot_len;
1930 : : } else {
1931 : : bOvfl = 1;
1932 : : break;
1933 : : }*/
1934 : : }
1935 : : }
1936 : 0 : *bOverflow |= bOvfl;
1937 : :
1938 : 0 : nLen = strbuf->nUsedLength - nUsedLength0;
1939 : :
1940 : 0 : return nLen;
1941 : : }
1942 : :
1943 : :
1944 : : /****************************************************************************/
1945 : 0 : int MakeIsoHString( int num_iso_H[],
1946 : : INCHI_IOS_STRING *strbuf,
1947 : : int nCtMode,
1948 : : int *bOverflow )
1949 : : {
1950 : : /* produce output string; */
1951 : 0 : int nUsedLength0 = 0, nLen = 0, len, tot_len, j, bOvfl = *bOverflow;
1952 : : /* djb-rwth: removing redundant variables */
1953 : : char szValue[2048];
1954 : : char *p;
1955 : : int nValue;
1956 : 0 : int bAbcNumbers = ( nCtMode & CT_MODE_ABC_NUMBERS );
1957 : : static const char letter[] = "tdh";
1958 : : static const char *h[] = { "T", "D", "H" };
1959 : :
1960 : 0 : nUsedLength0 = strbuf->nUsedLength;
1961 : :
1962 : : /* add connection table string */
1963 : : /* djb-rwth: removing redundant code */
1964 [ # # ]: 0 : if (!bOvfl)
1965 : : {
1966 : 0 : p = szValue;
1967 : 0 : tot_len = 0;
1968 [ # # ]: 0 : for (j = 1; j < 4; j++)
1969 : : {
1970 : 0 : nValue = num_iso_H[NUM_H_ISOTOPES - j];/* j: 1=>T, 2=>D, 3=>1H */
1971 [ # # ]: 0 : if (nValue)
1972 : : {
1973 [ # # ]: 0 : if (bAbcNumbers)
1974 : : {
1975 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, NULL, nValue );
1976 [ # # ]: 0 : if (len > 0)
1977 : : {
1978 : : /* make sure overflow has not happened */
1979 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len - len > 1)
1980 : : {
1981 : 0 : p[len++] = letter[j - 1];
1982 : 0 : p[len] = '\0';
1983 : : }
1984 : : else
1985 : : {
1986 : 0 : len = -1; /* overflow */
1987 : : }
1988 : : }
1989 : : }
1990 : : else
1991 : : {
1992 : : /* hydrogen isotope */
1993 [ # # ]: 0 : if (nValue != 1)
1994 : : {
1995 : 0 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, h[j - 1], nValue );
1996 : : }
1997 : : else
1998 : : {
1999 [ # # ]: 0 : if (( int )sizeof( szValue ) - tot_len > 1)
2000 : : {
2001 : 0 : strcpy(p, h[j - 1]);
2002 : 0 : len = 1;
2003 : : }
2004 : : else
2005 : : {
2006 : 0 : len = -1; /* overflow */
2007 : : }
2008 : : }
2009 : : }
2010 : : }
2011 : : else
2012 : : {
2013 : 0 : continue; /* do not write zeroes */
2014 : : }
2015 [ # # ]: 0 : if (len < 0)
2016 : : {
2017 : 0 : bOvfl = 1;
2018 : 0 : break;
2019 : : }
2020 : 0 : p += len;
2021 : 0 : tot_len += len;
2022 : : }
2023 : 0 : inchi_strbuf_printf( strbuf, "%s", szValue );
2024 : : /*if ( nLen+tot_len < nLen_szLinearCT ) {
2025 : : memcpy( szLinearCT+nLen, szValue, tot_len+1 );
2026 : : nLen += tot_len;
2027 : : } else {
2028 : : bOvfl = 1;
2029 : : }*/
2030 : : }
2031 : 0 : *bOverflow |= bOvfl;
2032 : :
2033 : 0 : nLen = strbuf->nUsedLength - nUsedLength0;
2034 : :
2035 : 0 : return nLen;
2036 : : }
2037 : :
2038 : :
2039 : : /****************************************************************************/
2040 : 59 : int MakeStereoString( AT_NUMB *at1,
2041 : : AT_NUMB *at2,
2042 : : S_CHAR *parity,
2043 : : int bAddDelim,
2044 : : int nLenCT,
2045 : : INCHI_IOS_STRING *strbuf,
2046 : : int nCtMode,
2047 : : int *bOverflow )
2048 : : {
2049 : : /* produce output string; */
2050 : 59 : int nUsedLength0 = 0, nLen = 0, len, tot_len, i, j, bOvfl = *bOverflow;
2051 : : char szValue[2048];
2052 : : char *p;
2053 : : int nValue;
2054 : : static const char parity_char[] = "!-+u?";
2055 : :
2056 : 59 : nUsedLength0 = strbuf->nUsedLength;
2057 : 59 : bAddDelim = 0;
2058 : :
2059 [ + - ]: 59 : if (!bOvfl)
2060 : : {
2061 [ + + ]: 274 : for (i = 0; i < nLenCT/* && nLen < nLen_szLinearCT*/; i++)
2062 : : {
2063 : 215 : p = szValue;
2064 : 215 : tot_len = 0;
2065 [ + + ]: 860 : for (j = 0; j < 3; j++)
2066 : : {
2067 [ + + + - ]: 645 : if (j == 0 && at1)
2068 : : {
2069 : 215 : nValue = (int) at1[i];
2070 : : }
2071 : : else
2072 : : {
2073 [ + + - + ]: 430 : if (j == 1 && at2)
2074 : : {
2075 : 0 : nValue = (int) at2[i];
2076 : : }
2077 : : else
2078 : : {
2079 [ + + + - ]: 430 : if (j == 2 && parity)
2080 : : {
2081 : 215 : nValue = (int) parity[i];
2082 : : }
2083 : : else
2084 : : {
2085 : 215 : continue;
2086 : : }
2087 : : }
2088 : : }
2089 [ - + ]: 430 : if (nCtMode & CT_MODE_ABC_NUMBERS)
2090 : : {
2091 [ # # ]: 0 : len = ( j == 2 ? MakeDecNumber : MakeAbcNumber )( p, ( int )sizeof( szValue ) - tot_len, NULL, nValue );
2092 : : }
2093 : : else
2094 : : {
2095 [ + + ]: 430 : if (j < 2)
2096 : : {
2097 [ + - + + : 215 : len = MakeDecNumber( p, ( int )sizeof( szValue ) - tot_len, tot_len ? "-" : ( i || bAddDelim ) ? ITEM_DELIMETER : NULL, nValue );
- + ]
2098 : : }
2099 : : else
2100 : : {
2101 [ + - ]: 215 : if (tot_len + 1 < ( int )sizeof( szValue ))
2102 : : {
2103 [ + - + - ]: 215 : *p++ = ( 0 <= nValue && nValue <= 4 ) ? parity_char[nValue] : parity_char[0];
2104 : 215 : *p = '\0';
2105 : 215 : len = 1;
2106 : : }
2107 : : else
2108 : : {
2109 : 0 : len = -1; /* Overflow */
2110 : : }
2111 : : }
2112 : : }
2113 [ - + ]: 430 : if (len < 0)
2114 : : {
2115 : 0 : bOvfl = 1;
2116 : 0 : break;
2117 : : }
2118 : 430 : p += len;
2119 : 430 : tot_len += len;
2120 : : }
2121 : :
2122 : 215 : inchi_strbuf_printf( strbuf, "%s", szValue );
2123 : : /*
2124 : : if ( nLen+tot_len < nLen_szLinearCT ) {
2125 : : memcpy( szLinearCT+nLen, szValue, tot_len+1 );
2126 : : nLen += tot_len;
2127 : : } else {
2128 : : bOvfl = 1;
2129 : : break;
2130 : : }*/
2131 : : }
2132 : : }
2133 : 59 : *bOverflow |= bOvfl;
2134 : :
2135 : 59 : nLen = strbuf->nUsedLength - nUsedLength0;
2136 : :
2137 : 59 : return nLen;
2138 : : }
2139 : :
2140 : : /**
2141 : : * @brief Compares two integers for qsort.
2142 : : *
2143 : : * @param a First integer pointer.
2144 : : * @param b Second integer pointer.
2145 : : * @return Returns negative, zero, or positive value based on comparison.
2146 : : */
2147 : 207 : int compare_ints(const void *a, const void *b) {
2148 : 207 : int arg1 = *(const int *)a;
2149 : 207 : int arg2 = *(const int *)b;
2150 : 207 : return (arg1 > arg2) - (arg1 < arg2);
2151 : : }
2152 : :
2153 : : /**
2154 : : * @brief Compares the third value of two integer arrays for qsort. Used to sort enhanced stereochemistry groups based on the canonical atom number of the first atom in the group.
2155 : : *
2156 : : * @param a First integer array pointer.
2157 : : * @param b Second integer array pointer.
2158 : : * @return Returns negative, zero, or positive value based on comparison.
2159 : : */
2160 : 113 : int compare_third_value(const void *a, const void *b) {
2161 : 113 : const int *arr1 = *(const int **)a;
2162 : 113 : const int *arr2 = *(const int **)b;
2163 : 113 : return arr1[2] - arr2[2];
2164 : : }
2165 : :
2166 : : /**
2167 : : * @brief Creates the enhanced stereochemistry string for the s - layer.
2168 : : *
2169 : : * @param pAux Pointer to the INCHI_AUX structure.
2170 : : * @param conf_stereo_string Pointer to the configuration stereochemistry string (abs, rel, rac).
2171 : : * @param enh_stereo Pointer to list of enhanced stereochemistry groups.
2172 : : * @param nof_stereo_groups Number of enhanced stereochemistry groups.
2173 : : * @param strbuf Pointer to the output string buffer.
2174 : : * @param nCtMode Mode flag for string representation.
2175 : : * @param bOverflow Pointer to overflow flag.
2176 : : * @return Returns the length of the created string.
2177 : : */
2178 : 138 : int MakeEnhStereoString( INChI_Aux *pAux,
2179 : : INCHI_IOS_STRING *strbuf,
2180 : : const char* conf_stereo_string,
2181 : : int **enh_stereo,
2182 : : int nof_stereo_groups,
2183 : : int nCtMode,
2184 : : int *bOverflow )
2185 : : {
2186 : 138 : int tot_len = 0;
2187 : 138 : int count_added = 0;
2188 : :
2189 [ - + ]: 138 : if (pAux == NULL) {
2190 : 0 : return 0;
2191 : : }
2192 : :
2193 [ + + ]: 138 : if (enh_stereo == NULL) {
2194 : 46 : return 0;
2195 : : }
2196 : :
2197 [ - + ]: 92 : if (nof_stereo_groups < 1) {
2198 : 0 : return 0;
2199 : : }
2200 : :
2201 : 92 : tot_len += MakeDelim( conf_stereo_string, strbuf, bOverflow );
2202 : :
2203 : 92 : int **enh_stereo_canon = (int**)inchi_calloc(nof_stereo_groups, sizeof(int*));
2204 : :
2205 : : // Converts the original atom numbers in the enhanced stereochemistry groups to canonical atom numbers
2206 : : // and sorts the atoms within each group based on their canonical atom numbers. This ensures that the order of
2207 : : // atoms in the string representation is consistent and does not depend on the order of atoms in the input data.
2208 : : // enh_stereo_canon is a 2D array where each row corresponds to an enhanced stereochemistry group. The first element
2209 : : // of each row (index 0) stores the number of atoms in the group, the second element (index 1) stores the count of found
2210 : : // atoms, and the remaining elements (starting from index 2) store the canonical atom numbers of the atoms in the group.
2211 [ + + ]: 267 : for (int i = 0; i < nof_stereo_groups; i++) {
2212 : 175 : const int *atom_numbers = &enh_stereo[i][2];
2213 : 175 : int count_found_atoms = 0;
2214 : 175 : int nof_atoms = enh_stereo[i][1];
2215 : :
2216 : 175 : enh_stereo_canon[i] = (int*)inchi_calloc(nof_atoms + 2, sizeof(int));
2217 : 175 : enh_stereo_canon[i][0] = nof_atoms;
2218 [ + + ]: 507 : for (int j = 0; j < nof_atoms; j++) {
2219 : :
2220 : 332 : int orig_atom_num = atom_numbers[j];
2221 : 332 : int canon_atom_num = get_canonical_atom_number(pAux, orig_atom_num);
2222 [ + + ]: 332 : if (canon_atom_num != -1) {
2223 : 163 : count_found_atoms++;
2224 : : } else {
2225 : 169 : canon_atom_num = INT_MAX;
2226 : : }
2227 : :
2228 : 332 : enh_stereo_canon[i][j + 2] = canon_atom_num;
2229 : : }
2230 : 175 : enh_stereo_canon[i][1] = count_found_atoms;
2231 : :
2232 [ + + ]: 175 : if (nof_atoms > 1) {
2233 : 92 : qsort(&enh_stereo_canon[i][2], nof_atoms, sizeof(int), compare_ints);
2234 : : }
2235 : : }
2236 : :
2237 : : // Sorts the enhanced stereochemistry groups based on the canonical atom number of the first atom in the group.
2238 : : // This ensures that the groups are always in a consistent order in the string representation, regardless of the
2239 : : // order they were added to the input data (e.g. AND1, AND2, ... or OR1, OR2, ...).
2240 : 92 : qsort(enh_stereo_canon, nof_stereo_groups, sizeof(int*), compare_third_value);
2241 : :
2242 : : // Creates the string for the stereo group based on the canonical atom numbers of the atoms in the group. If no
2243 : : // atoms were found for the group, it will not be added to the string.
2244 [ + + ]: 267 : for (int i = 0; i < nof_stereo_groups; i++) {
2245 : 175 : int nof_atoms = enh_stereo_canon[i][0];
2246 : 175 : int nof_found_atoms = enh_stereo_canon[i][1];
2247 : :
2248 [ + + ]: 175 : if (nof_found_atoms > 0) {
2249 : 114 : tot_len += MakeDelim( "(", strbuf, bOverflow );
2250 [ + + ]: 277 : for (int j = 0; j < nof_found_atoms; j++) {
2251 : 163 : tot_len += MakeNumber_EnhStereo( enh_stereo_canon[i][j + 2], "", strbuf, nCtMode, bOverflow );
2252 : 163 : count_added++;
2253 : :
2254 [ + + ]: 163 : if ((j + 1) < nof_found_atoms) {
2255 : 49 : tot_len += MakeDelim( ",", strbuf, bOverflow );
2256 : : }
2257 : : }
2258 : 114 : tot_len += MakeDelim( ")", strbuf, bOverflow );
2259 : : }
2260 : : }
2261 : :
2262 [ + + ]: 267 : for (int i = 0; i < nof_stereo_groups; i++) {
2263 [ + - ]: 175 : inchi_free(enh_stereo_canon[i]);
2264 : : }
2265 [ + - ]: 92 : inchi_free(enh_stereo_canon);
2266 : :
2267 : : // Removes the last value for the stereo group (1,2,3) if no atoms were added to the string
2268 [ + + ]: 92 : if (count_added == 0) {
2269 [ + - + - ]: 8 : if (strbuf && strbuf->nUsedLength > 0) {
2270 : 8 : strbuf->nUsedLength--;
2271 : 8 : strbuf->pStr[strbuf->nUsedLength] = '\0';
2272 : : }
2273 : :
2274 : 8 : tot_len = tot_len - 1;
2275 : : }
2276 : :
2277 : 92 : return tot_len;
2278 : : }
2279 : :
2280 : : /**
2281 : : * @brief Creates the string for the s - layer based on the enhanced stereochemistry information.
2282 : : *
2283 : : * @param orig_inp_data Pointer to the original atom data.
2284 : : * @param pINChISort Pointer to the INCHI_SORT structure.
2285 : : * @param bOutType Output type flag.
2286 : : * @param num_components Number of components in the molecule.
2287 : : * @param strbuf Pointer to the output string buffer.
2288 : : * @param nCtMode Mode flag for string representation.
2289 : : * @param bOverflow Pointer to overflow flag.
2290 : : * @return Returns the length of the created string.
2291 : : */
2292 : 36 : int MakeSlayerString( ORIG_ATOM_DATA *orig_inp_data,
2293 : : INCHI_SORT *pINChISort,
2294 : : INCHI_IOS_STRING *strbuf,
2295 : : int bOutType,
2296 : : int num_components,
2297 : : int nCtMode,
2298 : : int *bOverflow )
2299 : : {
2300 : :
2301 : 36 : int tot_len = 0;
2302 : : int ii;
2303 : :
2304 : 36 : const char* x_abs = "1";
2305 : 36 : const char* x_rel = "2";
2306 : 36 : const char* x_rac = "3";
2307 : :
2308 : 36 : const INCHI_SORT *is = NULL;
2309 : 36 : const INCHI_SORT *is0 = pINChISort;
2310 : :
2311 : : // INChI *pINChI = NULL;
2312 : 36 : INChI_Aux *pAux = NULL;
2313 : :
2314 : 36 : char **dictionary = (char**)inchi_calloc(ENH_STEREO_DICT_SIZE, sizeof(char*));
2315 : 36 : int *counts = (int*)inchi_calloc(ENH_STEREO_DICT_SIZE, sizeof(int));
2316 : :
2317 [ + + ]: 3636 : for (int i = 0; i < ENH_STEREO_DICT_SIZE; i++) {
2318 : 3600 : dictionary[i] = NULL;
2319 : 3600 : counts[i] = 0;
2320 : : }
2321 : :
2322 : 36 : INCHI_IOS_STRING tmpbuf = {0};
2323 : :
2324 [ + - + + ]: 82 : for (int cur_c = 0; !*bOverflow && cur_c < num_components; cur_c++)
2325 : : {
2326 : :
2327 : 46 : is = is0 + cur_c;
2328 : : // pINChI = ( 0 <= ( ii = GET_II( bOutType, is ) ) ) ? is->pINChI[ii] : NULL;
2329 [ - + - - : 46 : pAux = ( 0 <= ( ii = GET_II( bOutType, is ) ) ) ? is->pINChI_Aux[ii] : NULL;
- - - - -
- - - - -
+ - + - +
- - + - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
+ - ]
2330 : :
2331 : 46 : inchi_strbuf_init(&tmpbuf, INCHI_STRBUF_INITIAL_SIZE, INCHI_STRBUF_SIZE_INCREMENT);
2332 : :
2333 : : // s1
2334 : 92 : tot_len += MakeEnhStereoString( pAux,
2335 : : &tmpbuf,
2336 : : x_abs,
2337 : 46 : orig_inp_data->v3000->lists_steabs,
2338 : 46 : orig_inp_data->v3000->n_steabs,
2339 : : nCtMode,
2340 : : bOverflow);
2341 : :
2342 : : // s2
2343 : 92 : tot_len += MakeEnhStereoString( pAux,
2344 : : &tmpbuf,
2345 : : x_rel,
2346 : 46 : orig_inp_data->v3000->lists_sterel,
2347 : 46 : orig_inp_data->v3000->n_sterel,
2348 : : nCtMode,
2349 : : bOverflow);
2350 : :
2351 : : // s3
2352 : 92 : tot_len += MakeEnhStereoString( pAux,
2353 : : &tmpbuf,
2354 : : x_rac,
2355 : 46 : orig_inp_data->v3000->lists_sterac,
2356 : 46 : orig_inp_data->v3000->n_sterac,
2357 : : nCtMode,
2358 : : bOverflow);
2359 : :
2360 : 46 : int found = 0;
2361 [ + + ]: 4147 : for (int i = 0; i < ENH_STEREO_DICT_SIZE; i++) {
2362 [ + + + + ]: 4106 : if (dictionary[i] && strcmp(tmpbuf.pStr, dictionary[i]) == 0) {
2363 : 5 : counts[i]++;
2364 : 5 : found = 1;
2365 : 5 : break;
2366 : : }
2367 : : }
2368 [ + + ]: 46 : if (!found) {
2369 [ + - ]: 47 : for (int i = 0; i < ENH_STEREO_DICT_SIZE; i++) {
2370 [ + + ]: 47 : if (dictionary[i] == NULL) {
2371 : 41 : dictionary[i] = strdup(tmpbuf.pStr);
2372 : 41 : counts[i] = 1;
2373 : 41 : break;
2374 : : }
2375 : : }
2376 : : }
2377 : 46 : inchi_strbuf_close(&tmpbuf);
2378 : : }
2379 : :
2380 : : // String deduplication based on dictionary and counts
2381 : 36 : int count = 0;
2382 [ + + ]: 3636 : for (int i = 0; i < ENH_STEREO_DICT_SIZE; i++) {
2383 [ + + ]: 3600 : if (dictionary[i]) {
2384 [ + + ]: 41 : if (count > 0) {
2385 : 5 : tot_len += MakeDelim( ";", strbuf, bOverflow );
2386 : : }
2387 [ + + ]: 41 : if (counts[i] > 1) {
2388 : 5 : tot_len = inchi_strbuf_printf(strbuf, "%d*%s", counts[i], dictionary[i]);
2389 : : } else {
2390 : 36 : tot_len = inchi_strbuf_printf(strbuf, "%s", dictionary[i]);
2391 : : }
2392 [ + - ]: 41 : inchi_free(dictionary[i]);
2393 : 41 : count++;
2394 : : }
2395 : : }
2396 : :
2397 [ + - ]: 36 : inchi_free(dictionary);
2398 [ + - ]: 36 : inchi_free(counts);
2399 : :
2400 : 36 : return tot_len;
2401 : : }
2402 : :
2403 : : #ifdef ALPHA_BASE
2404 : : #if ( ALPHA_BASE != 27 )
2405 : : #error ALPHA_BASE definitions mismatch
2406 : : #endif
2407 : : #else
2408 : : #define ALPHA_BASE 27
2409 : : #endif
2410 : :
2411 : : #define ALPHA_MINUS '-'
2412 : : #define ALPHA_ZERO_VAL '.'
2413 : : #define ALPHA_ONE 'a'
2414 : : #define ALPHA_ZERO '@'
2415 : :
2416 : :
2417 : : /****************************************************************************
2418 : : MakeAbcNumber( ... )
2419 : :
2420 : : Produce an "Alphabetic" number, base 27 (27 digits: 0, a, b, ..., z)
2421 : : The leading "digit" uppercase, the rest -- lowercase
2422 : : szString length nStringLen includes 1 byte for zero termination
2423 : : Return Value: length without zero termination; -1 means not enough room
2424 : : Note: ASCII-encoding specific implementation
2425 : : ****************************************************************************/
2426 : 0 : int MakeAbcNumber( char *szString,
2427 : : int nStringLen,
2428 : : const char *szLeadingDelim,
2429 : : int nValue )
2430 : : {
2431 : 0 : char *p = szString;
2432 : : char *q;
2433 : : int nChar;
2434 : :
2435 [ # # ]: 0 : if (nStringLen < 2)
2436 : 0 : return -1;
2437 [ # # # # : 0 : while (szLeadingDelim && *szLeadingDelim && --nStringLen)
# # ]
2438 : : {
2439 : 0 : *p++ = *szLeadingDelim++;
2440 : : }
2441 [ # # ]: 0 : if (nStringLen < 2)
2442 : 0 : return -1;
2443 [ # # ]: 0 : if (!nValue)
2444 : : {
2445 : 0 : *p++ = ALPHA_ZERO_VAL; /* zero value (cannot use 0) */
2446 : 0 : *p = '\0';
2447 : 0 : return 1;
2448 : : }
2449 [ # # ]: 0 : if (nValue < 0)
2450 : : {
2451 : 0 : *p++ = ALPHA_MINUS;
2452 : 0 : nStringLen--;
2453 : 0 : nValue = -nValue;
2454 : : }
2455 [ # # # # ]: 0 : for (q = p; nValue && --nStringLen; nValue /= ALPHA_BASE)
2456 : : {
2457 [ # # ]: 0 : if ((nChar = nValue % ALPHA_BASE)) /* djb-rwth: addressing LLVM warning */
2458 : : {
2459 : 0 : nChar = ALPHA_ONE + nChar - 1;
2460 : : }
2461 : : else
2462 : : {
2463 : 0 : nChar = ALPHA_ZERO;
2464 : : }
2465 : 0 : *q++ = nChar;
2466 : : }
2467 [ # # ]: 0 : if (nStringLen <= 0)
2468 : 0 : return -1;
2469 : 0 : *q = '\0';
2470 : 0 : mystrrev( p );
2471 : 0 : p[0] = toupper( p[0] );
2472 : :
2473 : 0 : return (int) ( q - szString );
2474 : : }
2475 : :
2476 : :
2477 : : #if 1 /* ( READ_INCHI_STRING == 1 ) */
2478 : :
2479 : :
2480 : : static long abctol( const char *szString, char **q ); /* keep compiler happy */
2481 : :
2482 : :
2483 : : /****************************************************************************
2484 : : abctol( ... ) - analog of strtol() dealing with 'compressed InChI' input strings
2485 : : ****************************************************************************/
2486 : 0 : long abctol( const char *szString, char **q )
2487 : : {
2488 : : #define __MYTOLOWER(c) ( ((c) >= 'A') && ((c) <= 'Z') ? ((c) - 'A' + 'a') : (c) )
2489 : :
2490 : 0 : long val = 0;
2491 : : /* djb-rwth: removing redundant variables */
2492 : 0 : const char *p = szString, *pp = szString;
2493 : 0 : long treshold = ( LONG_MAX - 1 ) / ALPHA_BASE;
2494 : :
2495 [ # # ]: 0 : if (*p == ALPHA_MINUS)
2496 : : {
2497 : 0 : p++;
2498 : : /* djb-rwth: removing redundant code */
2499 : : }
2500 [ # # ]: 0 : if (*p == ALPHA_ZERO)
2501 : : {
2502 : 0 : p++;
2503 : 0 : goto exit_function;
2504 : : }
2505 [ # # ]: 0 : if (!isupper( UCINT *p ))
2506 : : {
2507 : 0 : p = szString;
2508 : 0 : goto exit_function; /* not an abc-number */
2509 : : }
2510 [ # # # # ]: 0 : val = __MYTOLOWER( *p ) - ALPHA_ONE + 1;
2511 : 0 : p++;
2512 [ # # ]: 0 : while (*p)
2513 : : {
2514 [ # # ]: 0 : if (islower( UCINT *p ))
2515 : : {
2516 : 0 : val *= ALPHA_BASE;
2517 : 0 : val += *p - ALPHA_ONE + 1;
2518 : : }
2519 : : else
2520 [ # # ]: 0 : if (*p == ALPHA_ZERO)
2521 : : {
2522 : : /*^^^ 1.06 */
2523 [ # # ]: 0 : if (val > treshold)
2524 : : {
2525 : 0 : p = pp;
2526 : 0 : val = 0;
2527 : 0 : goto exit_function;
2528 : : }
2529 : : else
2530 : : /* Software version 1.07 ^^^*/
2531 : 0 : val *= ALPHA_BASE; /* @1.06 fuzz testing caused overflow here! */
2532 : : }
2533 : : else
2534 : : {
2535 : 0 : break;
2536 : : }
2537 : 0 : p++;
2538 : : }
2539 : :
2540 : 0 : exit_function:
2541 [ # # ]: 0 : if (q)
2542 : : {
2543 : 0 : *q = (char *) p; /* cast deliberately discards const qualifier */
2544 : : }
2545 : :
2546 : 0 : return val;
2547 : : #undef __MYTOLOWER
2548 : : }
2549 : :
2550 : :
2551 : : /********************************************************/
2552 : 7 : long inchi_strtol(const char *str, const char **p, int base)
2553 : : {
2554 [ - + ]: 7 : if (base == ALPHA_BASE) {
2555 : 0 : return abctol(str, (char **)p); /* cast deliberately discards const qualifier */
2556 : : }
2557 : : else {
2558 : 7 : return strtol(str, (char **)p, base); /* cast deliberately discards const qualifier */
2559 : : }
2560 : : }
2561 : : #endif /* #if ( READ_INCHI_STRING == 1 ) */
2562 : :
2563 : : #undef ALPHA_BASE
2564 : : #undef ALPHA_MINUS
2565 : : #undef ALPHA_ZERO_VAL
2566 : : #undef ALPHA_ONE
2567 : : #undef ALPHA_ZERO
2568 : :
2569 : :
2570 : : /****************************************************************************/
2571 : 0 : double inchi_strtod(const char *str, const char **p)
2572 : : {
2573 : 0 : return strtod( str, (char **) p );
2574 : : }
2575 : :
2576 : :
2577 : : /****************************************************************************
2578 : : MakeDecNumber( ... )
2579 : :
2580 : : Produce a decimal number
2581 : :
2582 : : szString length nStringLen includes 1 byte for zero termination
2583 : : Return Value: length without zero termination; -1 means not enough room
2584 : : ****************************************************************************/
2585 : 2534 : int MakeDecNumber( char *szString,
2586 : : int nStringLen,
2587 : : const char *szLeadingDelim,
2588 : : int nValue )
2589 : : {
2590 : : #define DECIMAL_BASE 10
2591 : : #define DECIMAL_MINUS '-'
2592 : : #define DECIMAL_ZERO_VAL '0'
2593 : : #define DECIMAL_ONE '1'
2594 : : #define DECIMAL_ZERO '0'
2595 : :
2596 : 2534 : char *p = szString;
2597 : : char *q;
2598 : : int nChar;
2599 : :
2600 [ - + ]: 2534 : if (nStringLen < 2)
2601 : : {
2602 : 0 : return -1;
2603 : : }
2604 [ + + + + : 3873 : while (szLeadingDelim && *szLeadingDelim && --nStringLen)
+ - ]
2605 : : {
2606 : 1339 : *p++ = *szLeadingDelim++; /* djb-rwth: GCC 14 false positive */
2607 : : }
2608 [ - + ]: 2534 : if (nStringLen < 2)
2609 : : {
2610 : 0 : return -1;
2611 : : }
2612 [ - + ]: 2534 : if (!nValue)
2613 : : {
2614 : 0 : *p++ = DECIMAL_ZERO_VAL; /* zero value (cannot use 0) */
2615 : 0 : *p = '\0';
2616 : 0 : return (int) ( p - szString );
2617 : : }
2618 [ + + ]: 2534 : if (nValue < 0)
2619 : : {
2620 : 6 : *p++ = DECIMAL_MINUS;
2621 : 6 : nStringLen--;
2622 : 6 : nValue = -nValue;
2623 : : }
2624 [ + + + - ]: 5539 : for (q = p; nValue && --nStringLen; nValue /= DECIMAL_BASE)
2625 : : {
2626 [ + + ]: 3005 : if ((nChar = nValue % DECIMAL_BASE)) /* djb-rwth: addressing LLVM warning */
2627 : : {
2628 : 2915 : nChar = DECIMAL_ONE + nChar - 1;
2629 : : }
2630 : : else
2631 : : {
2632 : 90 : nChar = DECIMAL_ZERO;
2633 : : }
2634 : 3005 : *q++ = nChar;
2635 : : }
2636 [ - + ]: 2534 : if (nStringLen <= 0)
2637 : : {
2638 : 0 : return -1;
2639 : : }
2640 : 2534 : *q = '\0';
2641 : 2534 : mystrrev( p );
2642 : :
2643 : 2534 : return (int) ( q - szString );
2644 : :
2645 : : #undef DECIMAL_BASE
2646 : : #undef DECIMAL_MINUS
2647 : : #undef DECIMAL_ZERO_VAL
2648 : : #undef DECIMAL_ONE
2649 : : #undef DECIMAL_ZERO
2650 : : }
2651 : :
2652 : :
2653 : : /****************************************************************************
2654 : : Print out num[0..n-1] separated with commas
2655 : : For shortness, compress consecutive numbers (>2 members in a series)
2656 : : to a range:
2657 : : '1,2,5, 7-10' means 1,2,5,7,8,9,10'
2658 : : ****************************************************************************/
2659 : 4 : void print_sequence_of_nums_compressing_ranges( int n,
2660 : : int *num,
2661 : : INCHI_IOS_STRING *strbuf )
2662 : : {
2663 : : int k, range;
2664 : :
2665 : 4 : range = 0;
2666 [ + + ]: 12 : for (k = 0; k < n - 1; k++)
2667 : : {
2668 [ + + ]: 8 : if (num[k + 1] == num[k] + 1)
2669 : : {
2670 [ - + ]: 2 : if (range)
2671 : : {
2672 : 0 : range++;
2673 : : }
2674 : : else
2675 : : {
2676 : 2 : inchi_strbuf_printf( strbuf, "%d-", num[k] );
2677 : 2 : range = 1;
2678 : : }
2679 : : }
2680 : : else
2681 : : {
2682 [ + + ]: 6 : if (range)
2683 : : {
2684 : 2 : range = 0;
2685 : : }
2686 : 6 : inchi_strbuf_printf( strbuf, "%d,", num[k] );
2687 : : }
2688 : : }
2689 : 4 : inchi_strbuf_printf( strbuf, "%d", num[n - 1] );
2690 : :
2691 : 4 : return;
2692 : : }
|