(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
string-desc.c
       1  /* String descriptors.
       2     Copyright (C) 2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation, either version 3 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2023.  */
      18  
      19  #ifdef HAVE_CONFIG_H
      20  # include "config.h"
      21  #endif
      22  
      23  #define GL_STRING_DESC_INLINE _GL_EXTERN_INLINE
      24  
      25  /* Specification and inline definitions.  */
      26  #include "string-desc.h"
      27  
      28  #include <stdarg.h>
      29  #include <stdlib.h>
      30  #include <string.h>
      31  
      32  #include "ialloc.h"
      33  #include "full-write.h"
      34  
      35  
      36  /* ==== Side-effect-free operations on string descriptors ==== */
      37  
      38  /* Return true if A and B are equal.  */
      39  bool
      40  string_desc_equals (string_desc_t a, string_desc_t b)
      41  {
      42    return (a._nbytes == b._nbytes
      43            && (a._nbytes == 0 || memcmp (a._data, b._data, a._nbytes) == 0));
      44  }
      45  
      46  bool
      47  string_desc_startswith (string_desc_t s, string_desc_t prefix)
      48  {
      49    return (s._nbytes >= prefix._nbytes
      50            && (prefix._nbytes == 0
      51                || memcmp (s._data, prefix._data, prefix._nbytes) == 0));
      52  }
      53  
      54  bool
      55  string_desc_endswith (string_desc_t s, string_desc_t suffix)
      56  {
      57    return (s._nbytes >= suffix._nbytes
      58            && (suffix._nbytes == 0
      59                || memcmp (s._data + (s._nbytes - suffix._nbytes), suffix._data,
      60                           suffix._nbytes) == 0));
      61  }
      62  
      63  int
      64  string_desc_cmp (string_desc_t a, string_desc_t b)
      65  {
      66    if (a._nbytes > b._nbytes)
      67      {
      68        if (b._nbytes == 0)
      69          return 1;
      70        return (memcmp (a._data, b._data, b._nbytes) < 0 ? -1 : 1);
      71      }
      72    else if (a._nbytes < b._nbytes)
      73      {
      74        if (a._nbytes == 0)
      75          return -1;
      76        return (memcmp (a._data, b._data, a._nbytes) > 0 ? 1 : -1);
      77      }
      78    else /* a._nbytes == b._nbytes */
      79      {
      80        if (a._nbytes == 0)
      81          return 0;
      82        return memcmp (a._data, b._data, a._nbytes);
      83      }
      84  }
      85  
      86  ptrdiff_t
      87  string_desc_index (string_desc_t s, char c)
      88  {
      89    if (s._nbytes > 0)
      90      {
      91        void *found = memchr (s._data, (unsigned char) c, s._nbytes);
      92        if (found != NULL)
      93          return (char *) found - s._data;
      94      }
      95    return -1;
      96  }
      97  
      98  ptrdiff_t
      99  string_desc_last_index (string_desc_t s, char c)
     100  {
     101    if (s._nbytes > 0)
     102      {
     103        void *found = memrchr (s._data, (unsigned char) c, s._nbytes);
     104        if (found != NULL)
     105          return (char *) found - s._data;
     106      }
     107    return -1;
     108  }
     109  
     110  string_desc_t
     111  string_desc_new_empty (void)
     112  {
     113    string_desc_t result;
     114  
     115    result._nbytes = 0;
     116    result._data = NULL;
     117  
     118    return result;
     119  
     120  }
     121  
     122  string_desc_t
     123  string_desc_from_c (const char *s)
     124  {
     125    string_desc_t result;
     126  
     127    result._nbytes = strlen (s);
     128    result._data = (char *) s;
     129  
     130    return result;
     131  }
     132  
     133  string_desc_t
     134  string_desc_substring (string_desc_t s, idx_t start, idx_t end)
     135  {
     136    string_desc_t result;
     137  
     138    if (!(start >= 0 && start <= end))
     139      /* Invalid arguments.  */
     140      abort ();
     141  
     142    result._nbytes = end - start;
     143    result._data = s._data + start;
     144  
     145    return result;
     146  }
     147  
     148  int
     149  string_desc_write (int fd, string_desc_t s)
     150  {
     151    if (s._nbytes > 0)
     152      if (full_write (fd, s._data, s._nbytes) != s._nbytes)
     153        /* errno is set here.  */
     154        return -1;
     155    return 0;
     156  }
     157  
     158  int
     159  string_desc_fwrite (FILE *fp, string_desc_t s)
     160  {
     161    if (s._nbytes > 0)
     162      if (fwrite (s._data, 1, s._nbytes, fp) != s._nbytes)
     163        return -1;
     164    return 0;
     165  }
     166  
     167  
     168  /* ==== Memory-allocating operations on string descriptors ==== */
     169  
     170  int
     171  string_desc_new (string_desc_t *resultp, idx_t n)
     172  {
     173    string_desc_t result;
     174  
     175    if (!(n >= 0))
     176      /* Invalid argument.  */
     177      abort ();
     178  
     179    result._nbytes = n;
     180    if (n == 0)
     181      result._data = NULL;
     182    else
     183      {
     184        result._data = (char *) imalloc (n);
     185        if (result._data == NULL)
     186          /* errno is set here.  */
     187          return -1;
     188      }
     189  
     190    *resultp = result;
     191    return 0;
     192  }
     193  
     194  string_desc_t
     195  string_desc_new_addr (idx_t n, char *addr)
     196  {
     197    string_desc_t result;
     198  
     199    result._nbytes = n;
     200    if (n == 0)
     201      result._data = NULL;
     202    else
     203      result._data = addr;
     204  
     205    return result;
     206  }
     207  
     208  int
     209  string_desc_new_filled (string_desc_t *resultp, idx_t n, char c)
     210  {
     211    string_desc_t result;
     212  
     213    result._nbytes = n;
     214    if (n == 0)
     215      result._data = NULL;
     216    else
     217      {
     218        result._data = (char *) imalloc (n);
     219        if (result._data == NULL)
     220          /* errno is set here.  */
     221          return -1;
     222        memset (result._data, (unsigned char) c, n);
     223      }
     224  
     225    *resultp = result;
     226    return 0;
     227  }
     228  
     229  int
     230  string_desc_copy (string_desc_t *resultp, string_desc_t s)
     231  {
     232    string_desc_t result;
     233    idx_t n = s._nbytes;
     234  
     235    result._nbytes = n;
     236    if (n == 0)
     237      result._data = NULL;
     238    else
     239      {
     240        result._data = (char *) imalloc (n);
     241        if (result._data == NULL)
     242          /* errno is set here.  */
     243          return -1;
     244        memcpy (result._data, s._data, n);
     245      }
     246  
     247    *resultp = result;
     248    return 0;
     249  }
     250  
     251  int
     252  string_desc_concat (string_desc_t *resultp, idx_t n, string_desc_t string1, ...)
     253  {
     254    if (n <= 0)
     255      /* Invalid argument.  */
     256      abort ();
     257  
     258    idx_t total = 0;
     259    total += string1._nbytes;
     260    if (n > 1)
     261      {
     262        va_list other_strings;
     263        idx_t i;
     264  
     265        va_start (other_strings, string1);
     266        for (i = n - 1; i > 0; i--)
     267          {
     268            string_desc_t arg = va_arg (other_strings, string_desc_t);
     269            total += arg._nbytes;
     270          }
     271        va_end (other_strings);
     272      }
     273  
     274    char *combined = (char *) imalloc (total);
     275    if (combined == NULL)
     276      /* errno is set here.  */
     277      return -1;
     278    idx_t pos = 0;
     279    memcpy (combined, string1._data, string1._nbytes);
     280    pos += string1._nbytes;
     281    if (n > 1)
     282      {
     283        va_list other_strings;
     284        idx_t i;
     285  
     286        va_start (other_strings, string1);
     287        for (i = n - 1; i > 0; i--)
     288          {
     289            string_desc_t arg = va_arg (other_strings, string_desc_t);
     290            if (arg._nbytes > 0)
     291              memcpy (combined + pos, arg._data, arg._nbytes);
     292            pos += arg._nbytes;
     293          }
     294        va_end (other_strings);
     295      }
     296  
     297    string_desc_t result;
     298    result._nbytes = total;
     299    result._data = combined;
     300  
     301    *resultp = result;
     302    return 0;
     303  }
     304  
     305  char *
     306  string_desc_c (string_desc_t s)
     307  {
     308    idx_t n = s._nbytes;
     309    char *result = (char *) imalloc (n + 1);
     310    if (result == NULL)
     311      /* errno is set here.  */
     312      return NULL;
     313    if (n > 0)
     314      memcpy (result, s._data, n);
     315    result[n] = '\0';
     316  
     317    return result;
     318  }
     319  
     320  
     321  /* ==== Operations with side effects on string descriptors ==== */
     322  
     323  void
     324  string_desc_set_char_at (string_desc_t s, idx_t i, char c)
     325  {
     326    if (!(i >= 0 && i < s._nbytes))
     327      /* Invalid argument.  */
     328      abort ();
     329    s._data[i] = c;
     330  }
     331  
     332  void
     333  string_desc_fill (string_desc_t s, idx_t start, idx_t end, char c)
     334  {
     335    if (!(start >= 0 && start <= end))
     336      /* Invalid arguments.  */
     337      abort ();
     338  
     339    if (start < end)
     340      memset (s._data + start, (unsigned char) c, end - start);
     341  }
     342  
     343  void
     344  string_desc_overwrite (string_desc_t s, idx_t start, string_desc_t t)
     345  {
     346    if (!(start >= 0 && start + t._nbytes <= s._nbytes))
     347      /* Invalid arguments.  */
     348      abort ();
     349  
     350    if (t._nbytes > 0)
     351      memcpy (s._data + start, t._data, t._nbytes);
     352  }
     353  
     354  void
     355  string_desc_free (string_desc_t s)
     356  {
     357    free (s._data);
     358  }