www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2008/05/03/14:19:03

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
X-Recipient: djgpp-workers AT delorie DOT com
X-Authenticated: #27081556
X-Provags-ID: V01U2FsdGVkX1/N1clXzh/NdYq+9gEqBYadsdBJkod9b06ddkVvae
7x4sZ/YRVyPu8s
From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
To: djgpp-workers AT delorie DOT com
Subject: Implementation of argz family of functions.
Date: Sat, 3 May 2008 20:20:02 +0200
User-Agent: KMail/1.9.5
MIME-Version: 1.0
Message-Id: <200805032020.02734.juan.guerrero@gmx.de>
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

Here is a patch to implement the argz family of functions.  The primary reason
for this is to make porting easier.  Some attention must be payed to the
implementation of the new variable type error_t.  It is defined in the usual
way in sys/djtypes.h and I have made it available in error.h by inclusion of
djtypes.h.  glibc and cygwin, both make error_t available in error.h.  If this
is not wanted or an other way to solve this issue is prefered, please let me
know.  There is also a test program.  I have placed the new file in the new
directory src/libc/compat/argz/ and the test program in the new directory
tests/libc/compat/argz/.  If something different is prefered let me know.

Suggestions, objections, comments are welcome.


Regards,
Juan M. Guerrero



2008-04-27  Juan Manuel Guerrero  <juan DOT guerrero AT gmx DOT de>
	Diffs against djgpp CVS head of 2008-04-25.


	* include/argz.h: New file.  Declaration of functions.

	* include/errno.h: Make error_t available.

	* include/sys/djtypes.h: Define error_t.

	* src/libc/compat/argz/add.c: Implementation of argz_add.

	* src/libc/compat/argz/add.txh: Documentation of argz_add.

	* src/libc/compat/argz/add_sep.c: Implementation of argz_add_sep.

	* src/libc/compat/argz/add_sep.txh: Documentation of argz_add_sep.

	* src/libc/compat/argz/append.c: Implementation of argz_append.

	* src/libc/compat/argz/append.txh: Documentation of argz_append.

	* src/libc/compat/argz/count.c: Implementation of argz_count.

	* src/libc/compat/argz/count.txh: Documentation of argz_count.

	* src/libc/compat/argz/create.c: Implementation of argz_create.

	* src/libc/compat/argz/create.txh: Documentation of argz_create.

	* src/libc/compat/argz/creatsep.c: Implementation of argz_creatsep.

	* src/libc/compat/argz/creatsep.txh: Documentation of argz_creatsep.

	* src/libc/compat/argz/delete.c: Implementation of argz_delete.

	* src/libc/compat/argz/delete.txh: Documentation of argz_delete.

	* src/libc/compat/argz/extract.c: Implementation of argz_extract.

	* src/libc/compat/argz/extract.txh: Documentation of argz_extract.

	* src/libc/compat/argz/insert.c: Implementation of argz_insert.

	* src/libc/compat/argz/insert.txh: Documentation of argz_insert.

	* src/libc/compat/argz/next.c: Implementation of argz_next.

	* src/libc/compat/argz/next.txh: Documentation of argz_next.

	* src/libc/compat/argz/replace.c: Implementation of argz_replace.

	* src/libc/compat/argz/replace.txh: Documentation of argz_replace.

	* src/libc/compat/argz/strngify.c: Implementation of argz_strngify.

	* src/libc/compat/argz/strngify.txh: Documentation of argz_strngify.

	* src/libc/compat/argz/makefile: Initial version.

	* src/docs/kb/wc204.txi: Info about argz family of functions added.

	* tests/libc/compat/argz/argztest.c: New file.  Implements tests for
	argz family of functions.







diff -aprNU3 djgpp.orig/include/argz.h djgpp/include/argz.h
--- djgpp.orig/include/argz.h	1970-01-01 00:00:00 +0000
+++ djgpp/include/argz.h	2008-05-03 19:53:02 +0000
@@ -0,0 +1,52 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+
+#ifndef __dj_include_argz_h_
+#define __dj_include_argz_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __dj_ENFORCE_ANSI_FREESTANDING
+
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
+  || !defined(__STRICT_ANSI__)
+
+#endif /* (__STDC_VERSION__ >= 199901L) || !__STRICT_ANSI__ */
+
+#ifndef __STRICT_ANSI__
+
+#ifndef _POSIX_SOURCE
+
+#include <errno.h>
+
+#ifndef _SIZE_T
+__DJ_size_t
+#define _SIZE_T
+#endif
+
+error_t  argz_add(char **_argz, size_t *_argz_len, const char *_str);
+error_t  argz_add_sep(char **_argz, size_t *_argz_len, const char *_str, int _sep);
+error_t  argz_append(char **_argz, size_t *_argz_len, const char *_buf, size_t _buf_len);
+size_t   argz_count(const char *_argz, size_t _argz_len);
+error_t  argz_create(char *const _argv[], char **_argz, size_t *_argz_len);
+error_t  argz_create_sep(const char *_str, int _sep, char **_argz, size_t *_argz_len);
+void     argz_delete(char **_argz, size_t *_argz_len, char *_entry);
+void     argz_extract(const char *_argz, size_t _argz_len, char **_argv);
+error_t  argz_insert(char **_argz, size_t *_argz_len, char *_before, const char *_entry);
+char    *argz_next(const char *_argz, size_t _argz_len, const char *_entry);
+error_t  argz_replace(char **_argz, size_t *_argz_len, const char *_str, const char *_with, unsigned *_replace_count);
+void     argz_stringify(char *_argz, size_t _argz_len, int _sep);
+
+#endif /* !_POSIX_SOURCE */
+#endif /* !__STRICT_ANSI__ */
+#endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
+
+#ifndef __dj_ENFORCE_FUNCTION_CALLS
+#endif /* !__dj_ENFORCE_FUNCTION_CALLS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__dj_include__h_ */
diff -aprNU3 djgpp.orig/include/errno.h djgpp/include/errno.h
--- djgpp.orig/include/errno.h	2003-02-04 20:17:16 +0000
+++ djgpp/include/errno.h	2008-05-03 19:53:02 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
@@ -75,6 +76,13 @@ extern const char *	__sys_errlist[];
 extern int		__sys_nerr;
 extern int		_doserrno;
 
+#include <sys/djtypes.h>
+
+#ifndef _ERROR_T
+__DJ_error_t
+#define _ERROR_T
+#endif
+
 #endif /* !_POSIX_SOURCE */
 #endif /* !__STRICT_ANSI__ */
 #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
