Mon Apr 29 00:11:59 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
authorroland <roland>
Mon, 29 Apr 1996 05:14:16 +0000 (05:14 +0000)
committerroland <roland>
Mon, 29 Apr 1996 05:14:16 +0000 (05:14 +0000)
* string/envz.c, string/envz.h: New files.
* string/argz.h, string/argz-append.c, string/argz-count.c,
string/argz-create.c, string/argz-delete.c, string/argz-extract.c,
string/argz-insert.c, string/argz-stringify.c: New files.
* string/Makefile (routines): Add envz, argz-*.
(headers): Add argz.h, envz.h.

string/Makefile
string/argz-append.c [new file with mode: 0644]
string/argz-count.c [new file with mode: 0644]
string/argz-create.c [new file with mode: 0644]
string/argz-delete.c [new file with mode: 0644]
string/argz-extract.c [new file with mode: 0644]
string/argz-insert.c [new file with mode: 0644]
string/argz-stringify.c [new file with mode: 0644]
string/argz.h [new file with mode: 0644]
string/envz.c [new file with mode: 0644]
string/envz.h [new file with mode: 0644]

index 5901c36..d90bf6f 100644 (file)
@@ -21,7 +21,8 @@
 #
 subdir := string
 
 #
 subdir := string
 
-headers        := string.h strings.h memory.h endian.h bytesex.h
+headers        := string.h strings.h memory.h endian.h bytesex.h \
+          argz.h envz.h
 
 routines       := strcat strchr strcmp strcoll strcpy strcspn strdup   \
                   strerror _strerror strlen strnlen                    \
 
 routines       := strcat strchr strcmp strcoll strcpy strcspn strdup   \
                   strerror _strerror strlen strnlen                    \
@@ -31,7 +32,10 @@ routines     := strcat strchr strcmp strcoll strcpy strcspn strdup   \
                   bcopy bzero ffs stpcpy stpncpy                       \
                   strcasecmp strncase                                  \
                   memccpy memcpy wordcopy strsep                       \
                   bcopy bzero ffs stpcpy stpncpy                       \
                   strcasecmp strncase                                  \
                   memccpy memcpy wordcopy strsep                       \
-                  swab strfry memfrob memmem
+                  swab strfry memfrob memmem                           \
+                  $(addprefix argz-,append count create                \
+                                    delete extract insert stringify)   \
+                  envz
 
 tests          := tester testcopy test-ffs
 distribute     := memcopy.h pagecopy.h
 
 tests          := tester testcopy test-ffs
 distribute     := memcopy.h pagecopy.h
