(root)/
gettext-0.22.4/
gettext-tools/
src/
str-list.c
       1  /* GNU gettext - internationalization aids
       2     Copyright (C) 1995, 1998, 2000-2004, 2006, 2009, 2020 Free Software
       3     Foundation, Inc.
       4  
       5     This file was written by Peter Miller <millerp@canb.auug.org.au>
       6  
       7     This program is free software: you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      19  
      20  #ifdef HAVE_CONFIG_H
      21  # include "config.h"
      22  #endif
      23  
      24  /* Specification.  */
      25  #include "str-list.h"
      26  
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <string.h>
      30  
      31  #include "xalloc.h"
      32  
      33  
      34  /* Initialize an empty list of strings.  */
      35  void
      36  string_list_init (string_list_ty *slp)
      37  {
      38    slp->item = NULL;
      39    slp->nitems = 0;
      40    slp->nitems_max = 0;
      41  }
      42  
      43  
      44  /* Return a fresh, empty list of strings.  */
      45  string_list_ty *
      46  string_list_alloc ()
      47  {
      48    string_list_ty *slp;
      49  
      50    slp = XMALLOC (string_list_ty);
      51    slp->item = NULL;
      52    slp->nitems = 0;
      53    slp->nitems_max = 0;
      54  
      55    return slp;
      56  }
      57  
      58  
      59  /* Append a single string to the end of a list of strings.  */
      60  void
      61  string_list_append (string_list_ty *slp, const char *s)
      62  {
      63    /* Grow the list.  */
      64    if (slp->nitems >= slp->nitems_max)
      65      {
      66        size_t nbytes;
      67  
      68        slp->nitems_max = slp->nitems_max * 2 + 4;
      69        nbytes = slp->nitems_max * sizeof (slp->item[0]);
      70        slp->item = (const char **) xrealloc (slp->item, nbytes);
      71      }
      72  
      73    /* Add a copy of the string to the end of the list.  */
      74    slp->item[slp->nitems++] = xstrdup (s);
      75  }
      76  
      77  
      78  /* Append a single string to the end of a list of strings, unless it is
      79     already contained in the list.  */
      80  void
      81  string_list_append_unique (string_list_ty *slp, const char *s)
      82  {
      83    size_t j;
      84  
      85    /* Do nothing if the string is already in the list.  */
      86    for (j = 0; j < slp->nitems; ++j)
      87      if (strcmp (slp->item[j], s) == 0)
      88        return;
      89  
      90    /* Grow the list.  */
      91    if (slp->nitems >= slp->nitems_max)
      92      {
      93        slp->nitems_max = slp->nitems_max * 2 + 4;
      94        slp->item = (const char **) xrealloc (slp->item,
      95                                              slp->nitems_max
      96                                              * sizeof (slp->item[0]));
      97      }
      98  
      99    /* Add a copy of the string to the end of the list.  */
     100    slp->item[slp->nitems++] = xstrdup (s);
     101  }
     102  
     103  /* Likewise with a string descriptor as argument.  */
     104  void
     105  string_list_append_unique_desc (string_list_ty *slp,
     106                                  const char *s, size_t s_len)
     107  {
     108    size_t j;
     109  
     110    /* Do nothing if the string is already in the list.  */
     111    for (j = 0; j < slp->nitems; ++j)
     112      if (strlen (slp->item[j]) == s_len && memcmp (slp->item[j], s, s_len) == 0)
     113        return;
     114  
     115    /* Grow the list.  */
     116    if (slp->nitems >= slp->nitems_max)
     117      {
     118        slp->nitems_max = slp->nitems_max * 2 + 4;
     119        slp->item = (const char **) xrealloc (slp->item,
     120                                              slp->nitems_max
     121                                              * sizeof (slp->item[0]));
     122      }
     123  
     124    /* Add a copy of the string to the end of the list.  */
     125    {
     126      char *copy = XNMALLOC (s_len + 1, char);
     127      memcpy (copy, s, s_len);
     128      copy[s_len] = '\0';
     129  
     130      slp->item[slp->nitems++] = copy;
     131    }
     132  }
     133  
     134  
     135  /* Destroy a list of strings.  */
     136  void
     137  string_list_destroy (string_list_ty *slp)
     138  {
     139    size_t j;
     140  
     141    for (j = 0; j < slp->nitems; ++j)
     142      free ((char *) slp->item[j]);
     143    if (slp->item != NULL)
     144      free (slp->item);
     145  }
     146  
     147  
     148  /* Free a list of strings.  */
     149  void
     150  string_list_free (string_list_ty *slp)
     151  {
     152    size_t j;
     153  
     154    for (j = 0; j < slp->nitems; ++j)
     155      free ((char *) slp->item[j]);
     156    if (slp->item != NULL)
     157      free (slp->item);
     158    free (slp);
     159  }
     160  
     161  
     162  /* Return a freshly allocated string obtained by concatenating all the
     163     strings in the list.  */
     164  char *
     165  string_list_concat (const string_list_ty *slp)
     166  {
     167    size_t len;
     168    size_t j;
     169    char *result;
     170    size_t pos;
     171  
     172    len = 1;
     173    for (j = 0; j < slp->nitems; ++j)
     174      len += strlen (slp->item[j]);
     175    result = XNMALLOC (len, char);
     176    pos = 0;
     177    for (j = 0; j < slp->nitems; ++j)
     178      {
     179        len = strlen (slp->item[j]);
     180        memcpy (result + pos, slp->item[j], len);
     181        pos += len;
     182      }
     183    result[pos] = '\0';
     184    return result;
     185  }
     186  
     187  
     188  /* Return a freshly allocated string obtained by concatenating all the
     189     strings in the list, and destroy the list.  */
     190  char *
     191  string_list_concat_destroy (string_list_ty *slp)
     192  {
     193    char *result;
     194  
     195    /* Optimize the most frequent case.  */
     196    if (slp->nitems == 1)
     197      {
     198        result = (char *) slp->item[0];
     199        free (slp->item);
     200      }
     201    else
     202      {
     203        result = string_list_concat (slp);
     204        string_list_destroy (slp);
     205      }
     206    return result;
     207  }
     208  
     209  
     210  /* Return a freshly allocated string obtained by concatenating all the
     211     strings in the list, separated by the separator string, terminated
     212     by the terminator character.  The terminator character is not added if
     213     drop_redundant_terminator is true and the last string already ends with
     214     the terminator. */
     215  char *
     216  string_list_join (const string_list_ty *slp, const char *separator,
     217                    char terminator, bool drop_redundant_terminator)
     218  {
     219    size_t separator_len = strlen (separator);
     220    size_t len;
     221    size_t j;
     222    char *result;
     223    size_t pos;
     224  
     225    len = 1;
     226    for (j = 0; j < slp->nitems; ++j)
     227      {
     228        if (j > 0)
     229          len += separator_len;
     230        len += strlen (slp->item[j]);
     231      }
     232    if (terminator)
     233      ++len;
     234    result = XNMALLOC (len, char);
     235    pos = 0;
     236    for (j = 0; j < slp->nitems; ++j)
     237      {
     238        if (j > 0)
     239          {
     240            memcpy (result + pos, separator, separator_len);
     241            pos += separator_len;
     242          }
     243        len = strlen (slp->item[j]);
     244        memcpy (result + pos, slp->item[j], len);
     245        pos += len;
     246      }
     247    if (terminator
     248        && !(drop_redundant_terminator
     249             && slp->nitems > 0
     250             && (len = strlen (slp->item[slp->nitems - 1])) > 0
     251             && slp->item[slp->nitems - 1][len - 1] == terminator))
     252      result[pos++] = terminator;
     253    result[pos] = '\0';
     254    return result;
     255  }
     256  
     257  
     258  /* Return 1 if s is contained in the list of strings, 0 otherwise.  */
     259  bool
     260  string_list_member (const string_list_ty *slp, const char *s)
     261  {
     262    size_t j;
     263  
     264    for (j = 0; j < slp->nitems; ++j)
     265      if (strcmp (slp->item[j], s) == 0)
     266        return true;
     267    return false;
     268  }
     269  
     270  /* Likewise with a string descriptor as argument.  */
     271  bool
     272  string_list_member_desc (const string_list_ty *slp, const char *s, size_t s_len)
     273  {
     274    size_t j;
     275  
     276    for (j = 0; j < slp->nitems; ++j)
     277      if (strlen (slp->item[j]) == s_len && memcmp (slp->item[j], s, s_len) == 0)
     278        return true;
     279    return false;
     280  }
     281  
     282  
     283  /* Remove s from the list of strings.  Return the removed string or NULL.  */
     284  const char *
     285  string_list_remove (string_list_ty *slp, const char *s)
     286  {
     287    size_t j;
     288  
     289    for (j = 0; j < slp->nitems; ++j)
     290      if (strcmp (slp->item[j], s) == 0)
     291        {
     292          const char *found = slp->item[j];
     293          slp->nitems--;
     294          if (slp->nitems > j)
     295            memmove (&slp->item[j + 1], &slp->item[j],
     296                     (slp->nitems - j) * sizeof (const char *));
     297          return found;
     298        }
     299    return NULL;
     300  }