aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/util/program_lib_argz.c406
2 files changed, 407 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 76fda3960..5de419d02 100644
--- a/configure.ac
+++ b/configure.ac
@@ -245,7 +245,7 @@ AC_HEADER_STDC
245AC_CHECK_HEADERS([fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling GNUnet requires standard UNIX headers files])) 245AC_CHECK_HEADERS([fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling GNUnet requires standard UNIX headers files]))
246 246
247# Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) 247# Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there)
248AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h iconv.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h]) 248AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h iconv.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h])
249 249
250# Check for GMP header (and abort if not present) 250# Check for GMP header (and abort if not present)
251AC_CHECK_HEADERS([gmp.h],,AC_MSG_ERROR([Compiling GNUnet requires gmp.h (from the GNU MP library, libgmp)])) 251AC_CHECK_HEADERS([gmp.h],,AC_MSG_ERROR([Compiling GNUnet requires gmp.h (from the GNU MP library, libgmp)]))
diff --git a/src/util/program_lib_argz.c b/src/util/program_lib_argz.c
new file mode 100644
index 000000000..8f5d1f57f
--- /dev/null
+++ b/src/util/program_lib_argz.c
@@ -0,0 +1,406 @@
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 2, 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. */
29error_t
30argz_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. */
47error_t
48argz_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
55error_t
56argz_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
91error_t
92argz_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. */
144error_t
145argz_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
179char *
180argz_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. */
199void
200argz_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. */
216size_t
217argz_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. */
233void
234argz_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. */
250error_t
251argz_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. */
279void
280argz_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. */
300static void
301str_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. */
322error_t
323argz_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}