* argz.c (argz_add_sep, argz_create, argz_create_sep, argz_replace, argz_delete): import almost verbatim from glibc-2.7; only changes are additional asserts and renaming of __ functions to public interface * argz.m4: check for newly added functions * modules/argz: new dependencies on mempcpy, stpcpy, and strndup
Signed-off-by: David Lutterkort <[EMAIL PROTECTED]> --- lib/argz.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/argz.in.h | 7 ++ m4/argz.m4 | 3 +- modules/argz | 3 + 4 files changed, 233 insertions(+), 1 deletions(-) diff --git a/lib/argz.c b/lib/argz.c index f31ce17..a847bd4 100644 --- a/lib/argz.c +++ b/lib/argz.c @@ -85,6 +85,75 @@ argz_add (char **pargz, size_t *pargz_len, const char *str) error_t +argz_add_sep (char **argz, size_t *argz_len, const char *string, int delim) +{ + size_t nlen; + + assert(argz); + assert(argz_len); + assert(string); + + nlen = strlen(string) + 1; + if (nlen > 1) + { + const char *rp; + char *wp; + + *argz = (char *) realloc (*argz, *argz_len + nlen); + if (*argz == NULL) + return ENOMEM; + + wp = *argz + *argz_len; + rp = string; + do + if (*rp == delim) + { + if (wp > *argz && wp[-1] != '\0') + *wp++ = '\0'; + else + --nlen; + } + else + *wp++ = *rp; + while (*rp++ != '\0'); + + *argz_len += nlen; + } + + return 0; +} + +/* Make a '\0' separated arg vector from a unix argv vector, returning it in + ARGZ, and the total length in LEN. If a memory allocation error occurs, + ENOMEM is returned, otherwise 0. */ +error_t +argz_create (char *const argv[], char **argz, size_t *len) +{ + int argc; + size_t tlen = 0; + char *const *ap; + char *p; + + for (argc = 0; argv[argc] != NULL; ++argc) + tlen += strlen (argv[argc]) + 1; + + if (tlen == 0) + *argz = NULL; + else + { + *argz = malloc (tlen); + if (*argz == NULL) + return ENOMEM; + + for (p = *argz, ap = argv; *ap; ++ap, ++p) + p = __stpcpy (p, *ap); + } + *len = tlen; + + return 0; +} + +error_t argz_create_sep (const char *str, int delim, char **pargz, size_t *pargz_len) { size_t argz_len; @@ -181,6 +250,140 @@ argz_insert (char **pargz, size_t *pargz_len, char *before, const char *entry) return 0; } +/* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and + updating *TO & *TO_LEN appropriately. If an allocation error occurs, + *TO's old value is freed, and *TO is set to 0. */ +static void +str_append (char **to, size_t *to_len, const char *buf, const size_t buf_len) +{ + size_t new_len = *to_len + buf_len; + char *new_to = realloc (*to, new_len + 1); + + if (new_to) + { + *((char *) mempcpy (new_to + *to_len, buf, buf_len)) = '\0'; + *to = new_to; + *to_len = new_len; + } + else + { + free (*to); + *to = 0; + } +} + +/* Replace any occurrences of the string STR in ARGZ with WITH, reallocating + ARGZ as necessary. If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be + incremented by number of replacements performed. */ +error_t +argz_replace (char **argz, size_t *argz_len, const char *str, const char *with, + unsigned int *replace_count) +{ + error_t err = 0; + + assert(argz); + assert(*argz); + assert(argz_len); + assert(with); + assert(replace_count); + + if (str && *str) + { + char *arg = 0; + char *src = *argz; + size_t src_len = *argz_len; + char *dst = 0; + size_t dst_len = 0; + int delayed_copy = 1; /* True while we've avoided copying anything. */ + size_t str_len = strlen (str), with_len = strlen (with); + + while (!err && (arg = argz_next (src, src_len, arg))) + { + char *match = strstr (arg, str); + if (match) + { + char *from = match + str_len; + size_t to_len = match - arg; + char *to = strndup (arg, to_len); + + while (to && from) + { + str_append (&to, &to_len, with, with_len); + if (to) + { + match = strstr (from, str); + if (match) + { + str_append (&to, &to_len, from, match - from); + from = match + str_len; + } + else + { + str_append (&to, &to_len, from, strlen (from)); + from = 0; + } + } + } + + if (to) + { + if (delayed_copy) + /* We avoided copying SRC to DST until we found a match; + now that we've done so, copy everything from the start + of SRC. */ + { + if (arg > src) + err = __argz_append (&dst, &dst_len, src, (arg - src)); + delayed_copy = 0; + } + if (! err) + err = __argz_add (&dst, &dst_len, to); + free (to); + } + else + err = ENOMEM; + + if (replace_count) + (*replace_count)++; + } + else if (! delayed_copy) + err = __argz_add (&dst, &dst_len, arg); + } + + if (! err) + { + if (! delayed_copy) + /* We never found any instances of str. */ + { + free (src); + *argz = dst; + *argz_len = dst_len; + } + } + else if (dst_len > 0) + free (dst); + } + + return err; +} + +/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */ +void +argz_delete (char **argz, size_t *argz_len, char *entry) +{ + if (entry) + /* Get rid of the old value for NAME. */ + { + size_t entry_len = strlen (entry) + 1; + *argz_len -= entry_len; + memmove (entry, entry + entry_len, *argz_len - (entry - *argz)); + if (*argz_len == 0) + { + free (*argz); + *argz = 0; + } + } +} char * argz_next (char *argz, size_t argz_len, const char *entry) @@ -252,3 +455,21 @@ argz_count (const char *argz, size_t argz_len) return count; } + +/* Puts pointers to each string in ARGZ, plus a terminating 0 element, into + ARGV, which must be large enough to hold them all. */ +void +argz_extract (const char *argz, size_t len, char **argv) +{ + assert(argz); + assert(argv); + + while (len > 0) + { + size_t part_len = strlen (argz); + *argv++ = (char *) argz; + argz += part_len + 1; + len -= part_len + 1; + } + *argv = 0; +} diff --git a/lib/argz.in.h b/lib/argz.in.h index 40d5176..4191e12 100644 --- a/lib/argz.in.h +++ b/lib/argz.in.h @@ -51,10 +51,17 @@ LT_SCOPE error_t argz_append (char **pargz, size_t *pargz_len, const char *buf, size_t buf_len); LT_SCOPE error_t argz_add (char **pargz, size_t *pargz_len, const char *str); +LT_SCOPE error_t argz_add_sep (char **argz, size_t *argz_len, + const char *string, int delim); +LT_SCOPE error_t argz_create (char *const argv[], char **argz, size_t *len); LT_SCOPE error_t argz_create_sep(const char *str, int delim, char **pargz, size_t *pargz_len); LT_SCOPE error_t argz_insert (char **pargz, size_t *pargz_len, char *before, const char *entry); +LT_SCOPE error_t argz_replace (char **argz, size_t *argz_len, + const char *str, const char *with, + unsigned int *replace_count); +LT_SCOPE void argz_delete (char **argz, size_t *argz_len, char *entry); LT_SCOPE char * argz_next (char *argz, size_t argz_len, const char *entry); LT_SCOPE void argz_stringify (char *argz, size_t argz_len, int sep); diff --git a/m4/argz.m4 b/m4/argz.m4 index 37c1b11..cb7d490 100644 --- a/m4/argz.m4 +++ b/m4/argz.m4 @@ -25,7 +25,8 @@ AC_CHECK_TYPES([error_t], #endif]) ARGZ_H= -AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ +AC_CHECK_FUNCS([argz_add argz_add_sep argz_append argz_count \ + argz_create_sep argz_insert argz_replace argz_delete \ argz_next argz_stringify], [], [ARGZ_H=argz.h; AC_LIBOBJ([argz])]) dnl if have system argz functions, allow forced use of diff --git a/modules/argz b/modules/argz index 601abb7..9898435 100644 --- a/modules/argz +++ b/modules/argz @@ -7,6 +7,9 @@ lib/argz.c m4/argz.m4 Depends-on: +mempcpy +stpcpy +strndup configure.ac: gl_FUNC_ARGZ -- 1.5.4.1