diff -aprNU3 djgpp.orig/include/sys/djtypes.h djgpp/include/sys/djtypes.h
--- djgpp.orig/include/sys/djtypes.h	2007-12-11 07:48:42 +0000
+++ djgpp/include/sys/djtypes.h	2008-05-03 19:53:02 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
@@ -9,6 +10,7 @@
 #define __DJ_sys_djtypes_h_
 
 #define __DJ_clock_t	typedef int clock_t;
+#define __DJ_error_t	typedef int error_t;
 #define __DJ_gid_t	typedef int gid_t;
 #define __DJ_off_t	typedef int off_t;
 #define __DJ_off64_t	__extension__ typedef long long off64_t;
diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi	2008-05-03 19:39:32 +0000
+++ djgpp/src/docs/kb/wc204.txi	2008-05-03 19:53:02 +0000
@@ -1147,3 +1147,17 @@ family of functions.
 @findex strndup AT r{, added to the library}
 @findex strnlen AT r{, added to the library}
 GNU compatibility functions @code{strndup} and @code{strnlen} were added.
+
+@findex add AT r{, added to the library}
+@findex add_sep AT r{, added to the library}
+@findex append AT r{, added to the library}
+@findex count AT r{, added to the library}
+@findex create AT r{, added to the library}
+@findex create_sep AT r{, added to the library}
+@findex delete AT r{, added to the library}
+@findex extract AT r{, added to the library}
+@findex insert AT r{, added to the library}
+@findex next AT r{, added to the library}
+@findex replace AT r{, added to the library}
+@findex stringify AT r{, added to the library}
+New GNU glibc compatibility @code{argz} family of functions were added.
diff -aprNU3 djgpp.orig/src/libc/compat/argz/add.c djgpp/src/libc/compat/argz/add.c
--- djgpp.orig/src/libc/compat/argz/add.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/add.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,16 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <string.h>
+
+
+error_t
+argz_add(char **argz, size_t *argz_len, const char *str)
+{
+  /*
+   *  Add STR to the end of the argz vector in ARGZ of length ARGZ_LEN.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  return argz_append(argz, argz_len, str, strlen(str) + 1);
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/add.txh djgpp/src/libc/compat/argz/add.txh
--- djgpp.orig/src/libc/compat/argz/add.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/add.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,46 @@
+@node argz_add, string
+@findex argz_add
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_add(char **@var{argz}, size_t *@var{argz_len}, const char *@var{str})
+@end example
+
+@subheading Description
+
+Adds the string @var{str} to the end of the argz vector @var{argz} of length @var{argz_len}.
+If the string @var{str} was successfully added then the length @var{argz_len} will be increased
+accordingly.  Because the function modifies the argz vector, both its length @var{argz_len} and
+@var{argz} itself must be passed as pointers.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *str = "foobar";  /*  String to be added to argz.  */
+error_t error;
+
+error = argz_add(&argz, &argz_len, str);
+
+if (error)
+@{
+  printf("error: String %s could not be added to argz.\n", str);
+  exit(ENOMEM);
+@}
+else
+@{
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/add_sep.c djgpp/src/libc/compat/argz/add_sep.c
--- djgpp.orig/src/libc/compat/argz/add_sep.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/add_sep.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,36 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+error_t
+argz_add_sep(char **argz, size_t *argz_len, const char *str, int sep)
+{
+  /*
+   *  Add SEP separated list in STR to the end of the argz vector
+   *  in ARGZ with length ARGZ_LEN adjusted accordingly.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  char *str_argz = NULL;
+  size_t str_argz_len = 0;
+
+
+  argz_create_sep(str, sep, &str_argz, &str_argz_len);
+
+  if (str_argz_len)
+  {
+    size_t new_argz_len = *argz_len + str_argz_len;
+
+    *argz = realloc(*argz, new_argz_len);
+    if (*argz == NULL)
+      return ENOMEM;
+
+    memcpy(*argz + *argz_len, str_argz, str_argz_len);
+    *argz_len = new_argz_len;
+  }
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/add_sep.txh djgpp/src/libc/compat/argz/add_sep.txh
--- djgpp.orig/src/libc/compat/argz/add_sep.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/add_sep.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,50 @@
+@node argz_add_sep, string
+@findex argz_add_sep
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_add_sep(char **@var{argz}, size_t *@var{argz_len}, const char *@var{str},
+                     int @var{sep})
+@end example
+
+@subheading Description
+
+Adds the string @var{str} to the end of the argz vector @var{argz} of length @var{argz_len}.
+For every occurence of the delimiter @var{sep} in @var{str}, the delimiter is replaced by
+the @code{NUL} byte as separating token.  If the string @var{str} was successfully added
+then the length @var{argz_len} will be increased accordingly.  Because the function modifies
+the argz vector, both its length @var{argz_len} and itself @var{argz} must be passed as pointers.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *str = "foo:bar:foo";  /*  String to be added to argz.  */
+int delimiter = ':';  /*  Separator token.  Every ':' in str  */
+                      /*  will be replaced with '\0'.  */
+error_t error;
+
+error = argz_add_sep(&argz, &argz_len, str, delimiter);
+
+if (error)
+@{
+  printf("error: String %s could not be added to argz.\n", str);
+  exit(ENOMEM);
+@}
+else
+@{
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/append.c djgpp/src/libc/compat/argz/append.c
--- djgpp.orig/src/libc/compat/argz/append.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/append.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,33 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+error_t
+argz_append(char **argz, size_t *argz_len, const char *buf, size_t buf_len)
+{
+  /*
+   *  Append BUF, of length BUF_LEN to the argz vector in ARGZ
+   *  of length ARGZ_LEN.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  if (buf_len)
+  {
+    char *new_argz;
+    size_t new_argz_len;
+
+    new_argz_len = *argz_len + buf_len;
+    new_argz = realloc(*argz, new_argz_len);
+    if (new_argz == NULL)
+      return ENOMEM;
+
+    memcpy(new_argz + *argz_len, buf, buf_len);
+    *argz = new_argz;
+    *argz_len = new_argz_len;
+  }
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/argz.txh djgpp/src/libc/compat/argz/argz.txh
--- djgpp.orig/src/libc/compat/argz/argz.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/argz.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,24 @@
+@node argz functions, string
+@cindex argz functions
+
+@subheading Description
+
+These functions are glibc-specific and a GNU extension, so handle with care.
+
+An argz vector is a pointer to a character buffer together with a length.  The
+intended interpretation of the character buffer is array of strings, where the
+strings are separated by @code{NUL} bytes.  If the length is nonzero, the last
+byte of the buffer must be a @code{NUL} byte.  These functions are for handling
+argz vectors.  The pair (@code{NULL}, 0) is an argz  vector, and, conversely,
+argz vectors of length 0 must have @code{NULL} pointer.  Allocation of nonempty
+argz vectors is done using malloc, so that free can be used to dispose of them
+again.
+
+Argz vectors without final @code{NUL} may lead to Segmentation Faults.
+
+
+@subheading Return Value
+
+All argz functions that do memory allocation have a return type of @code{error_t},
+and return 0 for success, and ENOMEM if an allocation error occurs.
+
diff -aprNU3 djgpp.orig/src/libc/compat/argz/count.c djgpp/src/libc/compat/argz/count.c
--- djgpp.orig/src/libc/compat/argz/count.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/count.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,22 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+
+#define EOS  '\0'
+
+
+size_t
+argz_count(const char *argz, size_t argz_len)
+{
+  /*
+   *  Return the number of strings in ARGZ.
+   */
+
+  size_t counts, i;
+
+
+  for (counts = i = 0; i < argz_len; i++)
+    if (argz[i] == EOS)
+      counts++;
+
+  return counts;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/count.c.jmg djgpp/src/libc/compat/argz/count.c.jmg
--- djgpp.orig/src/libc/compat/argz/count.c.jmg	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/count.c.jmg	2008-05-03 19:53:02 +0000
@@ -0,0 +1,25 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+
+#define EOS  '\0'
+
+
+size_t
+argz_count(const char *argz, size_t argz_len)
+{
+  /*
+   *  Return the number of strings in ARGZ.
+   *  Version, die erlaubt dass angehaengter string nicht mit '\0' enden muss.  JMG.
+   */
+
+  size_t counts, i;
+
+
+  for (counts = i = 0; i < argz_len; i++)
+    if (argz[i] == EOS)
+      counts++;
+  if (argz[argz_len - 1] != EOS)
+    counts++;  /*  A not '\0' terminated string.  */
+
+  return counts;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/count.txh djgpp/src/libc/compat/argz/count.txh
--- djgpp.orig/src/libc/compat/argz/count.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/count.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,32 @@
+@node argz_count, string
+@findex argz_count
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+size_t argz_count(const char *@var{argz}, size_t @var{argz_len})
+@end example
+
+@subheading Description
+
+Counts the number of strings contained in the argz vector @var{argz} of length @var{argz_len}.
+Every string must be terminated with a @code{NUL} byte to be counted.
+
+@subheading Return Value
+
+The number of strings.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+size_t entries;
+
+entries = argz_count(argz, argz_len);
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/create.c djgpp/src/libc/compat/argz/create.c
--- djgpp.orig/src/libc/compat/argz/create.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/create.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,36 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+error_t
+argz_create(char *const argv[], char **argz, size_t *argz_len)
+{
+  /*
+   *  Make a '\0' separated argz vector from a ARGV vector,
+   *  returning it via ARGZ, and the total length in ARGZ_LEN.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  *argz_len = 0;
+  if (*argv == NULL)
+    *argz = NULL;
+  else
+  {
+    unsigned int argc, i;
+    char *p;
+
+    for (argc = 0; argv[argc]; argc++)
+      *argz_len += (strlen(argv[argc]) + 1);
+    *argz = malloc(*argz_len);
+    if (*argz == NULL)
+      return ENOMEM;
+
+    for (p = *argz, i = 0; i < argc; i++, p++)
+      p = stpcpy(p, argv[i]);
+  }
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/create.txh djgpp/src/libc/compat/argz/create.txh
--- djgpp.orig/src/libc/compat/argz/create.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/create.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,55 @@
+@node argz_create, string
+@findex argz_create
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_create(char *const @var{argv}[], char **@var{argz}, size_t *@var{argz_len})
+@end example
+
+@subheading Description
+
+Makes a @code{NUL} byte separated argz vector from a string array @var{argv},
+returning it via the pointer **@var{argz} and the total length via the pointer
+*@var{argz_len}.  The string array @var{argv} must be a Unix-style argument
+vector @code{argv} (a vector of pointers to normal C strings, terminated by @code{NULL}).
+Because the function modifies the argz vector, both its length @var{argz_len} and @var{argz}
+itself must be passed as pointers.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *const _argv[] = @{
+  "foo",
+  "bar",
+  NULL
+@};
+char *argz;  /*  Buffer will be allocated by argz_create.  */
+size_t argz_len;
+error_t error;
+
+
+error = argz_create(_argv, &argz, &argz_len);
+
+if (error)
+@{
+  printf("error: argz vector could not be created.\n");
+  exit(error);
+@}
+else
+@{
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/creatsep.c djgpp/src/libc/compat/argz/creatsep.c
--- djgpp.orig/src/libc/compat/argz/creatsep.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/creatsep.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,38 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EOS '\0'
+
+
+error_t
+argz_create_sep(const char *str, int sep, char **argz, size_t *argz_len)
+{
+  /*
+   *  Make a '\0' separated argz vector from a SEP separated list in
+   *  STR, returning it via ARGZ, and the total length in ARGZ_LEN.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  if (!str || str[0] == EOS)
+  {
+    *argz_len = 0;
+    *argz= NULL;
+  }
+  else
+  {
+    size_t i;
+
+    *argz_len = strlen(str) + 1;
+    *argz = malloc(*argz_len);
+    if (*argz == NULL)
+      return ENOMEM;
+
+    for (i = 0; i < *argz_len; i++)
+      (*argz)[i] = (str[i] == sep) ? EOS : str[i];
+  }
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/creatsep.c.jmg djgpp/src/libc/compat/argz/creatsep.c.jmg
--- djgpp.orig/src/libc/compat/argz/creatsep.c.jmg	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/creatsep.c.jmg	2008-05-03 19:53:02 +0000
@@ -0,0 +1,42 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EOS '\0'
+
+
+error_t
+argz_create_sep(const char *str, int sep, char **argz, size_t *argz_len)
+{
+  /*
+   *  Make a '\0' separated arg vector from a SEP separated list in
+   *  STR, returning it via ARGZ, and the total length in ARGZ_LEN.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   *  Version mit selber Anzahl von Zeichen.  JMG.
+   */
+
+  if (!str || str[0] == EOS)
+  {
+    *argz_len = 0;
+    *argz= NULL;
+  }
+  else
+  {
+    size_t i;
+
+    *argz_len = strlen(str) - 1;
+    if (str[*argz_len] != sep)
+      (*argz_len)++;
+    *argz = malloc(*argz_len);
+    if (*argz == NULL)
+      return ENOMEM;
+
+    (*argz_len)++;  /*  Count the trailing '\0' too.  */
+    for (i = 0; i < *argz_len; i++)
+      (*argz)[i] = (str[i] == sep) ? EOS : str[i];
+  }
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/creatsep.txh djgpp/src/libc/compat/argz/creatsep.txh
--- djgpp.orig/src/libc/compat/argz/creatsep.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/creatsep.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,51 @@
+@node argz_create_sep, string
+@findex argz_create_sep
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_create_sep(const char *@var{str}, int @var{sep}, char **@var{argz},
+                        size_t *@var{argz_len})
+@end example
+
+@subheading Description
+
+Makes a @code{NUL} byte separated argz vector from a @var{sep} separated list in
+@var{str}, returning it via the pointer **@var{argz} and the total length via the pointer
+*@var{argz_len}.  Because the function modifies the argz vector, both its length @var{argz_len}
+and @var{argz} itself must be passed as pointers.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *path = "c:\\foo;c:\\bar;c:\\temp";
+int path_sep = ';';
+char *argz;  /*  Buffer will be allocated by argz_create_sep.  */
+size_t argz_len;
+error_t error;
+
+
+error = argz_create_sep(path, path_sep, &argz, &argz_len);
+
+if (error)
+@{
+  printf("error: argz vector could not be created.\n");
+  exit(error);
+@}
+else
+@{
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/delete.c djgpp/src/libc/compat/argz/delete.c
--- djgpp.orig/src/libc/compat/argz/delete.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/delete.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,27 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+void
+argz_delete(char **argz, size_t *argz_len, char *entry)
+{
+  /*
+   *  Delete ENTRY from the argz vector in ARGZ
+   *  adjusting its length ARGZ_LEN accordingly.
+   */
+
+  if (entry)
+  {
+    size_t entry_len = strlen(entry) + 1;
+
+    *argz_len -= entry_len;
+    memmove(entry, entry + entry_len, *argz_len - (entry - *argz));
+    if (*argz_len == 0)
+    {
+      free(*argz);
+      *argz = NULL;
+    }
+  }
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/delete.txh djgpp/src/libc/compat/argz/delete.txh
--- djgpp.orig/src/libc/compat/argz/delete.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/delete.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,32 @@
+@node argz_delete, string
+@findex argz_delete
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+void argz_delete(char **@var{argz}, size_t *@var{argz_len}, char *@var{entry})
+@end example
+
+@subheading Description
+
+Deletes the string @var{entry} from the argz vector in @var{argz} adjusting its
+length @var{argz_len} accordingly.  Because the function modifies the argz
+vector, both its length @var{argz_len} and @var{argz} itself must be passed as
+pointers.
+
+@subheading Return Value
+
+Nothing.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+argz_delete(&argz, &argz_len, "FOOBAR");
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/extract.c djgpp/src/libc/compat/argz/extract.c
--- djgpp.orig/src/libc/compat/argz/extract.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/extract.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,35 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <libc/unconst.h>
+
+#define EOS  '\0'
+
+
+void
+argz_extract(const char *argz, size_t argz_len, char **argv)
+{
+  /*
+   *  Store pointers to each string in ARGZ, plus a terminating 0 element,
+   *  into the argv array ARGV, which must be large enough to hold them all.
+   */
+
+  const size_t counts = argz_count(argz, argz_len);
+  size_t i;
+
+
+
+  if (counts == argz_len)
+    for (i = 0; i < counts; i++)
+      argv[i] = unconst(&argz[i], char *);
+  else if (counts > 1)
+  {
+    size_t j = counts - 1;
+
+    for (i = argz_len - 2; i; i--)
+      if (argz[i] == EOS)
+        argv[j--] = unconst(&argz[i + 1], char *);
+    argv[0] = unconst(&argz[0], char *);
+  }
+  argv[counts] = NULL;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/extract.txh djgpp/src/libc/compat/argz/extract.txh
--- djgpp.orig/src/libc/compat/argz/extract.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/extract.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,56 @@
+@node argz_extract, string
+@findex argz_extract
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_extract(char *@var{argz}, size_t @var{argz_len}, char **@var{argv})
+@end example
+
+@subheading Description
+Converts the @code{NUL} byte separated argz vector @var{argz} of length @var{argz_len}
+into a Unix-style argument vector @var{argv} (a vector of pointers to normal
+C strings, terminated by @code{NULL}) by storing the pointers to every string in
+@var{argz} in @var{argv}.  The user must supply a @var{argv} large enough to contain
+all pointers and the terminating @code{NULL} pointer.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char **_argv;  /*  Unix-style argument vector.  */
+size_t entries;
+error_t error;
+
+entries = argz_count(argz, argz_len);  /*  Get number of strings  */
+                                       /*  contained in argz.  */
+_argv = malloc((entries + 1) * sizeof(char *));  /* One entry more for */
+                                                 /* the terminating NULL. */
+error = argz_extract(argz, argz_len, _argv);
+
+if (error)
+@{
+  printf("error: Strings could not be extracted from argz.\n", str);
+  free(_argv);
+  exit(ENOMEM);
+@}
+else
+@{
+  size_t i;
+
+  for (i = 0; _argv[i]; i++)
+    printf("argv[%zi] = \"%s\"\n", i, _argv[i]);
+
+  free(_argv);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/insert.c djgpp/src/libc/compat/argz/insert.c
--- djgpp.orig/src/libc/compat/argz/insert.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/insert.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,44 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+
+error_t
+argz_insert(char **argz, size_t *argz_len, char *before, const char *entry)
+{
+  /*
+   *  Insert ENTRY into ARGZ of length 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.
+   */
+
+  ptrdiff_t first_part_len;
+  size_t entry_len;
+
+
+  if (before == NULL)
+    return argz_add(argz, argz_len, entry);
+
+  if (before < *argz || before >= *argz + *argz_len)
+    return EINVAL;
+
+  for (; before != *argz && before[-1]; before--)
+    ;  /*  Make sure before is actually the beginning of an entry.  */
+
+  first_part_len = before - *argz;
+  entry_len = strlen(entry) + 1;
+  *argz = realloc(*argz, *argz_len + entry_len);
+  if (*argz == NULL)
+    return ENOMEM;
+
+  memmove(*argz + first_part_len + entry_len, *argz + first_part_len,  *argz_len - first_part_len);
+  memcpy(*argz + first_part_len, entry, entry_len);
+  *argz_len += entry_len;
+
+  return 0;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/insert.txh djgpp/src/libc/compat/argz/insert.txh
--- djgpp.orig/src/libc/compat/argz/insert.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/insert.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,55 @@
+@node argz_insert, string
+@findex argz_insert
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_insert(char **@var{argz}, size_t *@var{argz_len}, char *@var{before},
+                    const char *@var{entry})
+@end example
+
+@subheading Description
+
+Inserts the string @var{entry} into the argz vector @var{argz} of length @var{argz_len}
+before the string @var{before}, which should be an existing entry in @var{argz}; if @var{before}
+is @code{NULL}, @var{entry} is appended to the end.  Since @var{argz}'s first entry is the
+same as @var{argz}, @code{argz_insert(ARGZ, ARGZ_LEN, ARGZ, ENTRY)} will insert @var{entry}
+at the beginning of @var{argz}.  Because the function modifies the argz vector, both its
+length @var{argz_len} and @var{argz} itself must be passed as pointers.
+
+@subheading Return Value
+
+If @var{before} is not in @var{argz}, EINVAL is returned,
+else if memory can't be allocated for the new @var{argz},
+ENOMEM is returned, else 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *entry = "foobar";  /*  String to be inserted into argz.  */
+error_t error;
+
+error = argz_insert(&argz, &argz_len, before, entry);
+
+switch (error)
+@{
+case EINVAL:
+  printf("error: Entry \"%s\" is not in argz.\n", before);
+  exit(EINVAL);
+  break;
+case ENOMEM:
+  printf("error: Not enough memory to insert \"%s\" into argz.\n", entry);
+  exit(ENOMEM);
+  break;
+default:
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/makefile djgpp/src/libc/compat/argz/makefile
--- djgpp.orig/src/libc/compat/argz/makefile	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/makefile	2008-05-03 19:53:02 +0000
@@ -0,0 +1,17 @@
+# Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details
+TOP=../..
+
+SRC += add.c
+SRC += add_sep.c
+SRC += append.c
+SRC += count.c
+SRC += create.c
+SRC += creatsep.c
+SRC += delete.c
+SRC += extract.c
+SRC += insert.c
+SRC += next.c
+SRC += replace.c
+SRC += strngify.c
+
+include $(TOP)/../makefile.inc
diff -aprNU3 djgpp.orig/src/libc/compat/argz/next.c djgpp/src/libc/compat/argz/next.c
--- djgpp.orig/src/libc/compat/argz/next.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/next.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,25 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <string.h>
+#include <libc/unconst.h>
+
+
+char *
+argz_next(const char *argz, size_t argz_len, const char *entry)
+{
+  /*
+   *  Return the next entry in ARGZ of length ARGZ_LEN after ENTRY,
+   *  or NULL if there are no more.  If entry is NULL, then the first
+   *  entry is returned.
+   */
+
+  if (entry)
+  {
+    for (; *entry; entry++)
+      ;
+    entry++;
+    return (entry + 1 > argz + argz_len) ? NULL : unconst(entry, char *);
+  }
+
+  return (argz_len > 0) ? unconst(argz, char *) : NULL;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/next.txh djgpp/src/libc/compat/argz/next.txh
--- djgpp.orig/src/libc/compat/argz/next.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/next.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,42 @@
+@node argz_next, string
+@findex argz_next
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+char *argz_next(const char *@var{argz}, size_t @var{argz_len}, const char *@var{entry})
+@end example
+
+@subheading Description
+
+Returns the next entry in @var{argz} of length @var{argz_len} after the string @var{entry},
+or @code{NULL} if there are no more.  If entry is @code{NULL}, then the first entry is returned.
+
+@subheading Return Value
+
+A pointer to the entry or NULL.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *next_entry;
+
+next_entry = argz_next(argz, argz_len, entry);
+
+if (next_entry == NULL)
+@{
+  printf("error: No more entries in argz.\n");
+@}
+else
+@{
+  do_something_with(next_entry);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/replace.c djgpp/src/libc/compat/argz/replace.c
--- djgpp.orig/src/libc/compat/argz/replace.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/replace.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,64 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+
+error_t
+argz_replace(char **argz, size_t *argz_len, const char *str, const char *with, unsigned *replace_count)
+{
+  /*
+   *  Replace any occurrences of the string STR in the argz vector ARGZ with string WITH,
+   *  reallocating ARGZ as necessary.  If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be
+   *  incremented by number of replacements performed.
+   *  If a memory allocation error occurs, ENOMEM is returned,
+   *  otherwise 0.
+   */
+
+  error_t error = 0;
+
+
+  if (str && *str)
+  {
+    char *entry, *dst, *src;
+    size_t dst_len, src_len;
+    size_t str_len, with_len;
+
+    entry = NULL;
+    dst = NULL;
+    dst_len = 0;
+    src = *argz;
+    src_len = *argz_len;
+    str_len = strlen(str);
+    with_len = strlen(with);
+    while (!error && (entry = argz_next(src, src_len, entry)))
+      if (strstr(entry, str))
+      {
+        dst_len = src_len + with_len - str_len;
+        dst =  malloc(dst_len);
+        if (dst == NULL)
+          error = ENOMEM;
+        else
+        {
+          ptrdiff_t len;
+
+          len = entry - src;
+          memcpy(dst, src, len);
+          memcpy(dst + len, with, with_len);
+          memcpy(dst + len + with_len, entry + str_len, src_len - (len + str_len));
+
+          entry = dst + len + with_len + 1;
+          free(src);
+          src = dst;
+          src_len = dst_len;
+          if (replace_count)
+            (*replace_count)++;
+        }
+      }
+    *argz = src;
+    *argz_len = src_len;
+  }
+
+  return error;
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/replace.txh djgpp/src/libc/compat/argz/replace.txh
--- djgpp.orig/src/libc/compat/argz/replace.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/replace.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,48 @@
+@node argz_replace, string
+@findex argz_replace
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+error_t argz_replace(char **@var{argz}, size_t *@var{argz_len}, const char *@var{str}, const char *@var{with},
+                     unsigned *@var{replace_count})
+@end example
+
+@subheading Description
+
+Replaces any occurrences of the string @var{str} in the argz vector @var{argz} with the string @var{with},
+reallocating @var{argz} as necessary.  If @var{replace_count} is non-zero, *@var{replace_count} will be
+incremented by the number of replacements performed.  Because the function modifies the argz vector,
+both its length @var{argz_len} and @var{argz} itself must be passed as pointers.
+
+@subheading Return Value
+
+If a memory allocation error occurs, ENOMEM is returned, otherwise 0.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+char *str = "foobar";  /*  String to be replaced in argz.  */
+char *with = "BARFOO"; /*  Replacement.  */
+error_t error;
+
+error = argz_replace(&argz, &argz_len, str, with, NULL);
+
+if (error)
+@{
+  printf("error: \"%s\" could not be replaced by \"%s\" in argz.\n", str, with);
+  exit(ENOMEM);
+@}
+else
+@{
+  do_something_with(argz, argz_len);
+  free(argz);  /*  Free the resources.  */
+@}
+@end example
diff -aprNU3 djgpp.orig/src/libc/compat/argz/strngify.c djgpp/src/libc/compat/argz/strngify.c
--- djgpp.orig/src/libc/compat/argz/strngify.c	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/strngify.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,24 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+#include <argz.h>
+
+#define EOS  '\0'
+
+
+void
+argz_stringify(char *argz, size_t argz_len, int sep)
+{
+  /*
+   *  Make '\0' separated argz vector ARGZ printable by converting
+   *  all the '\0's except the last into the character SEP.
+   */
+
+  if (argz_len > 1)
+  {
+    size_t i, i_max;
+
+    i_max = argz_len - 1;
+    for (i = 0; i < i_max; i++)
+      if (argz[i] == EOS)
+        argz[i] = sep;
+  }
+}
diff -aprNU3 djgpp.orig/src/libc/compat/argz/strngify.txh djgpp/src/libc/compat/argz/strngify.txh
--- djgpp.orig/src/libc/compat/argz/strngify.txh	1970-01-01 00:00:00 +0000
+++ djgpp/src/libc/compat/argz/strngify.txh	2008-05-03 19:53:02 +0000
@@ -0,0 +1,32 @@
+@node argz_stringify, string
+@findex argz_stringify
+@subheading Syntax
+
+@example
+#include <argz.h>
+
+void argz_stringify(char *@var{argz}, size_t @var{argz_len}, int @var{sep})
+@end example
+
+@subheading Description
+
+Makes a @code{NUL} byte separated argz vector @var{argz} printable by converting
+all the @code{NUL}s except the last into the character @var{sep}.
+
+@subheading Return Value
+
+Nothing.
+
+@subheading Portability
+
+@port-note ansi This function is a GNU extension.
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+
+argz_stringify(argz, argz_len, '/');
+
+@end example
diff -aprNU3 djgpp.orig/tests/libc/compat/argz/argztest.c djgpp/tests/libc/compat/argz/argztest.c
--- djgpp.orig/tests/libc/compat/argz/argztest.c	1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/compat/argz/argztest.c	2008-05-03 19:53:02 +0000
@@ -0,0 +1,687 @@
+#include <argz.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFFER1 "TEXT TO BE APPENDED"
+#define BUFFER2 "NEW:TEST:STRING"
+#define BUFFER3 "TAIL"
+#define BUFFER4 "CENTRAL"
+#define BUFFER5 "HEAD"
+#define BUFFER  ""
+
+void print_result(char *argz, size_t argz_len)
+{
+  size_t index, len;
+
+
+  printf("argz_len: %zd\n", argz_len);
+  if (argz_len)
+    for (index = 0; index < argz_len;)
+    {
+      printf("argz[%zd] = <", index);
+      len = index;
+      index += printf("%s", argz + index);
+      printf("\\0>\t\tlength = %zd\n", ++index - len);
+    }
+  else
+    printf("argz[0] = %s", argz);
+}
+
+
+int main(void)
+{
+  char *const glibc_compatibility_test_argv[] = {
+    NULL
+  };
+  char *glibc_compatibility_test_string = "";
+  char *const test_argv[] = {
+    "Test",
+    "string",
+    "for",
+    "argz_create",
+    NULL
+  };
+  const char *test_string1 = "Test#string#1# #for#argz_create_sep#";
+  const char *test_string2 = "Test#string#2# #for#argz_create_sep";
+  const char *test_string3 = "TO BE REPLACED#string 1#TO BE REPLACED#string 2#string 3#TO BE REPLACED#string 4#string 5#TO BE REPLACED";
+  int delimiter = '#';
+  char *argz, **argvp = NULL, *before, *entry;
+  size_t argz_len, counts, entry_index, i;
+  error_t error;
+
+
+  /*
+   *  argz_create test.
+   */
+  printf("Test: argz_create.\n"
+         "==================\n"
+         "An argz vector shall be created using the following UNIX-style argv array:\n");
+  for (i = 0; test_argv[i]; i++)
+    printf("test_argv[%zi]: \"%s\"\n", i, test_argv[i]);
+  printf("test_argv[%zi]: \"%s\"\n", i, test_argv[i]);
+  printf("\n");
+
+  error = argz_create(test_argv, &argz, &argz_len);
+  if (error)
+  {
+    printf("argz_create test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("argz_create test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_count test.
+   */
+  printf("Test: argz_count.\n"
+         "=================\n"
+         "Count the strings contained in an argz vector.\n");
+  for (counts = 0; test_argv[counts]; counts++)
+    ;
+  if (counts != argz_count(argz, argz_len))
+  {
+    printf("argz_count test failed.\n");
+    exit(1);
+  }
+  else
+  {
+    printf("\nargz_count test passed.\n");
+    printf("counts: %zd\n", counts);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_create_sep test.
+   */
+  printf("Test 1: argz_create_sep.\n"
+         "========================\n"
+         "An argz vector shall be created using the following test string:\n"
+         "\"%s\"\n"
+         "The delimiter character \'%c\' will be used as string separator\n"
+         "in the test string and will be replaced with \'\\0\' in the argz vector.\n", test_string1, delimiter);
+  free(argz);
+  error = argz_create_sep(test_string1, delimiter, &argz, &argz_len);
+  if (error)
+  {
+    printf("\nargz_create_sep test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_create_sep test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n");
+
+  printf("Test 2: argz_create_sep.\n"
+         "========================\n"
+         "An argz vector shall be created using the following test string:\n"
+         "\"%s\"\n"
+         "The delimiter character \'%c\' will be used as string separator\n"
+         "in the test string and will be replaced with \'\\0\' in the argz vector.\n", test_string2, delimiter);
+  free(argz);
+  error = argz_create_sep(test_string2, delimiter, &argz, &argz_len);
+  if (error)
+  {
+    printf("argz_create_sep failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_create_sep test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_add test.
+   */
+  printf("Test: argz_add.\n"
+         "===============\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be added to the end of an argz vector.\n", BUFFER1);
+  entry_index = argz_len;  /*  Remember the position of the entry that later will be deleted.  */
+  error = argz_add(&argz, &argz_len, BUFFER1);
+  if (error)
+  {
+    printf("\nargz_add test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_add test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_add_sep test.
+   */
+  delimiter = ':';
+  printf("Test: argz_add_sep.\n"
+         "===================\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be added to the end of an argz vector.\n"
+         "The delimiter character \'%c\' will be used as string separator\n"
+         "in the test string and will be replaced with \'\\0\' in the argz vector.\n", BUFFER2, delimiter);
+  error = argz_add_sep(&argz, &argz_len, BUFFER2, delimiter);
+  if (error)
+  {
+    printf("\nargz_add_sep test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_add_sep test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_delete test.
+   */
+  printf("Test: argz_delete.\n"
+         "==================\n"
+         "The entry:\n"
+         "\"%s\"\n"
+         "will be deleted from argz vector.\n", BUFFER1);
+  argz_delete(&argz, &argz_len, argz + entry_index);
+  printf("\nargz_delete test passed.\n");
+  print_result(argz, argz_len);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_append test.
+   */
+  printf("Test: argz_append.\n"
+         "==================\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be appended to the end of an argz vector.\n", BUFFER1);
+  error = argz_append(&argz, &argz_len, BUFFER1, sizeof(BUFFER1));
+  if (error)
+  {
+    printf("\nargz_append test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_append test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_extract test.
+   */
+  printf("Test: argz_extract.\n"
+         "===================\n"
+         "Store pointers to each string contained in the argz vector in an UNIX-style argv array,\n"
+         "which must be large enough to contain them inclusive the terminating NULL pointer.\n");
+  counts = argz_count(argz, argz_len) + 1;
+  argvp = malloc(counts * sizeof(*argvp));
+  printf("\nargz_extract test passed.\n");
+  argz_extract(argz, argz_len, argvp);
+  printf("argz_len: %zd\n", argz_len);
+  for (i = 0; i < counts; i++)
+    printf("argvp[%zi]: \"%s\"\n", i, argvp[i]);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_next test.
+   */
+  printf("Test: argz_next.\n"
+         "================\n"
+         "Get a pointer to the next entry in the argz vector after the entry passed to the function.\n");
+  printf("\nargz_extract test passed.\n");
+  entry = NULL;
+  do {
+    printf("entry passed (0x%p):  \"%s\"\t\t", entry, entry);
+    entry = argz_next(argz, argz_len, entry);
+    printf("entry returned (0x%p):  \"%s\"\n", entry, entry);
+  } while (entry);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_insert test.
+   */
+  printf("Test: argz_insert.\n"
+         "==================\n"
+         "Insert entry in the argz vector before the string pointed by the pointer passed to the function.\n");
+  before = NULL;
+  error = argz_insert(&argz, &argz_len, before, BUFFER3);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nFirst argz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  thus  entry \"%s\" will be appended at the end of argz.\n", before, before, BUFFER3);
+    print_result(argz, argz_len);
+  }
+  before = argz + entry_index;
+  entry = strdup(before);
+  error = argz_insert(&argz, &argz_len, before, BUFFER4);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nSecond argz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  >  argz (0x%p): \"%s\"  thus  entry \"%s\" will be inserted before \"%s\".\n", entry, entry, argz, argz, BUFFER4, entry);
+    print_result(argz, argz_len);
+  }
+  free(entry);
+  before = argz;
+  error = argz_insert(&argz, &argz_len, before, BUFFER5);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nThird argz_insert test passed.\n");
+    printf("before (0x%p) == argz (0x%p)  thus  entry \"%s\" will be inserted before the beginnig of argz.\n", before, argz, BUFFER5);
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_stringify test.
+   */
+  delimiter = '/';
+  printf("Test: argz_stringify.\n"
+         "=====================\n"
+         "Make a '\\0' separated argz vector printable by converting all the '\\0's\n"
+         "except the last into the character '%c'.\n", delimiter);
+  argz_stringify(argz, argz_len, delimiter);
+  printf("\nargz_stringify test passed.\n");
+  print_result(argz, argz_len);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_replace test.
+   */
+  free(argz);
+  error = argz_create_sep(test_string3, '#', &argz, &argz_len);
+  if (error)
+  {
+    printf("argz_create_sep failed: ENOMEM\n");
+    exit(error);
+  }
+  entry = malloc(argz_len);
+  memcpy(entry, argz, argz_len);
+  argz_stringify(argz, argz_len, '/');
+  printf("Test: argz_replace.\n"
+         "===================\n"
+         "Replace any occurrences of string:\n"
+         "\"%s\"\n"
+         "in the argz vector:\n"
+         "\"%s\"\n"
+         "with:\n"
+         "\"%s\",\n"
+         "reallocating the argz vector as necessary.\n", "TO BE REPLACED", argz, "REPLACEMENT STRING");
+  free(argz);
+  argz = entry;
+  error = argz_replace(&argz, &argz_len, "TO BE REPLACED", "REPLACEMENT STRING", NULL);
+  if (error)
+  {
+    printf("\nargz_replace test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_replace test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+
+
+  /*
+   *
+   *  The same test but with (NULL, 0) to check if no SIGSEGV happens.
+   *
+   */
+  free(argz);
+  printf("#\n#\n#\n#  The same tests but with an argz vector of the form (NULL, 0).\n#\n#\n#\n\n\n");
+
+  /*
+   *  argz_create test.
+   */
+  printf("Test: argz_create.\n"
+         "==================\n"
+         "An argz vector shall be created using the following argv array:\n");
+  for (i = 0; glibc_compatibility_test_argv[i]; i++)
+    printf("test_argv[%zi]: \"%s\"\n", i, glibc_compatibility_test_argv[i]);
+  printf("test_argv[%zi]: \"%s\"\n", i, glibc_compatibility_test_argv[i]);
+  printf("\n");
+
+  error = argz_create(glibc_compatibility_test_argv, &argz, &argz_len);
+  if (error)
+  {
+    printf("argz_create test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("argz_create test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_create_sep test.
+   */
+  printf("Test: argz_create_sep.\n"
+         "======================\n"
+         "An argz vector shall be created using the following test string:\n"
+         "\"%s\"\n"
+         "The delimiter character \'%c\' will be used as string separator\n"
+         "in the test string and will be replaced with \'\\0\' in the argz vector.\n", glibc_compatibility_test_string, delimiter);
+  error = argz_create_sep(glibc_compatibility_test_string, delimiter, &argz, &argz_len);
+  if (error)
+  {
+    printf("\nargz_create_sep test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_create_sep test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_count test.
+   */
+  printf("Test: argz_count.\n"
+         "=================\n"
+         "Count the strings contained in an argz vector.\n");
+  for (counts = 0; glibc_compatibility_test_argv[counts]; counts++)
+    ;
+  if (counts != argz_count(argz, argz_len))
+  {
+    printf("argz_count test failed.\n");
+    exit(1);
+  }
+  else
+  {
+    printf("\nargz_count test passed.\n");
+    printf("counts: %zd\n", counts);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_add test.
+   */
+  printf("Test: argz_add.\n"
+         "===============\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be added to the end of an argz vector.\n", BUFFER);
+  entry_index = argz_len;  /*  Remember the position of the entry that later will be deleted.  */
+  error = argz_add(&argz, &argz_len, BUFFER);
+  if (error)
+  {
+    printf("\nargz_add test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_add test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_add_sep test.
+   */
+  delimiter = ':';
+  printf("Test: argz_add_sep.\n"
+         "======================\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be added to the end of an argz vector.\n"
+         "The delimiter character \'%c\' will be used as string separator\n"
+         "in the test string and will be replaced with \'\\0\' in the argz vector.\n", BUFFER, delimiter);
+  error = argz_add_sep(&argz, &argz_len, BUFFER, delimiter);
+  if (error)
+  {
+    printf("\nargz_add_sep test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_add_sep test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_delete test.
+   */
+  printf("Test: argz_delete.\n"
+         "==================\n"
+         "The entry:\n"
+         "\"%s\"\n"
+         "will be deleted from argz vector.\n", BUFFER);
+  argz_delete(&argz, &argz_len, argz + entry_index);
+  printf("\nargz_delete test passed.\n");
+  printf("argz_len: %zd\n", argz_len);
+  printf("argz:     %s\n", argz);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_append test.
+   */
+  printf("Test: argz_append.\n"
+         "==================\n"
+         "The test string:\n"
+         "\"%s\"\n"
+         "shall be appended to the end of an argz vector.\n", BUFFER);
+  error = argz_append(&argz, &argz_len, BUFFER, sizeof(BUFFER));
+  if (error)
+  {
+    printf("\nargz_append test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_append test passed.\n");
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_extract test.
+   */
+  printf("Test: argz_extract.\n"
+         "===================\n"
+         "Store pointers to each string contained in the argz vector in an argv array,\n"
+         "which must be large enough to contain them inclusive the terminating NULL pointer.\n");
+  error = argz_add(&argz, &argz_len, BUFFER);
+  error = argz_add(&argz, &argz_len, BUFFER);
+  error = argz_add(&argz, &argz_len, BUFFER);
+  error = argz_add(&argz, &argz_len, BUFFER);
+  counts = argz_count(argz, argz_len) + 1;
+  argvp = malloc(counts * sizeof(*argvp));
+  printf("\nargz_extract test passed.\n");
+  argz_extract(argz, 0, argvp);
+  printf("argz_len=0\n");
+  printf("argvp[0]: \"%s\"\n", argvp[0]);
+  printf("\n");
+  argz_extract(argz, 1, argvp);
+  printf("argz_len=1\n");
+  for (i = 0; i < 2; i++)
+    printf("argvp[%zi]: \"%s\"\n", i, argvp[i]);
+  printf("\n");
+  argz_extract(argz, argz_len, argvp);
+  printf("argz_len: %zd\n", argz_len);
+  for (i = 0; i < counts; i++)
+    printf("argvp[%zi]: \"%s\"\n", i, argvp[i]);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_next test.
+   */
+  printf("Test: argz_next.\n"
+         "================\n"
+         "Get a pointer to the next entry in the argz vector after the entry passed to the function.\n");
+  printf("\nargz_extract test passed.\n");
+  entry = NULL;
+  do {
+    printf("entry passed (0x%p):  \"%s\"\t\t", entry, entry);
+    entry = argz_next(argz, argz_len, entry);
+    printf("entry returned (0x%p):  \"%s\"\n", entry, entry);
+  } while (entry);
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_insert test.
+   */
+  printf("Test 1: argz_insert.\n"
+         "====================\n"
+         "Insert entry in the argz vector before the string pointed by the pointer passed to the function.\n");
+  before = NULL;
+  error = argz_insert(&argz, &argz_len, before, BUFFER);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  thus  entry \"%s\" will be appended at the end of argz.\n", before, before, BUFFER);
+    print_result(argz, argz_len);
+  }
+  before = argz + argz_len / 2;
+  entry = strdup(before);
+  error = argz_insert(&argz, &argz_len, before, BUFFER);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  >  argz (0x%p): \"%s\"  thus  entry \"%s\" will be inserted before \"%s\".\n", entry, entry, argz, argz, BUFFER, entry);
+    print_result(argz, argz_len);
+  }
+  free(entry);
+  before = argz;
+  error = argz_insert(&argz, &argz_len, before, BUFFER);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p) == argz (0x%p)  thus  entry \"%s\" will be inserted before the beginnig of argz.\n", before, argz, BUFFER);
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_insert test.
+   */
+  printf("Test 2: argz_insert.\n"
+         "==================\n"
+         "Insert entry in the argz vector before the string pointed by the pointer passed to the function.\n");
+  before = NULL;
+  error = argz_insert(&argz, &argz_len, before, BUFFER3);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  thus  entry: \"%s\" will be appended to the end of argz.\n", before, before, BUFFER3);
+    print_result(argz, argz_len);
+  }
+  before = argz + argz_len / 2;
+  entry = strdup(before);
+  error = argz_insert(&argz, &argz_len, before, BUFFER4);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p): \"%s\"  >  argz (0x%p): \"%s\"  thus  entry: \"%s\" will be inserted before \"%s\".\n", entry, entry, argz, argz, BUFFER4, entry);
+    print_result(argz, argz_len);
+  }
+  free(entry);
+  before = argz;
+  error = argz_insert(&argz, &argz_len, before, BUFFER5);
+  if (error)
+  {
+    printf("\nargz_insert test failed: ENOMEM\n");
+    exit(error);
+  }
+  else
+  {
+    printf("\nargz_insert test passed.\n");
+    printf("before (0x%p) == argz (0x%p)  thus  entry (0x%p): \"%s\" will be inserted before the beginnig of argz.\n", before, argz, BUFFER5, BUFFER5);
+    print_result(argz, argz_len);
+  }
+  printf("\n################################################################################\n\n\n");
+
+
+  /*
+   *  argz_stringify test.
+   */
+  delimiter = '/';
+  printf("Test: argz_stringify.\n"
+         "=====================\n"
+         "Make a '\\0' separated argz vector printable by converting all the '\\0's\n"
+         "except the last into the character '%c'.\n", delimiter);
+  argz_stringify(argz, argz_len, delimiter);
+  printf("\nargz_stringify test passed.\n");
+  print_result(argz, argz_len);
+  printf("\n################################################################################\n\n\n");
+
+  return 0;
+}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019