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