root/maint/gnulib/lib/amemxfrm.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. amemxfrm

   1 /* Locale dependent memory area transformation for comparison.
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2009.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* Specification.  */
  21 #include "amemxfrm.h"
  22 
  23 #include <errno.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 
  27 char *
  28 amemxfrm (char *s, size_t n, char *resultbuf, size_t *lengthp)
     /* [previous][next][first][last][top][bottom][index][help] */
  29 {
  30   /* Result accumulator.  */
  31   char *result;
  32   size_t length;
  33   size_t allocated;
  34 
  35   char orig_sentinel;
  36 
  37   /* Initial memory allocation.  */
  38   if (resultbuf != NULL && *lengthp > 0)
  39     {
  40       result = resultbuf;
  41       allocated = *lengthp;
  42     }
  43   else
  44     {
  45       allocated = (n > 0 ? n : 1);
  46       result = (char *) malloc (allocated);
  47       if (result == NULL)
  48         goto out_of_memory_2;
  49     }
  50   length = 0;
  51 
  52   /* Add sentinel.byte.  */
  53   orig_sentinel = s[n];
  54   s[n] = '\0';
  55 
  56   /* Iterate through S, transforming each NUL terminated segment.
  57      Accumulate the resulting transformed segments in result, separated by
  58      NULs.  */
  59   {
  60     const char *p_end = s + n + 1;
  61     const char *p;
  62 
  63     p = s;
  64     for (;;)
  65       {
  66         /* Search next NUL byte.  */
  67         size_t l = strlen (p);
  68 
  69         for (;;)
  70           {
  71             size_t k;
  72 
  73             /* A call to strxfrm costs about 20 times more than a call to
  74                strdup of the result.  Therefore it is worth to try to avoid
  75                calling strxfrm more than once on a given string, by making
  76                enough room before calling strxfrm.
  77                The size of the strxfrm result, k, is likely to be between
  78                l and 3 * l.  */
  79             if (3 * l >= allocated - length)
  80               {
  81                 /* Grow the result buffer.  */
  82                 size_t new_allocated;
  83                 char *new_result;
  84 
  85                 new_allocated = length + 3 * l + 1;
  86                 if (new_allocated < 2 * allocated)
  87                   new_allocated = 2 * allocated;
  88                 if (new_allocated < 64)
  89                   new_allocated = 64;
  90                 if (result == resultbuf)
  91                   new_result = (char *) malloc (new_allocated);
  92                 else
  93                   new_result = (char *) realloc (result, new_allocated);
  94                 if (new_result != NULL)
  95                   {
  96                     allocated = new_allocated;
  97                     result = new_result;
  98                   }
  99               }
 100 
 101             errno = 0;
 102             k = strxfrm (result + length, p, allocated - length);
 103             if (errno != 0)
 104               goto fail;
 105             if (k >= allocated - length)
 106               {
 107                 /* Grow the result buffer.  */
 108                 size_t new_allocated;
 109                 char *new_result;
 110 
 111                 new_allocated = length + k + 1;
 112                 if (new_allocated < 2 * allocated)
 113                   new_allocated = 2 * allocated;
 114                 if (new_allocated < 64)
 115                   new_allocated = 64;
 116                 if (result == resultbuf)
 117                   new_result = (char *) malloc (new_allocated);
 118                 else
 119                   new_result = (char *) realloc (result, new_allocated);
 120                 if (new_result == NULL)
 121                   goto out_of_memory_1;
 122                 allocated = new_allocated;
 123                 result = new_result;
 124               }
 125             else
 126               {
 127                 length += k;
 128                 break;
 129               }
 130           }
 131 
 132         p = p + l + 1;
 133         if (p == p_end)
 134           break;
 135         result[length] = '\0';
 136         length++;
 137       }
 138   }
 139 
 140   /* Shrink the allocated memory if possible.
 141      It is not worth calling realloc when length + 1 == allocated; it would
 142      save just one byte.  */
 143   if (result != resultbuf && length + 1 < allocated)
 144     {
 145       if ((length > 0 ? length : 1) <= *lengthp)
 146         {
 147           memcpy (resultbuf, result, length);
 148           free (result);
 149           result = resultbuf;
 150         }
 151       else
 152         {
 153           char *memory = (char *) realloc (result, length > 0 ? length : 1);
 154           if (memory != NULL)
 155             result = memory;
 156         }
 157     }
 158 
 159   s[n] = orig_sentinel;
 160   *lengthp = length;
 161   return result;
 162 
 163  fail:
 164   if (result != resultbuf)
 165     free (result);
 166   s[n] = orig_sentinel;
 167   return NULL;
 168 
 169  out_of_memory_1:
 170   if (result != resultbuf)
 171     free (result);
 172   s[n] = orig_sentinel;
 173  out_of_memory_2:
 174   errno = ENOMEM;
 175   return NULL;
 176 }

/* [previous][next][first][last][top][bottom][index][help] */