Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : : #include <string.h>
42 : : #include <stdlib.h>
43 : : #include <ctype.h>
44 : :
45 : : #include "mode.h"
46 : :
47 : : #if defined(COMPILE_ANSI_ONLY) && defined(__APPLE__)
48 : : /* For build under OSX, advice from Burt Leland */
49 : : #include "ichicomp.h" /* Needed for __isascii define */
50 : : #endif
51 : :
52 : : /* djb-rwth: defining __isascii */
53 : : #if defined(__isascii)
54 : : #define is_ascii __isascii
55 : : #elif defined(isascii)
56 : : #define is_ascii isascii
57 : : #else
58 : : #define is_ascii(c) ((unsigned)(c) < 0x80)
59 : : #endif
60 : :
61 : : #include "util.h"
62 : : #include "eldata.h"
63 : : #include "extr_ct.h"
64 : :
65 : : #include "bcf_s.h"
66 : :
67 : :
68 : : /*
69 : : MISC. CHEMICAL-STRUCTURE RELATED UTILITIES AND HELPERS
70 : : */
71 : :
72 : :
73 : : /****************************************************************************
74 : : Finds chemical symbol for element of given number.
75 : : Returns 0 if OK and -1 if element was not found.
76 : : ****************************************************************************/
77 : 1514 : int get_element_chemical_symbol( int nAtNum, char *szElement )
78 : : {
79 : 1514 : nAtNum -= 1;
80 : :
81 [ + + ]: 1514 : if ( 0 < nAtNum )
82 : : {
83 : 1508 : nAtNum += 2; /* bypass D, T */
84 : : }
85 : :
86 [ + - + - ]: 1514 : if ( 0 <= nAtNum && nAtNum < nElDataLen )
87 : : {
88 : : /* valid element symbol found */
89 : 1514 : strcpy(szElement, ElData[nAtNum].szElName);
90 : 1514 : return 0;
91 : : }
92 : :
93 : : /* not found */
94 : 0 : strcpy(szElement, "??");
95 : 0 : return -1;
96 : : }
97 : :
98 : :
99 : : /****************************************************************************
100 : : Finds symbol for element of given number.
101 : : Accounts for (translates)pseudoelements.
102 : : Returns 0 if OK and -1 if element was not found.
103 : : ****************************************************************************/
104 : 465 : int get_element_or_pseudoelement_symbol( int nAtNum,
105 : : char *szElement )
106 : : {
107 : 465 : nAtNum -= 1;
108 : :
109 [ + + ]: 465 : if ( 0 < nAtNum )
110 : : {
111 : 459 : nAtNum += 2; /* bypass D, T */
112 : : }
113 : :
114 [ + - + - ]: 465 : if ( 0 <= nAtNum && nAtNum < nElDataLen )
115 : : {
116 : : /* valid element symbol found */
117 : 465 : strcpy(szElement, ElData[nAtNum].szElName);
118 : :
119 [ - + ]: 465 : if (!strcmp( szElement, "Zy" ))
120 : : {
121 : 0 : strcpy(szElement, "Zz");
122 : : }
123 : :
124 : 465 : return 0;
125 : : }
126 : :
127 : : /* not found */
128 : 0 : strcpy(szElement, "??");
129 : :
130 : 0 : return -1;
131 : : }
132 : :
133 : :
134 : : /****************************************************************************/
135 : 2667 : int el_number_in_internal_ref_table( const char* elname )
136 : : {
137 : : int i;
138 : : const char* p;
139 : :
140 [ + - + + ]: 36184 : for (i = 0; ( p = ElData[i].szElName )[0] && strcmp( p, elname ); i++)
141 : : {
142 : : ;
143 : : }
144 : :
145 [ + - ]: 2667 : return p[0] ? i : ERR_ELEM;
146 : : }
147 : :
148 : :
149 : : /****************************************************************************
150 : : Get element number by symbol
151 : : ****************************************************************************/
152 : 1616 : int get_periodic_table_number( const char* elname )
153 : : {
154 : : int num;
155 : :
156 [ - + ]: 1616 : if (elname == NULL)
157 : : {
158 : 0 : return ERR_ELEM;
159 : : }
160 : :
161 [ - + ]: 1616 : if (strlen(elname) == 0)
162 : : {
163 : 0 : return ERR_ELEM;
164 : : }
165 : :
166 : : /* the single letter (common) elements */
167 [ + + ]: 1616 : if (!elname[1])
168 : : {
169 [ + + + + : 1274 : switch (elname[0])
+ + + + +
+ ]
170 : : {
171 : 11 : case 'H':
172 : 11 : return EL_NUMBER_H;
173 : : break;
174 : 2 : case 'B':
175 : 2 : return EL_NUMBER_B;
176 : : break;
177 : 940 : case 'C':
178 : 940 : return EL_NUMBER_C;
179 : : break;
180 : 36 : case 'N':
181 : 36 : return EL_NUMBER_N;
182 : : break;
183 : 244 : case 'O':
184 : 244 : return EL_NUMBER_O;
185 : : break;
186 : 2 : case 'P':
187 : 2 : return EL_NUMBER_P;
188 : : break;
189 : 6 : case 'S':
190 : 6 : return EL_NUMBER_S;
191 : : break;
192 : 22 : case 'F':
193 : 22 : return EL_NUMBER_F;
194 : : break;
195 : 2 : case 'I':
196 : 2 : return EL_NUMBER_I;
197 : : break;
198 : : }
199 : : }
200 : :
201 : 351 : num = el_number_in_internal_ref_table( elname );
202 : :
203 [ + - ]: 351 : if ( num < ERR_ELEM )
204 : : {
205 : : /* account for D,T in internal table (but not Mendeleev's table) */
206 : 351 : num = inchi_max( 1, num - 1 );
207 : : }
208 : :
209 : 351 : return num;
210 : : }
211 : :
212 : :
213 : : /****************************************************************************
214 : : Check if no H addition allowed
215 : : ****************************************************************************/
216 : 1574 : int if_skip_add_H( int nPeriodicNum )
217 : : /* was called if_skip_add_H(, renamed to avoid confusion with other procedures */
218 : : {
219 : : return
220 [ + + ]: 1574 : ElData[nPeriodicNum > 1 ? nPeriodicNum + 1 : 0].bSkipAddingH;
221 : : }
222 : :
223 : :
224 : : /****************************************************************************
225 : : Get reference value of atom valence at given charge
226 : : ****************************************************************************/
227 : 18120 : int get_el_valence( int nPeriodicNum, int charge, int val_num )
228 : : {
229 [ + + ]: 18120 : int idx = ( nPeriodicNum > 1 ) ? nPeriodicNum + 1 : 0;
230 : :
231 : : /* Bounds-check every index before touching ElData[].cValence[][].
232 : : * The original code guarded only the upper bound of val_num and the
233 : : * charge range; a negative nPeriodicNum/val_num or an element number
234 : : * beyond the table would read out of bounds. Return 0 (no known
235 : : * valence) for any out-of-range input. */
236 [ + - + - : 18120 : if ( nPeriodicNum < 0 || idx > nElDataLen ||
+ - ]
237 [ + - + - ]: 18120 : val_num < 0 || val_num >= MAX_NUM_VALENCES ||
238 [ - + ]: 18120 : charge < MIN_ATOM_CHARGE || charge > MAX_ATOM_CHARGE )
239 : : {
240 : 0 : return 0;
241 : : }
242 : :
243 : 18120 : return ElData[idx].cValence[NEUTRAL_STATE + charge][val_num];
244 : : }
245 : :
246 : :
247 : : /****************************************************************************
248 : : Output valence needed to unambiguosly reconstruct bonds
249 : : ****************************************************************************/
250 : 750 : int get_unusual_el_valence( int nPeriodicNum,
251 : : int charge,
252 : : int radical,
253 : : int bonds_valence,
254 : : int num_H,
255 : : int num_bonds )
256 : : {
257 : : int i, num_found, chem_valence, rad_adj, known_chem_valence, exact_found;
258 : :
259 [ + + - + ]: 750 : if ( !num_bonds && !num_H )
260 : : {
261 : 0 : return 0;
262 : : }
263 : :
264 [ + - - + ]: 750 : if ( charge < MIN_ATOM_CHARGE || charge > MAX_ATOM_CHARGE )
265 : : {
266 [ # # ]: 0 : if ( bonds_valence == num_bonds )
267 : : {
268 : 0 : return 0; /* all single bonds */
269 : : }
270 : 0 : return bonds_valence;
271 : : }
272 : :
273 [ + + + - ]: 750 : if (!get_el_valence( nPeriodicNum, charge, 0 ) && bonds_valence == num_bonds)
274 : : {
275 : 2 : return 0;
276 : : }
277 : :
278 : 748 : chem_valence = bonds_valence + num_H;
279 : 748 : rad_adj = 0;
280 : 748 : num_found = 0;
281 : 748 : exact_found = 0;
282 : :
283 : : /* Take into account a radical */
284 [ - + ]: 748 : if ( radical == RADICAL_DOUBLET )
285 : : {
286 : 0 : rad_adj = 1;
287 : : }
288 [ - + ]: 748 : else if ( radical == RADICAL_TRIPLET )
289 : : {
290 : 0 : rad_adj = 2;
291 : : }
292 : :
293 [ + + ]: 791 : for ( i = 0; i < MAX_NUM_VALENCES; i++ )
294 : : {
295 [ + + + + ]: 785 : if (0 < ( known_chem_valence = get_el_valence( nPeriodicNum, charge, i ) - rad_adj ) &&
296 [ + + ]: 751 : num_bonds <= known_chem_valence && known_chem_valence <= chem_valence)
297 : : {
298 : 749 : num_found++;
299 [ + + ]: 749 : if ( known_chem_valence == chem_valence )
300 : : {
301 : 742 : exact_found = 1;
302 : 742 : break;
303 : : }
304 : : }
305 : : }
306 : :
307 [ + + + + ]: 748 : return ( exact_found && 1 == num_found ) ? 0 : chem_valence;
308 : : }
309 : :
310 : :
311 : : /****************************************************************************
312 : : Output valence needed to unambiguosly reconstruct number of H
313 : : ****************************************************************************/
314 : 1614 : int needed_unusual_el_valence( int nPeriodicNum,
315 : : int charge,
316 : : int radical,
317 : : int bonds_valence,
318 : : int actual_bonds_valence,
319 : : int num_H, int
320 : : num_bonds )
321 : : {
322 : : int chem_valence, num_H_expected; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
323 : : char szElement[4];
324 : :
325 : : /*
326 : : if ( !num_bonds && !num_H )
327 : : return 0;
328 : : */
329 : :
330 [ + + + - ]: 1614 : if (num_bonds && get_element_chemical_symbol( nPeriodicNum, szElement ) != -1)
331 : : {
332 : 1514 : num_H_expected = get_num_H( szElement, 0, NULL, charge, radical, actual_bonds_valence, 0, 0, 0, 0 );
333 : : }
334 : : else
335 : : {
336 : 100 : num_H_expected = num_H;
337 : : }
338 : :
339 : 1614 : chem_valence = bonds_valence + num_H;
340 : :
341 : : #if ( (BUILD_WITH_ENG_OPTIONS==1) && (SDF_OUTPUT_HETERO_VALENCE==1) )
342 : : if ((nPeriodicNum == 1 && chem_valence != 1) /* H */ || (nPeriodicNum == 6 && chem_valence != 4) /* C */ ||
343 : : (nPeriodicNum != 1 && nPeriodicNum != 6) || charge || radical) /* djb-rwth: addressing LLVM warning */
344 : : {
345 : : return chem_valence ? chem_valence : -1;
346 : : }
347 : : else
348 : : {
349 : : return 0;
350 : : }
351 : : #else
352 : : {
353 : : int i, num_found, num_found_known, rad_adj, known_chem_valence, exact_found;
354 : :
355 [ + - + - : 3228 : if (charge < MIN_ATOM_CHARGE || charge > MAX_ATOM_CHARGE ||
+ + ]
356 [ + + ]: 3188 : !get_el_valence( nPeriodicNum, charge, 0 ) ||
357 [ + + + + ]: 3060 : if_skip_add_H( nPeriodicNum ) || bonds_valence != actual_bonds_valence ||
358 : : num_H_expected != num_H)
359 : : {
360 [ + + + + : 170 : if ( !num_H && !num_H_expected && bonds_valence == actual_bonds_valence )
+ + ]
361 : : {
362 : 96 : return 0; /* no H */
363 : : }
364 : 74 : return chem_valence; /* needs to add H-atoms */
365 : : }
366 : :
367 : : /* take into account radical */
368 [ - + ]: 1444 : if ( radical == RADICAL_DOUBLET )
369 : : {
370 : 0 : rad_adj = 1;
371 : : }
372 [ - + ]: 1444 : else if ( radical == RADICAL_TRIPLET )
373 : : {
374 : 0 : rad_adj = 2;
375 : : }
376 : : else
377 : : {
378 : 1444 : rad_adj = 0;
379 : : }
380 : :
381 : 1444 : num_found_known = 0;
382 : 1444 : num_found = 0;
383 : 1444 : exact_found = 0;
384 : :
385 [ + - ]: 1452 : for ( i = 0; i < MAX_NUM_VALENCES; i++ )
386 : : {
387 [ + - ]: 1452 : if (0 < ( known_chem_valence = get_el_valence( nPeriodicNum, charge, i ) ) &&
388 [ + + ]: 1452 : bonds_valence <= ( known_chem_valence -= rad_adj ))
389 : : {
390 : : /* found known valence that fits without H */
391 : 1444 : num_found_known++;
392 [ + - ]: 1444 : if ( known_chem_valence <= chem_valence )
393 : : {
394 : : /* known valence is large enough to accommodate (implicit) H */
395 : 1444 : num_found++;
396 : : }
397 [ + - ]: 1444 : if ( known_chem_valence == chem_valence )
398 : : {
399 : 1444 : exact_found = 1;
400 : 1444 : break;
401 : : }
402 : : }
403 : : }
404 : :
405 [ + - - + ]: 1444 : return ( exact_found && 1 == num_found && 1 == num_found_known )
406 : : ? 0
407 [ + - - - ]: 2888 : : chem_valence ? chem_valence : -1; /* needs zero */
408 : : }
409 : : #endif
410 : : }
411 : :
412 : :
413 : : /****************************************************************************
414 : : Output valence that does not fit any known valences
415 : : ****************************************************************************/
416 : 4686 : int detect_unusual_el_valence( int nPeriodicNum,
417 : : int charge,
418 : : int radical,
419 : : int bonds_valence,
420 : : int num_H,
421 : : int num_bonds )
422 : : {
423 : : int i, chem_valence, rad_adj, known_chem_valence;
424 : :
425 [ + + + + ]: 4686 : if ( !num_bonds && !num_H )
426 : : {
427 : 65 : return 0;
428 : : }
429 : :
430 [ + - - + ]: 4621 : if ( charge < MIN_ATOM_CHARGE || charge > MAX_ATOM_CHARGE )
431 : : {
432 [ # # ]: 0 : if ( bonds_valence == num_bonds )
433 : : {
434 : 0 : return 0; /* all single bonds */
435 : : }
436 : 0 : return bonds_valence;
437 : : }
438 : :
439 [ + + + - ]: 4621 : if (!get_el_valence( nPeriodicNum, charge, 0 ) && bonds_valence == num_bonds)
440 : : {
441 : 5 : return 0;
442 : : }
443 : :
444 : 4616 : chem_valence = bonds_valence + num_H;
445 : 4616 : rad_adj = 0;
446 : :
447 : : /* take into account radical */
448 [ - + ]: 4616 : if ( radical == RADICAL_DOUBLET )
449 : : {
450 : 0 : rad_adj = 1;
451 : : }
452 [ + - - + ]: 4616 : else if ( radical == RADICAL_TRIPLET || radical == RADICAL_SINGLET )
453 : : {
454 : 0 : rad_adj = 2;
455 : : }
456 : :
457 [ + + ]: 4870 : for ( i = 0; i < MAX_NUM_VALENCES; i++ )
458 : : {
459 [ + + ]: 4839 : if (0 < ( known_chem_valence = get_el_valence( nPeriodicNum, charge, i ) - rad_adj ))
460 : : {
461 [ + + ]: 4718 : if ( known_chem_valence == chem_valence )
462 : : {
463 : 4585 : return 0;
464 : : }
465 : : }
466 : : }
467 : :
468 : 31 : return chem_valence;
469 : : }
470 : :
471 : :
472 : : /****************************************************************************
473 : : Return element type
474 : : ****************************************************************************/
475 : 2005 : int get_el_type( int nPeriodicNum )
476 : : {
477 : 2005 : return ElData[nPeriodicNum + 1].nType;
478 : : }
479 : :
480 : :
481 : : /****************************************************************************
482 : : Check if element is metal
483 : : ****************************************************************************/
484 : 8424 : int is_el_a_metal( int nPeriodicNum )
485 : : {
486 : 8424 : return 0 != ( ElData[nPeriodicNum + 1].nType & IS_METAL );
487 : : }
488 : :
489 : :
490 : : /*#ifndef TARGET_API_LIB*/
491 : :
492 : :
493 : : /****************************************************************************
494 : : Extract radicals and charges
495 : : ****************************************************************************/
496 : 0 : int extract_charges_and_radicals( char *elname, int *pnRadical, int *pnCharge )
497 : : {
498 : : char *q, *r, *p;
499 : 0 : int nCharge = 0, nRad = 0, charge_len = 0, k, nVal, nSign, nLastSign = 1; /* djb-rwth: removing redundant variables */
500 : :
501 : 0 : p = elname;
502 : :
503 : : /* extract radicals & charges */
504 [ # # ]: 0 : while ( (q = strpbrk(p, "+-^")) ) /* djb-rwth: addressing LLVM warning */
505 : : {
506 [ # # # ]: 0 : switch ( *q )
507 : : {
508 : 0 : case '+':
509 : : case '-':
510 [ # # # # ]: 0 : for (k = 0, nVal = 0; ( nSign = ( '+' == q[k] ) ) || ( nSign = -( '-' == q[k] ) ); k++)
511 : : {
512 : 0 : nVal += ( nLastSign = nSign );
513 : 0 : charge_len++;
514 : : }
515 [ # # ]: 0 : if ((nSign = (int)strtol(q + k, &r, 10))) /* djb-rwth: addressing LLVM warning */
516 : : {
517 : : /* fixed 12-5-2001 */
518 : 0 : nVal += nLastSign * ( nSign - 1 );
519 : : }
520 : 0 : charge_len = (int) ( r - q );
521 : 0 : nCharge += nVal;
522 : 0 : break;
523 : : /* case '.': */ /* singlet '.' may be confused with '.' in formulas like CaO.H2O */
524 : 0 : case '^':
525 : 0 : nRad = 1; /* doublet here is 1. See below */
526 : 0 : charge_len = 1;
527 [ # # ]: 0 : for (k = 1; q[0] == q[k]; k++)
528 : : {
529 : 0 : nRad++;
530 : 0 : charge_len++;
531 : : }
532 : 0 : break;
533 : : }
534 : 0 : memmove(q, q + charge_len, strlen(q + charge_len) + 1);
535 : : }
536 : :
537 : : /* djb-rwth: removing redundant code */
538 : :
539 : : /* radical */
540 [ # # # # ]: 0 : if (( q = strrchr( p, ':' ) ) && !q[1])
541 : : {
542 : 0 : nRad = RADICAL_SINGLET;
543 : 0 : q[0] = '\0';
544 : : /* djb-rwth: removing redundant code */
545 : : }
546 : : else
547 : : {
548 [ # # # # ]: 0 : while (( q = strrchr( p, '.' ) ) && !q[1])
549 : : {
550 : 0 : nRad++;
551 : 0 : q[0] = '\0';
552 : : /* djb-rwth: removing redundant code */
553 : : }
554 : :
555 [ # # ]: 0 : nRad = nRad == 1 ? RADICAL_DOUBLET :
556 [ # # ]: 0 : nRad == 2 ? RADICAL_TRIPLET : 0;
557 : : }
558 : :
559 : 0 : *pnRadical = nRad;
560 : 0 : *pnCharge = nCharge;
561 : :
562 [ # # # # ]: 0 : return ( nRad || nCharge );
563 : : }
564 : :
565 : :
566 : : /*#endif*/
567 : :
568 : :
569 : : /****************************************************************************/
570 : 0 : int extract_H_atoms( char *elname, S_CHAR num_iso_H[] )
571 : : {
572 : : int i, len, c, k, num_H, val;
573 : : char* q;
574 : 0 : char elname1 = '\0';
575 : :
576 : 0 : i = 0;
577 : 0 : num_H = 0;
578 : 0 : len = (int) strlen( elname );
579 : 0 : c = UCINT elname[0];
580 : :
581 [ # # ]: 0 : if ( len > 1 )
582 : : {
583 : 0 : elname1 = elname[1];
584 : : }
585 : :
586 [ # # ]: 0 : while ( i < len )
587 : : {
588 [ # # # # ]: 0 : switch ( c )
589 : : {
590 : 0 : case 'H':
591 : 0 : k = 0;
592 : 0 : break;
593 : 0 : case 'D':
594 : 0 : k = 1;
595 : 0 : break;
596 : 0 : case 'T':
597 : 0 : k = 2;
598 : 0 : break;
599 : 0 : default:
600 : 0 : k = -1;
601 : 0 : break;
602 : : }
603 : :
604 : 0 : q = elname + i + 1; /* pointer to the next to elname[i] character */
605 : 0 : c = UCINT q[0];
606 : :
607 [ # # # # ]: 0 : if (k >= 0 && !islower( c ))
608 : : {
609 : : /* found a hydrogen */
610 [ # # ]: 0 : if (isdigit( c ))
611 : : {
612 : 0 : val = (int) strtol( q, &q, 10 );
613 : : /* q = pointer to the next to number of hydrogen atom(s) character */
614 : : }
615 : : else
616 : : {
617 : 0 : val = 1;
618 : : }
619 [ # # ]: 0 : if ( k )
620 : : {
621 : 0 : num_iso_H[k] += val;
622 : : }
623 : : else
624 : : {
625 : 0 : num_H += val;
626 : : }
627 : :
628 : : /* remove the hydrogen atom from the string */
629 : 0 : len -= (int) ( q - elname ) - i;
630 : 0 : memmove(elname + i, q, (long long)len + 1); /* djb-rwth: cast operator added */
631 : : /* c = UCINT elname[i]; */
632 : : }
633 : : else
634 : : {
635 : 0 : i++;
636 : : }
637 : :
638 : 0 : c = UCINT elname[i]; /* moved here 11-04-2002 */
639 : : }
640 : :
641 : 0 : len = (int) strlen( elname );
642 [ # # ]: 0 : if (len == 2)
643 : : {
644 [ # # ]: 0 : if ( elname[1] != elname1 )
645 : : /* Error, incorrect 2nd char of elname appears after 'subtracting' {H,D,T} */
646 : : /* See a bug reported to inchi-discuss by A. Dalke for alias atom "pH4d" */
647 : : /*^^^ 2017-01-06 */
648 : 0 : elname[1] = '?';
649 : : }
650 : :
651 : 0 : return num_H;
652 : : }
653 : :
654 : :
655 : : /****************************************************************************
656 : : Return number of attached hydrogens
657 : : ****************************************************************************/
658 : 2316 : int get_num_H( const char* elname,
659 : : int inp_num_H,
660 : : S_CHAR inp_num_iso_H[],
661 : : int charge,
662 : : int radical,
663 : : int chem_bonds_valence,
664 : : int atom_input_valence,
665 : : int bAliased,
666 : : int bDoNotAddH,
667 : : int bHasMetalNeighbor )
668 : : {
669 : 2316 : int val, i, el_number, num_H = 0, num_iso_H;
670 : : static int intl_el_number_N = 0, intl_el_number_S=0, intl_el_number_O=0, intl_el_number_C=0;
671 : :
672 [ + + ]: 2316 : if ( !intl_el_number_N )
673 : : {
674 : 6 : intl_el_number_N = el_number_in_internal_ref_table( "N" );
675 : : }
676 [ + + ]: 2316 : if ( !intl_el_number_S )
677 : : {
678 : 6 : intl_el_number_S = el_number_in_internal_ref_table( "S" );
679 : : }
680 [ + + ]: 2316 : if ( !intl_el_number_O )
681 : : {
682 : 6 : intl_el_number_O = el_number_in_internal_ref_table( "O" );
683 : : }
684 [ + + ]: 2316 : if ( !intl_el_number_C )
685 : : {
686 : 6 : intl_el_number_C = el_number_in_internal_ref_table( "C" );
687 : : }
688 : :
689 : :
690 : : /* atom_input_valence (cValence) cannot be specified in case of */
691 : : /* aliased MOLFile atom with known inp_num_H or inp_num_iso_H[] */
692 : :
693 [ - + ]: 2316 : if ( bAliased )
694 : : {
695 : 0 : num_H = inp_num_H;
696 : : }
697 [ + + + - ]: 2316 : else if (atom_input_valence && atom_input_valence != 15)
698 : : {
699 : 24 : num_H = inchi_max( 0, atom_input_valence - chem_bonds_valence );
700 : : }
701 [ - + ]: 2292 : else if ( atom_input_valence == 15 )
702 : : {
703 : : /* Explicit zero valence (V3000 VAL=-1 / V2000 valence field 15): the */
704 : : /* atom must carry neither implicit H nor (chemically) any bonds. Honour */
705 : : /* the zero valence regardless of whether bonds were drawn, instead of */
706 : : /* treating 15 as a literal target valence and adding 15 - chem_bonds_valence */
707 : : /* hydrogens (github #105). */
708 : 0 : num_H = 0;
709 : : }
710 [ + - + - ]: 2292 : else if (MIN_ATOM_CHARGE <= charge &&
711 : 2292 : MAX_ATOM_CHARGE >= charge &&
712 [ + - ]: 2292 : ERR_ELEM != ( el_number = el_number_in_internal_ref_table( elname ) ) &&
713 [ + + + + ]: 2292 : !ElData[el_number].bSkipAddingH && !bDoNotAddH)
714 : : {
715 : : /* add hydrogen atoms according to standard element valence */
716 [ - + - - ]: 2175 : if ( radical && radical != RADICAL_SINGLET )
717 : : {
718 [ # # ]: 0 : if ( (val = ElData[el_number].cValence[NEUTRAL_STATE + charge][0]) ) /* djb-rwth: addressing LLVM warning */
719 : : {
720 : 0 : val -= ( radical == RADICAL_DOUBLET ) ? 1
721 [ # # # # : 0 : : ( radical == RADICAL_SINGLET || radical == RADICAL_TRIPLET ) ? 2 : val;
# # ]
722 : : /* if unknown radical then do not add H */
723 : 0 : num_H = inchi_max( 0, val - chem_bonds_valence );
724 : : }
725 : : }
726 : : else
727 : : {
728 : : /* find the smallest valence that is greater than the sum of the chemical bond valences */
729 : 2175 : for (i = 0;
730 [ + + + + ]: 2187 : ( val = ElData[el_number].cValence[NEUTRAL_STATE + charge][i] ) &&
731 : : val < chem_bonds_valence;
732 : 12 : i++)
733 : : {
734 : : ;
735 : : }
736 : :
737 : : /* special case: do not add H to N(IV), S(III), S+(II), S-(II) */ /* S ions added 2004-05-10 */
738 [ + + + - : 2175 : if ( el_number == intl_el_number_N && !charge && !radical && val == 5 )
+ - - + ]
739 : : {
740 : 0 : val = 3;
741 : : }
742 : : /*else if ( el_number == el_number_N && !charge && !radical && val == 3 &&
743 : : chem_bonds_valence == 2 && bHasMetalNeighbor )
744 : : {
745 : : val = 2;
746 : : }
747 : : */
748 [ + + + - : 2175 : else if ( el_number == intl_el_number_S && !charge && !radical && val == 4 && chem_bonds_valence == 3 )
+ - - + -
- ]
749 : : {
750 : 0 : val = 3;
751 : : }
752 [ - + - - : 2175 : else if ( bHasMetalNeighbor && el_number != intl_el_number_C && val > 0 )
- - ]
753 : : {
754 : 0 : val--;
755 : : }
756 : : /*
757 : : if ( (el_number == el_number_S || el_number == el_number_O) &&
758 : : abs(charge)==1 && !radical && val == 3 && chem_bonds_valence == 2 && bHasMetalNeighbor )
759 : : {
760 : : val = 2;
761 : : }
762 : : else
763 : : */
764 : :
765 : 2175 : num_H = inchi_max( 0, val - chem_bonds_valence );
766 : : }
767 : :
768 : 2175 : num_iso_H = 0;
769 [ + + ]: 2175 : if ( inp_num_iso_H )
770 : : {
771 [ + + ]: 2868 : for ( i = 0; i < NUM_H_ISOTOPES; i++ )
772 : : {
773 : 2151 : num_iso_H += inp_num_iso_H[i];
774 : : }
775 : : }
776 : :
777 : : /* should not happen because atom here is not aliased */
778 [ - + ]: 2175 : if ( num_iso_H )
779 : : {
780 [ # # ]: 0 : if ( num_H >= num_iso_H )
781 : : {
782 : 0 : num_H -= num_iso_H;
783 : : }
784 : : else
785 : : {
786 : 0 : num_H = inp_num_H; /* as requested in the alias */
787 : : /* num_H = (num_iso_H - num_H) % 2; */ /* keep unchanged parity of the total number of H atoms */
788 : : }
789 : : }
790 : :
791 : : /* should not happen because atom here is not aliased */
792 [ - + ]: 2175 : if ( inp_num_H > num_H )
793 : : {
794 : 0 : num_H = inp_num_H; /* as requested in the alias */
795 : : /* num_H = inp_num_H + (inp_num_H - num_H)%2; */ /* keep unchanged parity of the number of non-isotopic H atoms */
796 : : }
797 : : }
798 : : else
799 : : {
800 : 117 : num_H = inp_num_H;
801 : : }
802 : :
803 : 2316 : return num_H;
804 : : }
805 : :
806 : :
807 : : /****************************************************************************/
808 : 0 : int get_atomic_mass_from_elnum( int nAtNum )
809 : : {
810 : 0 : nAtNum -= 1;
811 : :
812 [ # # ]: 0 : if ( 0 < nAtNum )
813 : : {
814 : 0 : nAtNum += 2; /* bypass D, T */
815 : : }
816 : :
817 [ # # # # ]: 0 : if ( 0 <= nAtNum && nAtNum < nElDataLen )
818 : : {
819 : 0 : return (int) ElData[nAtNum].nAtMass;
820 : : }
821 : :
822 : 0 : return 0;
823 : : }
824 : :
825 : :
826 : : /****************************************************************************
827 : : int get_mw(char elname[])
828 : : {
829 : : int i;
830 : :
831 : : for (i=0; i<NUMEL; i++)
832 : : if (strcmp(elname,elements[i])==0)
833 : : return(atomic_wt[i]);
834 : : return(0);
835 : : }
836 : : ****************************************************************************/
837 : :
838 : :
839 : :
840 : : /****************************************************************************/
841 : 0 : int get_atomic_mass( const char *elname )
842 : : {
843 : : int el_number, atw;
844 [ # # ]: 0 : if (ERR_ELEM != ( el_number = el_number_in_internal_ref_table( elname ) ))
845 : : {
846 : 0 : atw = ElData[el_number].nAtMass;
847 : : }
848 : : else
849 : : {
850 : 0 : atw = 0;
851 : : }
852 : :
853 : 0 : return atw;
854 : : }
855 : :
856 : :
857 : : /****************************************************************************
858 : : Check if atom is in the list
859 : : ****************************************************************************/
860 : 2840 : AT_NUMB *is_in_the_list( AT_NUMB *pathAtom, AT_NUMB nNextAtom, int nPathLen )
861 : : {
862 [ + + + + ]: 5572 : for ( ; nPathLen && *pathAtom != nNextAtom; nPathLen--, pathAtom++ )
863 : : {
864 : : ;
865 : : }
866 [ + + ]: 2840 : return nPathLen ? pathAtom : NULL;
867 : : }
868 : :
869 : : /****************************************************************************
870 : : Check if integer is in the list
871 : : ****************************************************************************/
872 : 44 : int *is_in_the_ilist( int *pathAtom, int nNextAtom, int nPathLen )
873 : : {
874 [ + + + + ]: 108 : for ( ; nPathLen && *pathAtom != nNextAtom; nPathLen--, pathAtom++ )
875 : : {
876 : : ;
877 : : }
878 [ + + ]: 44 : return nPathLen ? pathAtom : NULL;
879 : : }
880 : :
881 : :
882 : : /****************************************************************************
883 : : Check if list (of integers) is within the embedding list2
884 : : ****************************************************************************/
885 : 0 : int is_ilist_inside( int *ilist, int nlist, int *ilist2, int nlist2 )
886 : : {
887 : : int k;
888 [ # # ]: 0 : for ( k = 0; k < nlist; k++ )
889 : : {
890 [ # # ]: 0 : if (!is_in_the_ilist( ilist2, ilist[k], nlist2 ))
891 : : {
892 : 0 : return 0;
893 : : }
894 : : }
895 : 0 : return 1;
896 : : }
897 : :
898 : :
899 : : /****************************************************************************/
900 : 0 : int nBondsValToMetal( inp_ATOM* at, int iat )
901 : : {
902 : 0 : int i, bond_type, nVal2Metal = 0; /* djb-rwth: removing redundant variables */
903 : 0 : inp_ATOM* a = at + iat;
904 : :
905 [ # # ]: 0 : for ( i = 0; i < a->valence; i++ )
906 : : {
907 : : /* djb-rwth: removing redundant code */
908 : :
909 [ # # ]: 0 : if (is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
910 : : {
911 : 0 : bond_type = a->bond_type[i];
912 : :
913 [ # # ]: 0 : if ( bond_type <= BOND_TYPE_TRIPLE )
914 : : {
915 : 0 : nVal2Metal += bond_type;
916 : : }
917 : : else
918 : : {
919 : 0 : return -1; /* bond to metal order is not well defined */
920 : : }
921 : : }
922 : : }
923 : :
924 : 0 : return nVal2Metal;
925 : : }
926 : :
927 : :
928 : : /****************************************************************************/
929 : 134 : int num_of_H( inp_ATOM *at, int iat )
930 : : {
931 : : static int el_number_H = (int)EL_NUMBER_H;
932 : 134 : int i, n, num_explicit_H = 0;
933 : 134 : inp_ATOM *a = at + iat;
934 : :
935 [ + + ]: 298 : for (i = 0; i < a->valence; i++)
936 : : {
937 : 164 : n = a->neighbor[i];
938 [ + + - + ]: 164 : num_explicit_H += ( 1 == at[n].valence && el_number_H == at[n].el_number );
939 : : }
940 : :
941 : 134 : return num_explicit_H + NUMH( at, iat );
942 : : }
943 : :
944 : : /****************************************************************************/
945 : : /* Get the element group of an element. The base element rather than the */
946 : : /* periodic group is used to aid readability. */
947 : : /* - NitrogenGroup = 7 (EL_NUMBER_N) */
948 : : /* - OxygenGroup = 8 (EL_NUMBER_O) */
949 : : /* - Cargbon = 6 (EL_NUMBER_C) */
950 : : /****************************************************************************/
951 : 164 : U_CHAR ion_el_group( int el )
952 : : {
953 [ + - + + ]: 164 : switch ( el )
954 : : {
955 : 4 : case EL_NUMBER_C: /* fallthrough */
956 : : #if ( FIX_REM_ION_PAIRS_Si_BUG == 1 )
957 : : case EL_NUMBER_SI:
958 : : #endif
959 : 4 : return EL_NUMBER_C;
960 : 0 : case EL_NUMBER_N: /* fallthrough */
961 : : case EL_NUMBER_P:
962 : : case EL_NUMBER_AS:
963 : : case EL_NUMBER_SB:
964 : 0 : return EL_NUMBER_N;
965 : 142 : case EL_NUMBER_O: /* fallthrough */
966 : : case EL_NUMBER_S:
967 : : case EL_NUMBER_SE:
968 : : case EL_NUMBER_TE:
969 : 142 : return EL_NUMBER_O;
970 : 18 : default:
971 : 18 : return 0;
972 : : }
973 : : }
974 : :
975 : 0 : int has_other_ion_neigh( inp_ATOM *at,
976 : : int iat,
977 : : int iat_ion_neigh)
978 : : {
979 : 0 : int charge = at[iat_ion_neigh].charge;
980 : : int i, neigh;
981 : :
982 [ # # ]: 0 : for ( i = 0; i < at[iat].valence; i++ )
983 : : {
984 : 0 : neigh = at[iat].neighbor[i];
985 : :
986 [ # # # # : 0 : if (neigh != iat_ion_neigh && at[neigh].charge == charge &&
# # ]
987 : 0 : ion_el_group( at[neigh].el_number ))
988 : : {
989 : 0 : return 1;
990 : : }
991 : : }
992 : :
993 : 0 : return 0;
994 : : }
995 : :
996 : :
997 : : /****************************************************************************
998 : : Check if has_other_ion_in_sphere_2
999 : : BFS r=2
1000 : : ****************************************************************************/
1001 : 0 : int has_other_ion_in_sphere_2( inp_ATOM *at, int iat,
1002 : : int iat_ion_neigh )
1003 : : {
1004 : : #define MAXQ 16
1005 : : AT_NUMB q[MAXQ];
1006 : 0 : int lenq = 0, lenq2, dist = 0, i = 0, iq, neigh, j, nRet = 0;
1007 : 0 : q[lenq++] = iat;
1008 : 0 : at[iat].cFlags = 1;
1009 : :
1010 : 0 : iq = 0;
1011 : 0 : dist = 1;
1012 : : /* use at->cFlags as an indicator */
1013 : :
1014 [ # # ]: 0 : while ( dist <= 2 )
1015 : : {
1016 [ # # ]: 0 : for ( lenq2 = lenq; iq < lenq2; iq++ )
1017 : : {
1018 : 0 : i = q[iq];
1019 : :
1020 [ # # ]: 0 : for ( j = 0; j < at[i].valence; j++ )
1021 : : {
1022 : 0 : neigh = at[i].neighbor[j];
1023 : :
1024 [ # # ]: 0 : if (!at[neigh].cFlags &&
1025 [ # # # # ]: 0 : at[neigh].valence <= 3 &&
1026 : 0 : ion_el_group( at[neigh].el_number ))
1027 : : {
1028 : 0 : q[lenq++] = neigh;
1029 : 0 : at[neigh].cFlags = 1;
1030 [ # # ]: 0 : if (neigh != iat_ion_neigh &&
1031 [ # # ]: 0 : at[iat_ion_neigh].charge == at[neigh].charge)
1032 : : {
1033 : 0 : nRet++;
1034 : : }
1035 : : }
1036 : : }
1037 : : }
1038 : :
1039 : 0 : dist++;
1040 : : }
1041 : :
1042 [ # # ]: 0 : for ( iq = 0; iq < lenq; iq++ )
1043 : : {
1044 : 0 : i = q[iq];
1045 : 0 : at[i].cFlags = 0;
1046 : : }
1047 : :
1048 : 0 : return nRet;
1049 : : }
1050 : :
1051 : :
1052 : : /****************************************************************************/
1053 : 410 : int nNoMetalNumBonds( inp_ATOM *at, int at_no )
1054 : : {
1055 : : int i;
1056 : :
1057 : 410 : inp_ATOM *a = at + at_no;
1058 : 410 : int num_H = NUMH( a, 0 );
1059 : 410 : int std_chem_bonds_valence = get_el_valence( a->el_number, a->charge, 0 );
1060 : :
1061 [ + + ]: 410 : if ( a->chem_bonds_valence + num_H > std_chem_bonds_valence )
1062 : : {
1063 : 90 : int valence_to_metal = 0;
1064 : 90 : int num_bonds_to_metal = 0;
1065 : :
1066 [ + + ]: 370 : for ( i = 0; i < a->valence; i++ )
1067 : : {
1068 [ + + ]: 344 : if (is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
1069 : : {
1070 [ + - ]: 64 : if (( a->bond_type[i] & BOND_TYPE_MASK ) >= BOND_TYPE_ALTERN)
1071 : : {
1072 : 64 : return a->valence; /* fall back */
1073 : : }
1074 : 0 : num_bonds_to_metal++;
1075 : 0 : valence_to_metal += ( a->bond_type[i] & BOND_TYPE_MASK );
1076 : : }
1077 : : }
1078 : :
1079 [ - + ]: 26 : if ( a->chem_bonds_valence + num_H - valence_to_metal == std_chem_bonds_valence )
1080 : : {
1081 : : /* removing bonds to metal produces standard valence */
1082 : 0 : return a->valence - num_bonds_to_metal;
1083 : : }
1084 : : }
1085 : :
1086 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
1087 : : else
1088 : : {
1089 [ - + - - ]: 320 : if (1 == a->charge && 2 == get_endpoint_valence( a->el_number ) &&
1090 [ # # ]: 0 : a->chem_bonds_valence + num_H == std_chem_bonds_valence)
1091 : : {
1092 : 0 : int valence_to_metal = 0;
1093 : 0 : int num_bonds_to_metal = 0;
1094 [ # # ]: 0 : for ( i = 0; i < a->valence; i++ )
1095 : : {
1096 [ # # ]: 0 : if (is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
1097 : : {
1098 [ # # ]: 0 : if (( a->bond_type[i] & BOND_TYPE_MASK ) >= BOND_TYPE_ALTERN)
1099 : : {
1100 : 0 : return a->valence; /* fall back */
1101 : : }
1102 : 0 : num_bonds_to_metal++;
1103 : 0 : valence_to_metal += ( a->bond_type[i] & BOND_TYPE_MASK );
1104 : : }
1105 : : }
1106 [ # # ]: 0 : if ( 1 == valence_to_metal )
1107 : : {
1108 : : /* removing bonds to metal produces standard valence */
1109 : 0 : return a->valence - num_bonds_to_metal;
1110 : : }
1111 : : }
1112 : : }
1113 : : #endif
1114 : :
1115 : 346 : return a->valence;
1116 : : }
1117 : :
1118 : :
1119 : : /****************************************************************************/
1120 : 154 : int nNoMetalBondsValence( inp_ATOM *at, int at_no )
1121 : : {
1122 : : int i;
1123 : :
1124 : 154 : inp_ATOM *a = at + at_no;
1125 : 154 : int num_H = NUMH( a, 0 );
1126 : 154 : int std_chem_bonds_valence = get_el_valence( a->el_number, a->charge, 0 );
1127 : :
1128 [ + + ]: 154 : if ( a->chem_bonds_valence + num_H > std_chem_bonds_valence )
1129 : : {
1130 : 10 : int valence_to_metal = 0;
1131 : : /*int num_bonds_to_metal = 0;*/
1132 : :
1133 [ + + ]: 50 : for ( i = 0; i < a->valence; i++ )
1134 : : {
1135 [ - + ]: 40 : if (is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
1136 : : {
1137 [ # # ]: 0 : if (( a->bond_type[i] & BOND_TYPE_MASK ) >= BOND_TYPE_ALTERN)
1138 : : {
1139 : 0 : return a->valence; /* fall back */
1140 : : }
1141 : : /* num_bonds_to_metal ++;*/
1142 : 0 : valence_to_metal += ( a->bond_type[i] & BOND_TYPE_MASK );
1143 : : }
1144 : : }
1145 : :
1146 [ - + ]: 10 : if ( a->chem_bonds_valence + num_H - valence_to_metal == std_chem_bonds_valence )
1147 : : {
1148 : : /* removing bonds to metal produces standard valence */
1149 : 0 : return a->chem_bonds_valence - valence_to_metal;
1150 : : }
1151 : : }
1152 : :
1153 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
1154 [ - + - - ]: 144 : else if (1 == a->charge && 2 == get_endpoint_valence( a->el_number ) &&
1155 [ # # ]: 0 : a->chem_bonds_valence + num_H == std_chem_bonds_valence)
1156 : : {
1157 : :
1158 : 0 : int valence_to_metal = 0;
1159 : : /* int num_bonds_to_metal = 0;*/
1160 : :
1161 [ # # ]: 0 : for ( i = 0; i < a->valence; i++ )
1162 : : {
1163 [ # # ]: 0 : if (is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
1164 : : {
1165 [ # # ]: 0 : if (( a->bond_type[i] & BOND_TYPE_MASK ) >= BOND_TYPE_ALTERN)
1166 : : {
1167 : 0 : return a->valence; /* fall back */
1168 : : }
1169 : : /* num_bonds_to_metal ++;*/
1170 : 0 : valence_to_metal += ( a->bond_type[i] & BOND_TYPE_MASK );
1171 : : }
1172 : : }
1173 : :
1174 [ # # ]: 0 : if (1 == valence_to_metal)
1175 : : {/* removing bonds to metal produces standard valence */
1176 : 0 : return a->chem_bonds_valence - valence_to_metal;
1177 : : }
1178 : : }
1179 : : #endif
1180 : :
1181 : 154 : return a->chem_bonds_valence;
1182 : : }
1183 : :
1184 : :
1185 : : /****************************************************************************/
1186 : 112 : int nNoMetalNeighIndex( inp_ATOM *at, int at_no )
1187 : : {
1188 : : int i;
1189 : :
1190 : 112 : inp_ATOM* a = at + at_no;
1191 : :
1192 [ + - ]: 112 : for ( i = 0; i < a->valence; i++ )
1193 : : {
1194 [ + - ]: 112 : if (!is_el_a_metal( at[(int) a->neighbor[i]].el_number ))
1195 : : {
1196 : 112 : return i;
1197 : : }
1198 : : }
1199 : :
1200 : 0 : return -1;
1201 : : }
1202 : :
1203 : :
1204 : : /****************************************************************************/
1205 : 0 : int nNoMetalOtherNeighIndex( inp_ATOM *at, int at_no, int cur_neigh )
1206 : : {
1207 : : int i, neigh;
1208 : :
1209 : 0 : inp_ATOM* a = at + at_no;
1210 : :
1211 [ # # ]: 0 : for ( i = 0; i < a->valence; i++ )
1212 : : {
1213 : 0 : neigh = (int) a->neighbor[i];
1214 : :
1215 [ # # # # ]: 0 : if (neigh != cur_neigh && !is_el_a_metal( at[neigh].el_number ))
1216 : : {
1217 : 0 : return i;
1218 : : }
1219 : : }
1220 : :
1221 : 0 : return -1;
1222 : : }
1223 : :
1224 : :
1225 : : /****************************************************************************/
1226 : 0 : int nNoMetalOtherNeighIndex2( inp_ATOM *at,
1227 : : int at_no,
1228 : : int cur_neigh,
1229 : : int cur_neigh2 )
1230 : : {
1231 : : int i, neigh;
1232 : :
1233 : 0 : inp_ATOM* a = at + at_no;
1234 : :
1235 [ # # ]: 0 : for ( i = 0; i < a->valence; i++ )
1236 : : {
1237 : 0 : neigh = (int) a->neighbor[i];
1238 : :
1239 [ # # # # : 0 : if (neigh != cur_neigh && neigh != cur_neigh2 && !is_el_a_metal( at[neigh].el_number ))
# # ]
1240 : : {
1241 : 0 : return i;
1242 : : }
1243 : : }
1244 : :
1245 : 0 : return -1;
1246 : : }
1247 : :
1248 : :
1249 : :
1250 : : #ifndef COMPILE_ANSI_ONLY
1251 : :
1252 : :
1253 : : /****************************************************************************/
1254 : : int MakeRemovedProtonsString( int nNumRemovedProtons,
1255 : : NUM_H *nNumExchgIsotopicH,
1256 : : NUM_H *nNumRemovedProtonsIsotopic,
1257 : : int bIsotopic,
1258 : : char *szRemovedProtons,
1259 : : int *num_removed_iso_H )
1260 : : {
1261 : : int i, j, len, num;
1262 : :
1263 : : len = 0;
1264 : :
1265 : : if ( nNumRemovedProtons )
1266 : : {
1267 : : len = sprintf(szRemovedProtons, "Proton balance: %c %d H+",
1268 : : nNumRemovedProtons >= 0 ? '+' : '-', abs(nNumRemovedProtons));
1269 : : }
1270 : :
1271 : : if (bIsotopic && ( nNumRemovedProtonsIsotopic || nNumExchgIsotopicH ))
1272 : : {
1273 : :
1274 : : for ( i = 0, j = 0; i < NUM_H_ISOTOPES; i++ )
1275 : : {
1276 : :
1277 : : num = ( nNumExchgIsotopicH ? nNumExchgIsotopicH[i] : 0 ) +
1278 : : ( nNumRemovedProtonsIsotopic ? nNumRemovedProtonsIsotopic[i] : 0 );
1279 : :
1280 : : if ( num )
1281 : : {
1282 : : len += sprintf(szRemovedProtons + len, "%s %d^%dH",
1283 : : j ? ", " : " [ removed ", num, i + 1);
1284 : : j++;
1285 : : }
1286 : : }
1287 : :
1288 : : if ( j )
1289 : : {
1290 : : len += sprintf(szRemovedProtons + len, " ]");
1291 : : if ( num_removed_iso_H )
1292 : : {
1293 : : *num_removed_iso_H = j;
1294 : : }
1295 : : }
1296 : : }
1297 : :
1298 : : if ( !len )
1299 : : {
1300 : : szRemovedProtons[0] = '\0';
1301 : : }
1302 : :
1303 : : return len;
1304 : : }
1305 : : #endif
1306 : :
1307 : :
1308 : : /****************************************************************************/
1309 : 5164 : int get_endpoint_valence( U_CHAR el_number )
1310 : : {
1311 [ + + + ]: 5164 : switch (el_number)
1312 : : {
1313 : 1253 : case EL_NUMBER_O: /* fallthrough */
1314 : : case EL_NUMBER_S:
1315 : : case EL_NUMBER_SE:
1316 : : case EL_NUMBER_TE:
1317 : 1253 : return 2;
1318 : 107 : case EL_NUMBER_N:
1319 : 107 : return 3;
1320 : 3804 : default:
1321 : 3804 : return 0;
1322 : : }
1323 : : }
1324 : :
1325 : :
1326 : : #if ( KETO_ENOL_TAUT == 1 ) /* post v.1 feature */
1327 : :
1328 : :
1329 : : /****************************************************************************/
1330 : 0 : int get_endpoint_valence_KET( U_CHAR el_number )
1331 : : {
1332 [ # # # ]: 0 : switch (el_number)
1333 : : {
1334 : 0 : case EL_NUMBER_C:
1335 : 0 : return 4;
1336 : 0 : case EL_NUMBER_O:
1337 : 0 : return 2;
1338 : 0 : default:
1339 : 0 : return 0;
1340 : : }
1341 : : }
1342 : : #endif
1343 : :
1344 : :
1345 : : /*
1346 : : MEMORY MANAGEMENT
1347 : : */
1348 : :
1349 : :
1350 : : #ifndef inchi_malloc
1351 : : /****************************************************************************/
1352 : : void *inchi_malloc( size_t c )
1353 : : {
1354 : : return malloc( c );
1355 : : }
1356 : : #endif
1357 : :
1358 : :
1359 : : #ifndef inchi_calloc
1360 : : /****************************************************************************/
1361 : : void *inchi_calloc( size_t c, size_t n )
1362 : : {
1363 : : return calloc( c, n );
1364 : : }
1365 : : #endif
1366 : :
1367 : :
1368 : : #ifndef inchi_free
1369 : : /****************************************************************************/
1370 : : void inchi_free( void *p )
1371 : : {
1372 : : if ( p )
1373 : : {
1374 : : inchi_free( p ); /*added check if zero*/
1375 : : }
1376 : : }
1377 : : #endif
1378 : :
1379 : :
1380 : : /*
1381 : : STRINGS AND TEXT HANDLING
1382 : : */
1383 : :
1384 : :
1385 : : /****************************************************************************
1386 : : Remove leading & trailing spaces, replace consecutive
1387 : : spaces with a single space.
1388 : : ****************************************************************************/
1389 : 0 : int normalize_string( char* name )
1390 : : {
1391 : : int i, len, n;
1392 : :
1393 : 0 : len = (int) strlen( name );
1394 : :
1395 [ # # ]: 0 : for ( i = 0, n = 0; i < len; i++ )
1396 : : {
1397 [ # # ]: 0 : if (isspace( UCINT name[i] ) /*|| !isprint( UCINT name[i] )*/)
1398 : : {
1399 : 0 : name[i] = ' '; /* exterminate tabs !!! */
1400 : 0 : n++;
1401 : : }
1402 : : else
1403 : : {
1404 [ # # ]: 0 : if ( n > 0 )
1405 : : {
1406 : 0 : memmove((void*)&name[i - n], (void*)&name[i], (long long)len - (long long)i + 1); /* djb-rwth: cast operators added */
1407 : 0 : i -= n;
1408 : 0 : len -= n;
1409 : : }
1410 : 0 : n = -1;
1411 : : }
1412 : : }
1413 [ # # ]: 0 : if ( n == len ) /* empty line */
1414 : : {
1415 : 0 : name[len = 0] = '\0';
1416 : : }
1417 [ # # # # ]: 0 : else if ( ++n && n <= len )
1418 : : {
1419 : 0 : len -= n;
1420 : 0 : name[len] = '\0';
1421 : : }
1422 : :
1423 : 0 : return len;
1424 : : }
1425 : :
1426 : :
1427 : : /****************************************************************************
1428 : : Replace non-ASCII characters with '.', return number of replacements
1429 : : ****************************************************************************/
1430 : 0 : int dotify_non_printable_chars( char *line )
1431 : : {
1432 : 0 : int i, c, num = 0;
1433 : :
1434 [ # # ]: 0 : if ( line )
1435 : : {
1436 [ # # ]: 0 : for ( i = 0; (c = UCINT line[i]); i++ ) /* djb-rwth: addressing LLVM warning */
1437 : : {
1438 : : /* assuming ASCII charset */
1439 [ # # # # ]: 0 : if ( c < ' ' || c >= 0x7F )
1440 : : {
1441 : 0 : line[i] = '.';
1442 : 0 : num++;
1443 : : }
1444 : : }
1445 : : }
1446 : :
1447 : 0 : return num;
1448 : : }
1449 : :
1450 : :
1451 : : /****************************************************************************
1452 : : Reads char sequence pointed to by *pstring ( char *p = *ppstring) for
1453 : : not more than maxlen bytes) to 'field' up to first occurrence of any of
1454 : : delimiters in 'delims' or end of line, whichever occurs first.
1455 : : Sets *pstring to point to character which matches delimiter.
1456 : : Returns number of bytes copied, -1 on error.
1457 : : ****************************************************************************/
1458 : 8070 : int read_upto_delim( char **pstring, char *field, int maxlen, char* delims )
1459 : : {
1460 : : int i, n;
1461 : 8070 : char* p = *pstring;
1462 : :
1463 [ + + ]: 8070 : if ( !p )
1464 : : {
1465 : 1 : return -1;
1466 : : }
1467 : :
1468 : : /* skip leading spaces */
1469 [ + - + + ]: 14026 : for (i = 0; p[i] && isspace( UCINT p[i] ); i++)
1470 : : {
1471 : : ;
1472 : : }
1473 : 8069 : p += i;
1474 : :
1475 : : /* read up to next delim or eol */
1476 : 8069 : n = 0;
1477 [ + + + + ]: 31053 : while (p[n] && !is_matching_any_delim( p[n], delims ))
1478 : : {
1479 : 22984 : n++;
1480 : : }
1481 : :
1482 [ - + ]: 8069 : if ( n + 1 > maxlen )
1483 : : {
1484 : 0 : return -1;
1485 : : }
1486 : :
1487 : 8069 : mystrncpy( field, p, n + 1 );
1488 : 8069 : field[n + 1] = '\0';
1489 : :
1490 [ + + ]: 8069 : if ( !p[n] )
1491 : : {
1492 : : /* reached EOL */
1493 : 1414 : *pstring = NULL;
1494 : : }
1495 : : else
1496 : : {
1497 : : /* advance reading pos */
1498 : 6655 : *pstring = *pstring + i + n;
1499 : : }
1500 : :
1501 : 8069 : return n;
1502 : : }
1503 : :
1504 : :
1505 : : /****************************************************************************
1506 : : Check if a character is in the list of possible delimiters
1507 : : NB: same as isspace if delims is " \t\n\v\f\r"
1508 : : (0x20 and 0x09-0x0D)
1509 : : ****************************************************************************/
1510 : 29639 : int is_matching_any_delim( char c, char* delims )
1511 : : {
1512 : 29639 : int ic = UCINT c;
1513 [ + + ]: 174455 : while ( *delims )
1514 : : {
1515 [ + + ]: 151471 : if ( ic == *delims )
1516 : : {
1517 : 6655 : return 1;
1518 : : }
1519 : 144816 : delims++;
1520 : : }
1521 : 22984 : return 0;
1522 : : }
1523 : :
1524 : :
1525 : : /****************************************************************************
1526 : : Remove trailing spaces
1527 : : ****************************************************************************/
1528 : 1832 : void remove_trailing_spaces( char* p )
1529 : : {
1530 : : int len;
1531 [ + - + + ]: 22446 : for (len = (int) strlen( p ) - 1; len >= 0 && isspace( UCINT p[len] ); len--)
1532 : : {
1533 : : ;
1534 : : }
1535 : 1832 : p[++len] = '\0';
1536 : 1832 : }
1537 : :
1538 : :
1539 : : /****************************************************************************/
1540 : 2751 : void remove_one_lf( char* p )
1541 : : {
1542 : : size_t len;
1543 [ + - + - : 2751 : if (p && 0 < ( len = strlen( p ) ) && p[len - 1] == '\n')
+ + ]
1544 : : {
1545 : 862 : p[len - 1] = '\0';
1546 [ + + - + ]: 862 : if ( len >= 2 && p[len - 2] == '\r' )
1547 : : {
1548 : 0 : p[len - 2] = '\0';
1549 : : }
1550 : : }
1551 : 2751 : }
1552 : :
1553 : :
1554 : : /****************************************************************************
1555 : : Copies up to maxlen characters INCLUDING end null from source to target
1556 : : Fills out the rest of the target with null bytes
1557 : :
1558 : : protected from non-zero-terminated source and overlapped target/source.
1559 : : ****************************************************************************/
1560 : 10799 : int mystrncpy( char *target, const char *source, unsigned maxlen )
1561 : : {
1562 : : const char *p;
1563 : : unsigned len, source_len;
1564 : :
1565 [ + - + - : 10799 : if ( target == NULL || maxlen == 0 || source == NULL )
- + ]
1566 : : {
1567 : 0 : return 0;
1568 : : }
1569 : :
1570 : : /* giallu: PR #163 */
1571 : : /* Find actual source length first to limit memchr search */
1572 : 10799 : source_len = (unsigned)strlen(source);
1573 : :
1574 [ + + ]: 10799 : if (source_len < maxlen)
1575 : : {
1576 : : /* Source is shorter than maxlen, use actual source length */
1577 : 3990 : len = source_len;
1578 : : }
1579 [ - + ]: 6809 : else if ((p = (const char*)memchr(source, 0, maxlen))) /* djb-rwth: addressing LLVM warning */
1580 : : {
1581 : : /* maxlen does not include the found zero termination */
1582 : 0 : len = (int) ( p - source );
1583 : : }
1584 : : else
1585 : : {
1586 : : /* reduced length does not include one more byte for zero termination */
1587 : 6809 : len = maxlen - 1;
1588 : : }
1589 : :
1590 [ + - ]: 10799 : if ( len )
1591 : : {
1592 : 10799 : memmove(target, source, len);
1593 : : }
1594 : :
1595 : 10799 : memset(target + len, 0, maxlen - len); /* zero termination */ /* djb-rwth: memset_s C11/Annex K variant? */
1596 : :
1597 : 10799 : return 1;
1598 : : }
1599 : :
1600 : :
1601 : : /****************************************************************************
1602 : : Remove leading and trailing white spaces
1603 : : ****************************************************************************/
1604 : 4878 : char* lrtrim( char *p, int* nLen )
1605 : : {
1606 : 4878 : int i, len = 0;
1607 : :
1608 [ + - + - ]: 4878 : if (p && ( len = (int) strlen( p ) ))
1609 : : {
1610 [ + - + - : 27035 : for (i = 0; i < len && is_ascii( p[i] ) && isspace( p[i] ); i++)
+ + ]
1611 : : {
1612 : : ;
1613 : : }
1614 [ + + ]: 4878 : if ( i )
1615 : : {
1616 : 4875 : len -= i; /* djb-rwth: variable has to be decreased before memmove */
1617 : 4875 : (memmove)(p, p + i, ((long long)len + 1)); /* djb-rwth: now cast operator can be added */
1618 : : }
1619 : :
1620 [ + - + - : 4878 : for (; 0 < len && is_ascii( p[len - 1] ) && isspace( p[len - 1] ); len--)
- + ]
1621 : : {
1622 : : ;
1623 : : }
1624 : 4878 : p[len] = '\0';
1625 : : }
1626 : :
1627 [ + - ]: 4878 : if ( nLen )
1628 : : {
1629 : 4878 : *nLen = len;
1630 : : }
1631 : :
1632 : 4878 : return p;
1633 : : }
1634 : :
1635 : :
1636 : : /****************************************************************************
1637 : : Extract InChI substring embedded into a longer string.
1638 : :
1639 : : InChI should start from "InChI=".
1640 : :
1641 : : As for the end of InChI,
1642 : : consider that according to
1643 : : http://info-uri.info/registry/OAIHandler?verb=GetRecord&metadataPrefix=reg&identifier=info:inchi/
1644 : : an InChI identifier may contain the following characters:
1645 : : A-Z
1646 : : a-z
1647 : : 0-9
1648 : : ()*+,-./;=?@
1649 : :
1650 : : Here we treat any character not conforming this specification as a whitespace
1651 : : which marks the end of the InChI string.
1652 : : For example:
1653 : : "InChI=1/Ar%"
1654 : : "InChI=1/Ar\n"
1655 : : "InChI=1/Ar\r\t"
1656 : : all will be trimmed to
1657 : : "InChI=1/Ar"
1658 : :
1659 : : ****************************************************************************/
1660 : 1 : void extract_inchi_substring( char ** buf, const char *str, size_t slen )
1661 : : {
1662 : : size_t i;
1663 : : const char *p;
1664 : : char* bufp;
1665 : : char pp;
1666 : :
1667 : 1 : bufp = *buf;
1668 : 1 : *buf = NULL;
1669 : :
1670 [ - + ]: 1 : if ( str == NULL )
1671 : : {
1672 : 0 : return;
1673 : : }
1674 [ - + ]: 1 : if (strlen( str ) < 1)
1675 : : {
1676 : 0 : return;
1677 : : }
1678 : :
1679 : 1 : p = strstr( str, "InChI=" );
1680 [ - + ]: 1 : if (NULL == p)
1681 : 0 : return;
1682 : :
1683 [ + - ]: 57 : for ( i = 0; i < slen; i++ )
1684 : : {
1685 : 57 : pp = p[i];
1686 : :
1687 [ + + + + ]: 57 : if (pp >= 'A' && pp <= 'Z') continue;
1688 [ + + + - ]: 48 : if (pp >= 'a' && pp <= 'z') continue;
1689 [ + + + + ]: 43 : if (pp >= '0' && pp <= '9') continue;
1690 [ + + ]: 20 : switch (pp)
1691 : : {
1692 : 19 : case '(':
1693 : : case ')':
1694 : : case '*':
1695 : : case '+':
1696 : : case ',':
1697 : : case '-':
1698 : : case '.':
1699 : : case '/':
1700 : : case ';':
1701 : : case '=':
1702 : : case '?':
1703 : 19 : case '@': continue;
1704 : :
1705 : 1 : default: break;
1706 : : }
1707 : :
1708 : 1 : break;
1709 : : }
1710 : :
1711 : 1 : *buf = (char*) inchi_calloc( i + 1, sizeof( char ) );
1712 : 1 : memcpy(*buf, p, i);
1713 [ + - ]: 1 : if ( *buf )
1714 : 1 : (*buf)[i] = '\0';
1715 : :
1716 : 1 : return;
1717 : : }
1718 : :
1719 : :
1720 : : /****************************************************************************/
1721 : 1 : void extract_auxinfo_substring( char ** buf, const char *str, size_t slen )
1722 : : {
1723 : : size_t i;
1724 : : const char *p;
1725 : : char* bufp;
1726 : : char pp;
1727 : :
1728 : 1 : bufp = *buf;
1729 : 1 : *buf = NULL;
1730 : :
1731 [ - + ]: 1 : if ( str == NULL )
1732 : : {
1733 : 0 : return;
1734 : : }
1735 [ - + ]: 1 : if (strlen( str ) < 1)
1736 : : {
1737 : 0 : return;
1738 : : }
1739 : :
1740 : 1 : p = strstr( str, "AuxInfo=" );
1741 [ - + ]: 1 : if (NULL == p)
1742 : : {
1743 : 0 : return;
1744 : : }
1745 : :
1746 [ + - ]: 241 : for ( i = 0; i < slen; i++ )
1747 : : {
1748 : 241 : pp = p[i];
1749 [ + + ]: 241 : if (isspace( UCINT pp )) break;
1750 : : }
1751 : :
1752 : 1 : *buf = (char*) inchi_calloc( i + 1, sizeof( char ) );
1753 : 1 : memcpy(*buf, p, i);
1754 [ + - ]: 1 : if ( *buf )
1755 : 1 : (*buf)[i] = '\0';
1756 : :
1757 : 1 : return;
1758 : : }
1759 : :
1760 : :
1761 : : /****************************************************************************
1762 : : For compatibility: local implementation of non-ANSI
1763 : : (MS-specific) functions, prefixed with "inchi_"
1764 : : ****************************************************************************/
1765 : :
1766 : :
1767 : : #define __MYTOLOWER(c) ( ((c) >= 'A') && ((c) <= 'Z') ? ((c) - 'A' + 'a') : (c) )
1768 : :
1769 : :
1770 : : /****************************************************************************/
1771 : 356 : int inchi_memicmp( const void * p1, const void * p2, size_t length )
1772 : : {
1773 : 356 : const U_CHAR *s1 = (const U_CHAR*) p1;
1774 : 356 : const U_CHAR *s2 = (const U_CHAR*) p2;
1775 [ + - ]: 782 : while (length--)
1776 : : {
1777 [ + + + + ]: 1186 : if (*s1 == *s2 ||
1778 [ + + + + : 404 : __MYTOLOWER( (int) *s1 ) == __MYTOLOWER( (int) *s2 ))
+ + + + ]
1779 : : {
1780 : 426 : s1++;
1781 : 426 : s2++;
1782 : : }
1783 : : else
1784 : : {
1785 : : return
1786 [ + + + + : 356 : __MYTOLOWER( (int) *s1 ) - __MYTOLOWER( (int) *s2 );
+ + + + ]
1787 : : }
1788 : : }
1789 : :
1790 : 0 : return 0;
1791 : : }
1792 : :
1793 : :
1794 : : /****************************************************************************/
1795 : 1321 : int inchi_stricmp( const char *s1, const char *s2 )
1796 : : {
1797 [ + + ]: 2913 : while ( *s1 )
1798 : : {
1799 [ + + + + ]: 4096 : if (*s1 == *s2 ||
1800 [ + - + + : 1258 : __MYTOLOWER( (int) *s1 ) == __MYTOLOWER( (int) *s2 ))
+ + + + ]
1801 : : {
1802 : 1592 : s1++;
1803 : 1592 : s2++;
1804 : : }
1805 : : else
1806 : : {
1807 : : return
1808 [ + - + + : 1246 : __MYTOLOWER( (int) *s1 ) - __MYTOLOWER( (int) *s2 );
+ + + + ]
1809 : : }
1810 : : }
1811 : :
1812 [ - + ]: 75 : if ( *s2 )
1813 : : {
1814 : 0 : return -1;
1815 : : }
1816 : :
1817 : 75 : return 0;
1818 : : }
1819 : :
1820 : :
1821 : : /****************************************************************************/
1822 : 0 : char *inchi__strnset( char *s, int val, size_t length )
1823 : : {
1824 : 0 : char* ps = s;
1825 [ # # # # ]: 0 : while ( length-- && *ps )
1826 : : {
1827 : 0 : *ps++ = (char) val;
1828 : : }
1829 : :
1830 : 0 : return s;
1831 : : }
1832 : :
1833 : :
1834 : : /****************************************************************************/
1835 : 123 : char *inchi__strdup( const char *string )
1836 : : {
1837 : 123 : char* p = NULL;
1838 [ - + ]: 123 : if ( string )
1839 : : {
1840 : 0 : size_t length = strlen( string );
1841 : 0 : p = (char *) inchi_malloc( length + 1 );
1842 [ # # ]: 0 : if (p)
1843 : : {
1844 : 0 : strcpy(p, string);
1845 : : }
1846 : : }
1847 : :
1848 : 123 : return p;
1849 : : }
1850 : :
1851 : :
1852 : : #undef __MYTOLOWER
|