LCOV - code coverage report
Current view: top level - src - util.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 55.3 % 590 326
Test Date: 2026-10-14 12:14:55 Functions: 68.9 % 45 31
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 51.6 % 593 306

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

Generated by: LCOV version 2.0-1