[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 2/2] Add missing argz_* functions from glibc
From: |
Jim Meyering |
Subject: |
Re: [PATCH 2/2] Add missing argz_* functions from glibc |
Date: |
Tue, 03 Jun 2008 19:12:47 +0200 |
David Lutterkort <address@hidden> wrote:
> On Mon, 2008-06-02 at 14:00 +0200, Jim Meyering wrote:
>> If I hear no objection soon, I will sync gnulib's argz.c
>> directly from glibc, using something like the above.
>> Then, gnulib and libtool can evolve separately, if needed.
>>
>> However, I'd really like to hear that at least one owner of
>> an one argz-using project agrees with this approach.
>
> Since I started this whole discussion: I am perfectly fine with this
> approach.
David,
I've included a still-preliminary patch below, in case you'd like to test it.
[I say preliminary because it effectively removes the C++-accommodating
code that's in the old version and because it's totally untested.
Adding C++ syntax is trivial, if anyone is interested. ]
- argz.c generated via argz-gen, added in config, though I don't
care where this script goes -- it's just checked in on my
private branch for reference.
- argz.in.h generated via the following:
glibc_dir=/mirror/d/glibc
perl -pe 's/__(restrict|const|argz_|st|mem)/$1/g;s/\s*__THROW//' \
$glibc_dir/string/argz.h \
| perl -pe \
'/^(#include <features\.h>|__(?:BEGIN|END)_DECLS)/ or print' \
> argz.in.h
Note that the new .in.h file uses the "restrict" keyword,
so the m4/argz.m4 macro now tests for AC_C_RESTRICT.
In case anyone is interested, here's an alternative argz.c implementation
that gets the same result via separate .c files and cpp directives:
#include <config.h>
#undef weak_alias
#define weak_alias(local, symbol) /* empty */
#undef libc_hidden_def
#define libc_hidden_def(symbol) /* empty */
#undef INTDEF
#define INTDEF(symbol) /* empty */
#define __argz_add argz_add
#define __argz_add_sep argz_add_sep
#define __argz_append argz_append
#define __argz_count argz_count
#define __argz_create argz_create
#define __argz_create_sep argz_create_sep
#define __argz_extract argz_extract
#define __argz_insert argz_insert
#define __argz_next argz_next
#define __argz_replace argz_replace
#define __argz_stringify argz_stringify
#undef __mempcpy
#define __mempcpy mempcpy
#undef __stpcpy
#define __stpcpy stpcpy
#undef __strndup
#define __strndup strndup
#undef __strnlen
#define __strnlen strnlen
#include "argz-append.c"
#include "argz-addsep.c"
#include "argz-ctsep.c"
#include "argz-insert.c"
#include "argz-next.c"
#include "argz-stringify.c"
#include "argz-count.c"
#include "argz-extract.c"
#include "argz-create.c"
#include "argz-delete.c"
#include "argz-replace.c"
These files are all so small, that I have a slight
preference for combining them into one.
>From aef09032b3cdbe643304b25026a76d812d569b0f Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Tue, 3 Jun 2008 11:42:12 +0200
Subject: [PATCH] generate argz.c and argz.in.h from glibc sources
* m4/argz.m4: Require AC_C_RESTRICT.
* lib/argz.c: Generate directly from glibc sources.
* lib/argz.in.h: Likewise.
* config/argz-gen: New script: generate argz.c.
* config/argz.c: Reference argz.c -- FIXME: not to be checked in here.
* config/srclist.txt: Reflect that argz* files are no longer pulled
from libtool.
* config/README: notes on how I compared the two versions of argz.c
FIXME: not to be checked in here
---
config/README | 31 +++
config/argz-gen | 49 +++++
config/argz.c | 41 ++++
config/srclist.txt | 7 +-
lib/argz.c | 512 ++++++++++++++++++++++++++++++++++------------------
lib/argz.in.h | 231 ++++++++++++++++++------
m4/argz.m4 | 4 +-
7 files changed, 632 insertions(+), 243 deletions(-)
create mode 100644 config/README
create mode 100755 config/argz-gen
create mode 100644 config/argz.c
diff --git a/config/README b/config/README
new file mode 100644
index 0000000..9e09cfd
--- /dev/null
+++ b/config/README
@@ -0,0 +1,31 @@
+f='
+append
+addsep
+ctsep
+insert
+next
+stringify
+count
+extract
+create
+delete
+replace
+'
+mkdir -p tmp
+glibc_dir=/mirror/d/glibc
+for i in $f; do cp $glibc_dir/string/argz-$i.c tmp; done
+
+: > tmp/config.h
+
+gcc -E -Itmp argz.c > argz.i
+
+./argz-gen > a-gen.c
+gcc -E -Itmp a-gen.c > a-gen.i
+
+perl -ni -e '/^#/ or print' a-gen.i argz.i
+
+perl -pe 's/__(restrict|const|argz_|st|mem)/$1/g;s/\s*__THROW//' \
+ $glibc_dir/string/argz.h \
+ > argz.in.h
+perl -ni -e \
+ '/^(#include <features\.h>|__(?:BEGIN|END)_DECLS)/ or print' argz.in.h
diff --git a/config/argz-gen b/config/argz-gen
new file mode 100755
index 0000000..17ed52c
--- /dev/null
+++ b/config/argz-gen
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+cat <<\EOF
+/* Functions for dealing with '\0' separated arg vectors.
+ Copyright (C) 1995-1998, 2000-2002, 2006, 2008 Free Software Foundation,
Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <config.h>
+
+#include <argz.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+EOF
+
+f='
+append
+addsep
+ctsep
+insert
+next
+stringify
+count
+extract
+create
+delete
+replace
+'
+d=/mirror/d/glibc
+for i in $f; do
+ perl -pe 's/__(argz_|st|mem)/$1/g' $d/string/argz-$i.c \
+ | perl -0x0 -pe 's,/\*(.|\n)+?\*/\n,,' \
+ | grep -vE '^(#include|INTDEF|weak_alias|libc_hidden_def)'
+done
diff --git a/config/argz.c b/config/argz.c
new file mode 100644
index 0000000..493499c
--- /dev/null
+++ b/config/argz.c
@@ -0,0 +1,41 @@
+#include <config.h>
+
+#undef weak_alias
+#define weak_alias(local, symbol) /* empty */
+#undef libc_hidden_def
+#define libc_hidden_def(symbol) /* empty */
+#undef INTDEF
+#define INTDEF(symbol) /* empty */
+
+#define __argz_add argz_add
+#define __argz_add_sep argz_add_sep
+#define __argz_append argz_append
+#define __argz_count argz_count
+#define __argz_create argz_create
+#define __argz_create_sep argz_create_sep
+#define __argz_extract argz_extract
+#define __argz_insert argz_insert
+#define __argz_next argz_next
+#define __argz_replace argz_replace
+#define __argz_stringify argz_stringify
+
+#undef __mempcpy
+#define __mempcpy mempcpy
+#undef __stpcpy
+#define __stpcpy stpcpy
+#undef __strndup
+#define __strndup strndup
+#undef __strnlen
+#define __strnlen strnlen
+
+#include "argz-append.c"
+#include "argz-addsep.c"
+#include "argz-ctsep.c"
+#include "argz-insert.c"
+#include "argz-next.c"
+#include "argz-stringify.c"
+#include "argz-count.c"
+#include "argz-extract.c"
+#include "argz-create.c"
+#include "argz-delete.c"
+#include "argz-replace.c"
diff --git a/config/srclist.txt b/config/srclist.txt
index ce4f9c5..0ef714d 100644
--- a/config/srclist.txt
+++ b/config/srclist.txt
@@ -230,6 +230,7 @@ $LIBCSRC/stdlib/strtoul.c lib gpl
#$LIBCSRC/sysdeps/unix/sysv/gethostname.c lib gpl
#$LIBCSRC/sysdeps/unix/utime.c lib gpl
-$LIBTOOL/libltdl/argz.c lib gpl
-$LIBTOOL/libltdl/argz_.h lib gpl
-$LIBTOOL/libltdl/m4/argz.m4 m4
+# Now derived from concatenation of separate .c files in glibc.
+#$LIBTOOL/libltdl/argz.c lib gpl
+#$LIBTOOL/libltdl/argz_.h lib gpl
+#$LIBTOOL/libltdl/m4/argz.m4 m4
diff --git a/lib/argz.c b/lib/argz.c
index f31ce17..8f5d1f5 100644
--- a/lib/argz.c
+++ b/lib/argz.c
@@ -1,254 +1,406 @@
-/* argz.c -- argz implementation for non-glibc systems
-
- Copyright (C) 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
- Written by Gary V. Vaughan, 2004
-
- NOTE: The canonical source of this file is maintained with the
- GNU Libtool package. Report bugs to address@hidden
-
-GNU Libltdl is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-As a special exception to the GNU Lesser General Public License,
-if you distribute this file as part of a program or library that
-is built using GNU Libtool, you may include this file under the
-same distribution terms that you use for the rest of that program.
-
-GNU Libltdl is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with GNU Libltdl; see the file COPYING.LIB. If not, a
-copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
-or obtained by writing to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-
-#if defined(LTDL) && defined LT_CONFIG_H
-# include LT_CONFIG_H
-#else
-# include <config.h>
-#endif
+/* Functions for dealing with '\0' separated arg vectors.
+ Copyright (C) 1995-1998, 2000-2002, 2006, 2008 Free Software Foundation,
Inc.
+ This file is part of the GNU C Library.
-#include <argz.h>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <sys/types.h>
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <config.h>
+
+#include <argz.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
-#define EOS_CHAR '\0'
+
+/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
+error_t
+argz_append (char **argz, size_t *argz_len, const char *buf, size_t buf_len)
+{
+ size_t new_argz_len = *argz_len + buf_len;
+ char *new_argz = realloc (*argz, new_argz_len);
+ if (new_argz)
+ {
+ memcpy (new_argz + *argz_len, buf, buf_len);
+ *argz = new_argz;
+ *argz_len = new_argz_len;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into
+ argz.c in libshouldbelibc. */
error_t
-argz_append (char **pargz, size_t *pargz_len, const char *buf, size_t buf_len)
+argz_add (char **argz, size_t *argz_len, const char *str)
{
- size_t argz_len;
- char *argz;
+ return argz_append (argz, argz_len, str, strlen (str) + 1);
+}
- assert (pargz);
- assert (pargz_len);
- assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
- /* If nothing needs to be appended, no more work is required. */
- if (buf_len == 0)
- return 0;
- /* Ensure there is enough room to append BUF_LEN. */
- argz_len = *pargz_len + buf_len;
- argz = (char *) realloc (*pargz, argz_len);
- if (!argz)
- return ENOMEM;
+error_t
+argz_add_sep (char **argz, size_t *argz_len, const char *string, int delim)
+{
+ size_t nlen = strlen (string) + 1;
+
+ if (nlen > 1)
+ {
+ const char *rp;
+ char *wp;
- /* Copy characters from BUF after terminating '\0' in ARGZ. */
- memcpy (argz + *pargz_len, buf, buf_len);
+ *argz = (char *) realloc (*argz, *argz_len + nlen);
+ if (*argz == NULL)
+ return ENOMEM;
- /* Assign new values. */
- *pargz = argz;
- *pargz_len = argz_len;
+ 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;
}
-/* Add a string to the argz vector. */
-error_t
-argz_add (char **pargz, size_t *pargz_len, const char *str)
-{
- return argz_append (pargz, pargz_len, str, strlen (str) + 1);
-}
-
error_t
-argz_create_sep (const char *str, int delim, char **pargz, size_t *pargz_len)
+argz_create_sep (const char *string, int delim, char **argz, size_t *len)
{
- size_t argz_len;
- char *argz = 0;
+ size_t nlen = strlen (string) + 1;
- assert (str);
- assert (pargz);
- assert (pargz_len);
-
- /* Make a copy of STR, but replacing each occurrence of
- DELIM with '\0'. */
- argz_len = 1+ strlen (str);
- if (argz_len)
+ if (nlen > 1)
{
- const char *p;
- char *q;
+ const char *rp;
+ char *wp;
- argz = (char *) malloc (argz_len);
- if (!argz)
+ *argz = (char *) malloc (nlen);
+ if (*argz == NULL)
return ENOMEM;
- for (p = str, q = argz; *p != EOS_CHAR; ++p)
+ rp = string;
+ wp = *argz;
+ do
+ if (*rp == delim)
+ {
+ if (wp > *argz && wp[-1] != '\0')
+ *wp++ = '\0';
+ else
+ --nlen;
+ }
+ else
+ *wp++ = *rp;
+ while (*rp++ != '\0');
+
+ if (nlen == 0)
{
- if (*p == delim)
- {
- /* Ignore leading delimiters, and fold consecutive
- delimiters in STR into a single '\0' in ARGZ. */
- if ((q > argz) && (q[-1] != EOS_CHAR))
- *q++ = EOS_CHAR;
- else
- --argz_len;
- }
- else
- *q++ = *p;
+ free (*argz);
+ *argz = NULL;
+ *len = 0;
}
- /* Copy terminating EOS_CHAR. */
- *q = *p;
- }
-
- /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */
- if (!argz_len)
- argz = (free (argz), (char *) 0);
- /* Assign new values. */
- *pargz = argz;
- *pargz_len = argz_len;
+ *len = nlen;
+ }
+ else
+ {
+ *argz = NULL;
+ *len = 0;
+ }
return 0;
}
+/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
+ existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
+ Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
+ ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
+ in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
+ ARGZ, ENOMEM is returned, else 0. */
error_t
-argz_insert (char **pargz, size_t *pargz_len, char *before, const char *entry)
+argz_insert (char **argz, size_t *argz_len, char *before, const char *entry)
{
- assert (pargz);
- assert (pargz_len);
- assert (entry && *entry);
+ if (! before)
+ return argz_add (argz, argz_len, entry);
- /* No BEFORE address indicates ENTRY should be inserted after the
- current last element. */
- if (!before)
- return argz_append (pargz, pargz_len, entry, 1+ strlen (entry));
+ if (before < *argz || before >= *argz + *argz_len)
+ return EINVAL;
- /* This probably indicates a programmer error, but to preserve
- semantics, scan back to the start of an entry if BEFORE points
- into the middle of it. */
- while ((before > *pargz) && (before[-1] != EOS_CHAR))
- --before;
+ if (before > *argz)
+ /* Make sure before is actually the beginning of an entry. */
+ while (before[-1])
+ before--;
{
- size_t entry_len = 1+ strlen (entry);
- size_t argz_len = *pargz_len + entry_len;
- size_t offset = before - *pargz;
- char *argz = (char *) realloc (*pargz, argz_len);
-
- if (!argz)
+ size_t after_before = *argz_len - (before - *argz);
+ size_t entry_len = strlen (entry) + 1;
+ size_t new_argz_len = *argz_len + entry_len;
+ char *new_argz = realloc (*argz, new_argz_len);
+
+ if (new_argz)
+ {
+ before = new_argz + (before - *argz);
+ memmove (before + entry_len, before, after_before);
+ memmove (before, entry, entry_len);
+ *argz = new_argz;
+ *argz_len = new_argz_len;
+ return 0;
+ }
+ else
return ENOMEM;
+ }
+}
- /* Make BEFORE point to the equivalent offset in ARGZ that it
- used to have in *PARGZ incase realloc() moved the block. */
- before = argz + offset;
- /* Move the ARGZ entries starting at BEFORE up into the new
- space at the end -- making room to copy ENTRY into the
- resulting gap. */
- memmove (before + entry_len, before, *pargz_len - offset);
- memcpy (before, entry, entry_len);
+char *
+argz_next (const char *argz, size_t argz_len, const char *entry)
+{
+ if (entry)
+ {
+ if (entry < argz + argz_len)
+ entry = strchr (entry, '\0') + 1;
- /* Assign new values. */
- *pargz = argz;
- *pargz_len = argz_len;
- }
+ return entry >= argz + argz_len ? NULL : (char *) entry;
+ }
+ else
+ if (argz_len > 0)
+ return (char *) argz;
+ else
+ return NULL;
+}
- return 0;
+
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+void
+argz_stringify (char *argz, size_t len, int sep)
+{
+ if (len > 0)
+ while (1)
+ {
+ size_t part_len = strnlen (argz, len);
+ argz += part_len;
+ len -= part_len;
+ if (len-- <= 1) /* includes final '\0' we want to stop at */
+ break;
+ *argz++ = sep;
+ }
}
-char *
-argz_next (char *argz, size_t argz_len, const char *entry)
+/* Returns the number of strings in ARGZ. */
+size_t
+argz_count (const char *argz, size_t len)
{
- assert ((argz && argz_len) || (!argz && !argz_len));
+ size_t count = 0;
+ while (len > 0)
+ {
+ size_t part_len = strlen(argz);
+ argz += part_len + 1;
+ len -= part_len + 1;
+ count++;
+ }
+ return count;
+}
- if (entry)
+
+/* 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)
+{
+ while (len > 0)
{
- /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address
- within the ARGZ vector. */
- assert ((!argz && !argz_len)
- || ((argz <= entry) && (entry < (argz + argz_len))));
-
- /* Move to the char immediately after the terminating
- '\0' of ENTRY. */
- entry = 1+ strchr (entry, EOS_CHAR);
-
- /* Return either the new ENTRY, or else NULL if ARGZ is
- exhausted. */
- return (entry >= argz + argz_len) ? 0 : (char *) entry;
+ size_t part_len = strlen (argz);
+ *argv++ = (char *) argz;
+ argz += part_len + 1;
+ len -= part_len + 1;
}
+ *argv = 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
{
- /* This should probably be flagged as a programmer error,
- since starting an argz_next loop with the iterator set
- to ARGZ is safer. To preserve semantics, handle the NULL
- case by returning the start of ARGZ (if any). */
- if (argz_len > 0)
- return argz;
- else
- return 0;
+ *argz = malloc (tlen);
+ if (*argz == NULL)
+ return ENOMEM;
+
+ for (p = *argz, ap = argv; *ap; ++ap, ++p)
+ p = stpcpy (p, *ap);
}
+ *len = tlen;
+
+ return 0;
}
+/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */
void
-argz_stringify (char *argz, size_t argz_len, int sep)
+argz_delete (char **argz, size_t *argz_len, char *entry)
{
- assert ((argz && argz_len) || (!argz && !argz_len));
-
- if (sep)
+ if (entry)
+ /* Get rid of the old value for NAME. */
{
- --argz_len; /* don't stringify the terminating EOS */
- while (--argz_len > 0)
+ size_t entry_len = strlen (entry) + 1;
+ *argz_len -= entry_len;
+ memmove (entry, entry + entry_len, *argz_len - (entry - *argz));
+ if (*argz_len == 0)
{
- if (argz[argz_len] == EOS_CHAR)
- argz[argz_len] = sep;
+ free (*argz);
+ *argz = 0;
}
}
}
-/* Count number of elements (null bytes) in argz vector. */
-
-size_t
-argz_count (const char *argz, size_t argz_len)
+/* 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 count = 0;
+ 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;
+ }
+}
- assert ((argz && argz_len) || (!argz && !argz_len));
+/* 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 *replace_count)
+{
+ error_t err = 0;
- while (argz_len > 0)
+ if (str && *str)
{
- size_t part_len = strlen (argz);
- argz += part_len + 1;
- argz_len -= part_len + 1;
- count++;
+ 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 count;
+ return err;
}
diff --git a/lib/argz.in.h b/lib/argz.in.h
index 40d5176..462537d 100644
--- a/lib/argz.in.h
+++ b/lib/argz.in.h
@@ -1,71 +1,184 @@
-/* lt__argz.h -- internal argz interface for non-glibc systems
-
- Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc.
- Written by Gary V. Vaughan, 2004
-
- NOTE: The canonical source of this file is maintained with the
- GNU Libtool package. Report bugs to address@hidden
-
-GNU Libltdl is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-As a special exception to the GNU Lesser General Public License,
-if you distribute this file as part of a program or library that
-is built using GNU Libtool, you may include this file under the
-same distribution terms that you use for the rest of that program.
-
-GNU Libltdl is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with GNU Libltdl; see the file COPYING.LIB. If not, a
-copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
-or obtained by writing to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+/* Routines for dealing with '\0' separated arg vectors.
+ Copyright (C) 1995,96,97,98,99,2000,2004,2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _ARGZ_H
+#define _ARGZ_H 1
-#if !defined(LT__ARGZ_H)
-#define LT__ARGZ_H 1
-#include <stdlib.h>
#define __need_error_t
#include <errno.h>
-#include <sys/types.h>
+#include <string.h> /* Need size_t, and strchr is called below. */
-#if defined(LTDL)
-# include "lt__glibc.h"
-# include "lt_system.h"
-#else
-# define LT_SCOPE
+#ifndef const
+# define const const
#endif
-#if defined(__cplusplus)
-extern "C" {
+#ifndef __error_t_defined
+typedef int error_t;
#endif
-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_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 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);
-LT_SCOPE size_t argz_count (const char *argz, size_t argz_len);
-
-#if defined(__cplusplus)
+
+
+/* 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. The result can be destroyed using free. */
+extern error_t argz_create (char *const __argv[], char **restrict __argz,
+ size_t *restrict __len);
+extern error_t argz_create (char *const __argv[], char **restrict __argz,
+ size_t *restrict __len);
+
+/* Make a '\0' separated arg vector from a SEP separated list in
+ STRING, returning it in ARGZ, and the total length in LEN. If a
+ memory allocation error occurs, ENOMEM is returned, otherwise 0.
+ The result can be destroyed using free. */
+extern error_t argz_create_sep (const char *restrict string,
+ int __sep, char **restrict __argz,
+ size_t *restrict __len);
+extern error_t argz_create_sep (const char *restrict string,
+ int __sep, char **restrict __argz,
+ size_t *restrict __len);
+
+/* Returns the number of strings in ARGZ. */
+extern size_t argz_count (const char *__argz, size_t __len)
+ __attribute_pure__;
+extern size_t argz_count (const char *__argz, size_t __len)
+ __attribute_pure__;
+
+/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
+ to hold them all. */
+extern void argz_extract (const char *restrict __argz, size_t __len,
+ char **restrict __argv);
+extern void argz_extract (const char *restrict __argz, size_t __len,
+ char **restrict __argv);
+
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+extern void argz_stringify (char *__argz, size_t __len, int __sep);
+extern void argz_stringify (char *__argz, size_t __len, int __sep);
+
+/* Append BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
+extern error_t argz_append (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict __buf, size_t _buf_len)
+;
+extern error_t argz_append (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict __buf, size_t __buf_len)
+;
+
+/* Append STR to the argz vector in ARGZ & ARGZ_LEN. */
+extern error_t argz_add (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict str);
+extern error_t argz_add (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict str);
+
+/* Append SEP separated list in STRING to the argz vector in ARGZ &
+ ARGZ_LEN. */
+extern error_t argz_add_sep (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict string, int __delim)
+;
+extern error_t argz_add_sep (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict string, int __delim)
+;
+
+/* Delete ENTRY from ARGZ & ARGZ_LEN, if it appears there. */
+extern void argz_delete (char **restrict __argz,
+ size_t *restrict argz_len,
+ char *restrict __entry);
+extern void argz_delete (char **restrict __argz,
+ size_t *restrict argz_len,
+ char *restrict __entry);
+
+/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
+ existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
+ Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
+ ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
+ in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
+ ARGZ, ENOMEM is returned, else 0. */
+extern error_t argz_insert (char **restrict __argz,
+ size_t *restrict argz_len,
+ char *restrict __before,
+ const char *restrict __entry);
+extern error_t argz_insert (char **restrict __argz,
+ size_t *restrict argz_len,
+ char *restrict __before,
+ const char *restrict __entry);
+
+/* 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. */
+extern error_t argz_replace (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict str,
+ const char *restrict __with,
+ unsigned int *restrict __replace_count);
+extern error_t argz_replace (char **restrict __argz,
+ size_t *restrict argz_len,
+ const char *restrict str,
+ const char *restrict __with,
+ unsigned int *restrict __replace_count);
+
+/* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there
+ are no more. If entry is NULL, then the first entry is returned. This
+ behavior allows two convenient iteration styles:
+
+ char *entry = 0;
+ while ((entry = argz_next (argz, argz_len, entry)))
+ ...;
+
+ or
+
+ char *entry;
+ for (entry = argz; entry; entry = argz_next (argz, argz_len, entry))
+ ...;
+*/
+extern char *argz_next (const char *restrict __argz, size_t argz_len,
+ const char *restrict __entry);
+extern char *argz_next (const char *restrict __argz, size_t argz_len,
+ const char *restrict __entry);
+
+#ifdef __USE_EXTERN_INLINES
+__extern_inline char *
+__NTH (argz_next (const char *__argz, size_t argz_len,
+ const char *__entry))
+{
+ if (__entry)
+ {
+ if (__entry < __argz + argz_len)
+ __entry = strchr (__entry, '\0') + 1;
+
+ return __entry >= __argz + argz_len ? (char *) NULL : (char *) __entry;
+ }
+ else
+ return argz_len > 0 ? (char *) __argz : 0;
}
-#endif
+__extern_inline char *
+__NTH (argz_next (const char *__argz, size_t argz_len,
+ const char *__entry))
+{
+ return argz_next (__argz, argz_len, __entry);
+}
+#endif /* Use extern inlines. */
-#if !defined(LTDL)
-# undef LT_SCOPE
-#endif
-#endif /*!defined(LT__ARGZ_H)*/
+#endif /* argz.h */
diff --git a/m4/argz.m4 b/m4/argz.m4
index 37c1b11..3992ab6 100644
--- a/m4/argz.m4
+++ b/m4/argz.m4
@@ -1,6 +1,6 @@
# Portability macros for glibc argz. -*- Autoconf -*-
#
-# Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan <address@hidden>
#
# This file is free software; the Free Software Foundation gives
@@ -12,6 +12,8 @@
AC_DEFUN([gl_FUNC_ARGZ],
[gl_PREREQ_ARGZ
+AC_REQUIRE([AC_C_RESTRICT])
+
AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT])
AC_CHECK_TYPES([error_t],
--
1.5.6.rc1.2.g5648b