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-10-14 12:14:55 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                 :             :  * SPDX-License-Identifier: MIT
       3                 :             :  * Copyright (c) 2024 IUPAC and InChI Trust
       4                 :             :  */
       5                 :             : 
       6                 :             : #include <stdio.h>
       7                 :             : #include <stdlib.h>
       8                 :             : #include <string.h>
       9                 :             : #include <ctype.h>
      10                 :             : #include <stdarg.h>
      11                 :             : #include <errno.h>
      12                 :             : #include <limits.h>
      13                 :             : #include <float.h>
      14                 :             : #include <ctype.h>
      15                 :             : #include <locale.h>
      16                 :             : 
      17                 :             : #include "mode.h"
      18                 :             : 
      19                 :             : #if( BUILD_WITH_AMI == 1 && defined( _MSC_VER ) && MSC_AMI == 1 )
      20                 :             : #include <malloc.h>
      21                 :             : #include <io.h>
      22                 :             : #endif
      23                 :             : 
      24                 :             : 
      25                 :             : #ifdef _WIN32
      26                 :             : #include <crtdbg.h>
      27                 :             : #endif
      28                 :             : 
      29                 :             : #include "ichimain.h"
      30                 :             : #include "inchi_api.h"
      31                 :             : #include "bcf_s.h"
      32                 :             : #include "ichi_io.h"
      33                 :             : #include "inpdef.h"
      34                 :             : #include "permutation_util.h"
      35                 :             : 
      36                 :             : 
      37                 :           0 : int rrand(int m)
      38                 :             : {
      39                 :             :     return
      40                 :           0 :         (int)((double)m * (rand() / (RAND_MAX + 1.0)));
      41                 :             : }
      42                 :             : 
      43                 :           0 : void shuffle(void* obj, size_t nmemb, size_t size)
      44                 :             : {
      45                 :           0 :     void* temp = inchi_malloc(size);
      46                 :           0 :     size_t n = nmemb;
      47         [ #  # ]:           0 :     while (n > 1)
      48                 :             :     {
      49                 :           0 :         size_t k = rrand((int)n--);
      50         [ #  # ]:           0 :         if (temp) /* djb-rwth: fixing a NULL pointer dereference */
      51                 :             :         {
      52                 :           0 :             memcpy(temp, BYTE(obj) + n * size, size);
      53                 :           0 :             memcpy(BYTE(obj) + n * size, BYTE(obj) + k * size, size);
      54                 :           0 :             memcpy(BYTE(obj) + k * size, temp, size);
      55                 :             :         }
      56                 :             :     }
      57                 :             : #ifdef _WIN32
      58                 :             :     _free_dbg(temp, _NORMAL_BLOCK); /* djb-rwth: _free_dbg for _malloc_dbg must be used if Windows SDK is used */
      59                 :             : #else
      60                 :           0 :     free(temp); /* djb-rwth: otherwise just free */
      61                 :             : #endif
      62                 :           0 : }
      63                 :             : 
      64                 :             : 
      65                 :             : /* Use after OrigAtData_Duplicate (permuted <-- saved) */
      66                 :           0 : void OrigAtData_Permute(ORIG_ATOM_DATA* permuted, ORIG_ATOM_DATA* saved, int* numbers)
      67                 :             : {
      68                 :             :     int i, j, k;
      69                 :           0 :     int nat = saved->num_inp_atoms;
      70                 :           0 :     size_t atsize = sizeof(saved->at[0]);
      71         [ #  # ]:           0 :     for (i = 0; i < nat; i++)
      72                 :             :     {
      73                 :           0 :         j = numbers[i];
      74                 :           0 :         memcpy(permuted->at + j, saved->at + i, atsize);
      75         [ #  # ]:           0 :         for (k = 0; k < permuted->at[j].valence; k++)
      76                 :             :         {
      77                 :           0 :             permuted->at[j].neighbor[k] = numbers[permuted->at[j].neighbor[k]];
      78                 :             :         }
      79                 :           0 :         permuted->at[j].orig_at_number = 1 + numbers[permuted->at[j].orig_at_number - 1];
      80                 :             :     }
      81   [ #  #  #  # ]:           0 :     if (saved->polymer && permuted->polymer)
      82                 :             :     {
      83         [ #  # ]:           0 :         if (saved->polymer->pzz)
      84                 :             :         {
      85         [ #  # ]:           0 :             for (k = 0; k < saved->polymer->n_pzz; k++)
      86                 :             :             {
      87                 :           0 :                 permuted->polymer->pzz[k] = numbers[permuted->polymer->pzz[k]];
      88                 :             :             }
      89                 :             :         }
      90         [ #  # ]:           0 :         if (saved->polymer->units)
      91                 :             :         {
      92         [ #  # ]:           0 :             for (k = 0; k < saved->polymer->n; k++)
      93                 :             :             {
      94                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->cap1 - 1];
      95                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->end_atom1 - 1];
      96                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->cap2 - 1];
      97                 :           0 :                 permuted->polymer->units[k]->cap1 = 1 + numbers[permuted->polymer->units[k]->end_atom2 - 1];
      98         [ #  # ]:           0 :                 if (permuted->polymer->units[k]->alist)
      99                 :             :                 {
     100         [ #  # ]:           0 :                     for (j = 0; j < permuted->polymer->units[k]->na; j++)
     101                 :             :                     {
     102                 :           0 :                         permuted->polymer->units[k]->alist[j] = 1 + numbers[permuted->polymer->units[k]->alist[j] - 1];
     103                 :             :                     }
     104         [ #  # ]:           0 :                     for (j = 0; j < permuted->polymer->units[k]->nb; j++)
     105                 :             :                     {
     106                 :           0 :                         permuted->polymer->units[k]->blist[2 * j] = 1 + numbers[permuted->polymer->units[k]->blist[2 * j] - 1];
     107                 :           0 :                         permuted->polymer->units[k]->blist[2 * j + 1] = 1 + numbers[permuted->polymer->units[k]->blist[2 * j + 1] - 1];
     108                 :             :                     }
     109                 :             :                 }
     110                 :             :             }
     111                 :             :         }
     112                 :             :     }
     113   [ #  #  #  # ]:           0 :     if (saved->v3000 && permuted->v3000)
     114                 :             :     {
     115   [ #  #  #  # ]:           0 :         if (saved->v3000->atom_index_orig && permuted->v3000->atom_index_orig)
     116                 :             :         {
     117         [ #  # ]:           0 :             for (k = 0; k < nat; k++)
     118                 :             :             {
     119                 :           0 :                 permuted->v3000->atom_index_orig[k] = numbers[permuted->v3000->atom_index_orig[k]];
     120                 :             :             }
     121                 :             :         }
     122   [ #  #  #  # ]:           0 :         if (saved->v3000->atom_index_fin && permuted->v3000->atom_index_fin)
     123                 :             :         {
     124         [ #  # ]:           0 :             for (k = 0; k < nat; k++)
     125                 :             :             {
     126                 :           0 :                 permuted->v3000->atom_index_fin[k] = numbers[permuted->v3000->atom_index_fin[k]];
     127                 :             :             }
     128                 :             :         }
     129   [ #  #  #  #  :           0 :         if (saved->v3000->n_haptic_bonds && saved->v3000->lists_haptic_bonds && permuted->v3000->n_haptic_bonds && permuted->v3000->lists_haptic_bonds)
             #  #  #  # ]
     130                 :             :         {
     131         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_haptic_bonds; j++)
     132                 :             :             {
     133                 :           0 :                 permuted->v3000->lists_haptic_bonds[j][1] = numbers[permuted->v3000->lists_haptic_bonds[j][1]];
     134         [ #  # ]:           0 :                 for (k = 3; k < saved->v3000->lists_haptic_bonds[j][2]; k++)
     135                 :             :                 {
     136                 :           0 :                     permuted->v3000->lists_haptic_bonds[j][k] = numbers[permuted->v3000->lists_haptic_bonds[j][k]];
     137                 :             :                 }
     138                 :             :             }
     139                 :             :         }
     140   [ #  #  #  #  :           0 :         if (saved->v3000->n_steabs && saved->v3000->lists_steabs && permuted->v3000->n_steabs && permuted->v3000->lists_steabs)
             #  #  #  # ]
     141                 :             :         {
     142         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_steabs; j++)
     143                 :             :             {
     144         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_steabs[j][1] + 2; k++)
     145                 :             :                 {
     146                 :           0 :                     permuted->v3000->lists_steabs[j][k] = numbers[permuted->v3000->lists_steabs[j][k]];
     147                 :             :                 }
     148                 :             :             }
     149                 :             :         }
     150   [ #  #  #  #  :           0 :         if (saved->v3000->n_sterel && saved->v3000->lists_sterel && permuted->v3000->n_sterel && permuted->v3000->lists_sterel)
             #  #  #  # ]
     151                 :             :         {
     152         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_sterel; j++)
     153                 :             :             {
     154         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_sterel[j][1] + 2; k++)
     155                 :             :                 {
     156                 :           0 :                     permuted->v3000->lists_sterel[j][k] = numbers[permuted->v3000->lists_sterel[j][k]];
     157                 :             :                 }
     158                 :             :             }
     159                 :             :         }
     160   [ #  #  #  #  :           0 :         if (saved->v3000->n_sterac && saved->v3000->lists_sterac && permuted->v3000->n_sterac && permuted->v3000->lists_sterac)
             #  #  #  # ]
     161                 :             :         {
     162         [ #  # ]:           0 :             for (j = 0; j < saved->v3000->n_sterac; j++)
     163                 :             :             {
     164         [ #  # ]:           0 :                 for (k = 2; k < saved->v3000->lists_sterac[j][1] + 2; k++)
     165                 :             :                 {
     166                 :           0 :                     permuted->v3000->lists_sterac[j][k] = numbers[permuted->v3000->lists_sterac[j][k]];
     167                 :             :                 }
     168                 :             :             }
     169                 :             :         }
     170                 :             :     }
     171                 :             : 
     172                 :           0 :     return;
     173                 :             : }
     174                 :             : 
     175                 :           0 : EXPIMP_TEMPLATE INCHI_API int INCHI_DECL PermuteMolfileText(
     176                 :             :     const char *moltext,
     177                 :             :     char *permuted_moltext,
     178                 :             :     size_t permuted_moltext_len)
     179                 :             : {
     180                 :           0 :     int status = -1;
     181   [ #  #  #  #  :           0 :     if (!moltext || !permuted_moltext || permuted_moltext_len == 0) return status;
                   #  # ]
     182                 :             : 
     183                 :           0 :     int *permutation_mapping = NULL;
     184                 :             :     ORIG_ATOM_DATA atom_data;
     185                 :             :     ORIG_ATOM_DATA permuted_atom_data;
     186                 :           0 :     memset(&atom_data, 0, sizeof(atom_data));
     187                 :           0 :     memset(&permuted_atom_data, 0, sizeof(permuted_atom_data));
     188                 :             : 
     189                 :             :     INCHI_IOSTREAM input_stream;
     190                 :           0 :     inchi_ios_init(&input_stream, INCHI_IOS_TYPE_STRING, NULL);
     191                 :             : 
     192                 :             :     INCHI_IOSTREAM output_stream;
     193                 :           0 :     inchi_ios_init(&output_stream, INCHI_IOS_TYPE_STRING, NULL);
     194                 :             : 
     195         [ #  # ]:           0 :     if (inchi_ios_print_nodisplay(&input_stream, "%s", moltext) <= 0)
     196                 :           0 :         goto exit;
     197                 :             : 
     198                 :           0 :     INCHI_MODE input_atom_flags = 0;
     199                 :           0 :     int struct_read_error = 0;
     200                 :           0 :     int num_atoms = CreateOrigInpDataFromMolfile(
     201                 :             :         &input_stream,
     202                 :             :         &atom_data,
     203                 :             :         0, 1, 1, 0, 0, NULL, NULL, NULL, NULL,
     204                 :             :         &input_atom_flags,
     205                 :             :         &struct_read_error,
     206                 :             :         NULL, 0
     207                 :             :     );
     208                 :             : 
     209         [ #  # ]:           0 :     if (num_atoms <= 0)
     210                 :           0 :         goto exit;
     211                 :             : 
     212         [ #  # ]:           0 :     if (struct_read_error != 0)
     213                 :           0 :         goto exit;
     214                 :             : 
     215         [ #  # ]:           0 :     if (OrigAtData_Duplicate(&permuted_atom_data, &atom_data) != 0)
     216                 :           0 :         goto exit;
     217                 :             : 
     218                 :           0 :     permutation_mapping = inchi_malloc(num_atoms * sizeof(int));
     219         [ #  # ]:           0 :     if (!permutation_mapping)
     220                 :           0 :         goto exit;
     221                 :             : 
     222                 :             :     /* Enforce different permutation for molecules with more than one atom. */
     223                 :             :     int is_identity;
     224                 :             :     do {
     225         [ #  # ]:           0 :         for (int i = 0; i < num_atoms; ++i)
     226                 :           0 :             permutation_mapping[i] = i;
     227                 :           0 :         shuffle(permutation_mapping, num_atoms, sizeof(int));
     228                 :           0 :         is_identity = 1;
     229         [ #  # ]:           0 :         for (int i = 0; i < num_atoms; ++i) {
     230         [ #  # ]:           0 :             if (permutation_mapping[i] != i) {
     231                 :           0 :                 is_identity = 0;
     232                 :           0 :                 break;
     233                 :             :             }
     234                 :             :         }
     235   [ #  #  #  # ]:           0 :     } while (num_atoms > 1 && is_identity);
     236                 :             : 
     237                 :           0 :     OrigAtData_Permute(&permuted_atom_data, &atom_data, permutation_mapping);
     238                 :             : 
     239         [ #  # ]:           0 :     if (OrigAtData_WriteToSDfile(
     240                 :             :             &permuted_atom_data,
     241                 :             :             &output_stream,
     242                 :             :             NULL, NULL, 0, 0, NULL, NULL) != 0)
     243                 :           0 :         goto exit;
     244                 :             : 
     245                 :           0 :     size_t out_len = output_stream.s.nUsedLength;
     246         [ #  # ]:           0 :     if (out_len + 1 > permuted_moltext_len)
     247                 :           0 :         goto exit;
     248                 :             : 
     249                 :           0 :     memcpy(permuted_moltext, output_stream.s.pStr, out_len);
     250                 :           0 :     permuted_moltext[out_len] = '\0';
     251                 :           0 :     status = 0;
     252                 :             : 
     253                 :           0 : exit:
     254                 :           0 :     inchi_ios_close(&input_stream);
     255                 :           0 :     inchi_ios_close(&output_stream);
     256         [ #  # ]:           0 :     inchi_free(permutation_mapping);
     257                 :           0 :     FreeOrigAtData(&permuted_atom_data);
     258                 :           0 :     FreeOrigAtData(&atom_data);
     259                 :             : 
     260                 :           0 :     return status;
     261                 :             : }
        

Generated by: LCOV version 2.0-1