changeset 4224:83eabea25586

New modules vasnprintf and vasprintf.
author Bruno Haible <bruno@clisp.org>
date Thu, 30 Jan 2003 13:48:21 +0000
parents 94b829dffa17
children 2c0e7b3e787f
files ChangeLog MODULES.html.sh lib/ChangeLog lib/asnprintf.c lib/asprintf.c lib/printf-args.c lib/printf-args.h lib/printf-parse.c lib/printf-parse.h lib/vasnprintf.c lib/vasnprintf.h lib/vasprintf.c lib/vasprintf.h m4/ChangeLog m4/longdouble.m4 m4/signed.m4 m4/vasnprintf.m4 m4/vasprintf.m4 m4/wchar_t.m4 m4/wint_t.m4 modules/vasnprintf modules/vasprintf
diffstat 22 files changed, 2074 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-01-30  Bruno Haible  <bruno@clisp.org>
+
+	* modules/vasnprintf, modules/vasprintf: New modules.
+	* MODULES.html.sh (func_all_modules): Add them.
+
 2003-01-29  Bruno Haible  <bruno@clisp.org>
 
 	* modules/stpncpy: New module.
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1541,8 +1541,8 @@
 
   func_begin_table
   func_module unlocked-io
-  #func_module vasnprintf
-  #func_module vasprintf
+  func_module vasnprintf
+  func_module vasprintf
   func_end_table
 
   element="Command-line arguments"
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,16 @@
+2003-01-30  Bruno Haible  <bruno@clisp.org>
+
+	* printf-args.h: New file, from GNU gettext.
+	* printf-args.c: New file, from GNU gettext.
+	* printf-parse.h: New file, from GNU gettext.
+	* printf-parse.c: New file, from GNU gettext.
+	* vasnprintf.h: New file, from GNU gettext.
+	* vasnprintf.c: New file, from GNU gettext.
+	* asnprintf.c: New file, from GNU gettext.
+	* vasprintf.h: New file, from GNU gettext with modifications.
+	* vasprintf.c: New file, from GNU gettext.
+	* asprintf.c: New file, from GNU gettext.
+
 2003-01-29  Bruno Haible  <bruno@clisp.org>
 
 	* stpncpy.h: New file, from GNU gettext with modifications.