diff --git a/string/argz-append.c b/string/argz-append.c
new file mode 100644 (file)
index 0000000..e61e3ac
--- /dev/null
@@ -0,0 +1,50 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* 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;
+}
+weak_alias (__argz_append, argz_append)
+
+/* Add STR to the argz vector in ARGZ & ARGZ_LEN.  This should be moved into
+   argz.c in libshouldbelibc.  */
+error_t
+__argz_add (char **argz, size_t *argz_len, const char *str)
+{
+  return __argz_append (argz, argz_len, str, strlen (str) + 1);
+}
+weak_alias (__argz_add, argz_add)
diff --git a/string/argz-count.c b/string/argz-count.c
new file mode 100644 (file)
index 0000000..a10119b
--- /dev/null
@@ -0,0 +1,38 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <string.h>
+
+/* Returns the number of strings in ARGZ.  */
+size_t
+__argz_count (const char *argz, size_t 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;
+}
+weak_alias (__argz_count, argz_count)
diff --git a/string/argz-create.c b/string/argz-create.c
new file mode 100644 (file)
index 0000000..fab3222
--- /dev/null
@@ -0,0 +1,53 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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 **argv, char **argz, size_t *len)
+{
+  int argc;
+  size_t tlen = 0;
+  char *p, **ap;
+
+  for (argc = 0; argv[argc] != NULL; ++argc)
+    tlen += strlen (argv[argc]);
+
+  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;
+}
+weak_alias (__argz_create, argz_create)
diff --git a/string/argz-delete.c b/string/argz-delete.c
new file mode 100644 (file)
index 0000000..729b1b8
--- /dev/null
@@ -0,0 +1,41 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* 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;
+      memcpy (entry, entry + entry_len, *argz_len - (entry - *argz));
+      if (*argz_len == 0)
+       {
+         free (*argz);
+         *argz = 0;
+       }
+    }
+}
diff --git a/string/argz-extract.c b/string/argz-extract.c
new file mode 100644 (file)
index 0000000..5eb0e84
--- /dev/null
@@ -0,0 +1,36 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+
+/* Puts pointers to each string in ARGZ 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)
+    {
+      size_t part_len = strlen(argz);
+      *argv++ = argz;
+      argz += part_len + 1;
+      len -= part_len + 1;
+    }
+}
+weak_alias (__argz_extract, argz_extract)
diff --git a/string/argz-insert.c b/string/argz-insert.c
new file mode 100644 (file)
index 0000000..a110060
--- /dev/null
@@ -0,0 +1,64 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* 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 **argz, size_t *argz_len, char *before, const char *entry)
+{
+  if (! before)
+    return __argz_add (argz, argz_len, entry);
+
+  if (before < *argz || before >= *argz + *argz_len)
+    return EINVAL;
+
+  if (before > *argz)
+    /* Make sure before is actually the beginning of an entry.  */
+    while (before[-1])
+      before--;
+
+  {
+    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);
+       memcpy (before + entry_len, before, after_before);
+       memcpy (before, entry, entry_len);
+       *argz = new_argz;
+       *argz_len = new_argz_len;
+       return 0;
+      }
+    else
+      return ENOMEM;
+  }
+}
+weak_alias (__argz_insert, argz_insert)
diff --git a/string/argz-stringify.c b/string/argz-stringify.c
new file mode 100644 (file)
index 0000000..c7a109c
--- /dev/null
@@ -0,0 +1,38 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <string.h>
+
+/* 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)
+{
+  while (len > 0)
+    {
+      size_t part_len = strlen(argz);
+      argz += part_len;
+      len -= part_len + 1;
+      if (len > 0)
+       *argz++ = sep;
+    }
+}
+weak_alias (__argz_stringify, argz_stringify)
diff --git a/string/argz.h b/string/argz.h
new file mode 100644 (file)
index 0000000..9c03815
--- /dev/null
@@ -0,0 +1,100 @@
+/* Routines for dealing with '\0' separated arg vectors.
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __ARGZ_H__
+#define __ARGZ_H__     1
+#include <errno.h>             /* Define error_t.  */
+#include <string.h>            /* Need size_t, and strchr is called below.  */
+
+/* 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. */
+error_t __argz_create (char **argv, char **argz, size_t *len);
+error_t argz_create (char **argv, char **argz, size_t *len);
+
+/* Returns the number of strings in ARGZ.  */
+size_t __argz_count (const char *argz, size_t len);
+size_t argz_count (const char *argz, size_t len);
+
+/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
+   to hold them all.  */
+void __argz_extract (const char *argz, size_t len, char **argv);
+void argz_extract (const char *argz, size_t len, char **argv);
+
+/* 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);
+void argz_stringify (char *argz, size_t len, int sep);
+
+/* Append 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);
+error_t argz_append (char **argz, size_t *argz_len,
+                    const char *buf, size_t buf_len);
+
+/* Append STR to the argz vector in ARGZ & ARGZ_LEN.  */
+error_t __argz_add (char **argz, size_t *argz_len, const char *str);
+error_t argz_add (char **argz, size_t *argz_len, const char *str);
+
+/* Delete ENTRY from ARGZ & ARGZ_LEN, if it appears there.  */
+void __argz_delete (char **argz, size_t *argz_len, char *entry);
+void argz_delete (char **argz, size_t *argz_len, char *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.  */
+error_t __argz_insert (char **argz, size_t *argz_len,
+                      char *before, const char *entry);
+error_t argz_insert (char **argz, size_t *argz_len,
+                    char *before, const char *entry);
+\f
+/* 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 inline char *
+argz_next (char *argz, size_t argz_len, const char *entry)
+{
+  if (entry)
+    if (entry >= argz + argz_len)
+      return 0;
+    else
+      return strchr (entry, '\0') + 1;
+  else
+    if (argz_len > 0)
+      return argz;
+    else
+      return 0;
+}
+
+#endif /* __ARGZ_H__ */
diff --git a/string/envz.c b/string/envz.c
new file mode 100644 (file)
index 0000000..4d0816e
--- /dev/null
@@ -0,0 +1,171 @@
+/* Routines for dealing with '\0' separated environment vectors
+
+   Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <malloc.h>
+#include <string.h>
+
+#include "envz.h"
+
+/* The character separating names from values in an envz.  */
+#define SEP '='
+\f
+/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none.
+   If NAME contains the separator character, only the portion before it is
+   used in the comparison.  */
+char *
+envz_entry (char *envz, unsigned envz_len, char *name)
+{
+  while (envz_len)
+    {
+      char *p = name;
+      char *entry = envz;      /* Start of this entry. */
+
+      /* See how far NAME and ENTRY match.  */
+      while (envz_len && *p == *envz && *p && *p != SEP)
+       p++, envz++, envz_len--;
+
+      if ((*envz == '\0' || *envz == SEP) && (*p == '\0' || *p == SEP))
+       /* Bingo! */
+       return entry;
+
+      /* No match, skip to the next entry.  */
+      while (envz_len && *envz)
+       envz++, envz_len--;
+      if (envz_len)
+       envz++, envz_len--;     /* skip '\0' */
+    }
+
+  return 0;
+}
+
+/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
+   if there is none.  */
+char *
+envz_get (char *envz, unsigned envz_len, char *name)
+{
+  char *entry = envz_entry (envz, envz_len, name);
+  if (entry)
+    {
+      while (*entry && *entry != SEP)
+       entry++;
+      if (*entry)
+       entry++;
+      else
+       entry = 0;              /* A null entry.  */
+    }
+  return entry;
+}
+\f
+/* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any.  */
+void
+envz_remove (char **envz, unsigned *envz_len, char *name)
+{
+  char *entry = envz_entry (*envz, *envz_len, name);
+  if (entry)
+    argz_delete (envz, envz_len, entry);
+}
+
+/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN.  If an entry
+   with the same name already exists in ENVZ, it is removed.  If VALUE is
+   NULL, then the new entry will a special null one, for which envz_get will
+   return NULL, although envz_entry will still return an entry; this is handy
+   because when merging with another envz, the null entry can override an
+   entry in the other one.  Null entries can be removed with envz_strip ().  */
+error_t
+envz_add (char **envz, unsigned *envz_len, char *name, char *value)
+{
+  envz_remove (envz, envz_len, name);
+
+  if (value)
+    /* Add the new value, if there is one.  */
+    {
+      unsigned name_len = strlen (name);
+      unsigned value_len = strlen (value);
+      unsigned old_envz_len = *envz_len;
+      unsigned new_envz_len = old_envz_len + name_len + 1 + value_len + 1;
+      char *new_envz = realloc (*envz, new_envz_len);
+
+      if (new_envz)
+       {
+         bcopy (name, new_envz + old_envz_len, name_len);
+         new_envz[old_envz_len + name_len] = SEP;
+         bcopy (value, new_envz + old_envz_len + name_len + 1, value_len);
+         new_envz[new_envz_len - 1] = 0;
+
+         *envz = new_envz;
+         *envz_len = new_envz_len;
+
+         return 0;
+       }
+      else
+       return ENOMEM;
+    }
+  else
+    /* Add a null entry.  */
+    return argz_add (envz, envz_len, name);
+}
+\f
+/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add().  If
+   OVERRIDE is true, then values in ENVZ2 will supercede those with the same
+   name in ENV, otherwise not.  */
+error_t
+envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
+           int override)
+{
+  error_t err = 0;
+
+  while (envz2_len && ! err)
+    {
+      char *old = envz_entry (*envz, *envz_len, envz2);
+      size_t new_len = strlen (envz2) + 1;
+
+      if (! old)
+       err = argz_append (envz, envz_len, envz2, new_len);
+      else if (override)
+       {
+         argz_delete (envz, envz_len, old);
+         err = argz_append (envz, envz_len, envz2, new_len);
+       }
+
+      envz2 += new_len;
+      envz2_len -= new_len;
+    }
+
+  return err;
+}
+
+/* Remove null entries.  */
+void
+envz_strip (char **envz, unsigned *envz_len)
+{
+  char *entry = *envz;
+  unsigned left = *envz_len;
+  while (left)
+    {
+      unsigned entry_len = strlen (entry) + 1;
+      left -= entry_len;
+      if (! index (entry, SEP))
+       /* Null entry. */
+       bcopy (entry, entry + entry_len, left);
+      else
+       entry += entry_len;
+    }
+  *envz_len = entry - *envz;
+}
diff --git a/string/envz.h b/string/envz.h
new file mode 100644 (file)
index 0000000..55224c7
--- /dev/null
@@ -0,0 +1,55 @@
+/* Routines for dealing with '\0' separated environment vectors
+
+   Copyright (C) 1995 Free Software Foundation, Inc.
+
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __ENVZ_H__
+#define __ENVZ_H__
+
+#include <errno.h>
+
+/* Envz's are argz's too, and should be created etc., using the same
+   routines.  */
+#include <argz.h>
+
+/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none.  */
+char *envz_entry (char *envz, unsigned envz_len, char *name);
+
+/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
+   if there is none.  */
+char *envz_get (char *envz, unsigned envz_len, char *name);
+
+/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN.  If an entry
+   with the same name already exists in ENVZ, it is removed.  If VALUE is
+   NULL, then the new entry will a special null one, for which envz_get will
+   return NULL, although envz_entry will still return an entry; this is handy
+   because when merging with another envz, the null entry can override an
+   entry in the other one.  Null entries can be removed with envz_strip ().  */
+error_t envz_add (char **envz, unsigned *envz_len, char *name, char *value);
+
+/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add().  If
+   OVERRIDE is true, then values in ENVZ2 will supercede those with the same
+   name in ENV, otherwise not.  */
+error_t
+envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
+           int override);
+
+/* Remove null entries.  */
+void envz_strip (char **envz, unsigned *envz_len);
+
+#endif /* __ENVZ_H__ */