Remove texinfo from base
[dragonfly.git] / contrib / texinfo / gnulib / lib / argz.c
1 /* Functions for dealing with '\0' separated arg vectors.
2    Copyright (C) 1995-1998, 2000-2002, 2006, 2008 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3, or (at your option)
8    any later version.
9
10    This program 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 General Public License for more details.
14
15    You should have received a copy of the GNU General Public License along
16    with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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,
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 }