diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/util/program_lib_argz.c | 406 |
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 | |||
245 | AC_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])) | 245 | AC_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) |
248 | AC_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]) | 248 | AC_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) |
251 | AC_CHECK_HEADERS([gmp.h],,AC_MSG_ERROR([Compiling GNUnet requires gmp.h (from the GNU MP library, libgmp)])) | 251 | AC_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. */ | ||
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 | } | ||