LCOV - code coverage report
Current view: top level - src - runichi3.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 12.7 % 1687 215
Test Date: 2026-05-04 07:05:02 Functions: 12.2 % 49 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8.9 % 1416 126

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * International Chemical Identifier (InChI)
       3                 :             :  * Version 1
       4                 :             :  * Software version 1.07
       5                 :             :  * April 30, 2024
       6                 :             :  *
       7                 :             :  * MIT License
       8                 :             :  *
       9                 :             :  * Copyright (c) 2024 IUPAC and InChI Trust
      10                 :             :  *
      11                 :             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      12                 :             :  * of this software and associated documentation files (the "Software"), to deal
      13                 :             :  * in the Software without restriction, including without limitation the rights
      14                 :             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      15                 :             :  * copies of the Software, and to permit persons to whom the Software is
      16                 :             :  * furnished to do so, subject to the following conditions:
      17                 :             :  *
      18                 :             :  * The above copyright notice and this permission notice shall be included in all
      19                 :             :  * copies or substantial portions of the Software.
      20                 :             :  *
      21                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      24                 :             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      26                 :             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      27                 :             :  * SOFTWARE.
      28                 :             : *
      29                 :             : * The InChI library and programs are free software developed under the
      30                 :             :  * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
      31                 :             :  * Originally developed at NIST.
      32                 :             :  * Modifications and additions by IUPAC and the InChI Trust.
      33                 :             :  * Some portions of code were developed/changed by external contributors
      34                 :             :  * (either contractor or volunteer) which are listed in the file
      35                 :             :  * 'External-contributors' included in this distribution.
      36                 :             :  *
      37                 :             :  * info@inchi-trust.org
      38                 :             :  *
      39                 :             : */
      40                 :             : 
      41                 :             : 
      42                 :             : /*
      43                 :             :     Pre-processing related functions
      44                 :             : 
      45                 :             : */
      46                 :             : 
      47                 :             : #include <stdlib.h>
      48                 :             : #include <string.h>
      49                 :             : #include <stdarg.h>
      50                 :             : #include <errno.h>
      51                 :             : #include <limits.h>
      52                 :             : #include <math.h>
      53                 :             : #include <ctype.h>
      54                 :             : 
      55                 :             : 
      56                 :             : #include "mode.h"
      57                 :             : #include "ichitime.h"
      58                 :             : #ifndef COMPILE_ANSI_ONLY
      59                 :             : #include <conio.h>
      60                 :             : #endif
      61                 :             : #include "ichimain.h"
      62                 :             : #include "ichi_io.h"
      63                 :             : #include "mol_fmt.h"
      64                 :             : #include "inchi_api.h"
      65                 :             : #include "readinch.h"
      66                 :             : #ifdef TARGET_LIB_FOR_WINCHI
      67                 :             : #include "../../../IChI_lib/src/ichi_lib.h"
      68                 :             : #include "inchi_api.h"
      69                 :             : #else
      70                 :             : #include "inchi_gui.h"
      71                 :             : #endif
      72                 :             : #include "readinch.h"
      73                 :             : #include "inpdef.h"
      74                 :             : #include "ichi_io.h"
      75                 :             : 
      76                 :             : #include "bcf_s.h"
      77                 :             : 
      78                 :             : /* Local prototypes */
      79                 :             : static int OrigAtData_bCheckUnusualValences(ORIG_ATOM_DATA* orig_at_data,
      80                 :             :     int bAddIsoH,
      81                 :             :     char* pStrErrStruct,
      82                 :             :     int bNoWarnings);
      83                 :             : 
      84                 :             : static void OAD_PolymerUnit_RemoveLinkFromCRUChain(int at1, int at2, int* nbonds, int** bonds);
      85                 :             : 
      86                 :             : /****************************************************************************
      87                 :             :   Check inp_ATOM's for unusual valence
      88                 :             : ****************************************************************************/
      89                 :          54 : int OrigAtData_bCheckUnusualValences(ORIG_ATOM_DATA* orig_at_data,
      90                 :             :     int bAddIsoH,
      91                 :             :     char* pStrErrStruct,
      92                 :             :     int bNoWarnings)
      93                 :             : {
      94                 :          54 :     int i, val, num_found = 0;
      95                 :             :     char msg[32];
      96                 :             :     int len, num_H;
      97                 :             : 
      98   [ +  -  +  - ]:          54 :     int already_here = (orig_at_data && orig_at_data->num_inp_atoms > 0);
      99                 :             : 
     100         [ +  - ]:          54 :     inp_ATOM* at = already_here ? orig_at_data->at : NULL;
     101                 :             : 
     102         [ +  - ]:          54 :     if ( at )
     103                 :             :     {
     104         [ +  + ]:         673 :         for ( i = 0, num_found = 0; i < orig_at_data->num_inp_atoms; i++ )
     105                 :             :         {
     106         [ +  - ]:         619 :             num_H = bAddIsoH ? NUMH(at, i) : at[i].num_H;
     107                 :             : 
     108                 :         619 :             val = detect_unusual_el_valence(at[i].el_number,
     109                 :         619 :                 at[i].charge,
     110                 :         619 :                 at[i].radical,
     111                 :         619 :                 at[i].chem_bonds_valence,
     112                 :             :                 num_H,
     113                 :         619 :                 at[i].valence);
     114         [ +  + ]:         619 :             if ( val )
     115                 :             :             {
     116                 :          13 :                 num_found++;
     117         [ +  - ]:          13 :                 if ( !bNoWarnings )
     118                 :             :                 {
     119                 :          13 :                     WarningMessage(pStrErrStruct, "Accepted unusual valence(s):");
     120                 :             :                 }
     121                 :          13 :                 len = sprintf(msg, "%s", at[i].elname);
     122         [ +  + ]:          13 :                 if ( at[i].charge )
     123                 :             :                 {
     124                 :           2 :                     len += sprintf(msg + len, "%+d", at[i].charge);
     125                 :             :                 }
     126         [ -  + ]:          13 :                 if ( at[i].radical )
     127                 :             :                 {
     128         [ #  # ]:           0 :                     len += sprintf(msg + len, ",%s", at[i].radical == RADICAL_SINGLET ? "s" :
     129         [ #  # ]:           0 :                         at[i].radical == RADICAL_DOUBLET ? "d" :
     130         [ #  # ]:           0 :                         at[i].radical == RADICAL_TRIPLET ? "t" : "?");
     131                 :             :                 }
     132                 :          13 :                 len += sprintf(msg + len, "(%d)", val);
     133         [ +  - ]:          13 :                 if ( !bNoWarnings )
     134                 :             :                 {
     135                 :          13 :                     WarningMessage(pStrErrStruct, msg);
     136                 :             :                 }
     137                 :             :             }
     138                 :             :         }
     139                 :             :     }
     140                 :             : 
     141                 :          54 :     return num_found;
     142                 :             : }
     143                 :             : 
     144                 :             : 
     145                 :             : /****************************************************************************
     146                 :             :   Make a copy of ORIG_ATOM_DATA
     147                 :             : ****************************************************************************/
     148                 :          54 : int OrigAtData_Duplicate(ORIG_ATOM_DATA* new_orig_atom,
     149                 :             :     ORIG_ATOM_DATA* orig_atom)
     150                 :             : {
     151                 :          54 :     inp_ATOM* at = NULL;
     152                 :          54 :     AT_NUMB* nCurAtLen = NULL;
     153                 :          54 :     AT_NUMB* nOldCompNumber = NULL;
     154                 :             :     int k, m, nn;
     155                 :          54 :     int orig_nat = orig_atom->num_inp_atoms;
     156                 :             : 
     157                 :          54 :     int ret = -1; /* fail; 0 - OK */
     158                 :             : 
     159         [ -  + ]:          54 :     if ( new_orig_atom->at &&
     160         [ #  # ]:           0 :         new_orig_atom->num_inp_atoms >= orig_nat )
     161                 :             :     {
     162                 :           0 :         at = new_orig_atom->at;
     163                 :             :     }
     164                 :             :     else
     165                 :             :     {
     166                 :          54 :         at = (inp_ATOM*)inchi_calloc((long long)orig_nat + 1, sizeof(at[0])); /* djb-rwth: cast operator added */
     167         [ -  + ]:          54 :         if ( !at )
     168                 :             :         {
     169                 :           0 :             goto exit_function;
     170                 :             :         }
     171                 :             :     }
     172                 :             : 
     173         [ -  + ]:          54 :     if ( new_orig_atom->nOldCompNumber &&
     174         [ #  # ]:           0 :         new_orig_atom->num_components >= orig_atom->num_components )
     175                 :             :     {
     176                 :           0 :         nCurAtLen = new_orig_atom->nCurAtLen;
     177                 :             :     }
     178                 :             :     else
     179                 :             :     {
     180                 :          54 :         nCurAtLen = (AT_NUMB*)inchi_calloc((long long)orig_atom->num_components + 1, sizeof(nCurAtLen[0])); /* djb-rwth: cast operator added */
     181         [ -  + ]:          54 :         if ( !nCurAtLen )
     182                 :             :         {
     183                 :           0 :             goto exit_function;
     184                 :             :         }
     185                 :             :     }
     186                 :             : 
     187         [ -  + ]:          54 :     if ( new_orig_atom->nCurAtLen &&
     188         [ #  # ]:           0 :         new_orig_atom->num_components >= orig_atom->num_components )
     189                 :             :     {
     190                 :           0 :         nOldCompNumber = new_orig_atom->nOldCompNumber;
     191                 :             :     }
     192                 :             :     else
     193                 :             :     {
     194                 :          54 :         nOldCompNumber = (AT_NUMB*)inchi_calloc((long long)orig_atom->num_components + 1,
     195                 :             :             sizeof(nOldCompNumber[0])); /* djb-rwth: cast operator added */
     196         [ -  + ]:          54 :         if ( !nOldCompNumber )
     197                 :             :         {
     198                 :           0 :             goto exit_function;
     199                 :             :         }
     200                 :             :     }
     201                 :             : 
     202   [ -  +  -  +  :          54 :     if ( at && nCurAtLen && nOldCompNumber )
                   -  + ]
     203                 :             :     {
     204                 :             :         /* Copy */
     205         [ +  - ]:          54 :         if ( orig_atom->at )
     206                 :             :         {
     207                 :          54 :             memcpy(at, orig_atom->at,
     208                 :             :                 orig_nat * sizeof(new_orig_atom->at[0]));
     209                 :             :         }
     210         [ -  + ]:          54 :         if ( orig_atom->nCurAtLen )
     211                 :             :         {
     212                 :           0 :             memcpy(nCurAtLen, orig_atom->nCurAtLen,
     213                 :           0 :                 orig_atom->num_components * sizeof(nCurAtLen[0]));
     214                 :             :         }
     215         [ -  + ]:          54 :         if ( orig_atom->nOldCompNumber )
     216                 :             :         {
     217                 :           0 :             memcpy(nOldCompNumber, orig_atom->nOldCompNumber,
     218                 :           0 :                 orig_atom->num_components * sizeof(nOldCompNumber[0]));
     219                 :             :         }
     220                 :             : 
     221                 :             :         /* Deallocate */
     222   [ -  +  -  - ]:          54 :         if ( new_orig_atom->at && new_orig_atom->at != at )
     223                 :             :         {
     224         [ #  # ]:           0 :             inchi_free(new_orig_atom->at);
     225                 :             :         }
     226   [ -  +  -  - ]:          54 :         if ( new_orig_atom->nCurAtLen && new_orig_atom->nCurAtLen != nCurAtLen )
     227                 :             :         {
     228         [ #  # ]:           0 :             inchi_free(new_orig_atom->nCurAtLen);
     229                 :             :         }
     230         [ -  + ]:          54 :         if ( new_orig_atom->nOldCompNumber &&
     231         [ #  # ]:           0 :             new_orig_atom->nOldCompNumber != nOldCompNumber )
     232                 :             :         {
     233         [ #  # ]:           0 :             inchi_free(new_orig_atom->nOldCompNumber);
     234                 :             :         }
     235                 :             : 
     236                 :          54 :         *new_orig_atom = *orig_atom;
     237                 :          54 :         new_orig_atom->at = at;
     238                 :          54 :         new_orig_atom->nCurAtLen = nCurAtLen;
     239                 :          54 :         new_orig_atom->nOldCompNumber = nOldCompNumber;
     240                 :             : 
     241                 :             :         /* Data that are not to be copied */
     242                 :          54 :         new_orig_atom->nNumEquSets = 0;
     243                 :          54 :         memset(new_orig_atom->bSavedInINCHI_LIB, 0, sizeof(new_orig_atom->bSavedInINCHI_LIB)); /* djb-rwth: memset_s C11/Annex K variant? */
     244                 :          54 :         memset(new_orig_atom->bPreprocessed, 0, sizeof(new_orig_atom->bPreprocessed)); /* djb-rwth: memset_s C11/Annex K variant? */
     245                 :             : 
     246                 :             : 
     247                 :             : 
     248                 :          54 :         new_orig_atom->szCoord = NULL;
     249         [ +  + ]:          54 :         if ( orig_atom->szCoord )
     250                 :             :         {
     251                 :           6 :             new_orig_atom->szCoord = (MOL_COORD*)inchi_calloc(orig_nat, sizeof(new_orig_atom->szCoord[0]));
     252         [ -  + ]:           6 :             if ( !new_orig_atom->szCoord )
     253                 :             :             {
     254                 :           0 :                 goto exit_function;
     255                 :             :             }
     256                 :           6 :             memcpy(new_orig_atom->szCoord, orig_atom->szCoord, orig_nat * sizeof(new_orig_atom->szCoord[0]));
     257                 :             :         }
     258                 :             : 
     259                 :             : 
     260                 :             :         /* Arrays that are not to be copied */
     261                 :             : 
     262                 :          54 :         new_orig_atom->nEquLabels = NULL;
     263                 :          54 :         new_orig_atom->nSortedOrder = NULL;
     264                 :             : 
     265                 :          54 :         new_orig_atom->polymer = NULL;
     266         [ -  + ]:          54 :         if ( orig_atom->polymer )
     267                 :             :         {
     268                 :             :             /* Polymer stuff -- deep copy */
     269                 :           0 :             OAD_Polymer* oldp = orig_atom->polymer;
     270                 :           0 :             OAD_Polymer* newp = NULL;
     271                 :             : 
     272                 :           0 :             newp = (OAD_Polymer*)inchi_calloc(1, sizeof(OAD_Polymer));
     273         [ #  # ]:           0 :             if ( !newp )
     274                 :             :             {
     275         [ #  # ]:           0 :                 inchi_free(newp); /* djb-rwth: avoiding memory leak */
     276                 :           0 :                 goto exit_function;
     277                 :             :             }
     278                 :           0 :             memcpy(newp, orig_atom->polymer, sizeof(OAD_Polymer));
     279                 :           0 :             newp->units = (OAD_PolymerUnit**)inchi_calloc(newp->n, sizeof(OAD_PolymerUnit*)); /* djb-rwth: inchi_calloc must return OAD_PolymerUnit** */
     280         [ #  # ]:           0 :             if ( !newp->units )
     281                 :             :             {
     282         [ #  # ]:           0 :                 inchi_free(newp); /* djb-rwth: avoiding memory leak */
     283                 :           0 :                 goto exit_function;
     284                 :             :             }
     285         [ #  # ]:           0 :             for ( k = 0; k < orig_atom->polymer->n; k++ )
     286                 :             :             {
     287                 :           0 :                 newp->units[k] = OAD_PolymerUnit_CreateCopy(orig_atom->polymer->units[k]);
     288                 :             :             }
     289         [ #  # ]:           0 :             if ( oldp->n_pzz > 0 )
     290                 :             :             {
     291                 :           0 :                 newp->n_pzz = oldp->n_pzz;
     292                 :           0 :                 newp->pzz = (int*)inchi_calloc(newp->n_pzz, sizeof(int));
     293         [ #  # ]:           0 :                 if ( !newp->pzz )
     294                 :             :                 {
     295         [ #  # ]:           0 :                     inchi_free(newp->units); /* djb-rwth: fixing coverity ID #499546 */
     296         [ #  # ]:           0 :                     inchi_free(newp); /* djb-rwth: avoiding memory leak */
     297                 :           0 :                     goto exit_function;
     298                 :             :                 }
     299                 :           0 :                 memcpy(newp->pzz, oldp->pzz, newp->n_pzz * sizeof(oldp->pzz[0]));
     300                 :             :             }
     301                 :           0 :             new_orig_atom->polymer = newp;
     302                 :             :         }
     303                 :             : 
     304                 :          54 :         new_orig_atom->v3000 = NULL;
     305         [ +  + ]:          54 :         if ( orig_atom->v3000 )
     306                 :             :         {
     307                 :             :             /* V3000 features -- deep copy */
     308                 :          48 :             OAD_V3000* new_v3000 = NULL;
     309                 :          48 :             new_v3000 = (OAD_V3000*)inchi_calloc(1, sizeof(OAD_V3000));
     310         [ -  + ]:          48 :             if ( !new_v3000 )
     311                 :             :             {
     312         [ #  # ]:           0 :                 inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     313                 :           0 :                 goto exit_function;
     314                 :             :             }
     315                 :          48 :             memcpy(new_v3000, orig_atom->v3000, sizeof(OAD_V3000));
     316         [ +  - ]:          48 :             if ( orig_atom->v3000->atom_index_orig )
     317                 :             :             {
     318                 :          48 :                 new_v3000->atom_index_orig = (int*)inchi_calloc(orig_nat, sizeof(int));
     319                 :             :                 /* if ( NULL==new_v3000->atom_index_orig ) {TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; } */
     320         [ -  + ]:          48 :                 if ( !new_v3000->atom_index_orig )
     321                 :             :                 {
     322         [ #  # ]:           0 :                     inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     323                 :           0 :                     goto exit_function;
     324                 :             :                 }
     325                 :          48 :                 memcpy(new_v3000->atom_index_orig, orig_atom->v3000->atom_index_orig, orig_nat * sizeof(int));
     326                 :             :             }
     327         [ +  - ]:          48 :             if ( orig_atom->v3000->atom_index_fin )
     328                 :             :             {
     329                 :          48 :                 new_v3000->atom_index_fin = (int*)inchi_calloc(orig_nat, sizeof(int));
     330                 :             :                 /* if ( NULL==new_v3000->atom_index_fin ) {TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; } */
     331         [ -  + ]:          48 :                 if ( !new_v3000->atom_index_fin )
     332                 :             :                 {
     333         [ #  # ]:           0 :                     inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     334                 :           0 :                     goto exit_function;
     335                 :             :                 }
     336                 :          48 :                 memcpy(new_v3000->atom_index_fin, orig_atom->v3000->atom_index_fin, orig_nat * sizeof(int));
     337                 :             :             }
     338   [ +  +  +  - ]:          48 :             if ( orig_atom->v3000->n_haptic_bonds && orig_atom->v3000->lists_haptic_bonds )
     339                 :             :             {
     340                 :           2 :                 new_v3000->lists_haptic_bonds = (int**)inchi_calloc(orig_atom->v3000->n_haptic_bonds, sizeof(int*));
     341                 :             :                 /* if ( NULL==new_v3000->lists_haptic_bonds ) { TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; }*/
     342         [ +  + ]:           5 :                 for ( m = 0; m < orig_atom->v3000->n_haptic_bonds; m++ )
     343                 :             :                 {
     344                 :           3 :                     int* lst = NULL;
     345                 :           3 :                     int* old_lst = orig_atom->v3000->lists_haptic_bonds[m];
     346                 :           3 :                     nn = old_lst[2] + 3;
     347                 :           3 :                     lst = new_v3000->lists_haptic_bonds[m] = (int*)inchi_calloc(nn, sizeof(int));
     348         [ -  + ]:           3 :                     if ( !lst )
     349                 :             :                     {
     350         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_haptic_bonds); /* djb-rwth: fixing coverity ID #499504 */
     351         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_orig); /* djb-rwth: fixing coverity ID #499540 */
     352         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_fin); /* djb-rwth: fixing coverity ID #499613 */
     353         [ #  # ]:           0 :                         inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     354                 :           0 :                         goto exit_function;
     355                 :             :                     }
     356                 :           3 :                     memcpy(lst, old_lst, nn * sizeof(int));
     357                 :             :                 }
     358                 :             :             }
     359   [ +  +  +  - ]:          48 :             if ( orig_atom->v3000->n_steabs && orig_atom->v3000->lists_steabs )
     360                 :             :             {
     361                 :          23 :                 new_v3000->lists_steabs = (int**)inchi_calloc(orig_atom->v3000->n_steabs, sizeof(int*));
     362                 :             :                 /* if ( NULL==new_v3000->lists_steabs ) { TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; }*/
     363         [ +  + ]:          46 :                 for ( m = 0; m < orig_atom->v3000->n_steabs; m++ )
     364                 :             :                 {
     365                 :          23 :                     int* lst = NULL;
     366                 :          23 :                     int* old_lst = orig_atom->v3000->lists_steabs[m];
     367                 :          23 :                     nn = old_lst[1] + 2;
     368                 :          23 :                     lst = new_v3000->lists_steabs[m] = (int*)inchi_calloc(nn, sizeof(int));
     369         [ -  + ]:          23 :                     if ( !lst )
     370                 :             :                     {
     371         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_haptic_bonds); /* djb-rwth: fixing coverity ID #499504 */
     372         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_steabs); /* djb-rwth: fixing coverity ID #499543 */
     373         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_orig); /* djb-rwth: fixing coverity ID #499540 */
     374         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_fin); /* djb-rwth: fixing coverity ID #499613 */
     375         [ #  # ]:           0 :                         inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     376                 :           0 :                         goto exit_function;
     377                 :             :                     }
     378                 :          23 :                     memcpy(lst, old_lst, nn * sizeof(int));
     379                 :             :                 }
     380                 :             :             }
     381   [ +  +  +  - ]:          48 :             if ( orig_atom->v3000->n_sterel && orig_atom->v3000->lists_sterel )
     382                 :             :             {
     383                 :          17 :                 new_v3000->lists_sterel = (int**)inchi_calloc(orig_atom->v3000->n_sterel, sizeof(int*));
     384         [ -  + ]:          17 :                 if ( !new_v3000 )
     385                 :             :                 {
     386         [ #  # ]:           0 :                     inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     387                 :           0 :                     goto exit_function;
     388                 :             :                 }
     389                 :             :                 /* if ( NULL==new_v3000->lists_sterel ) { TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; }*/
     390         [ +  + ]:          48 :                 for ( m = 0; m < orig_atom->v3000->n_sterel; m++ )
     391                 :             :                 {
     392                 :          31 :                     int* lst = NULL;
     393                 :          31 :                     int* old_lst = orig_atom->v3000->lists_sterel[m];
     394                 :          31 :                     nn = old_lst[1] + 2;
     395         [ +  - ]:          31 :                     if ( new_v3000->lists_sterel ) /* djb-rwth: fixing a NULL pointer dereference */
     396                 :          31 :                         lst = new_v3000->lists_sterel[m] = (int*)inchi_calloc(nn, sizeof(int));
     397         [ -  + ]:          31 :                     if ( !lst )
     398                 :             :                     {
     399         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_haptic_bonds); /* djb-rwth: fixing coverity ID #499504 */
     400         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_steabs); /* djb-rwth: fixing coverity ID #499543 */
     401         [ #  # ]:           0 :                         inchi_free(new_v3000->lists_sterel); /* djb-rwth: fixing coverity ID #499504 */
     402         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_orig); /* djb-rwth: fixing coverity ID #499540 */
     403         [ #  # ]:           0 :                         inchi_free(new_v3000->atom_index_fin); /* djb-rwth: fixing coverity ID #499613 */
     404         [ #  # ]:           0 :                         inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     405                 :           0 :                         goto exit_function;
     406                 :             :                     }
     407                 :          31 :                     memcpy(lst, old_lst, nn * sizeof(int));
     408                 :             :                 }
     409                 :             :             }
     410   [ +  +  +  - ]:          48 :             if ( orig_atom->v3000->n_sterac && orig_atom->v3000->lists_sterac )
     411                 :             :             {
     412                 :          26 :                 new_v3000->lists_sterac = (int**)inchi_calloc(orig_atom->v3000->n_sterac, sizeof(int*));
     413                 :             :                 /* if ( NULL==new_v3000->lists_sterac ) { TREAT_ERR( err, 9001, "Out of RAM"); goto exit_function; }*/
     414         [ +  - ]:          26 :                 if ( new_v3000->lists_sterac ) /* djb-rwth: fixing a NULL pointer dereference */
     415                 :             :                 {
     416         [ +  + ]:          73 :                     for ( m = 0; m < orig_atom->v3000->n_sterac; m++ )
     417                 :             :                     {
     418                 :          47 :                         int* lst = NULL;
     419                 :          47 :                         int* old_lst = orig_atom->v3000->lists_sterac[m];
     420                 :          47 :                         nn = old_lst[1] + 2;
     421                 :          47 :                         lst = new_v3000->lists_sterac[m] = (int*)inchi_calloc(nn, sizeof(int));
     422         [ -  + ]:          47 :                         if ( !lst )
     423                 :             :                         {
     424         [ #  # ]:           0 :                             inchi_free(new_v3000->lists_haptic_bonds); /* djb-rwth: fixing coverity ID #499504 */
     425         [ #  # ]:           0 :                             inchi_free(new_v3000->lists_steabs); /* djb-rwth: fixing coverity ID #499543 */
     426         [ #  # ]:           0 :                             inchi_free(new_v3000->lists_sterel); /* djb-rwth: fixing coverity ID #499504 */
     427         [ #  # ]:           0 :                             inchi_free(new_v3000->lists_sterac); /* djb-rwth: fixing coverity ID #499575 */
     428         [ #  # ]:           0 :                             inchi_free(new_v3000->atom_index_orig); /* djb-rwth: fixing coverity ID #499540 */
     429         [ #  # ]:           0 :                             inchi_free(new_v3000->atom_index_fin); /* djb-rwth: fixing coverity ID #499613 */
     430         [ #  # ]:           0 :                             inchi_free(new_v3000); /* djb-rwth: avoiding memory leak */
     431                 :           0 :                             goto exit_function;
     432                 :             :                         }
     433                 :          47 :                         memcpy(lst, old_lst, nn * sizeof(int));
     434                 :             :                     }
     435                 :             :                 }
     436                 :             :             }
     437                 :             : 
     438                 :          48 :             new_orig_atom->v3000 = new_v3000;
     439                 :             :         }
     440                 :             : 
     441                 :             :         /* Success */
     442                 :          54 :         ret = 0;
     443                 :             :     }
     444                 :             : 
     445                 :           0 : exit_function:
     446                 :             : 
     447         [ -  + ]:          54 :     if ( ret != 0 )
     448                 :             :     {
     449   [ #  #  #  # ]:           0 :         if ( at && new_orig_atom->at != at )
     450         [ #  # ]:           0 :             inchi_free(at);
     451   [ #  #  #  # ]:           0 :         if ( nCurAtLen && new_orig_atom->nCurAtLen != nCurAtLen )
     452         [ #  # ]:           0 :             inchi_free(nCurAtLen);
     453   [ #  #  #  # ]:           0 :         if ( nOldCompNumber && new_orig_atom->nOldCompNumber != nOldCompNumber )
     454         [ #  # ]:           0 :             inchi_free(nOldCompNumber);
     455                 :             :     }
     456                 :             : 
     457                 :          54 :     return ret;
     458                 :             : }
     459                 :             : 
     460                 :             : 
     461                 :             : /****************************************************************************
     462                 :             :   Preprocess the whole structure
     463                 :             : 
     464                 :             :     The plan is as follows.
     465                 :             : 
     466                 :             :     1.    Copy orig_inp_data --> prep_inp_data (then work with the latter)
     467                 :             : 
     468                 :             :     2.    Fix odd things in prep_inp_data
     469                 :             : 
     470                 :             :             Find whether the structure can be disconnected or is a salt
     471                 :             :                 - check if needs salt disconnection
     472                 :             :                 - check if needs metal disconnection
     473                 :             : 
     474                 :             :     3.    If ( orig_inp_data->bDisconnectSalts ) then
     475                 :             :             disconnect salts in prep_inp_data
     476                 :             : 
     477                 :             :             Mark the (disconnected) components in prep_inp_data
     478                 :             : 
     479                 :             :             Detect isotopic H on heteroatoms (necessary condition
     480                 :             :             for global isotopic tautomerism)
     481                 :             : 
     482                 :             :     4.    Detect unusual valences (should be called before metal disconnection)
     483                 :             : 
     484                 :             :     5.    Create metal-disconnected structure if applicable.
     485                 :             :             - save reconnected structure in prep_inp_data+1 if requested
     486                 :             :             - make Disconnected structure in prep_inp_data
     487                 :             : ****************************************************************************/
     488                 :          54 : int PreprocessOneStructure(struct tagINCHI_CLOCK* ic,
     489                 :             :     STRUCT_DATA* sd,
     490                 :             :     INPUT_PARMS* ip,
     491                 :             :     ORIG_ATOM_DATA* orig_inp_data,
     492                 :             :     ORIG_ATOM_DATA* prep_inp_data)
     493                 :             : {
     494                 :             :     int i;
     495                 :          54 :     INCHI_MODE bTautFlags = 0;
     496                 :          54 :     INCHI_MODE bTautFlagsDone = 0;
     497                 :             : 
     498                 :             :     /* 1. Copy orig_inp_data --> prep_inp_data */
     499                 :             : 
     500         [ -  + ]:          54 :     if ( 0 > OrigAtData_Duplicate(prep_inp_data, orig_inp_data) )
     501                 :             :     {
     502                 :           0 :         AddErrorMessage(sd->pStrErrStruct, "Out of RAM");
     503                 :           0 :         sd->nStructReadError = 99;
     504                 :           0 :         sd->nErrorType = _IS_FATAL;
     505                 :           0 :         goto exit_function;
     506                 :             :     }
     507                 :             : 
     508                 :             : #if ( bRELEASE_VERSION == 0 && (EXTR_HAS_METAL_ATOM & (EXTR_MASK | EXTR_FLAG) ) )
     509                 :             :     if ( bHasMetalAtom(orig_inp_data) )
     510                 :             :     {
     511                 :             :         sd->bExtract |= EXTR_HAS_METAL_ATOM;
     512                 :             :     }
     513                 :             : #endif
     514                 :             : 
     515                 :             :     /* 2. Fix odd things in prep_inp_data            */
     516                 :             : 
     517         [ -  + ]:          54 :     if ( 0 < fix_odd_things(prep_inp_data->num_inp_atoms, prep_inp_data->at, /*0*/ip->bTautFlags & TG_FLAG_FIX_SP3_BUG, ip->bFixNonUniformDraw) )
     518                 :             :     {
     519                 :             :         /* changed 2010-03-17 DT */
     520         [ #  # ]:           0 :         if ( !ip->bNoWarnings )
     521                 :             :         {
     522                 :           0 :             WarningMessage(sd->pStrErrStruct, "Charges were rearranged");
     523                 :             :         }
     524         [ #  # ]:           0 :         if ( sd->nErrorType < _IS_WARNING )
     525                 :             :         {
     526                 :           0 :             sd->nErrorType = _IS_WARNING;
     527                 :             :         }
     528                 :           0 :         sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     529                 :             :     }
     530                 :             : 
     531                 :             : #if ( FIX_ADJ_RAD == 1 )
     532                 :             :     if ( ip->bTautFlags & TG_FLAG_FIX_ADJ_RADICALS )
     533                 :             :     {
     534                 :             :         if ( 0 < FixAdjacentRadicals(prep_inp_data->num_inp_atoms, prep_inp_data->at) )
     535                 :             :         {
     536                 :             :             sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ADJ_RADICALS_DONE;
     537                 :             :         }
     538                 :             :     }
     539                 :             : #endif
     540                 :             : 
     541                 :             : #if ( bRELEASE_VERSION == 0 && (EXTR_FLAGS & EXTR_HAS_FEATURE) )
     542                 :             :     if ( bFoundFeature(prep_inp_data->at, prep_inp_data->num_inp_atoms) )
     543                 :             :     {
     544                 :             :         sd->bExtract |= EXTR_HAS_FEATURE;
     545                 :             :     }
     546                 :             : #endif
     547                 :             : 
     548                 :             : 
     549                 :             :     /* Find whether the structure can be disconnected or is a salt */
     550                 :             : 
     551                 :             : 
     552                 :             :     /* Needs salt disconnection? */
     553                 :             : 
     554                 :             :     /* (@nnuk -> Nauman Ullah Khan) :: In case of Metal Salts with MolecularInorganics parameter we need to skip this pre-processing of Salts */
     555         [ +  + ]:          54 :     if ( ip->bMolecularInorganics )
     556                 :             :     {
     557                 :             :         ;
     558                 :             :     }
     559         [ +  - ]:          48 :     else if ( ip->bTautFlags & TG_FLAG_DISCONNECT_SALTS )
     560                 :             :     {
     561                 :          48 :         prep_inp_data->bDisconnectSalts = (0 < DisconnectSalts(prep_inp_data, 0));
     562                 :             :     }
     563                 :             :     else
     564                 :             :     {
     565                 :           0 :         prep_inp_data->bDisconnectSalts = 0;
     566                 :             :     }
     567                 :             : 
     568                 :             :     /* Needs metal disconnection? */
     569                 :             : 
     570         [ +  - ]:          54 :     if ( ip->bTautFlags & TG_FLAG_DISCONNECT_COORD )
     571                 :             :     {
     572                 :          54 :         i = (0 != (ip->bTautFlags & TG_FLAG_CHECK_VALENCE_COORD));
     573                 :          54 :         bMayDisconnectMetals(prep_inp_data, i, &bTautFlagsDone); /* changes prep_inp_data->bDisconnectCoord */
     574                 :          54 :         sd->bTautFlagsDone[INCHI_BAS] |= bTautFlagsDone; /* whether any disconnection has been rejected because of the metal proper valence */
     575                 :             : 
     576                 :             : #if ( bRELEASE_VERSION == 0 )
     577                 :             :         if ( i && (bTautFlagsDone & TG_FLAG_CHECK_VALENCE_COORD_DONE) )
     578                 :             :         {
     579                 :             :             sd->bExtract |= EXTR_METAL_WAS_NOT_DISCONNECTED;
     580                 :             :         }
     581                 :             : #endif
     582                 :             :     }
     583                 :             :     else
     584                 :             :     {
     585                 :           0 :         prep_inp_data->bDisconnectCoord = 0;
     586                 :             :     }
     587                 :          54 :     orig_inp_data->bDisconnectSalts = prep_inp_data->bDisconnectSalts;
     588                 :          54 :     orig_inp_data->bDisconnectCoord = prep_inp_data->bDisconnectCoord;
     589                 :             : 
     590                 :             :     /* 3. if( orig_inp_data->bDisconnectSalts ) then
     591                 :             :           disconnect salts in prep_inp_data    */
     592                 :             : 
     593   [ +  -  -  +  :          54 :     if ( (ip->bTautFlags & TG_FLAG_DISCONNECT_SALTS) && prep_inp_data->bDisconnectSalts &&
                   -  - ]
     594                 :           0 :         0 < (i = DisconnectSalts(prep_inp_data, 1)) ) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
     595                 :             :     {
     596         [ #  # ]:           0 :         if ( !ip->bNoWarnings )
     597                 :             :         {
     598                 :           0 :             WarningMessage(sd->pStrErrStruct, "Salt was disconnected");
     599                 :             :         }
     600                 :           0 :         sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_DISCONNECT_SALTS_DONE;
     601         [ #  # ]:           0 :         if ( sd->nErrorType < _IS_WARNING )
     602                 :             :         {
     603                 :           0 :             sd->nErrorType = _IS_WARNING;
     604                 :             :         }
     605         [ #  # ]:           0 :         if ( (i = ReconcileAllCmlBondParities(prep_inp_data->at, prep_inp_data->num_inp_atoms, 0)) ) /* djb-rwth: addressing LLVM warning */
     606                 :             :         {
     607                 :             :             char szErrCode[16];
     608                 :           0 :             sprintf(szErrCode, "%d", i);
     609                 :           0 :             AddErrorMessage(sd->pStrErrStruct, "0D Parities Reconciliation failed:");
     610                 :           0 :             AddErrorMessage(sd->pStrErrStruct, szErrCode);
     611                 :             :         }
     612                 :             : 
     613                 :             : #if ( bRELEASE_VERSION == 0 )
     614                 :             :         sd->bExtract |= EXTR_SALT_WAS_DISCONNECTED;
     615                 :             : #endif
     616                 :             :     }
     617                 :             :     else
     618                 :             :     {
     619                 :          54 :         prep_inp_data->bDisconnectSalts = 0;
     620                 :             :     }
     621                 :             : 
     622                 :             :     /*  Mark the (disconnected) components in prep_inp_data    */
     623                 :             : 
     624                 :          54 :     prep_inp_data->num_components = MarkDisconnectedComponents(prep_inp_data, 0);
     625                 :             : 
     626         [ -  + ]:          54 :     if ( prep_inp_data->num_components < 0 )
     627                 :             :     {
     628                 :           0 :         AddErrorMessage(sd->pStrErrStruct, "Out of RAM");
     629                 :           0 :         sd->nStructReadError = 99;
     630                 :           0 :         sd->nErrorType = _IS_FATAL;
     631                 :           0 :         goto exit_function;
     632                 :             :     }
     633                 :             : 
     634                 :             :     /* Detect isotopic H on heteroatoms -- necessary condition
     635                 :             :        for global isotopic tautomerism */
     636                 :             : 
     637         [ -  + ]:          54 :     if ( (i = bNumHeterAtomHasIsotopicH(prep_inp_data->at, prep_inp_data->num_inp_atoms)) ) /* djb-rwth: addressing LLVM warning */
     638                 :             :     {
     639         [ #  # ]:           0 :         if ( i & 1 )
     640                 :             :         {
     641                 :           0 :             sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FOUND_ISOTOPIC_H_DONE;
     642                 :             :         }
     643         [ #  # ]:           0 :         if ( i & 2 )
     644                 :             :         {
     645                 :           0 :             sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE;
     646                 :             :         }
     647                 :             :     }
     648                 :             : 
     649                 :             :     /* 4a. Detect unusual valences                                              */
     650                 :             : 
     651                 :          54 :     if ( OrigAtData_bCheckUnusualValences(prep_inp_data, 1, sd->pStrErrStruct, ip->bNoWarnings) )
     652                 :             :     {
     653                 :             : #if ( bRELEASE_VERSION == 0 )
     654                 :             :         sd->bExtract |= EXTR_UNUSUAL_VALENCES;
     655                 :             : #else
     656                 :             :         ;
     657                 :             : #endif
     658                 :             :     }
     659                 :             : 
     660                 :             : 
     661                 :             :     /*    5. if( orig_inp_data->bDisconnectCoord ) then
     662                 :             :               -- copy prep_inp_data --> prep_inp_data+1
     663                 :             :               -- disconnect metals in prep_inp_data            */
     664                 :             : 
     665                 :             :               /* (@nnuk -> Nauman Ullah Khan) :: In case of Metals with MolecularInorganics parameter we need to skip this pre-processing of Metals */
     666         [ +  + ]:          54 :     if ( ip->bMolecularInorganics )
     667                 :             :     {
     668                 :           6 :         return 0;             /* Skipping over current functionality */
     669                 :             :     }
     670         [ +  + ]:          48 :     else if ( prep_inp_data->bDisconnectCoord )
     671                 :             :     {
     672                 :             : 
     673                 :           1 :         prep_inp_data->num_components = MarkDisconnectedComponents(prep_inp_data, 0);
     674         [ -  + ]:           1 :         if ( prep_inp_data->num_components < 0 )
     675                 :             :         {
     676                 :           0 :             AddErrorMessage(sd->pStrErrStruct, "Out of RAM");
     677                 :           0 :             sd->nStructReadError = 99;
     678                 :           0 :             sd->nErrorType = _IS_FATAL;
     679                 :           0 :             goto exit_function;
     680                 :             :         }
     681                 :             : 
     682                 :             :         /* Save reconnected structure in prep_inp_data+1 if requested */
     683         [ -  + ]:           1 :         if ( 0 != (ip->bTautFlags & TG_FLAG_RECONNECT_COORD) )
     684                 :             :         {
     685         [ #  # ]:           0 :             if ( 0 > OrigAtData_Duplicate(prep_inp_data + 1, prep_inp_data) )
     686                 :             :             {
     687                 :           0 :                 AddErrorMessage(sd->pStrErrStruct, "Out of RAM");
     688                 :           0 :                 sd->nStructReadError = 99;
     689                 :           0 :                 sd->nErrorType = _IS_FATAL;
     690                 :           0 :                 goto exit_function;
     691                 :             :             }
     692                 :           0 :             sd->bTautFlags[INCHI_REC] = sd->bTautFlags[INCHI_BAS];
     693                 :           0 :             sd->bTautFlagsDone[INCHI_REC] = sd->bTautFlagsDone[INCHI_BAS];
     694                 :             :             {
     695                 :             :                 /* Remove "parity undefined in disconnected structure" flag from reconnected structure */
     696                 :             :                 int k, m; /* djb-rwth: removing redundant variables */
     697                 :           0 :                 inp_ATOM* at = (prep_inp_data + 1)->at;
     698                 :           0 :                 int       num_at = (prep_inp_data + 1)->num_inp_atoms;
     699         [ #  # ]:           0 :                 for ( k = 0; k < num_at; k++ )
     700                 :             :                 {
     701   [ #  #  #  # ]:           0 :                     for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[k].sb_parity[m]; m++ ) /* djb-rwth: removing redundant code */
     702                 :             :                     {
     703                 :           0 :                         at[k].sb_parity[m] &= SB_PARITY_MASK;
     704                 :             :                     }
     705                 :             :                 }
     706                 :             :             }
     707                 :             :         }
     708                 :             : 
     709                 :             :         /* Make disconnected structure in prep_inp_data */
     710                 :           1 :         i = (0 != (ip->bTautFlags & TG_FLAG_CHECK_VALENCE_COORD));
     711                 :             : 
     712                 :             :         /*    prep_inp_data->bDisconnectCoord > 1 means add
     713                 :             :                 prep_inp_data->bDisconnectCoord-1 explicit H atoms    */
     714         [ +  - ]:           1 :         if ( 0 < (i = DisconnectMetals(prep_inp_data, i, &bTautFlagsDone)) )
     715                 :             :         {
     716         [ +  - ]:           1 :             if ( !ip->bNoWarnings )
     717                 :             :             {
     718                 :           1 :                 WarningMessage(sd->pStrErrStruct, "Metal was disconnected");
     719                 :             :             }
     720                 :           1 :             sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_DISCONNECT_COORD_DONE;
     721         [ -  + ]:           1 :             if ( sd->nErrorType < _IS_WARNING )
     722                 :             :             {
     723                 :           0 :                 sd->nErrorType = _IS_WARNING;
     724                 :             :             }
     725                 :             : 
     726                 :             : #if ( bRELEASE_VERSION == 0 )
     727                 :             :             sd->bExtract |= EXTR_METAL_WAS_DISCONNECTED;
     728                 :             : #endif
     729                 :             : 
     730                 :             :             /* last parm=1 means find link between unchanged by Metal Disconnection components */
     731                 :           1 :             prep_inp_data->num_components = MarkDisconnectedComponents(prep_inp_data, 1);
     732                 :             : 
     733         [ -  + ]:           1 :             if ( prep_inp_data->num_components < 0 )
     734                 :             :             {
     735                 :           0 :                 AddErrorMessage(sd->pStrErrStruct, "Out of RAM");
     736                 :           0 :                 sd->nStructReadError = 99;
     737                 :           0 :                 sd->nErrorType = _IS_FATAL;
     738                 :           0 :                 goto exit_function;
     739                 :             :             }
     740                 :             : 
     741                 :             :             {
     742                 :             :                 /* Set parities for the disconnected structure */
     743                 :             :                 int k, m, p;
     744                 :           1 :                 inp_ATOM* at = (prep_inp_data)->at;
     745                 :           1 :                 int       num_at = (prep_inp_data)->num_inp_atoms;
     746         [ +  + ]:          12 :                 for ( k = 0; k < num_at; k++ )
     747                 :             :                 {
     748   [ +  -  -  + ]:          11 :                     for ( m = 0; m < MAX_NUM_STEREO_BONDS && (p = at[k].sb_parity[m]); m++ )
     749                 :             :                     {
     750         [ #  # ]:           0 :                         if ( p & SB_PARITY_FLAG )
     751                 :             :                         {
     752                 :           0 :                             at[k].sb_parity[m] = (p >> SB_PARITY_SHFT) & SB_PARITY_MASK;
     753                 :             :                         }
     754                 :             :                     }
     755                 :             :                 }
     756                 :             :             }
     757                 :             : 
     758         [ -  + ]:           1 :             if ( (i = ReconcileAllCmlBondParities(prep_inp_data->at, prep_inp_data->num_inp_atoms, 1)) ) /* djb-rwth: addressing LLVM warning */
     759                 :             :             {
     760                 :             :                 char szErrCode[16];
     761                 :           0 :                 sprintf(szErrCode, "%d", i);
     762                 :           0 :                 AddErrorMessage(sd->pStrErrStruct, "0D Parities Reconciliation failed:");
     763                 :           0 :                 AddErrorMessage(sd->pStrErrStruct, szErrCode);
     764                 :             :             }
     765                 :             : 
     766                 :             : #if ( REMOVE_ION_PAIRS_DISC_STRU == 1 )
     767         [ -  + ]:           1 :             if ( 0 < remove_ion_pairs(prep_inp_data->num_inp_atoms, prep_inp_data->at) )
     768                 :             :             {
     769         [ #  # ]:           0 :                 if ( !ip->bNoWarnings )
     770                 :             :                 {
     771                 :           0 :                     WarningMessage(sd->pStrErrStruct, "Charges were rearranged");
     772                 :             :                 }
     773         [ #  # ]:           0 :                 if ( sd->nErrorType < _IS_WARNING )
     774                 :             :                 {
     775                 :           0 :                     sd->nErrorType = _IS_WARNING;
     776                 :             :                 }
     777                 :           0 :                 sd->bTautFlagsDone[INCHI_REC] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     778                 :           0 :                 sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     779                 :             :             }
     780                 :             : #endif
     781                 :             : 
     782                 :             :             /*
     783                 :             :               if prep_inp_data->nOldCompNumber[i] = iINChI+1 > 0 then
     784                 :             :               component #(i+1) in prep_inp_data is identical to component #(iINChI+1) in prep_inp_data+1
     785                 :             :             */
     786                 :             :         }
     787         [ #  # ]:           0 :         else if ( i < 0 )
     788                 :             :         {
     789                 :           0 :             AddErrorMessage(sd->pStrErrStruct, "Cannot disconnect metal error");
     790                 :           0 :             sd->nStructReadError = i;
     791                 :           0 :             sd->nErrorType = _IS_ERROR;
     792                 :           0 :             goto exit_function;
     793                 :             :         }
     794                 :             :     }
     795                 :             :     else
     796                 :             :     {
     797                 :             :         /* Remove "disconnected structure parities" from the structure */
     798                 :             :         int k, m; /* djb-rwth: removing redundant variables */
     799                 :          47 :         inp_ATOM* at = (prep_inp_data)->at;
     800                 :          47 :         int       num_at = (prep_inp_data)->num_inp_atoms;
     801         [ +  + ]:         627 :         for ( k = 0; k < num_at; k++ )
     802                 :             :         {
     803   [ +  -  -  + ]:         580 :             for ( m = 0; m < MAX_NUM_STEREO_BONDS && at[k].sb_parity[m]; m++ ) /* djb-rwth: removing redundant code */
     804                 :             :             {
     805                 :           0 :                 at[k].sb_parity[m] &= SB_PARITY_MASK;
     806                 :             :             }
     807                 :             :         }
     808                 :             :     }
     809                 :             : 
     810                 :          47 : exit_function:
     811                 :             : 
     812   [ +  -  +  - ]:          48 :     if ( sd->nErrorType < _IS_ERROR && prep_inp_data )
     813                 :             :     {
     814         [ -  + ]:          48 :         if ( 0 < post_fix_odd_things(prep_inp_data->num_inp_atoms, prep_inp_data->at) )
     815                 :             :         {
     816         [ #  # ]:           0 :             if ( !ip->bNoWarnings )
     817                 :             :             {
     818                 :           0 :                 WarningMessage(sd->pStrErrStruct, "Charges were rearranged");
     819                 :             :             }
     820         [ #  # ]:           0 :             if ( sd->nErrorType < _IS_WARNING )
     821                 :             :             {
     822                 :           0 :                 sd->nErrorType = _IS_WARNING;
     823                 :             :             }
     824                 :           0 :             sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     825                 :             :         }
     826         [ +  + ]:          48 :         if ( (sd->bTautFlagsDone[INCHI_BAS] & TG_FLAG_DISCONNECT_COORD_DONE) &&
     827   [ -  +  -  - ]:           1 :             (prep_inp_data + 1)->at && (prep_inp_data + 1)->num_inp_atoms > 0 )
     828                 :             :         {
     829         [ #  # ]:           0 :             if ( 0 < post_fix_odd_things((prep_inp_data + 1)->num_inp_atoms, (prep_inp_data + 1)->at) )
     830                 :             :             {
     831         [ #  # ]:           0 :                 if ( !ip->bNoWarnings )
     832                 :             :                 {
     833                 :           0 :                     WarningMessage(sd->pStrErrStruct, "Charges were rearranged");
     834                 :             :                 }
     835         [ #  # ]:           0 :                 if ( sd->nErrorType < _IS_WARNING )
     836                 :             :                 {
     837                 :           0 :                     sd->nErrorType = _IS_WARNING;
     838                 :             :                 }
     839                 :           0 :                 sd->bTautFlagsDone[INCHI_REC] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     840                 :           0 :                 sd->bTautFlagsDone[INCHI_BAS] |= TG_FLAG_FIX_ODD_THINGS_DONE;
     841                 :             :             }
     842                 :             :         }
     843                 :             :     }
     844                 :             : 
     845                 :          48 :     sd->bTautFlags[INCHI_BAS] |= bTautFlags;  /* TG_FLAG_CHECK_VALENCE_COORD_DONE, TG_FLAG_MOVE_CHARGE_COORD_DONE */
     846                 :          48 :     sd->bTautFlagsDone[INCHI_BAS] |= bTautFlagsDone;  /* TG_FLAG_CHECK_VALENCE_COORD_DONE, TG_FLAG_MOVE_CHARGE_COORD_DONE */
     847                 :             : 
     848                 :          48 :     return sd->nErrorType;
     849                 :             : }
     850                 :             : 
     851                 :             : 
     852                 :             : #ifndef TARGET_API_LIB
     853                 :             : 
     854                 :             : 
     855                 :             : /****************************************************************************/
     856                 :             : int CreateCompositeNormAtom(COMP_ATOM_DATA* composite_norm_data,
     857                 :             :     INP_ATOM_DATA2* all_inp_norm_data,
     858                 :             :     int             num_components)
     859                 :             : {
     860                 :             :     int i, j, jj, k, n, m, tot_num_at, tot_num_H, cur_num_at, cur_num_H; /* djb-rwth: removing redundant variables */
     861                 :             :     int num_comp[TAUT_NUM + 1], num_taut[TAUT_NUM + 1], num_del[TAUT_NUM + 1], num_at[TAUT_NUM + 1], num_inp_at[TAUT_NUM + 1];
     862                 :             :     int ret = 0, indicator = 1;
     863                 :             :     inp_ATOM* at, * at_from;
     864                 :             :     memset(num_comp, 0, sizeof(num_comp)); /* djb-rwth: memset_s C11/Annex K variant? */
     865                 :             :     memset(num_taut, 0, sizeof(num_taut)); /* djb-rwth: memset_s C11/Annex K variant? */
     866                 :             :     memset(num_del, 0, sizeof(num_taut)); /* djb-rwth: memset_s C11/Annex K variant? */
     867                 :             : 
     868                 :             :     /* count taut and non-taut components */
     869                 :             :     for ( j = 0; j < TAUT_NUM; j++ )
     870                 :             :     {
     871                 :             :         num_comp[j] = num_taut[j] = 0;
     872                 :             :         for ( i = 0; i < num_components; i++ )
     873                 :             :         {
     874                 :             :             if ( all_inp_norm_data[i][j].bExists )
     875                 :             :             {
     876                 :             :                 num_del[j] += (0 != all_inp_norm_data[i][j].bDeleted);
     877                 :             :                 num_comp[j]++;
     878                 :             :                 num_taut[j] += (0 != all_inp_norm_data[i][j].bTautomeric);
     879                 :             :             }
     880                 :             :         }
     881                 :             :     }
     882                 :             : 
     883                 :             :     /* count intermediate taut structure components */
     884                 :             :     if ( num_comp[TAUT_YES] > num_del[TAUT_YES] && num_taut[TAUT_YES] )
     885                 :             :     {
     886                 :             :         /*
     887                 :             :         num_comp[TAUT_INI] = num_comp[TAUT_YES] - num_del[TAUT_YES];
     888                 :             :         */
     889                 :             : 
     890                 :             :         for ( i = 0, j = TAUT_YES; i < num_components; i++ )
     891                 :             :         {
     892                 :             :             if ( all_inp_norm_data[i][j].bExists &&
     893                 :             :                 (all_inp_norm_data[i][j].bDeleted ||
     894                 :             :                     (all_inp_norm_data[i][j].bTautomeric &&
     895                 :             :                         all_inp_norm_data[i][j].at_fixed_bonds &&
     896                 :             :                         all_inp_norm_data[i][j].bTautPreprocessed)) ) /* djb-rwth: addressing LLVM warning */
     897                 :             :             {
     898                 :             :                 num_comp[TAUT_INI]++;
     899                 :             :             }
     900                 :             :         }
     901                 :             :     }
     902                 :             : 
     903                 :             :     /* count atoms and allocate composite atom data */
     904                 :             :     for ( jj = 0; jj <= TAUT_INI; jj++ )
     905                 :             :     {
     906                 :             :         num_at[jj] = num_inp_at[jj] = 0;
     907                 :             :         j = inchi_min(jj, TAUT_YES);
     908                 :             :         if ( num_comp[jj] )
     909                 :             :         {
     910                 :             :             for ( i = 0; i < num_components; i++ )
     911                 :             :             {
     912                 :             :                 if ( all_inp_norm_data[i][j].bDeleted )
     913                 :             :                 {
     914                 :             :                     continue;
     915                 :             :                 }
     916                 :             :                 /* find k = the normaized structure index */
     917                 :             :                 if ( jj == TAUT_INI )
     918                 :             :                 {
     919                 :             :                     if ( all_inp_norm_data[i][j].bExists &&
     920                 :             :                         all_inp_norm_data[i][j].at_fixed_bonds )
     921                 :             :                     {
     922                 :             :                         k = j;
     923                 :             :                     }
     924                 :             :                     else
     925                 :             :                         if ( all_inp_norm_data[i][ALT_TAUT(j)].bExists && !all_inp_norm_data[i][ALT_TAUT(j)].bDeleted &&
     926                 :             :                             !all_inp_norm_data[i][j].bDeleted )
     927                 :             :                         {
     928                 :             :                             k = ALT_TAUT(j);
     929                 :             :                         }
     930                 :             :                         else
     931                 :             :                         {
     932                 :             :                             if ( all_inp_norm_data[i][j].bExists )
     933                 :             :                             {
     934                 :             :                                 k = j;
     935                 :             :                             }
     936                 :             :                             else
     937                 :             :                             {
     938                 :             :                                 continue;
     939                 :             :                             }
     940                 :             :                         }
     941                 :             :                 }
     942                 :             :                 else
     943                 :             :                 {
     944                 :             :                     if ( all_inp_norm_data[i][j].bExists )
     945                 :             :                     {
     946                 :             :                         k = j;
     947                 :             :                     }
     948                 :             :                     else
     949                 :             :                     {
     950                 :             :                         if ( all_inp_norm_data[i][ALT_TAUT(j)].bExists && !all_inp_norm_data[i][ALT_TAUT(j)].bDeleted )
     951                 :             :                         {
     952                 :             :                             k = ALT_TAUT(j);
     953                 :             :                         }
     954                 :             :                         else
     955                 :             :                         {
     956                 :             :                             continue;
     957                 :             :                         }
     958                 :             :                     }
     959                 :             :                 }
     960                 :             :                 num_inp_at[jj] += all_inp_norm_data[i][k].num_at; /* all atoms including terminal H */
     961                 :             :                 num_at[jj] += all_inp_norm_data[i][k].num_at - all_inp_norm_data[i][k].num_removed_H;
     962                 :             :             }
     963                 :             :             if ( num_inp_at[jj] )
     964                 :             :             {
     965                 :             :                 if ( !CreateCompAtomData(composite_norm_data + jj, num_inp_at[jj], num_components, jj == TAUT_INI) )
     966                 :             :                 {
     967                 :             :                     goto exit_error;
     968                 :             :                 }
     969                 :             :                 composite_norm_data[jj].num_removed_H = num_inp_at[jj] - num_at[jj];
     970                 :             :             }
     971                 :             :         }
     972                 :             :     }
     973                 :             : 
     974                 :             :     /* fill out composite atom */
     975                 :             :     for ( jj = 0; jj <= TAUT_INI; jj++, indicator <<= 1 )
     976                 :             :     {
     977                 :             :         j = inchi_min(jj, TAUT_YES);
     978                 :             :         if ( num_comp[jj] )
     979                 :             :         {
     980                 :             :             tot_num_at = 0;
     981                 :             :             tot_num_H = 0;
     982                 :             :             for ( i = 0; i < num_components; i++ )
     983                 :             :             {
     984                 :             :                 if ( all_inp_norm_data[i][j].bDeleted )
     985                 :             :                 {
     986                 :             :                     composite_norm_data[jj].nNumRemovedProtons += all_inp_norm_data[i][j].nNumRemovedProtons;
     987                 :             :                     for ( n = 0; n < NUM_H_ISOTOPES; n++ )
     988                 :             :                     {
     989                 :             :                         composite_norm_data[jj].nNumRemovedProtonsIsotopic[n] += all_inp_norm_data[i][j].nNumRemovedProtonsIsotopic[n];
     990                 :             :                     }
     991                 :             :                     continue;
     992                 :             :                 }
     993                 :             :                 /* djb-rwth: removing redundant code */
     994                 :             :                 /* find k = the normaized structure index */
     995                 :             :                 if ( jj == TAUT_INI )
     996                 :             :                 {
     997                 :             :                     if ( all_inp_norm_data[i][j].bExists && all_inp_norm_data[i][j].at_fixed_bonds )
     998                 :             :                     {
     999                 :             :                         k = j;
    1000                 :             :                     }
    1001                 :             :                     else
    1002                 :             :                     {
    1003                 :             :                         if ( all_inp_norm_data[i][ALT_TAUT(j)].bExists )
    1004                 :             :                         {
    1005                 :             :                             k = ALT_TAUT(j);
    1006                 :             :                         }
    1007                 :             :                         else
    1008                 :             :                         {
    1009                 :             :                             if ( all_inp_norm_data[i][j].bExists && !all_inp_norm_data[i][ALT_TAUT(j)].bDeleted )
    1010                 :             :                             {
    1011                 :             :                                 k = j;
    1012                 :             :                             }
    1013                 :             :                             else
    1014                 :             :                             {
    1015                 :             :                                 continue;
    1016                 :             :                             }
    1017                 :             :                         }
    1018                 :             :                     }
    1019                 :             :                 }
    1020                 :             :                 else
    1021                 :             :                 {
    1022                 :             :                     if ( all_inp_norm_data[i][j].bExists )
    1023                 :             :                     {
    1024                 :             :                         k = j;
    1025                 :             :                     }
    1026                 :             :                     else
    1027                 :             :                     {
    1028                 :             :                         if ( all_inp_norm_data[i][ALT_TAUT(j)].bExists && !all_inp_norm_data[i][ALT_TAUT(j)].bDeleted )
    1029                 :             :                         {
    1030                 :             :                             k = ALT_TAUT(j);
    1031                 :             :                         }
    1032                 :             :                         else
    1033                 :             :                         {
    1034                 :             :                             continue;
    1035                 :             :                         }
    1036                 :             :                     }
    1037                 :             :                 }
    1038                 :             :                 /* copy main atoms */
    1039                 :             :                 cur_num_H = all_inp_norm_data[i][k].num_removed_H;       /* number of terminal H atoms */
    1040                 :             :                 cur_num_at = all_inp_norm_data[i][k].num_at - cur_num_H;  /* number of all but explicit terminal H atoms */
    1041                 :             : 
    1042                 :             :                 if ( (tot_num_at + cur_num_at) > num_at[jj] ||
    1043                 :             :                     (num_at[jj] + tot_num_H + cur_num_H) > num_inp_at[jj] )
    1044                 :             :                 {
    1045                 :             :                     goto exit_error; /* miscount */
    1046                 :             :                 }
    1047                 :             :                 at = composite_norm_data[jj].at + tot_num_at; /* points to the 1st destination atom */
    1048                 :             :                 at_from = (jj == TAUT_INI && k == TAUT_YES && all_inp_norm_data[i][k].at_fixed_bonds) ?
    1049                 :             :                     all_inp_norm_data[i][k].at_fixed_bonds : all_inp_norm_data[i][k].at;
    1050                 :             :                 memcpy(at, at_from, sizeof(composite_norm_data[0].at[0]) * cur_num_at); /* copy atoms except terminal H */
    1051                 :             :                 /* shift neighbors of main atoms */
    1052                 :             :                 for ( n = 0; n < cur_num_at; n++, at++ )
    1053                 :             :                 {
    1054                 :             :                     for ( m = 0; m < at->valence; m++ )
    1055                 :             :                     {
    1056                 :             :                         at->neighbor[m] += tot_num_at;
    1057                 :             :                     }
    1058                 :             :                 }
    1059                 :             :                 /* copy explicit H */
    1060                 :             :                 if ( cur_num_H )
    1061                 :             :                 {
    1062                 :             :                     at = composite_norm_data[jj].at + num_at[jj] + tot_num_H; /* points to the 1st destination atom */
    1063                 :             :                     memcpy(at, at_from + cur_num_at,
    1064                 :             :                         sizeof(composite_norm_data[0].at[0]) * cur_num_H);
    1065                 :             :                     /* shift neighbors of explicit H atoms */
    1066                 :             :                     for ( n = 0; n < cur_num_H; n++, at++ )
    1067                 :             :                     {
    1068                 :             :                         for ( m = 0; m < at->valence; m++ )
    1069                 :             :                         {
    1070                 :             :                             at->neighbor[m] += tot_num_at;
    1071                 :             :                         }
    1072                 :             :                     }
    1073                 :             :                 }
    1074                 :             :                 /* composite counts */
    1075                 :             :                 composite_norm_data[jj].bHasIsotopicLayer |= all_inp_norm_data[i][k].bHasIsotopicLayer;
    1076                 :             :                 composite_norm_data[jj].num_isotopic += all_inp_norm_data[i][k].num_isotopic;
    1077                 :             :                 composite_norm_data[jj].num_bonds += all_inp_norm_data[i][k].num_bonds;
    1078                 :             :                 composite_norm_data[jj].bTautomeric += (j == jj) && all_inp_norm_data[i][k].bTautomeric;
    1079                 :             :                 composite_norm_data[jj].nNumRemovedProtons += all_inp_norm_data[i][k].nNumRemovedProtons;
    1080                 :             :                 for ( n = 0; n < NUM_H_ISOTOPES; n++ )
    1081                 :             :                 {
    1082                 :             :                     composite_norm_data[jj].nNumRemovedProtonsIsotopic[n] += all_inp_norm_data[i][k].nNumRemovedProtonsIsotopic[n];
    1083                 :             :                     composite_norm_data[jj].num_iso_H[n] += all_inp_norm_data[i][k].num_iso_H[n];
    1084                 :             :                 }
    1085                 :             :                 /*
    1086                 :             :                 composite_norm_data[j].num_at            += cur_num_at + cur_num_H;
    1087                 :             :                 composite_norm_data[j].num_removed_H     += cur_num_H;
    1088                 :             :                 */
    1089                 :             :                 /* total count */
    1090                 :             :                 tot_num_at += cur_num_at;
    1091                 :             :                 tot_num_H += cur_num_H;
    1092                 :             :                 /* offset for the next component */
    1093                 :             :                 if ( composite_norm_data[jj].nOffsetAtAndH )
    1094                 :             :                 {
    1095                 :             :                     composite_norm_data[jj].nOffsetAtAndH[2 * i] = tot_num_at;
    1096                 :             :                     composite_norm_data[jj].nOffsetAtAndH[2 * i + 1] = num_at[jj] + tot_num_H;
    1097                 :             :                 }
    1098                 :             :             }
    1099                 :             :             if ( tot_num_at != num_at[jj] ||
    1100                 :             :                 num_at[jj] + tot_num_H != num_inp_at[jj] )
    1101                 :             :             {
    1102                 :             :                 goto exit_error; /* miscount */
    1103                 :             :             }
    1104                 :             :             composite_norm_data[jj].bExists = (tot_num_at > 0);
    1105                 :             :             ret |= indicator;
    1106                 :             :         }
    1107                 :             :     }
    1108                 :             :     return ret;
    1109                 :             : 
    1110                 :             : exit_error:
    1111                 :             : 
    1112                 :             :     return ret;
    1113                 :             : }
    1114                 :             : #endif
    1115                 :             : 
    1116                 :             : 
    1117                 :             : /****************************************************************************/
    1118                 :           0 : void OrigAtData_DebugTrace(ORIG_ATOM_DATA* d)
    1119                 :             : {
    1120                 :             :     int i, k;
    1121                 :             : 
    1122                 :             :     ITRACE_("\n\n*********************************************************************\n* ORIG_ATOM_DATA @ 0x%p", d);
    1123                 :             :     ITRACE_("\n*  num_inp_atoms = %-d\n*  num_inp_bonds = %-d\n*  num_dimensions = %-d\n*  num_components = %-d",
    1124                 :             :         d->num_inp_atoms, d->num_inp_bonds, d->num_dimensions, d->num_components);
    1125                 :             :     ITRACE_("\n*  ATOMS");
    1126         [ #  # ]:           0 :     for ( i = 0; i < d->num_inp_atoms; i++ )
    1127                 :             :     {
    1128                 :             :         ITRACE_("\n*    #%-5d %s%-d ( charge %-d, rad %-d nH %-d val %-d) [%-f %-f %-f]",
    1129                 :             :             i, d->at[i].elname, d->at[i].orig_at_number, d->at[i].charge, d->at[i].radical, d->at[i].num_H, d->at[i].valence,
    1130                 :             :             d->at[i].x, d->at[i].y, d->at[i].z);
    1131         [ #  # ]:           0 :         if ( d->at[i].valence > 0 )
    1132                 :             :         {
    1133                 :             :             ITRACE_("\n            bonds to     ");
    1134         [ #  # ]:           0 :             for ( k = 0; k < d->at[i].valence; k++ )
    1135                 :             :             {
    1136                 :           0 :                 int nbr = d->at[i].neighbor[k]; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    1137                 :             :                 ITRACE_("%s%-3d ", d->at[nbr].elname, nbr + 1);
    1138                 :             :             }
    1139                 :             :         }
    1140         [ #  # ]:           0 :         if ( d->at[i].valence > 0 )
    1141                 :             :         {
    1142                 :             :             ITRACE_("\n            bond types   ");
    1143         [ #  # ]:           0 :             for ( k = 0; k < d->at[i].valence; k++ )
    1144                 :             :                 ITRACE_("%-3d ", d->at[i].bond_type[k]);
    1145                 :             :         }
    1146                 :             :     }
    1147                 :             :     /*OAD_Polymer_DebugTrace( d->polymer );*/
    1148                 :             :     ITRACE_("\n* V3000 INFO @ 0x%-p", d->v3000);
    1149                 :             :     ITRACE_("\n*\n");
    1150                 :           0 :     if ( d->v3000 )
    1151                 :             :     {
    1152                 :             :         ITRACE_("\n*  n_star_atoms = %-d\n*  n_haptic_bonds = %-d\n*  n_collections = %-d",
    1153                 :             :             d->v3000->n_star_atoms, d->v3000->n_haptic_bonds, d->v3000->n_collections);
    1154                 :             :     }
    1155                 :             :     ITRACE_("\n*\n* End ORIG_ATOM_DATA\n*********************************************************************\n");
    1156                 :             : 
    1157                 :           0 :     return;
    1158                 :             : }
    1159                 :             : 
    1160                 :             : 
    1161                 :             : 
    1162                 :             : /*
    1163                 :             :     Polymer related procedures
    1164                 :             : */
    1165                 :             : 
    1166                 :             : 
    1167                 :             : 
    1168                 :             : 
    1169                 :             : /****************************************************************************
    1170                 :             :  Create a new OAD_PolymerUnit
    1171                 :             : ****************************************************************************/
    1172                 :           0 : OAD_PolymerUnit* OAD_PolymerUnit_New(int       maxatoms,
    1173                 :             :     int       maxbonds,
    1174                 :             :     int       id,
    1175                 :             :     int       label,
    1176                 :             :     int       type,
    1177                 :             :     int       subtype,
    1178                 :             :     int       conn,
    1179                 :             :     char* smt,
    1180                 :             :     int       na,
    1181                 :             :     INT_ARRAY* alist,
    1182                 :             :     int       nb,
    1183                 :             :     INT_ARRAY* blist,
    1184                 :             :     int       nbkbonds,
    1185                 :             :     int** bkbonds)
    1186                 :             : {
    1187                 :           0 :     int k, err = 0;
    1188                 :           0 :     OAD_PolymerUnit* u2 = NULL;
    1189                 :             : 
    1190                 :           0 :     u2 = (OAD_PolymerUnit*)inchi_calloc(1, sizeof(OAD_PolymerUnit));
    1191         [ #  # ]:           0 :     if ( NULL == u2 )
    1192                 :             :     {
    1193                 :           0 :         err = 1;
    1194                 :           0 :         goto exit_function;
    1195                 :             :     }
    1196                 :             : 
    1197                 :           0 :     u2->id = id;
    1198                 :           0 :     u2->label = label;
    1199                 :           0 :     u2->type = type;
    1200                 :           0 :     u2->subtype = subtype;
    1201                 :           0 :     u2->conn = conn;
    1202                 :           0 :     u2->na = na;
    1203                 :           0 :     u2->nb = nb;
    1204                 :           0 :     u2->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1205                 :           0 :     u2->cyclized = 0;
    1206         [ #  # ]:           0 :     for ( k = 0; k < 4; k++ )
    1207                 :             :     {
    1208                 :           0 :         u2->xbr1[k] = 0.0;
    1209                 :           0 :         u2->xbr2[k] = 0.0;
    1210                 :             :     }
    1211                 :           0 :     strcpy(u2->smt, smt);
    1212                 :           0 :     u2->cap1 = -1;
    1213                 :           0 :     u2->end_atom1 = -1;
    1214                 :           0 :     u2->cap2 = -1;
    1215                 :           0 :     u2->end_atom2 = -1;
    1216                 :           0 :     u2->maxbkbonds = maxbonds;
    1217                 :           0 :     u2->nbkbonds = nbkbonds;
    1218                 :           0 :     u2->cap1_is_undef = 0;
    1219                 :           0 :     u2->cap2_is_undef = 0;
    1220                 :             : 
    1221                 :           0 :     u2->alist = NULL;
    1222   [ #  #  #  # ]:           0 :     if ( na > 0 || maxatoms > 0 )
    1223                 :             :     {
    1224         [ #  # ]:           0 :         u2->alist = (int*)inchi_calloc(na > 0 ? na : maxatoms, sizeof(int));
    1225         [ #  # ]:           0 :         if ( !u2->alist )
    1226                 :             :         {
    1227                 :           0 :             err = 2;
    1228                 :           0 :             goto exit_function;
    1229                 :             :         }
    1230         [ #  # ]:           0 :         for ( k = 0; k < na; k++ )
    1231                 :             :         {
    1232                 :           0 :             u2->alist[k] = alist->item[k];
    1233                 :             :         }
    1234                 :             :     }
    1235                 :           0 :     u2->blist = NULL;
    1236   [ #  #  #  # ]:           0 :     if ( nb > 0 || maxbonds > 0 )
    1237                 :             :     {
    1238         [ #  # ]:           0 :         u2->blist = (int*)inchi_calloc(nb > 0 ? 2 * nb : 2 * maxbonds, sizeof(int));
    1239         [ #  # ]:           0 :         if ( !u2->blist )
    1240                 :             :         {
    1241                 :           0 :             err = 3;
    1242                 :           0 :             goto exit_function;
    1243                 :             :         }
    1244         [ #  # ]:           0 :         if ( blist )
    1245                 :             :         {
    1246         [ #  # ]:           0 :             for ( k = 0; k < 2 * nb; k++ )
    1247                 :             :             {
    1248                 :           0 :                 u2->blist[k] = blist->item[k];
    1249                 :             :             }
    1250                 :             :         }
    1251                 :             : 
    1252                 :             :     }
    1253                 :           0 :     u2->bkbonds = NULL;
    1254                 :             : 
    1255                 :           0 : exit_function:
    1256                 :             : 
    1257         [ #  # ]:           0 :     if ( err )
    1258                 :             :     {
    1259                 :           0 :         OAD_PolymerUnit_Free(u2);
    1260                 :           0 :         return NULL;
    1261                 :             :     }
    1262                 :             : 
    1263                 :           0 :     return u2;
    1264                 :             : }
    1265                 :             : 
    1266                 :             : 
    1267                 :             : /****************************************************************************
    1268                 :             :  Create a copy of OAD_PolymerUnit
    1269                 :             : ****************************************************************************/
    1270                 :           0 : OAD_PolymerUnit* OAD_PolymerUnit_CreateCopy(OAD_PolymerUnit* u)
    1271                 :             : {
    1272                 :           0 :     int k, err = 0;
    1273                 :           0 :     OAD_PolymerUnit* u2 = NULL;
    1274                 :             : 
    1275                 :           0 :     u2 = (OAD_PolymerUnit*)inchi_calloc(1, sizeof(OAD_PolymerUnit));
    1276         [ #  # ]:           0 :     if ( NULL == u2 )
    1277                 :             :     {
    1278                 :           0 :         err = 1;
    1279                 :           0 :         goto exit_function;
    1280                 :             :     }
    1281                 :           0 :     u2->id = u->id;
    1282                 :           0 :     u2->type = u->type;
    1283                 :           0 :     u2->subtype = u->subtype;
    1284                 :           0 :     u2->conn = u->conn;
    1285                 :           0 :     u2->label = u->label;
    1286                 :           0 :     u2->na = u->na;
    1287                 :           0 :     u2->nb = u->nb;
    1288                 :           0 :     u2->cyclizable = u->cyclizable;
    1289                 :           0 :     u2->cyclized = u->cyclized;
    1290                 :           0 :     u2->cap1_is_undef = u->cap1_is_undef;
    1291                 :           0 :     u2->cap2_is_undef = u->cap2_is_undef;
    1292                 :             : 
    1293         [ #  # ]:           0 :     for ( k = 0; k < 4; k++ )
    1294                 :             :     {
    1295                 :           0 :         u2->xbr1[k] = u->xbr1[k];
    1296                 :           0 :         u2->xbr2[k] = u->xbr2[k];
    1297                 :             :     }
    1298                 :             : 
    1299                 :           0 :     strcpy(u2->smt, u->smt);
    1300                 :             : 
    1301                 :           0 :     u2->cap1 = u->cap1;
    1302                 :           0 :     u2->end_atom1 = u->end_atom1;
    1303                 :           0 :     u2->cap2 = u->cap2;
    1304                 :           0 :     u2->end_atom2 = u->end_atom2;
    1305                 :           0 :     u2->nbkbonds = u->nbkbonds;
    1306                 :           0 :     u2->maxbkbonds = inchi_max(u->maxbkbonds, u->nbkbonds);
    1307                 :             : 
    1308                 :           0 :     u2->alist = (int*)inchi_calloc(u2->na, sizeof(int));
    1309         [ #  # ]:           0 :     if ( !u2->alist )
    1310                 :             :     {
    1311                 :           0 :         err = 2;
    1312                 :           0 :         goto exit_function;
    1313                 :             :     }
    1314         [ #  # ]:           0 :     for ( k = 0; k < u2->na; k++ )
    1315                 :             :     {
    1316                 :           0 :         u2->alist[k] = u->alist[k];
    1317                 :             :     }
    1318                 :             : 
    1319                 :           0 :     u2->blist = (int*)inchi_calloc(2 * (long long)u2->nb, sizeof(int)); /* djb-rwth: cast operator added */
    1320         [ #  # ]:           0 :     if ( !u2->blist )
    1321                 :             :     {
    1322                 :           0 :         err = 2;
    1323                 :           0 :         goto exit_function;
    1324                 :             :     }
    1325         [ #  # ]:           0 :     for ( k = 0; k < 2 * u2->nb; k++ )
    1326                 :             :     {
    1327                 :           0 :         u2->blist[k] = u->blist[k];
    1328                 :             :     }
    1329                 :             : 
    1330                 :           0 :     err = imat_new(u2->maxbkbonds, 2, &(u2->bkbonds));
    1331         [ #  # ]:           0 :     if ( !err )
    1332                 :             :     {
    1333         [ #  # ]:           0 :         for ( k = 0; k < u2->nbkbonds; k++ )
    1334                 :             :         {
    1335                 :           0 :             u2->bkbonds[k][0] = u->bkbonds[k][0];
    1336                 :           0 :             u2->bkbonds[k][1] = u->bkbonds[k][1];
    1337                 :             :         }
    1338                 :             :     }
    1339                 :             : 
    1340                 :           0 : exit_function:
    1341         [ #  # ]:           0 :     if ( err )
    1342                 :             :     {
    1343                 :           0 :         OAD_PolymerUnit_Free(u2);
    1344                 :           0 :         return NULL;
    1345                 :             :     }
    1346                 :             : 
    1347                 :           0 :     return u2;
    1348                 :             : }
    1349                 :             : 
    1350                 :             : 
    1351                 :             : /****************************************************************************/
    1352                 :           0 : void OAD_PolymerUnit_Free(OAD_PolymerUnit* unit)
    1353                 :             : {
    1354                 :             : 
    1355                 :             :     ITRACE_("\n************** About to free OAD_PolymerUnit @ %-p\n", unit);
    1356                 :           0 :     OAD_PolymerUnit_DebugTrace(unit);
    1357                 :             : 
    1358         [ #  # ]:           0 :     if ( unit )
    1359                 :             :     {
    1360         [ #  # ]:           0 :         if ( unit->alist )
    1361                 :             :         {
    1362         [ #  # ]:           0 :             inchi_free(unit->alist);
    1363                 :           0 :             unit->alist = NULL;
    1364                 :             :         }
    1365         [ #  # ]:           0 :         if ( unit->blist )
    1366                 :             :         {
    1367         [ #  # ]:           0 :             inchi_free(unit->blist);
    1368                 :           0 :             unit->blist = NULL;
    1369                 :             :         }
    1370         [ #  # ]:           0 :         if ( unit->bkbonds )
    1371                 :             :         {
    1372                 :           0 :             imat_free(unit->maxbkbonds, unit->bkbonds);
    1373                 :           0 :             unit->bkbonds = NULL;
    1374                 :             :         }
    1375                 :             :     }
    1376                 :             : 
    1377         [ #  # ]:           0 :     inchi_free(unit);
    1378                 :             : 
    1379                 :           0 :     return;
    1380                 :             : }
    1381                 :             : 
    1382                 :             : 
    1383                 :             : /****************************************************************************
    1384                 :             :  Compare two polymer units, modified lexicographic order
    1385                 :             :     Modification: unit with smaller alist always go first
    1386                 :             : ****************************************************************************/
    1387                 :           0 : int  OAD_PolymerUnit_CompareAtomListsMod(OAD_PolymerUnit* u1,
    1388                 :             :     OAD_PolymerUnit* u2)
    1389                 :             : {
    1390                 :             :     int i;
    1391                 :           0 :     int n1 = u1->na;
    1392                 :           0 :     int n2 = u2->na;
    1393                 :           0 :     int n = n1;
    1394         [ #  # ]:           0 :     if ( n1 < n2 )    return -1;
    1395         [ #  # ]:           0 :     if ( n1 > n2 )    return 1;
    1396                 :             :     /* n1 == n2 == n */
    1397         [ #  # ]:           0 :     for ( i = 0; i < n; i++ )
    1398                 :             :     {
    1399         [ #  # ]:           0 :         if ( u1->alist[i] < u2->alist[i] )    return -1;
    1400         [ #  # ]:           0 :         if ( u1->alist[i] > u2->alist[i] )    return    1;
    1401                 :             :     }
    1402                 :             : 
    1403                 :           0 :     return 0;
    1404                 :             : }
    1405                 :             : 
    1406                 :             : 
    1407                 :             : /****************************************************************************
    1408                 :             :  Compare two polymer units, lexicographic order
    1409                 :             : ****************************************************************************/
    1410                 :           0 : int  OAD_PolymerUnit_CompareAtomLists(OAD_PolymerUnit* u1,
    1411                 :             :     OAD_PolymerUnit* u2)
    1412                 :             : {
    1413                 :             :     int i;
    1414                 :           0 :     int n1 = u1->na;
    1415                 :           0 :     int n2 = u2->na;
    1416                 :           0 :     int n = inchi_min(n1, n2);
    1417                 :             : 
    1418         [ #  # ]:           0 :     for ( i = 0; i < n; i++ )
    1419                 :             :     {
    1420         [ #  # ]:           0 :         if ( u1->alist[i] < u2->alist[i] )
    1421                 :             :         {
    1422                 :           0 :             return -1;
    1423                 :             :         }
    1424         [ #  # ]:           0 :         if ( u1->alist[i] > u2->alist[i] )
    1425                 :             :         {
    1426                 :           0 :             return 1;
    1427                 :             :         }
    1428                 :             :     }
    1429                 :             : 
    1430         [ #  # ]:           0 :     if ( n1 < n2 )
    1431                 :             :     {
    1432                 :           0 :         return -1;
    1433                 :             :     }
    1434                 :             : 
    1435         [ #  # ]:           0 :     if ( n1 > n2 )
    1436                 :             :     {
    1437                 :           0 :         return    1;
    1438                 :             :     }
    1439                 :             : 
    1440                 :           0 :     return 0;
    1441                 :             : }
    1442                 :             : 
    1443                 :             : 
    1444                 :             : /****************************************************************************
    1445                 :             :  Sort SRU bond lists atoms and bonds themselves
    1446                 :             : ****************************************************************************/
    1447                 :           0 : int  OAD_PolymerUnit_OrderBondAtomsAndBondsThemselves(OAD_PolymerUnit* u,
    1448                 :             :     int n_star_atoms,
    1449                 :             :     int* star_atoms)
    1450                 :             : {
    1451                 :             :     int k;
    1452                 :             : 
    1453                 :             :     /* Sort bond atoms */
    1454         [ #  # ]:           0 :     for ( k = 0; k < u->nb; k++ )
    1455                 :             :     {
    1456                 :             :         /* Place not-in-unit bond end to first place */
    1457                 :           0 :         int a1 = u->blist[2 * k];
    1458                 :           0 :         int a2 = u->blist[2 * k + 1];
    1459                 :           0 :         int a1_is_not_in_alist = 0;
    1460                 :           0 :         int a1_is_star_atom = 0;
    1461                 :           0 :         int a2_is_not_in_alist = 0;
    1462                 :           0 :         int a2_is_star_atom = 0;
    1463                 :             : 
    1464         [ #  # ]:           0 :         if ( !is_in_the_ilist(u->alist, a1, u->na) )
    1465                 :             :         {
    1466                 :           0 :             a1_is_not_in_alist = 1;
    1467                 :             :         }
    1468         [ #  # ]:           0 :         if ( is_in_the_ilist(star_atoms, a1, n_star_atoms) )
    1469                 :             :         {
    1470                 :           0 :             a1_is_star_atom = 1;
    1471                 :             :         }
    1472                 :             : 
    1473         [ #  # ]:           0 :         if ( !is_in_the_ilist(u->alist, a2, u->na) )
    1474                 :             :         {
    1475                 :           0 :             a2_is_not_in_alist = 1;
    1476                 :             :         }
    1477         [ #  # ]:           0 :         if ( is_in_the_ilist(star_atoms, a2, n_star_atoms) )
    1478                 :             :         {
    1479                 :           0 :             a2_is_star_atom = 1;
    1480                 :             :         }
    1481                 :             : 
    1482   [ #  #  #  #  :           0 :         if ( (a1_is_not_in_alist || a1_is_star_atom) &&
                   #  # ]
    1483         [ #  # ]:           0 :             (a2_is_not_in_alist || a2_is_star_atom) )
    1484                 :             :         {
    1485                 :             :             /* Both the ends are out of unit: the crossing bond is invalid */
    1486                 :           0 :             return 1;
    1487                 :             :         }
    1488                 :             :         /* If a2 is star atom or non-star external to the current unit, swap(a2,a1) */
    1489   [ #  #  #  # ]:           0 :         if ( a2_is_star_atom || a2_is_not_in_alist )
    1490                 :             :         {
    1491                 :           0 :             u->blist[2 * k] = a2;
    1492                 :           0 :             u->blist[2 * k + 1] = a1;
    1493                 :             :         }
    1494                 :             :     }
    1495                 :             : 
    1496                 :             :     /* Sort bond themselves
    1497                 :             :         for now, consider only the simplest cases of 2 bonds
    1498                 :             :     */
    1499         [ #  # ]:           0 :     if ( u->nb == 2 )            /* two bonds in SBL */
    1500                 :             :     {
    1501                 :           0 :         int b1a1 = u->blist[0];
    1502                 :           0 :         int b1a2 = u->blist[1];
    1503                 :           0 :         int b2a1 = u->blist[2];
    1504                 :           0 :         int b2a2 = u->blist[3];
    1505         [ #  # ]:           0 :         if ( b1a1 > b2a1 )
    1506                 :             :         {
    1507                 :             :             /* swap */
    1508                 :           0 :             u->blist[0] = b2a1; u->blist[1] = b2a2;
    1509                 :           0 :             u->blist[2] = b1a1; u->blist[3] = b1a2;
    1510                 :             :         }
    1511                 :             :     }
    1512                 :             : 
    1513                 :             :     /* for single or no bonds, do nothing
    1514                 :             :     else
    1515                 :             :         ;
    1516                 :             :     */
    1517                 :             : 
    1518                 :           0 :     return 0;
    1519                 :             : }
    1520                 :             : 
    1521                 :             : 
    1522                 :             : /****************************************************************************
    1523                 :             :  Parse pseudoelement and polymer data
    1524                 :             :  (unit, types, subtypes, connections, etc.)
    1525                 :             : ****************************************************************************/
    1526                 :          54 : int OAD_ValidatePolymerAndPseudoElementData(ORIG_ATOM_DATA* orig_at_data,
    1527                 :             :     int treat_polymers,
    1528                 :             :     int bNPZz,
    1529                 :             :     char* pStrErr,
    1530                 :             :     int bNoWarnings)
    1531                 :             : {
    1532                 :          54 :     int i, k, kk, type, subtype, representation, err = 0;
    1533                 :          54 :     int nat = orig_at_data->num_inp_atoms;
    1534                 :          54 :     int nsgroups = 0;
    1535                 :          54 :     OAD_PolymerUnit* u = NULL;
    1536                 :          54 :     OAD_Polymer* pd = orig_at_data->polymer;
    1537                 :             : 
    1538                 :             : 
    1539                 :             :     /* Assign polymer type and subunits type and check polymer data for consistency */
    1540                 :             :     /* djb-rwth: addressing coverity ID #499497 -- TREAT_ERR properly used in all cases */
    1541                 :             :     
    1542                 :          54 :     orig_at_data->valid_polymer = 0;
    1543   [ -  +  -  - ]:          54 :     if ( treat_polymers && pd )
    1544                 :             :     {
    1545                 :           0 :         orig_at_data->valid_polymer = 1;
    1546                 :             :     }
    1547         [ -  + ]:          54 :     if ( orig_at_data->valid_polymer )
    1548                 :             :     {
    1549                 :           0 :         nsgroups = pd->n;
    1550                 :             :     }
    1551         [ -  + ]:          54 :     if ( nsgroups == 1 )
    1552                 :             :     {
    1553                 :             :         /* Check if copolymer */
    1554                 :           0 :         type = pd->units[0]->type;
    1555         [ #  # ]:           0 :         if ( type == POLYMER_STY_COP )
    1556                 :             :         {
    1557         [ #  # ]:           0 :             TREAT_ERR(err, 9001, "Copolymer must contain more than one unit");
    1558                 :           0 :             goto exit_function;
    1559                 :             :         }
    1560                 :             :         /* Check if copolymer subtype */
    1561                 :           0 :         subtype = pd->units[0]->subtype;
    1562   [ #  #  #  #  :           0 :         if ( subtype == POLYMER_SST_RAN || subtype == POLYMER_SST_ALT || subtype == POLYMER_SST_BLK )
                   #  # ]
    1563                 :             :         {
    1564         [ #  # ]:           0 :             TREAT_ERR(err, 9002, "Single polymer unit may not be RAN/ALT/BLO");
    1565                 :           0 :             goto exit_function;
    1566                 :             :         }
    1567                 :             :     }
    1568                 :             : 
    1569                 :             :     /* For each CRU */
    1570         [ -  + ]:          54 :     for ( i = 0; i < nsgroups; i++ )
    1571                 :             :     {
    1572                 :             :         /* Check if unit data makes sense */
    1573                 :           0 :         u = pd->units[i];
    1574   [ #  #  #  # ]:           0 :         if ( u->nb != 0 && u->nb != 2 )
    1575                 :             :         {
    1576         [ #  # ]:           0 :             TREAT_ERR(err, 9003, "Number of crossing bonds in polymer unit is not 0 or 2");
    1577                 :           0 :             goto exit_function;
    1578                 :             :         }
    1579         [ #  # ]:           0 :         if ( u->na < 1 )
    1580                 :             :         {
    1581         [ #  # ]:           0 :             TREAT_ERR(err, 9004, "Empty polymer unit");
    1582                 :           0 :             goto exit_function;
    1583                 :             :         }
    1584         [ #  # ]:           0 :         if ( u->na > nat )
    1585                 :             :         {
    1586         [ #  # ]:           0 :             TREAT_ERR(err, 9005, "Too large polymer unit");
    1587                 :           0 :             goto exit_function;
    1588                 :             :         }
    1589         [ #  # ]:           0 :         for ( k = 0; k < u->na; k++ )
    1590                 :             :         {
    1591                 :           0 :             int atom = u->alist[k];
    1592   [ #  #  #  # ]:           0 :             if ( atom < 1 || atom > nat )
    1593                 :             :             {
    1594         [ #  # ]:           0 :                 TREAT_ERR(err, 9006, "Invalid atom number in polymer unit");
    1595                 :           0 :                 goto exit_function;
    1596                 :             :             }
    1597                 :             :             /* was not accounting for COP ...
    1598                 :             :             if (is_in_the_ilist( pd->pzz, atom, pd->n_pzz ))
    1599                 :             :             {
    1600                 :             :                 TREAT_ERR( err, 9007, "Star atom inside polymer unit" );
    1601                 :             :                 goto exit_function;
    1602                 :             :             }
    1603                 :             :             */
    1604                 :             :         }
    1605                 :             : 
    1606                 :           0 :         OAD_PolymerUnit_SetEndsAndCaps(u, orig_at_data, &err, pStrErr);
    1607                 :             :         /*      Reveal and store CRU caps and ends('stars and partners')
    1608                 :             :             Also set `unit->cap1_is_undef`, `unit->cap2_is_undef`, `unit->cyclizable`
    1609                 :             :         */
    1610         [ #  # ]:           0 :         if ( err )
    1611                 :             :         {
    1612                 :           0 :             goto exit_function;
    1613                 :             :         }
    1614                 :             : 
    1615                 :             : 
    1616                 :             :         /* Set possibly missing unit parameters */
    1617                 :           0 :         u->nbkbonds = 0;
    1618                 :           0 :         u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1619                 :           0 :         u->cyclized = 0;
    1620                 :             :     }
    1621                 :             : 
    1622                 :             : 
    1623                 :          54 :     OAD_ValidateAndSortOutPseudoElementAtoms(orig_at_data, treat_polymers, bNPZz, &err, pStrErr);
    1624                 :             :     /* Here we:
    1625                 :             :                 Make more polymer and pseudoatom data checks
    1626                 :             :                 Convert both "*" and "Zz" temporarily to "Zy" (polymer-unrelated interal pseudoatoms)
    1627                 :             :                 If applicable, check each CRU and back-convert "Zy" to "Zz" (polymer-related
    1628                 :             :                 pseudoelement atoms) if they are for valid bi-undef-end CRU
    1629                 :             :     */
    1630                 :             : 
    1631         [ -  + ]:          54 :     if ( err )
    1632                 :             :     {
    1633                 :             :         /* already treated TREAT_ERR( err, 9040, "Improper pseudoelement atoms" ); */
    1634                 :           0 :         goto exit_function;
    1635                 :             :     }
    1636                 :             : 
    1637                 :             : 
    1638                 :             :     /* Make more polymer and pseudoatom data checks */
    1639                 :             : 
    1640                 :             :     /* Check if non-polymer-related Zz/star atoms enabled */
    1641   [ -  +  -  - ]:          54 :     if ( orig_at_data->n_zy > 0 && bNPZz == 0 )
    1642                 :             :     {
    1643         [ #  # ]:           0 :         TREAT_ERR(err, 9, "Non-polymer-related Zz/star atoms are not allowed");
    1644                 :           0 :         goto exit_function;
    1645                 :             :     }
    1646                 :             : 
    1647   [ -  +  -  - ]:          54 :     if ( !pd || !orig_at_data->valid_polymer )
    1648                 :             :     {
    1649                 :          54 :         goto exit_function;
    1650                 :             :     }
    1651                 :             : 
    1652         [ #  # ]:           0 :     if ( pd->n_pzz > 0 )
    1653                 :             :     {
    1654                 :             :         /* Allocate memory for polymer-related pseudoatoms */
    1655         [ #  # ]:           0 :         if ( pd->treat == POLYMERS_NO )
    1656                 :             :         {
    1657         [ #  # ]:           0 :             TREAT_ERR(err, 9, "Pseudoelement endgroups are not allowed");
    1658                 :           0 :             goto exit_function;
    1659                 :             :         }
    1660         [ #  # ]:           0 :         if ( pd->pzz )
    1661                 :             :         {
    1662         [ #  # ]:           0 :             inchi_free(pd->pzz);
    1663                 :           0 :             pd->pzz = NULL;
    1664                 :             :         }
    1665                 :           0 :         pd->pzz = (int*)inchi_calloc(pd->n_pzz, sizeof(int));
    1666         [ #  # ]:           0 :         if ( !pd->pzz )
    1667                 :             :         {
    1668         [ #  # ]:           0 :             TREAT_ERR(err, 9010, "Not enough memory");
    1669                 :           0 :             goto exit_function;
    1670                 :             :         }
    1671                 :           0 :         kk = 0;
    1672         [ #  # ]:           0 :         for ( k = 0; k < nat; k++ )
    1673                 :             :         {
    1674         [ #  # ]:           0 :             if ( !strcmp(orig_at_data->at[k].elname, "Zz") )
    1675                 :             :             {
    1676                 :           0 :                 pd->pzz[kk++] = k + 1; /* djb-rwth: buffer overrun avoided implicitly */
    1677                 :             :             }
    1678                 :             :         }
    1679                 :             :     }
    1680                 :             : 
    1681                 :             :     /* Check copolymers and ensure that COP includes > 1 SRU */
    1682         [ #  # ]:           0 :     for ( i = 0; i < pd->n; i++ )
    1683                 :             :     {
    1684                 :           0 :         u = pd->units[i];
    1685                 :             : 
    1686         [ #  # ]:           0 :         if ( u->type == POLYMER_STY_COP ||
    1687         [ #  # ]:           0 :             u->type == POLYMER_STY_SRU     /* what drawn as 'SRU' [xyz]n may be actually copolymer [xyz]co */
    1688                 :             :             )
    1689                 :             :         {
    1690                 :           0 :             int j, in_units = 0;
    1691                 :             : 
    1692         [ #  # ]:           0 :             if ( u->nb > 0 )
    1693                 :             :             {
    1694                 :             :                 /* crossing bonds present, either valid SRU or invalid copolymer */
    1695         [ #  # ]:           0 :                 if ( u->type == POLYMER_STY_COP )
    1696                 :             :                 {
    1697         [ #  # ]:           0 :                     TREAT_ERR(err, 9026, "Polymer COP unit contains bracket-crossing bonds, not supported");
    1698                 :           0 :                     goto exit_function;
    1699                 :             :                 }
    1700                 :             :                 else
    1701                 :             :                 {
    1702                 :           0 :                     continue;
    1703                 :             :                 }
    1704                 :             :             }
    1705                 :             :             /* now we have no crossing bonds units */
    1706         [ #  # ]:           0 :             for ( j = 0; j < pd->n; j++ )
    1707                 :             :             {
    1708         [ #  # ]:           0 :                 if ( pd->units[j]->type == POLYMER_STY_COP )
    1709                 :             :                 {
    1710                 :           0 :                     continue;
    1711                 :             :                 }
    1712         [ #  # ]:           0 :                 if ( is_ilist_inside(pd->units[j]->alist, pd->units[j]->na, pd->units[i]->alist, pd->units[i]->na) )
    1713                 :             :                 {
    1714                 :           0 :                     in_units++;
    1715         [ #  # ]:           0 :                     if ( in_units == 2 )
    1716                 :             :                     {
    1717                 :           0 :                         break;
    1718                 :             :                     }
    1719                 :             :                 }
    1720                 :             :             }
    1721         [ #  # ]:           0 :             if ( in_units > 1 )
    1722                 :             :             {
    1723         [ #  # ]:           0 :                 if ( u->type != POLYMER_STY_COP )
    1724                 :             :                 {
    1725                 :           0 :                     u->type = POLYMER_STY_COP;
    1726         [ #  # ]:           0 :                     if ( !bNoWarnings )
    1727                 :             :                     {
    1728                 :           0 :                         WarningMessage(pStrErr, "Convert multiple-subunits unit to copolymer");
    1729                 :             :                     }
    1730                 :             :                 }
    1731                 :             :             }
    1732                 :             :             else    /* in_units <= 1)*/
    1733                 :             :             {
    1734         [ #  # ]:           0 :                 if ( u->type == POLYMER_STY_COP )
    1735                 :             :                 {
    1736         [ #  # ]:           0 :                     TREAT_ERR(err, 9027, "Polymer COP unit contains a single SRU instead of multiple");
    1737                 :           0 :                     goto exit_function;
    1738                 :             :                 }
    1739                 :             :             }
    1740                 :             :         }
    1741                 :             :     }
    1742                 :             : 
    1743                 :           0 :     representation = OAD_Polymer_GetRepresentation(pd);
    1744                 :             : 
    1745                 :             :     /* Make more polymer data checks and perform some corrections*/
    1746         [ #  # ]:           0 :     if ( representation == POLYMER_REPRESENTATION_SOURCE_BASED )
    1747                 :             :     {
    1748         [ #  # ]:           0 :         for ( i = 0; i < nsgroups; i++ )
    1749                 :             :         {
    1750                 :             :             /* Replace source-based 'SRU' with 'MON' */
    1751         [ #  # ]:           0 :             if ( pd->units[i]->type == POLYMER_STY_SRU )
    1752                 :             :             {
    1753                 :           0 :                 pd->units[i]->type = POLYMER_STY_MON;
    1754         [ #  # ]:           0 :                 if ( !bNoWarnings )
    1755                 :             :                 {
    1756                 :           0 :                     WarningMessage(pStrErr, "Converted src-based polymer unit type to MON");
    1757                 :             :                 }
    1758                 :             :             }
    1759         [ #  # ]:           0 :             if ( pd->units[i]->type == POLYMER_STY_COP )
    1760                 :             :             {
    1761                 :             :                 /* Set missing copolymer subtype to RAN */
    1762         [ #  # ]:           0 :                 if ( pd->units[i]->subtype == POLYMER_SST_NON )
    1763                 :             :                 {
    1764                 :           0 :                     pd->units[i]->subtype = POLYMER_SST_RAN;
    1765         [ #  # ]:           0 :                     if ( !bNoWarnings )
    1766                 :             :                     {
    1767                 :           0 :                         WarningMessage(pStrErr, "Set missing copolymer subtype to RAN");
    1768                 :             :                     }
    1769                 :             :                 }
    1770                 :             :             }
    1771                 :             :             /* Suppress connectivity ("HH", "HT", "EU") */
    1772         [ #  # ]:           0 :             if ( pd->units[i]->conn != POLYMER_CONN_NON )
    1773                 :             :             {
    1774                 :           0 :                 pd->units[i]->conn = POLYMER_CONN_NON;
    1775         [ #  # ]:           0 :                 if ( !bNoWarnings )
    1776                 :             :                 {
    1777                 :           0 :                     WarningMessage(pStrErr, "Ignore connection pattern for src-based polymer unit");
    1778                 :             :                 }
    1779                 :             :             }
    1780                 :             :         }
    1781                 :             :     }
    1782                 :             : 
    1783                 :             : #ifdef ALLOW_MIXED_SRU_AND_MON
    1784   [ #  #  #  # ]:           0 :     else if ( representation == POLYMER_REPRESENTATION_STRUCTURE_BASED ||
    1785                 :             :         representation == POLYMER_REPRESENTATION_MIXED )
    1786                 :             : #else
    1787                 :             :     else if ( representation == POLYMER_REPRESENTATION_STRUCTURE_BASED )
    1788                 :             : #endif
    1789                 :             :     {
    1790         [ #  # ]:           0 :         for ( i = 0; i < nsgroups; i++ )
    1791                 :             :         {
    1792                 :             :             int a1, a2, a1_is_not_in_alist, a1_is_star_atom, a2_is_not_in_alist, a2_is_star_atom;
    1793                 :             : 
    1794                 :           0 :             u = pd->units[i];
    1795                 :             : 
    1796                 :             :             /*    SRU that is copolymer unit embedding other SRU's */
    1797         [ #  # ]:           0 :             if ( u->nb == 0 )
    1798                 :             :             {
    1799         [ #  # ]:           0 :                 if ( u->type == POLYMER_STY_COP )
    1800                 :             :                 {
    1801                 :             :                     ;
    1802                 :             :                 }
    1803         [ #  # ]:           0 :                 else if ( u->type == POLYMER_STY_SRU )
    1804                 :             :                 {
    1805                 :           0 :                     u->type = POLYMER_STY_COP;
    1806         [ #  # ]:           0 :                     if ( !bNoWarnings )
    1807                 :             :                     {
    1808                 :           0 :                         WarningMessage(pStrErr, "Set copolymer embedding unit mark to COP");
    1809                 :             :                     }
    1810                 :             :                 }
    1811                 :             :             }
    1812         [ #  # ]:           0 :             if ( u->type == POLYMER_STY_COP )
    1813                 :             :             {
    1814                 :           0 :                 u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1815                 :             :                 /* Set possibly missing copolymer subtype to RAN */
    1816         [ #  # ]:           0 :                 if ( u->subtype == POLYMER_SST_NON )
    1817                 :             :                 {
    1818                 :           0 :                     u->subtype = POLYMER_SST_RAN;
    1819         [ #  # ]:           0 :                     if ( !bNoWarnings )
    1820                 :             :                     {
    1821                 :           0 :                         WarningMessage(pStrErr, "Set missing copolymer subtype to RAN");
    1822                 :             :                     }
    1823                 :             :                 }
    1824                 :           0 :                 continue;
    1825                 :             :             }
    1826                 :             : 
    1827                 :             : #ifdef ALLOW_MIXED_SRU_AND_MON
    1828         [ #  # ]:           0 :             if ( u->type == POLYMER_STY_MON )
    1829                 :             :             {
    1830                 :           0 :                 continue;
    1831                 :             :             }
    1832                 :             : #endif
    1833                 :             :             /*    SRU with endgroups or stars. Check it. */
    1834         [ #  # ]:           0 :             for ( k = 0; k < u->nb; k++ )
    1835                 :             :             {
    1836                 :             :                 /* Check that there are no H end groups */
    1837                 :           0 :                 a1 = u->blist[2 * k]; a2 = u->blist[2 * k + 1];
    1838         [ #  # ]:           0 :                 if ( !strcmp(orig_at_data->at[a1 - 1].elname, "H") ||
    1839         [ #  # ]:           0 :                     !strcmp(orig_at_data->at[a1 - 1].elname, "D") ||
    1840         [ #  # ]:           0 :                     !strcmp(orig_at_data->at[a1 - 1].elname, "T") )
    1841                 :             :                 {
    1842         [ #  # ]:           0 :                     TREAT_ERR(err, 9030, "H as polymer end group is not supported");
    1843                 :           0 :                     goto exit_function;
    1844                 :             :                 }
    1845         [ #  # ]:           0 :                 if ( !strcmp(orig_at_data->at[a2 - 1].elname, "H") ||
    1846         [ #  # ]:           0 :                     !strcmp(orig_at_data->at[a2 - 1].elname, "D") ||
    1847         [ #  # ]:           0 :                     !strcmp(orig_at_data->at[a2 - 1].elname, "T") )
    1848                 :             :                 {
    1849         [ #  # ]:           0 :                     TREAT_ERR(err, 9031, "H as polymer end group is not supported");
    1850                 :           0 :                     goto exit_function;
    1851                 :             :                 }
    1852                 :             :                 /* Ensure that caps of polymer unit lie outside it */
    1853                 :           0 :                 a1_is_not_in_alist = a1_is_star_atom = 0;
    1854                 :           0 :                 a2_is_not_in_alist = a2_is_star_atom = 0;
    1855         [ #  # ]:           0 :                 if ( !is_in_the_ilist(u->alist, a1, u->na) )
    1856                 :             :                 {
    1857                 :           0 :                     a1_is_not_in_alist = 1;
    1858                 :             :                 }
    1859         [ #  # ]:           0 :                 if ( is_in_the_ilist(pd->pzz, a1, pd->n_pzz) )
    1860                 :             :                 {
    1861                 :           0 :                     a1_is_star_atom = 1;
    1862                 :             :                 }
    1863         [ #  # ]:           0 :                 if ( !is_in_the_ilist(u->alist, a2, u->na) )
    1864                 :             :                 {
    1865                 :           0 :                     a2_is_not_in_alist = 1;
    1866                 :             :                 }
    1867         [ #  # ]:           0 :                 if ( is_in_the_ilist(pd->pzz, a2, pd->n_pzz) )
    1868                 :             :                 {
    1869                 :           0 :                     a2_is_star_atom = 1;
    1870                 :             :                 }
    1871   [ #  #  #  #  :           0 :                 if ( (a1_is_not_in_alist || a1_is_star_atom) &&
                   #  # ]
    1872         [ #  # ]:           0 :                     (a2_is_not_in_alist || a2_is_star_atom) )
    1873                 :             :                 {
    1874         [ #  # ]:           0 :                     TREAT_ERR(err, 9032, "Caps of polymer unit lie inside it");
    1875                 :           0 :                     goto exit_function;
    1876                 :             :                 }
    1877                 :             :             }
    1878                 :             : 
    1879   [ #  #  #  # ]:           0 :             if ( u->type == POLYMER_STY_SRU || u->type == POLYMER_STY_MOD ||
    1880   [ #  #  #  # ]:           0 :                 u->type == POLYMER_STY_CRO || u->type == POLYMER_STY_MER )
    1881                 :             :             {
    1882                 :             :                 /* If SRU connection is missing, set to default ('either') */
    1883         [ #  # ]:           0 :                 if ( u->conn == POLYMER_CONN_NON )
    1884                 :             :                 {
    1885         [ #  # ]:           0 :                     if ( !bNoWarnings )
    1886                 :             :                     {
    1887                 :           0 :                         WarningMessage(pStrErr, "Set missing copolymer unit connection to EU");
    1888                 :             :                     }
    1889                 :           0 :                     u->conn = POLYMER_CONN_EU;
    1890                 :             :                 }
    1891                 :             : 
    1892   [ #  #  #  # ]:           0 :                 if ( u->cap1 && u->cap2 )
    1893                 :             :                 {
    1894                 :             :                     /* Set SRU closure type */
    1895         [ #  # ]:           0 :                     if ( u->na == 1 )
    1896                 :             :                     {
    1897                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_DIRADICAL
    1898                 :           0 :                         u->cyclizable = CLOSING_SRU_DIRADICAL;
    1899                 :             : #else
    1900                 :             :                         u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1901                 :             : #ifdef  CLOSING_STARRED_SRU_IS_A_MUST
    1902                 :             :                         TREAT_ERR(err, 9029, "Could not perform SRU closure");
    1903                 :             :                         goto exit_function;
    1904                 :             : #endif
    1905                 :             : #endif
    1906                 :             :                     }
    1907         [ #  # ]:           0 :                     else if ( u->na == 2 )
    1908                 :             :                     {
    1909                 :             : 
    1910                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_HIGHER_ORDER_BOND
    1911                 :           0 :                         u->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;
    1912                 :             : #else
    1913                 :             :                         u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1914                 :             : #ifdef  CLOSING_STARRED_SRU_IS_A_MUST
    1915                 :             :                         TREAT_ERR(err, 9029, "Could not perform SRU closure");
    1916                 :             :                         goto exit_function;
    1917                 :             : #endif
    1918                 :             : #endif
    1919                 :             :                     }
    1920                 :             :                     else
    1921                 :             :                     {
    1922                 :           0 :                         u->cyclizable = CLOSING_SRU_RING;
    1923                 :             :                     }
    1924                 :             :                 }
    1925                 :             : 
    1926         [ #  # ]:           0 :                 if ( u->conn != POLYMER_CONN_HT )
    1927                 :             :                 {
    1928                 :             :                     /* frame shift/SRU cyclization is for head-to-tail connections only */
    1929                 :           0 :                     u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    1930                 :             :                 }
    1931                 :             : 
    1932         [ #  # ]:           0 :                 if ( u->cyclizable != CLOSING_SRU_NOT_APPLICABLE )
    1933                 :             :                 {
    1934                 :             :                     /* Allocate PS (frame-shiftable) bonds */
    1935         [ #  # ]:           0 :                     if ( u->bkbonds )
    1936                 :             :                     {
    1937                 :           0 :                         imat_free(u->maxbkbonds, u->bkbonds);
    1938                 :           0 :                         u->bkbonds = NULL;
    1939                 :             :                     }
    1940                 :           0 :                     u->maxbkbonds = orig_at_data->num_inp_bonds + 2;
    1941                 :           0 :                     err = imat_new(u->maxbkbonds, 2, &(u->bkbonds));
    1942         [ #  # ]:           0 :                     if ( err )
    1943                 :             :                     {
    1944         [ #  # ]:           0 :                         TREAT_ERR(err, 9034, "Not enough memory (polymers)");
    1945                 :           0 :                         goto exit_function;
    1946                 :             :                     }
    1947                 :             :                 }
    1948                 :             :             }
    1949                 :             : 
    1950                 :             :         }
    1951                 :             :     }
    1952                 :             :     else
    1953                 :             :     {
    1954         [ #  # ]:           0 :         TREAT_ERR(err, 9035, "Invalid kind of polymer representation");
    1955                 :           0 :         goto exit_function;
    1956                 :             :     }
    1957                 :             : 
    1958                 :           0 :     orig_at_data->valid_polymer = 1;
    1959                 :             : 
    1960                 :          54 : exit_function:
    1961         [ -  + ]:          54 :     if ( err )
    1962                 :             :     {
    1963                 :           0 :         orig_at_data->valid_polymer = 0;
    1964                 :             :     }
    1965                 :             : 
    1966                 :          54 :     return err;
    1967                 :             : }
    1968                 :             : 
    1969                 :             : 
    1970                 :             : /****************************************************************************/
    1971                 :           0 : int UnMarkRingSystemsInp(inp_ATOM* at, int num_atoms)
    1972                 :             : {
    1973                 :             :     int i;
    1974         [ #  # ]:           0 :     for ( i = 0; i < num_atoms; i++ )
    1975                 :             :     {
    1976                 :           0 :         at[i].bCutVertex = 0;
    1977                 :           0 :         at[i].nRingSystem = 0;
    1978                 :           0 :         at[i].nNumAtInRingSystem = 0;
    1979                 :           0 :         at[i].nBlockSystem = 0;
    1980                 :             :     }
    1981                 :             : 
    1982                 :           0 :     return 0;
    1983                 :             : }
    1984                 :             : 
    1985                 :             : 
    1986                 :             : /****************************************************************************
    1987                 :             :  Preprocess OAD_Polymer (NB: frame shift is invoked from here)
    1988                 :             : ****************************************************************************/
    1989                 :           0 : int OAD_Polymer_CyclizeCloseableUnits(ORIG_ATOM_DATA* orig_at_data,
    1990                 :             :     int treat_polymers,
    1991                 :             :     char* pStrErr,
    1992                 :             :     int bNoWarnings)
    1993                 :             : {
    1994                 :           0 :     int i, err = 0; /* djb-rwth: removing redundant variables */
    1995                 :             : 
    1996         [ #  # ]:           0 :     for ( i = 0; i < orig_at_data->polymer->n; i++ )
    1997                 :             :     {
    1998                 :           0 :         OAD_PolymerUnit* unit = orig_at_data->polymer->units[i];
    1999                 :             : 
    2000         [ #  # ]:           0 :         if ( !unit->cyclizable )
    2001                 :             :         {
    2002                 :           0 :             continue;
    2003                 :             :         }
    2004                 :             : 
    2005                 :             :         /* Find stars and their partners */
    2006                 :           0 :         OAD_PolymerUnit_SetEndsAndCaps(unit, orig_at_data, &err, pStrErr);
    2007                 :             :         /*      Reveal and store CRU caps and ends('stars and partners')
    2008                 :             :             Also set `unit->cap1_is_undef`, `unit->cap2_is_undef`, `unit->cyclizable`
    2009                 :             :         */
    2010         [ #  # ]:           0 :         if ( err )
    2011                 :             :         {
    2012                 :           0 :             break;
    2013                 :             :         }
    2014         [ #  # ]:           0 :         if ( !unit->cyclizable )
    2015                 :             :         {
    2016                 :           0 :             continue;
    2017                 :             :         }
    2018                 :             : 
    2019                 :             : 
    2020         [ #  # ]:           0 :         if ( OAD_PolymerUnit_HasMetal(unit, orig_at_data->at) )
    2021                 :             :         {
    2022                 :             :             /*unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;*/
    2023         [ #  # ]:           0 :             if ( unit->cyclizable == CLOSING_SRU_RING )
    2024                 :             :             {
    2025                 :             :                 /*unit->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;*/
    2026         [ #  # ]:           0 :                 if ( !bNoWarnings )
    2027                 :             :                 {
    2028                 :           0 :                     WarningMessage(pStrErr, "Frame shift in metallated polymer unit may be missed");
    2029                 :             :                 }
    2030                 :             :             }
    2031                 :             :         }
    2032                 :             : 
    2033                 :             :         /* Now remove bonds to cap ("star atoms and cyclize a SRU */
    2034                 :           0 :         OAD_PolymerUnit_UnlinkCapsAndConnectEndAtoms(unit, orig_at_data, &err, pStrErr);
    2035                 :             : 
    2036         [ #  # ]:           0 :         if ( err )
    2037                 :             :         {
    2038                 :           0 :             break;
    2039                 :             :         }
    2040         [ #  # ]:           0 :         if ( !unit->cyclizable )
    2041                 :             :         {
    2042                 :           0 :             continue;
    2043                 :             :         }
    2044                 :             : 
    2045                 :             :         /* djb-rwth: removing redundant code */
    2046                 :             :     }
    2047                 :             : 
    2048                 :             :     /*
    2049                 :             :     if ( ncyclized )
    2050                 :             :     {
    2051                 :             :         if (!bNoWarnings)
    2052                 :             :         {
    2053                 :             :             WarningMessage( pStrErr, "Made provision for frame shift in polymer unit(s)" );
    2054                 :             :         }
    2055                 :             :     }
    2056                 :             :     */
    2057                 :             : 
    2058                 :           0 :     return err;
    2059                 :             : }
    2060                 :             : 
    2061                 :             : 
    2062                 :             : /****************************************************************************
    2063                 :             :  Check if SRU contains metal
    2064                 :             : ****************************************************************************/
    2065                 :           0 : int OAD_PolymerUnit_HasMetal(OAD_PolymerUnit* u, inp_ATOM* at)
    2066                 :             : {
    2067                 :             :     int i;
    2068         [ #  # ]:           0 :     for ( i = 0; i < u->na; i++ )
    2069                 :             :     {
    2070         [ #  # ]:           0 :         if ( is_el_a_metal(at[u->alist[i] - 1].el_number) )
    2071                 :             :         {
    2072                 :           0 :             return 1;
    2073                 :             :         }
    2074                 :             :     }
    2075                 :             : 
    2076                 :           0 :     return 0;
    2077                 :             : }
    2078                 :             : 
    2079                 :             : 
    2080                 :             : /****************************************************************************/
    2081                 :         216 : void OAD_Polymer_Free(OAD_Polymer* pd)
    2082                 :             : {
    2083         [ -  + ]:         216 :     if ( pd )
    2084                 :             :     {
    2085         [ #  # ]:           0 :         if ( pd->pzz )
    2086                 :             :         {
    2087         [ #  # ]:           0 :             inchi_free(pd->pzz);
    2088                 :           0 :             pd->pzz = NULL;
    2089                 :           0 :             pd->n_pzz = 0;
    2090                 :             :         }
    2091   [ #  #  #  # ]:           0 :         if ( pd->n && pd->units )
    2092                 :             :         {
    2093                 :             :             int k;
    2094         [ #  # ]:           0 :             for ( k = 0; k < pd->n; k++ )
    2095                 :             :             {
    2096                 :           0 :                 OAD_PolymerUnit_Free(pd->units[k]);
    2097                 :             :             }
    2098         [ #  # ]:           0 :             inchi_free(pd->units);
    2099                 :           0 :             pd->units = NULL;
    2100                 :           0 :             pd->n = 0;
    2101                 :             :         }
    2102         [ #  # ]:           0 :         inchi_free(pd);
    2103                 :           0 :         pd = NULL;
    2104                 :             :     }
    2105                 :             : 
    2106                 :         216 :     return;
    2107                 :             : }
    2108                 :             : 
    2109                 :             : 
    2110                 :             : /****************************************************************************/
    2111                 :           0 : void OAD_PolymerUnit_UnlinkCapsAndConnectEndAtoms(OAD_PolymerUnit* unit,
    2112                 :             :     ORIG_ATOM_DATA* orig_inp_data,
    2113                 :             :     int* err,
    2114                 :             :     char* pStrErr)
    2115                 :             : {
    2116                 :             :     int bond_type, bond_stereo;
    2117                 :             : 
    2118                 :           0 :     *err = 0;
    2119         [ #  # ]:           0 :     if ( !unit->cyclizable )
    2120                 :             :     {
    2121                 :           0 :         return;
    2122                 :             :     }
    2123                 :             : 
    2124         [ #  # ]:           0 :     if ( unit->cyclizable == CLOSING_SRU_RING )
    2125                 :             :     {
    2126                 :             :         /* Disconnect both star atoms */
    2127                 :           0 :         OrigAtData_RemoveBond(unit->cap1 - 1, unit->end_atom1 - 1, orig_inp_data->at,
    2128                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2129                 :             : 
    2130                 :           0 :         OrigAtData_RemoveBond(unit->cap2 - 1, unit->end_atom2 - 1, orig_inp_data->at,
    2131                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2132                 :             : 
    2133                 :           0 :         OrigAtData_AddSingleStereolessBond(unit->end_atom1 - 1, unit->end_atom2 - 1,
    2134                 :             :             orig_inp_data->at, &orig_inp_data->num_inp_bonds);
    2135                 :             :     }
    2136                 :             : 
    2137         [ #  # ]:           0 :     else if ( unit->cyclizable == CLOSING_SRU_HIGHER_ORDER_BOND )
    2138                 :             :     {
    2139                 :             :         int elevated; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    2140                 :           0 :         elevated = OrigAtData_IncreaseBondOrder(unit->end_atom1 - 1, unit->end_atom2 - 1, orig_inp_data->at); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
    2141                 :             : #if 0
    2142                 :             :         /* the bond may already be broken at metal disconnection, so ignore the result here */
    2143                 :             :         if ( !elevated )
    2144                 :             :         {
    2145                 :             :             /* *err = 1; */
    2146                 :             :             WarningMessage(pStrErr, "SRU closure via higher order bond failed");
    2147                 :             :             unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    2148                 :             :             return;
    2149                 :             :         }
    2150                 :             : #endif
    2151                 :           0 :         OrigAtData_RemoveBond(unit->cap1 - 1, unit->end_atom1 - 1, orig_inp_data->at,
    2152                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2153                 :           0 :         OrigAtData_RemoveBond(unit->cap2 - 1, unit->end_atom2 - 1, orig_inp_data->at,
    2154                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2155                 :             :     }
    2156                 :             : 
    2157         [ #  # ]:           0 :     else if ( unit->cyclizable == CLOSING_SRU_DIRADICAL )
    2158                 :             :     {
    2159                 :           0 :         orig_inp_data->at[unit->end_atom1 - 1].radical = RADICAL_TRIPLET;
    2160                 :           0 :         OrigAtData_RemoveBond(unit->cap1 - 1, unit->end_atom1 - 1, orig_inp_data->at,
    2161                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2162                 :           0 :         OrigAtData_RemoveBond(unit->cap2 - 1, unit->end_atom2 - 1, orig_inp_data->at,
    2163                 :             :             &bond_type, &bond_stereo, &orig_inp_data->num_inp_bonds);
    2164                 :             :     }
    2165                 :             : 
    2166         [ #  # ]:           0 :     if ( !*err )
    2167                 :             :     {
    2168                 :           0 :         unit->cyclized = 1;
    2169                 :             :     }
    2170                 :             : 
    2171                 :           0 :     return;
    2172                 :             : }
    2173                 :             : 
    2174                 :             : 
    2175                 :             : /****************************************************************************/
    2176                 :           0 : void OAD_PolymerUnit_FindEndsAndCaps(OAD_PolymerUnit* unit,
    2177                 :             :     ORIG_ATOM_DATA* orig_at_data,
    2178                 :             :     int* end1,
    2179                 :             :     int* cap1,
    2180                 :             :     int* cap1_is_star,
    2181                 :             :     int* end2,
    2182                 :             :     int* cap2,
    2183                 :             :     int* cap2_is_star,
    2184                 :             :     int* err,
    2185                 :             :     char* pStrErr)
    2186                 :             : {
    2187                 :           0 :     int i, j, i_inside = 0, j_inside = 0;
    2188                 :           0 :     int num_atoms = orig_at_data->num_inp_atoms;
    2189                 :             : 
    2190                 :           0 :     *end1 = *end2 = *cap1 = *cap2 = 0;
    2191                 :           0 :     *cap1_is_star = *cap2_is_star = 0;
    2192                 :           0 :     *err = 0;
    2193                 :             : 
    2194   [ #  #  #  # ]:           0 :     if ( !unit->blist || unit->nb < 1 )
    2195                 :             :     {
    2196                 :           0 :         return;
    2197                 :             :     }
    2198                 :             :     /* Left crossing bond */
    2199                 :           0 :     i = unit->blist[0];
    2200                 :           0 :     j = unit->blist[1];
    2201                 :           0 :     i_inside = (NULL != is_in_the_ilist(unit->alist, i, unit->na));
    2202                 :           0 :     j_inside = (NULL != is_in_the_ilist(unit->alist, j, unit->na));
    2203   [ #  #  #  # ]:           0 :     if ( i_inside && j_inside )
    2204                 :             :     {
    2205         [ #  # ]:           0 :         TREAT_ERR(*err, 9032, "Polymer CRU cap(s) lie inside CRU");
    2206                 :           0 :         return;
    2207                 :             :     }
    2208         [ #  # ]:           0 :     if ( i_inside )
    2209                 :             :     {
    2210                 :           0 :         *end1 = i;
    2211                 :           0 :         *cap1 = j;
    2212                 :             :     }
    2213                 :             :     else
    2214                 :             :     {
    2215                 :           0 :         *end1 = j;
    2216                 :           0 :         *cap1 = i;
    2217                 :             :     }
    2218         [ #  # ]:           0 :     if ( !strcmp(orig_at_data->at[*cap1 - 1].elname, "Zz") )
    2219                 :             :     {
    2220                 :           0 :         *cap1_is_star = 1;
    2221                 :             :     }
    2222                 :             :     /* Right crossing bond */
    2223                 :           0 :     i = unit->blist[2];
    2224                 :           0 :     j = unit->blist[3];
    2225                 :           0 :     i_inside = NULL != is_in_the_ilist(unit->alist, i, unit->na);
    2226                 :           0 :     j_inside = NULL != is_in_the_ilist(unit->alist, j, unit->na);
    2227   [ #  #  #  # ]:           0 :     if ( i_inside && j_inside )
    2228                 :             :     {
    2229         [ #  # ]:           0 :         TREAT_ERR(*err, 9032, "Polymer CRU cap(s) lie inside CRU");
    2230                 :             :     }
    2231         [ #  # ]:           0 :     if ( i_inside )
    2232                 :             :     {
    2233                 :           0 :         *end2 = i;
    2234                 :           0 :         *cap2 = j;
    2235                 :             :     }
    2236                 :             :     else
    2237                 :             :     {
    2238                 :           0 :         *end2 = j;
    2239                 :           0 :         *cap2 = i;
    2240                 :             :     }
    2241         [ #  # ]:           0 :     if ( !strcmp(orig_at_data->at[*cap2 - 1].elname, "Zz") )
    2242                 :             :     {
    2243                 :           0 :         *cap2_is_star = 1;
    2244                 :             :     }
    2245                 :             :     /* Checks */
    2246   [ #  #  #  #  :           0 :     if ( *end1 <= 0 || *end1 > num_atoms || *cap1 <= 0 || *cap1 > num_atoms )
             #  #  #  # ]
    2247                 :             :     {
    2248         [ #  # ]:           0 :         TREAT_ERR(*err, 9090, "Invalid polymer CRU crossing bond");
    2249                 :           0 :         return;
    2250                 :             :     }
    2251   [ #  #  #  #  :           0 :     if ( *end2 <= 0 || *end2 > num_atoms || *cap2 <= 0 || *cap2 > num_atoms )
             #  #  #  # ]
    2252                 :             :     {
    2253         [ #  # ]:           0 :         TREAT_ERR(*err, 9091, "Invalid polymer CRU crossing bond");
    2254                 :           0 :         return;
    2255                 :             :     }
    2256         [ #  # ]:           0 :     if ( *cap1 == *cap2 ) /* || (*end1 == *end2 && unit->na>1)  */
    2257                 :             :     {
    2258         [ #  # ]:           0 :         TREAT_ERR(*err, 9090, "Invalid polymer CRU surrounding");
    2259                 :           0 :         return;
    2260                 :             :     }
    2261                 :             : 
    2262                 :             :     /* Paranoia, 2020-05-22 */
    2263                 :           0 :     unit->end_atom1 = *end1;
    2264                 :           0 :     unit->end_atom2 = *end2;
    2265                 :           0 :     unit->cap1 = *cap1;
    2266                 :           0 :     unit->cap2 = *cap2;
    2267                 :             : 
    2268                 :           0 :     *err = 0;
    2269                 :           0 :     return;
    2270                 :             : }
    2271                 :             : 
    2272                 :             : 
    2273                 :             : /****************************************************************************
    2274                 :             :  Reveal and store CRU caps and ends ('stars and partners')
    2275                 :             : ****************************************************************************/
    2276                 :           0 : void OAD_PolymerUnit_SetEndsAndCaps(OAD_PolymerUnit* unit,
    2277                 :             :     ORIG_ATOM_DATA* orig_at_data,
    2278                 :             :     int* err,
    2279                 :             :     char* pStrErr)
    2280                 :             : {
    2281                 :             :     int k;
    2282                 :             : 
    2283                 :           0 :     unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    2284                 :           0 :     unit->end_atom1 = unit->end_atom2 = unit->cap1 = unit->cap2 = -1;
    2285                 :           0 :     unit->cap1_is_undef = unit->cap2_is_undef = 0;
    2286                 :             : 
    2287                 :           0 :     OAD_PolymerUnit_FindEndsAndCaps(unit, orig_at_data,
    2288                 :             :         &unit->end_atom1, &unit->cap1, &unit->cap1_is_undef,
    2289                 :             :         &unit->end_atom2, &unit->cap2, &unit->cap2_is_undef,
    2290                 :             :         err, pStrErr);
    2291                 :             : 
    2292         [ #  # ]:           0 :     if ( *err )
    2293                 :             :     {
    2294                 :           0 :         goto exit_function;
    2295                 :             :     }
    2296                 :             : 
    2297                 :             : #if ( defined(DEBUG_POLYMERS) && ( DEBUG_POLYMERS != 0 ) )
    2298                 :             :     ITRACE_("Cap-end_atom pairs (numbers are from 1) are: %-d-%-d and %-d-%-d\n",
    2299                 :             :         unit->cap1, unit->end_atom1, unit->cap2, unit->end_atom2);
    2300                 :             : #endif
    2301                 :             : 
    2302   [ #  #  #  # ]:           0 :     if ( !unit->cap1_is_undef && !unit->cap2_is_undef )
    2303                 :             :     {
    2304                 :           0 :         goto exit_function;
    2305                 :             :     }
    2306                 :             : 
    2307                 :             :     /* The rest is applicable only to *---SRU---* case */
    2308                 :             : 
    2309                 :             :     /* Stars are separated by one atom - that's not error but do nothing */
    2310         [ #  # ]:           0 :     if ( unit->end_atom1 == unit->end_atom2 )
    2311                 :             :     {
    2312                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_DIRADICAL
    2313                 :           0 :         unit->cyclizable = CLOSING_SRU_DIRADICAL;
    2314                 :             : #else
    2315                 :             :         unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    2316                 :             : #endif
    2317                 :           0 :         goto exit_function;
    2318                 :             :     }
    2319                 :             : 
    2320                 :             :     /* Stars are separated by two atoms - that's not error but do nothing */
    2321         [ #  # ]:           0 :     for ( k = 0; k < orig_at_data->at[unit->end_atom1 - 1].valence; k++ )
    2322                 :             :     {
    2323         [ #  # ]:           0 :         if ( orig_at_data->at[unit->end_atom1 - 1].neighbor[k] == unit->end_atom2 - 1 )
    2324                 :             :         {
    2325                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_HIGHER_ORDER_BOND
    2326                 :           0 :             unit->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;
    2327                 :             : #else
    2328                 :             :             unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    2329                 :             : #endif
    2330                 :           0 :             goto exit_function;
    2331                 :             :         }
    2332                 :             :     }
    2333                 :             : 
    2334                 :           0 :     unit->cyclizable = CLOSING_SRU_RING;
    2335                 :             : 
    2336                 :           0 : exit_function:
    2337                 :             : 
    2338                 :           0 :     return;
    2339                 :             : }
    2340                 :             : 
    2341                 :             : 
    2342                 :             : /****************************************************************************
    2343                 :             :   Replace original atom numbers in polymer data with (canonical num + 1)
    2344                 :             :         Then prepare:
    2345                 :             :             units2    a copy of original polymer units (p->units) with
    2346                 :             :                       atomic numbers changed to curr canonical ones;
    2347                 :             :                       atoms in alists sorted; atoms in blists
    2348                 :             :                       and blists themselves are sorted
    2349                 :             :             unum      numbers of units (0..p->n) as they go when
    2350                 :             :                       sorted by alist's in lexicographic orders
    2351                 :             : ****************************************************************************/
    2352                 :           0 : int OAD_Polymer_PrepareWorkingSet(OAD_Polymer* p,
    2353                 :             :     int* cano_nums,
    2354                 :             :     int* compnt_nums,
    2355                 :             :     OAD_PolymerUnit** units2,       /* allocd by caller, to be filled */
    2356                 :             :     int* unum)         /* allocd by caller, to be filled */
    2357                 :             : 
    2358                 :             : {
    2359                 :           0 :     int i, k, err = 0, cano_num1 = -1, cano_num2 = -1;
    2360                 :             :     OAD_PolymerUnit* u;
    2361                 :             : 
    2362                 :             :     /*OAD_Polymer_DebugTrace( p );*/
    2363                 :             : 
    2364                 :             :     /*  Replace original atom numbers in polymer data with canonical plus 1.                    */
    2365                 :             :     /*  Note that we use 'cano1 nums', that is, 1-based (InChI internal 'cano nums' are 0-based)*/
    2366                 :             :     /*  Also remove from the list atoms who mapped to cano number 0  ( == -1 + 1_offset ),      */
    2367                 :             :     /*  they are explicit H's which have already been deleted.                                  */
    2368         [ #  # ]:           0 :     for ( k = 0; k < p->n_pzz; k++ )
    2369                 :             :     {
    2370                 :           0 :         cano_num1 = cano_nums[p->pzz[k]] + 1;
    2371         [ #  # ]:           0 :         if ( cano_num1 == 0 )
    2372                 :             :         {
    2373                 :             :             /* we shouldn't arrive here */
    2374                 :           0 :             err = 10;
    2375                 :           0 :             goto exit_function;
    2376                 :             :         }
    2377                 :           0 :         p->pzz[k] = cano_num1;
    2378                 :             :     }
    2379                 :             : 
    2380         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    2381                 :             :     {
    2382                 :           0 :         int na_new = -1;
    2383                 :           0 :         u = units2[i];
    2384                 :             : 
    2385         [ #  # ]:           0 :         for ( k = 0; k < u->na; k++ )
    2386                 :             :         {
    2387                 :           0 :             cano_num1 = cano_nums[u->alist[k]] + 1;
    2388         [ #  # ]:           0 :             if ( cano_num1 == 0 )
    2389                 :             :             {
    2390                 :           0 :                 continue;
    2391                 :             :             }
    2392                 :           0 :             u->alist[++na_new] = cano_num1;
    2393                 :             :         }
    2394                 :           0 :         u->na = na_new + 1;
    2395         [ #  # ]:           0 :         for ( k = 0; k < 2 * u->nb; k++ )
    2396                 :             :         {
    2397                 :           0 :             cano_num1 = cano_nums[u->blist[k]] + 1;
    2398         [ #  # ]:           0 :             if ( cano_num1 == 0 )
    2399                 :             :             {
    2400                 :             :                 /* Can not proceed further as one of PU crossing bond ends
    2401                 :             :                    leads to explicit H which has been removed already       */
    2402                 :           0 :                 err = 11;
    2403                 :           0 :                 goto exit_function;
    2404                 :             :             }
    2405                 :           0 :             u->blist[k] = cano_num1;
    2406                 :             :         }
    2407                 :             : 
    2408                 :           0 :         cano_num1 = cano_nums[u->cap1] + 1;
    2409         [ #  # ]:           0 :         if ( cano_num1 == 0 )
    2410                 :             :         {
    2411                 :           0 :             err = 11;
    2412                 :           0 :             goto exit_function;
    2413                 :             :         }
    2414                 :           0 :         u->cap1 = cano_num1;
    2415                 :             : 
    2416                 :           0 :         cano_num1 = cano_nums[u->cap2] + 1;
    2417         [ #  # ]:           0 :         if ( cano_num1 == 0 )
    2418                 :             :         {
    2419                 :           0 :             err = 11;
    2420                 :           0 :             goto exit_function;
    2421                 :             :         }
    2422                 :           0 :         u->cap2 = cano_num1;
    2423                 :             : 
    2424                 :           0 :         cano_num1 = cano_nums[u->end_atom1] + 1;
    2425         [ #  # ]:           0 :         if ( cano_num1 == 0 )
    2426                 :             :         {
    2427                 :           0 :             err = 11;
    2428                 :           0 :             goto exit_function;
    2429                 :             :         }
    2430                 :           0 :         u->end_atom1 = cano_num1;
    2431                 :             : 
    2432                 :           0 :         cano_num1 = cano_nums[u->end_atom2] + 1;
    2433         [ #  # ]:           0 :         if ( cano_num1 == 0 )
    2434                 :             :         {
    2435                 :           0 :             err = 11;
    2436                 :           0 :             goto exit_function;
    2437                 :             :         }
    2438                 :           0 :         u->end_atom2 = cano_num1;
    2439                 :             : 
    2440         [ #  # ]:           0 :         for ( k = 0; k < u->nbkbonds; k++ )
    2441                 :             :         {
    2442                 :           0 :             cano_num1 = cano_nums[u->bkbonds[k][0]] + 1;
    2443         [ #  # ]:           0 :             if ( cano_num1 == 0 )
    2444                 :             :             {
    2445                 :           0 :                 continue;
    2446                 :             :             }
    2447                 :           0 :             cano_num2 = cano_nums[u->bkbonds[k][1]] + 1;
    2448         [ #  # ]:           0 :             if ( cano_num2 == 0 )
    2449                 :             :             {
    2450                 :           0 :                 continue;
    2451                 :             :             }
    2452                 :           0 :             u->bkbonds[k][0] = inchi_min(cano_num1, cano_num2);
    2453                 :           0 :             u->bkbonds[k][1] = inchi_max(cano_num1, cano_num2);
    2454                 :             :         }
    2455                 :             :     }
    2456                 :             : 
    2457                 :             :     /* Sort the atoms and the bonds in all units */
    2458         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    2459                 :             :     {
    2460                 :           0 :         u = units2[i];
    2461                 :             : 
    2462                 :             :         /* sort atoms (alist) */
    2463                 :           0 :         iisort(u->alist, u->na);
    2464                 :             : 
    2465                 :             :         /*ITRACE_( "\n*** Polymer unit %-d : ( ", i );
    2466                 :             :         for (k = 0; k < u->na - 1; k++)
    2467                 :             :         {
    2468                 :             :             ITRACE_( "%-d-", u->alist[k] );
    2469                 :             :         }
    2470                 :             :         ITRACE_( "%-d )\n", u->alist[u->na - 1] );*/
    2471                 :             : 
    2472                 :             :         /* Sort bonds (blist) */
    2473                 :           0 :         err = OAD_PolymerUnit_OrderBondAtomsAndBondsThemselves(u, p->n_pzz, p->pzz);
    2474         [ #  # ]:           0 :         if ( err )
    2475                 :             :         {
    2476                 :             :             /* crossing bonds in blist are invalid */
    2477                 :           0 :             err = 12;
    2478                 :           0 :             goto exit_function;
    2479                 :             :         }
    2480                 :             : 
    2481                 :             :         /* Check each unit for >1 connected components */
    2482                 :             : #if 0
    2483                 :             :         {
    2484                 :             :             int icompnt;
    2485                 :             :             icompnt = compnt_nums[u->alist[0] - 1];
    2486                 :             :             for ( k = 1; k < u->na; k++ )
    2487                 :             :             {
    2488                 :             :                 if ( compnt_nums[u->alist[k] - 1] != icompnt )
    2489                 :             :                 {
    2490                 :             :                     u->disjoint = 1;
    2491                 :             :                     break;
    2492                 :             :                 }
    2493                 :             :             }
    2494                 :             :         }
    2495                 :             : #endif
    2496                 :             : 
    2497                 :             :     }
    2498                 :             : 
    2499                 :             :     /* Sort all units in modified alist's lexicographic order
    2500                 :             :     (modification is: longer list always go first )                     */
    2501         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    2502                 :             :     {
    2503                 :           0 :         unum[i] = i;
    2504                 :             :     }
    2505         [ #  # ]:           0 :     for ( i = 1; i < p->n; i++ )
    2506                 :             :     {
    2507                 :           0 :         int tmp = unum[i];
    2508                 :           0 :         int j = i - 1;
    2509   [ #  #  #  # ]:           0 :         while ( j >= 0 && OAD_PolymerUnit_CompareAtomListsMod(units2[unum[j]], units2[tmp]) > 0 )
    2510                 :             :             /*while ( j >= 0 &&    OAD_PolymerUnit_CompareAtomLists( units2[ unum[j] ], units2[ tmp ] ) > 0  )*/
    2511                 :             :         {
    2512                 :           0 :             unum[j + 1] = unum[j];
    2513                 :           0 :             j--;
    2514                 :             :         }
    2515                 :           0 :         unum[j + 1] = tmp;
    2516                 :             :     }
    2517                 :             : 
    2518                 :           0 : exit_function:
    2519                 :             : 
    2520                 :           0 :     return err;
    2521                 :             : }
    2522                 :             : 
    2523                 :             : 
    2524                 :             : /****************************************************************************
    2525                 :             :   Helper for cyclizing CRU. NB: 0-based
    2526                 :             : ****************************************************************************/
    2527                 :           0 : int  OrigAtData_RemoveHalfBond(int      this_atom,
    2528                 :             :     int      other_atom,
    2529                 :             :     inp_ATOM* at,
    2530                 :             :     int* bond_type,
    2531                 :             :     int* bond_stereo)
    2532                 :             : {
    2533                 :             :     int k, kk;
    2534                 :             :     /* djb-rwth: fixing oss-fuzz issues #68286, #30342 */
    2535   [ #  #  #  #  :           0 :     if ( at && (this_atom >= 0) && (other_atom >= 0) )
                   #  # ]
    2536                 :             :     {
    2537                 :           0 :         inp_ATOM* a = &(at[this_atom]);
    2538         [ #  # ]:           0 :         if ( a )
    2539                 :             :         {
    2540         [ #  # ]:           0 :             for ( k = 0; k < a->valence; k++ )
    2541                 :             :             {
    2542         [ #  # ]:           0 :                 if ( a->neighbor[k] != other_atom )
    2543                 :             :                 {
    2544                 :           0 :                     continue;
    2545                 :             :                 }
    2546                 :             : 
    2547                 :           0 :                 *bond_type = a->bond_type[k];
    2548                 :           0 :                 *bond_stereo = a->bond_stereo[k];
    2549                 :             : 
    2550                 :           0 :                 a->neighbor[k] = a->bond_type[k] = a->bond_stereo[k] = 0;
    2551                 :             : 
    2552         [ #  # ]:           0 :                 for ( kk = k + 1; kk < a->valence; kk++ )
    2553                 :             :                 {
    2554                 :           0 :                     a->neighbor[kk - 1] = a->neighbor[kk];
    2555                 :           0 :                     a->bond_type[kk - 1] = a->bond_type[kk];
    2556                 :           0 :                     a->bond_stereo[kk - 1] = a->bond_stereo[kk];
    2557                 :             :                 }
    2558         [ #  # ]:           0 :                 for ( kk = a->valence - 1; kk < MAXVAL; kk++ )
    2559                 :             :                 {
    2560                 :           0 :                     a->neighbor[kk] = 0;
    2561                 :           0 :                     a->bond_type[kk] = (U_CHAR)0;
    2562                 :           0 :                     a->bond_stereo[kk] = (S_CHAR)0;
    2563                 :             :                 }
    2564                 :           0 :                 return 1;
    2565                 :             :             } /* k */
    2566                 :             :         }
    2567                 :             :     }
    2568                 :             : 
    2569                 :           0 :     return 0;
    2570                 :             : }
    2571                 :             : 
    2572                 :             : 
    2573                 :             : /****************************************************************************/
    2574                 :           0 : int  OrigAtData_RemoveAtom(ORIG_ATOM_DATA* orig_at_data, int iatom)
    2575                 :             : {
    2576                 :             : 
    2577                 :             :     if ( 0 )
    2578                 :             :     {
    2579                 :             :         return 1;
    2580                 :             :     }
    2581                 :             : 
    2582                 :           0 :     return 0;
    2583                 :             : }
    2584                 :             : 
    2585                 :             : 
    2586                 :             : /****************************************************************************/
    2587                 :           0 : int  OrigAtData_RemoveBond(int      this_atom,
    2588                 :             :     int      other_atom,
    2589                 :             :     inp_ATOM* at,
    2590                 :             :     int* bond_type,
    2591                 :             :     int* bond_stereo,
    2592                 :             :     int* num_inp_bonds)
    2593                 :             : {
    2594                 :           0 :     int del = 0;
    2595                 :             : 
    2596   [ #  #  #  #  :           0 :     if ( at && (this_atom >= 0) && (other_atom >= 0) ) /* djb-rwth: fixing oss-fuzz issue #68329, #68286 */
                   #  # ]
    2597                 :             :     {
    2598                 :           0 :         del = OrigAtData_RemoveHalfBond(this_atom, other_atom, at, bond_type, bond_stereo);
    2599                 :           0 :         del += OrigAtData_RemoveHalfBond(other_atom, this_atom, at, bond_type, bond_stereo);
    2600                 :             : 
    2601         [ #  # ]:           0 :         if ( del == 2 )
    2602                 :             :         {
    2603                 :           0 :             (*num_inp_bonds)--;
    2604                 :           0 :             at[this_atom].valence--;
    2605                 :           0 :             at[this_atom].chem_bonds_valence -= *bond_type;
    2606                 :           0 :             at[other_atom].valence--;
    2607                 :           0 :             at[other_atom].chem_bonds_valence -= *bond_type;
    2608                 :           0 :             return 1;
    2609                 :             :         }
    2610                 :             :     }
    2611                 :             : 
    2612                 :           0 :     return 0;
    2613                 :             : }
    2614                 :             : 
    2615                 :             : 
    2616                 :             : /****************************************************************************/
    2617                 :           0 : int  OrigAtData_AddBond(int        this_atom,
    2618                 :             :     int        other_atom,
    2619                 :             :     inp_ATOM* at,
    2620                 :             :     int        bond_type,
    2621                 :             :     int        bond_stereo,
    2622                 :             :     int* num_bonds)
    2623                 :             : {
    2624         [ #  # ]:           0 :     if ( at )
    2625                 :             :     {
    2626                 :             :         /* djb-rwth: fixing oss-fuzz issue #68286 */
    2627                 :             :         int i, k, already_here;
    2628                 :           0 :         inp_ATOM* a = &(at[this_atom]);
    2629                 :             : 
    2630         [ #  # ]:           0 :         if ( at[this_atom].valence >= MAXVAL ||
    2631         [ #  # ]:           0 :             at[other_atom].valence >= MAXVAL )
    2632                 :             :         {
    2633                 :           0 :             return 0;
    2634                 :             :         }
    2635                 :             : 
    2636   [ #  #  #  # ]:           0 :         if ( bond_type != INCHI_BOND_TYPE_DOUBLE && bond_type != INCHI_BOND_TYPE_TRIPLE )
    2637                 :             :         {
    2638                 :           0 :             bond_type = INCHI_BOND_TYPE_SINGLE;
    2639                 :             :         }
    2640                 :             : 
    2641                 :           0 :         k = a->valence;
    2642                 :           0 :         already_here = 0;
    2643         [ #  # ]:           0 :         for ( i = 0; i < k; i++ )
    2644                 :             :         {
    2645         [ #  # ]:           0 :             if ( a->neighbor[i] == other_atom )
    2646                 :             :             {
    2647                 :           0 :                 already_here = 1; break;
    2648                 :             :             }
    2649                 :             :         }
    2650                 :             : 
    2651         [ #  # ]:           0 :         if ( !already_here )
    2652                 :             :         {
    2653                 :           0 :             a->neighbor[k] = other_atom;
    2654                 :           0 :             a->bond_type[k] = (U_CHAR)bond_type;
    2655                 :           0 :             a->bond_stereo[k] = (S_CHAR)bond_stereo;
    2656                 :           0 :             a->chem_bonds_valence += bond_type;
    2657                 :           0 :             a->valence++;
    2658                 :             :         }
    2659                 :             : 
    2660                 :           0 :         a = &(at[other_atom]);
    2661                 :           0 :         k = a->valence;
    2662                 :           0 :         already_here = 0;
    2663         [ #  # ]:           0 :         for ( i = 0; i < k; i++ )
    2664                 :             :         {
    2665         [ #  # ]:           0 :             if ( a->neighbor[i] == this_atom )
    2666                 :             :             {
    2667                 :           0 :                 already_here = 1; break;
    2668                 :             :             }
    2669                 :             :         }
    2670                 :             : 
    2671   [ #  #  #  # ]:           0 :         if ( !already_here && (k < MAXVAL) ) /* djb-rwth: condition added to prevent buffer overrun */
    2672                 :             :         {
    2673                 :           0 :             a->neighbor[k] = this_atom;
    2674                 :           0 :             a->bond_type[k] = (U_CHAR)bond_type;
    2675                 :           0 :             a->bond_stereo[k] = (S_CHAR)bond_stereo;
    2676                 :           0 :             a->chem_bonds_valence += bond_type;
    2677                 :           0 :             a->valence++;
    2678                 :             :         }
    2679                 :             : 
    2680                 :           0 :         (*num_bonds)++;
    2681                 :             : 
    2682                 :           0 :         return 1;
    2683                 :             :     }
    2684                 :             :     else
    2685                 :             :     {
    2686                 :           0 :         return 0;
    2687                 :             :     }
    2688                 :             : }
    2689                 :             : 
    2690                 :             : 
    2691                 :             : /****************************************************************************/
    2692                 :           0 : int  OrigAtData_AddSingleStereolessBond(int      this_atom,
    2693                 :             :     int      other_atom,
    2694                 :             :     inp_ATOM* at,
    2695                 :             :     int* num_bonds)
    2696                 :             : {
    2697                 :           0 :     return OrigAtData_AddBond(this_atom, other_atom, at, INCHI_BOND_TYPE_SINGLE, 0, num_bonds);
    2698                 :             : }
    2699                 :             : 
    2700                 :             : 
    2701                 :             : /****************************************************************************/
    2702                 :           0 : int  OrigAtData_IncreaseBondOrder(int this_atom, int other_atom, inp_ATOM* at)
    2703                 :             : {
    2704                 :           0 :     int i, k, n_up = 0;
    2705                 :             :     inp_ATOM* a;
    2706                 :             : 
    2707         [ #  # ]:           0 :     if ( at[this_atom].valence >= MAXVAL ||
    2708         [ #  # ]:           0 :         at[other_atom].valence >= MAXVAL )
    2709                 :             :     {
    2710                 :           0 :         return 0;
    2711                 :             :     }
    2712                 :             : 
    2713                 :           0 :     a = &(at[this_atom]);
    2714         [ #  # ]:           0 :     if ( a->chem_bonds_valence > MAXVAL - 1 )
    2715                 :             :     {
    2716                 :           0 :         return 0;
    2717                 :             :     }
    2718                 :             : 
    2719                 :           0 :     k = a->valence;
    2720         [ #  # ]:           0 :     for ( i = 0; i < k; i++ )
    2721                 :             :     {
    2722         [ #  # ]:           0 :         if ( a->neighbor[i] != other_atom )
    2723                 :           0 :             continue;
    2724         [ #  # ]:           0 :         if ( a->bond_type[i] > 3 )
    2725                 :           0 :             return 0;
    2726                 :           0 :         a->bond_type[i]++;
    2727                 :           0 :         a->chem_bonds_valence++;
    2728                 :           0 :         n_up++;
    2729                 :           0 :         break;
    2730                 :             :     }
    2731                 :             : 
    2732                 :           0 :     a = &(at[other_atom]);
    2733         [ #  # ]:           0 :     if ( a->chem_bonds_valence > MAXVAL - 1 )
    2734                 :             :     {
    2735                 :           0 :         return 0;
    2736                 :             :     }
    2737                 :           0 :     k = a->valence;
    2738                 :             : 
    2739         [ #  # ]:           0 :     for ( i = 0; i < k; i++ )
    2740                 :             :     {
    2741         [ #  # ]:           0 :         if ( a->neighbor[i] != this_atom )
    2742                 :             :         {
    2743                 :           0 :             continue;
    2744                 :             :         }
    2745         [ #  # ]:           0 :         if ( a->bond_type[i] > 3 )
    2746                 :             :         {
    2747                 :           0 :             return 0;
    2748                 :             :         }
    2749                 :           0 :         a->bond_type[i]++;
    2750                 :           0 :         a->chem_bonds_valence++;
    2751                 :           0 :         n_up++;
    2752                 :           0 :         break;
    2753                 :             :     }
    2754                 :             : 
    2755                 :           0 :     return n_up;
    2756                 :             : }
    2757                 :             : 
    2758                 :             : 
    2759                 :             : /****************************************************************************/
    2760                 :           0 : int  OrigAtData_DecreaseBondOrder(int      this_atom,
    2761                 :             :     int      other_atom,
    2762                 :             :     inp_ATOM* at)
    2763                 :             : {
    2764                 :           0 :     int i, k, n_dn = 0;
    2765                 :             :     inp_ATOM* a;
    2766                 :             : 
    2767                 :           0 :     a = &(at[this_atom]);
    2768         [ #  # ]:           0 :     if ( a->chem_bonds_valence > MAXVAL - 1 )
    2769                 :             :     {
    2770                 :           0 :         return 0;
    2771                 :             :     }
    2772                 :             : 
    2773                 :           0 :     k = a->valence;
    2774         [ #  # ]:           0 :     for ( i = 0; i < k; i++ )
    2775                 :             :     {
    2776         [ #  # ]:           0 :         if ( a->neighbor[i] != other_atom )
    2777                 :             :         {
    2778                 :           0 :             continue;
    2779                 :             :         }
    2780         [ #  # ]:           0 :         if ( a->bond_type[i] < 2 )
    2781                 :             :         {
    2782                 :           0 :             return 0;
    2783                 :             :         }
    2784                 :           0 :         a->bond_type[i]--;
    2785                 :           0 :         a->chem_bonds_valence--;
    2786                 :           0 :         n_dn++;
    2787                 :           0 :         break;
    2788                 :             :     }
    2789                 :             : 
    2790                 :           0 :     a = &(at[other_atom]);
    2791                 :           0 :     k = a->valence;
    2792         [ #  # ]:           0 :     for ( i = 0; i < k; i++ )
    2793                 :             :     {
    2794         [ #  # ]:           0 :         if ( a->neighbor[i] != this_atom )
    2795                 :             :         {
    2796                 :           0 :             continue;
    2797                 :             :         }
    2798         [ #  # ]:           0 :         if ( a->bond_type[i] < 2 )
    2799                 :             :         {
    2800                 :           0 :             return 0;
    2801                 :             :         }
    2802                 :           0 :         a->bond_type[i]--;
    2803                 :           0 :         a->chem_bonds_valence--;
    2804                 :           0 :         n_dn++;
    2805                 :           0 :         break;
    2806                 :             :     }
    2807                 :             : 
    2808                 :           0 :     return n_dn;
    2809                 :             : }
    2810                 :             : 
    2811                 :             : 
    2812                 :             : /****************************************************************************
    2813                 :             :  Collect bonds and optionally atoms of fragment
    2814                 :             : ****************************************************************************/
    2815                 :           0 : void OAD_CollectFragmentBondsAndAtoms(ORIG_ATOM_DATA* orig_at_data,
    2816                 :             :     int nforbidden,                     /* number of edges forbidden for traversal              */
    2817                 :             :     int* forbidden_orig,        /* atom nums of forbidden edges                                 */
    2818                 :             :     /* [edge1at1,edge1at2, edge2at1, edge2at2, ... ] */
    2819                 :             :     int* n_fragbonds,
    2820                 :             :     int** fragbonds,
    2821                 :             :     int* n_fragatoms,
    2822                 :             :     int* fragatoms,
    2823                 :             :     int* err,
    2824                 :             :     char* pStrErr)
    2825                 :             : {
    2826                 :             :     int i;
    2827                 :           0 :     int max_atoms = orig_at_data->num_inp_atoms;
    2828                 :           0 :     int* atnums = NULL;
    2829                 :           0 :     subgraf* sg = NULL;
    2830                 :           0 :     subgraf_pathfinder* spf = NULL;
    2831                 :             : 
    2832                 :           0 :     *err = 0;
    2833                 :           0 :     atnums = (int*)inchi_calloc(max_atoms, sizeof(int));
    2834         [ #  # ]:           0 :     if ( !atnums )
    2835                 :             :     {
    2836         [ #  # ]:           0 :         TREAT_ERR(*err, 9045, "Not enough memory");
    2837                 :           0 :         goto exit_function;
    2838                 :             :     }
    2839         [ #  # ]:           0 :     for ( i = 0; i < max_atoms; i++ )
    2840                 :             :     {
    2841                 :           0 :         atnums[i] = orig_at_data->at[i].orig_at_number; /* i+1 normally*/
    2842                 :             :     }
    2843                 :             : 
    2844                 :           0 :     sg = subgraf_new(orig_at_data, max_atoms, atnums);
    2845         [ #  # ]:           0 :     if ( !sg )
    2846                 :             :     {
    2847         [ #  # ]:           0 :         TREAT_ERR(*err, 9045, "Not enough memory");
    2848                 :           0 :         goto exit_function;
    2849                 :             :     }
    2850                 :           0 :     spf = subgraf_pathfinder_new(sg, orig_at_data, 0, 0); /* start = end = 0th node */
    2851         [ #  # ]:           0 :     if ( !spf )
    2852                 :             :     {
    2853         [ #  # ]:           0 :         TREAT_ERR(*err, 9045, "Not enough memory");
    2854                 :           0 :         goto exit_function;
    2855                 :             :     }
    2856                 :             : 
    2857                 :           0 :     spf->seen[0] = spf->start;
    2858                 :           0 :     spf->nseen = 1;
    2859                 :           0 :     *n_fragbonds = 0;
    2860                 :           0 :     *n_fragatoms = 0;
    2861                 :             : 
    2862                 :           0 :     subgraf_pathfinder_run(spf,
    2863                 :             :         nforbidden, forbidden_orig, /* this corrects cinnectivity of subgraf... */
    2864                 :             :         n_fragbonds, fragbonds,
    2865                 :             :         n_fragatoms, fragatoms);
    2866                 :             : 
    2867                 :             : 
    2868                 :           0 : exit_function:
    2869                 :           0 :     subgraf_free(sg);
    2870                 :           0 :     subgraf_pathfinder_free(spf);
    2871         [ #  # ]:           0 :     if ( atnums )
    2872                 :             :     {
    2873         [ #  # ]:           0 :         inchi_free(atnums);
    2874                 :             :     }
    2875                 :           0 :     return;
    2876                 :             : }
    2877                 :             : 
    2878                 :             : 
    2879                 :             : /****************************************************************************
    2880                 :             :  For all CRUs detect the bonds potentially involved in frame shift
    2881                 :             : ****************************************************************************/
    2882                 :           0 : void OAD_Polymer_FindBackbones(ORIG_ATOM_DATA* at_data,
    2883                 :             :     COMP_ATOM_DATA* composite_norm_data,
    2884                 :             :     int* err,
    2885                 :             :     char* pStrErr)
    2886                 :             : {
    2887                 :             :     int i;
    2888                 :             : 
    2889                 :           0 :     *err = 0;
    2890         [ #  # ]:           0 :     for ( i = 0; i < at_data->polymer->n; i++ )
    2891                 :             :     {
    2892         [ #  # ]:           0 :         if ( !at_data->polymer->units[i]->cyclizable )
    2893                 :             :         {
    2894                 :           0 :             continue;
    2895                 :             :         }
    2896                 :             : 
    2897                 :           0 :         OAD_CollectBackboneBonds(at_data,
    2898                 :           0 :             at_data->polymer->units[i]->na,
    2899                 :           0 :             at_data->polymer->units[i]->alist,
    2900                 :           0 :             at_data->polymer->units[i]->end_atom1,
    2901                 :           0 :             at_data->polymer->units[i]->end_atom2,
    2902                 :           0 :             &(at_data->polymer->units[i]->nbkbonds),
    2903                 :           0 :             at_data->polymer->units[i]->bkbonds,
    2904                 :             :             err, pStrErr);
    2905         [ #  # ]:           0 :         if ( *err )
    2906                 :             :         {
    2907                 :           0 :             at_data->polymer->units[i]->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    2908                 :           0 :             continue;
    2909                 :             :         }
    2910         [ #  # ]:           0 :         if ( at_data->polymer->units[i]->nbkbonds < 1 )
    2911                 :             :         {
    2912                 :           0 :             continue;
    2913                 :             :         }
    2914         [ #  # ]:           0 :         if ( at_data->polymer->units[i]->nbkbonds == 1 )
    2915                 :             :         {
    2916                 :             :             /*  Special case: we got only one bond between end_atom1 and   */
    2917                 :             :             /*  end_atom2 (this may be the result of metal disconnection)  */
    2918                 :           0 :             continue;
    2919                 :             :         }
    2920                 :             : 
    2921                 :           0 :         OAD_PolymerUnit_DelistIntraRingBackboneBonds(at_data->polymer->units[i], at_data, err, pStrErr);
    2922         [ #  # ]:           0 :         if ( *err )
    2923                 :             :         {
    2924                 :           0 :             continue;
    2925                 :             :         }
    2926                 :             : 
    2927                 :           0 :         OAD_PolymerUnit_DelistHighOrderBackboneBonds(at_data->polymer->units[i],
    2928                 :             :             at_data, composite_norm_data,
    2929                 :             :             err, pStrErr);
    2930         [ #  # ]:           0 :         if ( *err )
    2931                 :             :         {
    2932                 :           0 :             continue;
    2933                 :             :         }
    2934         [ #  # ]:           0 :         if ( at_data->polymer->units[i]->nbkbonds == 0 )
    2935                 :             :         {
    2936                 :             :             /* We already cyclized frame-shiftable unit and preprocessed it (in 'prep_inp_data').                       */
    2937                 :             :             /* Despite that, now we discovered that there are no bonds eligible for frame shift                         */
    2938                 :             :             /* (as all potentially eligible in-unit bonds are either in-ring or alternate ones).                        */
    2939                 :             :             /* We can not simply restore original connections as the structure may have been already heavily touched.   */
    2940                 :             :             /* The most viable action is to hold a single frame-shift bond (between original caps of CRU ends).   */
    2941                 :             :             /* It is for sure will be converted to original bonds to star atoms on possible inchi2struct.               */
    2942                 :           0 :             at_data->polymer->units[i]->cyclizable = 1;
    2943                 :           0 :             at_data->polymer->units[i]->nbkbonds = 1;
    2944                 :           0 :             at_data->polymer->units[i]->bkbonds[0][0] = at_data->polymer->units[i]->end_atom1;
    2945                 :           0 :             at_data->polymer->units[i]->bkbonds[0][1] = at_data->polymer->units[i]->end_atom2;
    2946                 :             :         }
    2947                 :             :     }
    2948                 :             : 
    2949                 :           0 :     return;
    2950                 :             : }
    2951                 :             : 
    2952                 :             : 
    2953                 :             : /****************************************************************************
    2954                 :             : Collect all backbone atoms - of main chain(s), side chains being ignored
    2955                 :             : ****************************************************************************/
    2956                 :           0 : void OAD_CollectBackboneAtoms(ORIG_ATOM_DATA* at_data,
    2957                 :             :     int na,
    2958                 :             :     int* alist,
    2959                 :             :     int end_atom1,
    2960                 :             :     int end_atom2,
    2961                 :             :     int* nbkatoms,
    2962                 :             :     int* bkatoms,
    2963                 :             :     int* err,
    2964                 :             :     char* pStrErr)
    2965                 :             : {
    2966                 :           0 :     int start = 0, end = 0;
    2967                 :           0 :     subgraf* sg = NULL;
    2968                 :           0 :     subgraf_pathfinder* spf = NULL;
    2969                 :           0 :     int nbkbonds = 0;
    2970                 :           0 :     int** bkbonds = NULL;               /* list of [breakable] backbone bonds   [ (a1,a2), (a3,a4), ... ]       */
    2971                 :             :     int maxbkbonds;
    2972                 :             : 
    2973                 :           0 :     *nbkatoms = 0;
    2974                 :           0 :     maxbkbonds = at_data->num_inp_bonds + 2;
    2975                 :           0 :     *err = imat_new(maxbkbonds, 2, &(bkbonds));
    2976                 :             :     /* djb-rwth: addressing coverity ID #499570 -- TREAT_ERR properly used in all cases */
    2977         [ #  # ]:           0 :     if (*err)
    2978                 :             :     {
    2979         [ #  # ]:           0 :         TREAT_ERR(*err, 9034, "Not enough memory (polymers)");
    2980                 :           0 :         goto exit_function;
    2981                 :             :     }
    2982                 :           0 :     nbkbonds = 0;
    2983                 :           0 :     sg = subgraf_new(at_data, na, alist);
    2984         [ #  # ]:           0 :     if ( !sg )
    2985                 :             :     {
    2986         [ #  # ]:           0 :         TREAT_ERR(*err, 9037, "Not enough memory (polymers)");
    2987                 :           0 :         goto exit_function;
    2988                 :             :     }
    2989                 :             : 
    2990                 :           0 :     start = sg->orig2node[end_atom1]; end = sg->orig2node[end_atom2];
    2991         [ #  # ]:           0 :     if ( start > end )
    2992                 :             :     {
    2993                 :           0 :         int tmp = end;
    2994                 :           0 :         end = start;
    2995                 :           0 :         start = tmp;
    2996                 :             :     }
    2997                 :           0 :     spf = subgraf_pathfinder_new(sg, at_data, start, end);
    2998         [ #  # ]:           0 :     if ( !spf )
    2999                 :             :     {
    3000         [ #  # ]:           0 :         TREAT_ERR(*err, 9039, "Not enough memory (polymers)");
    3001                 :           0 :         goto exit_function;
    3002                 :             :     }
    3003                 :             : 
    3004                 :           0 :     spf->seen[0] = spf->start; spf->nseen = 1;
    3005                 :           0 :     nbkbonds = 0;
    3006                 :           0 :     *nbkatoms = 0;
    3007                 :             : 
    3008                 :           0 :     subgraf_pathfinder_run(spf, 0, NULL, &nbkbonds, bkbonds, nbkatoms, bkatoms);
    3009                 :             : 
    3010                 :           0 :     subgraf_free(sg);
    3011                 :           0 :     subgraf_pathfinder_free(spf);
    3012                 :           0 :     *err = 0;
    3013                 :             : 
    3014                 :             : 
    3015                 :           0 : exit_function:
    3016         [ #  # ]:           0 :     if ( bkbonds )
    3017                 :             :     {
    3018                 :           0 :         imat_free(maxbkbonds, bkbonds);
    3019                 :           0 :         bkbonds = NULL;
    3020                 :             :     }
    3021                 :             : 
    3022                 :           0 :     return;
    3023                 :             : }
    3024                 :             : 
    3025                 :             : 
    3026                 :             : /****************************************************************************
    3027                 :             : Collect all atoms reachable from start_atom
    3028                 :             : ****************************************************************************/
    3029                 :           0 : int OAD_CollectReachableAtoms(ORIG_ATOM_DATA* orig_at_data,
    3030                 :             :     int start_atom,
    3031                 :             :     int nforbidden_bonds,
    3032                 :             :     int* forbidden_bond_atoms,
    3033                 :             :     int* n_reachable,
    3034                 :             :     int* reachable,
    3035                 :             :     int* err,
    3036                 :             :     char* pStrErr)
    3037                 :             : {
    3038                 :           0 :     int iatom, natnums, max_atoms, j, ret = _IS_OKAY;
    3039                 :           0 :     int max_n_reachable = *n_reachable;
    3040                 :           0 :     int* atnums = NULL;
    3041                 :           0 :     subgraf* sg = NULL;
    3042                 :           0 :     subgraf_pathfinder* spf = NULL;
    3043                 :             : 
    3044                 :             :     /* djb-rwth: removing redundant code */
    3045                 :           0 :     max_atoms = orig_at_data->num_inp_atoms;
    3046                 :           0 :     iatom = start_atom - 1;
    3047                 :           0 :     *n_reachable = 0;
    3048                 :             : 
    3049                 :           0 :     atnums = (int*)inchi_calloc(max_atoms, sizeof(int));
    3050         [ #  # ]:           0 :     if ( !atnums )
    3051                 :             :     {
    3052                 :           0 :         ret = _IS_ERROR;
    3053                 :           0 :         goto exit_function;
    3054                 :             :     }
    3055         [ #  # ]:           0 :     for ( j = 0; j < max_atoms; j++ )
    3056                 :             :     {
    3057                 :           0 :         atnums[j] = orig_at_data->at[j].orig_at_number;
    3058                 :             :     }
    3059                 :           0 :     sg = subgraf_new(orig_at_data, max_atoms, atnums);
    3060         [ #  # ]:           0 :     if ( !sg )
    3061                 :             :     {
    3062                 :           0 :         ret = _IS_ERROR;
    3063                 :           0 :         goto exit_function;
    3064                 :             :     }
    3065                 :           0 :     spf = subgraf_pathfinder_new(sg, orig_at_data, iatom, iatom);
    3066         [ #  # ]:           0 :     if ( !spf )
    3067                 :             :     {
    3068                 :           0 :         ret = _IS_ERROR;
    3069                 :           0 :         goto exit_function;
    3070                 :             :     }
    3071                 :             : 
    3072                 :             :     /* move from orig# to node# */
    3073                 :           0 :     spf->start = iatom;
    3074         [ #  # ]:           0 :     for ( j = 0; j < nforbidden_bonds; j++ )
    3075                 :             :     {
    3076                 :           0 :         forbidden_bond_atoms[2 * j] = sg->orig2node[forbidden_bond_atoms[2 * j]];
    3077                 :           0 :         forbidden_bond_atoms[2 * j + 1] = sg->orig2node[forbidden_bond_atoms[2 * j + 1]];
    3078                 :             :     }
    3079                 :             : 
    3080                 :             :     /*memset(atnums, -1, max_atoms * sizeof(int));*/
    3081         [ #  # ]:           0 :     for ( j = 0; j < max_atoms; j++ )
    3082                 :             :     {
    3083                 :           0 :         atnums[j] = -1;
    3084                 :             :     }
    3085                 :             : 
    3086                 :           0 :     spf->nseen = 0;
    3087                 :           0 :     natnums = subgraf_pathfinder_collect_all(spf, nforbidden_bonds, forbidden_bond_atoms, atnums);
    3088                 :             : 
    3089         [ #  # ]:           0 :     if ( natnums )
    3090                 :             :     {
    3091         [ #  # ]:           0 :         if ( natnums > max_n_reachable )
    3092                 :             :         {
    3093                 :           0 :             ret = _IS_ERROR;
    3094                 :           0 :             goto exit_function;
    3095                 :             :         }
    3096                 :             : 
    3097   [ #  #  #  # ]:           0 :         for (j = 0; j < natnums && j < max_atoms; j++) /* djb-rwth: fixing buffer overruns */
    3098                 :             :         {
    3099                 :           0 :             reachable[(*n_reachable)++ ] = atnums[j];
    3100                 :             :         }
    3101                 :             :     }
    3102                 :             : 
    3103                 :           0 : exit_function:
    3104                 :           0 :     subgraf_free(sg);
    3105                 :           0 :     subgraf_pathfinder_free(spf);
    3106         [ #  # ]:           0 :     if ( atnums )
    3107                 :             :     {
    3108         [ #  # ]:           0 :         inchi_free(atnums);
    3109                 :             :     }
    3110                 :             : 
    3111                 :           0 :     return ret;
    3112                 :             : }
    3113                 :             : 
    3114                 :             : 
    3115                 :             : /****************************************************************************
    3116                 :             :  Collect all backbone bonds - of main chain(s), side chains being ignored
    3117                 :             :  (for polymer CRU, these are the bonds potentially involved in frame shift)
    3118                 :             : ****************************************************************************/
    3119                 :           0 : void OAD_CollectBackboneBonds(ORIG_ATOM_DATA* at_data,
    3120                 :             :     int na,
    3121                 :             :     int* alist,
    3122                 :             :     int end_atom1,
    3123                 :             :     int end_atom2,
    3124                 :             :     int* nbkbonds,
    3125                 :             :     int** bkbonds,
    3126                 :             :     int* err,
    3127                 :             :     char* pStrErr)
    3128                 :             : {
    3129                 :           0 :     int start = 0, end = 0, dummy;
    3130                 :           0 :     subgraf* sg = NULL;
    3131                 :           0 :     subgraf_pathfinder* spf = NULL;
    3132                 :             :     /* Establish subgraph for na atoms of the alist */
    3133                 :           0 :     *nbkbonds = 0;
    3134                 :           0 :     sg = subgraf_new(at_data, na, alist);
    3135         [ #  # ]:           0 :     if ( !sg )
    3136                 :             :     {
    3137         [ #  # ]:           0 :         TREAT_ERR(*err, 9037, "Not enough memory (polymers)");
    3138                 :             :         /* unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE; */
    3139                 :           0 :         return;
    3140                 :             :     }
    3141                 :           0 :     start = sg->orig2node[end_atom1];
    3142                 :           0 :     end = sg->orig2node[end_atom2];
    3143                 :             : #if 0
    3144                 :             :     if ( start > end )
    3145                 :             :     {
    3146                 :             :         int tmp = end;
    3147                 :             :         end = start;
    3148                 :             :         start = tmp;
    3149                 :             :     }
    3150                 :             : #endif
    3151                 :           0 :     spf = subgraf_pathfinder_new(sg, at_data, start, end);
    3152         [ #  # ]:           0 :     if ( !spf )
    3153                 :             :     {
    3154         [ #  # ]:           0 :         TREAT_ERR( *err, 9039, "Not enough memory (polymers)" ); /* djb-rwth: addressing coverity ID #499539 -- TREAT_ERR properly used */
    3155                 :             :         /*unit->cyclizable = CLOSING_SRU_NOT_APPLICABLE;*/
    3156                 :           0 :         return;
    3157                 :             :     }
    3158                 :           0 :     spf->seen[0] = spf->start;
    3159                 :           0 :     spf->nseen = 1;
    3160                 :           0 :     *nbkbonds = 0;
    3161                 :           0 :     subgraf_pathfinder_run(spf, 0, NULL,
    3162                 :             :         nbkbonds,
    3163                 :             :         bkbonds, /* we will collect backbone CRU bonds here */
    3164                 :             :         &dummy,
    3165                 :             :         NULL);
    3166                 :             : 
    3167                 :           0 :     subgraf_free(sg);
    3168                 :           0 :     subgraf_pathfinder_free(spf);
    3169                 :           0 :     *err = 0;
    3170                 :             : 
    3171                 :           0 :     return;
    3172                 :             : }
    3173                 :             : 
    3174                 :             : 
    3175                 :             : /****************************************************************************
    3176                 :             :  Remove intra-ring bonds from the list of frame-shiftable bonds
    3177                 :             : ****************************************************************************/
    3178                 :           0 : void OAD_PolymerUnit_DelistIntraRingBackboneBonds(OAD_PolymerUnit* unit,
    3179                 :             :     ORIG_ATOM_DATA* at_data,
    3180                 :             :     int* err,
    3181                 :             :     char* pStrErr)
    3182                 :             : {
    3183                 :           0 :     int nrings = 0;
    3184                 :           0 :     int* num_ring_sys = NULL;
    3185                 :             : 
    3186         [ #  # ]:           0 :     if ( !unit )
    3187                 :             :     {
    3188                 :           0 :         return;
    3189                 :             :     }
    3190         [ #  # ]:           0 :     if ( unit->nbkbonds < 1 )
    3191                 :             :     {
    3192                 :           0 :         return;
    3193                 :             :     }
    3194                 :             : 
    3195                 :             :     /* Establish ring systems assignments for all related atoms */
    3196                 :             : 
    3197                 :           0 :     *err = 1;
    3198                 :           0 :     num_ring_sys = (int*)inchi_calloc((long long)at_data->num_inp_atoms + 1, sizeof(int)); /* djb-rwth: cast operator added */
    3199         [ #  # ]:           0 :     if ( !num_ring_sys )
    3200                 :             :     {
    3201                 :           0 :         goto exit_function;
    3202                 :             :     }
    3203                 :             : 
    3204                 :           0 :     *err = 0;
    3205                 :             : 
    3206                 :           0 :     nrings = OAD_Polymer_FindRingSystems(at_data->polymer, at_data->at, at_data->num_inp_atoms, &at_data->num_inp_bonds,
    3207                 :           0 :         num_ring_sys, NULL, unit->end_atom1 - 1); /* NB: start dfs within connected compt! */
    3208                 :             : 
    3209         [ #  # ]:           0 :     if ( nrings == 0 )
    3210                 :             :     {
    3211                 :           0 :         goto exit_function;
    3212                 :             :     }
    3213                 :             :     else
    3214                 :             :     {
    3215                 :           0 :         int at1, at2, j = 0;
    3216                 :           0 :     repeatj:
    3217                 :           0 :         at1 = unit->bkbonds[j][0];
    3218                 :           0 :         at2 = unit->bkbonds[j][1];
    3219   [ #  #  #  # ]:           0 :         if ( (num_ring_sys[at1] == num_ring_sys[at2]) && (num_ring_sys[at1] != -1) )
    3220                 :             :         {
    3221                 :           0 :             OAD_PolymerUnit_RemoveLinkFromCRUChain(at1, at2, &unit->nbkbonds, unit->bkbonds);
    3222                 :             :         }
    3223                 :             :         else
    3224                 :             :         {
    3225                 :           0 :             ++j;
    3226                 :             :         }
    3227         [ #  # ]:           0 :         if ( j < unit->nbkbonds )
    3228                 :             :         {
    3229                 :           0 :             goto repeatj;
    3230                 :             :         }
    3231                 :             :     }
    3232                 :             : 
    3233                 :           0 : exit_function:
    3234         [ #  # ]:           0 :     if ( num_ring_sys )
    3235                 :             :     {
    3236         [ #  # ]:           0 :         inchi_free(num_ring_sys);
    3237                 :             :     }
    3238                 :             : 
    3239                 :           0 :     return;
    3240                 :             : }
    3241                 :             : 
    3242                 :             : 
    3243                 :             : /****************************************************************************
    3244                 :             :  Find ring systems (exclude possible cyclizing bonds) in all polymer SRU's
    3245                 :             : ****************************************************************************/
    3246                 :           0 : int  OAD_Polymer_FindRingSystems(OAD_Polymer* pd,
    3247                 :             :     inp_ATOM* at,
    3248                 :             :     int         nat,
    3249                 :             :     int* num_inp_bonds,
    3250                 :             :     int* num_ring_sys,
    3251                 :             :     int* size_ring_sys,
    3252                 :             :     int         start)
    3253                 :             : {
    3254                 :           0 :     int i, j, nrings = 0, bond_type, bond_stereo;
    3255                 :             : 
    3256         [ #  # ]:           0 :     if ( NULL == num_ring_sys )
    3257                 :             :     {
    3258                 :           0 :         return 0;
    3259                 :             :     }
    3260                 :             : 
    3261                 :             :     /* Remove polymer SRU 'cyclizing' bonds if any */
    3262         [ #  # ]:           0 :     for ( j = 0; j < pd->n; j++ )
    3263                 :             :     {
    3264         [ #  # ]:           0 :         if ( pd->units[j]->cyclized )
    3265                 :             :         {
    3266                 :           0 :             OrigAtData_RemoveBond(pd->units[j]->end_atom1 - 1,
    3267                 :           0 :                 pd->units[j]->end_atom2 - 1,
    3268                 :             :                 at, &bond_type, &bond_stereo,
    3269                 :             :                 num_inp_bonds);
    3270                 :             :         }
    3271                 :             :     }
    3272                 :             : 
    3273                 :           0 :     MarkRingSystemsInp(at, nat, start); /*0 );*/
    3274                 :             : 
    3275         [ #  # ]:           0 :     for ( i = 0; i <= nat; i++ )
    3276                 :             :     {
    3277                 :           0 :         num_ring_sys[i] = -1;
    3278                 :             :     }
    3279         [ #  # ]:           0 :     for ( i = 0; i < nat; i++ )
    3280                 :             :     {
    3281         [ #  # ]:           0 :         if ( at[i].nNumAtInRingSystem > 2 )
    3282                 :             :         {
    3283                 :           0 :             int atnum = at[i].orig_at_number;
    3284                 :           0 :             num_ring_sys[atnum] = at[i].nRingSystem;
    3285         [ #  # ]:           0 :             if ( NULL != size_ring_sys )
    3286                 :             :             {
    3287                 :           0 :                 size_ring_sys[atnum] = at[i].nNumAtInRingSystem;
    3288                 :             :             }
    3289                 :             :         }
    3290                 :             :     }
    3291                 :             : 
    3292                 :           0 :     UnMarkRingSystemsInp(at, nat);
    3293                 :             : 
    3294         [ #  # ]:           0 :     for ( i = 0; i < nat; i++ )
    3295                 :             :     {
    3296         [ #  # ]:           0 :         if ( num_ring_sys[i] > -1 )
    3297                 :             :         {
    3298                 :           0 :             nrings++;
    3299                 :             :         }
    3300                 :             :     }
    3301                 :             : 
    3302                 :             :     /* Restore polymer SRU 'cyclizing' bonds if applicable */
    3303         [ #  # ]:           0 :     for ( j = 0; j < pd->n; j++ )
    3304                 :             :     {
    3305         [ #  # ]:           0 :         if ( pd->units[j]->cyclized )
    3306                 :             :         {
    3307                 :           0 :             OrigAtData_AddSingleStereolessBond(pd->units[j]->end_atom1 - 1,
    3308                 :           0 :                 pd->units[j]->end_atom2 - 1,
    3309                 :             :                 at,
    3310                 :             :                 num_inp_bonds);
    3311                 :             :         }
    3312                 :             :     }
    3313                 :             : 
    3314                 :           0 :     return nrings;
    3315                 :             : }
    3316                 :             : 
    3317                 :             : 
    3318                 :             : /****************************************************************************
    3319                 :             :   Fill atomic properties (OrigAtData ) necessary
    3320                 :             :   to calc seniority in polymer SRUs
    3321                 :             : ****************************************************************************/
    3322                 :           0 : void OAD_Polymer_SetAtProps(OAD_Polymer* pd,
    3323                 :             :     inp_ATOM* at,
    3324                 :             :     int         nat,
    3325                 :             :     int* num_inp_bonds,
    3326                 :             :     OAD_AtProps* aprops,
    3327                 :             :     int* cano_nums)
    3328                 :             : {
    3329                 :             :     /*  Max rank for in-ring atom is 216 which is achieved for N (element number 7 in Periodic system & erank_rule2[] ),*/
    3330                 :             :     /*    then goes O with rank 215 (element number 8), and so on... lowest rank is 1 for H .                           */
    3331                 :             :     /*                                                                                                                  */
    3332                 :             :     /*  This follows to IUPAC rule 2 [Pure Appl. Chem., Vol. 74, No. 10, 2002, p. 1926] which states:                   */
    3333                 :             :     /*  a. a ring or ring system containing nitrogen;                                                                   */
    3334                 :             :     /*  b. a ring or ring system containing the heteroatom occurring earliest in the order given in Rule 4;             */
    3335                 :             :     /*  ( which is     O > S > Se > Te > N > P > As > Sb > Bi > Si > Ge > Sn > Pb > B > Hg )                            */
    3336                 :             :     /*  ...                                                                                                             */
    3337                 :             : 
    3338                 :           0 :     int erank_rule2[] = { 0,1,198,197,196,202,2,216,215,191,190,189,188,187,206,210,214,183,182,181,180,179,178,177,176,
    3339                 :             :                           175,174,173,172,171,170,169,205,209,213,165,164,163,162,161,160,159,158,157,156,155,154,153,152,
    3340                 :             :                           151,204,208,212,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,
    3341                 :             :                           127,126,125,124,123,122,121,201,119,203,207,116,115,114,113,112,111,110,109,108,107,106,105,104,
    3342                 :             :                           103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81 };
    3343                 :             : 
    3344                 :             : 
    3345                 :             : 
    3346                 :             :     /*  Max rank for chain atom is 215 which is achieved for O (element number 8 in Periodic system & erank_rule4[] ),  */
    3347                 :             :     /*  then goes N with rank 212 (element number 8), and so on... lowest rank is 1 for H .                             */
    3348                 :             :     /*                                                                                                                  */
    3349                 :             :     /*  This follows to IUPAC rule 4 [Pure Appl. Chem., Vol. 74, No. 10, 2002, p. 1927] which states:                   */
    3350                 :             :     /*  O > S > Se > Te > N > P > As > Sb > Bi > Si > Ge > Sn > Pb > B > Hg                                             */
    3351                 :             :     /*  Note: Other heteroatoms may be placed within this order as indicated by their positions in the                  */
    3352                 :             :     /*  periodic table [5].                                                                                             */
    3353                 :             : 
    3354                 :           0 :     int erank_rule4[] = { 0,1,198,197,196,202,2,211,215,191,190,189,188,187,206,210,214,183,182,181,180,179,178,177,176,
    3355                 :             :                           175,174,173,172,171,170,169,205,209,213,165,164,163,162,161,160,159,158,157,156,155,154,153,152,
    3356                 :             :                           151,204,208,212,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,
    3357                 :             :                           127,126,125,124,123,122,121,201,119,203,207,116,115,114,113,112,111,110,109,108,107,106,105,104,
    3358                 :             :                           103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81 };
    3359                 :             : 
    3360                 :             : 
    3361                 :           0 :     int i, j, k, nrings = 0;
    3362                 :           0 :     int a1, a2, dummy = 0, bond_type = -1, bond_stereo = -1;
    3363                 :           0 :     int* num_ring_sys = NULL, * size_ring_sys = NULL;
    3364                 :             :     /* djb-rwth: fixing oss-fuzz issue #68112 */
    3365                 :           0 :     int err2_len = sizeof(erank_rule2) / sizeof(erank_rule2[0]);
    3366                 :           0 :     int err4_len = sizeof(erank_rule4) / sizeof(erank_rule4[0]);
    3367                 :             : 
    3368   [ #  #  #  #  :           0 :     if ( (NULL == aprops) || !at || !pd ) /* djb-rwth: fixing oss-fuzz issue #68329, #68286 */
                   #  # ]
    3369                 :             :     {
    3370                 :           0 :         return;
    3371                 :             :     }
    3372                 :             : 
    3373                 :             :     /* Establish element ranks for atoms */
    3374         [ #  # ]:           0 :     for ( k = 0; k < nat; k++ )
    3375                 :             :     {
    3376                 :           0 :         int atnum = at[k].orig_at_number, index = k;
    3377                 :           0 :         U_CHAR err4_ind = at[k].el_number;
    3378         [ #  # ]:           0 :         if ( cano_nums )
    3379                 :             :         {
    3380                 :           0 :             index = cano_nums[atnum];
    3381                 :             :         }
    3382   [ #  #  #  # ]:           0 :         if ( index >= 0 && err4_ind < err4_len )
    3383                 :             :         {
    3384                 :           0 :             aprops[index].erank = erank_rule4[err4_ind];
    3385                 :           0 :             aprops[index].ring_erank = 0;
    3386                 :           0 :             aprops[index].ring_size = 0;
    3387                 :           0 :             aprops[index].ring_num = -1;
    3388                 :             :         }
    3389                 :             :         else
    3390                 :             :         {
    3391                 :             :             /* deleted H's go here */
    3392                 :             :             ;
    3393                 :             :         }
    3394                 :             : 
    3395                 :             :     }
    3396                 :             : 
    3397                 :             :     /* Establish ring systems assignments for atoms */
    3398                 :           0 :     num_ring_sys = (int*)inchi_calloc((long long)nat + 1, sizeof(int)); /* djb-rwth: cast operator added */
    3399         [ #  # ]:           0 :     if ( NULL == num_ring_sys )
    3400                 :             :     {
    3401                 :           0 :         goto exit_function;
    3402                 :             :     }
    3403                 :           0 :     size_ring_sys = (int*)inchi_calloc((long long)nat + 1, sizeof(int)); /* djb-rwth: cast operator added */
    3404         [ #  # ]:           0 :     if ( NULL == size_ring_sys )
    3405                 :             :     {
    3406                 :           0 :         goto exit_function;
    3407                 :             :     }
    3408                 :             : 
    3409                 :             :     /* Note that we get here on the way of InChI2Struct conversion.            */
    3410                 :             :     /* Break temporarily any of (actually, the first) SRU 'cyclizing' bonds    */
    3411         [ #  # ]:           0 :     for ( j = 0; j < pd->n; j++ )
    3412                 :             :     {
    3413   [ #  #  #  # ]:           0 :         if ( pd->units[j]->na > 2 && pd->units[j]->nbkbonds > 0 &&
    3414         [ #  # ]:           0 :             pd->units[j]->cyclized == 0 &&
    3415         [ #  # ]:           0 :             pd->units[j]->cyclizable == CLOSING_SRU_RING )
    3416                 :             :         {
    3417                 :           0 :             a1 = pd->units[j]->bkbonds[0][0] - 1;
    3418                 :           0 :             a2 = pd->units[j]->bkbonds[0][1] - 1;
    3419                 :           0 :             OrigAtData_RemoveBond(a1, a2, at, &bond_type, &bond_stereo, &dummy);
    3420                 :             :         }
    3421                 :             :     }
    3422                 :             : 
    3423                 :           0 :     nrings = OAD_Polymer_FindRingSystems(pd, at, nat, num_inp_bonds, num_ring_sys, size_ring_sys, 0);
    3424                 :             : 
    3425                 :             :     /* Immediately restore just broken bond(s) */
    3426         [ #  # ]:           0 :     for ( j = 0; j < pd->n; j++ )
    3427                 :             :     {
    3428         [ #  # ]:           0 :         if ( pd->units[j]->na > 2 &&
    3429         [ #  # ]:           0 :             pd->units[j]->nbkbonds > 0 &&
    3430         [ #  # ]:           0 :             pd->units[j]->cyclized == 0 &&
    3431         [ #  # ]:           0 :             pd->units[j]->cyclizable == CLOSING_SRU_RING )
    3432                 :             :         {
    3433                 :           0 :             a1 = pd->units[j]->bkbonds[0][0] - 1;
    3434                 :           0 :             a2 = pd->units[j]->bkbonds[0][1] - 1;
    3435                 :             :             /* OrigAtData_AddSingleStereolessBond( a1, a2, at, &dummy ); */
    3436                 :           0 :             OrigAtData_AddBond(a1, a2, at, bond_type, bond_stereo, &dummy);
    3437                 :             :         }
    3438                 :             :     }
    3439                 :             : 
    3440         [ #  # ]:           0 :     if ( nrings )
    3441                 :             :     {
    3442                 :           0 :         int max_ring_num = 0;
    3443                 :             :         /* SRU contains ring[s], proceed with them following (not totally) the IUPAC guidelines */
    3444         [ #  # ]:           0 :         for ( k = 0; k < nat; k++ )
    3445                 :             :         {
    3446                 :             :             /* Browse 0-based original atoms, go to 1-based cano nums domain if cano_nums mapping is suppied */
    3447                 :           0 :             int atnum = at[k].orig_at_number, index = k;
    3448         [ #  # ]:           0 :             if ( cano_nums )
    3449                 :             :             {
    3450                 :           0 :                 index = cano_nums[atnum] + 1;
    3451                 :             :             }
    3452         [ #  # ]:           0 :             if ( num_ring_sys[atnum] >= 0 )
    3453                 :             :             {
    3454                 :           0 :                 aprops[index].ring_num = num_ring_sys[atnum];  /* temporarily */
    3455                 :             : 
    3456         [ #  # ]:           0 :                 if ( max_ring_num < aprops[index].ring_num )
    3457                 :           0 :                     max_ring_num = aprops[index].ring_num;          /* NB: OAD_Polymer_FindRingSystems may return num_ring_sys[]  */
    3458                 :             :                 /* which is not a list of consecutive numbers                 */
    3459                 :             : 
    3460                 :           0 :                 aprops[index].ring_size = size_ring_sys[atnum];     /* Size of ring system which includes the atom k .            */
    3461                 :             :                 /* It is used as an additional score for in-ring              */
    3462                 :             :                 /* atoms' prioritizing (instead of criteria in                */
    3463                 :             :                 /* 2c-2h of IUPAC rule 2 which deal with ring sizes).         */
    3464                 :             :             }
    3465                 :             :         }
    3466                 :             : 
    3467         [ #  # ]:           0 :         for ( i = 0; i <= max_ring_num; i++ )
    3468                 :             :         {
    3469                 :           0 :             int erank, max_erank = 0;
    3470         [ #  # ]:           0 :             for ( k = 0; k < nat; k++ )
    3471                 :             :             {
    3472                 :           0 :                 int atnum = at[k].orig_at_number, index = k;
    3473         [ #  # ]:           0 :                 if ( cano_nums )
    3474                 :             :                 {
    3475                 :           0 :                     index = cano_nums[atnum] + 1;
    3476                 :             :                 }
    3477         [ #  # ]:           0 :                 if ( aprops[index].ring_num == i )
    3478                 :             :                 {
    3479                 :           0 :                     erank = erank_rule2[at[k].el_number];
    3480         [ #  # ]:           0 :                     if ( erank > max_erank )
    3481                 :           0 :                         max_erank = erank;
    3482                 :             :                 }
    3483                 :             :             }
    3484         [ #  # ]:           0 :             for ( k = 0; k < nat; k++ )
    3485                 :             :             {
    3486                 :           0 :                 int atnum = at[k].orig_at_number, index = k;
    3487         [ #  # ]:           0 :                 if ( cano_nums )
    3488                 :             :                 {
    3489                 :           0 :                     index = cano_nums[atnum] + 1;
    3490                 :             :                 }
    3491         [ #  # ]:           0 :                 if ( aprops[index].ring_num == i )
    3492                 :             :                 {
    3493         [ #  # ]:           0 :                     if ( aprops[index].ring_size > 2 )
    3494                 :             :                     {
    3495                 :           0 :                         aprops[index].ring_erank = max_erank;
    3496                 :             :                     }
    3497                 :             :                 }
    3498                 :             :             }
    3499                 :             :         }
    3500                 :             :     }
    3501                 :             : 
    3502                 :           0 : exit_function:
    3503         [ #  # ]:           0 :     if ( num_ring_sys )
    3504                 :             :     {
    3505         [ #  # ]:           0 :         inchi_free(num_ring_sys);
    3506                 :             :     }
    3507         [ #  # ]:           0 :     if ( size_ring_sys )
    3508                 :             :     {
    3509         [ #  # ]:           0 :         inchi_free(size_ring_sys);
    3510                 :             :     }
    3511                 :             : 
    3512                 :           0 :     return;
    3513                 :             : }
    3514                 :             : 
    3515                 :             : 
    3516                 :             : /****************************************************************************
    3517                 :             :   Exclude higher order bonds from list of bkbonds
    3518                 :             : ****************************************************************************/
    3519                 :           0 : void OAD_PolymerUnit_DelistHighOrderBackboneBonds(OAD_PolymerUnit* unit,
    3520                 :             :     ORIG_ATOM_DATA* orig_at_data,
    3521                 :             :     COMP_ATOM_DATA* composite_norm_data,
    3522                 :             :     int* err,
    3523                 :             :     char* pStrErr)
    3524                 :             : {
    3525                 :           0 :     int at1, at2, j = 0, k, check_taut = 0, remove; /* djb-rwth: removing redundant variables/code */
    3526                 :             : 
    3527                 :           0 :     int* orig_num = NULL, * curr_num = NULL;
    3528                 :           0 :     int bond_is_untouchable = 0, btype;  /* DT: moved from below 2024-09-01 DT */
    3529                 :             : 
    3530         [ #  # ]:           0 :     if ( unit->na < 2 )
    3531                 :             :     {
    3532                 :           0 :         return;
    3533                 :             :     }
    3534         [ #  # ]:           0 :     if ( unit->nb < 2 )
    3535                 :             :     {
    3536                 :           0 :         return;
    3537                 :             :     }
    3538         [ #  # ]:           0 :     if ( unit->nbkbonds < 1 )
    3539                 :             :     {
    3540                 :           0 :         return;
    3541                 :             :     }
    3542                 :             : 
    3543                 :             :     /* Care on tautomeric bonds */
    3544         [ #  # ]:           0 :     if ( composite_norm_data )
    3545                 :             :     {
    3546                 :           0 :         check_taut = 1;
    3547                 :           0 :         orig_num = (int*)inchi_calloc((long long)orig_at_data->num_inp_atoms + 2, sizeof(int)); /* djb-rwth: cast operator added */
    3548                 :           0 :         curr_num = (int*)inchi_calloc((long long)orig_at_data->num_inp_atoms + 2, sizeof(int)); /* djb-rwth: cast operator added */
    3549   [ #  #  #  # ]:           0 :         if ( orig_num && curr_num )
    3550                 :             :         {
    3551                 :           0 :             check_taut = 1;
    3552                 :           0 :             CompAtomData_GetNumMapping(composite_norm_data, orig_num, curr_num);
    3553                 :             :         }
    3554                 :             :     }
    3555                 :           0 : repeatj:
    3556                 :           0 :     remove = 0;
    3557                 :           0 :     at1 = unit->bkbonds[j][0];
    3558                 :           0 :     at2 = unit->bkbonds[j][1];
    3559                 :             :     /* djb-rwth: removing redundant code */
    3560         [ #  # ]:           0 :     for ( k = 0; k < orig_at_data->at[at1 - 1].valence; k++ )
    3561                 :             :     {
    3562         [ #  # ]:           0 :         if ( orig_at_data->at[at1 - 1].neighbor[k] != at2 - 1 )
    3563                 :           0 :             continue;
    3564                 :             :         /* djb-rwth: removing redundant code */
    3565                 :             :     }
    3566                 :             :     /*if ( border > 1 ) */
    3567                 :             :     /* djb-rwth: removing redundant code */
    3568                 :           0 :     bond_is_untouchable = 0;
    3569   [ #  #  #  #  :           0 :     if ( check_taut && composite_norm_data && composite_norm_data->at && curr_num ) /* djb-rwth: fixing a NULL pointer dereference */
             #  #  #  # ]
    3570                 :             :     {
    3571         [ #  # ]:           0 :         for ( k = 0; k < composite_norm_data->at[curr_num[at1]].valence; k++ )
    3572                 :             :         {
    3573         [ #  # ]:           0 :             if ( composite_norm_data->at[curr_num[at1]].neighbor[k] != curr_num[at2] )
    3574                 :             :             {
    3575                 :           0 :                 continue;
    3576                 :             :             }
    3577                 :           0 :             btype = composite_norm_data->at[curr_num[at1]].bond_type[k];
    3578                 :           0 :             bond_is_untouchable = (btype == BOND_TAUTOM); /*|| btype == BOND_ALTERN );*/
    3579                 :           0 :             break;
    3580                 :             :         }
    3581                 :             :     }
    3582         [ #  # ]:           0 :     if ( bond_is_untouchable )
    3583                 :             :     {
    3584                 :           0 :         remove = 1;
    3585                 :             :     }
    3586                 :             : 
    3587         [ #  # ]:           0 :     if ( remove )
    3588                 :             :     {
    3589                 :           0 :         OAD_PolymerUnit_RemoveLinkFromCRUChain(at1, at2, &unit->nbkbonds, unit->bkbonds);
    3590                 :             :     }
    3591                 :             :     else
    3592                 :             :     {
    3593                 :           0 :         ++j;
    3594                 :             :     }
    3595                 :             : 
    3596         [ #  # ]:           0 :     if ( j < unit->nbkbonds )
    3597                 :             :     {
    3598                 :           0 :         goto repeatj;
    3599                 :             :     }
    3600                 :             : 
    3601         [ #  # ]:           0 :     if ( orig_num )
    3602                 :             :     {
    3603         [ #  # ]:           0 :         inchi_free(orig_num);
    3604                 :             :     }
    3605         [ #  # ]:           0 :     if ( curr_num )
    3606                 :             :     {
    3607         [ #  # ]:           0 :         inchi_free(curr_num);
    3608                 :             :     }
    3609                 :             : 
    3610                 :           0 :     return;
    3611                 :             : }
    3612                 :             : 
    3613                 :             : 
    3614                 :             : /****************************************************************************
    3615                 :             :  Remove bond (at1, at2)
    3616                 :             : ****************************************************************************/
    3617                 :           0 : void OAD_PolymerUnit_RemoveLinkFromCRUChain(int at1,
    3618                 :             :     int at2,
    3619                 :             :     int* nbonds,
    3620                 :             :     int** bonds)
    3621                 :             : {
    3622                 :             :     int p, q;
    3623                 :             : #if 0
    3624                 :             :     if ( at1 > at2 )
    3625                 :             :     {
    3626                 :             :         int tmp = at1;
    3627                 :             :         at1 = at2;
    3628                 :             :         at2 = tmp;
    3629                 :             :     }
    3630                 :             : #endif
    3631         [ #  # ]:           0 :     for ( p = 0; p < *nbonds; p++ )
    3632                 :             :     {
    3633   [ #  #  #  # ]:           0 :         if ( bonds[p][0] == at1 && bonds[p][1] == at2 )
    3634                 :             :         {
    3635         [ #  # ]:           0 :             for ( q = p + 1; q < *nbonds; q++ )
    3636                 :             :             {
    3637                 :           0 :                 bonds[q - 1][0] = bonds[q][0];
    3638                 :           0 :                 bonds[q - 1][1] = bonds[q][1];
    3639                 :             :             }
    3640                 :           0 :             (*nbonds)--;
    3641                 :           0 :             break;
    3642                 :             :         }
    3643                 :             :     }
    3644                 :             : 
    3645                 :           0 :     return;
    3646                 :             : }
    3647                 :             : 
    3648                 :             : 
    3649                 :             : /****************************************************************************
    3650                 :             :  Debug print polymer data for a given SRU
    3651                 :             : ****************************************************************************/
    3652                 :           0 : void OAD_PolymerUnit_DebugTrace(OAD_PolymerUnit* u)
    3653                 :             : {
    3654                 :           0 :     char* conn = "ABSENT", * typ = "ABSENT", * styp = "ABSENT";
    3655                 :             : 
    3656         [ #  # ]:           0 :     if ( !u )
    3657                 :             :     {
    3658                 :           0 :         return;
    3659                 :             :     }
    3660                 :             : 
    3661         [ #  # ]:           0 :     if ( u->conn == 1 )
    3662                 :             :     {
    3663                 :           0 :         conn = "HT"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3664                 :             :     }
    3665         [ #  # ]:           0 :     else if ( u->conn == 2 )
    3666                 :             :     {
    3667                 :           0 :         conn = "HH"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3668                 :             :     }
    3669         [ #  # ]:           0 :     else if ( u->conn == 3 )
    3670                 :             :     {
    3671                 :           0 :         conn = "EU"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3672                 :             :     }
    3673                 :             : 
    3674         [ #  # ]:           0 :     if ( u->type == 0 )
    3675                 :             :     {
    3676                 :           0 :         typ = "NONE"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3677                 :             :     }
    3678         [ #  # ]:           0 :     else if ( u->type == 1 )
    3679                 :             :     {
    3680                 :           0 :         typ = "SRU"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3681                 :             :     }
    3682         [ #  # ]:           0 :     else if ( u->type == 2 )
    3683                 :             :     {
    3684                 :           0 :         typ = "MON"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3685                 :             :     }
    3686         [ #  # ]:           0 :     else if ( u->type == 3 )
    3687                 :             :     {
    3688                 :           0 :         typ = "COP"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3689                 :             :     }
    3690         [ #  # ]:           0 :     else if ( u->type == 4 )
    3691                 :             :     {
    3692                 :           0 :         typ = "MOD"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3693                 :             :     }
    3694         [ #  # ]:           0 :     else if ( u->type == 5 )
    3695                 :             :     {
    3696                 :           0 :         typ = "MER"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3697                 :             :     }
    3698                 :             : 
    3699         [ #  # ]:           0 :     if ( u->subtype == 1 )
    3700                 :             :     {
    3701                 :           0 :         styp = "ALT"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3702                 :             :     }
    3703         [ #  # ]:           0 :     else if ( u->subtype == 2 )
    3704                 :             :     {
    3705                 :           0 :         styp = "RAN"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3706                 :             :     }
    3707         [ #  # ]:           0 :     else if ( u->subtype == 3 )
    3708                 :             :     {
    3709                 :           0 :         styp = "BLK"; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
    3710                 :             :     }
    3711                 :             : 
    3712                 :             :     {
    3713                 :             :         int i, k;
    3714                 :             :         int na, nb;
    3715                 :             : 
    3716                 :             :         ITRACE_("\n\nPOLYMER UNIT @ %-p", u);
    3717                 :             : 
    3718                 :             :         ITRACE_("\n\tid=%-d   label=%-d   type=%-s   subtype=%-s   conn=%-s   subscr='%-s'\n",
    3719                 :             :             u->id, u->label, typ, styp, conn, u->smt);
    3720                 :             : 
    3721                 :             :         ITRACE_("\tBracket1 coords: %-f, %-f, %-f, %-f\n", u->xbr1[0], u->xbr1[1], u->xbr1[2], u->xbr1[3]);
    3722                 :             :         ITRACE_("\tBracket2 coords: %-f, %-f, %-f, %-f\n", u->xbr2[0], u->xbr2[1], u->xbr2[2], u->xbr2[3]);
    3723                 :             : 
    3724                 :           0 :         na = u->na;
    3725                 :             :         ITRACE_("\t%-d atoms { ", na);
    3726         [ #  # ]:           0 :         for ( k = 0; k < na - 1; k++ )
    3727                 :             :         {
    3728                 :             :             ITRACE_(" %-d, ", u->alist[k]);
    3729                 :             :         }
    3730                 :             :         ITRACE_(" %-d }\n", u->alist[na - 1]);
    3731                 :             : 
    3732                 :           0 :         nb = u->nb;
    3733                 :             :         ITRACE_("\t%-d bonds crossing unit borders { ", nb);
    3734                 :             : 
    3735         [ #  # ]:           0 :         for ( k = 0; k < nb; k++ )
    3736                 :             :         {
    3737                 :             :             ITRACE_(" %-d-%-d ", u->blist[2 * k], u->blist[2 * k + 1]);
    3738                 :             :         }
    3739                 :             :         ITRACE_("}\n");
    3740                 :             : 
    3741                 :             :         ITRACE_("\tCRU caps and end atoms { ");
    3742                 :             : 
    3743                 :             :         ITRACE_("*%-d-[-%-d(end1) ... ", u->cap1, u->end_atom1);
    3744                 :             :         ITRACE_("%-d(end2)-]-*%-d", u->end_atom2, u->cap2);
    3745                 :             :         ITRACE_(" }\n");
    3746                 :             : 
    3747                 :             :         ITRACE_("\tBackbone bonds (may include 'artificially cyclizing' one) : %-d bonds ", u->nbkbonds);
    3748         [ #  # ]:           0 :         if ( u->nbkbonds )
    3749                 :             :         {
    3750                 :             :             ITRACE_(" { ");
    3751         [ #  # ]:           0 :             for ( i = 0; i < u->nbkbonds; i++ )
    3752                 :             :             {
    3753                 :             :                 ITRACE_("(%-d, %-d)  ", u->bkbonds[i][0], u->bkbonds[i][1]);
    3754                 :             :             }
    3755                 :             :             ITRACE_("}\n");
    3756                 :             :         }
    3757                 :             :     }
    3758                 :             : 
    3759                 :             : 
    3760                 :           0 :     return;
    3761                 :             : }
    3762                 :             : 
    3763                 :             : 
    3764                 :             : /****************************************************************************
    3765                 :             :  Debug print the whole polymer data
    3766                 :             : ****************************************************************************/
    3767                 :           0 : void OAD_Polymer_DebugTrace(OAD_Polymer* p)
    3768                 :             : {
    3769                 :             :     int i;
    3770                 :             : 
    3771         [ #  # ]:           0 :     if ( !p )
    3772                 :             :     {
    3773                 :           0 :         return;
    3774                 :             :     }
    3775                 :             : 
    3776                 :             :     ITRACE_("\n\n* POLYMER INFO @ %-p (%-d group(s))", p, p->n);
    3777                 :             :     ITRACE_("\n\n* %-d star atoms: ", p->n_pzz);
    3778         [ #  # ]:           0 :     for ( i = 0; i < p->n_pzz; i++ )
    3779                 :             :     {
    3780                 :             :         ITRACE_(" %-d", p->pzz[i]);
    3781                 :             :     }
    3782                 :             : 
    3783         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    3784                 :             :     {
    3785                 :             :         ITRACE_("\n* Polymer unit %-d", i);
    3786                 :           0 :         OAD_PolymerUnit_DebugTrace(p->units[i]);
    3787                 :             :     }
    3788                 :             :     ITRACE_("\n* Really-do-PS = %-d", p->really_do_frame_shift);
    3789                 :             :     ITRACE_("\n* Frame_shift_scheme = %-d", p->frame_shift_scheme);
    3790                 :             :     ITRACE_("\n* Edit-repeats = %-d", p->edit_repeats);
    3791                 :             :     ITRACE_("\n* End POLYMER INFO\n");
    3792                 :           0 :     return;
    3793                 :             : 
    3794                 :             : }
    3795                 :             : 
    3796                 :             : 
    3797                 :             : /****************************************************************************/
    3798                 :           0 : int  OAD_Polymer_GetRepresentation(OAD_Polymer* p)
    3799                 :             : {
    3800                 :           0 :     int i, n_source_based_units = 0, n_structure_based_units = 0;
    3801                 :             : 
    3802         [ #  # ]:           0 :     if ( !p )
    3803                 :             :     {
    3804                 :           0 :         return NO_POLYMER;
    3805                 :             :     }
    3806                 :             : 
    3807         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    3808                 :             :     {
    3809   [ #  #  #  # ]:           0 :         if ( p->units[i]->nb == 2 || p->units[i]->nbkbonds > 0 ||
    3810   [ #  #  #  # ]:           0 :             ((p->units[i]->cap1 > 0) && (p->units[i]->cap2 > 0)) )
    3811                 :             :         {
    3812                 :           0 :             p->units[i]->representation = POLYMER_REPRESENTATION_STRUCTURE_BASED;
    3813                 :           0 :             n_structure_based_units++;
    3814                 :             :         }
    3815         [ #  # ]:           0 :         else if ( p->units[i]->nb == 0 )
    3816                 :             :         {
    3817                 :           0 :             p->units[i]->representation = POLYMER_REPRESENTATION_SOURCE_BASED;
    3818                 :           0 :             n_source_based_units++;
    3819                 :             :         }
    3820                 :             :     }
    3821         [ #  # ]:           0 :     if ( p->n == n_source_based_units )
    3822                 :             :     {
    3823                 :           0 :         return POLYMER_REPRESENTATION_SOURCE_BASED;
    3824                 :             :     }
    3825         [ #  # ]:           0 :     else if ( p->n == n_structure_based_units )
    3826                 :             :     {
    3827                 :           0 :         return POLYMER_REPRESENTATION_STRUCTURE_BASED;
    3828                 :             :     }
    3829   [ #  #  #  # ]:           0 :     else if ( n_source_based_units &&
    3830                 :           0 :         n_structure_based_units &&
    3831         [ #  # ]:           0 :         (n_source_based_units + n_structure_based_units) == p->n )
    3832                 :             :     {
    3833                 :             :         /* TODO: check if SRU/MON are embedded in a single COP (is this check really necessary? ??) */
    3834                 :           0 :         return POLYMER_REPRESENTATION_MIXED;
    3835                 :             :     }
    3836                 :             : #if 0
    3837                 :             :     else if ( p->n == (n_source_based_units + n_structure_based_units) )
    3838                 :             :     {
    3839                 :             :         /*
    3840                 :             :             Structure based presentation may include no-crossing bond units
    3841                 :             :             which only serve as embedding for ( >1 ) structure-based SRU's.
    3842                 :             :             The code below accounts for this.
    3843                 :             :         */
    3844                 :             :         if ( n_source_based_units < n_structure_based_units )
    3845                 :             :         {
    3846                 :             :             int j, atom, atom_is_shared_with_struct_based_unit = 0;
    3847                 :             :             for ( i = 0; i < p->n; i++ )
    3848                 :             :             {
    3849                 :             :                 int k;
    3850                 :             :                 if ( p->units[i]->representation != POLYMER_REPRESENTATION_SOURCE_BASED )
    3851                 :             :                     continue;
    3852                 :             :                 for ( k = 0; k < p->units[i]->na; k++ )
    3853                 :             :                 {
    3854                 :             :                     atom = p->units[i]->alist[k];
    3855                 :             :                     if ( is_in_the_ilist(p->pzz, atom, p->n_pzz) )
    3856                 :             :                         continue;
    3857                 :             :                     atom_is_shared_with_struct_based_unit = 0;
    3858                 :             :                     for ( j = 0; j < p->n; j++ )
    3859                 :             :                     {
    3860                 :             :                         if ( p->units[j]->representation != POLYMER_REPRESENTATION_STRUCTURE_BASED )
    3861                 :             :                             continue;
    3862                 :             :                         if ( is_in_the_ilist(p->units[j]->alist, atom, p->units[j]->na) )
    3863                 :             :                         {
    3864                 :             :                             atom_is_shared_with_struct_based_unit = 1;
    3865                 :             :                             break;
    3866                 :             :                         }
    3867                 :             :                     }
    3868                 :             :                     if ( !atom_is_shared_with_struct_based_unit )
    3869                 :             :                         break;
    3870                 :             :                 }
    3871                 :             :                 if ( !atom_is_shared_with_struct_based_unit )
    3872                 :             :                     break;
    3873                 :             :             }
    3874                 :             :             if ( atom_is_shared_with_struct_based_unit )
    3875                 :             :                 return POLYMER_REPRESENTATION_STRUCTURE_BASED;
    3876                 :             :         }
    3877                 :             :         return POLYMER_REPRESENTATION_MIXED;
    3878                 :             :     }
    3879                 :             : #endif
    3880                 :             : 
    3881                 :           0 :     return POLYMER_REPRESENTATION_UNRECOGNIZED;
    3882                 :             : }
    3883                 :             : 
    3884                 :             : 
    3885                 :             : /****************************************************************************
    3886                 :             :  Open pre-cyclized CRUs appropriately (i.e., make frame shift)
    3887                 :             : ****************************************************************************/
    3888                 :           0 : void OAD_Polymer_SmartReopenCyclizedUnits(OAD_Polymer* p,
    3889                 :             :     inp_ATOM* at,
    3890                 :             :     int         nat,
    3891                 :             :     int* num_inp_bonds)
    3892                 :             : {
    3893                 :             :     int i;
    3894                 :             :     /* djb-rwth: fixing oss-fuzz issue #68329 */
    3895                 :           0 :     OAD_AtProps* aprops = (OAD_AtProps*)inchi_calloc((long long)nat + 1, sizeof(OAD_AtProps)); /* djb-rwth: cast operator added */
    3896                 :             :     /* nat + 1: add extra element for possibe 1-based indexing */
    3897                 :             : 
    3898         [ #  # ]:           0 :     if ( !p )
    3899                 :             :     {
    3900         [ #  # ]:           0 :         inchi_free(aprops); /* djb-rwth: avoiding memory leak */
    3901                 :           0 :         return;
    3902                 :             :     }
    3903         [ #  # ]:           0 :     if ( p->n < 1 )
    3904                 :             :     {
    3905         [ #  # ]:           0 :         inchi_free(aprops); /* djb-rwth: avoiding memory leak */
    3906                 :           0 :         return;
    3907                 :             :     }
    3908         [ #  # ]:           0 :     if ( !p->really_do_frame_shift )
    3909                 :             :     {
    3910         [ #  # ]:           0 :         inchi_free(aprops); /* djb-rwth: avoiding memory leak */
    3911                 :           0 :         return;
    3912                 :             :     }
    3913                 :             :     /* djb-rwth: fixing oss-fuzz issue #68329 */
    3914         [ #  # ]:           0 :     if ( nat <= 0 )
    3915                 :             :     {
    3916         [ #  # ]:           0 :         inchi_free(aprops); /* djb-rwth: avoiding memory leak */
    3917                 :           0 :         return;
    3918                 :             :     }
    3919                 :             : 
    3920                 :             :     /*ITRACE_( "\n\n*********************************************************************\n* ENTERING OAD_Polymer_SmartReopenCyclizedUnits()" );
    3921                 :             :     OAD_Polymer_DebugTrace( p );*/
    3922                 :             : 
    3923                 :             :     /* Set atom properties for sorting */
    3924   [ #  #  #  # ]:           0 :     if ( !aprops || !at ) /* djb-rwth: fixing oss-fuzz issue #68329, #68286 */
    3925                 :             :     {
    3926         [ #  # ]:           0 :         inchi_free(aprops); /* djb-rwth: avoiding memory leak */
    3927                 :           0 :         return;
    3928                 :             :     }
    3929                 :           0 :     OAD_Polymer_SetAtProps(p, at, nat, num_inp_bonds, aprops, NULL); /* NULL as we alredy are in 1-based cano_nums while at i2s/i2i*/
    3930         [ #  # ]:           0 :     for ( i = 0; i < p->n; i++ )
    3931                 :             :     {
    3932         [ #  # ]:           0 :         if ( p->units[i] ) /* djb-rwth: fixing oss-fuzz issue #68329 */
    3933                 :             :         {
    3934                 :           0 :             OAD_PolymerUnit* u = p->units[i];
    3935         [ #  # ]:           0 :             if ( p->frame_shift_scheme == FSS_NONE )
    3936                 :             :             {
    3937                 :           0 :                 continue;
    3938                 :             :             }
    3939                 :           0 :             if ( /* !u->cyclizable || u->cyclized  || */
    3940         [ #  # ]:           0 :                 u->nbkbonds < 1 ||
    3941   [ #  #  #  # ]:           0 :                 u->cap1 < 1 || u->cap2 < 1 ||
    3942   [ #  #  #  # ]:           0 :                 u->cap1 > nat || u->cap2 > nat )
    3943                 :             :             {
    3944                 :           0 :                 continue;
    3945                 :             :             }
    3946         [ #  # ]:           0 :             if ( OAD_PolymerUnit_SetReopeningDetails(u, at) )
    3947                 :             :             {
    3948                 :             :                 int senior_bond;
    3949                 :           0 :                 OAD_PolymerUnit_SortBackboneBondsAndSetSeniors(u, at, aprops, &senior_bond);
    3950                 :             :             }
    3951                 :           0 :             OAD_PolymerUnit_ReopenCyclized(u, at, aprops, nat, num_inp_bonds);
    3952                 :             :         }
    3953                 :             :     }
    3954                 :             : 
    3955                 :           0 :     p->really_do_frame_shift = 0;
    3956         [ #  # ]:           0 :     inchi_free(aprops);
    3957                 :             : 
    3958                 :           0 :     return;
    3959                 :             : }
    3960                 :             : 
    3961                 :             : 
    3962                 :             : /****************************************************************************/
    3963                 :           0 : void OAD_PolymerUnit_ReopenCyclized(OAD_PolymerUnit* u,
    3964                 :             :     inp_ATOM* at,
    3965                 :             :     OAD_AtProps* aprops,
    3966                 :             :     int             nat,
    3967                 :             :     int* num_inp_bonds)
    3968                 :             : {
    3969                 :             :     int bond_type, bond_stereo;
    3970                 :             : 
    3971         [ #  # ]:           0 :     if ( u->cyclizable == CLOSING_SRU_RING )
    3972                 :             :     {
    3973                 :             :         /* Decyclize artificially introduced bond */
    3974                 :           0 :         OrigAtData_RemoveBond(u->end_atom1 - 1, u->end_atom2 - 1,
    3975                 :             :             at, &bond_type, &bond_stereo, num_inp_bonds);
    3976                 :             :     }
    3977         [ #  # ]:           0 :     else if ( u->cyclizable == CLOSING_SRU_HIGHER_ORDER_BOND )
    3978                 :             :     {
    3979                 :           0 :         OrigAtData_DecreaseBondOrder(u->end_atom1 - 1, u->end_atom2 - 1, at);
    3980                 :             :     }
    3981         [ #  # ]:           0 :     else if ( u->cyclizable == CLOSING_SRU_DIRADICAL )
    3982                 :             :     {
    3983         [ #  # ]:           0 :         if ( at[u->end_atom1 - 1].radical == RADICAL_TRIPLET )
    3984                 :             :         {
    3985                 :           0 :             at[u->end_atom1 - 1].radical = 0;
    3986                 :             :         }
    3987                 :             :     }
    3988                 :             : 
    3989                 :             :     /* Add explicitly connections to star atoms */
    3990                 :           0 :     OrigAtData_AddSingleStereolessBond(u->cap1 - 1, u->end_atom1 - 1,
    3991                 :             :         at, num_inp_bonds);
    3992                 :           0 :     OrigAtData_AddSingleStereolessBond(u->cap2 - 1, u->end_atom2 - 1,
    3993                 :             :         at, num_inp_bonds);
    3994                 :             : 
    3995                 :             :     /* Create crossing bonds */
    3996                 :           0 :     u->nb = 2;
    3997                 :           0 :     u->nbkbonds = 0;
    3998         [ #  # ]:           0 :     if ( !u->blist )
    3999                 :             :     {
    4000                 :           0 :         u->blist = (int*)inchi_calloc(2 * (long long)u->nb, sizeof(int)); /* djb-rwth: cast operator added */
    4001                 :             :     }
    4002         [ #  # ]:           0 :     if ( !u->blist )
    4003                 :             :     {
    4004                 :           0 :         return;
    4005                 :             :     }
    4006                 :             : 
    4007                 :           0 :     u->blist[0] = u->cap1;
    4008                 :           0 :     u->blist[1] = u->end_atom1;
    4009                 :           0 :     u->blist[2] = u->cap2;
    4010                 :           0 :     u->blist[3] = u->end_atom2;
    4011                 :             : 
    4012                 :           0 :     return;
    4013                 :             : }
    4014                 :             : 
    4015                 :             : 
    4016                 :             : /****************************************************************************/
    4017                 :           0 : int OAD_PolymerUnit_SetReopeningDetails(OAD_PolymerUnit* u, inp_ATOM* at)
    4018                 :             : {
    4019                 :             :     int k;
    4020                 :             : 
    4021                 :             :     /* Check reopening  type */
    4022                 :             : 
    4023                 :             :     /* Caps are separated by one atom - that's not error but do nothing */
    4024         [ #  # ]:           0 :     if ( u->nbkbonds == 0 )
    4025                 :             :     {
    4026                 :             :         ;
    4027                 :             :     }
    4028         [ #  # ]:           0 :     else if ( u->nbkbonds == 1 )
    4029                 :             :     {
    4030                 :           0 :         u->end_atom1 = u->bkbonds[0][0];
    4031                 :           0 :         u->end_atom2 = u->bkbonds[0][1];
    4032                 :             : 
    4033         [ #  # ]:           0 :         if ( u->end_atom1 == u->end_atom2 )
    4034                 :             :         {
    4035                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_DIRADICAL
    4036                 :           0 :             u->cyclizable = CLOSING_SRU_DIRADICAL;
    4037                 :             : #else
    4038                 :             :             u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;
    4039                 :             : #endif
    4040                 :             :         }
    4041                 :             :         else
    4042                 :             :         {
    4043                 :             :             /* If caps are separated by two atoms - that's not error but do nothing */
    4044         [ #  # ]:           0 :             for ( k = 0; k < at[u->end_atom1 - 1].valence; k++ )
    4045                 :             :             {
    4046         [ #  # ]:           0 :                 if ( at[u->end_atom1 - 1].neighbor[k] == u->end_atom2 - 1 )
    4047                 :             :                 {
    4048         [ #  # ]:           0 :                     if ( at[u->end_atom1 - 1].bond_type[k] > 1 )
    4049                 :             : #ifdef ALLOW_CLOSING_SRU_VIA_HIGHER_ORDER_BOND
    4050                 :           0 :                         u->cyclizable = CLOSING_SRU_HIGHER_ORDER_BOND;
    4051                 :             : #else
    4052                 :             :                         /*                  u->cyclizable = CLOSING_SRU_NOT_APPLICABLE;*/
    4053                 :             : #endif
    4054                 :           0 :                         break;
    4055                 :             :                 }
    4056                 :             :             }
    4057                 :             :         }
    4058                 :             :     } /*    */
    4059                 :             : 
    4060                 :           0 :     return u->nbkbonds;
    4061                 :             : }
    4062                 :             : 
    4063                 :             : 
    4064                 :             : 
    4065                 :             : /****************************************************************************/
    4066                 :           0 : void OAD_PolymerUnit_SortBackboneBondsAndSetSeniors(OAD_PolymerUnit* u,
    4067                 :             :     inp_ATOM* at,
    4068                 :             :     OAD_AtProps* aprops,
    4069                 :             :     int* senior_bond)
    4070                 :             : {
    4071                 :           0 :     int j, * bnum = NULL;
    4072                 :             : 
    4073                 :           0 :     *senior_bond = 0;
    4074                 :             : 
    4075                 :             :     /* Sort backbone (== frame shiftable) bonds if necessary */
    4076         [ #  # ]:           0 :     if ( u->nbkbonds > 1 )
    4077                 :             :     {
    4078                 :           0 :         bnum = (int*)inchi_calloc(u->nbkbonds, sizeof(int));
    4079         [ #  # ]:           0 :         if ( bnum )
    4080                 :             :         {
    4081         [ #  # ]:           0 :             for ( j = 0; j < u->nbkbonds; j++ )
    4082                 :             :             {
    4083                 :           0 :                 bnum[j] = j;
    4084                 :             :             }
    4085                 :           0 :             OAD_PolymerUnit_SortBackboneBonds(u, aprops, bnum);
    4086                 :           0 :             *senior_bond = bnum[0];
    4087         [ #  # ]:           0 :             inchi_free(bnum);
    4088                 :             :         }
    4089                 :             :     }
    4090                 :             : 
    4091                 :             :     /* v. 1.05+ : place senior atom the first ("left") in the senior bond */
    4092         [ #  # ]:           0 :     if ( OAD_Polymer_IsFirstAtomRankLower(u->bkbonds[*senior_bond][0], u->bkbonds[*senior_bond][1], aprops) == 1 )
    4093                 :             :     {
    4094                 :           0 :         int tmp = u->bkbonds[*senior_bond][0];
    4095                 :           0 :         u->bkbonds[*senior_bond][0] = u->bkbonds[*senior_bond][1];
    4096                 :           0 :         u->bkbonds[*senior_bond][1] = tmp;
    4097                 :             :     }
    4098                 :             : 
    4099                 :           0 :     u->end_atom1 = u->bkbonds[*senior_bond][0];
    4100                 :           0 :     u->end_atom2 = u->bkbonds[*senior_bond][1];
    4101                 :             : 
    4102                 :           0 :     return;
    4103                 :             : }
    4104                 :             : 
    4105                 :             : 
    4106                 :             : /****************************************************************************/
    4107                 :           0 : void OAD_PolymerUnit_SortBackboneBonds(OAD_PolymerUnit* u,
    4108                 :             :     OAD_AtProps* aprops,
    4109                 :             :     int* bnum)
    4110                 :             : {
    4111                 :             :     int i, j, tmp;
    4112                 :           0 :     int n = u->nbkbonds;
    4113         [ #  # ]:           0 :     if ( NULL == bnum )
    4114                 :             :     {
    4115                 :           0 :         return;
    4116                 :             :     }
    4117         [ #  # ]:           0 :     for ( i = 1; i < n; i++ )
    4118                 :             :     {
    4119                 :           0 :         tmp = bnum[i];
    4120                 :           0 :         j = i - 1;
    4121   [ #  #  #  # ]:           0 :         while ( j >= 0 && OAD_Polymer_CompareBackboneBondsSeniority(u->bkbonds[bnum[j]], u->bkbonds[tmp], aprops) > 0 )
    4122                 :             :         {
    4123                 :           0 :             bnum[j + 1] = bnum[j];
    4124                 :           0 :             j--;
    4125                 :             :         }
    4126                 :           0 :         bnum[j + 1] = tmp;
    4127                 :             :     }
    4128                 :             : 
    4129                 :           0 :     return;
    4130                 :             : }
    4131                 :             : 
    4132                 :             : 
    4133                 :             : /****************************************************************************
    4134                 :             :  For sorting SRU cyclizing bonds (PS=='frame-shift') in descending order
    4135                 :             :  In general:  favor greater max-rank end
    4136                 :             :               if max ends are the same, favor lesser min-rank end
    4137                 :             : ****************************************************************************/
    4138                 :           0 : int  OAD_Polymer_CompareBackboneBondsSeniority(int* b1, int* b2, OAD_AtProps* aprops)
    4139                 :             : {
    4140                 :           0 :     int b1min, b1max, b2min, b2max, tmp, cmp = 0;
    4141                 :             : 
    4142                 :             :     /* Find min and max ext-ranked ends of the both bonds */
    4143                 :           0 :     b1max = b1[0]; b1min = b1[1];
    4144                 :           0 :     b2max = b2[0]; b2min = b2[1];
    4145         [ #  # ]:           0 :     if ( OAD_Polymer_IsFirstAtomRankLower(b1min, b1max, aprops) == -1 )
    4146                 :             :     {
    4147                 :           0 :         tmp = b1max;
    4148                 :           0 :         b1max = b1min;
    4149                 :           0 :         b1min = tmp;
    4150                 :             :     }
    4151         [ #  # ]:           0 :     if ( OAD_Polymer_IsFirstAtomRankLower(b2min, b2max, aprops) == -1 )
    4152                 :             :     {
    4153                 :           0 :         tmp = b2max;
    4154                 :           0 :         b2max = b2min;
    4155                 :           0 :         b2min = tmp;
    4156                 :             :     }
    4157                 :             : 
    4158                 :             :     /* Compare bonds' seniority */
    4159                 :             : 
    4160                 :             :     /* First, favor the bond which has greater ext-rank end
    4161                 :             :        NB: the result may be 0, that is, equal max ext. ranks */
    4162                 :             : 
    4163                 :           0 :     cmp = OAD_Polymer_CompareRanksOfTwoAtoms(b1max, b2max, aprops);
    4164         [ #  # ]:           0 :     if ( cmp == 1 )
    4165                 :             :     {
    4166                 :           0 :         return   1;        /* rank(b1max) < rank(b2max), so bond2 is senior */
    4167                 :             :     }
    4168         [ #  # ]:           0 :     else if ( cmp == -1 )
    4169                 :             :     {
    4170                 :           0 :         return  -1;        /* rank(b1max) > rank(b2max), so bond1 is senior */
    4171                 :             :     }
    4172                 :             : 
    4173                 :             :     /* Max ends are of the same rank, so favor the bond with lesser min-rank end
    4174                 :             :        NB: the result may NOT be 0, that is, the case is always resolved    */
    4175                 :             : 
    4176                 :           0 :     cmp = OAD_Polymer_CompareRanksOfTwoAtoms(b1min, b2min, aprops); /*OAD_Polymer_IsFirstAtomRankLower( b1min, b2min, aprops );*/
    4177                 :             : 
    4178         [ #  # ]:           0 :     if ( cmp == 1 )
    4179                 :             :     {
    4180                 :           0 :         return  -1;         /* rank(b1min) < rank(b2min), so bond1 is senior */
    4181                 :             :     }
    4182         [ #  # ]:           0 :     else if ( cmp == -1 )
    4183                 :             :     {
    4184                 :           0 :         return   1;         /* rank(b1min) > rank(b2min), so bond2 is senior */
    4185                 :             :     }
    4186                 :             : 
    4187                 :             :     /* Min ends are of the same rank. Here is the time to compare directly
    4188                 :             :        which canonical number is larger of max-ends ... */
    4189                 :             : 
    4190         [ #  # ]:           0 :     if ( b1max < b2max )
    4191                 :             :     {
    4192                 :           0 :         return  1;
    4193                 :             :     }
    4194         [ #  # ]:           0 :     if ( b1max > b2max )
    4195                 :             :     {
    4196                 :           0 :         return -1;
    4197                 :             :     }
    4198                 :             : 
    4199                 :             :     /* ... they are the same, so compare which canonical number is larger for min-ends ... */
    4200                 :             : 
    4201         [ #  # ]:           0 :     if ( b1min < b2min )
    4202                 :             :     {
    4203                 :           0 :         return -1;          /* b1min < b2min, so bond1 is senior */
    4204                 :             :     }
    4205         [ #  # ]:           0 :     if ( b1min > b2min )
    4206                 :             :     {
    4207                 :           0 :         return  1;          /* b1min > b2min, so bond2 is senior */
    4208                 :             :     }
    4209                 :             : 
    4210                 :           0 :     return 0;    /* we should not reach there */
    4211                 :             : }
    4212                 :             : 
    4213                 :             : 
    4214                 :             : /****************************************************************************
    4215                 :             :  Compare seniority of two atoms in polymer SRU
    4216                 :             :  loosely following IUPAC guidelines.
    4217                 :             :  NB: no last resort check here, so 0 (=='same seniority') may be returned
    4218                 :             : ****************************************************************************/
    4219                 :           0 : int OAD_Polymer_CompareRanksOfTwoAtoms(int atom1, int atom2, OAD_AtProps* aprops)
    4220                 :             : {
    4221                 :           0 :     const int HETEROCYC = 3, HETEROAT = 2, CARBOCYC = 1, CARBOAT = 0;
    4222                 :             :     /* NB: Carbon's rank is always 2, next to the lowest */
    4223                 :             : 
    4224                 :           0 :     int a1 = atom1 - 1;
    4225                 :           0 :     int a2 = atom2 - 1;
    4226                 :           0 :     int a1typ = CARBOAT;
    4227                 :           0 :     int a2typ = CARBOAT;
    4228                 :             : 
    4229                 :             :     /* djb-rwth: fixing oss-fuzz issue #69501, #68277 */
    4230   [ #  #  #  # ]:           0 :     if ( (a1 < 0) || (a2 < 0) )
    4231                 :             :     {
    4232                 :           0 :         return 0;
    4233                 :             :     }
    4234                 :             : 
    4235         [ #  # ]:           0 :     if ( aprops[a1].ring_size > 2 )
    4236                 :             :     {
    4237         [ #  # ]:           0 :         if ( aprops[a1].ring_erank <= 2 )
    4238                 :             :         {
    4239                 :           0 :             a1typ = CARBOCYC;
    4240                 :             :         }
    4241                 :             :         else
    4242                 :             :         {
    4243                 :           0 :             a1typ = HETEROCYC;
    4244                 :             :         }
    4245                 :             :     }
    4246                 :             :     else
    4247                 :             :     {
    4248         [ #  # ]:           0 :         if ( aprops[a1].erank == 2 )
    4249                 :             :         {
    4250                 :           0 :             a1typ = CARBOAT;
    4251                 :             :         }
    4252                 :             :         else
    4253                 :             :         {
    4254                 :           0 :             a1typ = HETEROAT;
    4255                 :             :         }
    4256                 :             :     }
    4257                 :             : 
    4258         [ #  # ]:           0 :     if ( aprops[a2].ring_size > 2 )
    4259                 :             :     {
    4260         [ #  # ]:           0 :         if ( aprops[a2].ring_erank <= 2 )
    4261                 :             :         {
    4262                 :           0 :             a2typ = CARBOCYC;
    4263                 :             :         }
    4264                 :             :         else
    4265                 :             :         {
    4266                 :           0 :             a2typ = HETEROCYC;
    4267                 :             :         }
    4268                 :             :     }
    4269                 :             :     else
    4270                 :             :     {
    4271         [ #  # ]:           0 :         if ( aprops[a2].erank == 2 )
    4272                 :             :         {
    4273                 :           0 :             a2typ = CARBOAT;
    4274                 :             :         }
    4275                 :             :         else
    4276                 :             :         {
    4277                 :           0 :             a2typ = HETEROAT;
    4278                 :             :         }
    4279                 :             :     }
    4280                 :             : 
    4281                 :             :     /* Compare */
    4282                 :             : 
    4283                 :             :     /*
    4284                 :             :         Follow IUPAC Rule 1
    4285                 :             :             'The basic order of seniority of subunits is:
    4286                 :             :                 heterocyclic rings and ring systems > heteroatom chains >
    4287                 :             :                     > carbocyclic rings and ring systems > acyclic carbon chains'
    4288                 :             :     */
    4289                 :             : 
    4290   [ #  #  #  # ]:           0 :     if ( a1typ == HETEROCYC && a2typ == HETEROCYC )   /* a1 and a2 are HETEROCYC */
    4291                 :             :     {
    4292                 :             :         /* Try resolving by senior-heteroatom ring */
    4293         [ #  # ]:           0 :         if ( aprops[a1].ring_erank < aprops[a2].ring_erank )
    4294                 :             :         {
    4295                 :           0 :             return  1;
    4296                 :             :         }
    4297         [ #  # ]:           0 :         if ( aprops[a1].ring_erank > aprops[a2].ring_erank )
    4298                 :             :         {
    4299                 :           0 :             return -1;
    4300                 :             :         }
    4301                 :             :         /* Same senior-heteroatom rings, try resolving by total ring size */
    4302         [ #  # ]:           0 :         if ( aprops[a1].ring_size < aprops[a2].ring_size )
    4303                 :             :         {
    4304                 :           0 :             return  1;
    4305                 :             :         }
    4306         [ #  # ]:           0 :         if ( aprops[a1].ring_size > aprops[a2].ring_size )
    4307                 :             :         {
    4308                 :           0 :             return -1;
    4309                 :             :         }
    4310                 :             :         /* Could not resolve... */
    4311                 :           0 :         return 0;
    4312                 :             :     }
    4313         [ #  # ]:           0 :     else if ( a1typ == HETEROCYC )
    4314                 :             :     {
    4315                 :           0 :         return -1;  /* a1 is HETEROCYC, a2 is any other (==junior) */
    4316                 :             :     }
    4317         [ #  # ]:           0 :     else if ( a2typ == HETEROCYC )
    4318                 :             :     {
    4319                 :           0 :         return  1;  /* a2 is HETEROCYC, a1 is any other (==junior) */
    4320                 :             :     }
    4321                 :             : 
    4322                 :             :     /* HETEROCYC left out */
    4323                 :             : 
    4324   [ #  #  #  # ]:           0 :     if ( a1typ == HETEROAT && a2typ == HETEROAT )  /* a1 and a2 are HETEROAT */
    4325                 :             :     {
    4326         [ #  # ]:           0 :         if ( aprops[a1].erank < aprops[a2].erank )
    4327                 :             :         {
    4328                 :           0 :             return  1;
    4329                 :             :         }
    4330         [ #  # ]:           0 :         if ( aprops[a1].erank > aprops[a2].erank )
    4331                 :             :         {
    4332                 :           0 :             return -1;
    4333                 :             :         }
    4334                 :             :         /* Could not resolve... */
    4335                 :           0 :         return 0;
    4336                 :             :     }
    4337         [ #  # ]:           0 :     else if ( a1typ == HETEROAT )
    4338                 :             :     {
    4339                 :           0 :         return -1;  /* a1 is HETEROAT, a2 is any other (==junior) */
    4340                 :             :     }
    4341         [ #  # ]:           0 :     else if ( a2typ == HETEROAT )
    4342                 :             :     {
    4343                 :           0 :         return  1;  /* a2 is HETEROAT, a1 is any other (==junior) */
    4344                 :             :     }
    4345                 :             : 
    4346                 :             :     /* HETEROAT left out */
    4347   [ #  #  #  # ]:           0 :     if ( a1typ == CARBOCYC && a2typ == CARBOCYC ) /* a1 and a2 are CARBOCYC */
    4348                 :             :     {
    4349                 :             :         /* Same senior-atom (C) ring, try resolving by total ring size */
    4350         [ #  # ]:           0 :         if ( aprops[a1].ring_size < aprops[a2].ring_size )
    4351                 :             :         {
    4352                 :           0 :             return  1;
    4353                 :             :         }
    4354         [ #  # ]:           0 :         if ( aprops[a1].ring_size > aprops[a2].ring_size )
    4355                 :             :         {
    4356                 :           0 :             return -1;
    4357                 :             :         }
    4358                 :             :         /* Could not resolve... */
    4359                 :           0 :         return 0;
    4360                 :             :     }
    4361         [ #  # ]:           0 :     else if ( a1typ == CARBOCYC )
    4362                 :             :     {
    4363                 :           0 :         return -1;
    4364                 :             :     }
    4365         [ #  # ]:           0 :     else if ( a2typ == CARBOCYC )
    4366                 :             :     {
    4367                 :           0 :         return  1;
    4368                 :             :     }
    4369                 :             : 
    4370                 :           0 :     return 0;        /* 0 means unresolved. It is legal here */
    4371                 :             : }
    4372                 :             : 
    4373                 :             : 
    4374                 :             : /****************************************************************************
    4375                 :             :  Compare seniority of two atoms in polymer SRU
    4376                 :             :  loosely following IUPAC guidelines.
    4377                 :             :  Always return non-zero result, that is, resolve the case.
    4378                 :             : ****************************************************************************/
    4379                 :           0 : int OAD_Polymer_IsFirstAtomRankLower(int atom1, int atom2, OAD_AtProps* aprops)
    4380                 :             : {
    4381                 :             :     /* Compare ext-ranks */
    4382                 :           0 :     int result = OAD_Polymer_CompareRanksOfTwoAtoms(atom1, atom2, aprops);
    4383                 :             : 
    4384         [ #  # ]:           0 :     if ( result )
    4385                 :             :     {
    4386                 :           0 :         return result;
    4387                 :             :     }
    4388                 :             : 
    4389                 :             :     /* Could not resolve who is junior by extended-ranks...             */
    4390                 :             :     /* As a last resort, simply check which canonical number is lesser  */
    4391         [ #  # ]:           0 :     if ( atom1 < atom2 )
    4392                 :             :     {
    4393                 :           0 :         return  1;
    4394                 :             :     }
    4395         [ #  # ]:           0 :     if ( atom1 > atom2 )
    4396                 :             :     {
    4397                 :           0 :         return -1;
    4398                 :             :     }
    4399                 :             : 
    4400                 :             :     /* should not reach there */
    4401                 :           0 :     return 0;
    4402                 :             : }
    4403                 :             : 
    4404                 :             : 
    4405                 :             : /****************************************************************************/
    4406                 :          54 : void OAD_ValidateAndSortOutPseudoElementAtoms(ORIG_ATOM_DATA* orig_at_data,
    4407                 :             :     int treat_polymers,
    4408                 :             :     int bNPZz,
    4409                 :             :     int* err,
    4410                 :             :     char* pStrErr)
    4411                 :             : {
    4412                 :          54 :     int i, k, n_pseudo = 0;
    4413                 :          54 :     int nsgroups = 0, nzz = 0;
    4414                 :          54 :     int nat = orig_at_data->num_inp_atoms;
    4415                 :          54 :     OAD_Polymer* pd = orig_at_data->polymer;
    4416                 :          54 :     OAD_PolymerUnit* u = NULL;
    4417                 :             : 
    4418   [ +  +  -  + ]:          54 :     int pseudos_allowed = (bNPZz == 1) || (treat_polymers != POLYMERS_NO);
    4419                 :             : 
    4420         [ +  + ]:         673 :     for ( k = 0; k < nat; k++ )
    4421                 :             :     {
    4422                 :         619 :         int is_zz = 0, is_star = 0, is_zy = 0;
    4423                 :             : 
    4424                 :             : 
    4425                 :             :         /* Though "Zy" is present in our internal Periodic Table,
    4426                 :             :            _input_ "Zy" atoms are prohibited.
    4427                 :             :         */
    4428         [ -  + ]:         619 :         if ( !strcmp(orig_at_data->at[k].elname, "Zy") )
    4429                 :             :         {
    4430                 :           0 :             is_zy = 1;
    4431                 :             : #if 0
    4432                 :             :             Disabled 2020 - 04 - 07
    4433                 :             :                 TREAT_ERR(*err, (70 + 5), "Invalid element(s):");
    4434                 :             :             TREAT_ERR(*err, (70 + 5), orig_at_data->at[k].elname);
    4435                 :             :             continue;
    4436                 :             : #endif 
    4437                 :             :         }
    4438                 :         619 :         is_star = !strcmp(orig_at_data->at[k].elname, "*");
    4439         [ +  - ]:         619 :         if ( !is_star )
    4440                 :             :         {
    4441                 :         619 :             is_zz = !strcmp(orig_at_data->at[k].elname, "Zz");
    4442                 :             :         }
    4443                 :             : 
    4444   [ +  -  +  -  :         619 :         if ( is_star || is_zz || is_zy )
                   -  + ]
    4445                 :             :         {
    4446                 :           0 :             n_pseudo++;
    4447         [ #  # ]:           0 :             if ( 0 == pseudos_allowed )
    4448                 :             :             {
    4449                 :             :                 /* That's an error */
    4450         [ #  # ]:           0 :                 TREAT_ERR(*err, (70 + 5), "Invalid element(s):");
    4451         [ #  # ]:           0 :                 TREAT_ERR(*err, (70 + 5), orig_at_data->at[k].elname);
    4452                 :           0 :                 continue;
    4453                 :             :             }
    4454                 :             : 
    4455                 :             :             /* Now check if valid pseudoelement atom */
    4456                 :             : 
    4457                 :             :             /* Should be strictly univalent and single-bonded */
    4458                 :             :             /* Should not have isotopic enrichment */
    4459         [ #  # ]:           0 :             if ( orig_at_data->at[k].valence > 1 ||
    4460         [ #  # ]:           0 :                 orig_at_data->at[k].chem_bonds_valence > 1 /* || orig_at_data->at[k].iso_atw_diff != 0    */
    4461                 :             :                 )
    4462                 :             :             {
    4463         [ #  # ]:           0 :                 TREAT_ERR(*err, (70 + 7), "Invalid pseudo element(s) bonding");
    4464                 :             :                 /*TREAT_ERR( *err, ( 70 + 7 ), orig_at_data->at[k].elname );*/
    4465                 :           0 :                 continue;
    4466                 :             :             }
    4467                 :             : 
    4468                 :             : 
    4469                 :             :             /* Now convert both "*" and "Zz" temporarily to "Zy" */
    4470                 :           0 :             mystrncpy(orig_at_data->at[k].elname, "Zy", sizeof("Zy"));
    4471                 :             :         }
    4472                 :             :     }
    4473                 :             : 
    4474                 :          54 :     orig_at_data->n_zy = 0;
    4475                 :          54 :     nzz = 0;
    4476         [ -  + ]:          54 :     if ( orig_at_data->valid_polymer )
    4477                 :             :     {
    4478                 :           0 :         nsgroups = pd->n;
    4479                 :             :         /* If applicable, check each CRU and back-convert "Zy" to "Zz" (polymer-related pseudoelement atoms)
    4480                 :             :            if they are from valid paired CRU crossing bond out-of-bracket caps */
    4481         [ #  # ]:           0 :         for ( i = 0; i < nsgroups; i++ )
    4482                 :             :         {
    4483                 :           0 :             u = pd->units[i];
    4484         [ #  # ]:           0 :             if ( u )
    4485                 :             :             {
    4486   [ #  #  #  # ]:           0 :                 if ( u->cap1_is_undef && u->cap2_is_undef )
    4487                 :             :                 {
    4488                 :             :                     /* valid pair: CRU is capped with two undefined-nature atoms, call them "Zz", finally */
    4489                 :           0 :                     strcpy(orig_at_data->at[u->cap1 - 1].elname, "Zz");
    4490                 :           0 :                     strcpy(orig_at_data->at[u->cap2 - 1].elname, "Zz");
    4491                 :           0 :                     nzz += 2;
    4492                 :             :                 }
    4493                 :             :             }
    4494                 :             :         }
    4495                 :           0 :         orig_at_data->polymer->n_pzz = nzz;
    4496                 :             :     }
    4497                 :             : 
    4498                 :          54 :     orig_at_data->n_zy = n_pseudo - nzz;
    4499         [ -  + ]:          54 :     if ( orig_at_data->n_zy )
    4500                 :             :     {
    4501                 :             :         /* Have non-polymer-related pseudoelement atoms */
    4502         [ #  # ]:           0 :         if ( 0 == bNPZz )
    4503                 :             :         {
    4504         [ #  # ]:           0 :             TREAT_ERR(*err, (70 + 4), "Polymer-unrelated pseudoatoms are not allowed");
    4505                 :             :         }
    4506                 :             :     }
    4507                 :             : 
    4508         [ -  + ]:          54 :     if ( *err )
    4509                 :             :     {
    4510                 :           0 :         orig_at_data->valid_polymer = 0;
    4511                 :             :     }
    4512                 :             : 
    4513                 :          54 : }
    4514                 :             : 
    4515                 :             : 
    4516                 :             : /****************************************************************************/
    4517                 :           0 : int Inp_Atom_GetBondType(inp_ATOM* at, int iatom1, int iatom2)
    4518                 :             : {
    4519                 :             :     int i;
    4520                 :             : 
    4521         [ #  # ]:           0 :     for ( i = 0; i < at[iatom1].valence; i++ )
    4522                 :             :     {
    4523         [ #  # ]:           0 :         if ( at[iatom1].neighbor[i] == iatom2 )
    4524                 :             :         {
    4525                 :           0 :             return at[iatom1].bond_type[i];
    4526                 :             :         }
    4527                 :             :     }
    4528                 :             : 
    4529                 :           0 :     return -1;
    4530                 :             : }
        

Generated by: LCOV version 2.0-1