LCOV - code coverage report
Current view: top level - src - mol_fmt3.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 60.3 % 758 457
Test Date: 2026-10-14 12:14:55 Functions: 81.2 % 16 13
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 41.6 % 522 217

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * SPDX-License-Identifier: MIT
       3                 :             :  * Copyright (c) 2024 IUPAC and InChI Trust
       4                 :             :  */
       5                 :             : 
       6                 :             : #include <stdlib.h>
       7                 :             : #include <ctype.h>
       8                 :             : #include <string.h>
       9                 :             : #include <math.h>
      10                 :             : #include <float.h>
      11                 :             : #include <limits.h>
      12                 :             : 
      13                 :             : #include "mode.h"
      14                 :             : #include "mol_fmt.h"
      15                 :             : 
      16                 :             : #include "ichierr.h"
      17                 :             : #include "util.h"
      18                 :             : #include "ichi_io.h"
      19                 :             : 
      20                 :             : #include "bcf_s.h"
      21                 :             : #include "stb_sprintf.h"
      22                 :             : 
      23                 :             : /*
      24                 :             :     Molfile V3000 related procedures
      25                 :             : 
      26                 :             : */
      27                 :             : 
      28                 :             : static int get_actual_atom_number(int index, int n, int *orig, int *fin);
      29                 :             : 
      30                 :             : /****************************************************************************
      31                 :             :  Init V3000 reader
      32                 :             : ****************************************************************************/
      33                 :          57 : int MolfileV3000Init(MOL_FMT_CTAB *ctab,
      34                 :             :                      char *pStrErr)
      35                 :             : {
      36                 :          57 :     int ret = 0;
      37                 :             :     int i;
      38                 :             : 
      39                 :             :     /* STAR ATOMS */
      40                 :          57 :     ctab->v3000->n_star_atoms = 0;
      41                 :          57 :     ctab->v3000->n_non_star_atoms = 0;
      42                 :             : 
      43         [ +  - ]:          57 :     if (ctab->n_atoms)
      44                 :             :     {
      45                 :          57 :         ctab->v3000->atom_index_orig = (int *)inchi_calloc(ctab->n_atoms, sizeof(int));
      46                 :          57 :         ctab->v3000->atom_index_fin = (int *)inchi_calloc(ctab->n_atoms, sizeof(int));
      47   [ +  -  +  - ]:          57 :         if (ctab->v3000->atom_index_orig && ctab->v3000->atom_index_fin) /* djb-rwth: fixing a NULL pointer dereference */
      48                 :             :         {
      49         [ +  + ]:         708 :             for (i = 0; i < ctab->n_atoms; i++) /* protective */
      50                 :             :             {
      51                 :         651 :                 ctab->v3000->atom_index_orig[i] = -1;
      52                 :         651 :                 ctab->v3000->atom_index_fin[i] = -1;
      53                 :             :             }
      54                 :             :         }
      55                 :             :     }
      56                 :             :     else
      57                 :             :     {
      58                 :           0 :         ctab->v3000->atom_index_orig = NULL;
      59                 :           0 :         ctab->v3000->atom_index_fin = NULL;
      60                 :             :     }
      61                 :             : 
      62                 :             :     /* HAPTIC BONDS */
      63                 :          57 :     ctab->v3000->n_haptic_bonds = 0;
      64                 :          57 :     ctab->v3000->haptic_bonds = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
      65         [ -  + ]:          57 :     if (!ctab->v3000->haptic_bonds)
      66                 :             :     {
      67                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
      68                 :           0 :         return -1;
      69                 :             :     }
      70                 :          57 :     ret = NumLists_Alloc(ctab->v3000->haptic_bonds, 8);
      71         [ -  + ]:          57 :     if (ret < 0)
      72                 :             :     {
      73                 :           0 :         ctab->v3000->haptic_bonds = NULL;
      74                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
      75                 :           0 :         return -1;
      76                 :             :     }
      77                 :             : 
      78                 :             :     /* STEABS */
      79                 :          57 :     ctab->v3000->n_steabs = 0;
      80                 :          57 :     ctab->v3000->steabs = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
      81         [ -  + ]:          57 :     if (!ctab->v3000->steabs)
      82                 :             :     {
      83                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
      84                 :           0 :         return -1;
      85                 :             :     }
      86                 :          57 :     ret = NumLists_Alloc(ctab->v3000->steabs, 1);
      87         [ -  + ]:          57 :     if (ret < 0)
      88                 :             :     {
      89                 :           0 :         ctab->v3000->steabs = NULL;
      90                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
      91                 :           0 :         return -1;
      92                 :             :     }
      93                 :             :     /* STEREL */
      94                 :          57 :     ctab->v3000->n_sterel = 0;
      95                 :          57 :     ctab->v3000->sterel = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
      96         [ -  + ]:          57 :     if (!ctab->v3000->sterel)
      97                 :             :     {
      98                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
      99                 :           0 :         return -1;
     100                 :             :     }
     101                 :          57 :     ret = NumLists_Alloc(ctab->v3000->sterel, 4);
     102         [ -  + ]:          57 :     if (ret < 0)
     103                 :             :     {
     104                 :           0 :         ctab->v3000->sterel = NULL;
     105                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
     106                 :           0 :         return -1;
     107                 :             :     }
     108                 :             :     /* STERAC */
     109                 :          57 :     ctab->v3000->n_sterac = 0;
     110                 :          57 :     ctab->v3000->sterac = (NUM_LISTS *)inchi_calloc(1, sizeof(NUM_LISTS));
     111         [ -  + ]:          57 :     if (!ctab->v3000->sterac)
     112                 :             :     {
     113                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
     114                 :           0 :         return -1;
     115                 :             :     }
     116                 :          57 :     ret = NumLists_Alloc(ctab->v3000->sterac, 4);
     117         [ -  + ]:          57 :     if (ret < 0)
     118                 :             :     {
     119                 :           0 :         ctab->v3000->sterac = NULL;
     120                 :           0 :         AddErrorMessage(pStrErr, "Out of RAM");
     121                 :           0 :         return -1;
     122                 :             :     }
     123                 :             : 
     124                 :          57 :     return ret;
     125                 :             : }
     126                 :             : 
     127                 :             : /****************************************************************************
     128                 :             :  Delete V3000 reader data
     129                 :             : ****************************************************************************/
     130                 :          57 : int DeleteMolfileV3000Info(MOL_FMT_v3000 *v3000)
     131                 :             : {
     132         [ +  - ]:          57 :     if (v3000)
     133                 :             :     {
     134                 :             : 
     135         [ +  - ]:          57 :         if (v3000->atom_index_orig)
     136                 :             :         {
     137         [ +  - ]:          57 :             inchi_free(v3000->atom_index_orig);
     138                 :             :         }
     139                 :             : 
     140         [ +  - ]:          57 :         if (v3000->atom_index_fin)
     141                 :             :         {
     142         [ +  - ]:          57 :             inchi_free(v3000->atom_index_fin);
     143                 :             :         }
     144                 :             : 
     145         [ +  - ]:          57 :         if (v3000->haptic_bonds)
     146                 :             :         {
     147                 :          57 :             NumLists_Free(v3000->haptic_bonds);
     148                 :          57 :             free(v3000->haptic_bonds);
     149                 :             :         }
     150                 :             : 
     151         [ +  - ]:          57 :         if (v3000->steabs)
     152                 :             :         {
     153                 :          57 :             NumLists_Free(v3000->steabs);
     154                 :          57 :             free(v3000->steabs);
     155                 :             :         }
     156                 :             : 
     157         [ +  - ]:          57 :         if (v3000->sterel)
     158                 :             :         {
     159                 :          57 :             NumLists_Free(v3000->sterel);
     160                 :          57 :             free(v3000->sterel);
     161                 :             :         }
     162                 :             : 
     163         [ +  - ]:          57 :         if (v3000->sterac)
     164                 :             :         {
     165                 :          57 :             NumLists_Free(v3000->sterac);
     166                 :          57 :             free(v3000->sterac);
     167                 :             :         }
     168                 :             : 
     169         [ +  - ]:          57 :         inchi_free(v3000);
     170                 :          57 :         v3000 = NULL;
     171                 :             :     }
     172                 :             : 
     173                 :          57 :     return 0;
     174                 :             : }
     175                 :             : 
     176                 :             : /****************************************************************************
     177                 :             :     Extended version of inchi_fgetsLf which is able of reading
     178                 :             :     concatenated lines (ending with '-') of V3000 Molfile.
     179                 :             :     Also removes "M  V30 " prefix" and normalizes the rest of string
     180                 :             : ****************************************************************************/
     181                 :           0 : char *inchi_fgetsLf_V3000(char *line, INCHI_IOSTREAM *inp_stream)
     182                 :             : {
     183                 :           0 :     char *p = NULL;
     184                 :           0 :     int len = 0;
     185                 :             : 
     186                 :           0 :     p = inchi_fgetsLf(line, MOL_FMT_V3000_INPLINELEN, inp_stream);
     187         [ #  # ]:           0 :     if (!p)
     188                 :             :     {
     189                 :           0 :         return NULL;
     190                 :             :     }
     191                 :             : 
     192                 :           0 :     len = (int)strlen(p);
     193         [ #  # ]:           0 :     if (len < 7)
     194                 :             :     {
     195                 :           0 :         return NULL;
     196                 :             :     }
     197                 :             : 
     198         [ #  # ]:           0 :     if (strncmp(p, "M  V30 ", 7))
     199                 :             :     {
     200                 :           0 :         return NULL;
     201                 :             :     }
     202                 :             : 
     203                 :           0 :     p += 7;
     204                 :           0 :     len = normalize_string(p); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     205                 :             : 
     206                 :           0 :     return p;
     207                 :             : }
     208                 :             : 
     209                 :             : /****************************************************************************
     210                 :             :     Read V3000 field.
     211                 :             : 
     212                 :             :     It is MolfileReadField updated for V3000.
     213                 :             :     It considers right whitespace as stop sign,
     214                 :             :     no predefined len is used.
     215                 :             : 
     216                 :             :     Returns -1 on error otherwise number of bytes read.
     217                 :             : 
     218                 :             :     NB: ASSUMES THAT STRING HAS BEEN NORMALIZED with normalize_string()
     219                 :             : 
     220                 :             :     TODO: treat strings with spaces in double quotes
     221                 :             : ****************************************************************************/
     222                 :        7241 : int MolfileV3000ReadField(void *data,
     223                 :             :                           int data_type,
     224                 :             :                           char **line_ptr)
     225                 :             : {
     226                 :        7241 :     int nread = 0;
     227                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
     228                 :        7241 :     const int max_field_len = sizeof(field);
     229                 :        7241 :     long ldata = 0L;
     230                 :        7241 :     double ddata = 0.0;
     231                 :             :     char *p_end;
     232                 :             : 
     233                 :        7241 :     memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
     234                 :             : 
     235                 :        7241 :     nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
     236                 :             : 
     237   [ +  +  +  - ]:        7241 :     switch (data_type)
     238                 :             :     {
     239                 :         710 :     case MOL_FMT_STRING_DATA:
     240                 :             :     {
     241   [ +  -  +  - ]:         710 :         if (nread && (nread <= ATOM_EL_LEN)) /* djb-rwth: fixing GHI #133 -- updated 28/09/2025 */
     242                 :             :         {
     243                 :         710 :             mystrncpy((char *)data, field, nread + 1);
     244                 :             :         }
     245                 :             :         else
     246                 :             :         {
     247                 :           0 :             ((char *)data)[0] = '\0';
     248                 :             :         }
     249                 :             :     }
     250                 :         710 :     break;
     251                 :             : 
     252                 :        4578 :     case MOL_FMT_CHAR_INT_DATA:
     253                 :             :     case MOL_FMT_SHORT_INT_DATA:
     254                 :             :     case MOL_FMT_LONG_INT_DATA:
     255                 :             :     case MOL_FMT_INT_DATA:
     256                 :             :     {
     257                 :             :         /* assume that field ends at first non-digit */
     258                 :        4578 :         ldata = strtol(field, &p_end, 10);
     259                 :             : 
     260         [ +  + ]:        4578 :         if (p_end == field)
     261                 :             :         {
     262                 :           3 :             nread = 0;
     263                 :             :         }
     264                 :             : 
     265         [ -  + ]:        4578 :         if (data_type == MOL_FMT_LONG_INT_DATA)
     266                 :             :         {
     267   [ #  #  #  # ]:           0 :             if (LONG_MIN < ldata && ldata < LONG_MAX)
     268                 :             :             {
     269                 :           0 :                 *(long *)data = (long)ldata;
     270                 :             :             }
     271                 :             :             else
     272                 :             :             {
     273                 :           0 :                 *(long *)data = 0L;
     274                 :           0 :                 nread = -1;
     275                 :             :             }
     276                 :             :         }
     277         [ +  + ]:        4578 :         else if (data_type == MOL_FMT_INT_DATA)
     278                 :             :         {
     279   [ +  -  +  - ]:        2321 :             if (INT_MIN <= ldata && ldata <= INT_MAX) /* djb-rwth: addressing coverity ID #499496/499553 -- ldata check seems to be necessary */
     280                 :             :             {
     281                 :        2321 :                 *(int *)data = (int)ldata;
     282                 :             :             }
     283                 :             :             else
     284                 :             :             {
     285                 :           0 :                 *(int *)data = (int)0;
     286                 :           0 :                 nread = -1;
     287                 :             :             }
     288                 :             :         }
     289                 :             : 
     290         [ +  + ]:        2257 :         else if (data_type == MOL_FMT_CHAR_INT_DATA)
     291                 :             :         {
     292   [ +  -  +  - ]:        1047 :             if (SCHAR_MIN <= ldata && ldata <= SCHAR_MAX)
     293                 :             :             {
     294                 :        1047 :                 *(S_CHAR *)data = (S_CHAR)ldata;
     295                 :             :             }
     296                 :             :             else
     297                 :             :             {
     298                 :           0 :                 *(S_CHAR *)data = (S_CHAR)0;
     299                 :           0 :                 nread = -1;
     300                 :             :             }
     301                 :             :         }
     302                 :             : 
     303         [ +  - ]:        1210 :         else if (data_type == MOL_FMT_SHORT_INT_DATA)
     304                 :             :         {
     305   [ +  -  +  - ]:        1210 :             if (SHRT_MIN <= ldata && ldata <= SHRT_MAX)
     306                 :             :             {
     307                 :        1210 :                 *(S_SHORT *)data = (S_SHORT)ldata;
     308                 :             :             }
     309                 :             :             else
     310                 :             :             {
     311                 :           0 :                 *(S_SHORT *)data = (S_SHORT)0;
     312                 :           0 :                 nread = -1;
     313                 :             :             }
     314                 :             :         }
     315                 :             :         else
     316                 :             :         {
     317                 :           0 :             nread = -1;
     318                 :             :         }
     319                 :             :     }
     320                 :        4578 :     break; /* INT's */
     321                 :             : 
     322                 :        1953 :     case MOL_FMT_DOUBLE_DATA:
     323                 :             :     case MOL_FMT_FLOAT_DATA:
     324                 :             :     {
     325                 :             :         /* assume that field ends at first non-digit */
     326                 :        1953 :         ddata = strtod(field, &p_end);
     327                 :             : 
     328         [ -  + ]:        1953 :         if (p_end == field)
     329                 :             :         {
     330                 :           0 :             nread = 0;
     331                 :             :         }
     332                 :             : 
     333         [ +  - ]:        1953 :         if (data_type == MOL_FMT_DOUBLE_DATA)
     334                 :             :         {
     335   [ +  -  +  - ]:        1953 :             if (ddata != HUGE_VAL && /*ldata*/ ddata != -HUGE_VAL)
     336                 :             :             {
     337                 :        1953 :                 *(double *)data = ddata;
     338                 :             :             }
     339                 :             :             else
     340                 :             :             {
     341                 :           0 :                 *(double *)data = 0.0;
     342                 :           0 :                 nread = -1;
     343                 :             :             }
     344                 :             :         }
     345         [ #  # ]:           0 :         else if (data_type == MOL_FMT_FLOAT_DATA)
     346                 :             :         {
     347         [ #  # ]:           0 :             if (fabs(ddata) <= (double)FLT_MIN)
     348                 :             :             {
     349                 :           0 :                 *(float *)data = 0.0;
     350                 :             :             }
     351         [ #  # ]:           0 :             else if (fabs(ddata) >= (double)FLT_MAX)
     352                 :             :             {
     353                 :           0 :                 *(float *)data = 0.0;
     354                 :           0 :                 nread = -1;
     355                 :             :             }
     356                 :             :         }
     357                 :             :         else
     358                 :             :         {
     359                 :           0 :             *(float *)data = (float)ddata; /* djb-rwth: addressing coverity ID #499519 -- probably never reached */
     360                 :             :         }
     361                 :             :     }
     362                 :        1953 :     break; /* REAL's */
     363                 :             : 
     364                 :           0 :     default:
     365                 :           0 :         nread = -1;
     366                 :             :     }
     367                 :             : 
     368                 :        7241 :     return nread;
     369                 :             : }
     370                 :             : 
     371                 :             : /****************************************************************************
     372                 :             :     Read V3000 keyword.
     373                 :             :     TODO: treat strings with spaces in double quotes
     374                 :             : ****************************************************************************/
     375                 :         416 : int MolfileV3000ReadKeyword(char *key,
     376                 :             :                             char **line_ptr)
     377                 :             : {
     378                 :         416 :     int nread = 0;
     379                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
     380                 :         416 :     const int max_field_len = sizeof(field);
     381                 :             : 
     382                 :         416 :     memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
     383                 :             : 
     384                 :         416 :     nread = read_upto_delim(line_ptr, field, max_field_len, "= \t\n\v\f\r");
     385                 :             : 
     386         [ +  - ]:         416 :     if (nread)
     387                 :             :     {
     388                 :         416 :         mystrncpy(key, field, nread + 1);
     389                 :             :         /* consume '=' sign if present */
     390         [ +  - ]:         416 :         if (*line_ptr)
     391                 :             :         {
     392         [ +  - ]:         416 :             if (*line_ptr[0] == '=')
     393                 :             :             {
     394                 :         416 :                 *line_ptr = *line_ptr + 1;
     395                 :             :             }
     396                 :             :         }
     397                 :             :     }
     398                 :             :     else
     399                 :             :     {
     400                 :           0 :         key[0] = '\0';
     401                 :             :     }
     402                 :             : 
     403                 :         416 :     return nread;
     404                 :             : }
     405                 :             : 
     406                 :             : /****************************************************************************
     407                 :             :  Read V3000 head of CTab
     408                 :             : ****************************************************************************/
     409                 :          57 : int MolfileV3000ReadCTABBeginAndCountsLine(MOL_FMT_CTAB *ctab,
     410                 :             :                                            INCHI_IOSTREAM *inp_file,
     411                 :             :                                            char *pStrErr)
     412                 :             : {
     413                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
     414                 :          57 :     int err = 0, len; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     415                 :          57 :     int failed = 0;
     416                 :             : 
     417                 :             :     int nc;
     418                 :          57 :     char *p = NULL, *line = NULL;
     419                 :             :     INCHI_IOSTREAM tmpin;
     420                 :          57 :     INCHI_IOS_STRING *pin = &tmpin.s;
     421                 :          57 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
     422                 :             : 
     423                 :          57 :     field[0] = '\0'; /* djb-rwth: adding zero termination */
     424                 :             : 
     425                 :             :     /* Check for proper start */
     426                 :             : 
     427                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     428                 :          57 :     inchi_strbuf_reset(pin);
     429                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     430         [ -  + ]:          57 :     if (nc < 1)
     431                 :             :     {
     432                 :           0 :         p = NULL;
     433                 :             :     }
     434                 :             :     else
     435                 :             :     {
     436                 :          57 :         p = line = pin->pStr;
     437                 :             :     }
     438   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "BEGIN CTAB"))
     439                 :             :     {
     440         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 CTab start marker");
     441                 :             :     }
     442                 :          57 :     remove_one_lf(line);
     443                 :             : 
     444                 :             :     /* Reset all previosly read data from quasi-counts line            */
     445                 :             :     /* (which contains only single meaningful value, 'V3000' marker    */
     446                 :          57 :     ctab->n_atoms = -1;
     447                 :          57 :     ctab->n_bonds = -1;
     448                 :          57 :     ctab->chiral_flag = -1;
     449                 :          57 :     ctab->n_stext_entries = -1;
     450                 :             :     /* Relax stricthness of V3000 conformance: */
     451                 :             :     /* Do not check if '999' supplied, just use this. */
     452                 :          57 :     ctab->n_property_lines = 999;
     453                 :             : 
     454                 :             :     /* Read counts line */
     455                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     456                 :          57 :     inchi_strbuf_reset(pin);
     457                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     458         [ -  + ]:          57 :     if (nc < 1)
     459                 :             :     {
     460                 :           0 :         p = NULL;
     461                 :             :     }
     462                 :             :     else
     463                 :             :     {
     464                 :          57 :         p = line = pin->pStr;
     465                 :             :     }
     466         [ -  + ]:          57 :     if (!p)
     467                 :             :     {
     468         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Cannot read V3000 counts line");
     469                 :             :     }
     470                 :          57 :     remove_one_lf(line);
     471                 :             : 
     472                 :             :     /* Parse counts line */
     473                 :          57 :     len = MolfileV3000ReadField(field, MOL_FMT_STRING_DATA, &p); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     474         [ -  + ]:          57 :     if (strcmp(field, "COUNTS"))
     475                 :             :     {
     476         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Cannot read V3000 counts line");
     477                 :             :     }
     478                 :          57 :     failed = 0;
     479         [ -  + ]:          57 :     if (0 > MolfileV3000ReadField(&ctab->n_atoms, MOL_FMT_INT_DATA, &p))
     480                 :             :     {
     481                 :           0 :         failed = 2;
     482                 :             :     }
     483         [ -  + ]:          57 :     else if (0 > MolfileV3000ReadField(&ctab->n_bonds, MOL_FMT_INT_DATA, &p))
     484                 :             :     {
     485                 :           0 :         failed = 1;
     486                 :             :     }
     487         [ -  + ]:          57 :     else if (0 > MolfileV3000ReadField(&ctab->v3000->n_sgroups, MOL_FMT_INT_DATA, &p))
     488                 :             :     {
     489                 :           0 :         failed = 1;
     490                 :             :     }
     491         [ -  + ]:          57 :     else if (0 > MolfileV3000ReadField(&ctab->v3000->n_3d_constraints, MOL_FMT_INT_DATA, &p))
     492                 :             :     {
     493                 :           0 :         failed = 1;
     494                 :             :     }
     495         [ -  + ]:          57 :     else if (0 > MolfileV3000ReadField(&ctab->chiral_flag, MOL_FMT_CHAR_INT_DATA, &p))
     496                 :             :     {
     497                 :           0 :         failed = 1;
     498                 :             :     }
     499                 :             : 
     500         [ +  - ]:          57 :     if (failed)
     501                 :             :     {
     502                 :           0 :         err = 3;
     503         [ #  # ]:           0 :         if (failed == 2)
     504                 :             :         {
     505         [ #  # ]:           0 :             TREAT_ERR(err, 3, "Number of atoms too large. V3000 counts line:");
     506                 :             :         }
     507                 :             :         else
     508                 :             :         {
     509                 :             :             /* too long input file line or other value min-max range mismatch */
     510         [ #  # ]:           0 :             TREAT_ERR(err, 3, "Cannot interpret V3000 counts line:");
     511                 :             :         }
     512                 :           0 :         dotify_non_printable_chars(line);
     513                 :           0 :         AddErrorMessage(pStrErr, line);
     514                 :           0 :         goto err_fin;
     515                 :             :     }
     516                 :             : 
     517                 :          57 : err_fin:
     518                 :          57 :     inchi_strbuf_close(pin);
     519                 :             : 
     520                 :          57 :     return err;
     521                 :             : }
     522                 :             : 
     523                 :             : /****************************************************************************
     524                 :             :  Read V3000 SGroup
     525                 :             : ****************************************************************************/
     526                 :           0 : int MolfileV3000ReadSGroup(MOL_FMT_CTAB *ctab,
     527                 :             :                            INCHI_IOSTREAM *inp_file,
     528                 :             :                            int err,
     529                 :             :                            char *pStrErr)
     530                 :             : {
     531                 :             :     int nc;
     532                 :           0 :     char *p = NULL, *line = NULL;
     533                 :             :     INCHI_IOSTREAM tmpin;
     534                 :           0 :     INCHI_IOS_STRING *pin = &tmpin.s;
     535                 :             : 
     536                 :           0 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
     537                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     538                 :             : 
     539                 :             :     while (1)
     540                 :             :     {
     541                 :           0 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     542                 :             : 
     543         [ #  # ]:           0 :         if (nc < 1)
     544                 :             :         {
     545                 :           0 :             p = NULL;
     546                 :             :         }
     547                 :             :         else
     548                 :             :         {
     549                 :           0 :             p = line = pin->pStr;
     550                 :           0 :             remove_one_lf(line);
     551                 :             :         }
     552   [ #  #  #  # ]:           0 :         if (p && !strcmp(p, "END SGROUP"))
     553                 :             :         {
     554                 :           0 :             inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
     555                 :           0 :             return 0;
     556                 :             :         }
     557                 :             :     }
     558                 :             : 
     559                 :             :     /* if (  !p  || strcmp(p, "END SGROUP") ) */
     560                 :             :     {
     561                 :             :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 SGroup end marker");
     562                 :             :     }
     563                 :             : 
     564                 :             : err_fin:
     565                 :             : 
     566                 :             :     inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
     567                 :             :     return err;
     568                 :             : }
     569                 :             : 
     570                 :             : /****************************************************************************
     571                 :             :  Read V3000 3DBlock
     572                 :             : ****************************************************************************/
     573                 :           0 : int MolfileV3000Read3DBlock(MOL_FMT_CTAB *ctab,
     574                 :             :                             INCHI_IOSTREAM *inp_file,
     575                 :             :                             int err,
     576                 :             :                             char *pStrErr)
     577                 :             : {
     578                 :             :     int nc;
     579                 :           0 :     char *p = NULL, *line = NULL;
     580                 :             :     INCHI_IOSTREAM tmpin;
     581                 :           0 :     INCHI_IOS_STRING *pin = &tmpin.s;
     582                 :           0 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
     583                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     584                 :             : 
     585                 :           0 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     586                 :             : 
     587         [ #  # ]:           0 :     if (nc < 1)
     588                 :             :     {
     589                 :           0 :         p = NULL;
     590                 :             :     }
     591                 :             :     else
     592                 :             :     {
     593                 :           0 :         p = line = pin->pStr;
     594                 :             :     }
     595                 :           0 :     remove_one_lf(line);
     596                 :             : 
     597   [ #  #  #  # ]:           0 :     if (!p || strcmp(p, "END OBJ3D"))
     598                 :             :     {
     599         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 3DBlock end marker");
     600                 :             :     }
     601                 :           0 :     goto err_fin;
     602                 :             : 
     603                 :           0 : err_fin:
     604                 :             : 
     605                 :           0 :     inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
     606                 :           0 :     return err;
     607                 :             : }
     608                 :             : 
     609                 :             : /****************************************************************************
     610                 :             :  Read V3000 collections
     611                 :             : ****************************************************************************/
     612                 :          37 : int MolfileV3000ReadCollections(MOL_FMT_CTAB *ctab,
     613                 :             :                                 INCHI_IOSTREAM *inp_file,
     614                 :             :                                 int err,
     615                 :             :                                 char *pStrErr)
     616                 :             : {
     617                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
     618                 :          37 :     const int max_field_len = sizeof(field);
     619                 :          37 :     int nread, len, n_coll = 0;
     620                 :          37 :     int failed = 0;
     621                 :             :     int nc;
     622                 :          37 :     char *p = NULL, *line = NULL;
     623                 :             :     INCHI_IOSTREAM tmpin;
     624                 :          37 :     INCHI_IOS_STRING *pin = &tmpin.s;
     625                 :             : 
     626                 :          37 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
     627                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     628                 :             : 
     629                 :          37 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     630                 :             : 
     631         [ -  + ]:          37 :     if (nc < 1)
     632                 :             :     {
     633                 :           0 :         p = NULL;
     634                 :             :     }
     635                 :             :     else
     636                 :             :     {
     637                 :          37 :         p = line = pin->pStr;
     638                 :             :     }
     639                 :          37 :     remove_one_lf(line);
     640                 :             : 
     641   [ +  -  +  + ]:         138 :     while (p && strcmp(p, "END COLLECTION"))
     642                 :             :     {
     643                 :         101 :         int stereo_kind = MOL_FMT_V3000_STENON;
     644                 :             :         /* stereo collection of interest */
     645                 :         101 :         NUM_LISTS *ste_coll = NULL;
     646                 :             : 
     647                 :         101 :         nread = read_upto_delim(&p, field, max_field_len, "/");
     648         [ -  + ]:         101 :         if (nread < 6)
     649                 :             :         {
     650                 :           0 :             failed = 1;
     651                 :           0 :             break;
     652                 :             :         }
     653         [ -  + ]:         101 :         if (strcmp(field, "MDLV30"))
     654                 :             :         {
     655                 :           0 :             failed = 1;
     656                 :           0 :             break;
     657                 :             :         }
     658                 :             : 
     659                 :         101 :         nread = read_upto_delim(&p, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     660         [ +  + ]:         101 :         if (!strcmp(field, "/STEABS"))
     661                 :             :         {
     662                 :          23 :             n_coll = 1;
     663                 :          23 :             stereo_kind = MOL_FMT_V3000_STEABS;
     664                 :          23 :             ste_coll = ctab->v3000->steabs;
     665                 :             :         }
     666         [ +  + ]:          78 :         else if (!strcmp(field, "/STEREL"))
     667                 :             :         {
     668                 :             :             /* get number of collection */
     669         [ -  + ]:          31 :             if (0 > MolfileV3000ReadField(&n_coll, MOL_FMT_CHAR_INT_DATA, &p))
     670                 :             :             {
     671                 :           0 :                 failed = 1;
     672                 :           0 :                 break;
     673                 :             :             }
     674                 :          31 :             stereo_kind = MOL_FMT_V3000_STEREL;
     675                 :          31 :             ste_coll = ctab->v3000->sterel;
     676                 :             :         }
     677         [ +  - ]:          47 :         else if (!strcmp(field, "/STERAC"))
     678                 :             :         {
     679                 :             :             /* get number of collection */
     680         [ -  + ]:          47 :             if (0 > MolfileV3000ReadField(&n_coll, MOL_FMT_CHAR_INT_DATA, &p))
     681                 :             :             {
     682                 :           0 :                 failed = 1;
     683                 :           0 :                 break;
     684                 :             :             }
     685                 :          47 :             stereo_kind = MOL_FMT_V3000_STERAC;
     686                 :          47 :             ste_coll = ctab->v3000->sterac;
     687                 :             :         }
     688                 :             :         else
     689                 :             :         {
     690                 :             :             ;
     691                 :             :         }
     692                 :             : 
     693         [ +  - ]:         101 :         if (stereo_kind != MOL_FMT_V3000_STENON)
     694                 :             :         /* currently skip non-stereo collections */
     695                 :             :         {
     696                 :             :             /* consume atoms= */
     697         [ +  - ]:         101 :             if ((len = MolfileV3000ReadKeyword(field, &p) > 0)) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     698                 :             :             {
     699         [ +  - ]:         101 :                 if (!strcmp(field, "ATOMS"))
     700                 :             :                 {
     701                 :         101 :                     int res, *num_list = NULL;
     702                 :             : 
     703         [ -  + ]:         101 :                     if (0 > MolfileV3000ReadStereoCollection(ctab, &p, &num_list, pStrErr))
     704                 :             :                     {
     705                 :           0 :                         failed = 1;
     706                 :             :                     }
     707         [ -  + ]:         101 :                     else if (!num_list)
     708                 :             :                     {
     709                 :           0 :                         failed = 1;
     710                 :             :                     }
     711                 :             :                     else
     712                 :             :                     {
     713                 :             :                         int k, nnum;
     714                 :         101 :                         num_list[0] = n_coll;
     715                 :         101 :                         nnum = num_list[1];
     716         [ +  + ]:         125 :                         for (k = 2; k < nnum; k++)
     717                 :             :                         {
     718                 :          24 :                             num_list[k] =
     719                 :          24 :                                 get_actual_atom_number(num_list[k],
     720                 :          24 :                                                        ctab->v3000->n_non_star_atoms + ctab->v3000->n_star_atoms,
     721                 :          24 :                                                        ctab->v3000->atom_index_orig,
     722                 :          24 :                                                        ctab->v3000->atom_index_fin);
     723                 :             :                         }
     724                 :         101 :                         res = NumLists_Append(ste_coll, num_list);
     725         [ -  + ]:         101 :                         if (res < 0)
     726                 :             :                         {
     727                 :           0 :                             failed = 1;
     728                 :             :                         }
     729                 :             :                         else
     730                 :             :                         {
     731         [ +  + ]:         101 :                             if (stereo_kind == MOL_FMT_V3000_STEABS)
     732                 :             :                             {
     733                 :          23 :                                 ctab->v3000->n_steabs++;
     734                 :          23 :                                 ctab->v3000->n_collections++;
     735                 :             :                             }
     736         [ +  + ]:          78 :                             else if (stereo_kind == MOL_FMT_V3000_STEREL)
     737                 :             :                             {
     738                 :          31 :                                 ctab->v3000->n_sterel++;
     739                 :          31 :                                 ctab->v3000->n_collections++;
     740                 :             :                             }
     741         [ +  - ]:          47 :                             else if (stereo_kind == MOL_FMT_V3000_STERAC)
     742                 :             :                             {
     743                 :          47 :                                 ctab->v3000->n_sterac++;
     744                 :          47 :                                 ctab->v3000->n_collections++;
     745                 :             :                             }
     746                 :             :                         }
     747                 :             :                     }
     748                 :             :                 }
     749                 :             :             }
     750                 :             :             else
     751                 :             :             {
     752                 :           0 :                 failed = 1;
     753                 :           0 :                 break;
     754                 :             :             }
     755                 :             :         }
     756                 :             : 
     757                 :             :         /*next_line:*/
     758                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     759                 :         101 :         inchi_strbuf_reset(pin);
     760                 :             : 
     761                 :         101 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     762                 :             : 
     763         [ -  + ]:         101 :         if (nc < 1)
     764                 :             :         {
     765                 :           0 :             p = NULL;
     766                 :             :         }
     767                 :             :         else
     768                 :             :         {
     769                 :         101 :             p = line = pin->pStr;
     770                 :         101 :             remove_one_lf(line);
     771                 :             :         }
     772                 :             :     }
     773                 :             : 
     774         [ -  + ]:          37 :     if (failed)
     775                 :             :     {
     776                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     777                 :           0 :         inchi_strbuf_reset(pin);
     778                 :           0 :         line = NULL; /* Reset line pointer since buffer was freed */
     779                 :             : 
     780                 :           0 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     781                 :             : 
     782         [ #  # ]:           0 :         if (nc < 1)
     783                 :             :         {
     784                 :           0 :             p = NULL;
     785                 :             :         }
     786                 :             :         else
     787                 :             :         {
     788                 :           0 :             p = line = pin->pStr;
     789                 :           0 :             remove_one_lf(line);
     790                 :             :         }
     791                 :             :     }
     792                 :             : 
     793         [ -  + ]:          37 :     if (!p)
     794                 :             :     {
     795                 :           0 :         failed = 1;
     796                 :             :     }
     797                 :             : 
     798         [ +  - ]:          37 :     if (failed)
     799                 :             :     {
     800                 :           0 :         err = 7;
     801         [ #  # ]:           0 :         TREAT_ERR(err, 7, "Cannot interpret V3000 collection line(s)"); /* djb-rwth: addressing coverity ID #499531 -- TREAT_ERR properly used */
     802         [ #  # ]:           0 :         if (line)
     803                 :             :         {
     804                 :           0 :             dotify_non_printable_chars(line);
     805                 :           0 :             AddErrorMessage(pStrErr, line);
     806                 :             :         }
     807                 :           0 :         goto err_fin;
     808                 :             :     }
     809                 :             : 
     810                 :             :     // /* Error: No V3000 Collection end marker */
     811                 :             :     // if (ctab->v3000->n_steabs ||
     812                 :             :     //     ctab->v3000->n_sterel ||
     813                 :             :     //     ctab->v3000->n_sterac)
     814                 :             :     // {
     815                 :             :     //     AddErrorMessage(pStrErr, "V3000 enhanced stereo read/stored but ignored");
     816                 :             :     // }
     817                 :             : 
     818                 :          37 : err_fin:
     819                 :             : 
     820                 :          37 :     inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
     821                 :          37 :     return err;
     822                 :             : }
     823                 :             : 
     824                 :             : /****************************************************************************
     825                 :             :  Read V3000 atoms
     826                 :             : ****************************************************************************/
     827                 :          57 : int MolfileV3000ReadAtomsBlock(MOL_FMT_CTAB *ctab,
     828                 :             :                                INCHI_IOSTREAM *inp_file,
     829                 :             :                                int err,
     830                 :             :                                char *pStrErr)
     831                 :             : {
     832                 :             :     int i;
     833                 :             :     /* djb-rwth: removing redundant variables */
     834                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
     835                 :          57 :     int nc, failed = 0;
     836                 :          57 :     char *p = NULL, *line = NULL;
     837                 :             :     INCHI_IOSTREAM tmpin;
     838                 :          57 :     INCHI_IOS_STRING *pin = &tmpin.s;
     839                 :          57 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
     840                 :             : 
     841                 :             :     /* Check for proper start */
     842                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     843                 :             : 
     844                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     845                 :             : 
     846         [ -  + ]:          57 :     if (nc < 1)
     847                 :             :     {
     848                 :           0 :         p = NULL;
     849                 :             :     }
     850                 :             :     else
     851                 :             :     {
     852                 :          57 :         p = line = pin->pStr;
     853                 :             :     }
     854   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "BEGIN ATOM"))
     855                 :             :     {
     856         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Atom block start marker");
     857                 :             :     }
     858                 :          57 :     remove_one_lf(line);
     859                 :             : 
     860                 :          57 :     ctab->v3000->n_non_star_atoms = 0;
     861         [ +  + ]:         708 :     for (i = 0; i < ctab->n_atoms; i++)
     862                 :             :     {
     863                 :         651 :         int ii = -1;
     864                 :             : 
     865                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
     866                 :         651 :         inchi_strbuf_reset(pin);
     867                 :             : 
     868                 :         651 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
     869                 :             : 
     870         [ -  + ]:         651 :         if (nc < 1)
     871                 :             :         {
     872                 :           0 :             p = NULL;
     873                 :             :         }
     874                 :             :         else
     875                 :             :         {
     876                 :         651 :             p = line = pin->pStr;
     877                 :             :         }
     878         [ -  + ]:         651 :         if (!p)
     879                 :             :         {
     880         [ #  # ]:           0 :             if (!err)
     881                 :             :             {
     882         [ #  # ]:           0 :                 TREAT_ERR(err, 2, "Cannot read V3000 atom block line");
     883                 :             :             }
     884                 :           0 :             break;
     885                 :             :         }
     886                 :         651 :         remove_one_lf(line);
     887                 :             : 
     888         [ -  + ]:         651 :         if (err)
     889                 :             :         {
     890         [ #  # ]:           0 :             if (!strcmp(line, SD_FMT_END_OF_DATA))
     891                 :             :             {
     892                 :           0 :                 err = -abs(err);
     893                 :           0 :                 break;
     894                 :             :             }
     895                 :           0 :             continue; /* bypass the rest of the Atom block */
     896                 :             :         }
     897                 :             : 
     898         [ +  - ]:         651 :         if (ctab->atoms)
     899                 :             :         {
     900                 :             :             int index, aamap; /* not used actually, just read them */
     901                 :             :             int len;
     902                 :             :             char symbol[6]; /* TODO: treat possibly long V3000 atom names */
     903                 :         651 :             double fx = 0.0, fy = 0.0, fz = 0.0;
     904                 :             : #ifdef GHI100_FIX
     905                 :             : #if (SPRINTF_FLAG == 2)
     906                 :             :             char *fxs, *fys, *fzs;
     907                 :             :             int rfxs, rfys, rfzs;
     908                 :             : 
     909                 :             :             fxs = (char *)inchi_malloc((10 + 3) * sizeof(double));
     910                 :             :             fys = (char *)inchi_malloc((10 + 3) * sizeof(double));
     911                 :             :             fzs = (char *)inchi_malloc((10 + 3) * sizeof(double));
     912                 :             : 
     913                 :             :             if (fxs || fys || fzs)
     914                 :             :             {
     915                 :             :                 failed = 1;
     916                 :             :             }
     917                 :             : #endif
     918                 :             : #endif
     919                 :         651 :             symbol[0] = '\0'; /* djb-rwth: adding zero termination */
     920                 :             : 
     921                 :             :             /* Read positional parameters */
     922                 :         651 :             failed = 0;
     923                 :             : 
     924         [ -  + ]:         651 :             if (0 > MolfileV3000ReadField(&index, MOL_FMT_INT_DATA, &p))
     925                 :             :             {
     926                 :           0 :                 failed = 1;
     927                 :             :             }
     928         [ -  + ]:         651 :             else if (0 > MolfileV3000ReadField(&symbol, MOL_FMT_STRING_DATA, &p))
     929                 :             :             {
     930                 :           0 :                 failed = 1;
     931                 :             :             }
     932         [ -  + ]:         651 :             else if (0 > MolfileV3000ReadField(&fx, MOL_FMT_DOUBLE_DATA, &p))
     933                 :             :             {
     934                 :           0 :                 failed = 1;
     935                 :             :             }
     936         [ -  + ]:         651 :             else if (0 > MolfileV3000ReadField(&fy, MOL_FMT_DOUBLE_DATA, &p))
     937                 :             :             {
     938                 :           0 :                 failed = 1;
     939                 :             :             }
     940         [ -  + ]:         651 :             else if (0 > MolfileV3000ReadField(&fz, MOL_FMT_DOUBLE_DATA, &p))
     941                 :             :             {
     942                 :           0 :                 failed = 1;
     943                 :             :             }
     944         [ -  + ]:         651 :             else if (0 > MolfileV3000ReadField(&aamap, MOL_FMT_INT_DATA, &p))
     945                 :             :             {
     946                 :           0 :                 failed = 1;
     947                 :             :             }
     948                 :             : 
     949         [ -  + ]:         651 :             if (failed)
     950                 :             :             {
     951                 :             : 
     952                 :           0 :                 err = 4;
     953         [ #  # ]:           0 :                 TREAT_ERR(err, 4, "Cannot interpret V3000 atom block line:"); /* djb-rwth: addressing coverity ID #499547 -- TREAT_ERR properly used */
     954                 :           0 :                 dotify_non_printable_chars(line);
     955                 :           0 :                 AddErrorMessage(pStrErr, line);
     956                 :             : 
     957         [ #  # ]:           0 :                 if (!strcmp(line, SD_FMT_END_OF_DATA))
     958                 :             :                 {
     959                 :           0 :                     err = -abs(err);
     960                 :           0 :                     break;
     961                 :             :                 }
     962                 :           3 :                 continue; /* can't interpret a first half of atom block line */
     963                 :             :             }
     964                 :             : 
     965                 :             :             /* emulate V2000 coordinates substring */
     966         [ +  - ]:         651 :             if (ctab->coords)
     967                 :             :             {
     968                 :             :                 char szcoords[40];
     969                 :             : #ifdef GHI100_FIX
     970                 :             : #if (SPRINTF_FLAG == 2)
     971                 :             :                 if (fxs)
     972                 :             :                 {
     973                 :             :                     rfxs = dbl2int(fxs, 10, -1, 'g', fx);
     974                 :             :                 }
     975                 :             :                 if (fys)
     976                 :             :                 {
     977                 :             :                     rfys = dbl2int(fys, 10, -1, 'g', fy);
     978                 :             :                 }
     979                 :             :                 if (fzs)
     980                 :             :                 {
     981                 :             :                     rfzs = dbl2int(fzs, 10, -1, 'g', fz);
     982                 :             :                 }
     983                 :             :                 if ((rfxs >= 0) && (rfys >= 0) && (rfzs >= 0))
     984                 :             :                 {
     985                 :             :                     sprintf(szcoords, "%s%s%s", fxs, fys, fzs);
     986                 :             :                 }
     987                 :             :                 else
     988                 :             :                 {
     989                 :             :                     failed = 1;
     990                 :             :                 }
     991                 :             :                 inchi_free(fxs);
     992                 :             :                 inchi_free(fys);
     993                 :             :                 inchi_free(fzs);
     994                 :             : #elif (SPRINTF_FLAG == 2)
     995                 :             :                 stbsp_sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
     996                 :             : #else
     997                 :             :                 sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
     998                 :             : #endif
     999                 :             : #endif
    1000                 :         651 :                 sprintf(szcoords, "%10g%10g%10g", fx, fy, fz);
    1001                 :         651 :                 strcpy(ctab->coords[i], szcoords);
    1002                 :             :             }
    1003                 :             : 
    1004         [ +  + ]:         651 :             if (!strcmp(symbol, "*"))
    1005                 :             :             {
    1006                 :             :                 /* ignore star atoms but save index info */
    1007                 :           3 :                 ctab->v3000->atom_index_orig[i] = index;
    1008                 :           3 :                 ctab->v3000->atom_index_fin[i] = -1;
    1009                 :           3 :                 ctab->v3000->n_star_atoms++;
    1010                 :           3 :                 continue;
    1011                 :             :             }
    1012                 :             : 
    1013                 :         648 :             ctab->v3000->n_non_star_atoms++;
    1014                 :         648 :             ctab->v3000->atom_index_orig[i] = index;
    1015                 :         648 :             ctab->v3000->atom_index_fin[i] = ctab->v3000->n_non_star_atoms;
    1016                 :         648 :             ii = ctab->v3000->n_non_star_atoms - 1;
    1017                 :             : 
    1018                 :         648 :             mystrncpy(ctab->atoms[ii].symbol, symbol, sizeof(ctab->atoms[ii].symbol));
    1019   [ +  +  -  + ]:         648 :             if (2 == strlen(ctab->atoms[ii].symbol) && isupper(UCINT ctab->atoms[ii].symbol[1]))
    1020                 :             :             {
    1021                 :           0 :                 ctab->atoms[ii].symbol[1] = (char)tolower(UCINT ctab->atoms[ii].symbol[1]); /* 5-4-99 DCh*/
    1022                 :             :             }
    1023                 :         648 :             ctab->atoms[ii].fx = fx;
    1024                 :         648 :             ctab->atoms[ii].fy = fy;
    1025                 :         648 :             ctab->atoms[ii].fz = fz;
    1026                 :             : 
    1027                 :             :             /* Read key-val pairs if any */
    1028   [ +  +  +  - ]:         777 :             while (p && (len = MolfileV3000ReadKeyword(field, &p)) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    1029                 :             :             {
    1030                 :             : 
    1031                 :             :                 int itmp;
    1032                 :             :                 char ctmp;
    1033                 :             :                 char stmp[MOL_FMT_V3000_MAXFIELDLEN];
    1034                 :             : 
    1035                 :         129 :                 failed = 0;
    1036         [ +  + ]:         129 :                 if (!strcmp(field, "CHG"))
    1037                 :             :                 {
    1038         [ -  + ]:          16 :                     if (0 > MolfileV3000ReadField(&ctab->atoms[ii].charge, MOL_FMT_CHAR_INT_DATA, &p))
    1039                 :             :                     {
    1040                 :           0 :                         failed = 1;
    1041                 :             :                     }
    1042                 :             :                 }
    1043         [ -  + ]:         113 :                 else if (!strcmp(field, "RAD"))
    1044                 :             :                 {
    1045         [ #  # ]:           0 :                     if (0 > MolfileV3000ReadField(&ctab->atoms[ii].radical, MOL_FMT_CHAR_INT_DATA, &p))
    1046                 :             :                     {
    1047                 :           0 :                         failed = 1;
    1048                 :             :                     }
    1049                 :             :                 }
    1050         [ +  + ]:         113 :                 else if (!strcmp(field, "CFG"))
    1051                 :             :                 {
    1052         [ -  + ]:         110 :                     if (0 > MolfileV3000ReadField(&ctab->atoms[ii].stereo_parity, MOL_FMT_CHAR_INT_DATA, &p))
    1053                 :             :                     {
    1054                 :           0 :                         failed = 1;
    1055                 :             :                     }
    1056                 :             :                 }
    1057                 :             : 
    1058         [ -  + ]:           3 :                 else if (!strcmp(field, "MASS"))
    1059                 :             :                 {
    1060                 :             :                     /*
    1061                 :             :                         Default = natural abundance
    1062                 :             :                         A specified value indicates the absolute
    1063                 :             :                         atomic weight of the designated atom.
    1064                 :             :                     */
    1065                 :             :                     S_SHORT iso_mass;
    1066         [ #  # ]:           0 :                     if (0 > MolfileV3000ReadField(&iso_mass, MOL_FMT_SHORT_INT_DATA, &p))
    1067                 :             :                     {
    1068                 :           0 :                         failed = 1;
    1069                 :           0 :                         TREAT_ERR(err, 0, "Isotopic data not recognized:");
    1070                 :           0 :                         AddErrorMessage(pStrErr, line);
    1071                 :             :                         /* ignore isotopic error for now */
    1072                 :             :                     }
    1073                 :             :                     else
    1074                 :             :                     {
    1075                 :             :                         /*  What we read is an absolute isotopic mass, by V3000 spec.
    1076                 :             :                             Adjust this to old convention for further processing:
    1077                 :             :                             set 'ctab->atoms[ii].mass_difference' to 127
    1078                 :             :                             if isotopic mass is the same as element mass
    1079                 :             :                             in Periodic Table (rounded avg by all isotopes), 'atw'
    1080                 :             :                             delta otherwise, the value of difference 'delta' = ( isotopic mass - 'atw')
    1081                 :             :                         */
    1082                 :             :                         int atw, delta;
    1083                 :           0 :                         atw = get_atomic_mass(ctab->atoms[ii].symbol);
    1084                 :           0 :                         delta = (int)iso_mass - atw;
    1085         [ #  # ]:           0 :                         ctab->atoms[ii].mass_difference = (char)(delta ? delta : ZERO_ATW_DIFF);
    1086                 :             :                     }
    1087                 :             :                 }
    1088                 :             : 
    1089         [ +  - ]:           3 :                 else if (!strcmp(field, "VAL"))
    1090                 :             :                 {
    1091         [ -  + ]:           3 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1092                 :             :                     {
    1093                 :           0 :                         failed = 1;
    1094                 :             :                     }
    1095                 :             :                     else
    1096                 :             :                     {
    1097                 :             :                         /* adjust to old convention: was 15 for zero, now -1 for zero */
    1098         [ -  + ]:           3 :                         if (itmp == -1)
    1099                 :             :                         {
    1100                 :           0 :                             ctmp = 15;
    1101                 :             :                         }
    1102                 :             :                         else
    1103                 :             :                         {
    1104                 :           3 :                             ctmp = (char)itmp;
    1105                 :             :                         }
    1106                 :           3 :                         ctab->atoms[ii].valence = ctmp;
    1107                 :             :                     }
    1108                 :             :                 }
    1109         [ #  # ]:           0 :                 else if (!strcmp(field, "HCOUNT"))
    1110                 :             :                 {
    1111                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1112                 :             :                     {
    1113                 :             :                         ; /* skip query-related stuff */
    1114                 :             :                     }
    1115                 :             :                 }
    1116         [ #  # ]:           0 :                 else if (!strcmp(field, "STBOX"))
    1117                 :             :                 {
    1118                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1119                 :             :                     {
    1120                 :             :                         ; /* skip for now */
    1121                 :             :                     }
    1122                 :             :                 }
    1123   [ #  #  #  # ]:           0 :                 else if (!strcmp(field, "INVRET") || !strcmp(field, "EXACHG"))
    1124                 :             :                 {
    1125                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1126                 :             :                     {
    1127                 :             :                         ; /* skip reaction-related stuff */
    1128                 :             :                     }
    1129                 :             :                 }
    1130   [ #  #  #  #  :           0 :                 else if (!strcmp(field, "SUBST") || !strcmp(field, "UNSAT") || !strcmp(field, "RBCNT"))
                   #  # ]
    1131                 :             :                 {
    1132                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1133                 :             :                     {
    1134                 :             :                         ; /* skip query-related stuff */
    1135                 :             :                     }
    1136                 :             :                 }
    1137         [ #  # ]:           0 :                 else if (!strcmp(field, "ATTCHPT"))
    1138                 :             :                 {
    1139                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1140                 :             :                     {
    1141                 :             :                         ;
    1142                 :             :                     }
    1143                 :             :                 }
    1144         [ #  # ]:           0 :                 else if (!strcmp(field, "RGROUPS"))
    1145                 :             :                 {
    1146                 :           0 :                     if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
    1147                 :             :                     {
    1148                 :             :                         ;
    1149                 :             :                     }
    1150                 :             :                 }
    1151         [ #  # ]:           0 :                 else if (!strcmp(field, "ATTCHORD"))
    1152                 :             :                 {
    1153                 :           0 :                     if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
    1154                 :             :                     {
    1155                 :             :                         ;
    1156                 :             :                     }
    1157                 :             :                 }
    1158         [ #  # ]:           0 :                 else if (!strcmp(field, "CLASS"))
    1159                 :             :                 {
    1160                 :           0 :                     if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
    1161                 :             :                     {
    1162                 :             :                         ;
    1163                 :             :                     }
    1164                 :             :                 }
    1165         [ #  # ]:           0 :                 else if (!strcmp(field, "SEQID"))
    1166                 :             :                 {
    1167                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1168                 :             :                     {
    1169                 :             :                         ;
    1170                 :             :                     }
    1171                 :             :                 }
    1172                 :             : 
    1173         [ -  + ]:         129 :                 if (failed)
    1174                 :             :                 {
    1175                 :           0 :                     err = 4;
    1176         [ #  # ]:           0 :                     TREAT_ERR(err, 4, "Cannot interpret V3000 atom block key-value pair");
    1177                 :           0 :                     dotify_non_printable_chars(line);
    1178                 :           0 :                     AddErrorMessage(pStrErr, line);
    1179                 :             : 
    1180         [ #  # ]:           0 :                     if (!strcmp(line, SD_FMT_END_OF_DATA))
    1181                 :             :                     {
    1182                 :           0 :                         err = -abs(err);
    1183                 :           0 :                         break;
    1184                 :             :                     }
    1185                 :           0 :                     continue;
    1186                 :             :                 }
    1187                 :             :             }
    1188                 :             :         } /* if ( NULL != ctab->atoms )  */
    1189                 :             :     } /* for ( i = 0; i < ctab->n_atoms; i++ )  */
    1190                 :             : 
    1191         [ +  + ]:          57 :     if (ctab->v3000->n_star_atoms)
    1192                 :             :     {
    1193                 :           2 :         AddErrorMessage(pStrErr, "V3000 star atoms ignored if MolecularInorganics or NPZz parameter not used");        /* @nnuk : when using /MolecularInorganics or /NPZz, star atoms will not be ignored */
    1194                 :           2 :         ctab->n_atoms = ctab->v3000->n_non_star_atoms;
    1195                 :             :     }
    1196                 :             : 
    1197                 :             :     /* Check for proper finish */
    1198                 :             : 
    1199                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1200                 :          57 :     inchi_strbuf_reset(pin);
    1201                 :             : 
    1202                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1203                 :             : 
    1204         [ -  + ]:          57 :     if (nc < 1)
    1205                 :             :     {
    1206                 :           0 :         p = NULL;
    1207                 :             :     }
    1208                 :             :     else
    1209                 :             :     {
    1210                 :          57 :         p = line = pin->pStr;
    1211                 :             :     }
    1212   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "END ATOM"))
    1213                 :             :     {
    1214         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Atom block end marker");
    1215                 :             :     }
    1216                 :          57 :     remove_one_lf(line);
    1217                 :             : 
    1218                 :          57 : err_fin:
    1219                 :          57 :     inchi_strbuf_close(pin);
    1220                 :             : 
    1221                 :          57 :     return err;
    1222                 :             : }
    1223                 :             : 
    1224                 :             : /****************************************************************************
    1225                 :             :  Read V3000 bonds
    1226                 :             : ****************************************************************************/
    1227                 :          57 : int MolfileV3000ReadBondsBlock(MOL_FMT_CTAB *ctab,
    1228                 :             :                                INCHI_IOSTREAM *inp_file,
    1229                 :             :                                int err,
    1230                 :             :                                char *pStrErr)
    1231                 :             : {
    1232                 :             :     int i;
    1233                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
    1234                 :             :     int nc;
    1235                 :          57 :     char *p = NULL, *line = NULL;
    1236                 :             :     INCHI_IOSTREAM tmpin;
    1237                 :          57 :     INCHI_IOS_STRING *pin = &tmpin.s;
    1238                 :             : 
    1239         [ -  + ]:          57 :     if (!ctab->n_bonds)
    1240                 :             :     {
    1241                 :           0 :         return 0;
    1242                 :             :     }
    1243                 :          57 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
    1244                 :             : 
    1245                 :             :     /* Check for proper start */
    1246                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1247                 :             : 
    1248                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1249                 :             : 
    1250         [ -  + ]:          57 :     if (nc < 1)
    1251                 :             :     {
    1252                 :           0 :         p = NULL;
    1253                 :             :     }
    1254                 :             :     else
    1255                 :             :     {
    1256                 :          57 :         p = line = pin->pStr;
    1257                 :             :     }
    1258   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "BEGIN BOND"))
    1259                 :             :     {
    1260         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Bond block start marker");
    1261                 :             :     }
    1262                 :          57 :     remove_one_lf(line);
    1263                 :             : 
    1264                 :          57 :     ctab->v3000->n_haptic_bonds = 0;
    1265                 :          57 :     ctab->v3000->n_non_haptic_bonds = 0;
    1266                 :             : 
    1267         [ +  + ]:         662 :     for (i = 0; i < ctab->n_bonds; i++)
    1268                 :             :     {
    1269                 :         605 :         int is_haptic = 0;
    1270                 :             : 
    1271                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1272                 :         605 :         inchi_strbuf_reset(pin);
    1273                 :             : 
    1274                 :         605 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1275                 :             : 
    1276         [ -  + ]:         605 :         if (nc < 1)
    1277                 :             :         {
    1278                 :           0 :             p = NULL;
    1279                 :             :         }
    1280                 :             :         else
    1281                 :             :         {
    1282                 :         605 :             p = line = pin->pStr;
    1283                 :             :         }
    1284         [ -  + ]:         605 :         if (!p)
    1285                 :             :         {
    1286         [ #  # ]:           0 :             if (!err)
    1287                 :             :             {
    1288         [ #  # ]:           0 :                 TREAT_ERR(err, 2, "Cannot read V3000 bond block line"); /* djb-rwth: addressing coverity ID #499565 -- TREAT_ERR properly used */
    1289                 :             :             }
    1290                 :           0 :             break;
    1291                 :             :         }
    1292                 :         605 :         remove_one_lf(line);
    1293                 :             : 
    1294         [ -  + ]:         605 :         if (err)
    1295                 :             :         {
    1296         [ #  # ]:           0 :             if (!strcmp(line, SD_FMT_END_OF_DATA))
    1297                 :             :             {
    1298                 :           0 :                 err = -abs(err);
    1299                 :           0 :                 break;
    1300                 :             :             }
    1301                 :           0 :             continue;
    1302                 :             :         }
    1303                 :             : 
    1304         [ +  - ]:         605 :         if (ctab->bonds)
    1305                 :             :         {
    1306                 :             :             int index, n_orig_at, len;
    1307                 :         605 :             short int atnum1 = -1, atnum2 = -1;
    1308                 :         605 :             char bond_type = 0, stereo = 0;
    1309                 :         605 :             int failed = 0;
    1310                 :             :             /* djb-rwth: removing redundant variables */
    1311                 :             : 
    1312                 :         605 :             n_orig_at = ctab->v3000->n_non_star_atoms + ctab->v3000->n_star_atoms;
    1313                 :             : 
    1314                 :             :             /* read positional parameters */
    1315         [ -  + ]:         605 :             if (0 > MolfileV3000ReadField(&index, MOL_FMT_INT_DATA, &p))
    1316                 :             :             {
    1317                 :           0 :                 failed = 1;
    1318                 :             :             }
    1319         [ -  + ]:         605 :             else if (0 > MolfileV3000ReadField(&bond_type, MOL_FMT_CHAR_INT_DATA, &p))
    1320                 :             :             {
    1321                 :           0 :                 failed = 1;
    1322                 :             :             }
    1323         [ -  + ]:         605 :             else if (0 > MolfileV3000ReadField(&atnum1, MOL_FMT_SHORT_INT_DATA, &p))
    1324                 :             :             {
    1325                 :           0 :                 failed = 1;
    1326                 :             :             }
    1327         [ -  + ]:         605 :             else if (0 > MolfileV3000ReadField(&atnum2, MOL_FMT_SHORT_INT_DATA, &p))
    1328                 :             :             {
    1329                 :           0 :                 failed = 1;
    1330                 :             :             }
    1331                 :             : 
    1332                 :        1210 :             atnum1 = get_actual_atom_number(atnum1, n_orig_at,
    1333                 :         605 :                                             ctab->v3000->atom_index_orig,
    1334                 :         605 :                                             ctab->v3000->atom_index_fin);
    1335                 :             : 
    1336                 :        1210 :             atnum2 = get_actual_atom_number(atnum2, n_orig_at,
    1337                 :         605 :                                             ctab->v3000->atom_index_orig,
    1338                 :         605 :                                             ctab->v3000->atom_index_fin);
    1339                 :             : 
    1340   [ -  +  -  - ]:         605 :             if ((atnum1 < 0) && (atnum2 < 0))
    1341                 :             :             {
    1342                 :           0 :                 failed = 1;
    1343                 :             :             }
    1344                 :             :             /* djb-rwth: removing redundant code */
    1345                 :             : 
    1346         [ -  + ]:         605 :             if (failed)
    1347                 :             :             {
    1348                 :             : 
    1349         [ #  # ]:           0 :                 if (!err)
    1350                 :             :                 {
    1351                 :             :                     /* can't interpret bonds block line */
    1352         [ #  # ]:           0 :                     TREAT_ERR(err, 4, "Cannot interpret V3000 bond block line:");
    1353                 :           0 :                     dotify_non_printable_chars(line);
    1354                 :           0 :                     AddErrorMessage(pStrErr, line);
    1355                 :             :                 }
    1356         [ #  # ]:           0 :                 if (!strcmp(line, SD_FMT_END_OF_DATA))
    1357                 :             :                 {
    1358                 :           0 :                     err = -abs(err);
    1359                 :           0 :                     break;
    1360                 :             :                 }
    1361                 :             :             }
    1362                 :             : 
    1363                 :             :             /* TODO: treat new bond types  9 10 */
    1364                 :             :             /* read key-val pairs if any */
    1365   [ +  +  +  - ]:         791 :             while (p && (len = MolfileV3000ReadKeyword(field, &p)) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    1366                 :             :             {
    1367                 :             : 
    1368                 :             :                 int itmp;
    1369                 :             :                 char stmp[MOL_FMT_V3000_MAXFIELDLEN];
    1370                 :         186 :                 failed = 0;
    1371                 :             : 
    1372         [ +  + ]:         186 :                 if (!strcmp(field, "CFG"))
    1373                 :             :                 {
    1374         [ -  + ]:         181 :                     if (0 > MolfileV3000ReadField(&stereo, MOL_FMT_CHAR_INT_DATA, &p))
    1375                 :             :                     {
    1376                 :           0 :                         failed = 1;
    1377                 :             :                     }
    1378                 :             :                     else
    1379                 :             :                     {
    1380                 :             :                         /*    adjust stereo to old convention for wedges which was:
    1381                 :             :                                 0 = not stereo, 1 = Up,  4 = Either, 6 = Down
    1382                 :             :                             now:
    1383                 :             :                                 0 = none (default), 1 = up, 2 = either, 3 = down
    1384                 :             :                         */
    1385         [ -  + ]:         181 :                         if (stereo == 2)
    1386                 :             :                         {
    1387                 :           0 :                             stereo = 4;
    1388                 :             :                         }
    1389         [ +  + ]:         181 :                         else if (stereo == 3)
    1390                 :             :                         {
    1391                 :          32 :                             stereo = 6;
    1392                 :             :                         }
    1393                 :             :                     }
    1394                 :             :                 }
    1395         [ -  + ]:           5 :                 else if (!strcmp(field, "TOPO"))
    1396                 :             :                 {
    1397                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1398                 :             :                     {
    1399                 :             :                         ; /* skip query-related stuff */
    1400                 :             :                     }
    1401                 :             :                 }
    1402         [ -  + ]:           5 :                 else if (!strcmp(field, "RXCTR"))
    1403                 :             :                 {
    1404                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1405                 :             :                     {
    1406                 :             :                         ; /* skip reaction-related stuff */
    1407                 :             :                     }
    1408                 :             :                 }
    1409         [ -  + ]:           5 :                 else if (!strcmp(field, "STBOX"))
    1410                 :             :                 {
    1411                 :           0 :                     if (0 > MolfileV3000ReadField(&itmp, MOL_FMT_INT_DATA, &p))
    1412                 :             :                     {
    1413                 :             :                         ; /* skip for now */
    1414                 :             :                     }
    1415                 :             :                 }
    1416         [ +  + ]:           5 :                 else if (!strcmp(field, "ENDPTS"))
    1417                 :             :                 {
    1418                 :           3 :                     int res, *num_list = NULL;
    1419         [ -  + ]:           3 :                     if (0 > MolfileV3000ReadHapticBond(ctab, &p, &num_list, pStrErr))
    1420                 :             :                     {
    1421                 :           0 :                         failed = 1;
    1422                 :             :                     }
    1423         [ -  + ]:           3 :                     else if (!num_list)
    1424                 :             :                     {
    1425                 :           0 :                         failed = 1;
    1426                 :             :                     }
    1427                 :             :                     else
    1428                 :             :                     {
    1429                 :           3 :                         int existent_atom = atnum1;
    1430         [ -  + ]:           3 :                         if (existent_atom < 0)
    1431                 :             :                         {
    1432                 :           0 :                             existent_atom = atnum2;
    1433                 :             :                         }
    1434         [ -  + ]:           3 :                         if (existent_atom < 0) /* should not be here */
    1435                 :             :                          {
    1436                 :           0 :                             failed = 1;
    1437                 :             :                         }
    1438                 :             :                         else
    1439                 :             :                         {
    1440                 :             :                             int k, nnum;
    1441                 :           3 :                             nnum = num_list[2];
    1442                 :           3 :                             num_list[1] = existent_atom;
    1443         [ +  + ]:          15 :                             for (k = 3; k < nnum + 3; k++)              /* @nnuk : wrong mapping of endpoints (+3 added for full endpoints mapping for all haptic bonds) */
    1444                 :             :                             {
    1445                 :          12 :                                 num_list[k] = get_actual_atom_number(num_list[k],
    1446                 :             :                                                                      n_orig_at,
    1447                 :          12 :                                                                      ctab->v3000->atom_index_orig,
    1448                 :          12 :                                                                      ctab->v3000->atom_index_fin);
    1449                 :             :                             }
    1450                 :           3 :                             res = NumLists_Append(ctab->v3000->haptic_bonds, num_list);
    1451         [ -  + ]:           3 :                             if (res < 0)
    1452                 :             :                             {
    1453                 :           0 :                                 failed = 1;
    1454                 :             :                             }
    1455                 :             :                             else
    1456                 :             :                             {
    1457                 :           3 :                                 is_haptic = 1;
    1458                 :             :                             }
    1459                 :             :                         }
    1460                 :             :                     }
    1461                 :             :                     /* djb-rwth: addressing coverity ID #499489 -- false positive as num_atoms allocated in MolfileV3000ReadHapticBond and returns a value in this block */
    1462                 :             :                 }
    1463         [ +  - ]:           2 :                 else if (!strcmp(field, "DISP"))
    1464                 :             :                 {
    1465                 :           2 :                     if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
    1466                 :             :                     {
    1467                 :             :                         ;
    1468                 :             :                     }
    1469                 :             :                 }
    1470         [ #  # ]:           0 :                 else if (!strcmp(field, "ATTACH"))
    1471                 :             :                 {
    1472                 :           0 :                     if (0 > MolfileV3000ReadField(&stmp, MOL_FMT_STRING_DATA, &p))
    1473                 :             :                     {
    1474                 :             :                         ;
    1475                 :             :                     }
    1476                 :             :                 }
    1477                 :             : 
    1478         [ -  + ]:         186 :                 if (failed)
    1479                 :             :                 {
    1480         [ #  # ]:           0 :                     if (!err)
    1481                 :             :                     {
    1482                 :             :                         /* can't interpret bonds block line */
    1483         [ #  # ]:           0 :                         TREAT_ERR(err, 4, "Cannot interpret V3000 bond block line:");
    1484                 :           0 :                         dotify_non_printable_chars(line);
    1485                 :           0 :                         AddErrorMessage(pStrErr, line);
    1486                 :             :                     }
    1487         [ #  # ]:           0 :                     if (!strcmp(line, SD_FMT_END_OF_DATA))
    1488                 :             :                     {
    1489                 :           0 :                         err = -abs(err);
    1490                 :           0 :                         break;
    1491                 :             :                     }
    1492                 :             :                 }
    1493                 :             :             } /* while ( p && (len=MolfileV3000ReadKeyword(field, &p)) > 0 ) */
    1494                 :             : 
    1495         [ +  + ]:         605 :             if (is_haptic)
    1496                 :           3 :             {
    1497                 :           3 :                 int ii = ctab->v3000->n_haptic_bonds;
    1498                 :           3 :                 ctab->v3000->haptic_bonds->lists[ii][0] = bond_type;
    1499                 :           3 :                 ctab->v3000->n_haptic_bonds++;
    1500                 :           3 :                 continue;
    1501                 :             :             }
    1502                 :             :             else
    1503                 :             :             {
    1504                 :         602 :                 int ii = ctab->v3000->n_non_haptic_bonds;
    1505                 :         602 :                 ctab->bonds[ii].atnum1 = atnum1;
    1506                 :         602 :                 ctab->bonds[ii].atnum2 = atnum2;
    1507                 :         602 :                 ctab->bonds[ii].bond_type = bond_type;
    1508                 :         602 :                 ctab->bonds[ii].bond_stereo = stereo;
    1509                 :         602 :                 ctab->v3000->n_non_haptic_bonds++;
    1510                 :             :             }
    1511                 :             :         } /* if ctab->bonds */
    1512                 :             :     } /* for ( i = 0; i < ctab->n_bonds; i++ )  */
    1513                 :             : 
    1514         [ +  + ]:          57 :     if (ctab->v3000->n_haptic_bonds)
    1515                 :             :     {
    1516                 :           2 :         AddErrorMessage(pStrErr, "V3000 haptic bonds read/stored and ignored if MolecularInorganics or NPZz parameter is not used");    /* @nnuk : when using /MolecularInorganics or /NPZz, haptic bonds will not be ignored */
    1517                 :           2 :         ctab->n_bonds = ctab->v3000->n_non_haptic_bonds;
    1518                 :             :     }
    1519                 :             : 
    1520                 :             :     /* Check for proper finish */
    1521                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1522                 :          57 :     inchi_strbuf_reset(pin);
    1523                 :             : 
    1524                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1525                 :             : 
    1526         [ -  + ]:          57 :     if (nc < 1)
    1527                 :             :     {
    1528                 :           0 :         p = NULL;
    1529                 :             :     }
    1530                 :             :     else
    1531                 :             :     {
    1532                 :          57 :         p = line = pin->pStr;
    1533                 :             :     }
    1534   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "END BOND"))
    1535                 :             :     {
    1536         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 Bond block end marker");
    1537                 :             :     }
    1538                 :          57 :     remove_one_lf(line);
    1539                 :             : 
    1540                 :          57 : err_fin:
    1541                 :             : 
    1542                 :          57 :     inchi_ios_close(&tmpin); /* ricrogz: fixing memory leak */
    1543                 :          57 :     return err;
    1544                 :             : }
    1545                 :             : 
    1546                 :             : /****************************************************************************
    1547                 :             :  Convert atom index to the final consequitive atom number (starting from 1)
    1548                 :             :  Returns -1 for star atom or not found index
    1549                 :             : ****************************************************************************/
    1550                 :        1246 : int get_actual_atom_number(int index, int n, int *orig, int *fin)
    1551                 :             : {
    1552                 :             :     int i;
    1553         [ +  - ]:       14523 :     for (i = 0; i < n; i++)
    1554                 :             :     {
    1555         [ +  + ]:       14523 :         if (orig[i] == index)
    1556                 :             :         {
    1557                 :        1246 :             return fin[i];
    1558                 :             :         }
    1559                 :             :     }
    1560                 :             : 
    1561                 :           0 :     return -1;
    1562                 :             : }
    1563                 :             : 
    1564                 :             : /****************************************************************************
    1565                 :             :  Read V3000 tail of CTab
    1566                 :             : ****************************************************************************/
    1567                 :          57 : int MolfileV3000ReadTailOfCTAB(MOL_FMT_CTAB *ctab,
    1568                 :             :                                INCHI_IOSTREAM *inp_file,
    1569                 :             :                                int err,
    1570                 :             :                                char *pStrErr)
    1571                 :             : {
    1572                 :          57 :     int retcode = err;
    1573                 :             :     int nc;
    1574                 :          57 :     char *p = NULL, *line = NULL;
    1575                 :             :     INCHI_IOSTREAM tmpin;
    1576                 :          57 :     INCHI_IOS_STRING *pin = &tmpin.s;
    1577                 :          57 :     inchi_ios_init(&tmpin, INCHI_IOS_TYPE_STRING, NULL);
    1578                 :             : 
    1579                 :             :     /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1580                 :             : 
    1581                 :          57 :     nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1582                 :             : 
    1583         [ -  + ]:          57 :     if (nc < 1)
    1584                 :             :     {
    1585                 :           0 :         p = NULL;
    1586                 :             :     }
    1587                 :             :     else
    1588                 :             :     {
    1589                 :          57 :         p = line = pin->pStr;
    1590                 :             :     }
    1591                 :          57 :     remove_one_lf(line);
    1592                 :             : 
    1593   [ +  -  -  + ]:          57 :     if (p && !strcmp(p, "BEGIN SGROUP"))
    1594                 :             :     {
    1595                 :           0 :         retcode = MolfileV3000ReadSGroup(ctab, inp_file, retcode, pStrErr);
    1596         [ #  # ]:           0 :         if (retcode)
    1597                 :             :         {
    1598                 :           0 :             retcode += 70;
    1599         [ #  # ]:           0 :             TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
    1600                 :             :         }
    1601                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1602                 :           0 :         inchi_strbuf_reset(pin);
    1603                 :           0 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1604         [ #  # ]:           0 :         if (nc < 1)
    1605                 :             :         {
    1606                 :           0 :             p = NULL;
    1607                 :             :         }
    1608                 :             :         else
    1609                 :             :         {
    1610                 :           0 :             p = line = pin->pStr;
    1611                 :           0 :             remove_one_lf(line);
    1612                 :             :         }
    1613                 :             :     }
    1614                 :             : 
    1615   [ +  -  -  + ]:          57 :     if (p && !strcmp(p, "BEGIN OBJ3D"))
    1616                 :             :     {
    1617                 :           0 :         retcode = MolfileV3000Read3DBlock(ctab, inp_file, retcode, pStrErr);
    1618         [ #  # ]:           0 :         if (retcode)
    1619                 :             :         {
    1620                 :           0 :             retcode += 70;
    1621         [ #  # ]:           0 :             TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
    1622                 :             :         }
    1623                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1624                 :           0 :         inchi_strbuf_reset(pin);
    1625                 :             : 
    1626                 :           0 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1627         [ #  # ]:           0 :         if (nc < 1)
    1628                 :             :         {
    1629                 :           0 :             p = NULL;
    1630                 :             :         }
    1631                 :             :         else
    1632                 :             :         {
    1633                 :           0 :             p = line = pin->pStr;
    1634                 :           0 :             remove_one_lf(line);
    1635                 :             :         }
    1636                 :             :     }
    1637                 :             : 
    1638   [ +  -  -  + ]:          57 :     while (p && !strcmp(p, "LINKNODE"))
    1639                 :             :     {
    1640                 :             :         /* skip for now */
    1641                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1642                 :           0 :         inchi_strbuf_reset(pin);
    1643                 :             : 
    1644                 :           0 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1645         [ #  # ]:           0 :         if (nc < 1)
    1646                 :             :         {
    1647                 :           0 :             p = NULL;
    1648                 :             :         }
    1649                 :             :         else
    1650                 :             :         {
    1651                 :           0 :             p = line = pin->pStr;
    1652                 :           0 :             remove_one_lf(line);
    1653                 :             :         }
    1654                 :             :     }
    1655                 :             : 
    1656                 :             :     /* Collections */
    1657   [ +  -  +  + ]:          94 :     while (p && !strcmp(p, "BEGIN COLLECTION"))
    1658                 :             :     {
    1659                 :          37 :         retcode = MolfileV3000ReadCollections(ctab, inp_file, retcode, pStrErr);
    1660         [ -  + ]:          37 :         if (retcode)
    1661                 :             :         {
    1662                 :           0 :             retcode += 70;
    1663         [ #  # ]:           0 :             TREAT_ERR_AND_FIN(retcode, 1, err_fin, pStrErr);
    1664                 :             :         }
    1665                 :             :         /*p = inchi_fgetsLf_V3000( line, inp_file );*/
    1666                 :          37 :         inchi_strbuf_reset(pin);
    1667                 :             : 
    1668                 :          37 :         nc = get_V3000_input_line_to_strbuf(pin, inp_file);
    1669                 :             : 
    1670         [ -  + ]:          37 :         if (nc < 1)
    1671                 :             :         {
    1672                 :           0 :             p = NULL;
    1673                 :             :         }
    1674                 :             :         else
    1675                 :             :         {
    1676                 :          37 :             p = line = pin->pStr;
    1677                 :          37 :             remove_one_lf(line);
    1678                 :             :         }
    1679                 :             :     }
    1680                 :             : 
    1681   [ +  -  -  + ]:          57 :     if (!p || strcmp(p, "END CTAB"))
    1682                 :             :     {
    1683         [ #  # ]:           0 :         TREAT_ERR_AND_FIN(err, 1, err_fin, "Error: No V3000 CTAB end marker");
    1684                 :             :     }
    1685                 :             : 
    1686                 :          57 :     remove_one_lf(line);
    1687                 :             : 
    1688                 :          57 : err_fin:
    1689                 :          57 :     inchi_strbuf_close(pin);
    1690                 :             : 
    1691                 :          57 :     return err;
    1692                 :             : }
    1693                 :             : 
    1694                 :             : /****************************************************************************
    1695                 :             :  Read haptic bond info
    1696                 :             : ****************************************************************************/
    1697                 :           3 : int MolfileV3000ReadHapticBond(MOL_FMT_CTAB *ctab,
    1698                 :             :                                char **line_ptr,
    1699                 :             :                                int **num_list,
    1700                 :             :                                char *pStrErr)
    1701                 :             : {
    1702                 :           3 :     int nread = 0;
    1703                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
    1704                 :           3 :     const int max_field_len = sizeof(field);
    1705                 :             :     char *p_end;
    1706                 :           3 :     int i, nnum = 0;
    1707                 :             : 
    1708                 :           3 :     *num_list = NULL;
    1709                 :             : 
    1710                 :           3 :     memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
    1711                 :             : 
    1712                 :           3 :     nread = read_upto_delim(line_ptr, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    1713         [ -  + ]:           3 :     if (strcmp(field, "("))
    1714                 :             :     {
    1715                 :           0 :         return -1;
    1716                 :             :     }
    1717                 :             : 
    1718                 :           3 :     nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    1719                 :             : 
    1720                 :           3 :     nnum = strtol(field, &p_end, 10);
    1721                 :             : 
    1722         [ -  + ]:           3 :     if (p_end == field)
    1723                 :             :     {
    1724                 :           0 :         return -1; /* paranoia */
    1725                 :             :     }
    1726         [ -  + ]:           3 :     if (nnum < 0)
    1727                 :             :     {
    1728                 :           0 :         return -1;
    1729                 :             :     }
    1730                 :             : 
    1731                 :           3 :     *num_list = (int *)inchi_calloc((long long)nnum + 3, sizeof(int)); /* djb-rwth: cast operator added */
    1732                 :             : 
    1733         [ -  + ]:           3 :     if (!*num_list)
    1734                 :             :     {
    1735                 :           0 :         nread = -1;
    1736                 :           0 :         goto ret;
    1737                 :             :     }
    1738                 :             : 
    1739                 :           3 :     (*num_list)[0] = -1; /* will be bond type, to be filled by caller */
    1740                 :           3 :     (*num_list)[1] = -1; /* will be atom number, to be filled by caller */
    1741                 :           3 :     (*num_list)[2] = nnum;
    1742                 :             : 
    1743         [ +  + ]:          15 :     for (i = 3; i < nnum + 3; i++)
    1744                 :             :     {
    1745         [ -  + ]:          12 :         if (0 > MolfileV3000ReadField(&((*num_list)[i]), MOL_FMT_INT_DATA, line_ptr))
    1746                 :             :         {
    1747                 :           0 :             nread = -1;
    1748                 :           0 :             goto ret;
    1749                 :             :         }
    1750                 :             :     }
    1751                 :             : 
    1752                 :             :     /* ')' should have been consumed  by strtol */
    1753                 :             : 
    1754                 :             :     /* check for ATTACH=ALL */
    1755                 :             : 
    1756                 :           3 :     nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
    1757         [ -  + ]:           3 :     if (nread > 0)
    1758                 :             :     {
    1759         [ +  - ]:           3 :         if (strcmp(field, "ATTACH=ALL"))
    1760                 :             :         {
    1761                 :           0 :             nread = -1;
    1762                 :           0 :             goto ret;
    1763                 :             :         }
    1764                 :             :     }
    1765                 :             : 
    1766                 :           3 : ret:
    1767         [ -  + ]:           3 :     if (nread < 0)
    1768                 :             :     {
    1769         [ #  # ]:           0 :         if (*num_list)
    1770                 :             :         {
    1771         [ #  # ]:           0 :             inchi_free(*num_list);
    1772                 :           0 :             *num_list = NULL;
    1773                 :             :         }
    1774                 :             :     }
    1775                 :             : 
    1776                 :           3 :     return nread;
    1777                 :             : }
    1778                 :             : 
    1779                 :             : /****************************************************************************
    1780                 :             :  Read V3000 stereo collection
    1781                 :             : ****************************************************************************/
    1782                 :         101 : int MolfileV3000ReadStereoCollection(MOL_FMT_CTAB *ctab,
    1783                 :             :                                      char **line_ptr,
    1784                 :             :                                      int **num_list,
    1785                 :             :                                      char *pStrErr)
    1786                 :             : {
    1787                 :         101 :     int nread = 0;
    1788                 :             :     char field[MOL_FMT_V3000_MAXFIELDLEN];
    1789                 :         101 :     const int max_field_len = sizeof(field);
    1790                 :             :     char *p_end;
    1791                 :         101 :     int i, nnum = 0;
    1792                 :             : 
    1793                 :         101 :     *num_list = NULL;
    1794                 :             : 
    1795                 :         101 :     memset(field, 0, max_field_len); /* djb-rwth: memset_s C11/Annex K variant? */
    1796                 :             : 
    1797                 :         101 :     nread = read_upto_delim(line_ptr, field, max_field_len, "1234567890 \t\n\v\f\r"); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    1798         [ -  + ]:         101 :     if (strcmp(field, "("))
    1799                 :             :     {
    1800                 :           0 :         return -1;
    1801                 :             :     }
    1802                 :             : 
    1803                 :         101 :     nread = read_upto_delim(line_ptr, field, max_field_len, " \t\n\v\f\r");
    1804                 :             : 
    1805                 :         101 :     nnum = strtol(field, &p_end, 10);
    1806                 :             : 
    1807         [ -  + ]:         101 :     if (p_end == field)
    1808                 :             :     {
    1809                 :           0 :         return -1; /* paranoia */
    1810                 :             :     }
    1811         [ -  + ]:         101 :     if (nnum < 0)
    1812                 :             :     {
    1813                 :           0 :         return -1;
    1814                 :             :     }
    1815                 :             : 
    1816                 :         101 :     *num_list = (int *)inchi_calloc((long long)nnum + 3, sizeof(int)); /* djb-rwth: cast operator added */
    1817                 :             : 
    1818         [ -  + ]:         101 :     if (!*num_list)
    1819                 :             :     {
    1820                 :           0 :         nread = -1;
    1821                 :           0 :         goto ret;
    1822                 :             :     }
    1823                 :             : 
    1824                 :         101 :     (*num_list)[0] = -1; /* reserved, may be filled by caller */
    1825                 :         101 :     (*num_list)[1] = nnum;
    1826                 :             : 
    1827         [ +  + ]:         272 :     for (i = 2; i < nnum + 2; i++)
    1828                 :             :     {
    1829         [ -  + ]:         171 :         if (0 > MolfileV3000ReadField(&((*num_list)[i]), MOL_FMT_INT_DATA, line_ptr))
    1830                 :             :         {
    1831                 :           0 :             nread = -1;
    1832                 :           0 :             goto ret;
    1833                 :             :         }
    1834                 :             :     }
    1835                 :             : 
    1836                 :             :     /* ')' should have been consumed  by strtol */
    1837                 :             : 
    1838                 :         101 : ret:
    1839         [ -  + ]:         101 :     if (nread < 0)
    1840                 :             :     {
    1841         [ #  # ]:           0 :         if (*num_list)
    1842                 :             :         {
    1843         [ #  # ]:           0 :             inchi_free(*num_list);
    1844                 :           0 :             *num_list = NULL;
    1845                 :             :         }
    1846                 :             :     }
    1847                 :             : 
    1848                 :         101 :     return nread;
    1849                 :             : }
    1850                 :             : 
    1851                 :             : /****************************************************************************
    1852                 :             :     Returns -1 @ error
    1853                 :             : ****************************************************************************/
    1854                 :        1830 : int get_V3000_input_line_to_strbuf(INCHI_IOS_STRING *buf,
    1855                 :             :                                    INCHI_IOSTREAM *inp_stream)
    1856                 :             : {
    1857                 :        1830 :     const int prefix_len = 7; /* "M  V30 " */
    1858                 :        1830 :     int old_used, crlf2lf = 1, preserve_lf = 0;
    1859                 :             : 
    1860                 :        1830 :     inchi_strbuf_reset(buf);
    1861                 :             : 
    1862                 :        1830 :     old_used = buf->nUsedLength;
    1863                 :             :     while (1)
    1864                 :             :     {
    1865                 :        1830 :         inchi_strbuf_addline(buf, inp_stream, crlf2lf, preserve_lf);
    1866                 :             : 
    1867         [ -  + ]:        1830 :         if (buf->nUsedLength - old_used < 8)
    1868                 :             :         {
    1869                 :           0 :             return -1;
    1870                 :             :         }
    1871         [ -  + ]:        1830 :         if (strncmp(buf->pStr + old_used, "M  V30 ", prefix_len))
    1872                 :             :         {
    1873                 :           0 :             return -1;
    1874                 :             :         }
    1875                 :             : 
    1876                 :        1830 :         memmove((void *)(buf->pStr + old_used), (void *)(buf->pStr + old_used + prefix_len), (long long)buf->nUsedLength - (long long)old_used - (long long)prefix_len + 1); /* djb-rwth: cast operators added */ /* ricrogz: fixing memory overflow error */
    1877                 :        1830 :         buf->nUsedLength -= prefix_len;
    1878                 :             : 
    1879         [ +  - ]:        1830 :         if (buf->pStr[buf->nUsedLength - 1] != '-')
    1880                 :             :         {
    1881                 :        1830 :             break;
    1882                 :             :         }
    1883                 :           0 :         buf->pStr[--buf->nUsedLength] = '\0';
    1884                 :             : 
    1885                 :           0 :         old_used = buf->nUsedLength;
    1886                 :             :     }
    1887                 :             : 
    1888                 :        1830 :     remove_trailing_spaces(buf->pStr);
    1889                 :        1830 :     buf->nUsedLength = strlen(buf->pStr);
    1890                 :             : 
    1891                 :        1830 :     return buf->nUsedLength;
    1892                 :             : }
        

Generated by: LCOV version 2.0-1