Use estream_asprintf instead of the GNU asprintf.
authorWerner Koch <wk@gnupg.org>
Tue, 15 May 2007 16:10:48 +0000 (16:10 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 15 May 2007 16:10:48 +0000 (16:10 +0000)
25 files changed:
ChangeLog
NEWS
README.maint
TODO
agent/ChangeLog
agent/protect.c
common/ChangeLog
common/Makefile.am
common/estream-printf.c [new file with mode: 0644]
common/estream-printf.h [new file with mode: 0644]
common/estream.c
common/estream.h
common/sexp-parse.h
common/sexputil.c
common/util.h
common/vasprintf.c [deleted file]
common/xasprintf.c
configure.ac
doc/ChangeLog
doc/examples/gpgconf.conf
doc/gpgsm.texi
gl/Makefile.am
m4/ChangeLog
m4/Makefile.am
m4/estream.m4 [new file with mode: 0644]

index 4817794..88cc4b4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2007-05-15  Werner Koch  <wk@g10code.com>
+
+       * configure.ac:  Call ESTREAM_INIT and define the memory
+       allocators for estream_asprintf.
+       (gl_MODULES): Remove vasprintf.
+
 2007-05-09  Werner Koch  <wk@g10code.com>
 
        Released 2.0.4.
diff --git a/NEWS b/NEWS
index 4fe8813..14455b5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Noteworthy changes in version 2.0.5
+------------------------------------------------
+
+
 Noteworthy changes in version 2.0.4 (2007-05-09)
 ------------------------------------------------
 
index 8bd169a..61643c8 100644 (file)
@@ -30,16 +30,18 @@ Release process:
   * Run "./autogen.sh --force"
     (--force is required for the svn magic in configure.ac and a good
     idea in any case)
+  * Run configure as usual.
   * Run "make distcheck"
   * Build and test the new tarball (best on a different machine).
-  * [1.4 only] Build and test the W32 vesion.
+  * [1.4 only] Build and test the W32 version.
+  * Using the final test build run a "make -C doc online".
   * Sign the tarball
   * Get the previous tarball and run "mkdiff gnupg".  
     You might need to set a different signature key than mine.  mkdiff
     has an option for this.
-  * If you are satisied with the result tag the release.  Use "svn
+  * If you are satisfied with the result tag the release.  Use "svn
     info" to get the current URL and use an svn cp command similar to
-    "svn cp svn+ssh://host/gnupg/trunk  svn+ssh://host/gnupg/tags/2.n.m"
+    "svn cp svn+ssh://host/gnupg/trunk  svn+ssh://host/gnupg/tags/gnupg-2.n.m"
     (for 1.4 you should see "branches/STABLE-BRANCH-1-4" instead of "trunk",
      however tags are all below tags).
   * Copy the files to the FTP server
diff --git a/TODO b/TODO
index c860883..954ffe7 100644 (file)
--- a/TODO
+++ b/TODO
    scdaemon stays as a zombie and gpg-agent does not perform any more
    commands.
 
+* Howtos
+** Migrate OpenPGP keys to another system
 
 
 
index 5d1ce5d..ce8b874 100644 (file)
@@ -1,3 +1,7 @@
+2007-05-14  Werner Koch  <wk@g10code.com>
+
+       * protect.c (make_shadow_info): Replace sprintf by smklen.
+
 2007-04-20  Werner Koch  <wk@g10code.com>
 
        * gpg-agent.c (my_gcry_logger, my_gcry_outofcore_handler): Removed.
index 2bb38f3..ee1b5ec 100644 (file)
@@ -1,6 +1,6 @@
 /* protect.c - Un/Protect a secret key
  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
- *               2003 Free Software Foundation, Inc.
+ *               2003, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -846,23 +846,21 @@ make_shadow_info (const char *serialno, const char *idstring)
 {
   const char *s;
   char *info, *p;
-  char numbuf[21];
-  int n;
+  char numbuf[20];
+  size_t n;
 
   for (s=serialno, n=0; *s && s[1]; s += 2)
     n++;
 
-  info = p = xtrymalloc (1 + 21 + n
-                           + 21 + strlen (idstring) + 1 + 1);
+  info = p = xtrymalloc (1 + sizeof numbuf + n
+                           + sizeof numbuf + strlen (idstring) + 1 + 1);
   if (!info)
     return NULL;
   *p++ = '(';
-  sprintf (numbuf, "%d:", n);
-  p = stpcpy (p, numbuf);
+  p = stpcpy (p, smklen (numbuf, sizeof numbuf, n, NULL));
   for (s=serialno; *s && s[1]; s += 2)
     *(unsigned char *)p++ = xtoi_2 (s);
-  sprintf (numbuf, "%u:", (unsigned int)strlen (idstring));
-  p = stpcpy (p, numbuf);
+  p = stpcpy (p, smklen (numbuf, sizeof numbuf, strlen (idstring), NULL));
   p = stpcpy (p, idstring);
   *p++ = ')';
   *p = 0;
index 797f119..5c76973 100644 (file)
@@ -1,3 +1,20 @@
+2007-05-15  Werner Koch  <wk@g10code.com>
+
+       * util.h: Do not include gnulib's vasprintf.  Redefine asprintf
+       and vasprintf.
+
+       * xasprintf.c (xasprintf, xtryasprintf): Use estream_vasprintf.
+
+       * estream-printf.h, estream-printf.c: New.  Taken from current
+       libestream SVN.
+       * Makefile.am (common_sources): Add them.
+
+2007-05-14  Werner Koch  <wk@g10code.com>
+
+       * sexp-parse.h (smklen): New.
+       * sexputil.c: Include sexp-parse.h.
+       (make_simple_sexp_from_hexstr): Replace sprintf by smklen.
+
 2007-05-07  Werner Koch  <wk@g10code.com>
 
        * signal.c (got_fatal_signal): Protect SIG from being clobbered by
index a0b27a1..237c899 100644 (file)
@@ -54,7 +54,7 @@ common_sources = \
        w32reg.c \
        signal.c \
        dynload.h \
-       estream.c estream.h \
+       estream.c estream.h estream-printf.c estream-printf.h \
        srv.c srv.h \
        dns-cert.c dns-cert.h \
        pka.c pka.h \
diff --git a/common/estream-printf.c b/common/estream-printf.c
new file mode 100644 (file)
index 0000000..dcbb807
--- /dev/null
@@ -0,0 +1,2139 @@
+/* estream-printf.c - Versatile C-99 compliant printf formatting
+ * Copyright (C) 2007 g10 Code GmbH
+ *
+ * This file is part of Libestream.
+ *
+ * Libestream is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * Libestream is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Libestream; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * $Id: estream-printf.c 54 2007-05-15 14:12:06Z wk $
+ */
+
+/*  Required autoconf tests:
+
+    AC_TYPE_LONG_LONG_INT            defines HAVE_LONG_LONG_INT
+    AC_TYPE_LONG_DOUBLE              defines HAVE_LONG_DOUBLE
+    AC_TYPE_INTMAX_T                 defines HAVE_INTMAX_T
+    AC_TYPE_UINTMAX_T                defines HAVE_UINTMAX_T
+    AC_CHECK_TYPES([ptrdiff_t])      defines HAVE_PTRDIFF_T
+    AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG
+    AC_CHECK_SIZEOF([void *])        defines SIZEOF_VOID_P
+                                             HAVE_LANGINFO_THOUSANDS_SEP
+
+    Note that the file estream.m4 provides the autoconf macro
+    ESTREAM_PRINTF_INIT which runs all required checks.
+
+
+  Missing stuff:  wchar and wint_t
+                  thousands_sep in pr_float.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stddef.h>
+#include <assert.h>
+#if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T)
+# include <stdint.h>
+#endif
+#ifdef HAVE_LANGINFO_THOUSANDS_SEP
+#include <langinfo.h>
+#endif
+#ifdef TEST
+# include <locale.h>
+#endif
+#ifdef ESTREAM_PRINTF_EXTRA_INCLUDE
+#include ESTREAM_PRINTF_EXTRA_INCLUDE
+#endif
+#include "estream-printf.h"
+
+/* Allow redefinition of asprintf used malloc functions.  */
+#ifdef ESTREAM_ASPRINTF_MALLOC
+#define my_asprintf_malloc(a) ESTREAM_ASPRINTF_MALLOC((a))  
+#else
+#define my_asprintf_malloc(a) malloc((a))
+#endif
+#ifdef ESTREAM_ASPRINTF_FREE
+#define my_asprintf_free(a)   ESTREAM_ASPRINTF_FREE((a))  
+#else
+#define my_asprintf_free(a)   free((a))
+#endif
+
+
+/* Calculate array dimension.  */
+#ifndef DIM
+#define DIM(array) (sizeof (array) / sizeof (*array))
+#endif
+
+
+/* We allow for that many args without requiring malloced memory. */
+#define DEFAULT_MAX_ARGSPECS  5
+
+/* We allow for that many values without requiring malloced memory. */
+#define DEFAULT_MAX_VALUES  8
+
+/* We allocate this many new array argspec elements each time.  */
+#define ARGSPECS_BUMP_VALUE   10
+
+/* Special values for the field width and the precision.  */
+#define NO_FIELD_VALUE   (-1)
+#define STAR_FIELD_VALUE (-2)
+
+/* Bit valuues used for the conversion flags. */
+#define FLAG_GROUPING   1
+#define FLAG_LEFT_JUST  2
+#define FLAG_PLUS_SIGN  4
+#define FLAG_SPACE_PLUS 8
+#define FLAG_ALT_CONV   16
+#define FLAG_ZERO_PAD   32
+
+/* Constants used the length modifiers.  */
+typedef enum
+  {
+    LENMOD_NONE = 0,
+    LENMOD_CHAR,     /* "hh" */
+    LENMOD_SHORT,    /* "h"  */
+    LENMOD_LONG,     /* "l"  */
+    LENMOD_LONGLONG, /* "ll" */
+    LENMOD_INTMAX,   /* "j"  */
+    LENMOD_SIZET,    /* "z"  */
+    LENMOD_PTRDIFF,  /* "t"  */
+    LENMOD_LONGDBL   /* "L"  */
+  } lenmod_t;
+
+/* All the conversion specifiers.  */
+typedef enum
+  {
+    CONSPEC_UNKNOWN = 0,
+    CONSPEC_DECIMAL,
+    CONSPEC_OCTAL,
+    CONSPEC_UNSIGNED,
+    CONSPEC_HEX,
+    CONSPEC_HEX_UP,
+    CONSPEC_FLOAT,
+    CONSPEC_FLOAT_UP,
+    CONSPEC_EXP,
+    CONSPEC_EXP_UP,
+    CONSPEC_F_OR_G,
+    CONSPEC_F_OR_G_UP,
+    CONSPEC_HEX_EXP,
+    CONSPEC_HEX_EXP_UP,
+    CONSPEC_CHAR,
+    CONSPEC_STRING,
+    CONSPEC_POINTER,
+    CONSPEC_STRERROR,
+    CONSPEC_BYTES_SO_FAR
+  } conspec_t;
+
+
+/* Constants describing all the suppoorted types.  Note that we list
+   all the types we know about even if certain types are not available
+   on this system. */
+typedef enum
+  {
+    VALTYPE_UNSUPPORTED = 0,  /* Artificial type for error detection.  */
+    VALTYPE_CHAR,
+    VALTYPE_SCHAR,
+    VALTYPE_UCHAR,
+    VALTYPE_SHORT,
+    VALTYPE_USHORT,
+    VALTYPE_INT,
+    VALTYPE_UINT,
+    VALTYPE_LONG,
+    VALTYPE_ULONG,
+    VALTYPE_LONGLONG,
+    VALTYPE_ULONGLONG,
+    VALTYPE_DOUBLE,
+    VALTYPE_LONGDOUBLE,
+    VALTYPE_STRING,
+    VALTYPE_INTMAX,
+    VALTYPE_UINTMAX,
+    VALTYPE_SIZE,
+    VALTYPE_PTRDIFF,
+    VALTYPE_POINTER,
+    VALTYPE_CHAR_PTR,
+    VALTYPE_SCHAR_PTR,
+    VALTYPE_SHORT_PTR,
+    VALTYPE_INT_PTR,
+    VALTYPE_LONG_PTR,
+    VALTYPE_LONGLONG_PTR,
+    VALTYPE_INTMAX_PTR,
+    VALTYPE_SIZE_PTR,
+    VALTYPE_PTRDIFF_PTR
+  } valtype_t;
+
+
+/* A union used to store the actual values. */
+typedef union 
+{
+  char a_char;
+  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_long;
+  unsigned long int a_ulong;
+#ifdef HAVE_LONG_LONG_INT
+  long long int a_longlong;
+  unsigned long long int a_ulonglong;
+#endif
+  double a_double;
+#ifdef HAVE_LONG_DOUBLE
+  long double a_longdouble;
+#endif
+  const char *a_string;
+#ifdef HAVE_INTMAX_T
+  intmax_t a_intmax;
+#endif
+#ifdef HAVE_UINTMAX_T
+  intmax_t a_uintmax;
+#endif
+  size_t a_size;
+#ifdef HAVE_PTRDIFF_T
+  ptrdiff_t a_ptrdiff;
+#endif
+  void *a_void_ptr;
+  char *a_char_ptr;
+  signed char *a_schar_ptr;
+  short *a_short_ptr;
+  int  *a_int_ptr;
+  long *a_long_ptr;
+#ifdef HAVE_LONG_LONG_INT
+  long long int *a_longlong_ptr;
+#endif
+#ifdef HAVE_INTMAX_T
+  intmax_t *a_intmax_ptr;
+#endif
+  size_t *a_size_ptr;
+#ifdef HAVE_PTRDIFF_T
+  ptrdiff_t *a_ptrdiff_ptr;
+#endif
+} value_t;
+
+/* An object used to keep track of a format option and arguments. */
+struct argspec_s
+{
+  size_t length;       /* The length of these args including the percent.  */
+  unsigned int flags;  /* The conversion flags (bits defined by FLAG_foo).  */
+  int width;           /* The field width.  */
+  int precision;       /* The precision.  */
+  lenmod_t lenmod;     /* The length modifier.  */
+  conspec_t conspec;   /* The conversion specifier.  */
+  int arg_pos;         /* The position of the argument.  This one may
+                          be -1 to indicate that no value is expected
+                          (e.g. for "%m").  */
+  int width_pos;       /* The position of the argument for a field
+                          width star's value. 0 for not used.  */
+  int precision_pos;   /* The position of the argument for the a
+                          precision star's value.  0 for not used. */
+  valtype_t vt;        /* The type of the corresponding argument.  */
+};
+typedef struct argspec_s *argspec_t;
+
+/* An object to build up a table of values and their types.  */
+struct valueitem_s
+{
+  valtype_t vt;  /* The type of the value.  */
+  value_t value; /* The value.  */
+};
+typedef struct valueitem_s *valueitem_t;
+
+
+#ifdef TEST
+static int verbose; 
+
+static void
+dump_argspecs (argspec_t arg, size_t argcount)
+{
+  int idx;
+
+  for (idx=0; argcount; argcount--, arg++, idx++)
+    fprintf (stderr, 
+             "%2d: len=%u flags=%u width=%d prec=%d mod=%d "
+             "con=%d vt=%d pos=%d-%d-%d\n",
+             idx,
+             (unsigned int)arg->length,
+             arg->flags,
+             arg->width,
+             arg->precision,
+             arg->lenmod,
+             arg->conspec,
+             arg->vt,
+             arg->arg_pos,
+             arg->width_pos,
+             arg->precision_pos);
+}
+#endif /*TEST*/
+
+
+/* Set the vt field for ARG.  */
+static void
+compute_type (argspec_t arg)
+{
+  switch (arg->conspec)
+    {
+    case CONSPEC_UNKNOWN: 
+      arg->vt = VALTYPE_UNSUPPORTED; 
+      break;
+
+    case CONSPEC_DECIMAL:
+      switch (arg->lenmod)
+        {
+        case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break;
+        case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break;
+        case LENMOD_LONG: arg->vt = VALTYPE_LONG; break;
+        case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break;
+        case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break;
+        case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;   
+        case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
+        default: arg->vt = VALTYPE_INT; break;
+        }
+      break;
+
+    case CONSPEC_OCTAL:
+    case CONSPEC_UNSIGNED:
+    case CONSPEC_HEX:
+    case CONSPEC_HEX_UP:
+      switch (arg->lenmod)
+        {
+        case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break;
+        case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break;
+        case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break;
+        case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break;
+        case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break;
+        case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break;   
+        case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break;
+        default: arg->vt = VALTYPE_UINT; break;
+        }
+      break;
+      
+    case CONSPEC_FLOAT:
+    case CONSPEC_FLOAT_UP:
+    case CONSPEC_EXP:
+    case CONSPEC_EXP_UP:
+    case CONSPEC_F_OR_G:
+    case CONSPEC_F_OR_G_UP:
+    case CONSPEC_HEX_EXP:
+    case CONSPEC_HEX_EXP_UP:
+      switch (arg->lenmod)
+        {
+        case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break;
+        case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break;
+        default: arg->vt = VALTYPE_DOUBLE; break;
+        }
+      break;
+      
+    case CONSPEC_CHAR:
+      arg->vt = VALTYPE_INT; 
+      break;
+
+    case CONSPEC_STRING:
+      arg->vt = VALTYPE_STRING;
+      break;
+
+    case CONSPEC_POINTER:
+      arg->vt = VALTYPE_POINTER;
+      break;
+
+    case CONSPEC_STRERROR:
+      arg->vt = VALTYPE_STRING;
+      break;
+
+    case CONSPEC_BYTES_SO_FAR:
+      switch (arg->lenmod)
+        {
+        case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break;
+        case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break;
+        case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break;
+        case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break;
+        case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break;
+        case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break;   
+        case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break;
+        default: arg->vt = VALTYPE_INT_PTR; break;
+        }
+      break;
+      
+    }
+}
+
+
+
+/* Parse the FORMAT string and populate the specification array stored
+   at the address ARGSPECS_ADDR.  The caller has provided enough space
+   to store up to MAX_ARGSPECS in that buffer.  The function may
+   however ignore the provided buffer and malloc a larger one.  On
+   success the addrrss of that larger buffer will be stored at
+   ARGSPECS_ADDR.  The actual number of specifications will be
+   returned at R_ARGSPECS_COUNT. */
+static int
+parse_format (const char *format,
+              argspec_t *argspecs_addr, size_t max_argspecs,
+              size_t *r_argspecs_count)
+{
+  const char *s;
+  argspec_t argspecs = *argspecs_addr;
+  argspec_t arg;
+  size_t argcount = 0;
+
+  if (!format)
+    goto leave_einval;
+      
+  for (; *format; format++)
+    {
+      unsigned int flags;
+      int width, precision;
+      lenmod_t lenmod;
+      conspec_t conspec;
+      int arg_pos, width_pos, precision_pos;
+      
+      if (*format != '%')
+        continue;
+      s = ++format;
+      if (!*s)
+        goto leave_einval;
+      if (*s == '%')
+        continue; /* Just a quoted percent.  */
+
+      /* First check whether there is a positional argument.  */
+      arg_pos = 0; /* No positional argument given.  */
+      if (*s >= '1' && *s <= '9')
+        {
+          const char *save_s = s;
+          
+          arg_pos = (*s++ - '0');
+          for (; *s >= '0' && *s <= '9'; s++)
+            arg_pos = 10*arg_pos + (*s - '0');
+          if (arg_pos < 0)
+            goto leave_einval; /* Overflow during conversion.  */
+          if (*s == '$')
+            s++;
+          else
+            {
+              arg_pos = 0;
+              s = save_s;
+            }
+        }
+         
+      /* Parse the flags.  */
+      flags = 0;
+      for ( ; *s; s++)
+        {
+          switch (*s)
+            {
+            case '\'': flags |= FLAG_GROUPING; break;
+            case '-': flags |= FLAG_LEFT_JUST; break;
+            case '+': flags |= FLAG_PLUS_SIGN; break;
+            case ' ': flags |= FLAG_SPACE_PLUS; break;
+            case '#': flags |= FLAG_ALT_CONV; break;
+            case '0': flags |= FLAG_ZERO_PAD; break;
+            default:
+              goto flags_parsed;
+            }
+        }
+    flags_parsed:
+      
+      /* Parse the field width.  */
+      width_pos = 0;
+      if (*s == '*')
+        {
+          width = STAR_FIELD_VALUE;
+          s++;
+          /* If we have a positional argument, another one might also
+             be used to give the position of the star's value. */
+          if (arg_pos && *s >= '1' && *s <= '9')
+            {
+              width_pos = (*s++ - '0');
+              for (; *s >= '0' && *s <= '9'; s++)
+                width_pos = 10*width_pos + (*s - '0');
+              if (width_pos < 1)
+                goto leave_einval; /* Overflow during conversion.  */
+              if (*s != '$')
+                goto leave_einval; /* Not followed by $.  */
+              s++;
+            }
+        }
+      else if ( *s >= '0' && *s <= '9')
+        {
+          width = (*s++ - '0');
+          for (; *s >= '0' && *s <= '9'; s++)
+            {
+              if (!width && *s == '0')
+                goto leave_einval; /* Leading zeroes are not allowed.
+                                      Fixme: check what other
+                                      implementations do. */
+              width = 10*width + (*s - '0');
+            }
+          if (width < 0)
+            goto leave_einval; /* Overflow during conversion.  */
+        }
+      else
+        width = NO_FIELD_VALUE;
+
+      /* Parse the precision.  */
+      precision_pos = 0;
+      precision = NO_FIELD_VALUE;
+      if (*s == '.')
+        {
+          int ignore_value = (s[1] == '-');
+
+          s++;
+          if (*s == '*')
+            {
+              precision = STAR_FIELD_VALUE;
+              s++;
+              /* If we have a positional argument, another one might also
+                 be used to give the position of the star's value. */
+              if (arg_pos && *s >= '1' && *s <= '9')
+                {
+                  precision_pos = (*s++ - '0');
+                  for (; *s >= '0' && *s <= '9'; s++)
+                    precision_pos = 10*precision_pos + (*s - '0');
+                  if (precision_pos < 1)
+                    goto leave_einval; /* Overflow during conversion.  */
+                  if (*s != '$')
+                    goto leave_einval; /* Not followed by $.  */
+                  s++;
+                }
+            }
+          else if ( *s >= '0' && *s <= '9')
+            {
+              precision = (*s++ - '0');
+              for (; *s >= '0' && *s <= '9'; s++)
+                {
+                  if (!precision && *s == '0')
+                    goto leave_einval; /* Leading zeroes are not allowed.
+                                          Fixme: check what other
+                                          implementations do. */
+                  precision = 10*precision + (*s - '0');
+                }
+              if (precision < 0)
+                goto leave_einval; /* Overflow during conversion.  */
+            }
+          else
+            precision = 0;
+          if (ignore_value)
+            precision = NO_FIELD_VALUE;
+        }
+      
+      /* Parse the length modifiers.  */
+      switch (*s)
+        {
+        case 'h': 
+          if (s[1] == 'h')
+            {
+              lenmod = LENMOD_CHAR;
+              s++;
+            }
+          else
+            lenmod = LENMOD_SHORT;
+          s++;
+          break;
+        case 'l':
+          if (s[1] == 'l')
+            {
+              lenmod = LENMOD_LONGLONG;
+              s++;
+            }
+          else
+            lenmod = LENMOD_LONG;
+          s++;
+          break;
+        case 'j': lenmod = LENMOD_INTMAX; s++; break;
+        case 'z': lenmod = LENMOD_SIZET; s++; break;
+        case 't': lenmod = LENMOD_PTRDIFF; s++; break;
+        case 'L': lenmod = LENMOD_LONGDBL; s++; break;
+        default:  lenmod = LENMOD_NONE; break;
+        }
+      
+      /* Parse the conversion specifier.  */
+      switch (*s)
+        {
+        case 'd':
+        case 'i': conspec = CONSPEC_DECIMAL; break;
+        case 'o': conspec = CONSPEC_OCTAL; break;
+        case 'u': conspec = CONSPEC_UNSIGNED; break;
+        case 'x': conspec = CONSPEC_HEX; break;
+        case 'X': conspec = CONSPEC_HEX_UP; break;
+        case 'f': conspec = CONSPEC_FLOAT; break;
+        case 'F': conspec = CONSPEC_FLOAT_UP; break;
+        case 'e': conspec = CONSPEC_EXP; break;
+        case 'E': conspec = CONSPEC_EXP_UP; break;
+        case 'g': conspec = CONSPEC_F_OR_G; break;
+        case 'G': conspec = CONSPEC_F_OR_G_UP; break;
+        case 'a': conspec = CONSPEC_HEX_EXP; break;
+        case 'A': conspec = CONSPEC_HEX_EXP_UP; break;
+        case 'c': conspec = CONSPEC_CHAR; break;
+        case 's': conspec = CONSPEC_STRING; break;
+        case 'p': conspec = CONSPEC_POINTER; break;
+        case 'n': conspec = CONSPEC_BYTES_SO_FAR; break;
+        case 'C': conspec = CONSPEC_CHAR; lenmod = LENMOD_LONG; break;
+        case 'S': conspec = CONSPEC_STRING; lenmod = LENMOD_LONG; break;
+        case 'm': conspec = CONSPEC_STRERROR; arg_pos = -1; break;
+        default: conspec = CONSPEC_UNKNOWN;
+        }
+
+      /* Save the args. */
+      if (argcount >= max_argspecs)
+        {
+          /* We either need to allocate a new array instead of the
+             caller provided one or realloc the array.  Instead of
+             using realloc we allocate a new one and release the
+             original one then. */
+          size_t n, newmax;
+          argspec_t newarg;
+
+          newmax = max_argspecs + ARGSPECS_BUMP_VALUE;
+          if (newmax <= max_argspecs)
+            goto leave_einval;  /* Too many arguments. */
+          newarg = calloc (newmax, sizeof *newarg);
+          if (!newarg)
+            goto leave;
+          for (n=0; n < argcount; n++)
+            newarg[n] = argspecs[n];
+          if (argspecs != *argspecs_addr)
+            free (argspecs);
+          argspecs = newarg;
+          max_argspecs = newmax;
+        }
+
+      arg = argspecs + argcount;
+      arg->length = s - format + 2;
+      arg->flags = flags;
+      arg->width = width;
+      arg->precision = precision;
+      arg->lenmod = lenmod;
+      arg->conspec = conspec;
+      arg->arg_pos = arg_pos;
+      arg->width_pos = width_pos;
+      arg->precision_pos = precision_pos;
+      compute_type (arg);
+      argcount++;
+      format = s;
+    }
+
+  *argspecs_addr = argspecs;
+  *r_argspecs_count = argcount;
+  return 0; /* Success.  */
+  
+ leave_einval:
+  errno = EINVAL;
+ leave:
+  if (argspecs != *argspecs_addr)
+    free (argspecs);
+  *argspecs_addr = NULL;
+  return -1;
+}
+
+/* This function is used for testing to provide default arguments.  */
+static int
+read_dummy_value (value_t *value, valtype_t vt)
+{
+  switch (vt)
+    {
+    case VALTYPE_CHAR: value->a_char = 'a'; break;
+    case VALTYPE_CHAR_PTR: value->a_char_ptr = NULL; break;
+    case VALTYPE_SCHAR: value->a_schar = 'a'; break;
+    case VALTYPE_SCHAR_PTR: value->a_schar_ptr = NULL; break;
+    case VALTYPE_UCHAR: value->a_uchar = 'a'; break;
+    case VALTYPE_SHORT: value->a_short = -4711; break;
+    case VALTYPE_USHORT: value->a_ushort = 4711; break;
+    case VALTYPE_SHORT_PTR: value->a_short_ptr = NULL; break;
+    case VALTYPE_INT: value->a_int = 42; break;
+    case VALTYPE_INT_PTR: value->a_int_ptr = NULL; break;
+    case VALTYPE_UINT: value->a_uint = 65535; break;
+    case VALTYPE_LONG: value->a_long = 11071961; break;
+    case VALTYPE_ULONG: value->a_ulong = 19610711; break;
+    case VALTYPE_LONG_PTR: value->a_long_ptr = NULL; break;
+#ifdef HAVE_LONG_LONG_INT
+    case VALTYPE_LONGLONG: value->a_longlong = 11223344; break;
+    case VALTYPE_ULONGLONG: value->a_ulonglong = 2233445566u; break;
+    case VALTYPE_LONGLONG_PTR: value->a_longlong_ptr = NULL; break;
+#endif
+    case VALTYPE_DOUBLE: value->a_double = 3.1415926535; break;
+#ifdef HAVE_LONG_DOUBLE
+    case VALTYPE_LONGDOUBLE: value->a_longdouble = 2.7; break;
+#endif
+    case VALTYPE_STRING: value->a_string = "heart of gold"; break;
+    case VALTYPE_POINTER: value->a_void_ptr = (void*)0xdeadbeef; break;
+#ifdef HAVE_INTMAX_T
+    case VALTYPE_INTMAX: value->a_intmax = 100; break;
+    case VALTYPE_INTMAX_PTR: value->a_intmax_ptr = NULL; break;
+#endif
+#ifdef HAVE_UINTMAX_T
+    case VALTYPE_UINTMAX: value->a_uintmax = 200; break;
+#endif
+    case VALTYPE_SIZE: value->a_size = 65537; break;
+    case VALTYPE_SIZE_PTR: value->a_size_ptr = NULL; break;
+#ifdef HAVE_PTRDIFF_T
+    case VALTYPE_PTRDIFF: value->a_ptrdiff = 2; break;
+    case VALTYPE_PTRDIFF_PTR: value->a_ptrdiff_ptr = NULL; break;
+#endif
+    default: /* Unsupported type.  */
+      return -1;
+    }
+  return 0;
+}
+
+
+/* This function reads all the values as specified by VALUETABLE into
+   VALUETABLE.  The values are expected in VAARGS.  The function
+   returns -1 if a specified type is not supported. */
+static int
+read_values (valueitem_t valuetable, size_t valuetable_len, va_list vaargs)
+{
+  int validx;
+
+  for (validx=0; validx < valuetable_len; validx++)
+    {
+      value_t *value = &valuetable[validx].value;
+      valtype_t vt = valuetable[validx].vt;
+
+      if (!vaargs)
+        {
+          if (read_dummy_value (value, vt))
+            return -1;
+        }
+      else
+        {
+          switch (vt)
+            {
+            case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break;
+            case VALTYPE_CHAR_PTR:
+              value->a_char_ptr = va_arg (vaargs, char *);
+              break;
+            case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break;
+            case VALTYPE_SCHAR_PTR: 
+              value->a_schar_ptr = va_arg (vaargs, signed char *); 
+              break;
+            case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break;
+            case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break;
+            case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break;
+            case VALTYPE_SHORT_PTR: 
+              value->a_short_ptr = va_arg (vaargs, short *); 
+              break;
+            case VALTYPE_INT:
+              value->a_int = va_arg (vaargs, int);
+              break;
+            case VALTYPE_INT_PTR:
+              value->a_int_ptr = va_arg (vaargs, int *);
+              break;
+            case VALTYPE_UINT:
+              value->a_uint = va_arg (vaargs, unsigned int);
+              break;
+            case VALTYPE_LONG:
+              value->a_long = va_arg (vaargs, long);
+              break;
+            case VALTYPE_ULONG: 
+              value->a_ulong = va_arg (vaargs, unsigned long);
+              break;
+            case VALTYPE_LONG_PTR: 
+              value->a_long_ptr = va_arg (vaargs, long *); 
+              break;
+#ifdef HAVE_LONG_LONG_INT
+            case VALTYPE_LONGLONG:
+              value->a_longlong = va_arg (vaargs, long long int);
+              break;
+            case VALTYPE_ULONGLONG: 
+              value->a_ulonglong = va_arg (vaargs, unsigned long long int); 
+              break;
+            case VALTYPE_LONGLONG_PTR: 
+              value->a_longlong_ptr = va_arg (vaargs, long long *);
+              break;
+#endif
+            case VALTYPE_DOUBLE:
+              value->a_double = va_arg (vaargs, double);
+              break;
+#ifdef HAVE_LONG_DOUBLE
+            case VALTYPE_LONGDOUBLE:
+              value->a_longdouble = va_arg (vaargs, long double);
+              break;
+#endif
+            case VALTYPE_STRING:
+              value->a_string = va_arg (vaargs, const char *);
+              break;
+            case VALTYPE_POINTER: 
+              value->a_void_ptr = va_arg (vaargs, void *);
+              break;
+#ifdef HAVE_INTMAX_T
+            case VALTYPE_INTMAX:
+              value->a_intmax = va_arg (vaargs, intmax_t);
+              break;
+            case VALTYPE_INTMAX_PTR: 
+              value->a_intmax_ptr = va_arg (vaargs, intmax_t *); 
+              break;
+#endif
+#ifdef HAVE_UINTMAX_T
+            case VALTYPE_UINTMAX: 
+              value->a_uintmax = va_arg (vaargs, uintmax_t); 
+              break;
+#endif
+            case VALTYPE_SIZE:
+              value->a_size = va_arg (vaargs, size_t);
+              break;
+            case VALTYPE_SIZE_PTR: 
+              value->a_size_ptr = va_arg (vaargs, size_t *); 
+              break;
+#ifdef HAVE_PTRDIFF_T
+            case VALTYPE_PTRDIFF:
+              value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); 
+              break;
+            case VALTYPE_PTRDIFF_PTR:
+              value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *);
+              break;
+#endif
+            default: /* Unsupported type.  */
+              return -1;
+            }
+        }
+    }
+  return 0;
+}
+
+
+\f
+/* Output COUNT padding characters PADCHAR and update NBYTES by the
+   number of bytes actually written.  */
+static int
+pad_out (estream_printf_out_t outfnc, void *outfncarg,
+         int padchar, int count, size_t *nbytes)
+{
+  char buf[32];
+  size_t n;
+  int rc;
+
+  while (count > 0)
+    {
+      n = (count <= sizeof buf)? count : sizeof buf;
+      memset (buf, padchar, n);
+      rc = outfnc (outfncarg, buf, n);
+      if (rc)
+        return rc;
+      *nbytes += n;
+      count -= n;
+    }
+  
+  return 0;
+}
+
+
+/* "d,i,o,u,x,X" formatting.  OUTFNC and OUTFNCARG describes the
+   output routine, ARG gives the argument description and VALUE the
+   actual value (its type is available through arg->vt).  */
+static int
+pr_integer (estream_printf_out_t outfnc, void *outfncarg,
+            argspec_t arg, value_t value, size_t *nbytes)
+{
+  int rc;
+#ifdef HAVE_LONG_LONG_INT
+  unsigned long long aulong;
+#else
+  unsigned long aulong;
+#endif
+  char numbuf[100];
+  char *p, *pend;
+  size_t n;
+  char signchar = 0;
+  int n_prec;  /* Number of extra precision digits required.  */
+  int n_extra; /* Extra number of prefix or sign characters.  */
+
+  if (arg->conspec == CONSPEC_DECIMAL)
+    {
+#ifdef HAVE_LONG_LONG_INT
+      long long along;
+#else
+      long along;
+#endif
+
+      switch (arg->vt)
+        {
+        case VALTYPE_SHORT: along = value.a_short; break;
+        case VALTYPE_INT: along = value.a_int; break;
+        case VALTYPE_LONG: along = value.a_long; break;  
+#ifdef HAVE_LONG_LONG_INT
+        case VALTYPE_LONGLONG: along = value.a_longlong; break;  
+        case VALTYPE_SIZE: along = value.a_size; break;  
+# ifdef HAVE_INTMAX_T
+        case VALTYPE_INTMAX: along = value.a_intmax; break;  
+# endif
+# ifdef HAVE_PTRDIFF_T
+        case VALTYPE_PTRDIFF: along = value.a_ptrdiff; break;  
+# endif
+#endif /*HAVE_LONG_LONG_INT*/
+        default: 
+          return -1;
+        }
+      if (along < 0)
+        {
+          aulong = -along;
+          signchar = '-';
+        }
+      else
+        aulong = along;
+    }
+  else
+    {
+      switch (arg->vt)
+        {
+        case VALTYPE_USHORT: aulong = value.a_ushort; break;
+        case VALTYPE_UINT: aulong = value.a_uint; break;
+        case VALTYPE_ULONG: aulong = value.a_ulong; break;  
+#ifdef HAVE_LONG_LONG_INT
+        case VALTYPE_ULONGLONG: aulong = value.a_ulonglong; break;  
+        case VALTYPE_SIZE: aulong = value.a_size; break;  
+# ifdef HAVE_UINTMAX_T
+        case VALTYPE_UINTMAX: aulong = value.a_uintmax; break;  
+# endif
+# ifdef HAVE_PTRDIFF_T
+        case VALTYPE_PTRDIFF: aulong = value.a_ptrdiff; break;  
+# endif
+#endif /*HAVE_LONG_LONG_INT*/
+        default: 
+          return -1;
+        }
+    }
+
+  if (signchar == '-')
+    ;
+  else if ((arg->flags & FLAG_PLUS_SIGN))
+    signchar = '+';
+  else if ((arg->flags & FLAG_SPACE_PLUS))
+    signchar = ' ';
+
+  n_extra = !!signchar;
+
+  /* We build the string up backwards.  */
+  p = pend = numbuf + DIM(numbuf);
+  if ((!aulong && !arg->precision))
+    ;
+  else if (arg->conspec == CONSPEC_DECIMAL
+           || arg->conspec == CONSPEC_UNSIGNED)
+    {
+      int grouping = -1;
+      const char * grouping_string =
+#ifdef HAVE_LANGINFO_THOUSANDS_SEP
+        nl_langinfo(THOUSANDS_SEP);
+#else
+        "'";
+#endif
+
+      do
+        {
+          if ((arg->flags & FLAG_GROUPING) 
+              && (++grouping == 3) && *grouping_string)
+            {
+              *--p = *grouping_string;
+              grouping = 0;
+            }
+          *--p = '0' + (aulong % 10);
+          aulong /= 10;
+        }
+      while (aulong);
+    }
+  else if (arg->conspec == CONSPEC_OCTAL)
+    {
+      do
+        {
+          *--p = '0' + (aulong % 8);
+          aulong /= 8;
+        }
+      while (aulong);
+      if ((arg->flags & FLAG_ALT_CONV) && *p != '0')
+        *--p = '0';
+    }
+  else /* HEX or HEXUP */
+    {
+      const char *digits = ((arg->conspec == CONSPEC_HEX)
+                            ? "0123456789abcdef" : "0123456789ABCDEF");
+      do
+        {
+          *--p = digits[(aulong % 16)];
+          aulong /= 16;
+        }
+      while (aulong);
+      if ((arg->flags & FLAG_ALT_CONV))
+        n_extra += 2;
+    }
+  
+  n = pend - p;
+
+  if ((arg->flags & FLAG_ZERO_PAD)
+      && arg->precision == NO_FIELD_VALUE && !(arg->flags & FLAG_LEFT_JUST)
+      && n && arg->width - n_extra > n )
+    n_prec = arg->width - n_extra - n;
+  else if (arg->precision > 0 && arg->precision > n)
+    n_prec = arg->precision - n;
+  else
+    n_prec = 0;
+
+  if (!(arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width - n_extra > n
+      && arg->width - n_extra - n >= n_prec )
+    {
+      rc = pad_out (outfnc, outfncarg, ' ',
+                    arg->width - n_extra - n - n_prec, nbytes);
+      if (rc)
+        return rc;
+    }
+
+  if (signchar)
+    {
+      rc = outfnc (outfncarg, &signchar, 1);
+      if (rc)
+        return rc;
+      *nbytes += 1;
+    }
+
+  if ((arg->flags & FLAG_ALT_CONV)
+      && (arg->conspec == CONSPEC_HEX || arg->conspec == CONSPEC_HEX_UP))
+    {
+      rc = outfnc (outfncarg, arg->conspec == CONSPEC_HEX? "0x": "0X", 2);
+      if (rc)
+        return rc;
+      *nbytes += 2;
+    }
+
+  if (n_prec)
+    {
+      rc = pad_out (outfnc, outfncarg, '0', n_prec, nbytes);
+      if (rc)
+        return rc;
+    }
+      
+  rc = outfnc (outfncarg, p, pend - p);
+  if (rc)
+    return rc;
+  *nbytes += pend - p;
+
+  if ((arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width - n_extra - n_prec > n)
+    {
+      rc = pad_out (outfnc, outfncarg, ' ',
+                    arg->width - n_extra - n_prec - n, nbytes);
+      if (rc)
+        return rc;
+    }
+
+  return 0;
+}
+
+
+/* "e,E,f,F,g,G,a,A" formatting.  OUTFNC and OUTFNCARG describes the
+   output routine, ARG gives the argument description and VALUE the
+   actual value (its type is available through arg->vt).  For
+   portability reasons sprintf is used for the actual formatting.
+   This is useful because sprint is the only standard function to
+   convert a floating number into its ascii representation.  To avoid
+   using malloc we just pass the precision to sprintf and do the final
+   formatting with our own code.  */
+static int
+pr_float (estream_printf_out_t outfnc, void *outfncarg,
+          argspec_t arg, value_t value, size_t *nbytes)
+{
+  int rc;
+#ifdef HAVE_LONG_DOUBLE
+  long double adblfloat = 0; /* Just to please gcc.  */
+  int use_dbl = 0;
+#endif
+  double afloat;
+  char numbuf[200];
+  char formatstr[20];
+  char *p, *pend;
+  size_t n;
+  char signchar = 0;
+  int n_extra;  /* Extra number of prefix or sign characters.  */
+
+  switch (arg->vt)
+    {
+    case VALTYPE_DOUBLE: afloat = value.a_double; break;
+#ifdef HAVE_LONG_DOUBLE
+    case VALTYPE_LONGDOUBLE:
+      afloat = 0;  /* Just to please gcc.  */
+      adblfloat = value.a_longdouble;
+      use_dbl=1; break;
+#endif
+    default: 
+      return -1;
+    }
+
+  /* We build the string using sprint.  */
+  p = formatstr + sizeof formatstr;
+  *--p = 0;
+  switch (arg->conspec)
+    {
+    case CONSPEC_FLOAT:      *--p = 'f'; break;
+    case CONSPEC_FLOAT_UP:   *--p = 'F'; break;
+    case CONSPEC_EXP:        *--p = 'e'; break;
+    case CONSPEC_EXP_UP:     *--p = 'E'; break;
+    case CONSPEC_F_OR_G:     *--p = 'g'; break;
+    case CONSPEC_F_OR_G_UP:  *--p = 'G'; break;
+    case CONSPEC_HEX_EXP:    *--p = 'a'; break;
+    case CONSPEC_HEX_EXP_UP: *--p = 'A'; break;
+    default:
+      return -1; /* Actually a bug.  */
+    }
+#ifdef HAVE_LONG_DOUBLE
+  if (use_dbl)
+    *--p = 'L';
+#endif
+  if (arg->precision != NO_FIELD_VALUE)
+    {
+      /* Limit it to a meaningful value so that even a stupid sprintf
+         won't overflow our buffer.  */
+      n = arg->precision <= 100? arg->precision : 100;
+      do
+        {
+          *--p = '0' + (n % 10);
+          n /= 10;
+        }
+      while (n);
+      *--p = '.';
+    }
+  if ((arg->flags & FLAG_ALT_CONV))
+    *--p = '#';
+  *--p = '%';
+#ifdef HAVE_LONG_DOUBLE
+  if (use_dbl)
+    sprintf (numbuf, p, adblfloat);
+  else
+#endif /*HAVE_LONG_DOUBLE*/
+    sprintf (numbuf, p, afloat);
+  p = numbuf;
+  n = strlen (numbuf);
+  pend = p + n;
+
+  if (*p =='-')
+    {
+      signchar = '-';
+      p++;
+      n--;
+    }
+  else if ((arg->flags & FLAG_PLUS_SIGN))
+    signchar = '+';
+  else if ((arg->flags & FLAG_SPACE_PLUS))
+    signchar = ' ';
+
+  n_extra = !!signchar;
+
+  if (!(arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width - n_extra > n)
+    {
+      rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
+      if (rc)
+        return rc;
+    }
+
+  if (signchar)
+    {
+      rc = outfnc (outfncarg, &signchar, 1);
+      if (rc)
+        return rc;
+      *nbytes += 1;
+    }
+
+  rc = outfnc (outfncarg, p, pend - p);
+  if (rc)
+    return rc;
+  *nbytes += pend - p;
+
+  if ((arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width - n_extra > n)
+    {
+      rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes);
+      if (rc)
+        return rc;
+    }
+
+  return 0;
+}
+
+
+/* "c" formatting.  */
+static int
+pr_char (estream_printf_out_t outfnc, void *outfncarg,
+            argspec_t arg, value_t value, size_t *nbytes)
+{
+  int rc;
+  char buf[1];
+
+  if (arg->vt != VALTYPE_INT)
+    return -1;
+  buf[0] = (unsigned int)value.a_int;
+  rc = outfnc (outfncarg, buf, 1);
+  if(rc)
+    return rc;
+  *nbytes += 1;
+  
+  return 0;
+}
+
+
+/* "s" formatting.  */
+static int
+pr_string (estream_printf_out_t outfnc, void *outfncarg,
+            argspec_t arg, value_t value, size_t *nbytes)
+{
+  int rc;
+  size_t n;
+  const char *string, *s;
+
+  if (arg->vt != VALTYPE_STRING)
+    return -1;
+  string = value.a_string;
+  if (!string)
+    string = "(null)";
+  if (arg->precision >= 0)
+    {
+      for (n=0,s=string; *s && n < arg->precision; s++) 
+        n++;
+    }
+  else
+    n = strlen (string);
+
+  if (!(arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width > n )
+    {
+      rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
+      if (rc)
+        return rc;
+    }
+
+  rc = outfnc (outfncarg, string, n);
+  if (rc)
+    return rc;
+  *nbytes += n;
+
+  if ((arg->flags & FLAG_LEFT_JUST)
+      && arg->width >= 0 && arg->width > n)
+    {
+      rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes);
+      if (rc)
+        return rc;
+    }
+  
+  return 0;
+}
+
+
+/* "p" formatting.  */
+static int
+pr_pointer (estream_printf_out_t outfnc, void *outfncarg,
+            argspec_t arg, value_t value, size_t *nbytes)
+{
+  int rc;
+#ifdef HAVE_LONG_LONG_INT
+  unsigned long long aulong;
+#else
+  unsigned long aulong;
+#endif
+  char numbuf[100];
+  char *p, *pend;
+
+  if (arg->vt != VALTYPE_POINTER)
+    return -1;
+  /* We assume that a pointer can be converted to an unsigned long.
+     That is not correct for a 64 bit Windows, but then we assume that
+     long long is supported and usable for storing a pointer.  */
+#if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P)
+  aulong = (unsigned long long)value.a_void_ptr;
+#else
+  aulong = (unsigned long)value.a_void_ptr;
+#endif
+
+  p = pend = numbuf + DIM(numbuf);
+  do
+    {
+      *--p = "0123456789abcdefx"[(aulong % 16)];
+      aulong /= 16;
+    }
+  while (aulong);
+  while ((pend-p) < 2*sizeof (aulong))
+    *--p = '0';
+  *--p = 'x';
+  *--p = '0';
+  
+  rc = outfnc (outfncarg, p, pend - p);
+  if (rc)
+    return rc;
+  *nbytes += pend - p;
+
+  return 0;
+}
+
+/* "n" pesudo format operation.  */
+static int
+pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg,
+                 argspec_t arg, value_t value, size_t *nbytes)
+{
+  switch (arg->vt)
+    {
+    case VALTYPE_SCHAR_PTR: 
+      *value.a_schar_ptr = (signed char)(unsigned int)(*nbytes); 
+      break;
+    case VALTYPE_SHORT_PTR:  
+      *value.a_short_ptr = (short)(unsigned int)(*nbytes);
+      break;
+    case VALTYPE_LONG_PTR:     
+      *value.a_long_ptr = (long)(*nbytes); 
+      break;
+#ifdef HAVE_LONG_LONG_INT
+    case VALTYPE_LONGLONG_PTR:
+      *value.a_longlong_ptr = (long long)(*nbytes);
+      break;
+#endif
+#ifdef HAVE_INTMAX_T
+    case VALTYPE_INTMAX_PTR:   
+      *value.a_intmax_ptr = (intmax_t)(*nbytes);
+      break;
+#endif
+    case VALTYPE_SIZE_PTR:
+      *value.a_size_ptr = (*nbytes); 
+      break;
+#ifdef HAVE_PTRDIFF_T
+    case VALTYPE_PTRDIFF_PTR:
+      *value.a_ptrdiff_ptr = (ptrdiff_t)(*nbytes);
+      break;
+#endif
+    case VALTYPE_INT_PTR:
+      *value.a_int_ptr = (int)(*nbytes);
+      break;
+    default:
+      return -1; /* An unsupported type has been used.  */
+    }
+
+  return 0;
+}
+
+
+
+/* Run the actual formatting.  OUTFNC and OUTFNCARG are the output
+   functions.  FORMAT is format string ARGSPECS is the parsed format
+   string, ARGSPECS_LEN the number of items in ARGSPECS.  VALUETABLE
+   holds the values and may be directly addressed using the poistion
+   arguments given by ARGSPECS.  MYERRNO is used for the "%m"
+   conversion. NBYTES well be updated to reflect the number of bytes
+   send to the output function. */ 
+static int 
+do_format (estream_printf_out_t outfnc, void *outfncarg,
+           const char *format, argspec_t argspecs, size_t argspecs_len,
+           valueitem_t valuetable, int myerrno, size_t *nbytes)
+{
+  int rc = 0;
+  const char *s;
+  argspec_t arg = argspecs;
+  int argidx = 0; /* Only used for assertion.  */
+  size_t n;
+  value_t value;
+
+  s = format;
+  while ( *s )
+    {
+      if (*s != '%')
+        {
+          s++;
+          continue;
+        }
+      if (s != format)
+        {
+          rc = outfnc (outfncarg, format, (n=s-format));
+          if (rc)
+            return rc;
+          *nbytes += n;
+        }
+      if (s[1] == '%')
+        {
+          /* Note that this code ignores one trailing percent escape -
+             this is however okay as the args parser must have
+             detected this already.  */
+          rc = outfnc (outfncarg, s, 1);
+          if (rc)
+            return rc;
+          *nbytes += 1;
+          s += 2;
+          format = s;
+          continue;
+        }
+
+      /* Save the next start.  */
+      s += arg->length;
+      format = s;
+      assert (argidx < argspecs_len);
+      argidx++;
+
+      /* Apply indirect field width and precision values.  */
+      if (arg->width == STAR_FIELD_VALUE)
+        {
+          assert (valuetable[arg->width_pos-1].vt == VALTYPE_INT);
+          arg->width = valuetable[arg->width_pos-1].value.a_int;
+          if (arg->width < 0)
+            {
+              arg->width = -arg->width;
+              arg->flags |= FLAG_LEFT_JUST;
+            }
+        }
+      if (arg->precision == STAR_FIELD_VALUE)
+        {
+          assert (valuetable[arg->precision_pos-1].vt == VALTYPE_INT);
+          arg->precision = valuetable[arg->precision_pos-1].value.a_int;
+          if (arg->precision < 0)
+            arg->precision = NO_FIELD_VALUE;
+        }
+
+      if (arg->arg_pos == -1 && arg->conspec == CONSPEC_STRERROR)
+        value.a_string = strerror (myerrno);
+      else
+        {
+          assert (arg->vt == valuetable[arg->arg_pos-1].vt);
+          value = valuetable[arg->arg_pos-1].value;
+        }
+
+      switch (arg->conspec)
+        {
+        case CONSPEC_UNKNOWN: assert (!"bug"); break;
+
+        case CONSPEC_DECIMAL:
+        case CONSPEC_UNSIGNED:
+        case CONSPEC_OCTAL:
+        case CONSPEC_HEX:
+        case CONSPEC_HEX_UP:
+          rc = pr_integer (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        case CONSPEC_FLOAT:
+        case CONSPEC_FLOAT_UP:
+        case CONSPEC_EXP:
+        case CONSPEC_EXP_UP:
+        case CONSPEC_F_OR_G:
+        case CONSPEC_F_OR_G_UP:
+        case CONSPEC_HEX_EXP:
+        case CONSPEC_HEX_EXP_UP:
+          rc = pr_float (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        case CONSPEC_CHAR:
+          rc = pr_char (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        case CONSPEC_STRING:
+        case CONSPEC_STRERROR:
+          rc = pr_string (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        case CONSPEC_POINTER:
+          rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        case CONSPEC_BYTES_SO_FAR:
+          rc = pr_bytes_so_far (outfnc, outfncarg, arg, value, nbytes);
+          break;
+        }
+      if (rc)
+        return rc;
+      arg++;    
+    }
+  
+  /* Print out any trailing stuff. */
+  s++;  /* Need to output a terminating nul; take it from format.  */
+  rc = outfnc (outfncarg, format, (n=s - format));
+  if (!rc)
+    *nbytes += n;
+
+  return rc;
+}
+
+
+
+\f
+/* The versatile printf formatting routine.  It expects a callback
+   function OUTFNC and an opaque argument OUTFNCARG used for actual
+   output of the formatted stuff.  FORMAT is the format specification
+   and VAARGS a variable argumemt list matching the arguments of
+   FORMAT.  */
+int 
+estream_format (estream_printf_out_t outfnc,
+                void *outfncarg,
+                const char *format, va_list vaargs)
+{
+  /* Buffer to hold the argspecs and a pointer to it.*/
+  struct argspec_s argspecs_buffer[DEFAULT_MAX_ARGSPECS];
+  argspec_t argspecs = argspecs_buffer;
+  size_t argspecs_len;  /* Number of specifications in ARGSPECS.  */
+
+  /* Buffer to hold the description for the values.  */
+  struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES];
+  valueitem_t valuetable = valuetable_buffer;
+
+  int rc;     /* Return code. */
+  size_t argidx; /* Used to index the argspecs array.  */
+  size_t validx; /* Used to index the valuetable.  */
+  int max_pos;/* Highest argument position.  */
+
+  size_t nbytes = 0; /* Keep track of the number of bytes passed to
+                        the output function.  */
+
+  int myerrno = errno; /* Save the errno for use with "%m". */
+
+
+  /* Parse the arguments to come up with descriptive list.  We can't
+     do this on the fly because we need to support positional
+     arguments. */
+  rc = parse_format (format, &argspecs, DIM(argspecs_buffer), &argspecs_len);
+  if (rc)
+    goto leave;
+
+  /* Check that all ARG_POS fields are set.  */
+  for (argidx=0,max_pos=0; argidx < argspecs_len; argidx++)
+    {
+      if (argspecs[argidx].arg_pos != -1 
+          && argspecs[argidx].arg_pos > max_pos)
+        max_pos = argspecs[argidx].arg_pos;
+      if (argspecs[argidx].width_pos > max_pos)
+        max_pos = argspecs[argidx].width_pos;
+      if (argspecs[argidx].precision_pos > max_pos)
+        max_pos = argspecs[argidx].precision_pos;
+    }
+  if (!max_pos)
+    {
+      /* Fill in all the positions.  */
+      for (argidx=0; argidx < argspecs_len; argidx++)
+        {
+          if (argspecs[argidx].width == STAR_FIELD_VALUE)
+            argspecs[argidx].width_pos = ++max_pos;
+          if (argspecs[argidx].precision == STAR_FIELD_VALUE)
+            argspecs[argidx].precision_pos = ++max_pos;
+          if (argspecs[argidx].arg_pos != -1 )
+            argspecs[argidx].arg_pos = ++max_pos;
+        }
+    }
+  else
+    {
+      /* Check that they are all filled.   More test are done later.  */
+      for (argidx=0; argidx < argspecs_len; argidx++)
+        {
+          if (!argspecs[argidx].arg_pos
+              || (argspecs[argidx].width == STAR_FIELD_VALUE
+                  && !argspecs[argidx].width_pos)
+              || (argspecs[argidx].precision == STAR_FIELD_VALUE
+                  && !argspecs[argidx].precision_pos))
+            goto leave_einval;
+        }
+    }
+  /* Check that there is no overflow in max_pos and that it has a
+     reasonable length.  There may never be more elements than the
+     number of characters in FORMAT.  */
+  if (max_pos < 0 || max_pos >= strlen (format))
+    goto leave_einval;
+
+#ifdef TEST
+  if (verbose > 1)
+    dump_argspecs (argspecs, argspecs_len);
+#endif
+
+  /* Allocate a table to hold the values.  If it is small enough we
+     use a stack allocated buffer.  */
+  if (max_pos > DIM(valuetable_buffer))
+    {
+      valuetable = calloc (max_pos, sizeof *valuetable);
+      if (!valuetable)
+        goto leave_error;
+    }
+  else
+    {
+      for (validx=0; validx < DIM(valuetable_buffer); validx++)
+        valuetable[validx].vt = VALTYPE_UNSUPPORTED;
+    }
+  for (argidx=0; argidx < argspecs_len; argidx++)
+    {
+      if (argspecs[argidx].arg_pos != - 1)
+        {
+          validx = argspecs[argidx].arg_pos - 1;
+          if (valuetable[validx].vt)
+            goto leave_einval; /* Already defined. */
+          valuetable[validx].vt = argspecs[argidx].vt;
+        }
+      if (argspecs[argidx].width == STAR_FIELD_VALUE)
+        {
+          validx = argspecs[argidx].width_pos - 1;
+          if (valuetable[validx].vt)
+            goto leave_einval; /* Already defined.  */
+          valuetable[validx].vt = VALTYPE_INT;
+        }
+      if (argspecs[argidx].precision == STAR_FIELD_VALUE)
+        {
+          validx = argspecs[argidx].precision_pos - 1;
+          if (valuetable[validx].vt)
+            goto leave_einval; /* Already defined.  */
+          valuetable[validx].vt = VALTYPE_INT;
+        }
+    }
+  
+  /* Read all the arguments.  This will error out for unsupported
+     types and for not given positional arguments. */
+  rc = read_values (valuetable, max_pos, vaargs);
+  if (rc)
+    goto leave_einval;  
+  
+/*   for (validx=0; validx < max_pos; validx++) */
+/*     fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */
+
+  /* Everything has been collected, go ahead with the formatting.  */
+  rc = do_format (outfnc, outfncarg, format,
+                  argspecs, argspecs_len, valuetable, myerrno, &nbytes);
+
+  goto leave;
+  
+ leave_einval:
+  errno = EINVAL;
+ leave_error:
+  rc = -1;
+ leave:
+  if (valuetable != valuetable_buffer)
+    free (valuetable);
+  if (argspecs != argspecs_buffer)
+    free (argspecs);
+  return rc;
+}
+
+
+\f
+
+/* A simple output handler utilizing stdio.  */
+static int
+plain_stdio_out (void *outfncarg, const char *buf, size_t buflen)
+{
+  FILE *fp = (FILE*)outfncarg;
+
+  fputs ("OUT->", fp);
+  if ( fwrite (buf, buflen, 1, fp) != 1 )
+    return -1;
+  fputs ("<-\n", fp);
+  return 0;
+}
+
+
+/* A replacement for printf.  */
+int
+estream_printf (const char *format, ...)
+{
+  int rc;
+  va_list arg_ptr;
+  
+  va_start (arg_ptr, format);
+  rc = estream_format (plain_stdio_out, stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  
+  return rc;
+}
+
+/* A replacement for fprintf.  */
+int
+estream_fprintf (FILE *fp, const char *format, ...)
+{
+  int rc;
+  va_list arg_ptr;
+  
+  va_start (arg_ptr, format);
+  rc = estream_format (plain_stdio_out, fp, format, arg_ptr);
+  va_end (arg_ptr);
+  
+  return rc;
+}
+
+/* A replacement for vfprintf.  */
+int 
+estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
+{
+  return estream_format (plain_stdio_out, fp, format, arg_ptr);
+}
+
+
+\f
+/* Communication object used between estream_snprintf and
+   fixed_buffer_out.  */
+struct fixed_buffer_parm_s
+{
+  size_t size;    /* Size of the buffer.  */
+  size_t count;   /* Number of bytes requested for output.  */
+  size_t used;    /* Used size of the buffer.  */
+  char *buffer;   /* Provided buffer.  */
+};
+
+/* A simple malloced buffer output handler.  */
+static int
+fixed_buffer_out (void *outfncarg, const char *buf, size_t buflen)
+{
+  struct fixed_buffer_parm_s *parm = outfncarg;
+
+  parm->count += buflen;
+
+  if (!parm->buffer)
+    ;
+  else if (parm->used + buflen < parm->size)
+    {
+      /* Handle the common case that everything fits into the buffer
+         separately.  */
+      memcpy (parm->buffer + parm->used, buf, buflen);
+      parm->used += buflen;
+    }
+  else
+    {
+      /* The slow version of above.  */
+      for ( ;buflen && parm->used < parm->size; buflen--)
+        parm->buffer[parm->used++] = *buf++;
+    }
+
+  return 0;
+}
+
+
+/* A replacement for vsnprintf. */
+int 
+estream_vsnprintf (char *buf, size_t bufsize,
+                   const char *format, va_list arg_ptr)
+{
+  struct fixed_buffer_parm_s parm;
+  int rc;
+
+  parm.size = bufsize? bufsize-1:0;
+  parm.count = 0;
+  parm.used = 0;
+  parm.buffer = bufsize?buf:NULL;
+  rc = estream_format (fixed_buffer_out, &parm, format, arg_ptr);
+  if (rc == -1)
+    return -1;
+  if (bufsize && buf && parm.count >= parm.size)
+    buf[parm.size-1] = 0;
+
+  return (int)parm.count; /* Return number of bytes which would have
+                             been written.  */
+}
+
+/* A replacement for snprintf.  */
+int 
+estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
+{
+  int rc;
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  rc = estream_vsnprintf (buf, bufsize, format, arg_ptr);
+  va_end (arg_ptr);
+    
+  return rc;
+}
+
+
+\f
+/* Communication object used between estream_asprintf and
+   dynamic_buffer_out.  */
+struct dynamic_buffer_parm_s
+{
+  int error_flag; /* Internal helper.  */ 
+  size_t alloced; /* Allocated size of the buffer.  */
+  size_t used;    /* Used size of the buffer.  */
+  char *buffer;   /* Malloced buffer.  */
+};
+
+/* A simple malloced buffer output handler.  */
+static int
+dynamic_buffer_out (void *outfncarg, const char *buf, size_t buflen)
+{
+  struct dynamic_buffer_parm_s *parm = outfncarg;
+
+  if (parm->error_flag)
+    {
+      /* Just in case some formatting routine did not checked for an
+         error. */
+      errno = parm->error_flag;
+      return -1;
+    }
+
+  if (parm->used + buflen >= parm->alloced)
+    {
+      char *p;
+      
+      parm->alloced += buflen + 512;
+      p = realloc (parm->buffer, parm->alloced);
+      if (!p)
+        {
+          parm->error_flag = errno ? errno : ENOMEM;
+          /* Wipe out what we already accumulated.  This is useful in
+             case sensitive data is formated.  */
+          memset (parm->buffer, 0, parm->used);
+          return -1;
+        }
+      parm->buffer = p;
+    }
+  memcpy (parm->buffer + parm->used, buf, buflen);
+  parm->used += buflen;
+
+  return 0;
+}
+
+
+/* A replacement for vasprintf.  As with the BSD of vasprintf version -1
+   will be returned on error and NULL stored at BUFP.  On success the
+   number of bytes printed will be returned. */
+int 
+estream_vasprintf (char **bufp, const char *format, va_list arg_ptr)
+{
+  struct dynamic_buffer_parm_s parm;
+  int rc;
+
+  parm.error_flag = 0;
+  parm.alloced = 512;
+  parm.used = 0;
+  parm.buffer = my_asprintf_malloc (parm.alloced);
+  if (!parm.buffer)
+    {
+      *bufp = NULL;
+      return -1;
+    }
+  
+  rc = estream_format (dynamic_buffer_out, &parm, format, arg_ptr);
+
+  if (rc != -1 && parm.error_flag)
+    {
+      rc = -1;
+      errno = parm.error_flag;
+    }
+  if (rc == -1)
+    {
+      memset (parm.buffer, 0, parm.used);
+      my_asprintf_free (parm.buffer);
+      *bufp = NULL;
+      return -1;
+    }
+  
+  *bufp = parm.buffer;
+  return parm.used - 1; /* Do not include the nul. */
+}
+
+/* A replacement for asprintf.  As with the BSD of asprintf version -1
+   will be returned on error and NULL stored at BUFP.  On success the
+   number of bytes printed will be returned. */
+int 
+estream_asprintf (char **bufp, const char *format, ...)
+{
+  int rc;
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  rc = estream_vasprintf (bufp, format, arg_ptr);
+  va_end (arg_ptr);
+    
+  return rc;
+}
+
+
+#ifdef TEST
+
+static int
+one_test (const char *format, ...)
+{
+  int rc1, rc2;
+  va_list arg_ptr;
+  char *buf1, *buf2;
+
+  if (verbose)
+    printf ("format: ->%s<-\n", format);
+
+  va_start (arg_ptr, format);
+  rc1 = vasprintf (&buf1, format, arg_ptr);
+  va_end (arg_ptr);
+  if (rc1 == -1)
+    {
+      printf ("   sys: errno=%d (%s)\n", errno, strerror (errno));
+      buf1 = NULL;
+    }
+  else if (verbose)
+    printf ("   sys: ->%s<-\n", buf1);
+  
+  va_start (arg_ptr, format);
+  rc2 = estream_vasprintf (&buf2, format, arg_ptr);
+  va_end (arg_ptr);
+  if (rc2 == -1)
+    printf ("   our: errno=%d (%s)\n", errno, strerror (errno));
+  else if (verbose)
+    printf ("   our: ->%s<-\n", buf2);
+
+  if (rc1 != -1 && rc2 != -1 && strcmp (buf1, buf2))
+    printf ("error: output does not match\n"
+            "format: ->%s<-\n   sys: ->%s<-\n   our: ->%s<-\n",
+            format, buf1, buf2);
+  else if ( rc1 != rc2 )
+    printf ("error: return codes are different: sys_rc=%d our_rc=%d\n",
+            rc1, rc2);
+
+  free (buf2);
+  free (buf1);
+
+  return 0;
+}
+
+
+static void
+run_tests (void)
+{
+#if 0
+  one_test ("%d %% %'d", 17, 19681977);
+
+  one_test ("%d %% %d", 17, 768114563);
+  one_test ("%d %% %d", 17, -768114563);
+
+  one_test ("%d", 17);
+  one_test ("%4d", 17);
+  one_test ("%40d", 17);
+  one_test ("%-d", 17);
+  one_test ("%-4d", 17);
+  one_test ("%-140d", 17);
+  one_test ("%d", -17);
+  one_test ("%4d", -17);
+  one_test ("%40d", -17);
+  one_test ("%-d", -17);
+  one_test ("%-4d", -17);
+  one_test ("%-40d", -17);
+
+  one_test ("%+4d", 17);
+  one_test ("%+4d", -17);
+  one_test ("%-+4d", 17);
+  one_test ("%-+4d", -17);
+  one_test ("% 4d", 17);
+  one_test ("% 4d", -17);
+  one_test ("%- +4d", 17);
+  one_test ("%- +4d", -17);
+
+  one_test ("%.4d", 17);
+  one_test ("%.0d", 17);
+  one_test ("%.0d", 0);
+  one_test ("%.4d", -17);
+  one_test ("%.0d", -17);
+  one_test ("%6.4d", 17);
+  one_test ("%6.4d", -17);
+  one_test ("%6.0d", 0);
+  one_test ("%4.6d", 17);
+  one_test ("%4.6d", -17);
+
+  one_test ("% 4.6d", 17);
+  one_test ("% 6.0d", 0);
+
+  one_test ("%.4d", 17);
+  one_test ("%04d", 17);
+  one_test ("%.4d", -17);
+  one_test ("%04d", -17);
+  one_test ("%0.d", 0);
+
+  one_test ("%*d", 7, 42);
+  one_test ("%*d", -7, 42);
+  one_test ("%.*d", 7, 42);
+  one_test ("%.*d", -7, 42);
+  one_test ("%*.*d", 10, 7, 42);
+  one_test ("%*.*d", 10, -7, 42);
+  one_test ("%*.*d", -10, 7, 42);
+  one_test ("%*.*d", -10, -7, 42);
+
+  one_test ("%*x", 7, 42);
+  one_test ("%*x", -7, 42);
+  one_test ("%.*x", 7, 42);
+  one_test ("%.*x", -7, 42);
+  one_test ("%*.*x", 10, 7, 42);
+  one_test ("%*.*x", 10, -7, 42);
+  one_test ("%*.*x", -10, 7, 42);
+  one_test ("%*.*x", -10, -7, 42);
+  one_test ("%#*x", 7, 42);
+  one_test ("%#*x", -7, 42);
+  one_test ("%#.*x", 7, 42);
+  one_test ("%#.*x", -7, 42);
+  one_test ("%#*.*x", 10, 7, 42);
+  one_test ("%#*.*x", 10, -7, 42);
+  one_test ("%#*.*x", -10, 7, 42);
+  one_test ("%#*.*x", -10, -7, 42);
+
+  one_test ("%*X", 7, 42);
+  one_test ("%*X", -7, 42);
+  one_test ("%.*X", 7, 42);
+  one_test ("%.*X", -7, 42);
+  one_test ("%*.*X", 10, 7, 42);
+  one_test ("%*.*X", 10, -7, 42);
+  one_test ("%*.*X", -10, 7, 42);
+  one_test ("%*.*X", -10, -7, 42);
+  one_test ("%#*X", 7, 42);
+  one_test ("%#*X", -7, 42);
+  one_test ("%#.*X", 7, 42);
+  one_test ("%#.*X", -7, 42);
+  one_test ("%#*.*X", 10, 7, 42);
+  one_test ("%#*.*X", 10, -7, 42);
+  one_test ("%#*.*X", -10, 7, 42);
+  one_test ("%#*.*X", -10, -7, 42);
+
+  one_test ("%*o", 7, 42);
+  one_test ("%*o", -7, 42);
+  one_test ("%.*o", 7, 42);
+  one_test ("%.*o", -7, 42);
+  one_test ("%*.*o", 10, 7, 42);
+  one_test ("%*.*o", 10, -7, 42);
+  one_test ("%*.*o", -10, 7, 42);
+  one_test ("%*.*o", -10, -7, 42);
+  one_test ("%#*o", 7, 42);
+  one_test ("%#*o", -7, 42);
+  one_test ("%#.*o", 7, 42);
+  one_test ("%#.*o", -7, 42);
+  one_test ("%#*.*o", 10, 7, 42);
+  one_test ("%#*.*o", 10, -7, 42);
+  one_test ("%#*.*o", -10, 7, 42);
+  one_test ("%#*.*o", -10, -7, 42);
+
+  one_test ("%s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.0s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.10s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.48s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.49s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.50s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%.51s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%48s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%49s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%50s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%51s", "the quick brown fox jumps over the lazy dogs back");
+  one_test ("%-51s", "the quick brown fox jumps over the lazy dogs back");
+#endif
+
+  one_test ("%f", 3.1415926535);
+  one_test ("%f", -3.1415926535);
+  one_test ("%.10f", 3.1415926535);
+  one_test ("%.2f", 3.1415926535);
+  one_test ("%.1f", 3.1415926535);
+  one_test ("%.0f", 3.1415926535);
+  one_test ("%.20f", 3.1415926535);
+  one_test ("%10.10f", 3.1415926535);
+  one_test ("%10.2f", 3.1415926535);
+  one_test ("%10.1f", 3.1415926535);
+  one_test ("%10.0f", 3.1415926535);
+  one_test ("%30.20f", 3.1415926535);
+  one_test ("%10.10f", -3.1415926535);
+  one_test ("%10.2f", -3.1415926535);
+  one_test ("%10.1f", -3.1415926535);
+  one_test ("%10.0f", -3.1415926535);
+  one_test ("%30.20f", -3.1415926535);
+
+  one_test ("%-10f", 3.1415926535);
+  one_test ("%-10.10f", 3.1415926535);
+  one_test ("%-10.2f", 3.1415926535);
+  one_test ("%-10.1f", 3.1415926535);
+  one_test ("%-10.0f", 3.1415926535);
+  one_test ("%-30.20f", 3.1415926535);
+  one_test ("%-10f", -3.1415926535);
+  one_test ("%-10.10f", -3.1415926535);
+  one_test ("%-10.2f", -3.1415926535);
+  one_test ("%-10.1f", -3.1415926535);
+  one_test ("%-10.0f", -3.1415926535);
+  one_test ("%-30.20f", -3.1415926535);
+
+  one_test ("%#.0f",  3.1415926535);
+  one_test ("%#10.0f",  3.1415926535);
+  one_test ("%#10.0f", -3.1415926535);
+  one_test ("%-#10.0f",  3.1415926535);
+  one_test ("%-#10.0f", -3.1415926535);
+
+  one_test ("%e", 3.1415926535);
+  one_test ("%g", 3.1415926535);
+
+  one_test ("%a", 1);
+  one_test ("%a", -1);
+  one_test ("%a", 3.1415926535);
+
+#ifdef HAVE_LONG_DOUBLE
+  one_test ("%La", 1);
+  one_test ("%La", -1);
+  one_test ("%La", 3.1415926535);
+#endif
+
+#ifdef __GLIBC__
+  /* "%m" is a glibc extension so this _test_ will only work on such a
+     system.  */
+  errno = ENOENT;
+  one_test ("%m");
+  errno = ENOENT;
+  one_test ("%d=%m", 17);
+  errno = ENOENT;
+  one_test ("%2$d:%m:%1$d", 42, 17);
+#endif /*__GLIBC__*/
+
+}
+
+static void
+check_snprintf (void)
+{
+  char buffer[20];
+  int rc;
+
+  rc = estream_snprintf (buffer, 0, "%*s", 18, "");
+  if (rc != 19)
+    printf ("rc=%d\n", rc );
+  rc = estream_snprintf (buffer, sizeof buffer, "%*s", 18, "");
+  if (rc != 19)
+    printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
+  rc = estream_snprintf (buffer, sizeof buffer, "%*s", 19, "");
+  if (rc != 20)
+    printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
+  rc = estream_snprintf (buffer, sizeof buffer, "%*s", 20, "");
+  if (rc != 21)
+    printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
+  rc = estream_snprintf (buffer, sizeof buffer, "%*s", 21, "");
+  if (rc != 22)
+    printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer));
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int rc;
+
+  if (argc) {argc--; argv++; }
+
+  setlocale (LC_NUMERIC, "");
+
+  while (argc && !strcmp (*argv, "--verbose"))
+    {
+      verbose++;
+      argc--;
+      argv++;
+    }
+
+  if (!argc)
+    {
+      run_tests ();
+      check_snprintf () ;
+    }
+  else
+    {
+      rc = estream_vfprintf (stdout, argv[0], NULL);
+      fflush (stdout);
+      fprintf (stderr, "[estream_vfprintf returns: %d]\n", rc);
+    }
+
+  return 0;
+}
+#endif /*TEST*/
+/*
+Local Variables:
+compile-command: "cc -Wall -O3 -g -I.. -DHAVE_CONFIG_H -DTEST -o estream-printf estream-printf.c"
+End:
+*/
diff --git a/common/estream-printf.h b/common/estream-printf.h
new file mode 100644 (file)
index 0000000..bbf132b
--- /dev/null
@@ -0,0 +1,60 @@
+/* estream-printf.h - Versatile C-99 compliant printf formatting.
+ * Copyright (C) 2007 g10 Code GmbH
+ *
+ * This file is part of Libestream.
+ *
+ * Libestream is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * Libestream is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Libestream; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * $Id: estream-printf.h 54 2007-05-15 14:12:06Z wk $
+ */
+
+#ifndef ESTREAM_PRINTF_H
+#define ESTREAM_PRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+# define ESTREAM_GCC_A_PRINTF( f, a )  __attribute__ ((format (printf,f,a)))
+#else
+# define ESTREAM_GCC_A_PRINTF( f, a )
+#endif
+
+
+typedef int (*estream_printf_out_t)
+     (void *outfncarg,  const char *buf, size_t buflen);
+
+int estream_format (estream_printf_out_t outfnc, void *outfncarg,
+                    const char *format, va_list vaargs) 
+     ESTREAM_GCC_A_PRINTF(3,0);
+int estream_printf (const char *format, ...) 
+     ESTREAM_GCC_A_PRINTF(1,2);
+int estream_fprintf (FILE *fp, const char *format, ... )
+     ESTREAM_GCC_A_PRINTF(2,3);
+int estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
+     ESTREAM_GCC_A_PRINTF(2,0);
+int estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
+     ESTREAM_GCC_A_PRINTF(3,4);
+int estream_vsnprintf (char *buf,size_t bufsize, 
+                       const char *format, va_list arg_ptr) 
+     ESTREAM_GCC_A_PRINTF(3,0);
+int estream_asprintf (char **bufp, const char *format, ...)
+     ESTREAM_GCC_A_PRINTF(2,3);
+int estream_vasprintf (char **bufp, const char *format, va_list arg_ptr)
+     ESTREAM_GCC_A_PRINTF(2,0);
+
+
+#endif /*ESTREAM_PRINTF_H*/
index 31e91d5..65c5664 100644 (file)
@@ -1,5 +1,5 @@
 /* estream.c - Extended Stream I/O Library
- * Copyright (C) 2004, 2006, 2007 g10 Code GmbH
+ * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
  *
  * This file is part of Libestream.
  *
@@ -11,7 +11,7 @@
  * Libestream is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with Libestream; if not, write to the Free Software
@@ -49,6 +49,7 @@
 # include <pth.h>
 #endif
 
+/* This is for the special hack to use estream.c in GnuPG.  */
 #ifdef GNUPG_MAJOR_VERSION
 #include "../common/util.h"
 #endif
@@ -62,7 +63,7 @@ void *memrchr (const void *block, int c, size_t size);
 #endif
 
 #include <estream.h>
-
+#include <estream-printf.h>
 
 \f
 
@@ -747,8 +748,8 @@ static int
 es_convert_mode (const char *mode, unsigned int *flags)
 {
 
-  /* FIXME: We need to allow all combinations for mode flags and for
-     binary we need to do a
+  /* FIXME: We need to allow all mode flags permutations and for
+     binary mode we need to do a
 
      #ifdef HAVE_DOSISH_SYSTEM
        setmode (fd, O_BINARY);
@@ -1671,29 +1672,19 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
 }
 
 
-/* Helper for esprint. */
-#if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
-static my_funopen_hook_ret_t
-print_fun_writer (void *cookie_arg, const char *buffer, size_t size)
+/* Output fucntion used for estream_format.  */
+static int
+print_writer (void *outfncarg, const char *buf, size_t buflen)
 {
-  estream_t stream = cookie_arg;
+  estream_t stream = outfncarg;
   size_t nwritten;
-  
-  /* We don't return an error but let es_print check whether an error
-     has occured.  Internally we skip everything after an error. */
-  if (!stream->intern->print_err)
-    {
-      if (es_writen (stream, buffer, size, &nwritten))
-        {
-          stream->intern->print_err = 1;
-          stream->intern->print_errno = errno;
-        }
-      else
-        stream->intern->print_ntotal += nwritten;
-    }
-  return 0;
+  int rc;
+
+  nwritten = 0;
+  rc = es_writen (stream, buf, buflen, &nwritten);
+  stream->intern->print_ntotal += nwritten;
+  return rc;
 }
-#endif /* HAVE_FOPENCOOKIE || HAVE_FUNOPEN */
 
 
 /* The core of our printf function.  This is called in locked state. */
@@ -1701,98 +1692,13 @@ static int
 es_print (estream_t ES__RESTRICT stream,
          const char *ES__RESTRICT format, va_list ap)
 {
-#if defined(HAVE_FOPENCOOKIE) || defined(HAVE_FUNOPEN)
-
-  if (!stream->intern->print_fp)
-    {
-#ifdef HAVE_FOPENCOOKIE
-      {
-        cookie_io_functions_t io = { NULL };
-        io.write = print_fun_writer;
-        
-        stream->intern->print_fp = fopencookie (stream, "w", io);
-      }
-#else /*!HAVE_FOPENCOOKIE*/
-      stream->intern->print_fp = funopen (stream, NULL,
-                                          print_fun_writer, NULL, NULL);
-#endif /*!HAVE_FOPENCOOKIE*/
-      if (!stream->intern->print_fp)
-        return -1;
-    }
+  int rc;
 
-  stream->intern->print_err = 0;
-  stream->intern->print_errno = 0;
   stream->intern->print_ntotal = 0;
-
-  if ( vfprintf (stream->intern->print_fp, format, ap) < 0 
-       || fflush (stream->intern->print_fp) )
-    {
-      stream->intern->print_errno = errno;
-      stream->intern->print_err = 1;
-      fclose (stream->intern->print_fp);
-      stream->intern->print_fp = NULL;
-    }
-  if (stream->intern->print_err)
-    {
-      errno = stream->intern->print_errno;
-      return -1;
-    }
-
+  rc = estream_format (print_writer, stream, format, ap);
+  if (rc)
+    return -1;
   return (int)stream->intern->print_ntotal;
-  
-#else /* No funopen or fopencookie. */
-  
-  char data[BUFFER_BLOCK_SIZE];
-  size_t bytes_read;
-  size_t bytes_written;
-  FILE *tmp_stream;
-  int err;
-
-  bytes_written = 0;
-  tmp_stream = NULL;
-  err = 0;
-  
-  tmp_stream = tmpfile ();
-  if (! tmp_stream)
-    {
-      err = errno;
-      goto out;
-    }
-
-  err = vfprintf (tmp_stream, format, ap);
-  if (err < 0)
-    goto out;
-
-  err = fseek (tmp_stream, 0, SEEK_SET);
-  if (err)
-    goto out;
-
-  while (1)
-    {
-      bytes_read = fread (data, 1, sizeof (data), tmp_stream);
-      if (ferror (tmp_stream))
-       {
-         err = -1;
-         break;
-       }
-
-      err = es_writen (stream, data, bytes_read, NULL);
-      if (err)
-       break;
-      else
-       bytes_written += bytes_read;
-      if (feof (tmp_stream))
-       break;
-    }
-  if (err)
-    goto out;
-
- out:
-  if (tmp_stream)
-    fclose (tmp_stream);
-
-  return err ? -1 : bytes_written;
-#endif /* no funopen or fopencookie */
 }
 
 
@@ -2718,7 +2624,7 @@ es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
 
 static int
 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
-           const char *ES__RESTRICT format, ...)
+           const char *ES__RESTRICT format, ...)
 {
   int ret;
   
@@ -2868,8 +2774,6 @@ es_opaque_get (estream_t stream)
   return opaque;
 }
 
-
-
 /* Print a BUFFER to STREAM while replacing all control characters and
    the characters in DELIMITERS by standard C escape sequences.
    Returns 0 on success or -1 on error.  If BYTES_WRITTEN is not NULL
@@ -2992,7 +2896,7 @@ es_write_hexstring (estream_t ES__RESTRICT stream,
    encoding.  The interface is the same as es_write_sanitized, however
    only one delimiter may be supported. 
 
-   THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG. */
+   THIS IS NOT A STANDARD ESTREAM FUNCTION AND ONLY USED BY GNUPG!. */
 int
 es_write_sanitized_utf8_buffer (estream_t stream,
                                 const void *buffer, size_t length, 
@@ -3025,6 +2929,3 @@ es_write_sanitized_utf8_buffer (estream_t stream,
     return es_write_sanitized (stream, p, length, delimiters, bytes_written);
 }
 #endif /*GNUPG_MAJOR_VERSION*/
-
-
-
index aede408..0d10472 100644 (file)
@@ -1,5 +1,5 @@
 /* estream.h - Extended stream I/O/ Library
- * Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
  *
  * This file is part of Libestream.
  *
@@ -211,7 +211,6 @@ void es_opaque_set (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque);
 void *es_opaque_get (estream_t stream);
 
 
-
 #ifdef GNUPG_MAJOR_VERSION
 int es_write_sanitized_utf8_buffer (estream_t stream,
                                     const void *buffer, size_t length, 
@@ -220,5 +219,6 @@ int es_write_sanitized_utf8_buffer (estream_t stream,
 #endif /*GNUPG_MAJOR_VERSION*/
 
 
+
 #endif /*ESTREAM_H*/
 
index 1064e51..bb96e44 100644 (file)
@@ -1,5 +1,5 @@
 /* sexp-parse.h - S-Exp helper functions
- *     Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -97,4 +97,34 @@ smatch (unsigned char const **buf, size_t buflen, const char *token)
   return 1;
 }
 
+/* Format VALUE for use as the length indicatior of an S-expression.
+   The caller needs to provide a buffer HELP_BUFFER wth a length of
+   HELP_BUFLEN.  The return value is a pointer into HELP_BUFFER with
+   the formatted length string.  The colon and a trailing nul are
+   appended.  HELP_BUFLEN must be at least 3 - a more useful value is
+   15.  If LENGTH is not NULL, the LENGTH of the resulting string
+   (excluding the terminating nul) is stored at that address. */
+static inline char *
+smklen (char *help_buffer, size_t help_buflen, size_t value, size_t *length)
+{
+  char *p = help_buffer + help_buflen;
+
+  if (help_buflen >= 3)
+    {
+      *--p = 0;
+      *--p = ':';
+      do
+        {
+          *--p = '0' + (value % 10);
+          value /= 10;
+        }
+      while (value && p > help_buffer);
+    }
+
+  if (length)
+    *length = (help_buffer + help_buflen) - p;
+  return p;
+}
+    
+
 #endif /*SEXP_PARSE_H*/
index da6124d..7bac990 100644 (file)
@@ -34,7 +34,7 @@
 #endif
 
 #include "util.h"
-
+#include "sexp-parse.h"
 
 /* Return the so called "keygrip" which is the SHA-1 hash of the
    public key parameters expressed in a way depended on the algorithm.
@@ -115,7 +115,8 @@ make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
   const char *s;
   unsigned char *buf;
   unsigned char *p;
-  char numbuf[50];
+  char numbuf[50], *numbufp;
+  size_t numbuflen;
 
   for (n=0, s=line; hexdigitp (s); s++, n++)
     ;
@@ -124,11 +125,12 @@ make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
   if (!n)
     return NULL;
   len = ((n+1) & ~0x01)/2; 
-  sprintf (numbuf, "(%u:", (unsigned int)len);
-  buf = xtrymalloc (strlen (numbuf) + len + 1 + 1);
+  numbufp = smklen (numbuf, sizeof numbuf, len, &numbuflen);
+  buf = xtrymalloc (1 + numbuflen + len + 1 + 1);
   if (!buf)
     return NULL;
-  p = (unsigned char *)stpcpy ((char *)buf, numbuf);
+  buf[0] = '(';
+  p = (unsigned char *)stpcpy ((char *)buf+1, numbufp);
   s = line;
   if ((n&1))
     {
index 1fc4d2a..5aeb791 100644 (file)
 #include <errno.h>  /* We need errno.  */
 #include <gpg-error.h> /* We need gpg_error_t. */
 
-/* Common GNUlib includes (-I ../gl/). */
-#include "vasprintf.h"
-
-
 /* Hash function used with libksba. */
 #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
 
 #include "../jnlib/dotlock.h"
 #include "../jnlib/utf8conv.h"
 
+/* Redefine asprintf by our estream version which uses our own memory
+   allocator..  */
+#include "estream-printf.h"
+#define asprintf estream_asprintf
+#define vasprintf estream_vasprintf
+
+
+/* GCC attributes.  */
 #if __GNUC__ >= 4 
 # define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
 #else
@@ -175,13 +179,9 @@ void gnupg_rl_initialize (void);
    logging subsystem. */
 void setup_libgcrypt_logging (void);
 
-/* Same as asprintf but return an allocated buffer suitable to be
-   freed using xfree.  This function simply dies on memory failure,
-   thus no extra check is required. */
+/* Same as estream_asprintf but die on memory failure.  */
 char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2);
-/* Same as asprintf but return an allocated buffer suitable to be
-   freed using xfree.  This function returns NULL on memory failure and
-   sets errno. */
+/* This is now an alias to estream_asprintf.  */
 char *xtryasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2);
 
 const char *print_fname_stdout (const char *s);
diff --git a/common/vasprintf.c b/common/vasprintf.c
deleted file mode 100644 (file)
index 4bed8de..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Like vsprintf but provides a pointer to malloc'd storage, which must
-   be freed by the caller.
-   Copyright (C) 1994, 2002 Free Software Foundation, Inc.
-
-This file is part of the libiberty library.
-Libiberty 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 of the License, or (at your option) any later version.
-
-Libiberty 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 libiberty; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 51 Franklin Street,
-Fifth Floor, Boston, MA 02110-1301, USA. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#ifdef TEST
-int global_total_width;
-#endif
-
-int
-vasprintf (char **result, const char *format, va_list args)
-{
-  const char *p = format;
-  /* Add one to make sure that it is never zero, which might cause malloc
-     to return NULL.  */
-  int total_width = strlen (format) + 1;
-  va_list ap;
-
-#ifdef va_copy
-  va_copy (ap, args);
-#else
-#ifdef __va_copy
-  __va_copy (ap, args);
-#else
-  memcpy (&ap, args, sizeof (va_list));
-#endif /* __va_copy */
-#endif /* va_copy */
-
-  while (*p != '\0')
-    {
-      if (*p++ == '%')
-       {
-         while (strchr ("-+ #0", *p))
-           ++p;
-         if (*p == '*')
-           {
-             ++p;
-             total_width += abs (va_arg (ap, int));
-           }
-         else
-           total_width += strtoul (p, (char**)&p, 10);
-         if (*p == '.')
-           {
-             ++p;
-             if (*p == '*')
-               {
-                 ++p;
-                 total_width += abs (va_arg (ap, int));
-               }
-             else
-             total_width += strtoul (p, (char**)&p, 10);
-           }
-         while (strchr ("hlL", *p))
-           ++p;
-         /* Should be big enough for any format specifier except %s
-             and floats.  */
-         total_width += 30;
-         switch (*p)
-           {
-           case 'd':
-           case 'i':
-           case 'o':
-           case 'u':
-           case 'x':
-           case 'X':
-           case 'c':
-             (void) va_arg (ap, int);
-             break;
-           case 'f':
-           case 'e':
-           case 'E':
-           case 'g':
-           case 'G':
-             (void) va_arg (ap, double);
-             /* Since an ieee double can have an exponent of 307, we'll
-                make the buffer wide enough to cover the gross case. */
-             total_width += 307;
-             break;
-           case 's':
-              {
-                char *tmp = va_arg (ap, char *);
-                if (tmp)
-                  total_width += strlen (tmp);
-                else /* in case the vsprintf does prints a text */
-                  total_width += 25; /* e.g. "(null pointer reference)" */
-              }
-             break;
-           case 'p':
-           case 'n':
-             (void) va_arg (ap, char *);
-             break;
-           }
-       }
-    }
-#ifdef TEST
-  global_total_width = total_width;
-#endif
-  *result = malloc (total_width);
-  if (*result != NULL)
-    return vsprintf (*result, format, args);
-  else
-    return 0;
-}
-
-
-int
-asprintf (char **buf, const char *fmt, ...)
-{
-  int status;
-  va_list ap;
-
-  va_start (ap, fmt);
-  status = vasprintf (buf, fmt, ap);
-  va_end (ap);
-  return status;
-}
-
-
-#ifdef TEST
-void
-checkit (const char* format, ...)
-{
-  va_list args;
-  char *result;
-
-  va_start (args, format);
-  vasprintf (&result, format, args);
-  if (strlen (result) < global_total_width)
-    printf ("PASS: ");
-  else
-    printf ("FAIL: ");
-  printf ("%d %s\n", global_total_width, result);
-}
-
-int
-main (void)
-{
-  checkit ("%d", 0x12345678);
-  checkit ("%200d", 5);
-  checkit ("%.300d", 6);
-  checkit ("%100.150d", 7);
-  checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
-777777777777777777333333333333366666666666622222222222777777777777733333");
-  checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
-}
-#endif /* TEST */
index 75ae180..ce013ba 100644 (file)
 
 #include "util.h"
 #include "iobuf.h"
+#include "estream-printf.h"
+
+#if !defined(ESTREAM_ASPRINTF_MALLOC) || !defined(ESTREAM_ASPRINTF_FREE)
+#error Need to define ESTREAM_ASPRINTF_MALLOC and _FREE
+#endif
 
 /* Same as asprintf but return an allocated buffer suitable to be
    freed using xfree.  This function simply dies on memory failure,
@@ -33,15 +38,13 @@ char *
 xasprintf (const char *fmt, ...)
 {
   va_list ap;
-  char *buf, *p;
+  char *buf;
 
   va_start (ap, fmt);
-  if (vasprintf (&buf, fmt, ap) < 0)
-    log_fatal ("asprintf failed: %s\n", strerror (errno));
+  if (estream_vasprintf (&buf, fmt, ap) < 0)
+    log_fatal ("estream_asprintf failed: %s\n", strerror (errno));
   va_end (ap);
-  p = xstrdup (buf);
-  free (buf);
-  return p;
+  return buf;
 }
 
 /* Same as above but return NULL on memory failure.  */
@@ -50,14 +53,12 @@ xtryasprintf (const char *fmt, ...)
 {
   int rc;
   va_list ap;
-  char *buf, *p;
+  char *buf;
 
   va_start (ap, fmt);
-  rc = vasprintf (&buf, fmt, ap);
+  rc = estream_vasprintf (&buf, fmt, ap);
   va_end (ap);
   if (rc < 0)
     return NULL;
-  p = xtrystrdup (buf);
-  free (buf);
-  return p;
+  return buf;
 }
index e2c9c7e..48be044 100644 (file)
@@ -26,8 +26,8 @@ min_automake_version="1.10"
 # Remember to change the version number immediately *after* a release.
 # Set my_issvn to "yes" for non-released code.  Remember to run an
 # "svn up" and "autogen.sh" right before creating a distribution.
-m4_define([my_version], [2.0.4])
-m4_define([my_issvn], [no])
+m4_define([my_version], [2.0.5])
+m4_define([my_issvn], [yes])
 
 
 m4_define([svn_revision], m4_esyscmd([echo -n $( (svn info 2>/dev/null \
@@ -426,6 +426,11 @@ AH_BOTTOM([
    currently enables it by default for no reason. */
 #define PTH_SYSCALL_SOFT 0
 
+/* We want to use the libgcrypt provided memory allocation for
+   asprintf.  */
+#define ESTREAM_ASPRINTF_MALLOC      gcry_malloc
+#define ESTREAM_ASPRINTF_FREE        gcry_free
+#define ESTREAM_PRINTF_EXTRA_INCLUDE "util.h"
 
 #endif /*GNUPG_CONFIG_H_INCLUDED*/
 ])
@@ -986,7 +991,7 @@ AC_CHECK_FUNCS([flockfile funlockfile fopencookie funopen])
 #
 gl_SOURCE_BASE([gl])
 gl_M4_BASE([gl/m4])
-gl_MODULES([setenv mkdtemp vasprintf xsize])
+gl_MODULES([setenv mkdtemp xsize])
 gl_INIT
 
 
@@ -1189,6 +1194,12 @@ fi
 
 
 #
+# Prepare building of estream
+#
+estream_INIT
+
+
+#
 # Decide what to build
 #
 missing_pth=no
index f2d6b05..8811a88 100644 (file)
@@ -1,5 +1,11 @@
+2007-05-11  Werner Koch  <wk@g10code.com>
+
+       * gpgsm.texi (--export): Enhanced description.
+
 2007-05-09  Werner Koch  <wk@g10code.com>
 
+       * examples/gpgconf.conf: Remove active example line.
+
        * Makefile.am (online): Distinguish between released and svn manuals.
 
 2007-05-08  Werner Koch  <wk@g10code.com>
index c901213..f66b6b1 100644 (file)
@@ -52,7 +52,5 @@
 #-------------------------------------------------------------------
 
 
-# Deny all users to change the allow-mark-trusted option.
-* gpg-agent allow-mark-trusted [no-change]
 
 
index 451f09a..eed673c 100644 (file)
@@ -228,8 +228,14 @@ Delete the keys matching @var{pattern}.
 @item --export [@var{pattern}]
 @opindex export
 Export all certificates stored in the Keybox or those specified by the
-optional @var{pattern}.  When using along with the @code{--armor} option
-a few informational lines are prepended before each block.
+optional @var{pattern}. Those pattern consist of a list of user ids
+(@pxref{how-to-specify-a-user-id}).  When used along with the
+@option{--armor} option a few informational lines are prepended before
+each block.  There is one limitation: As there is no commonly agreed
+upon way to pack more than one certificate into an ASN.1 structure, the
+binary export (i.e. without using @option{armor}) works only for the
+export of one certificate.  Thus it is required to specify a
+@var{pattern} which yields exactly one certificate.
 
 @item --export-secret-key-p12 @var{key-id}
 @opindex export
index dceae98..5fdb926 100644 (file)
@@ -59,18 +59,6 @@ libgnu_a_SOURCES += setenv.h
 
 ## end   gnulib module setenv
 
-## begin gnulib module vasnprintf
-
-libgnu_a_SOURCES += printf-args.h printf-parse.h vasnprintf.h
-
-## end   gnulib module vasnprintf
-
-## begin gnulib module vasprintf
-
-libgnu_a_SOURCES += vasprintf.h
-
-## end   gnulib module vasprintf
-
 ## begin gnulib module xsize
 
 libgnu_a_SOURCES += xsize.h
index b699f4c..9940338 100644 (file)
@@ -1,3 +1,7 @@
+2007-05-15  Werner Koch  <wk@g10code.com>
+
+       * estream.m4: New.
+
 2007-05-09  Werner Koch  <wk@g10code.com>
 
        * gpg-error.m4, ksba.m4, libassuan.m4, libgcrypt.m4: Updated.
index c8b74ae..d199c21 100644 (file)
@@ -8,3 +8,7 @@ EXTRA_DIST += gpg-error.m4 libgcrypt.m4 libassuan.m4 ksba.m4
 
 EXTRA_DIST += autobuild.m4
 
+EXTRA_DIST += estream.m4
+
+
+
diff --git a/m4/estream.m4 b/m4/estream.m4
new file mode 100644 (file)
index 0000000..4b6c745
--- /dev/null
@@ -0,0 +1,48 @@
+dnl Autoconf macros for libestream
+dnl       Copyright (C) 2007 g10 Code GmbH
+dnl
+dnl This file is free software; as a special exception the author gives
+dnl unlimited permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+dnl This file is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
+dnl estream_PRINTF_INIT
+dnl Prepare build of source included estream-printf.c
+dnl
+AC_DEFUN([estream_PRINTF_INIT],
+[ 
+  AC_MSG_NOTICE([checking system features for estream-printf])
+  AC_TYPE_LONG_LONG_INT  
+  AC_TYPE_LONG_DOUBLE  
+  AC_TYPE_INTMAX_T
+  AC_TYPE_UINTMAX_T
+  AC_CHECK_TYPES([ptrdiff_t])
+  AC_CHECK_SIZEOF([unsigned long])
+  AC_CHECK_SIZEOF([void *])
+  AC_CACHE_CHECK([for nl_langinfo and THOUSANDS_SEP],
+                  estream_cv_langinfo_thousands_sep,
+      [AC_TRY_LINK([#include <langinfo.h>],
+        [char* cs = nl_langinfo(THOUSANDS_SEP); return !cs;],
+        estream_cv_langinfo_thousands_sep=yes,
+        estream_cv_langinfo_thousands_sep=no)
+      ])
+  if test $estream_cv_langinfo_thousands_sep = yes; then
+    AC_DEFINE(HAVE_LANGINFO_THOUSANDS_SEP, 1,
+      [Define if you have <langinfo.h> and nl_langinfo(THOUSANDS_SEP).])
+  fi
+])
+
+
+dnl estream_INIT
+dnl Prepare build of source included estream.c
+dnl
+AC_DEFUN([estream_INIT],
+[ 
+  AC_REQUIRE([estream_PRINTF_INIT])
+  AC_MSG_NOTICE([checking system features for estream])
+
+])