root/maint/gnulib/lib/argz.c

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

DEFINITIONS

This source file includes following definitions.
  1. argz_append
  2. argz_add
  3. argz_add_sep
  4. argz_create_sep
  5. argz_insert
  6. argz_next
  7. argz_stringify
  8. argz_count
  9. argz_extract
  10. argz_create
  11. argz_delete
  12. str_append
  13. argz_replace

   1 /* Functions for dealing with '\0' separated arg vectors.
   2    Copyright (C) 1995-1998, 2000-2002, 2006, 2008-2021 Free Software
   3    Foundation, Inc.
   4    This file is part of the GNU C Library.
   5 
   6    This file is free software: you can redistribute it and/or modify
   7    it under the terms of the GNU Lesser General Public License as
   8    published by the Free Software Foundation; either version 2.1 of the
   9    License, or (at your option) any later version.
  10 
  11    This file is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU Lesser General Public License for more details.
  15 
  16    You should have received a copy of the GNU Lesser General Public License
  17    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  18 
  19 #include <config.h>
  20 
  21 #include <argz.h>
  22 #include <errno.h>
  23 #include <stdlib.h>
  24 #include <string.h>
  25 
  26 
  27 
  28 /* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN.  */
  29 error_t
  30 argz_append (char **argz, size_t *argz_len, const char *buf, size_t buf_len)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32   size_t new_argz_len = *argz_len + buf_len;
  33   char *new_argz = realloc (*argz, new_argz_len);
  34   if (new_argz)
  35     {
  36       memcpy (new_argz + *argz_len, buf, buf_len);
  37       *argz = new_argz;
  38       *argz_len = new_argz_len;
  39       return 0;
  40     }
  41   else
  42     return ENOMEM;
  43 }
  44 
  45 /* Add STR to the argz vector in ARGZ & ARGZ_LEN.  This should be moved into
  46    argz.c in libshouldbelibc.  */
  47 error_t
  48 argz_add (char **argz, size_t *argz_len, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50   return argz_append (argz, argz_len, str, strlen (str) + 1);
  51 }
  52 
  53 
  54 
  55 error_t
  56 argz_add_sep (char **argz, size_t *argz_len, const char *string, int delim)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58   size_t nlen = strlen (string) + 1;
  59 
  60   if (nlen > 1)
  61     {
  62       const char *rp;
  63       char *wp;
  64 
  65       *argz = (char *) realloc (*argz, *argz_len + nlen);
  66       if (*argz == NULL)
  67         return ENOMEM;
  68 
  69       wp = *argz + *argz_len;
  70       rp = string;
  71       do
  72         if (*rp == delim)
  73           {
  74             if (wp > *argz && wp[-1] != '\0')
  75               *wp++ = '\0';
  76             else
  77               --nlen;
  78           }
  79         else
  80           *wp++ = *rp;
  81       while (*rp++ != '\0');
  82 
  83       *argz_len += nlen;
  84     }
  85 
  86   return 0;
  87 }
  88 
  89 
  90 
  91 error_t
  92 argz_create_sep (const char *string, int delim, char **argz, size_t *len)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94   size_t nlen = strlen (string) + 1;
  95 
  96   if (nlen > 1)
  97     {
  98       const char *rp;
  99       char *wp;
 100 
 101       *argz = (char *) malloc (nlen);
 102       if (*argz == NULL)
 103         return ENOMEM;
 104 
 105       rp = string;
 106       wp = *argz;
 107       do
 108         if (*rp == delim)
 109           {
 110             if (wp > *argz && wp[-1] != '\0')
 111               *wp++ = '\0';
 112             else
 113               --nlen;
 114           }
 115         else
 116           *wp++ = *rp;
 117       while (*rp++ != '\0');
 118 
 119       if (nlen == 0)
 120         {
 121           free (*argz);
 122           *argz = NULL;
 123           *len = 0;
 124         }
 125 
 126       *len = nlen;
 127     }
 128   else
 129     {
 130       *argz = NULL;
 131       *len = 0;
 132     }
 133 
 134   return 0;
 135 }
 136 
 137 
 138 /* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
 139    existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
 140    Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
 141    ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ.  If BEFORE is not
 142    in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
 143    ARGZ, ENOMEM is returned, else 0.  */
 144 error_t
 145 argz_insert (char **argz, size_t *argz_len, char *before, const char *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   if (! before)
 148     return argz_add (argz, argz_len, entry);
 149 
 150   if (before < *argz || before >= *argz + *argz_len)
 151     return EINVAL;
 152 
 153   if (before > *argz)
 154     /* Make sure before is actually the beginning of an entry.  */
 155     while (before[-1])
 156       before--;
 157 
 158   {
 159     size_t after_before = *argz_len - (before - *argz);
 160     size_t entry_len = strlen  (entry) + 1;
 161     size_t new_argz_len = *argz_len + entry_len;
 162     char *new_argz = realloc (*argz, new_argz_len);
 163 
 164     if (new_argz)
 165       {
 166         before = new_argz + (before - *argz);
 167         memmove (before + entry_len, before, after_before);
 168         memmove (before, entry, entry_len);
 169         *argz = new_argz;
 170         *argz_len = new_argz_len;
 171         return 0;
 172       }
 173     else
 174       return ENOMEM;
 175   }
 176 }
 177 
 178 
 179 char *
 180 argz_next (const char *argz, size_t argz_len, const char *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182   if (entry)
 183     {
 184       if (entry < argz + argz_len)
 185         entry = strchr (entry, '\0') + 1;
 186 
 187       return entry >= argz + argz_len ? NULL : (char *) entry;
 188     }
 189   else
 190     if (argz_len > 0)
 191       return (char *) argz;
 192     else
 193       return NULL;
 194 }
 195 
 196 
 197 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
 198    except the last into the character SEP.  */
 199 void
 200 argz_stringify (char *argz, size_t len, int sep)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202   if (len > 0)
 203     while (1)
 204       {
 205         size_t part_len = strnlen (argz, len);
 206         argz += part_len;
 207         len -= part_len;
 208         if (len-- <= 1)         /* includes final '\0' we want to stop at */
 209           break;
 210         *argz++ = sep;
 211       }
 212 }
 213 
 214 
 215 /* Returns the number of strings in ARGZ.  */
 216 size_t
 217 argz_count (const char *argz, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219   size_t count = 0;
 220   while (len > 0)
 221     {
 222       size_t part_len = strlen (argz);
 223       argz += part_len + 1;
 224       len -= part_len + 1;
 225       count++;
 226     }
 227   return count;
 228 }
 229 
 230 
 231 /* Puts pointers to each string in ARGZ, plus a terminating 0 element, into
 232    ARGV, which must be large enough to hold them all.  */
 233 void
 234 argz_extract (const char *argz, size_t len, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236   while (len > 0)
 237     {
 238       size_t part_len = strlen (argz);
 239       *argv++ = (char *) argz;
 240       argz += part_len + 1;
 241       len -= part_len + 1;
 242     }
 243   *argv = 0;
 244 }
 245 
 246 
 247 /* Make a '\0' separated arg vector from a unix argv vector, returning it in
 248    ARGZ, and the total length in LEN.  If a memory allocation error occurs,
 249    ENOMEM is returned, otherwise 0.  */
 250 error_t
 251 argz_create (char *const argv[], char **argz, size_t *len)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253   int argc;
 254   size_t tlen = 0;
 255   char *const *ap;
 256   char *p;
 257 
 258   for (argc = 0; argv[argc] != NULL; ++argc)
 259     tlen += strlen (argv[argc]) + 1;
 260 
 261   if (tlen == 0)
 262     *argz = NULL;
 263   else
 264     {
 265       *argz = malloc (tlen);
 266       if (*argz == NULL)
 267         return ENOMEM;
 268 
 269       for (p = *argz, ap = argv; *ap; ++ap, ++p)
 270         p = stpcpy (p, *ap);
 271     }
 272   *len = tlen;
 273 
 274   return 0;
 275 }
 276 
 277 
 278 /* Delete ENTRY from ARGZ & ARGZ_LEN, if any.  */
 279 void
 280 argz_delete (char **argz, size_t *argz_len, char *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282   if (entry)
 283     /* Get rid of the old value for NAME.  */
 284     {
 285       size_t entry_len = strlen (entry) + 1;
 286       *argz_len -= entry_len;
 287       memmove (entry, entry + entry_len, *argz_len - (entry - *argz));
 288       if (*argz_len == 0)
 289         {
 290           free (*argz);
 291           *argz = 0;
 292         }
 293     }
 294 }
 295 
 296 
 297 /* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and
 298    updating *TO & *TO_LEN appropriately.  If an allocation error occurs,
 299    *TO's old value is freed, and *TO is set to 0.  */
 300 static void
 301 str_append (char **to, size_t *to_len, const char *buf, const size_t buf_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303   size_t new_len = *to_len + buf_len;
 304   char *new_to = realloc (*to, new_len + 1);
 305 
 306   if (new_to)
 307     {
 308       *((char *) mempcpy (new_to + *to_len, buf, buf_len)) = '\0';
 309       *to = new_to;
 310       *to_len = new_len;
 311     }
 312   else
 313     {
 314       free (*to);
 315       *to = 0;
 316     }
 317 }
 318 
 319 /* Replace any occurrences of the string STR in ARGZ with WITH, reallocating
 320    ARGZ as necessary.  If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be
 321    incremented by number of replacements performed.  */
 322 error_t
 323 argz_replace (char **argz, size_t *argz_len, const char *str, const char *with,
     /* [previous][next][first][last][top][bottom][index][help] */
 324                 unsigned *replace_count)
 325 {
 326   error_t err = 0;
 327 
 328   if (str && *str)
 329     {
 330       char *arg = 0;
 331       char *src = *argz;
 332       size_t src_len = *argz_len;
 333       char *dst = 0;
 334       size_t dst_len = 0;
 335       int delayed_copy = 1;     /* True while we've avoided copying anything.  */
 336       size_t str_len = strlen (str), with_len = strlen (with);
 337 
 338       while (!err && (arg = argz_next (src, src_len, arg)))
 339         {
 340           char *match = strstr (arg, str);
 341           if (match)
 342             {
 343               char *from = match + str_len;
 344               size_t to_len = match - arg;
 345               char *to = strndup (arg, to_len);
 346 
 347               while (to && from)
 348                 {
 349                   str_append (&to, &to_len, with, with_len);
 350                   if (to)
 351                     {
 352                       match = strstr (from, str);
 353                       if (match)
 354                         {
 355                           str_append (&to, &to_len, from, match - from);
 356                           from = match + str_len;
 357                         }
 358                       else
 359                         {
 360                           str_append (&to, &to_len, from, strlen (from));
 361                           from = 0;
 362                         }
 363                     }
 364                 }
 365 
 366               if (to)
 367                 {
 368                   if (delayed_copy)
 369                     /* We avoided copying SRC to DST until we found a match;
 370                        now that we've done so, copy everything from the start
 371                        of SRC.  */
 372                     {
 373                       if (arg > src)
 374                         err = argz_append (&dst, &dst_len, src, (arg - src));
 375                       delayed_copy = 0;
 376                     }
 377                   if (! err)
 378                     err = argz_add (&dst, &dst_len, to);
 379                   free (to);
 380                 }
 381               else
 382                 err = ENOMEM;
 383 
 384               if (replace_count)
 385                 (*replace_count)++;
 386             }
 387           else if (! delayed_copy)
 388             err = argz_add (&dst, &dst_len, arg);
 389         }
 390 
 391       if (! err)
 392         {
 393           if (! delayed_copy)
 394             /* We never found any instances of str.  */
 395             {
 396               free (src);
 397               *argz = dst;
 398               *argz_len = dst_len;
 399             }
 400         }
 401       else if (dst_len > 0)
 402         free (dst);
 403     }
 404 
 405   return err;
 406 }

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