bug-libtool
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]