new file mode 100644
--- /dev/null
+++ b/lib/asnprintf.c
@@ -0,0 +1,38 @@
+/* Formatted output to strings.
+   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "vasnprintf.h"
+
+#include <stdarg.h>
+
+char *
+asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+{
+  va_list args;
+  char *result;
+
+  va_start (args, format);
+  result = vasnprintf (resultbuf, lengthp, format, args);
+  va_end (args);
+  return result;
+}
new file mode 100644
--- /dev/null
+++ b/lib/asprintf.c
@@ -0,0 +1,38 @@
+/* Formatted output to strings.
+   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "vasprintf.h"
+
+#include <stdarg.h>
+
+int
+asprintf (char **resultp, const char *format, ...)
+{
+  va_list args;
+  int result;
+
+  va_start (args, format);
+  result = vasprintf (resultp, format, args);
+  va_end (args);
+  return result;
+}
new file mode 100644
--- /dev/null
+++ b/lib/printf-args.c
@@ -0,0 +1,119 @@
+/* Decomposed printf argument list.
+   Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "printf-args.h"
+
+#ifdef STATIC
+STATIC
+#endif
+int
+printf_fetchargs (va_list args, arguments *a)
+{
+  unsigned int i;
+  argument *ap;
+
+  for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
+    switch (ap->type)
+      {
+      case TYPE_SCHAR:
+	ap->a.a_schar = va_arg (args, /*signed char*/ int);
+	break;
+      case TYPE_UCHAR:
+	ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
+	break;
+      case TYPE_SHORT:
+	ap->a.a_short = va_arg (args, /*short*/ int);
+	break;
+      case TYPE_USHORT:
+	ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
+	break;
+      case TYPE_INT:
+	ap->a.a_int = va_arg (args, int);
+	break;
+      case TYPE_UINT:
+	ap->a.a_uint = va_arg (args, unsigned int);
+	break;
+      case TYPE_LONGINT:
+	ap->a.a_longint = va_arg (args, long int);
+	break;
+      case TYPE_ULONGINT:
+	ap->a.a_ulongint = va_arg (args, unsigned long int);
+	break;
+#ifdef HAVE_LONG_LONG
+      case TYPE_LONGLONGINT:
+	ap->a.a_longlongint = va_arg (args, long long int);
+	break;
+      case TYPE_ULONGLONGINT:
+	ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
+	break;
+#endif
+      case TYPE_DOUBLE:
+	ap->a.a_double = va_arg (args, double);
+	break;
+#ifdef HAVE_LONG_DOUBLE
+      case TYPE_LONGDOUBLE:
+	ap->a.a_longdouble = va_arg (args, long double);
+	break;
+#endif
+      case TYPE_CHAR:
+	ap->a.a_char = va_arg (args, int);
+	break;
+#ifdef HAVE_WINT_T
+      case TYPE_WIDE_CHAR:
+	ap->a.a_wide_char = va_arg (args, wint_t);
+	break;
+#endif
+      case TYPE_STRING:
+	ap->a.a_string = va_arg (args, const char *);
+	break;
+#ifdef HAVE_WCHAR_T
+      case TYPE_WIDE_STRING:
+	ap->a.a_wide_string = va_arg (args, const wchar_t *);
+	break;
+#endif
+      case TYPE_POINTER:
+	ap->a.a_pointer = va_arg (args, void *);
+	break;
+      case TYPE_COUNT_SCHAR_POINTER:
+	ap->a.a_count_schar_pointer = va_arg (args, signed char *);
+	break;
+      case TYPE_COUNT_SHORT_POINTER:
+	ap->a.a_count_short_pointer = va_arg (args, short *);
+	break;
+      case TYPE_COUNT_INT_POINTER:
+	ap->a.a_count_int_pointer = va_arg (args, int *);
+	break;
+      case TYPE_COUNT_LONGINT_POINTER:
+	ap->a.a_count_longint_pointer = va_arg (args, long int *);
+	break;
+#ifdef HAVE_LONG_LONG
+      case TYPE_COUNT_LONGLONGINT_POINTER:
+	ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
+	break;
+#endif
+      default:
+	/* Unknown type.  */
+	return -1;
+      }
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/lib/printf-args.h
@@ -0,0 +1,134 @@
+/* Decomposed printf argument list.
+   Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _PRINTF_ARGS_H
+#define _PRINTF_ARGS_H
+
+/* Get wchar_t.  */
+#ifdef HAVE_WCHAR_T
+# include <stddef.h>
+#endif
+
+/* Get wint_t.  */
+#ifdef HAVE_WINT_T
+# include <wchar.h>
+#endif
+
+/* Get va_list.  */
+#include <stdarg.h>
+
+
+/* Argument types */
+typedef enum
+{
+  TYPE_NONE,
+  TYPE_SCHAR,
+  TYPE_UCHAR,
+  TYPE_SHORT,
+  TYPE_USHORT,
+  TYPE_INT,
+  TYPE_UINT,
+  TYPE_LONGINT,
+  TYPE_ULONGINT,
+#ifdef HAVE_LONG_LONG
+  TYPE_LONGLONGINT,
+  TYPE_ULONGLONGINT,
+#endif
+  TYPE_DOUBLE,
+#ifdef HAVE_LONG_DOUBLE
+  TYPE_LONGDOUBLE,
+#endif
+  TYPE_CHAR,
+#ifdef HAVE_WINT_T
+  TYPE_WIDE_CHAR,
+#endif
+  TYPE_STRING,
+#ifdef HAVE_WCHAR_T
+  TYPE_WIDE_STRING,
+#endif
+  TYPE_POINTER,
+  TYPE_COUNT_SCHAR_POINTER,
+  TYPE_COUNT_SHORT_POINTER,
+  TYPE_COUNT_INT_POINTER,
+  TYPE_COUNT_LONGINT_POINTER
+#ifdef HAVE_LONG_LONG
+, TYPE_COUNT_LONGLONGINT_POINTER
+#endif
+} arg_type;
+
+/* Polymorphic argument */
+typedef struct
+{
+  arg_type type;
+  union
+  {
+    signed char			a_schar;
+    unsigned char		a_uchar;
+    short			a_short;
+    unsigned short		a_ushort;
+    int				a_int;
+    unsigned int		a_uint;
+    long int			a_longint;
+    unsigned long int		a_ulongint;
+#ifdef HAVE_LONG_LONG
+    long long int		a_longlongint;
+    unsigned long long int	a_ulonglongint;
+#endif
+    float			a_float;
+    double			a_double;
+#ifdef HAVE_LONG_DOUBLE
+    long double			a_longdouble;
+#endif
+    int				a_char;
+#ifdef HAVE_WINT_T
+    wint_t			a_wide_char;
+#endif
+    const char*			a_string;
+#ifdef HAVE_WCHAR_T
+    const wchar_t*		a_wide_string;
+#endif
+    void*			a_pointer;
+    signed char *		a_count_schar_pointer;
+    short *			a_count_short_pointer;
+    int *			a_count_int_pointer;
+    long int *			a_count_longint_pointer;
+#ifdef HAVE_LONG_LONG
+    long long int *		a_count_longlongint_pointer;
+#endif
+  }
+  a;
+}
+argument;
+
+typedef struct
+{
+  unsigned int count;
+  argument *arg;
+}
+arguments;
+
+
+/* Fetch the arguments, putting them into a. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_fetchargs (va_list args, arguments *a);
+
+#endif /* _PRINTF_ARGS_H */
new file mode 100644
--- /dev/null
+++ b/lib/printf-parse.c
@@ -0,0 +1,477 @@
+/* Formatted output to strings.
+   Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "printf-parse.h"
+
+/* Get size_t, NULL.  */
+#include <stddef.h>
+
+/* Get intmax_t.  */
+#if HAVE_STDINT_H_WITH_UINTMAX
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+# include <inttypes.h>
+#endif
+
+/* malloc(), realloc(), free().  */
+#include <stdlib.h>
+
+#ifdef STATIC
+STATIC
+#endif
+int
+printf_parse (const char *format, char_directives *d, arguments *a)
+{
+  const char *cp = format;		/* pointer into format */
+  int arg_posn = 0;		/* number of regular arguments consumed */
+  unsigned int d_allocated;		/* allocated elements of d->dir */
+  unsigned int a_allocated;		/* allocated elements of a->arg */
+  unsigned int max_width_length = 0;
+  unsigned int max_precision_length = 0;
+
+  d->count = 0;
+  d_allocated = 1;
+  d->dir = malloc (d_allocated * sizeof (char_directive));
+  if (d->dir == NULL)
+    /* Out of memory.  */
+    return -1;
+
+  a->count = 0;
+  a_allocated = 0;
+  a->arg = NULL;
+
+#define REGISTER_ARG(_index_,_type_) \
+  {									\
+    unsigned int n = (_index_);						\
+    if (n >= a_allocated)						\
+      {									\
+	argument *memory;						\
+	a_allocated = 2 * a_allocated;					\
+	if (a_allocated <= n)						\
+	  a_allocated = n + 1;						\
+	memory = (a->arg						\
+		  ? realloc (a->arg, a_allocated * sizeof (argument))	\
+		  : malloc (a_allocated * sizeof (argument)));		\
+	if (memory == NULL)						\
+	  /* Out of memory.  */						\
+	  goto error;							\
+	a->arg = memory;						\
+      }									\
+    while (a->count <= n)						\
+      a->arg[a->count++].type = TYPE_NONE;				\
+    if (a->arg[n].type == TYPE_NONE)					\
+      a->arg[n].type = (_type_);					\
+    else if (a->arg[n].type != (_type_))				\
+      /* Ambiguous type for positional argument.  */			\
+      goto error;							\
+  }
+
+  while (*cp != '\0')
+    {
+      char c = *cp++;
+      if (c == '%')
+	{
+	  int arg_index = -1;
+	  char_directive *dp = &d->dir[d->count];/* pointer to next directive */
+
+	  /* Initialize the next directive.  */
+	  dp->dir_start = cp - 1;
+	  dp->flags = 0;
+	  dp->width_start = NULL;
+	  dp->width_end = NULL;
+	  dp->width_arg_index = -1;
+	  dp->precision_start = NULL;
+	  dp->precision_end = NULL;
+	  dp->precision_arg_index = -1;
+	  dp->arg_index = -1;
+
+	  /* Test for positional argument.  */
+	  if (*cp >= '0' && *cp <= '9')
+	    {
+	      const char *np;
+
+	      for (np = cp; *np >= '0' && *np <= '9'; np++)
+		;
+	      if (*np == '$')
+		{
+		  unsigned int n = 0;
+
+		  for (np = cp; *np >= '0' && *np <= '9'; np++)
+		    n = 10 * n + (*np - '0');
+		  if (n == 0)
+		    /* Positional argument 0.  */
+		    goto error;
+		  arg_index = n - 1;
+		  cp = np + 1;
+		}
+	    }
+
+	  /* Read the flags.  */
+	  for (;;)
+	    {
+	      if (*cp == '\'')
+		{
+		  dp->flags |= FLAG_GROUP;
+		  cp++;
+		}
+	      else if (*cp == '-')
+		{
+		  dp->flags |= FLAG_LEFT;
+		  cp++;
+		}
+	      else if (*cp == '+')
+		{
+		  dp->flags |= FLAG_SHOWSIGN;
+		  cp++;
+		}
+	      else if (*cp == ' ')
+		{
+		  dp->flags |= FLAG_SPACE;
+		  cp++;
+		}
+	      else if (*cp == '#')
+		{
+		  dp->flags |= FLAG_ALT;
+		  cp++;
+		}
+	      else if (*cp == '0')
+		{
+		  dp->flags |= FLAG_ZERO;
+		  cp++;
+		}
+	      else
+		break;
+	    }
+
+	  /* Parse the field width.  */
+	  if (*cp == '*')
+	    {
+	      dp->width_start = cp;
+	      cp++;
+	      dp->width_end = cp;
+	      if (max_width_length < 1)
+		max_width_length = 1;
+
+	      /* Test for positional argument.  */
+	      if (*cp >= '0' && *cp <= '9')
+		{
+		  const char *np;
+
+		  for (np = cp; *np >= '0' && *np <= '9'; np++)
+		    ;
+		  if (*np == '$')
+		    {
+		      unsigned int n = 0;
+
+		      for (np = cp; *np >= '0' && *np <= '9'; np++)
+			n = 10 * n + (*np - '0');
+		      if (n == 0)
+			/* Positional argument 0.  */
+			goto error;
+		      dp->width_arg_index = n - 1;
+		      cp = np + 1;
+		    }
+		}
+	      if (dp->width_arg_index < 0)
+		dp->width_arg_index = arg_posn++;
+	      REGISTER_ARG (dp->width_arg_index, TYPE_INT);
+	    }
+	  else if (*cp >= '0' && *cp <= '9')
+	    {
+	      unsigned int width_length;
+
+	      dp->width_start = cp;
+	      for (; *cp >= '0' && *cp <= '9'; cp++)
+		;
+	      dp->width_end = cp;
+	      width_length = dp->width_end - dp->width_start;
+	      if (max_width_length < width_length)
+		max_width_length = width_length;
+	    }
+
+	  /* Parse the precision.  */
+	  if (*cp == '.')
+	    {
+	      cp++;
+	      if (*cp == '*')
+		{
+		  dp->precision_start = cp - 1;
+		  cp++;
+		  dp->precision_end = cp;
+		  if (max_precision_length < 2)
+		    max_precision_length = 2;
+
+		  /* Test for positional argument.  */
+		  if (*cp >= '0' && *cp <= '9')
+		    {
+		      const char *np;
+
+		      for (np = cp; *np >= '0' && *np <= '9'; np++)
+			;
+		      if (*np == '$')
+			{
+			  unsigned int n = 0;
+
+			  for (np = cp; *np >= '0' && *np <= '9'; np++)
+			    n = 10 * n + (*np - '0');
+			  if (n == 0)
+			    /* Positional argument 0.  */
+			    goto error;
+			  dp->precision_arg_index = n - 1;
+			  cp = np + 1;
+			}
+		    }
+		  if (dp->precision_arg_index < 0)
+		    dp->precision_arg_index = arg_posn++;
+		  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
+		}
+	      else
+		{
+		  unsigned int precision_length;
+
+		  dp->precision_start = cp - 1;
+		  for (; *cp >= '0' && *cp <= '9'; cp++)
+		    ;
+		  dp->precision_end = cp;
+		  precision_length = dp->precision_end - dp->precision_start;
+		  if (max_precision_length < precision_length)
+		    max_precision_length = precision_length;
+		}
+	    }
+
+	  {
+	    arg_type type;
+
+	    /* Parse argument type/size specifiers.  */
+	    {
+	      int flags = 0;
+
+	      for (;;)
+		{
+		  if (*cp == 'h')
+		    {
+		      flags |= (1 << (flags & 1));
+		      cp++;
+		    }
+		  else if (*cp == 'L')
+		    {
+		      flags |= 4;
+		      cp++;
+		    }
+		  else if (*cp == 'l')
+		    {
+		      flags += 8;
+		      cp++;
+		    }
+#ifdef HAVE_INTMAX_T
+		  else if (*cp == 'j')
+		    {
+		      if (sizeof (intmax_t) > sizeof (long))
+			{
+			  /* intmax_t = long long */
+			  flags += 16;
+			}
+		      else if (sizeof (intmax_t) > sizeof (int))
+			{
+			  /* intmax_t = long */
+			  flags += 8;
+			}
+		      cp++;
+		    }
+#endif
+		  else if (*cp == 'z' || *cp == 'Z')
+		    {
+		      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
+			 because the warning facility in gcc-2.95.2 understands
+			 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
+		      if (sizeof (size_t) > sizeof (long))
+			{
+			  /* size_t = long long */
+			  flags += 16;
+			}
+		      else if (sizeof (size_t) > sizeof (int))
+			{
+			  /* size_t = long */
+			  flags += 8;
+			}
+		      cp++;
+		    }
+		  else if (*cp == 't')
+		    {
+		      if (sizeof (ptrdiff_t) > sizeof (long))
+			{
+			  /* ptrdiff_t = long long */
+			  flags += 16;
+			}
+		      else if (sizeof (ptrdiff_t) > sizeof (int))
+			{
+			  /* ptrdiff_t = long */
+			  flags += 8;
+			}
+		      cp++;
+		    }
+		  else
+		    break;
+		}
+
+	      /* Read the conversion character.  */
+	      c = *cp++;
+	      switch (c)
+		{
+		case 'd': case 'i':
+#ifdef HAVE_LONG_LONG
+		  if (flags >= 16 || (flags & 4))
+		    type = TYPE_LONGLONGINT;
+		  else
+#endif
+		  if (flags >= 8)
+		    type = TYPE_LONGINT;
+		  else if (flags & 2)
+		    type = TYPE_SCHAR;
+		  else if (flags & 1)
+		    type = TYPE_SHORT;
+		  else
+		    type = TYPE_INT;
+		  break;
+		case 'o': case 'u': case 'x': case 'X':
+#ifdef HAVE_LONG_LONG
+		  if (flags >= 16 || (flags & 4))
+		    type = TYPE_ULONGLONGINT;
+		  else
+#endif
+		  if (flags >= 8)
+		    type = TYPE_ULONGINT;
+		  else if (flags & 2)
+		    type = TYPE_UCHAR;
+		  else if (flags & 1)
+		    type = TYPE_USHORT;
+		  else
+		    type = TYPE_UINT;
+		  break;
+		case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+		case 'a': case 'A':
+#ifdef HAVE_LONG_DOUBLE
+		  if (flags >= 16 || (flags & 4))
+		    type = TYPE_LONGDOUBLE;
+		  else
+#endif
+		  type = TYPE_DOUBLE;
+		  break;
+		case 'c':
+		  if (flags >= 8)
+#ifdef HAVE_WINT_T
+		    type = TYPE_WIDE_CHAR;
+#else
+		    goto error;
+#endif
+		  else
+		    type = TYPE_CHAR;
+		  break;
+#ifdef HAVE_WINT_T
+		case 'C':
+		  type = TYPE_WIDE_CHAR;
+		  c = 'c';
+		  break;
+#endif
+		case 's':
+		  if (flags >= 8)
+#ifdef HAVE_WCHAR_T
+		    type = TYPE_WIDE_STRING;
+#else
+		    goto error;
+#endif
+		  else
+		    type = TYPE_STRING;
+		  break;
+#ifdef HAVE_WCHAR_T
+		case 'S':
+		  type = TYPE_WIDE_STRING;
+		  c = 's';
+		  break;
+#endif
+		case 'p':
+		  type = TYPE_POINTER;
+		  break;
+		case 'n':
+#ifdef HAVE_LONG_LONG
+		  if (flags >= 16 || (flags & 4))
+		    type = TYPE_COUNT_LONGLONGINT_POINTER;
+		  else
+#endif
+		  if (flags >= 8)
+		    type = TYPE_COUNT_LONGINT_POINTER;
+		  else if (flags & 2)
+		    type = TYPE_COUNT_SCHAR_POINTER;
+		  else if (flags & 1)
+		    type = TYPE_COUNT_SHORT_POINTER;
+		  else
+		    type = TYPE_COUNT_INT_POINTER;
+		  break;
+		case '%':
+		  type = TYPE_NONE;
+		  break;
+		default:
+		  /* Unknown conversion character.  */
+		  goto error;
+		}
+	    }
+
+	    if (type != TYPE_NONE)
+	      {
+		dp->arg_index = arg_index;
+		if (dp->arg_index < 0)
+		  dp->arg_index = arg_posn++;
+		REGISTER_ARG (dp->arg_index, type);
+	      }
+	    dp->conversion = c;
+	    dp->dir_end = cp;
+	  }
+
+	  d->count++;
+	  if (d->count >= d_allocated)
+	    {
+	      char_directive *memory;
+
+	      d_allocated = 2 * d_allocated;
+	      memory = realloc (d->dir, d_allocated * sizeof (char_directive));
+	      if (memory == NULL)
+		/* Out of memory.  */
+		goto error;
+	      d->dir = memory;
+	    }
+	}
+    }
+  d->dir[d->count].dir_start = cp;
+
+  d->max_width_length = max_width_length;
+  d->max_precision_length = max_precision_length;
+  return 0;
+
+error:
+  if (a->arg)
+    free (a->arg);
+  if (d->dir)
+    free (d->dir);
+  return -1;
+}
new file mode 100644
--- /dev/null
+++ b/lib/printf-parse.h
@@ -0,0 +1,72 @@
+/* Parse printf format string.
+   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _PRINTF_PARSE_H
+#define _PRINTF_PARSE_H
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP	 1	/* ' flag */
+#define FLAG_LEFT	 2	/* - flag */
+#define FLAG_SHOWSIGN	 4	/* + flag */
+#define FLAG_SPACE	 8	/* space flag */
+#define FLAG_ALT	16	/* # flag */
+#define FLAG_ZERO	32
+
+/* A parsed directive.  */
+typedef struct
+{
+  const char* dir_start;
+  const char* dir_end;
+  int flags;
+  const char* width_start;
+  const char* width_end;
+  int width_arg_index;
+  const char* precision_start;
+  const char* precision_end;
+  int precision_arg_index;
+  char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+  int arg_index;
+}
+char_directive;
+
+/* A parsed format string.  */
+typedef struct
+{
+  unsigned int count;
+  char_directive *dir;
+  unsigned int max_width_length;
+  unsigned int max_precision_length;
+}
+char_directives;
+
+
+/* Parses the format string.  Fills in the number N of directives, and fills
+   in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+   to the end of the format string.  Also fills in the arg_type fields of the
+   arguments and the needed count of arguments.  */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_parse (const char *format, char_directives *d, arguments *a);
+
+#endif /* _PRINTF_PARSE_H */
new file mode 100644
--- /dev/null
+++ b/lib/vasnprintf.c
@@ -0,0 +1,767 @@
+/* vsprintf with automatic memory allocation.
+   Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
+   This must come before <config.h> because <config.h> may include
+   <features.h>, and once <features.h> has been included, it's too late.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE    1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <alloca.h>
+
+/* Specification.  */
+#include "vasnprintf.h"
+
+#include <stdio.h>	/* snprintf(), sprintf() */
+#include <stdlib.h>	/* abort(), malloc(), realloc(), free() */
+#include <string.h>	/* memcpy(), strlen() */
+#include <errno.h>	/* errno */
+#include <limits.h>	/* CHAR_BIT */
+#include <float.h>	/* DBL_MAX_EXP, LDBL_MAX_EXP */
+#include "printf-parse.h"
+
+/* For those losing systems which don't have 'alloca' we have to add
+   some additional code emulating it.  */ 
+#ifdef HAVE_ALLOCA 
+# define freea(p) /* nothing */
+#else
+# define alloca(n) malloc (n) 
+# define freea(p) free (p) 
+#endif
+
+char *
+vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
+{
+  char_directives d;
+  arguments a;
+
+  if (printf_parse (format, &d, &a) < 0)
+    {
+      errno = EINVAL;
+      return NULL;
+    }
+
+#define CLEANUP() \
+  free (d.dir);								\
+  if (a.arg)								\
+    free (a.arg);
+
+  if (printf_fetchargs (args, &a) < 0)
+    {
+      CLEANUP ();
+      errno = EINVAL;
+      return NULL;
+    }
+
+  {
+    char *buf =
+      (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6);
+    const char *cp;
+    unsigned int i;
+    char_directive *dp;
+    /* Output string accumulator.  */
+    char *result;
+    size_t allocated;
+    size_t length;
+
+    if (resultbuf != NULL)
+      {
+	result = resultbuf;
+	allocated = *lengthp;
+      }
+    else
+      {
+	result = NULL;
+	allocated = 0;
+      }
+    length = 0;
+    /* Invariants:
+       result is either == resultbuf or == NULL or malloc-allocated.
+       If length > 0, then result != NULL.  */
+
+#define ENSURE_ALLOCATION(needed) \
+    if ((needed) > allocated)						\
+      {									\
+	char *memory;							\
+									\
+	allocated = (allocated > 0 ? 2 * allocated : 12);		\
+	if ((needed) > allocated)					\
+	  allocated = (needed);						\
+	if (result == resultbuf || result == NULL)			\
+	  memory = (char *) malloc (allocated);				\
+	else								\
+	  memory = (char *) realloc (result, allocated);		\
+									\
+	if (memory == NULL)						\
+	  {								\
+	    if (!(result == resultbuf || result == NULL))		\
+	      free (result);						\
+	    freea (buf);						\
+	    CLEANUP ();							\
+	    errno = ENOMEM;						\
+	    return NULL;						\
+	  }								\
+	if (result == resultbuf && length > 0)				\
+	  memcpy (memory, result, length);				\
+	result = memory;						\
+      }
+
+    for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
+      {
+	if (cp != dp->dir_start)
+	  {
+	    size_t n = dp->dir_start - cp;
+
+	    ENSURE_ALLOCATION (length + n);
+	    memcpy (result + length, cp, n);
+	    length += n;
+	  }
+	if (i == d.count)
+	  break;
+
+	/* Execute a single directive.  */
+	if (dp->conversion == '%')
+	  {
+	    if (!(dp->arg_index < 0))
+	      abort ();
+	    ENSURE_ALLOCATION (length + 1);
+	    result[length] = '%';
+	    length += 1;
+	  }
+	else
+	  {
+	    if (!(dp->arg_index >= 0))
+	      abort ();
+
+	    if (dp->conversion == 'n')
+	      {
+		switch (a.arg[dp->arg_index].type)
+		  {
+		  case TYPE_COUNT_SCHAR_POINTER:
+		    *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
+		    break;
+		  case TYPE_COUNT_SHORT_POINTER:
+		    *a.arg[dp->arg_index].a.a_count_short_pointer = length;
+		    break;
+		  case TYPE_COUNT_INT_POINTER:
+		    *a.arg[dp->arg_index].a.a_count_int_pointer = length;
+		    break;
+		  case TYPE_COUNT_LONGINT_POINTER:
+		    *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
+		    break;
+#ifdef HAVE_LONG_LONG
+		  case TYPE_COUNT_LONGLONGINT_POINTER:
+		    *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
+		    break;
+#endif
+		  default:
+		    abort ();
+		  }
+	      }
+	    else
+	      {
+		arg_type type = a.arg[dp->arg_index].type;
+		char *p;
+		unsigned int prefix_count;
+		int prefixes[2];
+#if !HAVE_SNPRINTF
+		unsigned int tmp_length;
+		char tmpbuf[700];
+		char *tmp;
+
+		/* Allocate a temporary buffer of sufficient size for calling
+		   sprintf.  */
+		{
+		  unsigned int width;
+		  unsigned int precision;
+
+		  width = 0;
+		  if (dp->width_start != dp->width_end)
+		    {
+		      if (dp->width_arg_index >= 0)
+			{
+			  int arg;
+
+			  if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+			    abort ();
+			  arg = a.arg[dp->width_arg_index].a.a_int;
+			  width = (arg < 0 ? -arg : arg);
+			}
+		      else
+			{
+			  const char *digitp = dp->width_start;
+
+			  do
+			    width = width * 10 + (*digitp++ - '0');
+			  while (digitp != dp->width_end);
+			}
+		    }
+
+		  precision = 6;
+		  if (dp->precision_start != dp->precision_end)
+		    {
+		      if (dp->precision_arg_index >= 0)
+			{
+			  int arg;
+
+			  if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+			    abort ();
+			  arg = a.arg[dp->precision_arg_index].a.a_int;
+			  precision = (arg < 0 ? 0 : arg);
+			}
+		      else
+			{
+			  const char *digitp = dp->precision_start + 1;
+
+			  precision = 0;
+			  do
+			    precision = precision * 10 + (*digitp++ - '0');
+			  while (digitp != dp->precision_end);
+			}
+		    }
+
+		  switch (dp->conversion)
+		    {
+
+		    case 'd': case 'i': case 'u':
+# ifdef HAVE_LONG_LONG
+		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+					  * 0.30103 /* binary -> decimal */
+					  * 2 /* estimate for FLAG_GROUP */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      else
+# endif
+		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+					  * 0.30103 /* binary -> decimal */
+					  * 2 /* estimate for FLAG_GROUP */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      else
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+					  * 0.30103 /* binary -> decimal */
+					  * 2 /* estimate for FLAG_GROUP */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      break;
+
+		    case 'o':
+# ifdef HAVE_LONG_LONG
+		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+					  * 0.333334 /* binary -> octal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      else
+# endif
+		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+					  * 0.333334 /* binary -> octal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      else
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+					  * 0.333334 /* binary -> octal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 1; /* account for leading sign */
+		      break;
+
+		    case 'x': case 'X':
+# ifdef HAVE_LONG_LONG
+		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+					  * 0.25 /* binary -> hexadecimal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 2; /* account for leading sign or alternate form */
+		      else
+# endif
+		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+					  * 0.25 /* binary -> hexadecimal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 2; /* account for leading sign or alternate form */
+		      else
+			tmp_length =
+			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+					  * 0.25 /* binary -> hexadecimal */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + 2; /* account for leading sign or alternate form */
+		      break;
+
+		    case 'f': case 'F':
+# ifdef HAVE_LONG_DOUBLE
+		      if (type == TYPE_LONGDOUBLE)
+			tmp_length =
+			  (unsigned int) (LDBL_MAX_EXP
+					  * 0.30103 /* binary -> decimal */
+					  * 2 /* estimate for FLAG_GROUP */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + precision
+			  + 10; /* sign, decimal point etc. */
+		      else
+# endif
+			tmp_length =
+			  (unsigned int) (DBL_MAX_EXP
+					  * 0.30103 /* binary -> decimal */
+					  * 2 /* estimate for FLAG_GROUP */
+					 )
+			  + 1 /* turn floor into ceil */
+			  + precision
+			  + 10; /* sign, decimal point etc. */
+		      break;
+
+		    case 'e': case 'E': case 'g': case 'G':
+		    case 'a': case 'A':
+		      tmp_length =
+			precision
+			+ 12; /* sign, decimal point, exponent etc. */
+		      break;
+
+		    case 'c':
+# ifdef HAVE_WINT_T
+		      if (type == TYPE_WIDE_CHAR)
+			tmp_length = MB_CUR_MAX;
+		      else
+# endif
+			tmp_length = 1;
+		      break;
+
+		    case 's':
+# ifdef HAVE_WCHAR_T
+		      if (type == TYPE_WIDE_STRING)
+			tmp_length =
+			  wcslen (a.arg[dp->arg_index].a.a_wide_string)
+			  * MB_CUR_MAX;
+		      else
+# endif
+			tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
+		      break;
+
+		    case 'p':
+		      tmp_length =
+			(unsigned int) (sizeof (void *) * CHAR_BIT
+					* 0.25 /* binary -> hexadecimal */
+				       )
+			  + 1 /* turn floor into ceil */
+			  + 2; /* account for leading 0x */
+		      break;
+
+		    default:
+		      abort ();
+		    }
+
+		  if (tmp_length < width)
+		    tmp_length = width;
+
+		  tmp_length++; /* account for trailing NUL */
+		}
+
+		if (tmp_length <= sizeof (tmpbuf))
+		  tmp = tmpbuf;
+		else
+		  {
+		    tmp = (char *) malloc (tmp_length);
+		    if (tmp == NULL)
+		      {
+			/* Out of memory.  */
+			if (!(result == resultbuf || result == NULL))
+			  free (result);
+			freea (buf);
+			CLEANUP ();
+			errno = ENOMEM;
+			return NULL;
+		      }
+		  }
+#endif
+
+		/* Construct the format string for calling snprintf or
+		   sprintf.  */
+		p = buf;
+		*p++ = '%';
+		if (dp->flags & FLAG_GROUP)
+		  *p++ = '\'';
+		if (dp->flags & FLAG_LEFT)
+		  *p++ = '-';
+		if (dp->flags & FLAG_SHOWSIGN)
+		  *p++ = '+';
+		if (dp->flags & FLAG_SPACE)
+		  *p++ = ' ';
+		if (dp->flags & FLAG_ALT)
+		  *p++ = '#';
+		if (dp->flags & FLAG_ZERO)
+		  *p++ = '0';
+		if (dp->width_start != dp->width_end)
+		  {
+		    size_t n = dp->width_end - dp->width_start;
+		    memcpy (p, dp->width_start, n);
+		    p += n;
+		  }
+		if (dp->precision_start != dp->precision_end)
+		  {
+		    size_t n = dp->precision_end - dp->precision_start;
+		    memcpy (p, dp->precision_start, n);
+		    p += n;
+		  }
+
+		switch (type)
+		  {
+#ifdef HAVE_LONG_LONG
+		  case TYPE_LONGLONGINT:
+		  case TYPE_ULONGLONGINT:
+		    *p++ = 'l';
+		    /*FALLTHROUGH*/
+#endif
+		  case TYPE_LONGINT:
+		  case TYPE_ULONGINT:
+#ifdef HAVE_WINT_T
+		  case TYPE_WIDE_CHAR:
+#endif
+#ifdef HAVE_WCHAR_T
+		  case TYPE_WIDE_STRING:
+#endif
+		    *p++ = 'l';
+		    break;
+#ifdef HAVE_LONG_DOUBLE
+		  case TYPE_LONGDOUBLE:
+		    *p++ = 'L';
+		    break;
+#endif
+		  default:
+		    break;
+		  }
+		*p = dp->conversion;
+#if HAVE_SNPRINTF
+		p[1] = '%';
+		p[2] = 'n';
+		p[3] = '\0';
+#else
+		p[1] = '\0';
+#endif
+
+		/* Construct the arguments for calling snprintf or sprintf.  */
+		prefix_count = 0;
+		if (dp->width_arg_index >= 0)
+		  {
+		    if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+		      abort ();
+		    prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
+		  }
+		if (dp->precision_arg_index >= 0)
+		  {
+		    if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+		      abort ();
+		    prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
+		  }
+
+#if HAVE_SNPRINTF
+		/* Prepare checking whether snprintf returns the count
+		   via %n.  */
+		ENSURE_ALLOCATION (length + 1);
+		result[length] = '\0';
+#endif
+
+		for (;;)
+		  {
+		    size_t maxlen;
+		    int count;
+		    int retcount;
+
+		    maxlen = allocated - length;
+		    count = -1;
+		    retcount = 0;
+
+#if HAVE_SNPRINTF
+#define SNPRINTF_BUF(arg) \
+		    switch (prefix_count)				    \
+		      {							    \
+		      case 0:						    \
+			retcount = snprintf (result + length, maxlen, buf,  \
+					     arg, &count);		    \
+			break;						    \
+		      case 1:						    \
+			retcount = snprintf (result + length, maxlen, buf,  \
+					     prefixes[0], arg, &count);	    \
+			break;						    \
+		      case 2:						    \
+			retcount = snprintf (result + length, maxlen, buf,  \
+					     prefixes[0], prefixes[1], arg, \
+					     &count);			    \
+			break;						    \
+		      default:						    \
+			abort ();					    \
+		      }
+#else
+#define SNPRINTF_BUF(arg) \
+		    switch (prefix_count)				    \
+		      {							    \
+		      case 0:						    \
+			count = sprintf (tmp, buf, arg);		    \
+			break;						    \
+		      case 1:						    \
+			count = sprintf (tmp, buf, prefixes[0], arg);	    \
+			break;						    \
+		      case 2:						    \
+			count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
+					 arg);				    \
+			break;						    \
+		      default:						    \
+			abort ();					    \
+		      }
+#endif
+
+		    switch (type)
+		      {
+		      case TYPE_SCHAR:
+			{
+			  int arg = a.arg[dp->arg_index].a.a_schar;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_UCHAR:
+			{
+			  unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_SHORT:
+			{
+			  int arg = a.arg[dp->arg_index].a.a_short;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_USHORT:
+			{
+			  unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_INT:
+			{
+			  int arg = a.arg[dp->arg_index].a.a_int;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_UINT:
+			{
+			  unsigned int arg = a.arg[dp->arg_index].a.a_uint;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_LONGINT:
+			{
+			  long int arg = a.arg[dp->arg_index].a.a_longint;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_ULONGINT:
+			{
+			  unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#ifdef HAVE_LONG_LONG
+		      case TYPE_LONGLONGINT:
+			{
+			  long long int arg = a.arg[dp->arg_index].a.a_longlongint;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      case TYPE_ULONGLONGINT:
+			{
+			  unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#endif
+		      case TYPE_DOUBLE:
+			{
+			  double arg = a.arg[dp->arg_index].a.a_double;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#ifdef HAVE_LONG_DOUBLE
+		      case TYPE_LONGDOUBLE:
+			{
+			  long double arg = a.arg[dp->arg_index].a.a_longdouble;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#endif
+		      case TYPE_CHAR:
+			{
+			  int arg = a.arg[dp->arg_index].a.a_char;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#ifdef HAVE_WINT_T
+		      case TYPE_WIDE_CHAR:
+			{
+			  wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#endif
+		      case TYPE_STRING:
+			{
+			  const char *arg = a.arg[dp->arg_index].a.a_string;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#ifdef HAVE_WCHAR_T
+		      case TYPE_WIDE_STRING:
+			{
+			  const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+#endif
+		      case TYPE_POINTER:
+			{
+			  void *arg = a.arg[dp->arg_index].a.a_pointer;
+			  SNPRINTF_BUF (arg);
+			}
+			break;
+		      default:
+			abort ();
+		      }
+
+#if HAVE_SNPRINTF
+		    /* Portability: Not all implementations of snprintf()
+		       are ISO C 99 compliant.  Determine the number of
+		       bytes that snprintf() has produced or would have
+		       produced.  */
+		    if (count >= 0)
+		      {
+			/* Verify that snprintf() has NUL-terminated its
+			   result.  */
+			if (count < maxlen && result[length + count] != '\0')
+			  abort ();
+			/* Portability hack.  */
+			if (retcount > count)
+			  count = retcount;
+		      }
+		    else
+		      {
+			/* snprintf() doesn't understand the '%n'
+			   directive.  */
+			if (p[1] != '\0')
+			  {
+			    /* Don't use the '%n' directive; instead, look
+			       at the snprintf() return value.  */
+			    p[1] = '\0';
+			    continue;
+			  }
+			count = retcount;
+		      }
+#endif
+
+		    /* Attempt to handle failure.  */
+		    if (count < 0)
+		      {
+			if (!(result == resultbuf || result == NULL))
+			  free (result);
+			freea (buf);
+			CLEANUP ();
+			errno = EINVAL;
+			return NULL;
+		      }
+
+#if !HAVE_SNPRINTF
+		    if (count >= tmp_length)
+		      /* tmp_length was incorrectly calculated - fix the
+			 code above!  */
+		      abort ();
+#endif
+
+		    /* Make room for the result.  */
+		    if (count >= maxlen)
+		      {
+			/* Need at least count bytes.  But allocate
+			   proportionally, to avoid looping eternally if
+			   snprintf() reports a too small count.  */
+			size_t n = length + count;
+
+			if (n < 2 * allocated)
+			  n = 2 * allocated;
+
+			ENSURE_ALLOCATION (n);
+#if HAVE_SNPRINTF
+			continue;
+#endif
+		      }
+
+#if HAVE_SNPRINTF
+		    /* The snprintf() result did fit.  */
+#else
+		    /* Append the sprintf() result.  */
+		    memcpy (result + length, tmp, count);
+		    if (tmp != tmpbuf)
+		      free (tmp);
+#endif
+
+		    length += count;
+		    break;
+		  }
+	      }
+	  }
+      }
+
+    /* Add the final NUL.  */
+    ENSURE_ALLOCATION (length + 1);
+    result[length] = '\0';
+
+    if (result != resultbuf && length + 1 < allocated)
+      {
+	/* Shrink the allocated memory if possible.  */
+	char *memory;
+
+	memory = (char *) realloc (result, length + 1);
+	if (memory != NULL)
+	  result = memory;
+      }
+
+    freea (buf);
+    CLEANUP ();
+    *lengthp = length;
+    return result;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/lib/vasnprintf.h
@@ -0,0 +1,61 @@
+/* vsprintf with automatic memory allocation.
+   Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _VASNPRINTF_H
+#define _VASNPRINTF_H
+
+/* Get va_list.  */
+#include <stdarg.h>
+
+/* Get size_t.  */
+#include <stddef.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+#  define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+   are accepted by gcc versions 2.6.4 (effectively 2.7) and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+#  define __format__ format
+#  define __printf__ printf
+# endif
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+   You can pass a preallocated buffer for the result in RESULTBUF and its
+   size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+   If successful, return the address of the string (this may be = RESULTBUF
+   if no dynamic memory allocation was necessary) and set *LENGTHP to the
+   number of resulting bytes, excluding the trailing NUL.  Upon error, set
+   errno and return NULL.  */
+extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 3, 4)));
+extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 3, 0)));
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _VASNPRINTF_H */
new file mode 100644
--- /dev/null
+++ b/lib/vasprintf.c
@@ -0,0 +1,38 @@
+/* Formatted output to strings.
+   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "vasprintf.h"
+
+#include "vasnprintf.h"
+
+int
+vasprintf (char **resultp, const char *format, va_list args)
+{
+  size_t length;
+  char *result = vasnprintf (NULL, &length, format, args);
+  if (result == NULL)
+    return -1;
+  *resultp = result;
+  /* Return the number of resulting bytes, excluding the trailing NUL.  */
+  return length;
+}
new file mode 100644
--- /dev/null
+++ b/lib/vasprintf.h
@@ -0,0 +1,64 @@
+/* vsprintf with automatic memory allocation.
+   Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _VASPRINTF_H
+#define _VASPRINTF_H
+
+#if HAVE_VASPRINTF
+
+/* Get asprintf(), vasprintf() declarations.  */
+#include <stdio.h>
+
+#else
+
+/* Get va_list.  */
+#include <stdarg.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+#  define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+   are accepted by gcc versions 2.6.4 (effectively 2.7) and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+#  define __format__ format
+#  define __printf__ printf
+# endif
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+   If the memory allocation succeeds, store the address of the string in
+   *RESULT and return the number of resulting bytes, excluding the trailing
+   NUL.  Upon memory allocation error, or some other error, return -1.  */
+extern int asprintf (char **result, const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 2, 3)));
+extern int vasprintf (char **result, const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif
+
+#endif /* _VASPRINTF_H */
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,12 @@
+2003-01-30  Bruno Haible  <bruno@clisp.org>
+
+	* signed.m4: New file, from GNU gettext.
+	* longdouble.m4: New file, from GNU gettext.
+	* wchar_t.m4: New file, from GNU gettext.
+	* wint_t.m4: New file, from GNU gettext.
+	* vasnprintf.m4: New file.
+	* vasprintf.m4: New file.
+
 2003-01-29  Bruno Haible  <bruno@clisp.org>
 
 	* stpncpy.m4: New file.
new file mode 100644
--- /dev/null
+++ b/m4/longdouble.m4
@@ -0,0 +1,30 @@
+# longdouble.m4 serial 1 (gettext-0.11.6)
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+dnl Test whether the compiler supports the 'long double' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_LONGDOUBLE],
+[
+  AC_CACHE_CHECK([for long double], gt_cv_c_long_double,
+    [if test "$GCC" = yes; then
+       gt_cv_c_long_double=yes
+     else
+       AC_TRY_COMPILE([
+         /* The Stardent Vistra knows sizeof(long double), but does not support it.  */
+         long double foo = 0.0;
+         /* On Ultrix 4.3 cc, long double is 4 and double is 8.  */
+         int array [2*(sizeof(long double) >= sizeof(double)) - 1];
+         ], ,
+         gt_cv_c_long_double=yes, gt_cv_c_long_double=no)
+     fi])
+  if test $gt_cv_c_long_double = yes; then
+    AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.])
+  fi
+])
new file mode 100644
--- /dev/null
+++ b/m4/signed.m4
@@ -0,0 +1,19 @@
+# signed.m4 serial 1 (gettext-0.10.40)
+dnl Copyright (C) 2001-2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([bh_C_SIGNED],
+[
+  AC_CACHE_CHECK([for signed], bh_cv_c_signed,
+   [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)])
+  if test $bh_cv_c_signed = no; then
+    AC_DEFINE(signed, ,
+              [Define to empty if the C compiler doesn't support this keyword.])
+  fi
+])
new file mode 100644
--- /dev/null
+++ b/m4/vasnprintf.m4
@@ -0,0 +1,59 @@
+# vasnprintf.m4 serial 1
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+AC_DEFUN([gl_FUNC_VASNPRINTF],
+[
+  AC_REPLACE_FUNCS(vasnprintf)
+  if test $ac_cv_func_vasnprintf = no; then
+    AC_LIBOBJ(printf-args)
+    AC_LIBOBJ(printf-parse)
+    AC_LIBOBJ(asnprintf)
+    gl_PREREQ_PRINTF_ARGS
+    gl_PREREQ_PRINTF_PARSE
+    gl_PREREQ_VASNPRINTF
+    gl_PREREQ_ASNPRINTF
+  fi
+])
+
+# Prequisites of lib/printf-args.h, lib/printf-args.c.
+AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
+[
+  AC_REQUIRE([bh_C_SIGNED])
+  AC_REQUIRE([jm_AC_TYPE_LONG_LONG])
+  AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+  AC_REQUIRE([gt_TYPE_WCHAR_T])
+  AC_REQUIRE([gt_TYPE_WINT_T])
+])
+
+# Prequisites of lib/printf-parse.h, lib/printf-parse.c.
+AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
+[
+  AC_REQUIRE([jm_AC_TYPE_LONG_LONG])
+  AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+  AC_REQUIRE([gt_TYPE_WCHAR_T])
+  AC_REQUIRE([gt_TYPE_WINT_T])
+  AC_REQUIRE([AC_TYPE_SIZE_T])
+  AC_CHECK_TYPES(ptrdiff_t)
+  AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
+])
+
+# Prerequisites of lib/vasnprintf.c.
+AC_DEFUN([gl_PREREQ_VASNPRINTF],
+[
+  AC_REQUIRE([AC_FUNC_ALLOCA])
+  AC_REQUIRE([jm_AC_TYPE_LONG_LONG])
+  AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+  AC_REQUIRE([gt_TYPE_WCHAR_T])
+  AC_REQUIRE([gt_TYPE_WINT_T])
+  AC_CHECK_FUNCS(snprintf)
+])
+
+# Prerequisites of lib/asnprintf.c.
+AC_DEFUN([gl_PREREQ_ASNPRINTF],
+[
+])
new file mode 100644
--- /dev/null
+++ b/m4/vasprintf.m4
@@ -0,0 +1,27 @@
+# vasprintf.m4 serial 1
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+AC_DEFUN([gl_FUNC_VASPRINTF],
+[
+  AC_REPLACE_FUNCS(vasprintf)
+  if test $ac_cv_func_vasprintf = no; then
+    AC_LIBOBJ(asprintf)
+    gl_PREREQ_VASPRINTF
+    gl_PREREQ_ASPRINTF
+  fi
+])
+
+# Prerequisites of lib/vasprintf.c.
+AC_DEFUN([gl_PREREQ_VASPRINTF],
+[
+])
+
+# Prerequisites of lib/asprintf.c.
+AC_DEFUN([gl_PREREQ_ASPRINTF],
+[
+])
new file mode 100644
--- /dev/null
+++ b/m4/wchar_t.m4
@@ -0,0 +1,22 @@
+# wchar_t.m4 serial 1 (gettext-0.11.6)
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+dnl Test whether <stddef.h> has the 'wchar_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WCHAR_T],
+[
+  AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t,
+    [AC_TRY_COMPILE([#include <stddef.h>
+       wchar_t foo = (wchar_t)'\0';], ,
+       gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)])
+  if test $gt_cv_c_wchar_t = yes; then
+    AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.])
+  fi
+])
new file mode 100644
--- /dev/null
+++ b/m4/wint_t.m4
@@ -0,0 +1,22 @@
+# wint_t.m4 serial 1
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+dnl Test whether <wchar.h> has the 'wint_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WINT_T],
+[
+  AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t,
+    [AC_TRY_COMPILE([#include <wchar.h>
+       wint_t foo = (wchar_t)'\0';], ,
+       gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)])
+  if test $gt_cv_c_wint_t = yes; then
+    AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.])
+  fi
+])
new file mode 100644
--- /dev/null
+++ b/modules/vasnprintf
@@ -0,0 +1,34 @@
+Description:
+vsprintf with automatic memory allocation and bounded output size.
+
+Files:
+lib/printf-args.h
+lib/printf-args.c
+lib/printf-parse.h
+lib/printf-parse.c
+lib/vasnprintf.h
+lib/vasnprintf.c
+lib/asnprintf.c
+m4/signed.m4
+m4/longdouble.m4
+m4/wchar_t.m4
+m4/wint_t.m4
+m4/longlong.m4
+m4/intmax_t.m4
+m4/vasnprintf.m4
+
+Depends-on:
+alloca
+
+configure.ac:
+gl_FUNC_VASNPRINTF
+
+Makefile.am:
+lib_SOURCES += printf-args.h printf-parse.h vasnprintf.h
+
+Include:
+"vasnprintf.h"
+
+Maintainer:
+Bruno Haible
+
new file mode 100644
--- /dev/null
+++ b/modules/vasprintf
@@ -0,0 +1,24 @@
+Description:
+vsprintf with automatic memory allocation.
+
+Files:
+lib/vasprintf.h
+lib/vasprintf.c
+lib/asprintf.c
+m4/vasprintf.m4
+
+Depends-on:
+vasnprintf
+
+configure.ac:
+gl_FUNC_VASPRINTF
+
+Makefile.am:
+lib_SOURCES += vasprintf.h
+
+Include:
+"vasprintf.h"
+
+Maintainer:
+Bruno Haible
+