LCOV - code coverage report
Current view: top level - src - permutation_util.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 0.0 % 110 0
Test Date: 2026-08-20 14:32:48 Functions: 0.0 % 4 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0.0 % 122 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * International Chemical Identifier (InChI)
       3                 :             :  * Version 1
       4                 :             :  * Software version 1.07
       5                 :             :  * April 30, 2024
       6                 :             :  *
       7                 :             :  * MIT License
       8                 :             :  *
       9                 :             :  * Copyright (c) 2024 IUPAC and InChI Trust
      10                 :             :  *
      11                 :             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      12                 :             :  * of this software and associated documentation files (the "Software"), to deal
      13                 :             :  * in the Software without restriction, including without limitation the rights
      14                 :             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      15                 :             :  * copies of the Software, and to permit persons to whom the Software is
      16                 :             :  * furnished to do so, subject to the following conditions:
      17                 :             :  *
      18                 :             :  * The above copyright notice and this permission notice shall be included in all
      19                 :             :  * copies or substantial portions of the Software.
      20                 :             :  *
      21                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      24                 :             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      26                 :             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      27                 :             :  * SOFTWARE.
      28                 :             : *
      29                 :             : * The InChI library and programs are free software developed under the
      30                 :             :  * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
      31                 :             :  * Originally developed at NIST.
      32                 :             :  * Modifications and additions by IUPAC and the InChI Trust.
      33                 :             :  * Some portions of code were developed/changed by external contributors
      34                 :             :  * (either contractor or volunteer) which are listed in the file
      35                 :             :  * 'External-contributors' included in this distribution.
      36                 :             :  *
      37                 :             :  * info@inchi-trust.org
      38                 :             :  *
      39                 :             : */
      40                 :             : 
      41                 :             : #include <stdio.h>
      42                 :             : #include <stdlib.h>
      43                 :             : #include <string.h>
      44                 :             : #include <ctype.h>
      45                 :             : #include <stdarg.h>
      46                 :             : #include <errno.h>
      47                 :             : #include <limits.h>
      48                 :             : #include <float.h>
      49                 :             : #include <ctype.h>
      50                 :             : #include <locale.h>
      51                 :             : 
      52                 :             : #include "mode.h"
      53                 :             : 
      54                 :             : #if( BUILD_WITH_AMI == 1 && defined( _MSC_VER ) && MSC_AMI == 1 )
      55                 :             : #include <malloc.h>
      56                 :             : #include <io.h>
      57                 :             : #endif
      58                 :             : 
      59                 :             : 
      60                 :             : #ifdef _WIN32
      61                 :             : #include <crtdbg.h>
      62                 :             : #endif
      63                 :             : 
      64                 :             : #include "ichimain.h"
      65                 :             : #include "inchi_api.h"
      66                 :             : #include "bcf_s.h"
      67                 :             : #include "ichi_io.h"
      68                 :             : #include "inpdef.h"
      69                 :             : #include "permutation_util.h"
      70                 :             : 
      71                 :             : 
      72                 :           0 : int rrand(int m)
      73                 :             : {
      74                 :             :     return
      75                 :           0 :         (int)((double)m * (rand() / (RAND_MAX + 1.0)));
      76                 :             : }
      77                 :             : 
      78                 :           0 : void shuffle(void* obj, size_t nmemb, size_t size)
      79                 :             : {
      80                 :           0 :     void* temp = inchi_malloc(size);
      81                 :           0 :     size_t n = nmemb;
      82         [ #  # ]:           0 :     while (n > 1)
      83                 :             :     {
      84                 :           0 :         size_t k = rrand((int)n--);
      85         [ #  # ]:           0 :         if (temp) /* djb-rwth: fixing a NULL pointer dereference */
      86                 :             :         {
      87                 :           0 :             memcpy(temp, BYTE(obj) + n * size, size);
      88                 :           0 :             memcpy(BYTE(obj) + n * size, BYTE(obj) + k * size, size);
      89                 :           0 :             memcpy(BYTE(obj) + k * size, temp, size);
      90                 :             :         }
      91                 :             :     }
      92                 :             : #ifdef _WIN32
      93                 :             :     _free_dbg(temp, _NORMAL_BLOCK); /* djb-rwth: _free_dbg for _malloc_dbg must be used if Windows SDK is used */
      94                 :             : #else
      95                 :           0 :     free(temp); /* djb-rwth: otherwise just free */
      96                 :             : #endif
      97                 :           0 : }
      98                 :             : 
      99                 :             : 
     100                 :             : /* Use after OrigAtData_Duplicate (permuted <-- saved) */
     101                 :           0 : void OrigAtData_Permute(ORIG_ATOM_DATA* permuted, ORIG_ATOM_DATA* saved, int* numbers)
     102                 :             : {
     103                 :             :     int i, j, k;
     104                 :           0 :     int nat = saved->num_inp_atoms;
     105                 :           0 :     size_t atsize = sizeof(saved->at[0]);
     106         [ #  # ]:           0 :     for (i = 0; i < nat; i++)
     107                 :             :     {
     108                 :           0 :         j = numbers[i];
     109                 :           0 :         memcpy(permuted->at + j, saved->at + i, atsize);
     110         [ #  # ]:           0 :         for (k = 0; k < permuted->at[j].valence; k++)
     111                 :             :         {
     112                 :           0 :             permuted->at[j].neighbor[k] = numbers[permuted->at[j].neighbor[k]];
     113                 :             :         }
     114                 :           0 :         permuted->at[j].orig_at_number = 1 + numbers[permuted->at[j].orig_at_number - 1];
     115                 :             :     }
     116   [ #  #  #  # ]:           0 :     if (saved->polymer && permuted->polymer)
     117                 :             :     {
     118         [ #  # ]:           0 :         if (saved->polymer->pzz)
     119                 :             :         {
     120         [ #  # ]:           0 :             for (k = 0; k < saved->polymer->n_pzz; k++)
     121                 :             :             {
     122                 :           0 :                 permuted->polymer->pzz[k] = numbers[permuted->polymer->pzz[k]];
     123                 :             :             }
     124                 :             :         }
     125         [ #  # ]:           0 :         if (saved->polymer->units)
     126                 :             :         {
     127         [ #  # ]:           0 :             for (k = 0; k < saved->polymer->n; k++)
     128                 :             :             {
     129                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->cap1 - 1];
     130                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->end_atom1 - 1];
     131                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->cap2 - 1];
     132                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->end_atom2 - 1];
     133         [ #  # ]:           0 :                 if (permuted->polymer->units[k]->alist)
     134                 :             :                 {
     135         [ #  # ]:           0 :                     for (j = 0; j < permuted->polymer->units[k]->na; j++)
     136                 :             :                     {
     137                 :           0 :                         permuted->polymer->units[k]->alist[j] = 1 + numbers[permuted->polymer->units[k]->alist[j] - 1];
     138                 :             :                     }
     139         [ #  # ]:           0 :                     for (j = 0; j < permuted->polymer->units[k]->nb; j++)
     140                 :             :                     {
     141                 :           0 :                         permuted->polymer->units[k]->blist[2 * j] = 1 + numbers[permuted->polymer->units[k]->blist[2 * j] - 1];
     142                 :           0 :                         permuted->polymer->units[k]->blist[2 * j + 1] = 1 + numbers[permuted->polymer->units[k]->blist[2 * j + 1] - 1];
     143                 :             :                     }
     144                 :             :                 }
     145                 :             :             }
     146                 :             :         }
     147                 :             :     }
     148   [ #  #  #  # ]:           0 :     if (saved->v3000 && permuted->v3000)
     149                 :             :     {
     150   [ #  #  #  # ]:           0 :         if (saved->v3000->atom_index_orig && permuted->v3000->atom_index_orig)
     151                 :             :         {
     152         [ #  # ]:           0 :             for (k = 0; k < nat; k++)
     153                 :             :             {
     154                 :           0 :                 permuted->v3000->atom_index_orig[k] = numbers[permuted->v3000->atom_index_orig[k]];
     155                 :             :             }
     156                 :             :         }
     157   [ #  #  #  # ]:           0 :         if (saved->v3000->atom_index_fin && permuted->v3000->atom_index_fin)
     158                 :             :         {
     159         [ #  # ]:           0 :             for (k = 0; k < nat; k++)
     160                 :             :             {
     161                 :           0 :                 permuted->v3000->atom_index_fin[k] = numbers[permuted->v3000->atom_index_fin[k]];
     162                 :             :             }
     163                 :             :         }
     164   [ #  #  #  #  :           0 :         if (saved->v3000->n_haptic_bonds && saved->v3000->lists_haptic_bonds && permuted->v3000->n_haptic_bonds && permuted->v3000->lists_haptic_bonds)
             #  #  #  # ]
     165                 :             :         {
     166         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_haptic_bonds; j++)
     167                 :             :             {
     168                 :           0 :                 permuted->v3000->lists_haptic_bonds[j][1] = numbers[permuted->v3000->lists_haptic_bonds[j][1]];
     169         [ #  # ]:           0 :                 for (k = 3; k < saved->v3000->lists_haptic_bonds[j][2]; k++)
     170                 :             :                 {
     171                 :           0 :                     permuted->v3000->lists_haptic_bonds[j][k] = numbers[permuted->v3000->lists_haptic_bonds[j][k]];
     172                 :             :                 }
     173                 :             :             }
     174                 :             :         }
     175   [ #  #  #  #  :           0 :         if (saved->v3000->n_steabs && saved->v3000->lists_steabs && permuted->v3000->n_steabs && permuted->v3000->lists_steabs)
             #  #  #  # ]
     176                 :             :         {
     177         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_steabs; j++)
     178                 :             :             {
     179         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_steabs[j][1] + 2; k++)
     180                 :             :                 {
     181                 :           0 :                     permuted->v3000->lists_steabs[j][k] = numbers[permuted->v3000->lists_steabs[j][k]];
     182                 :             :                 }
     183                 :             :             }
     184                 :             :         }
     185   [ #  #  #  #  :           0 :         if (saved->v3000->n_sterel && saved->v3000->lists_sterel && permuted->v3000->n_sterel && permuted->v3000->lists_sterel)
             #  #  #  # ]
     186                 :             :         {
     187         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_sterel; j++)
     188                 :             :             {
     189         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_sterel[j][1] + 2; k++)
     190                 :             :                 {
     191                 :           0 :                     permuted->v3000->lists_sterel[j][k] = numbers[permuted->v3000->lists_sterel[j][k]];
     192                 :             :                 }
     193                 :             :             }
     194                 :             :         }
     195   [ #  #  #  #  :           0 :         if (saved->v3000->n_sterac && saved->v3000->lists_sterac && permuted->v3000->n_sterac && permuted->v3000->lists_sterac)
             #  #  #  # ]
     196                 :             :         {
     197         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_sterac; j++)
     198                 :             :             {
     199         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_sterac[j][1] + 2; k++)
     200                 :             :                 {
     201                 :           0 :                     permuted->v3000->lists_sterac[j][k] = numbers[permuted->v3000->lists_sterac[j][k]];
     202                 :             :                 }
     203                 :             :             }
     204                 :             :         }
     205                 :             :     }
     206                 :             : 
     207                 :           0 :     return;
     208                 :             : }
     209                 :             : 
     210                 :           0 : EXPIMP_TEMPLATE INCHI_API int INCHI_DECL PermuteMolfileText(
     211                 :             :     const char *moltext,
     212                 :             :     char *permuted_moltext,
     213                 :             :     size_t permuted_moltext_len)
     214                 :             : {
     215                 :           0 :     int status = -1;
     216   [ #  #  #  #  :           0 :     if (!moltext || !permuted_moltext || permuted_moltext_len == 0) return status;
                   #  # ]
     217                 :             : 
     218                 :           0 :     int *permutation_mapping = NULL;
     219                 :             :     ORIG_ATOM_DATA atom_data;
     220                 :             :     ORIG_ATOM_DATA permuted_atom_data;
     221                 :           0 :     memset(&atom_data, 0, sizeof(atom_data));
     222                 :           0 :     memset(&permuted_atom_data, 0, sizeof(permuted_atom_data));
     223                 :             : 
     224                 :             :     INCHI_IOSTREAM input_stream;
     225                 :           0 :     inchi_ios_init(&input_stream, INCHI_IOS_TYPE_STRING, NULL);
     226                 :             : 
     227                 :             :     INCHI_IOSTREAM output_stream;
     228                 :           0 :     inchi_ios_init(&output_stream, INCHI_IOS_TYPE_STRING, NULL);
     229                 :             : 
     230         [ #  # ]:           0 :     if (inchi_ios_print_nodisplay(&input_stream, "%s", moltext) <= 0)
     231                 :           0 :         goto exit;
     232                 :             : 
     233                 :           0 :     INCHI_MODE input_atom_flags = 0;
     234                 :           0 :     int struct_read_error = 0;
     235                 :           0 :     int num_atoms = CreateOrigInpDataFromMolfile(
     236                 :             :         &input_stream,
     237                 :             :         &atom_data,
     238                 :             :         0, 1, 1, 0, 0, NULL, NULL, NULL, NULL,
     239                 :             :         &input_atom_flags,
     240                 :             :         &struct_read_error,
     241                 :             :         NULL, 0
     242                 :             :     );
     243                 :             : 
     244         [ #  # ]:           0 :     if (num_atoms <= 0)
     245                 :           0 :         goto exit;
     246                 :             : 
     247         [ #  # ]:           0 :     if (struct_read_error != 0)
     248                 :           0 :         goto exit;
     249                 :             : 
     250         [ #  # ]:           0 :     if (OrigAtData_Duplicate(&permuted_atom_data, &atom_data) != 0)
     251                 :           0 :         goto exit;
     252                 :             : 
     253                 :           0 :     permutation_mapping = inchi_malloc(num_atoms * sizeof(int));
     254         [ #  # ]:           0 :     if (!permutation_mapping)
     255                 :           0 :         goto exit;
     256                 :             : 
     257                 :             :     /* Enforce different permutation for molecules with more than one atom. */
     258                 :             :     int is_identity;
     259                 :             :     do {
     260         [ #  # ]:           0 :         for (int i = 0; i < num_atoms; ++i)
     261                 :           0 :             permutation_mapping[i] = i;
     262                 :           0 :         shuffle(permutation_mapping, num_atoms, sizeof(int));
     263                 :           0 :         is_identity = 1;
     264         [ #  # ]:           0 :         for (int i = 0; i < num_atoms; ++i) {
     265         [ #  # ]:           0 :             if (permutation_mapping[i] != i) {
     266                 :           0 :                 is_identity = 0;
     267                 :           0 :                 break;
     268                 :             :             }
     269                 :             :         }
     270   [ #  #  #  # ]:           0 :     } while (num_atoms > 1 && is_identity);
     271                 :             : 
     272                 :           0 :     OrigAtData_Permute(&permuted_atom_data, &atom_data, permutation_mapping);
     273                 :             : 
     274         [ #  # ]:           0 :     if (OrigAtData_WriteToSDfile(
     275                 :             :             &permuted_atom_data,
     276                 :             :             &output_stream,
     277                 :             :             NULL, NULL, 0, 0, NULL, NULL) != 0)
     278                 :           0 :         goto exit;
     279                 :             : 
     280                 :           0 :     size_t out_len = output_stream.s.nUsedLength;
     281         [ #  # ]:           0 :     if (out_len + 1 > permuted_moltext_len)
     282                 :           0 :         goto exit;
     283                 :             : 
     284                 :           0 :     memcpy(permuted_moltext, output_stream.s.pStr, out_len);
     285                 :           0 :     permuted_moltext[out_len] = '\0';
     286                 :           0 :     status = 0;
     287                 :             : 
     288                 :           0 : exit:
     289                 :           0 :     inchi_ios_close(&input_stream);
     290                 :           0 :     inchi_ios_close(&output_stream);
     291         [ #  # ]:           0 :     inchi_free(permutation_mapping);
     292                 :           0 :     FreeOrigAtData(&permuted_atom_data);
     293                 :           0 :     FreeOrigAtData(&atom_data);
     294                 :             : 
     295                 :           0 :     return status;
     296                 :             : }
        

Generated by: LCOV version 2.0-1