lintian doesn't like orphan packages with uploaders...
[debian/amanda] / gnulib / vasnprintf.c
index f56382334919f19824971ece142a18194e211fba..e618901ba282161a0b067e087782939049e4fa3a 100644 (file)
@@ -1,9 +1,9 @@
 /* vsprintf with automatic memory allocation.
 /* vsprintf with automatic memory allocation.
-   Copyright (C) 1999, 2002-2007 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2002-2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
    any later version.
 
    This program is distributed in the hope that it will be useful,
 # endif
 #endif
 
 # endif
 #endif
 
-#include <locale.h>    /* localeconv() */
-#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 <locale.h>     /* localeconv() */
+#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 */
 #if HAVE_NL_LANGINFO
 # include <langinfo.h>
 #endif
 #if HAVE_NL_LANGINFO
 # include <langinfo.h>
 #endif
 /* Checked size_t computations.  */
 #include "xsize.h"
 
 /* Checked size_t computations.  */
 #include "xsize.h"
 
-#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
 # include <math.h>
 # include "float+.h"
 # include <math.h>
 # include "float+.h"
-# include "fpucw.h"
 #endif
 
 #endif
 
-#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL
+#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
 # include <math.h>
 # include <math.h>
-# include "isnan.h"
+# include "isnand-nolibm.h"
 #endif
 
 #endif
 
-#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL
+#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL
 # include <math.h>
 # include "isnanl-nolibm.h"
 # include "fpucw.h"
 #endif
 
 # include <math.h>
 # include "isnanl-nolibm.h"
 # include "fpucw.h"
 #endif
 
-#if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
+#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
 # include <math.h>
 # include <math.h>
-# include "isnan.h"
+# include "isnand-nolibm.h"
 # include "printf-frexp.h"
 # include "printf-frexp.h"
+#endif
+
+#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
+# include <math.h>
 # include "isnanl-nolibm.h"
 # include "printf-frexpl.h"
 # include "fpucw.h"
 #endif
 
 # include "isnanl-nolibm.h"
 # include "printf-frexpl.h"
 # include "fpucw.h"
 #endif
 
-/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
-#ifndef EOVERFLOW
-# define EOVERFLOW E2BIG
-#endif
-
-#if HAVE_WCHAR_T
-# if HAVE_WCSLEN
-#  define local_wcslen wcslen
-# else
-   /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
-      a dependency towards this library, here is a local substitute.
-      Define this substitute only once, even if this file is included
-      twice in the same compilation unit.  */
-#  ifndef local_wcslen_defined
-#   define local_wcslen_defined 1
-static size_t
-local_wcslen (const wchar_t *s)
-{
-  const wchar_t *ptr;
-
-  for (ptr = s; *ptr != (wchar_t) 0; ptr++)
-    ;
-  return ptr - s;
-}
-#  endif
-# endif
-#endif
-
 /* Default parameters.  */
 #ifndef VASNPRINTF
 # if WIDE_CHAR_VERSION
 /* Default parameters.  */
 #ifndef VASNPRINTF
 # if WIDE_CHAR_VERSION
@@ -154,6 +129,7 @@ local_wcslen (const wchar_t *s)
 #  define DIRECTIVES wchar_t_directives
 #  define PRINTF_PARSE wprintf_parse
 #  define DCHAR_CPY wmemcpy
 #  define DIRECTIVES wchar_t_directives
 #  define PRINTF_PARSE wprintf_parse
 #  define DCHAR_CPY wmemcpy
+#  define DCHAR_SET wmemset
 # else
 #  define VASNPRINTF vasnprintf
 #  define FCHAR_T char
 # else
 #  define VASNPRINTF vasnprintf
 #  define FCHAR_T char
@@ -164,6 +140,7 @@ local_wcslen (const wchar_t *s)
 #  define DIRECTIVES char_directives
 #  define PRINTF_PARSE printf_parse
 #  define DCHAR_CPY memcpy
 #  define DIRECTIVES char_directives
 #  define PRINTF_PARSE printf_parse
 #  define DCHAR_CPY memcpy
+#  define DCHAR_SET memset
 # endif
 #endif
 #if WIDE_CHAR_VERSION
 # endif
 #endif
 #if WIDE_CHAR_VERSION
@@ -171,25 +148,40 @@ local_wcslen (const wchar_t *s)
 # define USE_SNPRINTF 1
 # if HAVE_DECL__SNWPRINTF
    /* On Windows, the function swprintf() has a different signature than
 # define USE_SNPRINTF 1
 # if HAVE_DECL__SNWPRINTF
    /* On Windows, the function swprintf() has a different signature than
-      on Unix; we use the _snwprintf() function instead.  */
-#  define SNPRINTF _snwprintf
+      on Unix; we use the function _snwprintf() or - on mingw - snwprintf()
+      instead.  The mingw function snwprintf() has fewer bugs than the
+      MSVCRT function _snwprintf(), so prefer that.  */
+#  if defined __MINGW32__
+#   define SNPRINTF snwprintf
+#  else
+#   define SNPRINTF _snwprintf
+#  endif
 # else
    /* Unix.  */
 #  define SNPRINTF swprintf
 # endif
 #else
   /* TCHAR_T is char.  */
 # else
    /* Unix.  */
 #  define SNPRINTF swprintf
 # endif
 #else
   /* TCHAR_T is char.  */
-# /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
+  /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
      But don't use it on BeOS, since BeOS snprintf produces no output if the
      But don't use it on BeOS, since BeOS snprintf produces no output if the
-     size argument is >= 0x3000000.  */
-# if (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) && !defined __BEOS__
+     size argument is >= 0x3000000.
+     Also don't use it on Linux libc5, since there snprintf with size = 1
+     writes any output without bounds, like sprintf.  */
+# if (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) && !defined __BEOS__ && !(__GNU_LIBRARY__ == 1)
 #  define USE_SNPRINTF 1
 # else
 #  define USE_SNPRINTF 0
 # endif
 # if HAVE_DECL__SNPRINTF
 #  define USE_SNPRINTF 1
 # else
 #  define USE_SNPRINTF 0
 # endif
 # if HAVE_DECL__SNPRINTF
-   /* Windows.  */
-#  define SNPRINTF _snprintf
+   /* Windows.  The mingw function snprintf() has fewer bugs than the MSVCRT
+      function _snprintf(), so prefer that.  */
+#  if defined __MINGW32__
+#   define SNPRINTF snprintf
+    /* Here we need to call the native snprintf, not rpl_snprintf.  */
+#   undef snprintf
+#  else
+#   define SNPRINTF _snprintf
+#  endif
 # else
    /* Unix.  */
 #  define SNPRINTF snprintf
 # else
    /* Unix.  */
 #  define SNPRINTF snprintf
@@ -200,19 +192,92 @@ local_wcslen (const wchar_t *s)
 /* Here we need to call the native sprintf, not rpl_sprintf.  */
 #undef sprintf
 
 /* Here we need to call the native sprintf, not rpl_sprintf.  */
 #undef sprintf
 
-#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
+/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
+   warnings in this file.  Use -Dlint to suppress them.  */
+#ifdef lint
+# define IF_LINT(Code) Code
+#else
+# define IF_LINT(Code) /* empty */
+#endif
+
+/* Avoid some warnings from "gcc -Wshadow".
+   This file doesn't use the exp() and remainder() functions.  */
+#undef exp
+#define exp expo
+#undef remainder
+#define remainder rem
+
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION
+# if (HAVE_STRNLEN && !defined _AIX)
+#  define local_strnlen strnlen
+# else
+#  ifndef local_strnlen_defined
+#   define local_strnlen_defined 1
+static size_t
+local_strnlen (const char *string, size_t maxlen)
+{
+  const char *end = memchr (string, '\0', maxlen);
+  return end ? (size_t) (end - string) : maxlen;
+}
+#  endif
+# endif
+#endif
+
+#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
+# if HAVE_WCSLEN
+#  define local_wcslen wcslen
+# else
+   /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
+      a dependency towards this library, here is a local substitute.
+      Define this substitute only once, even if this file is included
+      twice in the same compilation unit.  */
+#  ifndef local_wcslen_defined
+#   define local_wcslen_defined 1
+static size_t
+local_wcslen (const wchar_t *s)
+{
+  const wchar_t *ptr;
+
+  for (ptr = s; *ptr != (wchar_t) 0; ptr++)
+    ;
+  return ptr - s;
+}
+#  endif
+# endif
+#endif
+
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+# if HAVE_WCSNLEN
+#  define local_wcsnlen wcsnlen
+# else
+#  ifndef local_wcsnlen_defined
+#   define local_wcsnlen_defined 1
+static size_t
+local_wcsnlen (const wchar_t *s, size_t maxlen)
+{
+  const wchar_t *ptr;
+
+  for (ptr = s; maxlen > 0 && *ptr != (wchar_t) 0; ptr++, maxlen--)
+    ;
+  return ptr - s;
+}
+#  endif
+# endif
+#endif
+
+#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
 /* Determine the decimal-point character according to the current locale.  */
 # ifndef decimal_point_char_defined
 #  define decimal_point_char_defined 1
 static char
 /* Determine the decimal-point character according to the current locale.  */
 # ifndef decimal_point_char_defined
 #  define decimal_point_char_defined 1
 static char
-decimal_point_char ()
+decimal_point_char (void)
 {
   const char *point;
   /* Determine it in a multithread-safe way.  We know nl_langinfo is
 {
   const char *point;
   /* Determine it in a multithread-safe way.  We know nl_langinfo is
-     multithread-safe on glibc systems, but is not required to be multithread-
-     safe by POSIX.  sprintf(), however, is multithread-safe.  localeconv()
-     is rarely multithread-safe.  */
-#  if HAVE_NL_LANGINFO && __GLIBC__
+     multithread-safe on glibc systems and MacOS X systems, but is not required
+     to be multithread-safe by POSIX.  sprintf(), however, is multithread-safe.
+     localeconv() is rarely multithread-safe.  */
+#  if HAVE_NL_LANGINFO && (__GLIBC__ || (defined __APPLE__ && defined __MACH__))
   point = nl_langinfo (RADIXCHAR);
 #  elif 1
   char pointbuf[5];
   point = nl_langinfo (RADIXCHAR);
 #  elif 1
   char pointbuf[5];
@@ -227,29 +292,29 @@ decimal_point_char ()
 # endif
 #endif
 
 # endif
 #endif
 
-#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL
+#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL
 
 /* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */
 static int
 is_infinite_or_zero (double x)
 {
 
 /* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */
 static int
 is_infinite_or_zero (double x)
 {
-  return isnan (x) || x + x == x;
+  return isnand (x) || x + x == x;
 }
 
 #endif
 
 }
 
 #endif
 
-#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL
+#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
 
 
-/* Equivalent to !isfinite(x), but does not require libm.  */
+/* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */
 static int
 static int
-is_infinitel (long double x)
+is_infinite_or_zerol (long double x)
 {
 {
-  return isnanl (x) || (x + x == x && x != 0.0L);
+  return isnanl (x) || x + x == x;
 }
 
 #endif
 
 }
 
 #endif
 
-#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
 
 /* Converting 'long double' to decimal without rare rounding bugs requires
    real bignums.  We use the naming conventions of GNU gmp, but vastly simpler
 
 /* Converting 'long double' to decimal without rare rounding bugs requires
    real bignums.  We use the naming conventions of GNU gmp, but vastly simpler
@@ -312,26 +377,26 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
       dlen = len1 + len2;
       dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
       if (dp == NULL)
       dlen = len1 + len2;
       dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
       if (dp == NULL)
-       return NULL;
+        return NULL;
       for (k = len2; k > 0; )
       for (k = len2; k > 0; )
-       dp[--k] = 0;
+        dp[--k] = 0;
       for (i = 0; i < len1; i++)
       for (i = 0; i < len1; i++)
-       {
-         mp_limb_t digit1 = p1[i];
-         mp_twolimb_t carry = 0;
-         for (j = 0; j < len2; j++)
-           {
-             mp_limb_t digit2 = p2[j];
-             carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
-             carry += dp[i + j];
-             dp[i + j] = (mp_limb_t) carry;
-             carry = carry >> GMP_LIMB_BITS;
-           }
-         dp[i + len2] = (mp_limb_t) carry;
-       }
+        {
+          mp_limb_t digit1 = p1[i];
+          mp_twolimb_t carry = 0;
+          for (j = 0; j < len2; j++)
+            {
+              mp_limb_t digit2 = p2[j];
+              carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
+              carry += dp[i + j];
+              dp[i + j] = (mp_limb_t) carry;
+              carry = carry >> GMP_LIMB_BITS;
+            }
+          dp[i + len2] = (mp_limb_t) carry;
+        }
       /* Normalise.  */
       while (dlen > 0 && dp[dlen - 1] == 0)
       /* Normalise.  */
       while (dlen > 0 && dp[dlen - 1] == 0)
-       dlen--;
+        dlen--;
       dest->nlimbs = dlen;
       dest->limbs = dp;
     }
       dest->nlimbs = dlen;
       dest->limbs = dp;
     }
@@ -361,7 +426,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
        Normalise [q[m-1],...,q[0]], yields q.
      If m>=n>1, perform a multiple-precision division:
        We have a/b < beta^(m-n+1).
        Normalise [q[m-1],...,q[0]], yields q.
      If m>=n>1, perform a multiple-precision division:
        We have a/b < beta^(m-n+1).
-       s:=intDsize-1-(hightest bit in b[n-1]), 0<=s<intDsize.
+       s:=intDsize-1-(highest bit in b[n-1]), 0<=s<intDsize.
        Shift a and b left by s bits, copying them. r:=a.
        r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2.
        For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).}
        Shift a and b left by s bits, copying them. r:=a.
        r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2.
        For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).}
@@ -425,12 +490,12 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
   for (;;)
     {
       if (b_len == 0)
   for (;;)
     {
       if (b_len == 0)
-       /* Division by zero.  */
-       abort ();
+        /* Division by zero.  */
+        abort ();
       if (b_ptr[b_len - 1] == 0)
       if (b_ptr[b_len - 1] == 0)
-       b_len--;
+        b_len--;
       else
       else
-       break;
+        break;
     }
 
   /* Here m = a_len >= 0 and n = b_len > 0.  */
     }
 
   /* Here m = a_len >= 0 and n = b_len > 0.  */
@@ -447,261 +512,261 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
   else if (b_len == 1)
     {
       /* n=1: single precision division.
   else if (b_len == 1)
     {
       /* n=1: single precision division.
-        beta^(m-1) <= a < beta^m  ==>  beta^(m-2) <= a/b < beta^m  */
+         beta^(m-1) <= a < beta^m  ==>  beta^(m-2) <= a/b < beta^m  */
       r_ptr = roomptr;
       q_ptr = roomptr + 1;
       {
       r_ptr = roomptr;
       q_ptr = roomptr + 1;
       {
-       mp_limb_t den = b_ptr[0];
-       mp_limb_t remainder = 0;
-       const mp_limb_t *sourceptr = a_ptr + a_len;
-       mp_limb_t *destptr = q_ptr + a_len;
-       size_t count;
-       for (count = a_len; count > 0; count--)
-         {
-           mp_twolimb_t num =
-             ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
-           *--destptr = num / den;
-           remainder = num % den;
-         }
-       /* Normalise and store r.  */
-       if (remainder > 0)
-         {
-           r_ptr[0] = remainder;
-           r_len = 1;
-         }
-       else
-         r_len = 0;
-       /* Normalise q.  */
-       q_len = a_len;
-       if (q_ptr[q_len - 1] == 0)
-         q_len--;
+        mp_limb_t den = b_ptr[0];
+        mp_limb_t remainder = 0;
+        const mp_limb_t *sourceptr = a_ptr + a_len;
+        mp_limb_t *destptr = q_ptr + a_len;
+        size_t count;
+        for (count = a_len; count > 0; count--)
+          {
+            mp_twolimb_t num =
+              ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
+            *--destptr = num / den;
+            remainder = num % den;
+          }
+        /* Normalise and store r.  */
+        if (remainder > 0)
+          {
+            r_ptr[0] = remainder;
+            r_len = 1;
+          }
+        else
+          r_len = 0;
+        /* Normalise q.  */
+        q_len = a_len;
+        if (q_ptr[q_len - 1] == 0)
+          q_len--;
       }
     }
   else
     {
       /* n>1: multiple precision division.
       }
     }
   else
     {
       /* n>1: multiple precision division.
-        beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n  ==>
-        beta^(m-n-1) <= a/b < beta^(m-n+1).  */
+         beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n  ==>
+         beta^(m-n-1) <= a/b < beta^(m-n+1).  */
       /* Determine s.  */
       size_t s;
       {
       /* Determine s.  */
       size_t s;
       {
-       mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
-       s = 31;
-       if (msd >= 0x10000)
-         {
-           msd = msd >> 16;
-           s -= 16;
-         }
-       if (msd >= 0x100)
-         {
-           msd = msd >> 8;
-           s -= 8;
-         }
-       if (msd >= 0x10)
-         {
-           msd = msd >> 4;
-           s -= 4;
-         }
-       if (msd >= 0x4)
-         {
-           msd = msd >> 2;
-           s -= 2;
-         }
-       if (msd >= 0x2)
-         {
-           msd = msd >> 1;
-           s -= 1;
-         }
+        mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
+        s = 31;
+        if (msd >= 0x10000)
+          {
+            msd = msd >> 16;
+            s -= 16;
+          }
+        if (msd >= 0x100)
+          {
+            msd = msd >> 8;
+            s -= 8;
+          }
+        if (msd >= 0x10)
+          {
+            msd = msd >> 4;
+            s -= 4;
+          }
+        if (msd >= 0x4)
+          {
+            msd = msd >> 2;
+            s -= 2;
+          }
+        if (msd >= 0x2)
+          {
+            msd = msd >> 1;
+            s -= 1;
+          }
       }
       /* 0 <= s < GMP_LIMB_BITS.
       }
       /* 0 <= s < GMP_LIMB_BITS.
-        Copy b, shifting it left by s bits.  */
+         Copy b, shifting it left by s bits.  */
       if (s > 0)
       if (s > 0)
-       {
-         tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t));
-         if (tmp_roomptr == NULL)
-           {
-             free (roomptr);
-             return NULL;
-           }
-         {
-           const mp_limb_t *sourceptr = b_ptr;
-           mp_limb_t *destptr = tmp_roomptr;
-           mp_twolimb_t accu = 0;
-           size_t count;
-           for (count = b_len; count > 0; count--)
-             {
-               accu += (mp_twolimb_t) *sourceptr++ << s;
-               *destptr++ = (mp_limb_t) accu;
-               accu = accu >> GMP_LIMB_BITS;
-             }
-           /* accu must be zero, since that was how s was determined.  */
-           if (accu != 0)
-             abort ();
-         }
-         b_ptr = tmp_roomptr;
-       }
+        {
+          tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t));
+          if (tmp_roomptr == NULL)
+            {
+              free (roomptr);
+              return NULL;
+            }
+          {
+            const mp_limb_t *sourceptr = b_ptr;
+            mp_limb_t *destptr = tmp_roomptr;
+            mp_twolimb_t accu = 0;
+            size_t count;
+            for (count = b_len; count > 0; count--)
+              {
+                accu += (mp_twolimb_t) *sourceptr++ << s;
+                *destptr++ = (mp_limb_t) accu;
+                accu = accu >> GMP_LIMB_BITS;
+              }
+            /* accu must be zero, since that was how s was determined.  */
+            if (accu != 0)
+              abort ();
+          }
+          b_ptr = tmp_roomptr;
+        }
       /* Copy a, shifting it left by s bits, yields r.
       /* Copy a, shifting it left by s bits, yields r.
-        Memory layout:
-        At the beginning: r = roomptr[0..a_len],
-        at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len]  */
+         Memory layout:
+         At the beginning: r = roomptr[0..a_len],
+         at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len]  */
       r_ptr = roomptr;
       if (s == 0)
       r_ptr = roomptr;
       if (s == 0)
-       {
-         memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
-         r_ptr[a_len] = 0;
-       }
+        {
+          memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
+          r_ptr[a_len] = 0;
+        }
       else
       else
-       {
-         const mp_limb_t *sourceptr = a_ptr;
-         mp_limb_t *destptr = r_ptr;
-         mp_twolimb_t accu = 0;
-         size_t count;
-         for (count = a_len; count > 0; count--)
-           {
-             accu += (mp_twolimb_t) *sourceptr++ << s;
-             *destptr++ = (mp_limb_t) accu;
-             accu = accu >> GMP_LIMB_BITS;
-           }
-         *destptr++ = (mp_limb_t) accu;
-       }
+        {
+          const mp_limb_t *sourceptr = a_ptr;
+          mp_limb_t *destptr = r_ptr;
+          mp_twolimb_t accu = 0;
+          size_t count;
+          for (count = a_len; count > 0; count--)
+            {
+              accu += (mp_twolimb_t) *sourceptr++ << s;
+              *destptr++ = (mp_limb_t) accu;
+              accu = accu >> GMP_LIMB_BITS;
+            }
+          *destptr++ = (mp_limb_t) accu;
+        }
       q_ptr = roomptr + b_len;
       q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */
       {
       q_ptr = roomptr + b_len;
       q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */
       {
-       size_t j = a_len - b_len; /* m-n */
-       mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */
-       mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */
-       mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */
-         ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd;
-       /* Division loop, traversed m-n+1 times.
-          j counts down, b is unchanged, beta/2 <= b[n-1] < beta.  */
-       for (;;)
-         {
-           mp_limb_t q_star;
-           mp_limb_t c1;
-           if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */
-             {
-               /* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow.  */
-               mp_twolimb_t num =
-                 ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS)
-                 | r_ptr[j + b_len - 1];
-               q_star = num / b_msd;
-               c1 = num % b_msd;
-             }
-           else
-             {
-               /* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1].  */
-               q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */
-               /* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta
-                  <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta
-                  <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta)
-                       {<= beta !}.
-                  If yes, jump directly to the subtraction loop.
-                  (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta
-                   <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */
-               if (r_ptr[j + b_len] > b_msd
-                   || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd)
-                 /* r[j+n] >= b[n-1]+1 or
-                    r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a
-                    carry.  */
-                 goto subtract;
-             }
-           /* q_star = q*,
-              c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta).  */
-           {
-             mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */
-               ((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2];
-             mp_twolimb_t c3 = /* b[n-2] * q* */
-               (mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star;
-             /* While c2 < c3, increase c2 and decrease c3.
-                Consider c3-c2.  While it is > 0, decrease it by
-                b[n-1]*beta+b[n-2].  Because of b[n-1]*beta+b[n-2] >= beta^2/2
-                this can happen only twice.  */
-             if (c3 > c2)
-               {
-                 q_star = q_star - 1; /* q* := q* - 1 */
-                 if (c3 - c2 > b_msdd)
-                   q_star = q_star - 1; /* q* := q* - 1 */
-               }
-           }
-           if (q_star > 0)
-             subtract:
-             {
-               /* Subtract r := r - b * q* * beta^j.  */
-               mp_limb_t cr;
-               {
-                 const mp_limb_t *sourceptr = b_ptr;
-                 mp_limb_t *destptr = r_ptr + j;
-                 mp_twolimb_t carry = 0;
-                 size_t count;
-                 for (count = b_len; count > 0; count--)
-                   {
-                     /* Here 0 <= carry <= q*.  */
-                     carry =
-                       carry
-                       + (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++
-                       + (mp_limb_t) ~(*destptr);
-                     /* Here 0 <= carry <= beta*q* + beta-1.  */
-                     *destptr++ = ~(mp_limb_t) carry;
-                     carry = carry >> GMP_LIMB_BITS; /* <= q* */
-                   }
-                 cr = (mp_limb_t) carry;
-               }
-               /* Subtract cr from r_ptr[j + b_len], then forget about
-                  r_ptr[j + b_len].  */
-               if (cr > r_ptr[j + b_len])
-                 {
-                   /* Subtraction gave a carry.  */
-                   q_star = q_star - 1; /* q* := q* - 1 */
-                   /* Add b back.  */
-                   {
-                     const mp_limb_t *sourceptr = b_ptr;
-                     mp_limb_t *destptr = r_ptr + j;
-                     mp_limb_t carry = 0;
-                     size_t count;
-                     for (count = b_len; count > 0; count--)
-                       {
-                         mp_limb_t source1 = *sourceptr++;
-                         mp_limb_t source2 = *destptr;
-                         *destptr++ = source1 + source2 + carry;
-                         carry =
-                           (carry
-                            ? source1 >= (mp_limb_t) ~source2
-                            : source1 > (mp_limb_t) ~source2);
-                       }
-                   }
-                   /* Forget about the carry and about r[j+n].  */
-                 }
-             }
-           /* q* is determined.  Store it as q[j].  */
-           q_ptr[j] = q_star;
-           if (j == 0)
-             break;
-           j--;
-         }
+        size_t j = a_len - b_len; /* m-n */
+        mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */
+        mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */
+        mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */
+          ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd;
+        /* Division loop, traversed m-n+1 times.
+           j counts down, b is unchanged, beta/2 <= b[n-1] < beta.  */
+        for (;;)
+          {
+            mp_limb_t q_star;
+            mp_limb_t c1;
+            if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */
+              {
+                /* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow.  */
+                mp_twolimb_t num =
+                  ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS)
+                  | r_ptr[j + b_len - 1];
+                q_star = num / b_msd;
+                c1 = num % b_msd;
+              }
+            else
+              {
+                /* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1].  */
+                q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */
+                /* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta
+                   <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta
+                   <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta)
+                        {<= beta !}.
+                   If yes, jump directly to the subtraction loop.
+                   (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta
+                    <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */
+                if (r_ptr[j + b_len] > b_msd
+                    || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd)
+                  /* r[j+n] >= b[n-1]+1 or
+                     r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a
+                     carry.  */
+                  goto subtract;
+              }
+            /* q_star = q*,
+               c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta).  */
+            {
+              mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */
+                ((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2];
+              mp_twolimb_t c3 = /* b[n-2] * q* */
+                (mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star;
+              /* While c2 < c3, increase c2 and decrease c3.
+                 Consider c3-c2.  While it is > 0, decrease it by
+                 b[n-1]*beta+b[n-2].  Because of b[n-1]*beta+b[n-2] >= beta^2/2
+                 this can happen only twice.  */
+              if (c3 > c2)
+                {
+                  q_star = q_star - 1; /* q* := q* - 1 */
+                  if (c3 - c2 > b_msdd)
+                    q_star = q_star - 1; /* q* := q* - 1 */
+                }
+            }
+            if (q_star > 0)
+              subtract:
+              {
+                /* Subtract r := r - b * q* * beta^j.  */
+                mp_limb_t cr;
+                {
+                  const mp_limb_t *sourceptr = b_ptr;
+                  mp_limb_t *destptr = r_ptr + j;
+                  mp_twolimb_t carry = 0;
+                  size_t count;
+                  for (count = b_len; count > 0; count--)
+                    {
+                      /* Here 0 <= carry <= q*.  */
+                      carry =
+                        carry
+                        + (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++
+                        + (mp_limb_t) ~(*destptr);
+                      /* Here 0 <= carry <= beta*q* + beta-1.  */
+                      *destptr++ = ~(mp_limb_t) carry;
+                      carry = carry >> GMP_LIMB_BITS; /* <= q* */
+                    }
+                  cr = (mp_limb_t) carry;
+                }
+                /* Subtract cr from r_ptr[j + b_len], then forget about
+                   r_ptr[j + b_len].  */
+                if (cr > r_ptr[j + b_len])
+                  {
+                    /* Subtraction gave a carry.  */
+                    q_star = q_star - 1; /* q* := q* - 1 */
+                    /* Add b back.  */
+                    {
+                      const mp_limb_t *sourceptr = b_ptr;
+                      mp_limb_t *destptr = r_ptr + j;
+                      mp_limb_t carry = 0;
+                      size_t count;
+                      for (count = b_len; count > 0; count--)
+                        {
+                          mp_limb_t source1 = *sourceptr++;
+                          mp_limb_t source2 = *destptr;
+                          *destptr++ = source1 + source2 + carry;
+                          carry =
+                            (carry
+                             ? source1 >= (mp_limb_t) ~source2
+                             : source1 > (mp_limb_t) ~source2);
+                        }
+                    }
+                    /* Forget about the carry and about r[j+n].  */
+                  }
+              }
+            /* q* is determined.  Store it as q[j].  */
+            q_ptr[j] = q_star;
+            if (j == 0)
+              break;
+            j--;
+          }
       }
       r_len = b_len;
       /* Normalise q.  */
       if (q_ptr[q_len - 1] == 0)
       }
       r_len = b_len;
       /* Normalise q.  */
       if (q_ptr[q_len - 1] == 0)
-       q_len--;
+        q_len--;
 # if 0 /* Not needed here, since we need r only to compare it with b/2, and
 # if 0 /* Not needed here, since we need r only to compare it with b/2, and
-         b is shifted left by s bits.  */
+          b is shifted left by s bits.  */
       /* Shift r right by s bits.  */
       if (s > 0)
       /* Shift r right by s bits.  */
       if (s > 0)
-       {
-         mp_limb_t ptr = r_ptr + r_len;
-         mp_twolimb_t accu = 0;
-         size_t count;
-         for (count = r_len; count > 0; count--)
-           {
-             accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
-             accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s);
-             *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS);
-           }
-       }
+        {
+          mp_limb_t ptr = r_ptr + r_len;
+          mp_twolimb_t accu = 0;
+          size_t count;
+          for (count = r_len; count > 0; count--)
+            {
+              accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
+              accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s);
+              *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS);
+            }
+        }
 # endif
       /* Normalise r.  */
       while (r_len > 0 && r_ptr[r_len - 1] == 0)
 # endif
       /* Normalise r.  */
       while (r_len > 0 && r_ptr[r_len - 1] == 0)
-       r_len--;
+        r_len--;
     }
   /* Compare r << 1 with b.  */
   if (r_len > b_len)
     }
   /* Compare r << 1 with b.  */
   if (r_len > b_len)
@@ -710,17 +775,17 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
     size_t i;
     for (i = b_len;;)
       {
     size_t i;
     for (i = b_len;;)
       {
-       mp_limb_t r_i =
-         (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
-         | (i < r_len ? r_ptr[i] << 1 : 0);
-       mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
-       if (r_i > b_i)
-         goto increment_q;
-       if (r_i < b_i)
-         goto keep_q;
-       if (i == 0)
-         break;
-       i--;
+        mp_limb_t r_i =
+          (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
+          | (i < r_len ? r_ptr[i] << 1 : 0);
+        mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
+        if (r_i > b_i)
+          goto increment_q;
+        if (r_i < b_i)
+          goto keep_q;
+        if (i == 0)
+          break;
+        i--;
       }
   }
   if (q_len > 0 && ((q_ptr[0] & 1) != 0))
       }
   }
   if (q_len > 0 && ((q_ptr[0] & 1) != 0))
@@ -729,8 +794,8 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
     {
       size_t i;
       for (i = 0; i < q_len; i++)
     {
       size_t i;
       for (i = 0; i < q_len; i++)
-       if (++(q_ptr[i]) != 0)
-         goto keep_q;
+        if (++(q_ptr[i]) != 0)
+          goto keep_q;
       q_ptr[q_len++] = 1;
     }
   keep_q:
       q_ptr[q_len++] = 1;
     }
   keep_q:
@@ -759,42 +824,44 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
     {
       char *d_ptr = c_ptr;
       for (; extra_zeroes > 0; extra_zeroes--)
     {
       char *d_ptr = c_ptr;
       for (; extra_zeroes > 0; extra_zeroes--)
-       *d_ptr++ = '0';
+        *d_ptr++ = '0';
       while (a_len > 0)
       while (a_len > 0)
-       {
-         /* Divide a by 10^9, in-place.  */
-         mp_limb_t remainder = 0;
-         mp_limb_t *ptr = a_ptr + a_len;
-         size_t count;
-         for (count = a_len; count > 0; count--)
-           {
-             mp_twolimb_t num =
-               ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr;
-             *ptr = num / 1000000000;
-             remainder = num % 1000000000;
-           }
-         /* Store the remainder as 9 decimal digits.  */
-         for (count = 9; count > 0; count--)
-           {
-             *d_ptr++ = '0' + (remainder % 10);
-             remainder = remainder / 10;
-           }
-         /* Normalize a.  */
-         if (a_ptr[a_len - 1] == 0)
-           a_len--;
-       }
+        {
+          /* Divide a by 10^9, in-place.  */
+          mp_limb_t remainder = 0;
+          mp_limb_t *ptr = a_ptr + a_len;
+          size_t count;
+          for (count = a_len; count > 0; count--)
+            {
+              mp_twolimb_t num =
+                ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr;
+              *ptr = num / 1000000000;
+              remainder = num % 1000000000;
+            }
+          /* Store the remainder as 9 decimal digits.  */
+          for (count = 9; count > 0; count--)
+            {
+              *d_ptr++ = '0' + (remainder % 10);
+              remainder = remainder / 10;
+            }
+          /* Normalize a.  */
+          if (a_ptr[a_len - 1] == 0)
+            a_len--;
+        }
       /* Remove leading zeroes.  */
       while (d_ptr > c_ptr && d_ptr[-1] == '0')
       /* Remove leading zeroes.  */
       while (d_ptr > c_ptr && d_ptr[-1] == '0')
-       d_ptr--;
+        d_ptr--;
       /* But keep at least one zero.  */
       if (d_ptr == c_ptr)
       /* But keep at least one zero.  */
       if (d_ptr == c_ptr)
-       *d_ptr++ = '0';
+        *d_ptr++ = '0';
       /* Terminate the string.  */
       *d_ptr = '\0';
     }
   return c_ptr;
 }
 
       /* Terminate the string.  */
       *d_ptr = '\0';
     }
   return c_ptr;
 }
 
+# if NEED_PRINTF_LONG_DOUBLE
+
 /* Assuming x is finite and >= 0:
    write x as x = 2^e * m, where m is a bignum.
    Return the allocated memory in case of success, NULL in case of memory
 /* Assuming x is finite and >= 0:
    write x as x = 2^e * m, where m is a bignum.
    Return the allocated memory in case of success, NULL in case of memory
@@ -823,34 +890,34 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
      2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
      'long double' values between 0 and 2^16 (to 'unsigned int' or 'int',
      doesn't matter).  */
      2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
      'long double' values between 0 and 2^16 (to 'unsigned int' or 'int',
      doesn't matter).  */
-# if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0
-#  if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
+#  if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0
+#   if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
     {
       mp_limb_t hi, lo;
       y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2));
       hi = (int) y;
       y -= hi;
       if (!(y >= 0.0L && y < 1.0L))
     {
       mp_limb_t hi, lo;
       y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2));
       hi = (int) y;
       y -= hi;
       if (!(y >= 0.0L && y < 1.0L))
-       abort ();
+        abort ();
       y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
       lo = (int) y;
       y -= lo;
       if (!(y >= 0.0L && y < 1.0L))
       y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
       lo = (int) y;
       y -= lo;
       if (!(y >= 0.0L && y < 1.0L))
-       abort ();
+        abort ();
       m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
     }
       m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
     }
-#  else
+#   else
     {
       mp_limb_t d;
       y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS);
       d = (int) y;
       y -= d;
       if (!(y >= 0.0L && y < 1.0L))
     {
       mp_limb_t d;
       y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS);
       d = (int) y;
       y -= d;
       if (!(y >= 0.0L && y < 1.0L))
-       abort ();
+        abort ();
       m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d;
     }
       m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d;
     }
+#   endif
 #  endif
 #  endif
-# endif
   for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
     {
       mp_limb_t hi, lo;
   for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
     {
       mp_limb_t hi, lo;
@@ -858,16 +925,19 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
       hi = (int) y;
       y -= hi;
       if (!(y >= 0.0L && y < 1.0L))
       hi = (int) y;
       y -= hi;
       if (!(y >= 0.0L && y < 1.0L))
-       abort ();
+        abort ();
       y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
       lo = (int) y;
       y -= lo;
       if (!(y >= 0.0L && y < 1.0L))
       y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
       lo = (int) y;
       y -= lo;
       if (!(y >= 0.0L && y < 1.0L))
-       abort ();
+        abort ();
       m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
     }
       m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
     }
+#if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess
+         precision.  */
   if (!(y == 0.0L))
     abort ();
   if (!(y == 0.0L))
     abort ();
+#endif
   /* Normalise.  */
   while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
     m.nlimbs--;
   /* Normalise.  */
   while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
     m.nlimbs--;
@@ -876,17 +946,101 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
   return m.limbs;
 }
 
   return m.limbs;
 }
 
-/* Assuming x is finite and >= 0, and n is an integer:
+# endif
+
+# if NEED_PRINTF_DOUBLE
+
+/* Assuming x is finite and >= 0:
+   write x as x = 2^e * m, where m is a bignum.
+   Return the allocated memory in case of success, NULL in case of memory
+   allocation failure.  */
+static void *
+decode_double (double x, int *ep, mpn_t *mp)
+{
+  mpn_t m;
+  int exp;
+  double y;
+  size_t i;
+
+  /* Allocate memory for result.  */
+  m.nlimbs = (DBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+  m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
+  if (m.limbs == NULL)
+    return NULL;
+  /* Split into exponential part and mantissa.  */
+  y = frexp (x, &exp);
+  if (!(y >= 0.0 && y < 1.0))
+    abort ();
+  /* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * DBL_MANT_BIT), and the
+     latter is an integer.  */
+  /* Convert the mantissa (y * DBL_MANT_BIT) to a sequence of limbs.
+     I'm not sure whether it's safe to cast a 'double' value between
+     2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
+     'double' values between 0 and 2^16 (to 'unsigned int' or 'int',
+     doesn't matter).  */
+#  if (DBL_MANT_BIT % GMP_LIMB_BITS) != 0
+#   if (DBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
+    {
+      mp_limb_t hi, lo;
+      y *= (mp_limb_t) 1 << (DBL_MANT_BIT % (GMP_LIMB_BITS / 2));
+      hi = (int) y;
+      y -= hi;
+      if (!(y >= 0.0 && y < 1.0))
+        abort ();
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      lo = (int) y;
+      y -= lo;
+      if (!(y >= 0.0 && y < 1.0))
+        abort ();
+      m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
+    }
+#   else
+    {
+      mp_limb_t d;
+      y *= (mp_limb_t) 1 << (DBL_MANT_BIT % GMP_LIMB_BITS);
+      d = (int) y;
+      y -= d;
+      if (!(y >= 0.0 && y < 1.0))
+        abort ();
+      m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = d;
+    }
+#   endif
+#  endif
+  for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
+    {
+      mp_limb_t hi, lo;
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      hi = (int) y;
+      y -= hi;
+      if (!(y >= 0.0 && y < 1.0))
+        abort ();
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      lo = (int) y;
+      y -= lo;
+      if (!(y >= 0.0 && y < 1.0))
+        abort ();
+      m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
+    }
+  if (!(y == 0.0))
+    abort ();
+  /* Normalise.  */
+  while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
+    m.nlimbs--;
+  *mp = m;
+  *ep = exp - DBL_MANT_BIT;
+  return m.limbs;
+}
+
+# endif
+
+/* Assuming x = 2^e * m is finite and >= 0, and n is an integer:
    Returns the decimal representation of round (x * 10^n).
    Return the allocated memory - containing the decimal digits in low-to-high
    order, terminated with a NUL character - in case of success, NULL in case
    of memory allocation failure.  */
 static char *
    Returns the decimal representation of round (x * 10^n).
    Return the allocated memory - containing the decimal digits in low-to-high
    order, terminated with a NUL character - in case of success, NULL in case
    of memory allocation failure.  */
 static char *
-scale10_round_decimal_long_double (long double x, int n)
+scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
 {
 {
-  int e;
-  mpn_t m;
-  void *memory = decode_long_double (x, &e, &m);
   int s;
   size_t extra_zeroes;
   unsigned int abs_n;
   int s;
   size_t extra_zeroes;
   unsigned int abs_n;
@@ -922,8 +1076,8 @@ scale10_round_decimal_long_double (long double x, int n)
   abs_n = (n >= 0 ? n : -n);
   abs_s = (s >= 0 ? s : -s);
   pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
   abs_n = (n >= 0 ? n : -n);
   abs_s = (s >= 0 ? s : -s);
   pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
-                                   + abs_s / GMP_LIMB_BITS + 1)
-                                  * sizeof (mp_limb_t));
+                                    + abs_s / GMP_LIMB_BITS + 1)
+                                   * sizeof (mp_limb_t));
   if (pow5_ptr == NULL)
     {
       free (memory);
   if (pow5_ptr == NULL)
     {
       free (memory);
@@ -936,26 +1090,26 @@ scale10_round_decimal_long_double (long double x, int n)
   if (abs_n > 0)
     {
       static mp_limb_t const small_pow5[13 + 1] =
   if (abs_n > 0)
     {
       static mp_limb_t const small_pow5[13 + 1] =
-       {
-         1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
-         48828125, 244140625, 1220703125
-       };
+        {
+          1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
+          48828125, 244140625, 1220703125
+        };
       unsigned int n13;
       for (n13 = 0; n13 <= abs_n; n13 += 13)
       unsigned int n13;
       for (n13 = 0; n13 <= abs_n; n13 += 13)
-       {
-         mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
-         size_t j;
-         mp_twolimb_t carry = 0;
-         for (j = 0; j < pow5_len; j++)
-           {
-             mp_limb_t digit2 = pow5_ptr[j];
-             carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
-             pow5_ptr[j] = (mp_limb_t) carry;
-             carry = carry >> GMP_LIMB_BITS;
-           }
-         if (carry > 0)
-           pow5_ptr[pow5_len++] = (mp_limb_t) carry;
-       }
+        {
+          mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
+          size_t j;
+          mp_twolimb_t carry = 0;
+          for (j = 0; j < pow5_len; j++)
+            {
+              mp_limb_t digit2 = pow5_ptr[j];
+              carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
+              pow5_ptr[j] = (mp_limb_t) carry;
+              carry = carry >> GMP_LIMB_BITS;
+            }
+          if (carry > 0)
+            pow5_ptr[pow5_len++] = (mp_limb_t) carry;
+        }
     }
   s_limbs = abs_s / GMP_LIMB_BITS;
   s_bits = abs_s % GMP_LIMB_BITS;
     }
   s_limbs = abs_s / GMP_LIMB_BITS;
   s_bits = abs_s % GMP_LIMB_BITS;
@@ -963,129 +1117,129 @@ scale10_round_decimal_long_double (long double x, int n)
     {
       /* Multiply with 2^|s|.  */
       if (s_bits > 0)
     {
       /* Multiply with 2^|s|.  */
       if (s_bits > 0)
-       {
-         mp_limb_t *ptr = pow5_ptr;
-         mp_twolimb_t accu = 0;
-         size_t count;
-         for (count = pow5_len; count > 0; count--)
-           {
-             accu += (mp_twolimb_t) *ptr << s_bits;
-             *ptr++ = (mp_limb_t) accu;
-             accu = accu >> GMP_LIMB_BITS;
-           }
-         if (accu > 0)
-           {
-             *ptr = (mp_limb_t) accu;
-             pow5_len++;
-           }
-       }
+        {
+          mp_limb_t *ptr = pow5_ptr;
+          mp_twolimb_t accu = 0;
+          size_t count;
+          for (count = pow5_len; count > 0; count--)
+            {
+              accu += (mp_twolimb_t) *ptr << s_bits;
+              *ptr++ = (mp_limb_t) accu;
+              accu = accu >> GMP_LIMB_BITS;
+            }
+          if (accu > 0)
+            {
+              *ptr = (mp_limb_t) accu;
+              pow5_len++;
+            }
+        }
       if (s_limbs > 0)
       if (s_limbs > 0)
-       {
-         size_t count;
-         for (count = pow5_len; count > 0;)
-           {
-             count--;
-             pow5_ptr[s_limbs + count] = pow5_ptr[count];
-           }
-         for (count = s_limbs; count > 0;)
-           {
-             count--;
-             pow5_ptr[count] = 0;
-           }
-         pow5_len += s_limbs;
-       }
+        {
+          size_t count;
+          for (count = pow5_len; count > 0;)
+            {
+              count--;
+              pow5_ptr[s_limbs + count] = pow5_ptr[count];
+            }
+          for (count = s_limbs; count > 0;)
+            {
+              count--;
+              pow5_ptr[count] = 0;
+            }
+          pow5_len += s_limbs;
+        }
       pow5.limbs = pow5_ptr;
       pow5.nlimbs = pow5_len;
       if (n >= 0)
       pow5.limbs = pow5_ptr;
       pow5.nlimbs = pow5_len;
       if (n >= 0)
-       {
-         /* Multiply m with pow5.  No division needed.  */
-         z_memory = multiply (m, pow5, &z);
-       }
+        {
+          /* Multiply m with pow5.  No division needed.  */
+          z_memory = multiply (m, pow5, &z);
+        }
       else
       else
-       {
-         /* Divide m by pow5 and round.  */
-         z_memory = divide (m, pow5, &z);
-       }
+        {
+          /* Divide m by pow5 and round.  */
+          z_memory = divide (m, pow5, &z);
+        }
     }
   else
     {
       pow5.limbs = pow5_ptr;
       pow5.nlimbs = pow5_len;
       if (n >= 0)
     }
   else
     {
       pow5.limbs = pow5_ptr;
       pow5.nlimbs = pow5_len;
       if (n >= 0)
-       {
-         /* n >= 0, s < 0.
-            Multiply m with pow5, then divide by 2^|s|.  */
-         mpn_t numerator;
-         mpn_t denominator;
-         void *tmp_memory;
-         tmp_memory = multiply (m, pow5, &numerator);
-         if (tmp_memory == NULL)
-           {
-             free (pow5_ptr);
-             free (memory);
-             return NULL;
-           }
-         /* Construct 2^|s|.  */
-         {
-           mp_limb_t *ptr = pow5_ptr + pow5_len;
-           size_t i;
-           for (i = 0; i < s_limbs; i++)
-             ptr[i] = 0;
-           ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
-           denominator.limbs = ptr;
-           denominator.nlimbs = s_limbs + 1;
-         }
-         z_memory = divide (numerator, denominator, &z);
-         free (tmp_memory);
-       }
+        {
+          /* n >= 0, s < 0.
+             Multiply m with pow5, then divide by 2^|s|.  */
+          mpn_t numerator;
+          mpn_t denominator;
+          void *tmp_memory;
+          tmp_memory = multiply (m, pow5, &numerator);
+          if (tmp_memory == NULL)
+            {
+              free (pow5_ptr);
+              free (memory);
+              return NULL;
+            }
+          /* Construct 2^|s|.  */
+          {
+            mp_limb_t *ptr = pow5_ptr + pow5_len;
+            size_t i;
+            for (i = 0; i < s_limbs; i++)
+              ptr[i] = 0;
+            ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
+            denominator.limbs = ptr;
+            denominator.nlimbs = s_limbs + 1;
+          }
+          z_memory = divide (numerator, denominator, &z);
+          free (tmp_memory);
+        }
       else
       else
-       {
-         /* n < 0, s > 0.
-            Multiply m with 2^s, then divide by pow5.  */
-         mpn_t numerator;
-         mp_limb_t *num_ptr;
-         num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1)
-                                         * sizeof (mp_limb_t));
-         if (num_ptr == NULL)
-           {
-             free (pow5_ptr);
-             free (memory);
-             return NULL;
-           }
-         {
-           mp_limb_t *destptr = num_ptr;
-           {
-             size_t i;
-             for (i = 0; i < s_limbs; i++)
-               *destptr++ = 0;
-           }
-           if (s_bits > 0)
-             {
-               const mp_limb_t *sourceptr = m.limbs;
-               mp_twolimb_t accu = 0;
-               size_t count;
-               for (count = m.nlimbs; count > 0; count--)
-                 {
-                   accu += (mp_twolimb_t) *sourceptr++ << s;
-                   *destptr++ = (mp_limb_t) accu;
-                   accu = accu >> GMP_LIMB_BITS;
-                 }
-               if (accu > 0)
-                 *destptr++ = (mp_limb_t) accu;
-             }
-           else
-             {
-               const mp_limb_t *sourceptr = m.limbs;
-               size_t count;
-               for (count = m.nlimbs; count > 0; count--)
-                 *destptr++ = *sourceptr++;
-             }
-           numerator.limbs = num_ptr;
-           numerator.nlimbs = destptr - num_ptr;
-         }
-         z_memory = divide (numerator, pow5, &z);
-         free (num_ptr);
-       }
+        {
+          /* n < 0, s > 0.
+             Multiply m with 2^s, then divide by pow5.  */
+          mpn_t numerator;
+          mp_limb_t *num_ptr;
+          num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1)
+                                          * sizeof (mp_limb_t));
+          if (num_ptr == NULL)
+            {
+              free (pow5_ptr);
+              free (memory);
+              return NULL;
+            }
+          {
+            mp_limb_t *destptr = num_ptr;
+            {
+              size_t i;
+              for (i = 0; i < s_limbs; i++)
+                *destptr++ = 0;
+            }
+            if (s_bits > 0)
+              {
+                const mp_limb_t *sourceptr = m.limbs;
+                mp_twolimb_t accu = 0;
+                size_t count;
+                for (count = m.nlimbs; count > 0; count--)
+                  {
+                    accu += (mp_twolimb_t) *sourceptr++ << s_bits;
+                    *destptr++ = (mp_limb_t) accu;
+                    accu = accu >> GMP_LIMB_BITS;
+                  }
+                if (accu > 0)
+                  *destptr++ = (mp_limb_t) accu;
+              }
+            else
+              {
+                const mp_limb_t *sourceptr = m.limbs;
+                size_t count;
+                for (count = m.nlimbs; count > 0; count--)
+                  *destptr++ = *sourceptr++;
+              }
+            numerator.limbs = num_ptr;
+            numerator.nlimbs = destptr - num_ptr;
+          }
+          z_memory = divide (numerator, pow5, &z);
+          free (num_ptr);
+        }
     }
   free (pow5_ptr);
   free (memory);
     }
   free (pow5_ptr);
   free (memory);
@@ -1099,6 +1253,44 @@ scale10_round_decimal_long_double (long double x, int n)
   return digits;
 }
 
   return digits;
 }
 
+# if NEED_PRINTF_LONG_DOUBLE
+
+/* Assuming x is finite and >= 0, and n is an integer:
+   Returns the decimal representation of round (x * 10^n).
+   Return the allocated memory - containing the decimal digits in low-to-high
+   order, terminated with a NUL character - in case of success, NULL in case
+   of memory allocation failure.  */
+static char *
+scale10_round_decimal_long_double (long double x, int n)
+{
+  int e IF_LINT(= 0);
+  mpn_t m;
+  void *memory = decode_long_double (x, &e, &m);
+  return scale10_round_decimal_decoded (e, m, memory, n);
+}
+
+# endif
+
+# if NEED_PRINTF_DOUBLE
+
+/* Assuming x is finite and >= 0, and n is an integer:
+   Returns the decimal representation of round (x * 10^n).
+   Return the allocated memory - containing the decimal digits in low-to-high
+   order, terminated with a NUL character - in case of success, NULL in case
+   of memory allocation failure.  */
+static char *
+scale10_round_decimal_double (double x, int n)
+{
+  int e IF_LINT(= 0);
+  mpn_t m;
+  void *memory = decode_double (x, &e, &m);
+  return scale10_round_decimal_decoded (e, m, memory, n);
+}
+
+# endif
+
+# if NEED_PRINTF_LONG_DOUBLE
+
 /* Assuming x is finite and > 0:
    Return an approximation for n with 10^n <= x < 10^(n+1).
    The approximation is usually the right n, but may be off by 1 sometimes.  */
 /* Assuming x is finite and > 0:
    Return an approximation for n with 10^n <= x < 10^(n+1).
    The approximation is usually the right n, but may be off by 1 sometimes.  */
@@ -1119,35 +1311,35 @@ floorlog10l (long double x)
   if (y < 0.5L)
     {
       while (y < (1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
   if (y < 0.5L)
     {
       while (y < (1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
-       {
-         y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
-         exp -= GMP_LIMB_BITS;
-       }
+        {
+          y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
+          exp -= GMP_LIMB_BITS;
+        }
       if (y < (1.0L / (1 << 16)))
       if (y < (1.0L / (1 << 16)))
-       {
-         y *= 1.0L * (1 << 16);
-         exp -= 16;
-       }
+        {
+          y *= 1.0L * (1 << 16);
+          exp -= 16;
+        }
       if (y < (1.0L / (1 << 8)))
       if (y < (1.0L / (1 << 8)))
-       {
-         y *= 1.0L * (1 << 8);
-         exp -= 8;
-       }
+        {
+          y *= 1.0L * (1 << 8);
+          exp -= 8;
+        }
       if (y < (1.0L / (1 << 4)))
       if (y < (1.0L / (1 << 4)))
-       {
-         y *= 1.0L * (1 << 4);
-         exp -= 4;
-       }
+        {
+          y *= 1.0L * (1 << 4);
+          exp -= 4;
+        }
       if (y < (1.0L / (1 << 2)))
       if (y < (1.0L / (1 << 2)))
-       {
-         y *= 1.0L * (1 << 2);
-         exp -= 2;
-       }
+        {
+          y *= 1.0L * (1 << 2);
+          exp -= 2;
+        }
       if (y < (1.0L / (1 << 1)))
       if (y < (1.0L / (1 << 1)))
-       {
-         y *= 1.0L * (1 << 1);
-         exp -= 1;
-       }
+        {
+          y *= 1.0L * (1 << 1);
+          exp -= 1;
+        }
     }
   if (!(y >= 0.5L && y < 1.0L))
     abort ();
     }
   if (!(y >= 0.5L && y < 1.0L))
     abort ();
@@ -1176,9 +1368,9 @@ floorlog10l (long double x)
     }
   /* Now 0.95 <= z <= 1.01.  */
   z = 1 - z;
     }
   /* Now 0.95 <= z <= 1.01.  */
   z = 1 - z;
-  /* log(1-z) = - z - z^2/2 - z^3/3 - z^4/4 - ...
+  /* log2(1-z) = 1/log(2) * (- z - z^2/2 - z^3/3 - z^4/4 - ...)
      Four terms are enough to get an approximation with error < 10^-7.  */
      Four terms are enough to get an approximation with error < 10^-7.  */
-  l -= z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
+  l -= 1.4426950408889634074 * z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
   /* Finally multiply with log(2)/log(10), yields an approximation for
      log10(x).  */
   l *= 0.30102999566398119523;
   /* Finally multiply with log(2)/log(10), yields an approximation for
      log10(x).  */
   l *= 0.30102999566398119523;
@@ -1186,24 +1378,381 @@ floorlog10l (long double x)
   return (int) l + (l < 0 ? -1 : 0);
 }
 
   return (int) l + (l < 0 ? -1 : 0);
 }
 
+# endif
+
+# if NEED_PRINTF_DOUBLE
+
+/* Assuming x is finite and > 0:
+   Return an approximation for n with 10^n <= x < 10^(n+1).
+   The approximation is usually the right n, but may be off by 1 sometimes.  */
+static int
+floorlog10 (double x)
+{
+  int exp;
+  double y;
+  double z;
+  double l;
+
+  /* Split into exponential part and mantissa.  */
+  y = frexp (x, &exp);
+  if (!(y >= 0.0 && y < 1.0))
+    abort ();
+  if (y == 0.0)
+    return INT_MIN;
+  if (y < 0.5)
+    {
+      while (y < (1.0 / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
+        {
+          y *= 1.0 * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
+          exp -= GMP_LIMB_BITS;
+        }
+      if (y < (1.0 / (1 << 16)))
+        {
+          y *= 1.0 * (1 << 16);
+          exp -= 16;
+        }
+      if (y < (1.0 / (1 << 8)))
+        {
+          y *= 1.0 * (1 << 8);
+          exp -= 8;
+        }
+      if (y < (1.0 / (1 << 4)))
+        {
+          y *= 1.0 * (1 << 4);
+          exp -= 4;
+        }
+      if (y < (1.0 / (1 << 2)))
+        {
+          y *= 1.0 * (1 << 2);
+          exp -= 2;
+        }
+      if (y < (1.0 / (1 << 1)))
+        {
+          y *= 1.0 * (1 << 1);
+          exp -= 1;
+        }
+    }
+  if (!(y >= 0.5 && y < 1.0))
+    abort ();
+  /* Compute an approximation for l = log2(x) = exp + log2(y).  */
+  l = exp;
+  z = y;
+  if (z < 0.70710678118654752444)
+    {
+      z *= 1.4142135623730950488;
+      l -= 0.5;
+    }
+  if (z < 0.8408964152537145431)
+    {
+      z *= 1.1892071150027210667;
+      l -= 0.25;
+    }
+  if (z < 0.91700404320467123175)
+    {
+      z *= 1.0905077326652576592;
+      l -= 0.125;
+    }
+  if (z < 0.9576032806985736469)
+    {
+      z *= 1.0442737824274138403;
+      l -= 0.0625;
+    }
+  /* Now 0.95 <= z <= 1.01.  */
+  z = 1 - z;
+  /* log2(1-z) = 1/log(2) * (- z - z^2/2 - z^3/3 - z^4/4 - ...)
+     Four terms are enough to get an approximation with error < 10^-7.  */
+  l -= 1.4426950408889634074 * z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
+  /* Finally multiply with log(2)/log(10), yields an approximation for
+     log10(x).  */
+  l *= 0.30102999566398119523;
+  /* Round down to the next integer.  */
+  return (int) l + (l < 0 ? -1 : 0);
+}
+
+# endif
+
+/* Tests whether a string of digits consists of exactly PRECISION zeroes and
+   a single '1' digit.  */
+static int
+is_borderline (const char *digits, size_t precision)
+{
+  for (; precision > 0; precision--, digits++)
+    if (*digits != '0')
+      return 0;
+  if (*digits != '1')
+    return 0;
+  digits++;
+  return *digits == '\0';
+}
+
+#endif
+
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99
+
+/* Use a different function name, to make it possible that the 'wchar_t'
+   parametrization and the 'char' parametrization get compiled in the same
+   translation unit.  */
+# if WIDE_CHAR_VERSION
+#  define MAX_ROOM_NEEDED wmax_room_needed
+# else
+#  define MAX_ROOM_NEEDED max_room_needed
+# endif
+
+/* Returns the number of TCHAR_T units needed as temporary space for the result
+   of sprintf or SNPRINTF of a single conversion directive.  */
+static inline size_t
+MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
+                 arg_type type, int flags, size_t width, int has_precision,
+                 size_t precision, int pad_ourselves)
+{
+  size_t tmp_length;
+
+  switch (conversion)
+    {
+    case 'd': case 'i': case 'u':
+# if HAVE_LONG_LONG_INT
+      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+        tmp_length =
+          (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+                          * 0.30103 /* binary -> decimal */
+                         )
+          + 1; /* turn floor into ceil */
+      else
+# endif
+      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+        tmp_length =
+          (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+                          * 0.30103 /* binary -> decimal */
+                         )
+          + 1; /* turn floor into ceil */
+      else
+        tmp_length =
+          (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+                          * 0.30103 /* binary -> decimal */
+                         )
+          + 1; /* turn floor into ceil */
+      if (tmp_length < precision)
+        tmp_length = precision;
+      /* Multiply by 2, as an estimate for FLAG_GROUP.  */
+      tmp_length = xsum (tmp_length, tmp_length);
+      /* Add 1, to account for a leading sign.  */
+      tmp_length = xsum (tmp_length, 1);
+      break;
+
+    case 'o':
+# if HAVE_LONG_LONG_INT
+      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 */
+      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 */
+      else
+        tmp_length =
+          (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+                          * 0.333334 /* binary -> octal */
+                         )
+          + 1; /* turn floor into ceil */
+      if (tmp_length < precision)
+        tmp_length = precision;
+      /* Add 1, to account for a leading sign.  */
+      tmp_length = xsum (tmp_length, 1);
+      break;
+
+    case 'x': case 'X':
+# if HAVE_LONG_LONG_INT
+      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 */
+      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 */
+      else
+        tmp_length =
+          (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+                          * 0.25 /* binary -> hexadecimal */
+                         )
+          + 1; /* turn floor into ceil */
+      if (tmp_length < precision)
+        tmp_length = precision;
+      /* Add 2, to account for a leading sign or alternate form.  */
+      tmp_length = xsum (tmp_length, 2);
+      break;
+
+    case 'f': case 'F':
+      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 */
+          + 10; /* sign, decimal point etc. */
+      else
+        tmp_length =
+          (unsigned int) (DBL_MAX_EXP
+                          * 0.30103 /* binary -> decimal */
+                          * 2 /* estimate for FLAG_GROUP */
+                         )
+          + 1 /* turn floor into ceil */
+          + 10; /* sign, decimal point etc. */
+      tmp_length = xsum (tmp_length, precision);
+      break;
+
+    case 'e': case 'E': case 'g': case 'G':
+      tmp_length =
+        12; /* sign, decimal point, exponent etc. */
+      tmp_length = xsum (tmp_length, precision);
+      break;
+
+    case 'a': case 'A':
+      if (type == TYPE_LONGDOUBLE)
+        tmp_length =
+          (unsigned int) (LDBL_DIG
+                          * 0.831 /* decimal -> hexadecimal */
+                         )
+          + 1; /* turn floor into ceil */
+      else
+        tmp_length =
+          (unsigned int) (DBL_DIG
+                          * 0.831 /* decimal -> hexadecimal */
+                         )
+          + 1; /* turn floor into ceil */
+      if (tmp_length < precision)
+        tmp_length = precision;
+      /* Account for sign, decimal point etc. */
+      tmp_length = xsum (tmp_length, 12);
+      break;
+
+    case 'c':
+# if HAVE_WINT_T && !WIDE_CHAR_VERSION
+      if (type == TYPE_WIDE_CHAR)
+        tmp_length = MB_CUR_MAX;
+      else
+# endif
+        tmp_length = 1;
+      break;
+
+    case 's':
+# if HAVE_WCHAR_T
+      if (type == TYPE_WIDE_STRING)
+        {
+#  if WIDE_CHAR_VERSION
+          /* ISO C says about %ls in fwprintf:
+               "If the precision is not specified or is greater than the size
+                of the array, the array shall contain a null wide character."
+             So if there is a precision, we must not use wcslen.  */
+          const wchar_t *arg = ap->arg[arg_index].a.a_wide_string;
+
+          if (has_precision)
+            tmp_length = local_wcsnlen (arg, precision);
+          else
+            tmp_length = local_wcslen (arg);
+#  else
+          /* ISO C says about %ls in fprintf:
+               "If a precision is specified, no more than that many bytes are
+                written (including shift sequences, if any), and the array
+                shall contain a null wide character if, to equal the multibyte
+                character sequence length given by the precision, the function
+                would need to access a wide character one past the end of the
+                array."
+             So if there is a precision, we must not use wcslen.  */
+          /* This case has already been handled separately in VASNPRINTF.  */
+          abort ();
+#  endif
+        }
+      else
+# endif
+        {
+# if WIDE_CHAR_VERSION
+          /* ISO C says about %s in fwprintf:
+               "If the precision is not specified or is greater than the size
+                of the converted array, the converted array shall contain a
+                null wide character."
+             So if there is a precision, we must not use strlen.  */
+          /* This case has already been handled separately in VASNPRINTF.  */
+          abort ();
+# else
+          /* ISO C says about %s in fprintf:
+               "If the precision is not specified or greater than the size of
+                the array, the array shall contain a null character."
+             So if there is a precision, we must not use strlen.  */
+          const char *arg = ap->arg[arg_index].a.a_string;
+
+          if (has_precision)
+            tmp_length = local_strnlen (arg, precision);
+          else
+            tmp_length = strlen (arg);
+# endif
+        }
+      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 (!pad_ourselves)
+    {
+# if ENABLE_UNISTDIO
+      /* Padding considers the number of characters, therefore the number of
+         elements after padding may be
+           > max (tmp_length, width)
+         but is certainly
+           <= tmp_length + width.  */
+      tmp_length = xsum (tmp_length, width);
+# else
+      /* Padding considers the number of elements, says POSIX.  */
+      if (tmp_length < width)
+        tmp_length = width;
+# endif
+    }
+
+  tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+
+  return tmp_length;
+}
+
 #endif
 
 DCHAR_T *
 VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #endif
 
 DCHAR_T *
 VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
-           const FCHAR_T *format, va_list args)
+            const FCHAR_T *format, va_list args)
 {
   DIRECTIVES d;
   arguments a;
 
   if (PRINTF_PARSE (format, &d, &a) < 0)
 {
   DIRECTIVES d;
   arguments a;
 
   if (PRINTF_PARSE (format, &d, &a) < 0)
-    {
-      errno = EINVAL;
-      return NULL;
-    }
+    /* errno is already set.  */
+    return NULL;
 
 #define CLEANUP() \
 
 #define CLEANUP() \
-  free (d.dir);                                                                \
-  if (a.arg)                                                           \
+  free (d.dir);                                                         \
+  if (a.arg)                                                            \
     free (a.arg);
 
   if (PRINTF_FETCHARGS (args, &a) < 0)
     free (a.arg);
 
   if (PRINTF_FETCHARGS (args, &a) < 0)
@@ -1232,30 +1781,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if HAVE_ALLOCA
     if (buf_neededlength < 4000 / sizeof (TCHAR_T))
       {
 #if HAVE_ALLOCA
     if (buf_neededlength < 4000 / sizeof (TCHAR_T))
       {
-       buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T));
-       buf_malloced = NULL;
+        buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T));
+        buf_malloced = NULL;
       }
     else
 #endif
       {
       }
     else
 #endif
       {
-       size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T));
-       if (size_overflow_p (buf_memsize))
-         goto out_of_memory_1;
-       buf = (TCHAR_T *) malloc (buf_memsize);
-       if (buf == NULL)
-         goto out_of_memory_1;
-       buf_malloced = buf;
+        size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T));
+        if (size_overflow_p (buf_memsize))
+          goto out_of_memory_1;
+        buf = (TCHAR_T *) malloc (buf_memsize);
+        if (buf == NULL)
+          goto out_of_memory_1;
+        buf_malloced = buf;
       }
 
     if (resultbuf != NULL)
       {
       }
 
     if (resultbuf != NULL)
       {
-       result = resultbuf;
-       allocated = *lengthp;
+        result = resultbuf;
+        allocated = *lengthp;
       }
     else
       {
       }
     else
       {
-       result = NULL;
-       allocated = 0;
+        result = NULL;
+        allocated = 0;
       }
     length = 0;
     /* Invariants:
       }
     length = 0;
     /* Invariants:
@@ -1265,2648 +1814,3694 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
     /* Ensures that allocated >= needed.  Aborts through a jump to
        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
 #define ENSURE_ALLOCATION(needed) \
     /* Ensures that allocated >= needed.  Aborts through a jump to
        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
 #define ENSURE_ALLOCATION(needed) \
-    if ((needed) > allocated)                                               \
-      {                                                                             \
-       size_t memory_size;                                                  \
-       DCHAR_T *memory;                                                     \
-                                                                            \
-       allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);            \
-       if ((needed) > allocated)                                            \
-         allocated = (needed);                                              \
-       memory_size = xtimes (allocated, sizeof (DCHAR_T));                  \
-       if (size_overflow_p (memory_size))                                   \
-         goto out_of_memory;                                                \
-       if (result == resultbuf || result == NULL)                           \
-         memory = (DCHAR_T *) malloc (memory_size);                         \
-       else                                                                 \
-         memory = (DCHAR_T *) realloc (result, memory_size);                \
-       if (memory == NULL)                                                  \
-         goto out_of_memory;                                                \
-       if (result == resultbuf && length > 0)                               \
-         DCHAR_CPY (memory, result, length);                                \
-       result = memory;                                                     \
+    if ((needed) > allocated)                                                \
+      {                                                                      \
+        size_t memory_size;                                                  \
+        DCHAR_T *memory;                                                     \
+                                                                             \
+        allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);            \
+        if ((needed) > allocated)                                            \
+          allocated = (needed);                                              \
+        memory_size = xtimes (allocated, sizeof (DCHAR_T));                  \
+        if (size_overflow_p (memory_size))                                   \
+          goto out_of_memory;                                                \
+        if (result == resultbuf || result == NULL)                           \
+          memory = (DCHAR_T *) malloc (memory_size);                         \
+        else                                                                 \
+          memory = (DCHAR_T *) realloc (result, memory_size);                \
+        if (memory == NULL)                                                  \
+          goto out_of_memory;                                                \
+        if (result == resultbuf && length > 0)                               \
+          DCHAR_CPY (memory, result, length);                                \
+        result = memory;                                                     \
       }
 
     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
       {
       }
 
     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;
-           size_t augmented_length = xsum (length, n);
-
-           ENSURE_ALLOCATION (augmented_length);
-           /* This copies a piece of FCHAR_T[] into a DCHAR_T[].  Here we
-              need that the format string contains only ASCII characters
-              if FCHAR_T and DCHAR_T are not the same type.  */
-           if (sizeof (FCHAR_T) == sizeof (DCHAR_T))
-             {
-               DCHAR_CPY (result + length, (const DCHAR_T *) cp, n);
-               length = augmented_length;
-             }
-           else
-             {
-               do
-                 result[length++] = (unsigned char) *cp++;
-               while (--n > 0);
-             }
-         }
-       if (i == d.count)
-         break;
-
-       /* Execute a single directive.  */
-       if (dp->conversion == '%')
-         {
-           size_t augmented_length;
-
-           if (!(dp->arg_index == ARG_NONE))
-             abort ();
-           augmented_length = xsum (length, 1);
-           ENSURE_ALLOCATION (augmented_length);
-           result[length] = '%';
-           length = augmented_length;
-         }
-       else
-         {
-           if (!(dp->arg_index != ARG_NONE))
-             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;
+        if (cp != dp->dir_start)
+          {
+            size_t n = dp->dir_start - cp;
+            size_t augmented_length = xsum (length, n);
+
+            ENSURE_ALLOCATION (augmented_length);
+            /* This copies a piece of FCHAR_T[] into a DCHAR_T[].  Here we
+               need that the format string contains only ASCII characters
+               if FCHAR_T and DCHAR_T are not the same type.  */
+            if (sizeof (FCHAR_T) == sizeof (DCHAR_T))
+              {
+                DCHAR_CPY (result + length, (const DCHAR_T *) cp, n);
+                length = augmented_length;
+              }
+            else
+              {
+                do
+                  result[length++] = (unsigned char) *cp++;
+                while (--n > 0);
+              }
+          }
+        if (i == d.count)
+          break;
+
+        /* Execute a single directive.  */
+        if (dp->conversion == '%')
+          {
+            size_t augmented_length;
+
+            if (!(dp->arg_index == ARG_NONE))
+              abort ();
+            augmented_length = xsum (length, 1);
+            ENSURE_ALLOCATION (augmented_length);
+            result[length] = '%';
+            length = augmented_length;
+          }
+        else
+          {
+            if (!(dp->arg_index != ARG_NONE))
+              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;
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                 case TYPE_COUNT_LONGLONGINT_POINTER:
-                   *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
-                   break;
+                  case TYPE_COUNT_LONGLONGINT_POINTER:
+                    *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
+                    break;
 #endif
 #endif
-                 default:
-                   abort ();
-                 }
-             }
+                  default:
+                    abort ();
+                  }
+              }
 #if ENABLE_UNISTDIO
 #if ENABLE_UNISTDIO
-           /* The unistdio extensions.  */
-           else if (dp->conversion == 'U')
-             {
-               arg_type type = a.arg[dp->arg_index].type;
-               int flags = dp->flags;
-               int has_width;
-               size_t width;
-               int has_precision;
-               size_t precision;
-
-               has_width = 0;
-               width = 0;
-               if (dp->width_start != dp->width_end)
-                 {
-                   if (dp->width_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->width_arg_index].a.a_int;
-                       if (arg < 0)
-                         {
-                           /* "A negative field width is taken as a '-' flag
-                               followed by a positive field width."  */
-                           flags |= FLAG_LEFT;
-                           width = (unsigned int) (-arg);
-                         }
-                       else
-                         width = arg;
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->width_start;
-
-                       do
-                         width = xsum (xtimes (width, 10), *digitp++ - '0');
-                       while (digitp != dp->width_end);
-                     }
-                   has_width = 1;
-                 }
-
-               has_precision = 0;
-               precision = 0;
-               if (dp->precision_start != dp->precision_end)
-                 {
-                   if (dp->precision_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->precision_arg_index].a.a_int;
-                       /* "A negative precision is taken as if the precision
-                           were omitted."  */
-                       if (arg >= 0)
-                         {
-                           precision = arg;
-                           has_precision = 1;
-                         }
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->precision_start + 1;
-
-                       precision = 0;
-                       while (digitp != dp->precision_end)
-                         precision = xsum (xtimes (precision, 10), *digitp++ - '0');
-                       has_precision = 1;
-                     }
-                 }
-
-               switch (type)
-                 {
-                 case TYPE_U8_STRING:
-                   {
-                     const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string;
-                     const uint8_t *arg_end;
-                     size_t characters;
-
-                     if (has_precision)
-                       {
-                         /* Use only PRECISION characters, from the left.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (; precision > 0; precision--)
-                           {
-                             int count = u8_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else if (has_width)
-                       {
-                         /* Use the entire string, and count the number of
-                            characters.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (;;)
-                           {
-                             int count = u8_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else
-                       {
-                         /* Use the entire string.  */
-                         arg_end = arg + u8_strlen (arg);
-                         /* The number of characters doesn't matter.  */
-                         characters = 0;
-                       }
-
-                     if (has_width && width > characters
-                         && !(dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
+            /* The unistdio extensions.  */
+            else if (dp->conversion == 'U')
+              {
+                arg_type type = a.arg[dp->arg_index].type;
+                int flags = dp->flags;
+                int has_width;
+                size_t width;
+                int has_precision;
+                size_t precision;
+
+                has_width = 0;
+                width = 0;
+                if (dp->width_start != dp->width_end)
+                  {
+                    if (dp->width_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->width_arg_index].a.a_int;
+                        if (arg < 0)
+                          {
+                            /* "A negative field width is taken as a '-' flag
+                                followed by a positive field width."  */
+                            flags |= FLAG_LEFT;
+                            width = (unsigned int) (-arg);
+                          }
+                        else
+                          width = arg;
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->width_start;
+
+                        do
+                          width = xsum (xtimes (width, 10), *digitp++ - '0');
+                        while (digitp != dp->width_end);
+                      }
+                    has_width = 1;
+                  }
+
+                has_precision = 0;
+                precision = 0;
+                if (dp->precision_start != dp->precision_end)
+                  {
+                    if (dp->precision_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->precision_arg_index].a.a_int;
+                        /* "A negative precision is taken as if the precision
+                            were omitted."  */
+                        if (arg >= 0)
+                          {
+                            precision = arg;
+                            has_precision = 1;
+                          }
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->precision_start + 1;
+
+                        precision = 0;
+                        while (digitp != dp->precision_end)
+                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+                        has_precision = 1;
+                      }
+                  }
+
+                switch (type)
+                  {
+                  case TYPE_U8_STRING:
+                    {
+                      const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string;
+                      const uint8_t *arg_end;
+                      size_t characters;
+
+                      if (has_precision)
+                        {
+                          /* Use only PRECISION characters, from the left.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (; precision > 0; precision--)
+                            {
+                              int count = u8_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else if (has_width)
+                        {
+                          /* Use the entire string, and count the number of
+                             characters.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (;;)
+                            {
+                              int count = u8_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else
+                        {
+                          /* Use the entire string.  */
+                          arg_end = arg + u8_strlen (arg);
+                          /* The number of characters doesn't matter.  */
+                          characters = 0;
+                        }
+
+                      if (has_width && width > characters
+                          && !(dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
 
 # if DCHAR_IS_UINT8_T
 
 # if DCHAR_IS_UINT8_T
-                     {
-                       size_t n = arg_end - arg;
-                       ENSURE_ALLOCATION (xsum (length, n));
-                       DCHAR_CPY (result + length, arg, n);
-                       length += n;
-                     }
+                      {
+                        size_t n = arg_end - arg;
+                        ENSURE_ALLOCATION (xsum (length, n));
+                        DCHAR_CPY (result + length, arg, n);
+                        length += n;
+                      }
 # else
 # else
-                     { /* Convert.  */
-                       DCHAR_T *converted = result + length;
-                       size_t converted_len = allocated - length;
+                      { /* Convert.  */
+                        DCHAR_T *converted = result + length;
+                        size_t converted_len = allocated - length;
 #  if DCHAR_IS_TCHAR
 #  if DCHAR_IS_TCHAR
-                       /* Convert from UTF-8 to locale encoding.  */
-                       if (u8_conv_to_encoding (locale_charset (),
-                                                iconveh_question_mark,
-                                                arg, arg_end - arg, NULL,
-                                                &converted, &converted_len)
-                           < 0)
+                        /* Convert from UTF-8 to locale encoding.  */
+                        converted =
+                          u8_conv_to_encoding (locale_charset (),
+                                               iconveh_question_mark,
+                                               arg, arg_end - arg, NULL,
+                                               converted, &converted_len);
 #  else
 #  else
-                       /* Convert from UTF-8 to UTF-16/UTF-32.  */
-                       converted =
-                         U8_TO_DCHAR (arg, arg_end - arg,
-                                      converted, &converted_len);
-                       if (converted == NULL)
+                        /* Convert from UTF-8 to UTF-16/UTF-32.  */
+                        converted =
+                          U8_TO_DCHAR (arg, arg_end - arg,
+                                       converted, &converted_len);
 #  endif
 #  endif
-                         {
-                           int saved_errno = errno;
-                           if (!(result == resultbuf || result == NULL))
-                             free (result);
-                           if (buf_malloced != NULL)
-                             free (buf_malloced);
-                           CLEANUP ();
-                           errno = saved_errno;
-                           return NULL;
-                         }
-                       if (converted != result + length)
-                         {
-                           ENSURE_ALLOCATION (xsum (length, converted_len));
-                           DCHAR_CPY (result + length, converted, converted_len);
-                           free (converted);
-                         }
-                       length += converted_len;
-                     }
+                        if (converted == NULL)
+                          {
+                            int saved_errno = errno;
+                            if (!(result == resultbuf || result == NULL))
+                              free (result);
+                            if (buf_malloced != NULL)
+                              free (buf_malloced);
+                            CLEANUP ();
+                            errno = saved_errno;
+                            return NULL;
+                          }
+                        if (converted != result + length)
+                          {
+                            ENSURE_ALLOCATION (xsum (length, converted_len));
+                            DCHAR_CPY (result + length, converted, converted_len);
+                            free (converted);
+                          }
+                        length += converted_len;
+                      }
 # endif
 
 # endif
 
-                     if (has_width && width > characters
-                         && (dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
-                   }
-                   break;
-
-                 case TYPE_U16_STRING:
-                   {
-                     const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string;
-                     const uint16_t *arg_end;
-                     size_t characters;
-
-                     if (has_precision)
-                       {
-                         /* Use only PRECISION characters, from the left.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (; precision > 0; precision--)
-                           {
-                             int count = u16_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else if (has_width)
-                       {
-                         /* Use the entire string, and count the number of
-                            characters.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (;;)
-                           {
-                             int count = u16_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else
-                       {
-                         /* Use the entire string.  */
-                         arg_end = arg + u16_strlen (arg);
-                         /* The number of characters doesn't matter.  */
-                         characters = 0;
-                       }
-
-                     if (has_width && width > characters
-                         && !(dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
+                      if (has_width && width > characters
+                          && (dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
+                    }
+                    break;
+
+                  case TYPE_U16_STRING:
+                    {
+                      const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string;
+                      const uint16_t *arg_end;
+                      size_t characters;
+
+                      if (has_precision)
+                        {
+                          /* Use only PRECISION characters, from the left.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (; precision > 0; precision--)
+                            {
+                              int count = u16_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else if (has_width)
+                        {
+                          /* Use the entire string, and count the number of
+                             characters.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (;;)
+                            {
+                              int count = u16_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else
+                        {
+                          /* Use the entire string.  */
+                          arg_end = arg + u16_strlen (arg);
+                          /* The number of characters doesn't matter.  */
+                          characters = 0;
+                        }
+
+                      if (has_width && width > characters
+                          && !(dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
 
 # if DCHAR_IS_UINT16_T
 
 # if DCHAR_IS_UINT16_T
-                     {
-                       size_t n = arg_end - arg;
-                       ENSURE_ALLOCATION (xsum (length, n));
-                       DCHAR_CPY (result + length, arg, n);
-                       length += n;
-                     }
+                      {
+                        size_t n = arg_end - arg;
+                        ENSURE_ALLOCATION (xsum (length, n));
+                        DCHAR_CPY (result + length, arg, n);
+                        length += n;
+                      }
 # else
 # else
-                     { /* Convert.  */
-                       DCHAR_T *converted = result + length;
-                       size_t converted_len = allocated - length;
+                      { /* Convert.  */
+                        DCHAR_T *converted = result + length;
+                        size_t converted_len = allocated - length;
 #  if DCHAR_IS_TCHAR
 #  if DCHAR_IS_TCHAR
-                       /* Convert from UTF-16 to locale encoding.  */
-                       if (u16_conv_to_encoding (locale_charset (),
-                                                 iconveh_question_mark,
-                                                 arg, arg_end - arg, NULL,
-                                                 &converted, &converted_len)
-                           < 0)
+                        /* Convert from UTF-16 to locale encoding.  */
+                        converted =
+                          u16_conv_to_encoding (locale_charset (),
+                                                iconveh_question_mark,
+                                                arg, arg_end - arg, NULL,
+                                                converted, &converted_len);
 #  else
 #  else
-                       /* Convert from UTF-16 to UTF-8/UTF-32.  */
-                       converted =
-                         U16_TO_DCHAR (arg, arg_end - arg,
-                                       converted, &converted_len);
-                       if (converted == NULL)
+                        /* Convert from UTF-16 to UTF-8/UTF-32.  */
+                        converted =
+                          U16_TO_DCHAR (arg, arg_end - arg,
+                                        converted, &converted_len);
 #  endif
 #  endif
-                         {
-                           int saved_errno = errno;
-                           if (!(result == resultbuf || result == NULL))
-                             free (result);
-                           if (buf_malloced != NULL)
-                             free (buf_malloced);
-                           CLEANUP ();
-                           errno = saved_errno;
-                           return NULL;
-                         }
-                       if (converted != result + length)
-                         {
-                           ENSURE_ALLOCATION (xsum (length, converted_len));
-                           DCHAR_CPY (result + length, converted, converted_len);
-                           free (converted);
-                         }
-                       length += converted_len;
-                     }
+                        if (converted == NULL)
+                          {
+                            int saved_errno = errno;
+                            if (!(result == resultbuf || result == NULL))
+                              free (result);
+                            if (buf_malloced != NULL)
+                              free (buf_malloced);
+                            CLEANUP ();
+                            errno = saved_errno;
+                            return NULL;
+                          }
+                        if (converted != result + length)
+                          {
+                            ENSURE_ALLOCATION (xsum (length, converted_len));
+                            DCHAR_CPY (result + length, converted, converted_len);
+                            free (converted);
+                          }
+                        length += converted_len;
+                      }
 # endif
 
 # endif
 
-                     if (has_width && width > characters
-                         && (dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
-                   }
-                   break;
-
-                 case TYPE_U32_STRING:
-                   {
-                     const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string;
-                     const uint32_t *arg_end;
-                     size_t characters;
-
-                     if (has_precision)
-                       {
-                         /* Use only PRECISION characters, from the left.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (; precision > 0; precision--)
-                           {
-                             int count = u32_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else if (has_width)
-                       {
-                         /* Use the entire string, and count the number of
-                            characters.  */
-                         arg_end = arg;
-                         characters = 0;
-                         for (;;)
-                           {
-                             int count = u32_strmblen (arg_end);
-                             if (count == 0)
-                               break;
-                             if (count < 0)
-                               {
-                                 if (!(result == resultbuf || result == NULL))
-                                   free (result);
-                                 if (buf_malloced != NULL)
-                                   free (buf_malloced);
-                                 CLEANUP ();
-                                 errno = EILSEQ;
-                                 return NULL;
-                               }
-                             arg_end += count;
-                             characters++;
-                           }
-                       }
-                     else
-                       {
-                         /* Use the entire string.  */
-                         arg_end = arg + u32_strlen (arg);
-                         /* The number of characters doesn't matter.  */
-                         characters = 0;
-                       }
-
-                     if (has_width && width > characters
-                         && !(dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
+                      if (has_width && width > characters
+                          && (dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
+                    }
+                    break;
+
+                  case TYPE_U32_STRING:
+                    {
+                      const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string;
+                      const uint32_t *arg_end;
+                      size_t characters;
+
+                      if (has_precision)
+                        {
+                          /* Use only PRECISION characters, from the left.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (; precision > 0; precision--)
+                            {
+                              int count = u32_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else if (has_width)
+                        {
+                          /* Use the entire string, and count the number of
+                             characters.  */
+                          arg_end = arg;
+                          characters = 0;
+                          for (;;)
+                            {
+                              int count = u32_strmblen (arg_end);
+                              if (count == 0)
+                                break;
+                              if (count < 0)
+                                {
+                                  if (!(result == resultbuf || result == NULL))
+                                    free (result);
+                                  if (buf_malloced != NULL)
+                                    free (buf_malloced);
+                                  CLEANUP ();
+                                  errno = EILSEQ;
+                                  return NULL;
+                                }
+                              arg_end += count;
+                              characters++;
+                            }
+                        }
+                      else
+                        {
+                          /* Use the entire string.  */
+                          arg_end = arg + u32_strlen (arg);
+                          /* The number of characters doesn't matter.  */
+                          characters = 0;
+                        }
+
+                      if (has_width && width > characters
+                          && !(dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
 
 # if DCHAR_IS_UINT32_T
 
 # if DCHAR_IS_UINT32_T
-                     {
-                       size_t n = arg_end - arg;
-                       ENSURE_ALLOCATION (xsum (length, n));
-                       DCHAR_CPY (result + length, arg, n);
-                       length += n;
-                     }
+                      {
+                        size_t n = arg_end - arg;
+                        ENSURE_ALLOCATION (xsum (length, n));
+                        DCHAR_CPY (result + length, arg, n);
+                        length += n;
+                      }
 # else
 # else
-                     { /* Convert.  */
-                       DCHAR_T *converted = result + length;
-                       size_t converted_len = allocated - length;
+                      { /* Convert.  */
+                        DCHAR_T *converted = result + length;
+                        size_t converted_len = allocated - length;
 #  if DCHAR_IS_TCHAR
 #  if DCHAR_IS_TCHAR
-                       /* Convert from UTF-32 to locale encoding.  */
-                       if (u32_conv_to_encoding (locale_charset (),
-                                                 iconveh_question_mark,
-                                                 arg, arg_end - arg, NULL,
-                                                 &converted, &converted_len)
-                           < 0)
+                        /* Convert from UTF-32 to locale encoding.  */
+                        converted =
+                          u32_conv_to_encoding (locale_charset (),
+                                                iconveh_question_mark,
+                                                arg, arg_end - arg, NULL,
+                                                converted, &converted_len);
 #  else
 #  else
-                       /* Convert from UTF-32 to UTF-8/UTF-16.  */
-                       converted =
-                         U32_TO_DCHAR (arg, arg_end - arg,
-                                       converted, &converted_len);
-                       if (converted == NULL)
+                        /* Convert from UTF-32 to UTF-8/UTF-16.  */
+                        converted =
+                          U32_TO_DCHAR (arg, arg_end - arg,
+                                        converted, &converted_len);
 #  endif
 #  endif
-                         {
-                           int saved_errno = errno;
-                           if (!(result == resultbuf || result == NULL))
-                             free (result);
-                           if (buf_malloced != NULL)
-                             free (buf_malloced);
-                           CLEANUP ();
-                           errno = saved_errno;
-                           return NULL;
-                         }
-                       if (converted != result + length)
-                         {
-                           ENSURE_ALLOCATION (xsum (length, converted_len));
-                           DCHAR_CPY (result + length, converted, converted_len);
-                           free (converted);
-                         }
-                       length += converted_len;
-                     }
+                        if (converted == NULL)
+                          {
+                            int saved_errno = errno;
+                            if (!(result == resultbuf || result == NULL))
+                              free (result);
+                            if (buf_malloced != NULL)
+                              free (buf_malloced);
+                            CLEANUP ();
+                            errno = saved_errno;
+                            return NULL;
+                          }
+                        if (converted != result + length)
+                          {
+                            ENSURE_ALLOCATION (xsum (length, converted_len));
+                            DCHAR_CPY (result + length, converted, converted_len);
+                            free (converted);
+                          }
+                        length += converted_len;
+                      }
 # endif
 
 # endif
 
-                     if (has_width && width > characters
-                         && (dp->flags & FLAG_LEFT))
-                       {
-                         size_t n = width - characters;
-                         ENSURE_ALLOCATION (xsum (length, n));
-                         DCHAR_SET (result + length, ' ', n);
-                         length += n;
-                       }
-                   }
-                   break;
-
-                 default:
-                   abort ();
-                 }
-             }
+                      if (has_width && width > characters
+                          && (dp->flags & FLAG_LEFT))
+                        {
+                          size_t n = width - characters;
+                          ENSURE_ALLOCATION (xsum (length, n));
+                          DCHAR_SET (result + length, ' ', n);
+                          length += n;
+                        }
+                    }
+                    break;
+
+                  default:
+                    abort ();
+                  }
+              }
 #endif
 #endif
-#if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
-           else if (dp->conversion == 'a' || dp->conversion == 'A')
-             {
-               arg_type type = a.arg[dp->arg_index].type;
-               int flags = dp->flags;
-               int has_width;
-               size_t width;
-               int has_precision;
-               size_t precision;
-               size_t tmp_length;
-               DCHAR_T tmpbuf[700];
-               DCHAR_T *tmp;
-               DCHAR_T *pad_ptr;
-               DCHAR_T *p;
-
-               has_width = 0;
-               width = 0;
-               if (dp->width_start != dp->width_end)
-                 {
-                   if (dp->width_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->width_arg_index].a.a_int;
-                       if (arg < 0)
-                         {
-                           /* "A negative field width is taken as a '-' flag
-                               followed by a positive field width."  */
-                           flags |= FLAG_LEFT;
-                           width = (unsigned int) (-arg);
-                         }
-                       else
-                         width = arg;
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->width_start;
-
-                       do
-                         width = xsum (xtimes (width, 10), *digitp++ - '0');
-                       while (digitp != dp->width_end);
-                     }
-                   has_width = 1;
-                 }
-
-               has_precision = 0;
-               precision = 0;
-               if (dp->precision_start != dp->precision_end)
-                 {
-                   if (dp->precision_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->precision_arg_index].a.a_int;
-                       /* "A negative precision is taken as if the precision
-                           were omitted."  */
-                       if (arg >= 0)
-                         {
-                           precision = arg;
-                           has_precision = 1;
-                         }
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->precision_start + 1;
-
-                       precision = 0;
-                       while (digitp != dp->precision_end)
-                         precision = xsum (xtimes (precision, 10), *digitp++ - '0');
-                       has_precision = 1;
-                     }
-                 }
-
-               /* Allocate a temporary buffer of sufficient size.  */
-               if (type == TYPE_LONGDOUBLE)
-                 tmp_length =
-                   (unsigned int) ((LDBL_DIG + 1)
-                                   * 0.831 /* decimal -> hexadecimal */
-                                  )
-                   + 1; /* turn floor into ceil */
-               else
-                 tmp_length =
-                   (unsigned int) ((DBL_DIG + 1)
-                                   * 0.831 /* decimal -> hexadecimal */
-                                  )
-                   + 1; /* turn floor into ceil */
-               if (tmp_length < precision)
-                 tmp_length = precision;
-               /* Account for sign, decimal point etc. */
-               tmp_length = xsum (tmp_length, 12);
-
-               if (tmp_length < width)
-                 tmp_length = width;
-
-               tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
-
-               if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
-                 tmp = tmpbuf;
-               else
-                 {
-                   size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
-
-                   if (size_overflow_p (tmp_memsize))
-                     /* Overflow, would lead to out of memory.  */
-                     goto out_of_memory;
-                   tmp = (DCHAR_T *) malloc (tmp_memsize);
-                   if (tmp == NULL)
-                     /* Out of memory.  */
-                     goto out_of_memory;
-                 }
-
-               pad_ptr = NULL;
-               p = tmp;
-               if (type == TYPE_LONGDOUBLE)
-                 {
-                   long double arg = a.arg[dp->arg_index].a.a_longdouble;
-
-                   if (isnanl (arg))
-                     {
-                       if (dp->conversion == 'A')
-                         {
-                           *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
-                         }
-                       else
-                         {
-                           *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
-                         }
-                     }
-                   else
-                     {
-                       int sign = 0;
-                       DECL_LONG_DOUBLE_ROUNDING
-
-                       BEGIN_LONG_DOUBLE_ROUNDING ();
-
-                       if (signbit (arg)) /* arg < 0.0L or negative zero */
-                         {
-                           sign = -1;
-                           arg = -arg;
-                         }
-
-                       if (sign < 0)
-                         *p++ = '-';
-                       else if (flags & FLAG_SHOWSIGN)
-                         *p++ = '+';
-                       else if (flags & FLAG_SPACE)
-                         *p++ = ' ';
-
-                       if (arg > 0.0L && arg + arg == arg)
-                         {
-                           if (dp->conversion == 'A')
-                             {
-                               *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
-                             }
-                           else
-                             {
-                               *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
-                             }
-                         }
-                       else
-                         {
-                           int exponent;
-                           long double mantissa;
-
-                           if (arg > 0.0L)
-                             mantissa = printf_frexpl (arg, &exponent);
-                           else
-                             {
-                               exponent = 0;
-                               mantissa = 0.0L;
-                             }
-
-                           if (has_precision
-                               && precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1)
-                             {
-                               /* Round the mantissa.  */
-                               long double tail = mantissa;
-                               size_t q;
-
-                               for (q = precision; ; q--)
-                                 {
-                                   int digit = (int) tail;
-                                   tail -= digit;
-                                   if (q == 0)
-                                     {
-                                       if (digit & 1 ? tail >= 0.5L : tail > 0.5L)
-                                         tail = 1 - tail;
-                                       else
-                                         tail = - tail;
-                                       break;
-                                     }
-                                   tail *= 16.0L;
-                                 }
-                               if (tail != 0.0L)
-                                 for (q = precision; q > 0; q--)
-                                   tail *= 0.0625L;
-                               mantissa += tail;
-                             }
-
-                           *p++ = '0';
-                           *p++ = dp->conversion - 'A' + 'X';
-                           pad_ptr = p;
-                           {
-                             int digit;
-
-                             digit = (int) mantissa;
-                             mantissa -= digit;
-                             *p++ = '0' + digit;
-                             if ((flags & FLAG_ALT)
-                                 || mantissa > 0.0L || precision > 0)
-                               {
-                                 *p++ = decimal_point_char ();
-                                 /* This loop terminates because we assume
-                                    that FLT_RADIX is a power of 2.  */
-                                 while (mantissa > 0.0L)
-                                   {
-                                     mantissa *= 16.0L;
-                                     digit = (int) mantissa;
-                                     mantissa -= digit;
-                                     *p++ = digit
-                                            + (digit < 10
-                                               ? '0'
-                                               : dp->conversion - 10);
-                                     if (precision > 0)
-                                       precision--;
-                                   }
-                                 while (precision > 0)
-                                   {
-                                     *p++ = '0';
-                                     precision--;
-                                   }
-                               }
-                             }
-                             *p++ = dp->conversion - 'A' + 'P';
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
+            else if (dp->conversion == 's'
 # if WIDE_CHAR_VERSION
 # if WIDE_CHAR_VERSION
-                             {
-                               static const wchar_t decimal_format[] =
-                                 { '%', '+', 'd', '\0' };
-                               SNPRINTF (p, 6 + 1, decimal_format, exponent);
-                             }
-                             while (*p != '\0')
-                               p++;
+                     && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
 # else
 # else
-                             if (sizeof (DCHAR_T) == 1)
-                               {
-                                 sprintf ((char *) p, "%+d", exponent);
-                                 while (*p != '\0')
-                                   p++;
-                               }
-                             else
-                               {
-                                 char expbuf[6 + 1];
-                                 const char *ep;
-                                 sprintf (expbuf, "%+d", exponent);
-                                 for (ep = expbuf; (*p = *ep) != '\0'; ep++)
-                                   p++;
-                               }
+                     && a.arg[dp->arg_index].type == TYPE_WIDE_STRING
 # endif
 # endif
-                         }
-
-                       END_LONG_DOUBLE_ROUNDING ();
-                     }
-                 }
-               else
-                 {
-                   double arg = a.arg[dp->arg_index].a.a_double;
-
-                   if (isnan (arg))
-                     {
-                       if (dp->conversion == 'A')
-                         {
-                           *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
-                         }
-                       else
-                         {
-                           *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
-                         }
-                     }
-                   else
-                     {
-                       int sign = 0;
-
-                       if (signbit (arg)) /* arg < 0.0 or negative zero */
-                         {
-                           sign = -1;
-                           arg = -arg;
-                         }
-
-                       if (sign < 0)
-                         *p++ = '-';
-                       else if (flags & FLAG_SHOWSIGN)
-                         *p++ = '+';
-                       else if (flags & FLAG_SPACE)
-                         *p++ = ' ';
-
-                       if (arg > 0.0 && arg + arg == arg)
-                         {
-                           if (dp->conversion == 'A')
-                             {
-                               *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
-                             }
-                           else
-                             {
-                               *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
-                             }
-                         }
-                       else
-                         {
-                           int exponent;
-                           double mantissa;
-
-                           if (arg > 0.0)
-                             mantissa = printf_frexp (arg, &exponent);
-                           else
-                             {
-                               exponent = 0;
-                               mantissa = 0.0;
-                             }
-
-                           if (has_precision
-                               && precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1)
-                             {
-                               /* Round the mantissa.  */
-                               double tail = mantissa;
-                               size_t q;
-
-                               for (q = precision; ; q--)
-                                 {
-                                   int digit = (int) tail;
-                                   tail -= digit;
-                                   if (q == 0)
-                                     {
-                                       if (digit & 1 ? tail >= 0.5 : tail > 0.5)
-                                         tail = 1 - tail;
-                                       else
-                                         tail = - tail;
-                                       break;
-                                     }
-                                   tail *= 16.0;
-                                 }
-                               if (tail != 0.0)
-                                 for (q = precision; q > 0; q--)
-                                   tail *= 0.0625;
-                               mantissa += tail;
-                             }
-
-                           *p++ = '0';
-                           *p++ = dp->conversion - 'A' + 'X';
-                           pad_ptr = p;
-                           {
-                             int digit;
-
-                             digit = (int) mantissa;
-                             mantissa -= digit;
-                             *p++ = '0' + digit;
-                             if ((flags & FLAG_ALT)
-                                 || mantissa > 0.0 || precision > 0)
-                               {
-                                 *p++ = decimal_point_char ();
-                                 /* This loop terminates because we assume
-                                    that FLT_RADIX is a power of 2.  */
-                                 while (mantissa > 0.0)
-                                   {
-                                     mantissa *= 16.0;
-                                     digit = (int) mantissa;
-                                     mantissa -= digit;
-                                     *p++ = digit
-                                            + (digit < 10
-                                               ? '0'
-                                               : dp->conversion - 10);
-                                     if (precision > 0)
-                                       precision--;
-                                   }
-                                 while (precision > 0)
-                                   {
-                                     *p++ = '0';
-                                     precision--;
-                                   }
-                               }
-                             }
-                             *p++ = dp->conversion - 'A' + 'P';
+                    )
+              {
+                /* The normal handling of the 's' directive below requires
+                   allocating a temporary buffer.  The determination of its
+                   length (tmp_length), in the case when a precision is
+                   specified, below requires a conversion between a char[]
+                   string and a wchar_t[] wide string.  It could be done, but
+                   we have no guarantee that the implementation of sprintf will
+                   use the exactly same algorithm.  Without this guarantee, it
+                   is possible to have buffer overrun bugs.  In order to avoid
+                   such bugs, we implement the entire processing of the 's'
+                   directive ourselves.  */
+                int flags = dp->flags;
+                int has_width;
+                size_t width;
+                int has_precision;
+                size_t precision;
+
+                has_width = 0;
+                width = 0;
+                if (dp->width_start != dp->width_end)
+                  {
+                    if (dp->width_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->width_arg_index].a.a_int;
+                        if (arg < 0)
+                          {
+                            /* "A negative field width is taken as a '-' flag
+                                followed by a positive field width."  */
+                            flags |= FLAG_LEFT;
+                            width = (unsigned int) (-arg);
+                          }
+                        else
+                          width = arg;
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->width_start;
+
+                        do
+                          width = xsum (xtimes (width, 10), *digitp++ - '0');
+                        while (digitp != dp->width_end);
+                      }
+                    has_width = 1;
+                  }
+
+                has_precision = 0;
+                precision = 6;
+                if (dp->precision_start != dp->precision_end)
+                  {
+                    if (dp->precision_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->precision_arg_index].a.a_int;
+                        /* "A negative precision is taken as if the precision
+                            were omitted."  */
+                        if (arg >= 0)
+                          {
+                            precision = arg;
+                            has_precision = 1;
+                          }
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->precision_start + 1;
+
+                        precision = 0;
+                        while (digitp != dp->precision_end)
+                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+                        has_precision = 1;
+                      }
+                  }
+
 # if WIDE_CHAR_VERSION
 # if WIDE_CHAR_VERSION
-                             {
-                               static const wchar_t decimal_format[] =
-                                 { '%', '+', 'd', '\0' };
-                               SNPRINTF (p, 6 + 1, decimal_format, exponent);
-                             }
-                             while (*p != '\0')
-                               p++;
+                /* %s in vasnwprintf.  See the specification of fwprintf.  */
+                {
+                  const char *arg = a.arg[dp->arg_index].a.a_string;
+                  const char *arg_end;
+                  size_t characters;
+
+                  if (has_precision)
+                    {
+                      /* Use only as many bytes as needed to produce PRECISION
+                         wide characters, from the left.  */
+#  if HAVE_MBRTOWC
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      arg_end = arg;
+                      characters = 0;
+                      for (; precision > 0; precision--)
+                        {
+                          int count;
+#  if HAVE_MBRTOWC
+                          count = mbrlen (arg_end, MB_CUR_MAX, &state);
+#  else
+                          count = mblen (arg_end, MB_CUR_MAX);
+#  endif
+                          if (count == 0)
+                            /* Found the terminating NUL.  */
+                            break;
+                          if (count < 0)
+                            {
+                              /* Invalid or incomplete multibyte character.  */
+                              if (!(result == resultbuf || result == NULL))
+                                free (result);
+                              if (buf_malloced != NULL)
+                                free (buf_malloced);
+                              CLEANUP ();
+                              errno = EILSEQ;
+                              return NULL;
+                            }
+                          arg_end += count;
+                          characters++;
+                        }
+                    }
+                  else if (has_width)
+                    {
+                      /* Use the entire string, and count the number of wide
+                         characters.  */
+#  if HAVE_MBRTOWC
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      arg_end = arg;
+                      characters = 0;
+                      for (;;)
+                        {
+                          int count;
+#  if HAVE_MBRTOWC
+                          count = mbrlen (arg_end, MB_CUR_MAX, &state);
+#  else
+                          count = mblen (arg_end, MB_CUR_MAX);
+#  endif
+                          if (count == 0)
+                            /* Found the terminating NUL.  */
+                            break;
+                          if (count < 0)
+                            {
+                              /* Invalid or incomplete multibyte character.  */
+                              if (!(result == resultbuf || result == NULL))
+                                free (result);
+                              if (buf_malloced != NULL)
+                                free (buf_malloced);
+                              CLEANUP ();
+                              errno = EILSEQ;
+                              return NULL;
+                            }
+                          arg_end += count;
+                          characters++;
+                        }
+                    }
+                  else
+                    {
+                      /* Use the entire string.  */
+                      arg_end = arg + strlen (arg);
+                      /* The number of characters doesn't matter.  */
+                      characters = 0;
+                    }
+
+                  if (has_width && width > characters
+                      && !(dp->flags & FLAG_LEFT))
+                    {
+                      size_t n = width - characters;
+                      ENSURE_ALLOCATION (xsum (length, n));
+                      DCHAR_SET (result + length, ' ', n);
+                      length += n;
+                    }
+
+                  if (has_precision || has_width)
+                    {
+                      /* We know the number of wide characters in advance.  */
+                      size_t remaining;
+#  if HAVE_MBRTOWC
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      ENSURE_ALLOCATION (xsum (length, characters));
+                      for (remaining = characters; remaining > 0; remaining--)
+                        {
+                          wchar_t wc;
+                          int count;
+#  if HAVE_MBRTOWC
+                          count = mbrtowc (&wc, arg, arg_end - arg, &state);
+#  else
+                          count = mbtowc (&wc, arg, arg_end - arg);
+#  endif
+                          if (count <= 0)
+                            /* mbrtowc not consistent with mbrlen, or mbtowc
+                               not consistent with mblen.  */
+                            abort ();
+                          result[length++] = wc;
+                          arg += count;
+                        }
+                      if (!(arg == arg_end))
+                        abort ();
+                    }
+                  else
+                    {
+#  if HAVE_MBRTOWC
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      while (arg < arg_end)
+                        {
+                          wchar_t wc;
+                          int count;
+#  if HAVE_MBRTOWC
+                          count = mbrtowc (&wc, arg, arg_end - arg, &state);
+#  else
+                          count = mbtowc (&wc, arg, arg_end - arg);
+#  endif
+                          if (count <= 0)
+                            /* mbrtowc not consistent with mbrlen, or mbtowc
+                               not consistent with mblen.  */
+                            abort ();
+                          ENSURE_ALLOCATION (xsum (length, 1));
+                          result[length++] = wc;
+                          arg += count;
+                        }
+                    }
+
+                  if (has_width && width > characters
+                      && (dp->flags & FLAG_LEFT))
+                    {
+                      size_t n = width - characters;
+                      ENSURE_ALLOCATION (xsum (length, n));
+                      DCHAR_SET (result + length, ' ', n);
+                      length += n;
+                    }
+                }
+# else
+                /* %ls in vasnprintf.  See the specification of fprintf.  */
+                {
+                  const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+                  const wchar_t *arg_end;
+                  size_t characters;
+#  if !DCHAR_IS_TCHAR
+                  /* This code assumes that TCHAR_T is 'char'.  */
+                  typedef int TCHAR_T_verify[2 * (sizeof (TCHAR_T) == 1) - 1];
+                  TCHAR_T *tmpsrc;
+                  DCHAR_T *tmpdst;
+                  size_t tmpdst_len;
+#  endif
+                  size_t w;
+
+                  if (has_precision)
+                    {
+                      /* Use only as many wide characters as needed to produce
+                         at most PRECISION bytes, from the left.  */
+#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      arg_end = arg;
+                      characters = 0;
+                      while (precision > 0)
+                        {
+                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */
+                          int count;
+
+                          if (*arg_end == 0)
+                            /* Found the terminating null wide character.  */
+                            break;
+#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                          count = wcrtomb (cbuf, *arg_end, &state);
+#  else
+                          count = wctomb (cbuf, *arg_end);
+#  endif
+                          if (count < 0)
+                            {
+                              /* Cannot convert.  */
+                              if (!(result == resultbuf || result == NULL))
+                                free (result);
+                              if (buf_malloced != NULL)
+                                free (buf_malloced);
+                              CLEANUP ();
+                              errno = EILSEQ;
+                              return NULL;
+                            }
+                          if (precision < count)
+                            break;
+                          arg_end++;
+                          characters += count;
+                          precision -= count;
+                        }
+                    }
+#  if DCHAR_IS_TCHAR
+                  else if (has_width)
+#  else
+                  else
+#  endif
+                    {
+                      /* Use the entire string, and count the number of
+                         bytes.  */
+#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#  endif
+                      arg_end = arg;
+                      characters = 0;
+                      for (;;)
+                        {
+                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */
+                          int count;
+
+                          if (*arg_end == 0)
+                            /* Found the terminating null wide character.  */
+                            break;
+#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                          count = wcrtomb (cbuf, *arg_end, &state);
+#  else
+                          count = wctomb (cbuf, *arg_end);
+#  endif
+                          if (count < 0)
+                            {
+                              /* Cannot convert.  */
+                              if (!(result == resultbuf || result == NULL))
+                                free (result);
+                              if (buf_malloced != NULL)
+                                free (buf_malloced);
+                              CLEANUP ();
+                              errno = EILSEQ;
+                              return NULL;
+                            }
+                          arg_end++;
+                          characters += count;
+                        }
+                    }
+#  if DCHAR_IS_TCHAR
+                  else
+                    {
+                      /* Use the entire string.  */
+                      arg_end = arg + local_wcslen (arg);
+                      /* The number of bytes doesn't matter.  */
+                      characters = 0;
+                    }
+#  endif
+
+#  if !DCHAR_IS_TCHAR
+                  /* Convert the string into a piece of temporary memory.  */
+                  tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T));
+                  if (tmpsrc == NULL)
+                    goto out_of_memory;
+                  {
+                    TCHAR_T *tmpptr = tmpsrc;
+                    size_t remaining;
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                    mbstate_t state;
+                    memset (&state, '\0', sizeof (mbstate_t));
+#   endif
+                    for (remaining = characters; remaining > 0; )
+                      {
+                        char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */
+                        int count;
+
+                        if (*arg == 0)
+                          abort ();
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                        count = wcrtomb (cbuf, *arg, &state);
+#   else
+                        count = wctomb (cbuf, *arg);
+#   endif
+                        if (count <= 0)
+                          /* Inconsistency.  */
+                          abort ();
+                        memcpy (tmpptr, cbuf, count);
+                        tmpptr += count;
+                        arg++;
+                        remaining -= count;
+                      }
+                    if (!(arg == arg_end))
+                      abort ();
+                  }
+
+                  /* Convert from TCHAR_T[] to DCHAR_T[].  */
+                  tmpdst =
+                    DCHAR_CONV_FROM_ENCODING (locale_charset (),
+                                              iconveh_question_mark,
+                                              tmpsrc, characters,
+                                              NULL,
+                                              NULL, &tmpdst_len);
+                  if (tmpdst == NULL)
+                    {
+                      int saved_errno = errno;
+                      free (tmpsrc);
+                      if (!(result == resultbuf || result == NULL))
+                        free (result);
+                      if (buf_malloced != NULL)
+                        free (buf_malloced);
+                      CLEANUP ();
+                      errno = saved_errno;
+                      return NULL;
+                    }
+                  free (tmpsrc);
+#  endif
+
+                  if (has_width)
+                    {
+#  if ENABLE_UNISTDIO
+                      /* Outside POSIX, it's preferrable to compare the width
+                         against the number of _characters_ of the converted
+                         value.  */
+                      w = DCHAR_MBSNLEN (result + length, characters);
+#  else
+                      /* The width is compared against the number of _bytes_
+                         of the converted value, says POSIX.  */
+                      w = characters;
+#  endif
+                    }
+                  else
+                    /* w doesn't matter.  */
+                    w = 0;
+
+                  if (has_width && width > w
+                      && !(dp->flags & FLAG_LEFT))
+                    {
+                      size_t n = width - w;
+                      ENSURE_ALLOCATION (xsum (length, n));
+                      DCHAR_SET (result + length, ' ', n);
+                      length += n;
+                    }
+
+#  if DCHAR_IS_TCHAR
+                  if (has_precision || has_width)
+                    {
+                      /* We know the number of bytes in advance.  */
+                      size_t remaining;
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#   endif
+                      ENSURE_ALLOCATION (xsum (length, characters));
+                      for (remaining = characters; remaining > 0; )
+                        {
+                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */
+                          int count;
+
+                          if (*arg == 0)
+                            abort ();
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                          count = wcrtomb (cbuf, *arg, &state);
+#   else
+                          count = wctomb (cbuf, *arg);
+#   endif
+                          if (count <= 0)
+                            /* Inconsistency.  */
+                            abort ();
+                          memcpy (result + length, cbuf, count);
+                          length += count;
+                          arg++;
+                          remaining -= count;
+                        }
+                      if (!(arg == arg_end))
+                        abort ();
+                    }
+                  else
+                    {
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                      mbstate_t state;
+                      memset (&state, '\0', sizeof (mbstate_t));
+#   endif
+                      while (arg < arg_end)
+                        {
+                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */
+                          int count;
+
+                          if (*arg == 0)
+                            abort ();
+#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
+                          count = wcrtomb (cbuf, *arg, &state);
+#   else
+                          count = wctomb (cbuf, *arg);
+#   endif
+                          if (count <= 0)
+                            {
+                              /* Cannot convert.  */
+                              if (!(result == resultbuf || result == NULL))
+                                free (result);
+                              if (buf_malloced != NULL)
+                                free (buf_malloced);
+                              CLEANUP ();
+                              errno = EILSEQ;
+                              return NULL;
+                            }
+                          ENSURE_ALLOCATION (xsum (length, count));
+                          memcpy (result + length, cbuf, count);
+                          length += count;
+                          arg++;
+                        }
+                    }
+#  else
+                  ENSURE_ALLOCATION (xsum (length, tmpdst_len));
+                  DCHAR_CPY (result + length, tmpdst, tmpdst_len);
+                  free (tmpdst);
+                  length += tmpdst_len;
+#  endif
+
+                  if (has_width && width > w
+                      && (dp->flags & FLAG_LEFT))
+                    {
+                      size_t n = width - w;
+                      ENSURE_ALLOCATION (xsum (length, n));
+                      DCHAR_SET (result + length, ' ', n);
+                      length += n;
+                    }
+                }
+# endif
+              }
+#endif
+#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
+            else if ((dp->conversion == 'a' || dp->conversion == 'A')
+# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
+                     && (0
+#  if NEED_PRINTF_DOUBLE
+                         || a.arg[dp->arg_index].type == TYPE_DOUBLE
+#  endif
+#  if NEED_PRINTF_LONG_DOUBLE
+                         || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
+#  endif
+                        )
+# endif
+                    )
+              {
+                arg_type type = a.arg[dp->arg_index].type;
+                int flags = dp->flags;
+                int has_width;
+                size_t width;
+                int has_precision;
+                size_t precision;
+                size_t tmp_length;
+                DCHAR_T tmpbuf[700];
+                DCHAR_T *tmp;
+                DCHAR_T *pad_ptr;
+                DCHAR_T *p;
+
+                has_width = 0;
+                width = 0;
+                if (dp->width_start != dp->width_end)
+                  {
+                    if (dp->width_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->width_arg_index].a.a_int;
+                        if (arg < 0)
+                          {
+                            /* "A negative field width is taken as a '-' flag
+                                followed by a positive field width."  */
+                            flags |= FLAG_LEFT;
+                            width = (unsigned int) (-arg);
+                          }
+                        else
+                          width = arg;
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->width_start;
+
+                        do
+                          width = xsum (xtimes (width, 10), *digitp++ - '0');
+                        while (digitp != dp->width_end);
+                      }
+                    has_width = 1;
+                  }
+
+                has_precision = 0;
+                precision = 0;
+                if (dp->precision_start != dp->precision_end)
+                  {
+                    if (dp->precision_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->precision_arg_index].a.a_int;
+                        /* "A negative precision is taken as if the precision
+                            were omitted."  */
+                        if (arg >= 0)
+                          {
+                            precision = arg;
+                            has_precision = 1;
+                          }
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->precision_start + 1;
+
+                        precision = 0;
+                        while (digitp != dp->precision_end)
+                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+                        has_precision = 1;
+                      }
+                  }
+
+                /* Allocate a temporary buffer of sufficient size.  */
+                if (type == TYPE_LONGDOUBLE)
+                  tmp_length =
+                    (unsigned int) ((LDBL_DIG + 1)
+                                    * 0.831 /* decimal -> hexadecimal */
+                                   )
+                    + 1; /* turn floor into ceil */
+                else
+                  tmp_length =
+                    (unsigned int) ((DBL_DIG + 1)
+                                    * 0.831 /* decimal -> hexadecimal */
+                                   )
+                    + 1; /* turn floor into ceil */
+                if (tmp_length < precision)
+                  tmp_length = precision;
+                /* Account for sign, decimal point etc. */
+                tmp_length = xsum (tmp_length, 12);
+
+                if (tmp_length < width)
+                  tmp_length = width;
+
+                tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+
+                if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
+                  tmp = tmpbuf;
+                else
+                  {
+                    size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
+
+                    if (size_overflow_p (tmp_memsize))
+                      /* Overflow, would lead to out of memory.  */
+                      goto out_of_memory;
+                    tmp = (DCHAR_T *) malloc (tmp_memsize);
+                    if (tmp == NULL)
+                      /* Out of memory.  */
+                      goto out_of_memory;
+                  }
+
+                pad_ptr = NULL;
+                p = tmp;
+                if (type == TYPE_LONGDOUBLE)
+                  {
+# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
+                    long double arg = a.arg[dp->arg_index].a.a_longdouble;
+
+                    if (isnanl (arg))
+                      {
+                        if (dp->conversion == 'A')
+                          {
+                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+                          }
+                        else
+                          {
+                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+                          }
+                      }
+                    else
+                      {
+                        int sign = 0;
+                        DECL_LONG_DOUBLE_ROUNDING
+
+                        BEGIN_LONG_DOUBLE_ROUNDING ();
+
+                        if (signbit (arg)) /* arg < 0.0L or negative zero */
+                          {
+                            sign = -1;
+                            arg = -arg;
+                          }
+
+                        if (sign < 0)
+                          *p++ = '-';
+                        else if (flags & FLAG_SHOWSIGN)
+                          *p++ = '+';
+                        else if (flags & FLAG_SPACE)
+                          *p++ = ' ';
+
+                        if (arg > 0.0L && arg + arg == arg)
+                          {
+                            if (dp->conversion == 'A')
+                              {
+                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+                              }
+                            else
+                              {
+                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+                              }
+                          }
+                        else
+                          {
+                            int exponent;
+                            long double mantissa;
+
+                            if (arg > 0.0L)
+                              mantissa = printf_frexpl (arg, &exponent);
+                            else
+                              {
+                                exponent = 0;
+                                mantissa = 0.0L;
+                              }
+
+                            if (has_precision
+                                && precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1)
+                              {
+                                /* Round the mantissa.  */
+                                long double tail = mantissa;
+                                size_t q;
+
+                                for (q = precision; ; q--)
+                                  {
+                                    int digit = (int) tail;
+                                    tail -= digit;
+                                    if (q == 0)
+                                      {
+                                        if (digit & 1 ? tail >= 0.5L : tail > 0.5L)
+                                          tail = 1 - tail;
+                                        else
+                                          tail = - tail;
+                                        break;
+                                      }
+                                    tail *= 16.0L;
+                                  }
+                                if (tail != 0.0L)
+                                  for (q = precision; q > 0; q--)
+                                    tail *= 0.0625L;
+                                mantissa += tail;
+                              }
+
+                            *p++ = '0';
+                            *p++ = dp->conversion - 'A' + 'X';
+                            pad_ptr = p;
+                            {
+                              int digit;
+
+                              digit = (int) mantissa;
+                              mantissa -= digit;
+                              *p++ = '0' + digit;
+                              if ((flags & FLAG_ALT)
+                                  || mantissa > 0.0L || precision > 0)
+                                {
+                                  *p++ = decimal_point_char ();
+                                  /* This loop terminates because we assume
+                                     that FLT_RADIX is a power of 2.  */
+                                  while (mantissa > 0.0L)
+                                    {
+                                      mantissa *= 16.0L;
+                                      digit = (int) mantissa;
+                                      mantissa -= digit;
+                                      *p++ = digit
+                                             + (digit < 10
+                                                ? '0'
+                                                : dp->conversion - 10);
+                                      if (precision > 0)
+                                        precision--;
+                                    }
+                                  while (precision > 0)
+                                    {
+                                      *p++ = '0';
+                                      precision--;
+                                    }
+                                }
+                              }
+                              *p++ = dp->conversion - 'A' + 'P';
+#  if WIDE_CHAR_VERSION
+                              {
+                                static const wchar_t decimal_format[] =
+                                  { '%', '+', 'd', '\0' };
+                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                              }
+                              while (*p != '\0')
+                                p++;
+#  else
+                              if (sizeof (DCHAR_T) == 1)
+                                {
+                                  sprintf ((char *) p, "%+d", exponent);
+                                  while (*p != '\0')
+                                    p++;
+                                }
+                              else
+                                {
+                                  char expbuf[6 + 1];
+                                  const char *ep;
+                                  sprintf (expbuf, "%+d", exponent);
+                                  for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                    p++;
+                                }
+#  endif
+                          }
+
+                        END_LONG_DOUBLE_ROUNDING ();
+                      }
 # else
 # else
-                             if (sizeof (DCHAR_T) == 1)
-                               {
-                                 sprintf ((char *) p, "%+d", exponent);
-                                 while (*p != '\0')
-                                   p++;
-                               }
-                             else
-                               {
-                                 char expbuf[6 + 1];
-                                 const char *ep;
-                                 sprintf (expbuf, "%+d", exponent);
-                                 for (ep = expbuf; (*p = *ep) != '\0'; ep++)
-                                   p++;
-                               }
+                    abort ();
 # endif
 # endif
-                         }
-                     }
-                 }
-               /* The generated string now extends from tmp to p, with the
-                  zero padding insertion point being at pad_ptr.  */
-               if (has_width && p - tmp < width)
-                 {
-                   size_t pad = width - (p - tmp);
-                   DCHAR_T *end = p + pad;
-
-                   if (flags & FLAG_LEFT)
-                     {
-                       /* Pad with spaces on the right.  */
-                       for (; pad > 0; pad--)
-                         *p++ = ' ';
-                     }
-                   else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
-                     {
-                       /* Pad with zeroes.  */
-                       DCHAR_T *q = end;
-
-                       while (p > pad_ptr)
-                         *--q = *--p;
-                       for (; pad > 0; pad--)
-                         *p++ = '0';
-                     }
-                   else
-                     {
-                       /* Pad with spaces on the left.  */
-                       DCHAR_T *q = end;
-
-                       while (p > tmp)
-                         *--q = *--p;
-                       for (; pad > 0; pad--)
-                         *p++ = ' ';
-                     }
-
-                   p = end;
-                 }
-
-               {
-                 size_t count = p - tmp;
-
-                 if (count >= tmp_length)
-                   /* tmp_length was incorrectly calculated - fix the
-                      code above!  */
-                   abort ();
-
-                 /* Make room for the result.  */
-                 if (count >= allocated - length)
-                   {
-                     size_t n = xsum (length, count);
-
-                     ENSURE_ALLOCATION (n);
-                   }
-
-                 /* Append the result.  */
-                 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
-                 if (tmp != tmpbuf)
-                   free (tmp);
-                 length += count;
-               }
-             }
+                  }
+                else
+                  {
+# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
+                    double arg = a.arg[dp->arg_index].a.a_double;
+
+                    if (isnand (arg))
+                      {
+                        if (dp->conversion == 'A')
+                          {
+                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+                          }
+                        else
+                          {
+                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+                          }
+                      }
+                    else
+                      {
+                        int sign = 0;
+
+                        if (signbit (arg)) /* arg < 0.0 or negative zero */
+                          {
+                            sign = -1;
+                            arg = -arg;
+                          }
+
+                        if (sign < 0)
+                          *p++ = '-';
+                        else if (flags & FLAG_SHOWSIGN)
+                          *p++ = '+';
+                        else if (flags & FLAG_SPACE)
+                          *p++ = ' ';
+
+                        if (arg > 0.0 && arg + arg == arg)
+                          {
+                            if (dp->conversion == 'A')
+                              {
+                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+                              }
+                            else
+                              {
+                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+                              }
+                          }
+                        else
+                          {
+                            int exponent;
+                            double mantissa;
+
+                            if (arg > 0.0)
+                              mantissa = printf_frexp (arg, &exponent);
+                            else
+                              {
+                                exponent = 0;
+                                mantissa = 0.0;
+                              }
+
+                            if (has_precision
+                                && precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1)
+                              {
+                                /* Round the mantissa.  */
+                                double tail = mantissa;
+                                size_t q;
+
+                                for (q = precision; ; q--)
+                                  {
+                                    int digit = (int) tail;
+                                    tail -= digit;
+                                    if (q == 0)
+                                      {
+                                        if (digit & 1 ? tail >= 0.5 : tail > 0.5)
+                                          tail = 1 - tail;
+                                        else
+                                          tail = - tail;
+                                        break;
+                                      }
+                                    tail *= 16.0;
+                                  }
+                                if (tail != 0.0)
+                                  for (q = precision; q > 0; q--)
+                                    tail *= 0.0625;
+                                mantissa += tail;
+                              }
+
+                            *p++ = '0';
+                            *p++ = dp->conversion - 'A' + 'X';
+                            pad_ptr = p;
+                            {
+                              int digit;
+
+                              digit = (int) mantissa;
+                              mantissa -= digit;
+                              *p++ = '0' + digit;
+                              if ((flags & FLAG_ALT)
+                                  || mantissa > 0.0 || precision > 0)
+                                {
+                                  *p++ = decimal_point_char ();
+                                  /* This loop terminates because we assume
+                                     that FLT_RADIX is a power of 2.  */
+                                  while (mantissa > 0.0)
+                                    {
+                                      mantissa *= 16.0;
+                                      digit = (int) mantissa;
+                                      mantissa -= digit;
+                                      *p++ = digit
+                                             + (digit < 10
+                                                ? '0'
+                                                : dp->conversion - 10);
+                                      if (precision > 0)
+                                        precision--;
+                                    }
+                                  while (precision > 0)
+                                    {
+                                      *p++ = '0';
+                                      precision--;
+                                    }
+                                }
+                              }
+                              *p++ = dp->conversion - 'A' + 'P';
+#  if WIDE_CHAR_VERSION
+                              {
+                                static const wchar_t decimal_format[] =
+                                  { '%', '+', 'd', '\0' };
+                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                              }
+                              while (*p != '\0')
+                                p++;
+#  else
+                              if (sizeof (DCHAR_T) == 1)
+                                {
+                                  sprintf ((char *) p, "%+d", exponent);
+                                  while (*p != '\0')
+                                    p++;
+                                }
+                              else
+                                {
+                                  char expbuf[6 + 1];
+                                  const char *ep;
+                                  sprintf (expbuf, "%+d", exponent);
+                                  for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                    p++;
+                                }
+#  endif
+                          }
+                      }
+# else
+                    abort ();
+# endif
+                  }
+                /* The generated string now extends from tmp to p, with the
+                   zero padding insertion point being at pad_ptr.  */
+                if (has_width && p - tmp < width)
+                  {
+                    size_t pad = width - (p - tmp);
+                    DCHAR_T *end = p + pad;
+
+                    if (flags & FLAG_LEFT)
+                      {
+                        /* Pad with spaces on the right.  */
+                        for (; pad > 0; pad--)
+                          *p++ = ' ';
+                      }
+                    else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
+                      {
+                        /* Pad with zeroes.  */
+                        DCHAR_T *q = end;
+
+                        while (p > pad_ptr)
+                          *--q = *--p;
+                        for (; pad > 0; pad--)
+                          *p++ = '0';
+                      }
+                    else
+                      {
+                        /* Pad with spaces on the left.  */
+                        DCHAR_T *q = end;
+
+                        while (p > tmp)
+                          *--q = *--p;
+                        for (; pad > 0; pad--)
+                          *p++ = ' ';
+                      }
+
+                    p = end;
+                  }
+
+                {
+                  size_t count = p - tmp;
+
+                  if (count >= tmp_length)
+                    /* tmp_length was incorrectly calculated - fix the
+                       code above!  */
+                    abort ();
+
+                  /* Make room for the result.  */
+                  if (count >= allocated - length)
+                    {
+                      size_t n = xsum (length, count);
+
+                      ENSURE_ALLOCATION (n);
+                    }
+
+                  /* Append the result.  */
+                  memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+                  if (tmp != tmpbuf)
+                    free (tmp);
+                  length += count;
+                }
+              }
 #endif
 #endif
-#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
-           else if ((dp->conversion == 'f' || dp->conversion == 'F'
-                     || dp->conversion == 'e' || dp->conversion == 'E'
-                     || dp->conversion == 'g' || dp->conversion == 'G'
-                     || dp->conversion == 'a' || dp->conversion == 'A')
-                    && (0
-# if NEED_PRINTF_INFINITE_DOUBLE
-                        || (a.arg[dp->arg_index].type == TYPE_DOUBLE
-                            /* The systems (mingw) which produce wrong output
-                               for Inf, -Inf, and NaN also do so for -0.0.
-                               Therefore we treat this case here as well.  */
-                            && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double))
+#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
+            else if ((dp->conversion == 'f' || dp->conversion == 'F'
+                      || dp->conversion == 'e' || dp->conversion == 'E'
+                      || dp->conversion == 'g' || dp->conversion == 'G'
+                      || dp->conversion == 'a' || dp->conversion == 'A')
+                     && (0
+# if NEED_PRINTF_DOUBLE
+                         || a.arg[dp->arg_index].type == TYPE_DOUBLE
+# elif NEED_PRINTF_INFINITE_DOUBLE
+                         || (a.arg[dp->arg_index].type == TYPE_DOUBLE
+                             /* The systems (mingw) which produce wrong output
+                                for Inf, -Inf, and NaN also do so for -0.0.
+                                Therefore we treat this case here as well.  */
+                             && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double))
 # endif
 # if NEED_PRINTF_LONG_DOUBLE
 # endif
 # if NEED_PRINTF_LONG_DOUBLE
-                        || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
+                         || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
 # elif NEED_PRINTF_INFINITE_LONG_DOUBLE
 # elif NEED_PRINTF_INFINITE_LONG_DOUBLE
-                        || (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
-                            /* Some systems produce wrong output for Inf,
-                               -Inf, and NaN.  */
-                            && is_infinitel (a.arg[dp->arg_index].a.a_longdouble))
+                         || (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
+                             /* Some systems produce wrong output for Inf,
+                                -Inf, and NaN.  Some systems in this category
+                                (IRIX 5.3) also do so for -0.0.  Therefore we
+                                treat this case here as well.  */
+                             && is_infinite_or_zerol (a.arg[dp->arg_index].a.a_longdouble))
 # endif
 # endif
-                       ))
-             {
-# if NEED_PRINTF_INFINITE_DOUBLE && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE)
-               arg_type type = a.arg[dp->arg_index].type;
+                        ))
+              {
+# if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE)
+                arg_type type = a.arg[dp->arg_index].type;
 # endif
 # endif
-               int flags = dp->flags;
-               int has_width;
-               size_t width;
-               int has_precision;
-               size_t precision;
-               size_t tmp_length;
-               DCHAR_T tmpbuf[700];
-               DCHAR_T *tmp;
-               DCHAR_T *pad_ptr;
-               DCHAR_T *p;
-
-               has_width = 0;
-               width = 0;
-               if (dp->width_start != dp->width_end)
-                 {
-                   if (dp->width_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->width_arg_index].a.a_int;
-                       if (arg < 0)
-                         {
-                           /* "A negative field width is taken as a '-' flag
-                               followed by a positive field width."  */
-                           flags |= FLAG_LEFT;
-                           width = (unsigned int) (-arg);
-                         }
-                       else
-                         width = arg;
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->width_start;
-
-                       do
-                         width = xsum (xtimes (width, 10), *digitp++ - '0');
-                       while (digitp != dp->width_end);
-                     }
-                   has_width = 1;
-                 }
-
-               has_precision = 0;
-               precision = 0;
-               if (dp->precision_start != dp->precision_end)
-                 {
-                   if (dp->precision_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->precision_arg_index].a.a_int;
-                       /* "A negative precision is taken as if the precision
-                           were omitted."  */
-                       if (arg >= 0)
-                         {
-                           precision = arg;
-                           has_precision = 1;
-                         }
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->precision_start + 1;
-
-                       precision = 0;
-                       while (digitp != dp->precision_end)
-                         precision = xsum (xtimes (precision, 10), *digitp++ - '0');
-                       has_precision = 1;
-                     }
-                 }
-
-               /* POSIX specifies the default precision to be 6 for %f, %F,
-                  %e, %E, but not for %g, %G.  Implementations appear to use
-                  the same default precision also for %g, %G.  */
-               if (!has_precision)
-                 precision = 6;
-
-               /* Allocate a temporary buffer of sufficient size.  */
-# if NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE
-               tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0);
+                int flags = dp->flags;
+                int has_width;
+                size_t width;
+                int has_precision;
+                size_t precision;
+                size_t tmp_length;
+                DCHAR_T tmpbuf[700];
+                DCHAR_T *tmp;
+                DCHAR_T *pad_ptr;
+                DCHAR_T *p;
+
+                has_width = 0;
+                width = 0;
+                if (dp->width_start != dp->width_end)
+                  {
+                    if (dp->width_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->width_arg_index].a.a_int;
+                        if (arg < 0)
+                          {
+                            /* "A negative field width is taken as a '-' flag
+                                followed by a positive field width."  */
+                            flags |= FLAG_LEFT;
+                            width = (unsigned int) (-arg);
+                          }
+                        else
+                          width = arg;
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->width_start;
+
+                        do
+                          width = xsum (xtimes (width, 10), *digitp++ - '0');
+                        while (digitp != dp->width_end);
+                      }
+                    has_width = 1;
+                  }
+
+                has_precision = 0;
+                precision = 0;
+                if (dp->precision_start != dp->precision_end)
+                  {
+                    if (dp->precision_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->precision_arg_index].a.a_int;
+                        /* "A negative precision is taken as if the precision
+                            were omitted."  */
+                        if (arg >= 0)
+                          {
+                            precision = arg;
+                            has_precision = 1;
+                          }
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->precision_start + 1;
+
+                        precision = 0;
+                        while (digitp != dp->precision_end)
+                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+                        has_precision = 1;
+                      }
+                  }
+
+                /* POSIX specifies the default precision to be 6 for %f, %F,
+                   %e, %E, but not for %g, %G.  Implementations appear to use
+                   the same default precision also for %g, %G.  But for %a, %A,
+                   the default precision is 0.  */
+                if (!has_precision)
+                  if (!(dp->conversion == 'a' || dp->conversion == 'A'))
+                    precision = 6;
+
+                /* Allocate a temporary buffer of sufficient size.  */
+# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE
+                tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1);
+# elif NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE
+                tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0);
 # elif NEED_PRINTF_LONG_DOUBLE
 # elif NEED_PRINTF_LONG_DOUBLE
-               tmp_length = LDBL_DIG + 1;
+                tmp_length = LDBL_DIG + 1;
+# elif NEED_PRINTF_DOUBLE
+                tmp_length = DBL_DIG + 1;
 # else
 # else
-               tmp_length = 0;
+                tmp_length = 0;
 # endif
 # endif
-               if (tmp_length < precision)
-                 tmp_length = precision;
+                if (tmp_length < precision)
+                  tmp_length = precision;
 # if NEED_PRINTF_LONG_DOUBLE
 # if NEED_PRINTF_LONG_DOUBLE
-#  if NEED_PRINTF_INFINITE_DOUBLE
-               if (type == TYPE_LONGDOUBLE)
+#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
+                if (type == TYPE_LONGDOUBLE)
 #  endif
 #  endif
-                 if (dp->conversion == 'f' || dp->conversion == 'F')
-                   {
-                     long double arg = a.arg[dp->arg_index].a.a_longdouble;
-                     if (!(isnanl (arg) || arg + arg == arg))
-                       {
-                         /* arg is finite and nonzero.  */
-                         int exponent = floorlog10l (arg < 0 ? -arg : arg);
-                         if (exponent >= 0 && tmp_length < exponent + precision)
-                           tmp_length = exponent + precision;
-                       }
-                   }
+                  if (dp->conversion == 'f' || dp->conversion == 'F')
+                    {
+                      long double arg = a.arg[dp->arg_index].a.a_longdouble;
+                      if (!(isnanl (arg) || arg + arg == arg))
+                        {
+                          /* arg is finite and nonzero.  */
+                          int exponent = floorlog10l (arg < 0 ? -arg : arg);
+                          if (exponent >= 0 && tmp_length < exponent + precision)
+                            tmp_length = exponent + precision;
+                        }
+                    }
 # endif
 # endif
-               /* Account for sign, decimal point etc. */
-               tmp_length = xsum (tmp_length, 12);
+# if NEED_PRINTF_DOUBLE
+#  if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
+                if (type == TYPE_DOUBLE)
+#  endif
+                  if (dp->conversion == 'f' || dp->conversion == 'F')
+                    {
+                      double arg = a.arg[dp->arg_index].a.a_double;
+                      if (!(isnand (arg) || arg + arg == arg))
+                        {
+                          /* arg is finite and nonzero.  */
+                          int exponent = floorlog10 (arg < 0 ? -arg : arg);
+                          if (exponent >= 0 && tmp_length < exponent + precision)
+                            tmp_length = exponent + precision;
+                        }
+                    }
+# endif
+                /* Account for sign, decimal point etc. */
+                tmp_length = xsum (tmp_length, 12);
 
 
-               if (tmp_length < width)
-                 tmp_length = width;
+                if (tmp_length < width)
+                  tmp_length = width;
 
 
-               tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+                tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
 
 
-               if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
-                 tmp = tmpbuf;
-               else
-                 {
-                   size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
+                if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
+                  tmp = tmpbuf;
+                else
+                  {
+                    size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
 
 
-                   if (size_overflow_p (tmp_memsize))
-                     /* Overflow, would lead to out of memory.  */
-                     goto out_of_memory;
-                   tmp = (DCHAR_T *) malloc (tmp_memsize);
-                   if (tmp == NULL)
-                     /* Out of memory.  */
-                     goto out_of_memory;
-                 }
+                    if (size_overflow_p (tmp_memsize))
+                      /* Overflow, would lead to out of memory.  */
+                      goto out_of_memory;
+                    tmp = (DCHAR_T *) malloc (tmp_memsize);
+                    if (tmp == NULL)
+                      /* Out of memory.  */
+                      goto out_of_memory;
+                  }
 
 
-               pad_ptr = NULL;
-               p = tmp;
+                pad_ptr = NULL;
+                p = tmp;
 
 # if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
 
 # if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE
-#  if NEED_PRINTF_INFINITE_DOUBLE
-               if (type == TYPE_LONGDOUBLE)
+#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
+                if (type == TYPE_LONGDOUBLE)
 #  endif
 #  endif
-                 {
-                   long double arg = a.arg[dp->arg_index].a.a_longdouble;
-
-                   if (isnanl (arg))
-                     {
-                       if (dp->conversion >= 'A' && dp->conversion <= 'Z')
-                         {
-                           *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
-                         }
-                       else
-                         {
-                           *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
-                         }
-                     }
-                   else
-                     {
-                       int sign = 0;
-                       DECL_LONG_DOUBLE_ROUNDING
-
-                       BEGIN_LONG_DOUBLE_ROUNDING ();
-
-                       if (signbit (arg)) /* arg < 0.0L or negative zero */
-                         {
-                           sign = -1;
-                           arg = -arg;
-                         }
-
-                       if (sign < 0)
-                         *p++ = '-';
-                       else if (flags & FLAG_SHOWSIGN)
-                         *p++ = '+';
-                       else if (flags & FLAG_SPACE)
-                         *p++ = ' ';
-
-                       if (arg > 0.0L && arg + arg == arg)
-                         {
-                           if (dp->conversion >= 'A' && dp->conversion <= 'Z')
-                             {
-                               *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
-                             }
-                           else
-                             {
-                               *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
-                             }
-                         }
-                       else
-                         {
+                  {
+                    long double arg = a.arg[dp->arg_index].a.a_longdouble;
+
+                    if (isnanl (arg))
+                      {
+                        if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+                          {
+                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+                          }
+                        else
+                          {
+                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+                          }
+                      }
+                    else
+                      {
+                        int sign = 0;
+                        DECL_LONG_DOUBLE_ROUNDING
+
+                        BEGIN_LONG_DOUBLE_ROUNDING ();
+
+                        if (signbit (arg)) /* arg < 0.0L or negative zero */
+                          {
+                            sign = -1;
+                            arg = -arg;
+                          }
+
+                        if (sign < 0)
+                          *p++ = '-';
+                        else if (flags & FLAG_SHOWSIGN)
+                          *p++ = '+';
+                        else if (flags & FLAG_SPACE)
+                          *p++ = ' ';
+
+                        if (arg > 0.0L && arg + arg == arg)
+                          {
+                            if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+                              {
+                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+                              }
+                            else
+                              {
+                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+                              }
+                          }
+                        else
+                          {
 #  if NEED_PRINTF_LONG_DOUBLE
 #  if NEED_PRINTF_LONG_DOUBLE
-                           pad_ptr = p;
-
-                           if (dp->conversion == 'f' || dp->conversion == 'F')
-                             {
-                               char *digits;
-                               size_t ndigits;
-
-                               digits =
-                                 scale10_round_decimal_long_double (arg, precision);
-                               if (digits == NULL)
-                                 {
-                                   END_LONG_DOUBLE_ROUNDING ();
-                                   goto out_of_memory;
-                                 }
-                               ndigits = strlen (digits);
-
-                               if (ndigits > precision)
-                                 do
-                                   {
-                                     --ndigits;
-                                     *p++ = digits[ndigits];
-                                   }
-                                 while (ndigits > precision);
-                               else
-                                 *p++ = '0';
-                               /* Here ndigits <= precision.  */
-                               if ((flags & FLAG_ALT) || precision > 0)
-                                 {
-                                   *p++ = decimal_point_char ();
-                                   for (; precision > ndigits; precision--)
-                                     *p++ = '0';
-                                   while (ndigits > 0)
-                                     {
-                                       --ndigits;
-                                       *p++ = digits[ndigits];
-                                     }
-                                 }
-
-                               free (digits);
-                             }
-                           else if (dp->conversion == 'e' || dp->conversion == 'E')
-                             {
-                               int exponent;
-
-                               if (arg == 0.0L)
-                                 {
-                                   exponent = 0;
-                                   *p++ = '0';
-                                   if ((flags & FLAG_ALT) || precision > 0)
-                                     {
-                                       *p++ = decimal_point_char ();
-                                       for (; precision > 0; precision--)
-                                         *p++ = '0';
-                                     }
-                                 }
-                               else
-                                 {
-                                   /* arg > 0.0L.  */
-                                   int adjusted;
-                                   char *digits;
-                                   size_t ndigits;
-
-                                   exponent = floorlog10l (arg);
-                                   adjusted = 0;
-                                   for (;;)
-                                     {
-                                       digits =
-                                         scale10_round_decimal_long_double (arg,
-                                                                            (int)precision - exponent);
-                                       if (digits == NULL)
-                                         {
-                                           END_LONG_DOUBLE_ROUNDING ();
-                                           goto out_of_memory;
-                                         }
-                                       ndigits = strlen (digits);
-
-                                       if (ndigits == precision + 1)
-                                         break;
-                                       if (ndigits < precision
-                                           || ndigits > precision + 2)
-                                         /* The exponent was not guessed
-                                            precisely enough.  */
-                                         abort ();
-                                       if (adjusted)
-                                         /* None of two values of exponent is
-                                            the right one.  Prevent an endless
-                                            loop.  */
-                                         abort ();
-                                       free (digits);
-                                       if (ndigits == precision)
-                                         exponent -= 1;
-                                       else
-                                         exponent += 1;
-                                       adjusted = 1;
-                                     }
-
-                                   /* Here ndigits = precision+1.  */
-                                   *p++ = digits[--ndigits];
-                                   if ((flags & FLAG_ALT) || precision > 0)
-                                     {
-                                       *p++ = decimal_point_char ();
-                                       while (ndigits > 0)
-                                         {
-                                           --ndigits;
-                                           *p++ = digits[ndigits];
-                                         }
-                                     }
-
-                                   free (digits);
-                                 }
-
-                               *p++ = dp->conversion; /* 'e' or 'E' */
+                            pad_ptr = p;
+
+                            if (dp->conversion == 'f' || dp->conversion == 'F')
+                              {
+                                char *digits;
+                                size_t ndigits;
+
+                                digits =
+                                  scale10_round_decimal_long_double (arg, precision);
+                                if (digits == NULL)
+                                  {
+                                    END_LONG_DOUBLE_ROUNDING ();
+                                    goto out_of_memory;
+                                  }
+                                ndigits = strlen (digits);
+
+                                if (ndigits > precision)
+                                  do
+                                    {
+                                      --ndigits;
+                                      *p++ = digits[ndigits];
+                                    }
+                                  while (ndigits > precision);
+                                else
+                                  *p++ = '0';
+                                /* Here ndigits <= precision.  */
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > ndigits; precision--)
+                                      *p++ = '0';
+                                    while (ndigits > 0)
+                                      {
+                                        --ndigits;
+                                        *p++ = digits[ndigits];
+                                      }
+                                  }
+
+                                free (digits);
+                              }
+                            else if (dp->conversion == 'e' || dp->conversion == 'E')
+                              {
+                                int exponent;
+
+                                if (arg == 0.0L)
+                                  {
+                                    exponent = 0;
+                                    *p++ = '0';
+                                    if ((flags & FLAG_ALT) || precision > 0)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        for (; precision > 0; precision--)
+                                          *p++ = '0';
+                                      }
+                                  }
+                                else
+                                  {
+                                    /* arg > 0.0L.  */
+                                    int adjusted;
+                                    char *digits;
+                                    size_t ndigits;
+
+                                    exponent = floorlog10l (arg);
+                                    adjusted = 0;
+                                    for (;;)
+                                      {
+                                        digits =
+                                          scale10_round_decimal_long_double (arg,
+                                                                             (int)precision - exponent);
+                                        if (digits == NULL)
+                                          {
+                                            END_LONG_DOUBLE_ROUNDING ();
+                                            goto out_of_memory;
+                                          }
+                                        ndigits = strlen (digits);
+
+                                        if (ndigits == precision + 1)
+                                          break;
+                                        if (ndigits < precision
+                                            || ndigits > precision + 2)
+                                          /* The exponent was not guessed
+                                             precisely enough.  */
+                                          abort ();
+                                        if (adjusted)
+                                          /* None of two values of exponent is
+                                             the right one.  Prevent an endless
+                                             loop.  */
+                                          abort ();
+                                        free (digits);
+                                        if (ndigits == precision)
+                                          exponent -= 1;
+                                        else
+                                          exponent += 1;
+                                        adjusted = 1;
+                                      }
+                                    /* Here ndigits = precision+1.  */
+                                    if (is_borderline (digits, precision))
+                                      {
+                                        /* Maybe the exponent guess was too high
+                                           and a smaller exponent can be reached
+                                           by turning a 10...0 into 9...9x.  */
+                                        char *digits2 =
+                                          scale10_round_decimal_long_double (arg,
+                                                                             (int)precision - exponent + 1);
+                                        if (digits2 == NULL)
+                                          {
+                                            free (digits);
+                                            END_LONG_DOUBLE_ROUNDING ();
+                                            goto out_of_memory;
+                                          }
+                                        if (strlen (digits2) == precision + 1)
+                                          {
+                                            free (digits);
+                                            digits = digits2;
+                                            exponent -= 1;
+                                          }
+                                        else
+                                          free (digits2);
+                                      }
+                                    /* Here ndigits = precision+1.  */
+
+                                    *p++ = digits[--ndigits];
+                                    if ((flags & FLAG_ALT) || precision > 0)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        while (ndigits > 0)
+                                          {
+                                            --ndigits;
+                                            *p++ = digits[ndigits];
+                                          }
+                                      }
+
+                                    free (digits);
+                                  }
+
+                                *p++ = dp->conversion; /* 'e' or 'E' */
 #   if WIDE_CHAR_VERSION
 #   if WIDE_CHAR_VERSION
-                               {
-                                 static const wchar_t decimal_format[] =
-                                   { '%', '+', '.', '2', 'd', '\0' };
-                                 SNPRINTF (p, 6 + 1, decimal_format, exponent);
-                               }
-                               while (*p != '\0')
-                                 p++;
+                                {
+                                  static const wchar_t decimal_format[] =
+                                    { '%', '+', '.', '2', 'd', '\0' };
+                                  SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                                }
+                                while (*p != '\0')
+                                  p++;
 #   else
 #   else
-                               if (sizeof (DCHAR_T) == 1)
-                                 {
-                                   sprintf ((char *) p, "%+.2d", exponent);
-                                   while (*p != '\0')
-                                     p++;
-                                 }
-                               else
-                                 {
-                                   char expbuf[6 + 1];
-                                   const char *ep;
-                                   sprintf (expbuf, "%+.2d", exponent);
-                                   for (ep = expbuf; (*p = *ep) != '\0'; ep++)
-                                     p++;
-                                 }
+                                if (sizeof (DCHAR_T) == 1)
+                                  {
+                                    sprintf ((char *) p, "%+.2d", exponent);
+                                    while (*p != '\0')
+                                      p++;
+                                  }
+                                else
+                                  {
+                                    char expbuf[6 + 1];
+                                    const char *ep;
+                                    sprintf (expbuf, "%+.2d", exponent);
+                                    for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                      p++;
+                                  }
 #   endif
 #   endif
-                             }
-                           else if (dp->conversion == 'g' || dp->conversion == 'G')
-                             {
-                               if (precision == 0)
-                                 precision = 1;
-                               /* precision >= 1.  */
-
-                               if (arg == 0.0L)
-                                 /* The exponent is 0, >= -4, < precision.
-                                    Use fixed-point notation.  */
-                                 {
-                                   size_t ndigits = precision;
-                                   /* Number of trailing zeroes that have to be
-                                      dropped.  */
-                                   size_t nzeroes =
-                                     (flags & FLAG_ALT ? 0 : precision - 1);
-
-                                   --ndigits;
-                                   *p++ = '0';
-                                   if ((flags & FLAG_ALT) || ndigits > nzeroes)
-                                     {
-                                       *p++ = decimal_point_char ();
-                                       while (ndigits > nzeroes)
-                                         {
-                                           --ndigits;
-                                           *p++ = '0';
-                                         }
-                                     }
-                                 }
-                               else
-                                 {
-                                   /* arg > 0.0L.  */
-                                   int exponent;
-                                   int adjusted;
-                                   char *digits;
-                                   size_t ndigits;
-                                   size_t nzeroes;
-
-                                   exponent = floorlog10l (arg);
-                                   adjusted = 0;
-                                   for (;;)
-                                     {
-                                       digits =
-                                         scale10_round_decimal_long_double (arg,
-                                                                            (int)(precision - 1) - exponent);
-                                       if (digits == NULL)
-                                         {
-                                           END_LONG_DOUBLE_ROUNDING ();
-                                           goto out_of_memory;
-                                         }
-                                       ndigits = strlen (digits);
-
-                                       if (ndigits == precision)
-                                         break;
-                                       if (ndigits < precision - 1
-                                           || ndigits > precision + 1)
-                                         /* The exponent was not guessed
-                                            precisely enough.  */
-                                         abort ();
-                                       if (adjusted)
-                                         /* None of two values of exponent is
-                                            the right one.  Prevent an endless
-                                            loop.  */
-                                         abort ();
-                                       free (digits);
-                                       if (ndigits < precision)
-                                         exponent -= 1;
-                                       else
-                                         exponent += 1;
-                                       adjusted = 1;
-                                     }
-                                   /* Here ndigits = precision.  */
-
-                                   /* Determine the number of trailing zeroes
-                                      that have to be dropped.  */
-                                   nzeroes = 0;
-                                   if ((flags & FLAG_ALT) == 0)
-                                     while (nzeroes < ndigits
-                                            && digits[nzeroes] == '0')
-                                       nzeroes++;
-
-                                   /* The exponent is now determined.  */
-                                   if (exponent >= -4
-                                       && exponent < (long)precision)
-                                     {
-                                       /* Fixed-point notation:
-                                          max(exponent,0)+1 digits, then the
-                                          decimal point, then the remaining
-                                          digits without trailing zeroes.  */
-                                       if (exponent >= 0)
-                                         {
-                                           size_t count = exponent + 1;
-                                           /* Note: count <= precision = ndigits.  */
-                                           for (; count > 0; count--)
-                                             *p++ = digits[--ndigits];
-                                           if ((flags & FLAG_ALT) || ndigits > nzeroes)
-                                             {
-                                               *p++ = decimal_point_char ();
-                                               while (ndigits > nzeroes)
-                                                 {
-                                                   --ndigits;
-                                                   *p++ = digits[ndigits];
-                                                 }
-                                             }
-                                         }
-                                       else
-                                         {
-                                           size_t count = -exponent - 1;
-                                           *p++ = '0';
-                                           *p++ = decimal_point_char ();
-                                           for (; count > 0; count--)
-                                             *p++ = '0';
-                                           while (ndigits > nzeroes)
-                                             {
-                                               --ndigits;
-                                               *p++ = digits[ndigits];
-                                             }
-                                         }
-                                     }
-                                   else
-                                     {
-                                       /* Exponential notation.  */
-                                       *p++ = digits[--ndigits];
-                                       if ((flags & FLAG_ALT) || ndigits > nzeroes)
-                                         {
-                                           *p++ = decimal_point_char ();
-                                           while (ndigits > nzeroes)
-                                             {
-                                               --ndigits;
-                                               *p++ = digits[ndigits];
-                                             }
-                                         }
-                                       *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
+                              }
+                            else if (dp->conversion == 'g' || dp->conversion == 'G')
+                              {
+                                if (precision == 0)
+                                  precision = 1;
+                                /* precision >= 1.  */
+
+                                if (arg == 0.0L)
+                                  /* The exponent is 0, >= -4, < precision.
+                                     Use fixed-point notation.  */
+                                  {
+                                    size_t ndigits = precision;
+                                    /* Number of trailing zeroes that have to be
+                                       dropped.  */
+                                    size_t nzeroes =
+                                      (flags & FLAG_ALT ? 0 : precision - 1);
+
+                                    --ndigits;
+                                    *p++ = '0';
+                                    if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        while (ndigits > nzeroes)
+                                          {
+                                            --ndigits;
+                                            *p++ = '0';
+                                          }
+                                      }
+                                  }
+                                else
+                                  {
+                                    /* arg > 0.0L.  */
+                                    int exponent;
+                                    int adjusted;
+                                    char *digits;
+                                    size_t ndigits;
+                                    size_t nzeroes;
+
+                                    exponent = floorlog10l (arg);
+                                    adjusted = 0;
+                                    for (;;)
+                                      {
+                                        digits =
+                                          scale10_round_decimal_long_double (arg,
+                                                                             (int)(precision - 1) - exponent);
+                                        if (digits == NULL)
+                                          {
+                                            END_LONG_DOUBLE_ROUNDING ();
+                                            goto out_of_memory;
+                                          }
+                                        ndigits = strlen (digits);
+
+                                        if (ndigits == precision)
+                                          break;
+                                        if (ndigits < precision - 1
+                                            || ndigits > precision + 1)
+                                          /* The exponent was not guessed
+                                             precisely enough.  */
+                                          abort ();
+                                        if (adjusted)
+                                          /* None of two values of exponent is
+                                             the right one.  Prevent an endless
+                                             loop.  */
+                                          abort ();
+                                        free (digits);
+                                        if (ndigits < precision)
+                                          exponent -= 1;
+                                        else
+                                          exponent += 1;
+                                        adjusted = 1;
+                                      }
+                                    /* Here ndigits = precision.  */
+                                    if (is_borderline (digits, precision - 1))
+                                      {
+                                        /* Maybe the exponent guess was too high
+                                           and a smaller exponent can be reached
+                                           by turning a 10...0 into 9...9x.  */
+                                        char *digits2 =
+                                          scale10_round_decimal_long_double (arg,
+                                                                             (int)(precision - 1) - exponent + 1);
+                                        if (digits2 == NULL)
+                                          {
+                                            free (digits);
+                                            END_LONG_DOUBLE_ROUNDING ();
+                                            goto out_of_memory;
+                                          }
+                                        if (strlen (digits2) == precision)
+                                          {
+                                            free (digits);
+                                            digits = digits2;
+                                            exponent -= 1;
+                                          }
+                                        else
+                                          free (digits2);
+                                      }
+                                    /* Here ndigits = precision.  */
+
+                                    /* Determine the number of trailing zeroes
+                                       that have to be dropped.  */
+                                    nzeroes = 0;
+                                    if ((flags & FLAG_ALT) == 0)
+                                      while (nzeroes < ndigits
+                                             && digits[nzeroes] == '0')
+                                        nzeroes++;
+
+                                    /* The exponent is now determined.  */
+                                    if (exponent >= -4
+                                        && exponent < (long)precision)
+                                      {
+                                        /* Fixed-point notation:
+                                           max(exponent,0)+1 digits, then the
+                                           decimal point, then the remaining
+                                           digits without trailing zeroes.  */
+                                        if (exponent >= 0)
+                                          {
+                                            size_t count = exponent + 1;
+                                            /* Note: count <= precision = ndigits.  */
+                                            for (; count > 0; count--)
+                                              *p++ = digits[--ndigits];
+                                            if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                              {
+                                                *p++ = decimal_point_char ();
+                                                while (ndigits > nzeroes)
+                                                  {
+                                                    --ndigits;
+                                                    *p++ = digits[ndigits];
+                                                  }
+                                              }
+                                          }
+                                        else
+                                          {
+                                            size_t count = -exponent - 1;
+                                            *p++ = '0';
+                                            *p++ = decimal_point_char ();
+                                            for (; count > 0; count--)
+                                              *p++ = '0';
+                                            while (ndigits > nzeroes)
+                                              {
+                                                --ndigits;
+                                                *p++ = digits[ndigits];
+                                              }
+                                          }
+                                      }
+                                    else
+                                      {
+                                        /* Exponential notation.  */
+                                        *p++ = digits[--ndigits];
+                                        if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                          {
+                                            *p++ = decimal_point_char ();
+                                            while (ndigits > nzeroes)
+                                              {
+                                                --ndigits;
+                                                *p++ = digits[ndigits];
+                                              }
+                                          }
+                                        *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
 #   if WIDE_CHAR_VERSION
 #   if WIDE_CHAR_VERSION
-                                       {
-                                         static const wchar_t decimal_format[] =
-                                           { '%', '+', '.', '2', 'd', '\0' };
-                                         SNPRINTF (p, 6 + 1, decimal_format, exponent);
-                                       }
-                                       while (*p != '\0')
-                                         p++;
+                                        {
+                                          static const wchar_t decimal_format[] =
+                                            { '%', '+', '.', '2', 'd', '\0' };
+                                          SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                                        }
+                                        while (*p != '\0')
+                                          p++;
 #   else
 #   else
-                                       if (sizeof (DCHAR_T) == 1)
-                                         {
-                                           sprintf ((char *) p, "%+.2d", exponent);
-                                           while (*p != '\0')
-                                             p++;
-                                         }
-                                       else
-                                         {
-                                           char expbuf[6 + 1];
-                                           const char *ep;
-                                           sprintf (expbuf, "%+.2d", exponent);
-                                           for (ep = expbuf; (*p = *ep) != '\0'; ep++)
-                                             p++;
-                                         }
+                                        if (sizeof (DCHAR_T) == 1)
+                                          {
+                                            sprintf ((char *) p, "%+.2d", exponent);
+                                            while (*p != '\0')
+                                              p++;
+                                          }
+                                        else
+                                          {
+                                            char expbuf[6 + 1];
+                                            const char *ep;
+                                            sprintf (expbuf, "%+.2d", exponent);
+                                            for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                              p++;
+                                          }
 #   endif
 #   endif
-                                     }
+                                      }
 
 
-                                   free (digits);
-                                 }
-                             }
-                           else
-                             abort ();
+                                    free (digits);
+                                  }
+                              }
+                            else
+                              abort ();
 #  else
 #  else
-                           /* arg is finite.  */
-                           abort ();
+                            /* arg is finite.  */
+                            if (!(arg == 0.0L))
+                              abort ();
+
+                            pad_ptr = p;
+
+                            if (dp->conversion == 'f' || dp->conversion == 'F')
+                              {
+                                *p++ = '0';
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > 0; precision--)
+                                      *p++ = '0';
+                                  }
+                              }
+                            else if (dp->conversion == 'e' || dp->conversion == 'E')
+                              {
+                                *p++ = '0';
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > 0; precision--)
+                                      *p++ = '0';
+                                  }
+                                *p++ = dp->conversion; /* 'e' or 'E' */
+                                *p++ = '+';
+                                *p++ = '0';
+                                *p++ = '0';
+                              }
+                            else if (dp->conversion == 'g' || dp->conversion == 'G')
+                              {
+                                *p++ = '0';
+                                if (flags & FLAG_ALT)
+                                  {
+                                    size_t ndigits =
+                                      (precision > 0 ? precision - 1 : 0);
+                                    *p++ = decimal_point_char ();
+                                    for (; ndigits > 0; --ndigits)
+                                      *p++ = '0';
+                                  }
+                              }
+                            else if (dp->conversion == 'a' || dp->conversion == 'A')
+                              {
+                                *p++ = '0';
+                                *p++ = dp->conversion - 'A' + 'X';
+                                pad_ptr = p;
+                                *p++ = '0';
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > 0; precision--)
+                                      *p++ = '0';
+                                  }
+                                *p++ = dp->conversion - 'A' + 'P';
+                                *p++ = '+';
+                                *p++ = '0';
+                              }
+                            else
+                              abort ();
 #  endif
 #  endif
-                         }
+                          }
 
 
-                       END_LONG_DOUBLE_ROUNDING ();
-                     }
-                 }
-#  if NEED_PRINTF_INFINITE_DOUBLE
-               else
+                        END_LONG_DOUBLE_ROUNDING ();
+                      }
+                  }
+#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
+                else
 #  endif
 # endif
 #  endif
 # endif
-# if NEED_PRINTF_INFINITE_DOUBLE
-                 {
-                   /* Simpler than above: handle only NaN, Infinity, zero.  */
-                   double arg = a.arg[dp->arg_index].a.a_double;
-
-                   if (isnan (arg))
-                     {
-                       if (dp->conversion >= 'A' && dp->conversion <= 'Z')
-                         {
-                           *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
-                         }
-                       else
-                         {
-                           *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
-                         }
-                     }
-                   else
-                     {
-                       int sign = 0;
-
-                       if (signbit (arg)) /* arg < 0.0L or negative zero */
-                         {
-                           sign = -1;
-                           arg = -arg;
-                         }
-
-                       if (sign < 0)
-                         *p++ = '-';
-                       else if (flags & FLAG_SHOWSIGN)
-                         *p++ = '+';
-                       else if (flags & FLAG_SPACE)
-                         *p++ = ' ';
-
-                       if (arg > 0.0 && arg + arg == arg)
-                         {
-                           if (dp->conversion >= 'A' && dp->conversion <= 'Z')
-                             {
-                               *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
-                             }
-                           else
-                             {
-                               *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
-                             }
-                         }
-                       else
-                         {
-                           if (!(arg == 0.0))
-                             abort ();
-
-                           pad_ptr = p;
-
-                           if (dp->conversion == 'f' || dp->conversion == 'F')
-                             {
-                               *p++ = '0';
-                               if ((flags & FLAG_ALT) || precision > 0)
-                                 {
-                                   *p++ = decimal_point_char ();
-                                   for (; precision > 0; precision--)
-                                     *p++ = '0';
-                                 }
-                             }
-                           else if (dp->conversion == 'e' || dp->conversion == 'E')
-                             {
-                               *p++ = '0';
-                               if ((flags & FLAG_ALT) || precision > 0)
-                                 {
-                                   *p++ = decimal_point_char ();
-                                   for (; precision > 0; precision--)
-                                     *p++ = '0';
-                                 }
-                               *p++ = dp->conversion; /* 'e' or 'E' */
-                               *p++ = '+';
-                               /* Produce the same number of exponent digits as
-                                  the native printf implementation.  */
-#  if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-                               *p++ = '0';
+# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
+                  {
+                    double arg = a.arg[dp->arg_index].a.a_double;
+
+                    if (isnand (arg))
+                      {
+                        if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+                          {
+                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+                          }
+                        else
+                          {
+                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+                          }
+                      }
+                    else
+                      {
+                        int sign = 0;
+
+                        if (signbit (arg)) /* arg < 0.0 or negative zero */
+                          {
+                            sign = -1;
+                            arg = -arg;
+                          }
+
+                        if (sign < 0)
+                          *p++ = '-';
+                        else if (flags & FLAG_SHOWSIGN)
+                          *p++ = '+';
+                        else if (flags & FLAG_SPACE)
+                          *p++ = ' ';
+
+                        if (arg > 0.0 && arg + arg == arg)
+                          {
+                            if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+                              {
+                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+                              }
+                            else
+                              {
+                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+                              }
+                          }
+                        else
+                          {
+#  if NEED_PRINTF_DOUBLE
+                            pad_ptr = p;
+
+                            if (dp->conversion == 'f' || dp->conversion == 'F')
+                              {
+                                char *digits;
+                                size_t ndigits;
+
+                                digits =
+                                  scale10_round_decimal_double (arg, precision);
+                                if (digits == NULL)
+                                  goto out_of_memory;
+                                ndigits = strlen (digits);
+
+                                if (ndigits > precision)
+                                  do
+                                    {
+                                      --ndigits;
+                                      *p++ = digits[ndigits];
+                                    }
+                                  while (ndigits > precision);
+                                else
+                                  *p++ = '0';
+                                /* Here ndigits <= precision.  */
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > ndigits; precision--)
+                                      *p++ = '0';
+                                    while (ndigits > 0)
+                                      {
+                                        --ndigits;
+                                        *p++ = digits[ndigits];
+                                      }
+                                  }
+
+                                free (digits);
+                              }
+                            else if (dp->conversion == 'e' || dp->conversion == 'E')
+                              {
+                                int exponent;
+
+                                if (arg == 0.0)
+                                  {
+                                    exponent = 0;
+                                    *p++ = '0';
+                                    if ((flags & FLAG_ALT) || precision > 0)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        for (; precision > 0; precision--)
+                                          *p++ = '0';
+                                      }
+                                  }
+                                else
+                                  {
+                                    /* arg > 0.0.  */
+                                    int adjusted;
+                                    char *digits;
+                                    size_t ndigits;
+
+                                    exponent = floorlog10 (arg);
+                                    adjusted = 0;
+                                    for (;;)
+                                      {
+                                        digits =
+                                          scale10_round_decimal_double (arg,
+                                                                        (int)precision - exponent);
+                                        if (digits == NULL)
+                                          goto out_of_memory;
+                                        ndigits = strlen (digits);
+
+                                        if (ndigits == precision + 1)
+                                          break;
+                                        if (ndigits < precision
+                                            || ndigits > precision + 2)
+                                          /* The exponent was not guessed
+                                             precisely enough.  */
+                                          abort ();
+                                        if (adjusted)
+                                          /* None of two values of exponent is
+                                             the right one.  Prevent an endless
+                                             loop.  */
+                                          abort ();
+                                        free (digits);
+                                        if (ndigits == precision)
+                                          exponent -= 1;
+                                        else
+                                          exponent += 1;
+                                        adjusted = 1;
+                                      }
+                                    /* Here ndigits = precision+1.  */
+                                    if (is_borderline (digits, precision))
+                                      {
+                                        /* Maybe the exponent guess was too high
+                                           and a smaller exponent can be reached
+                                           by turning a 10...0 into 9...9x.  */
+                                        char *digits2 =
+                                          scale10_round_decimal_double (arg,
+                                                                        (int)precision - exponent + 1);
+                                        if (digits2 == NULL)
+                                          {
+                                            free (digits);
+                                            goto out_of_memory;
+                                          }
+                                        if (strlen (digits2) == precision + 1)
+                                          {
+                                            free (digits);
+                                            digits = digits2;
+                                            exponent -= 1;
+                                          }
+                                        else
+                                          free (digits2);
+                                      }
+                                    /* Here ndigits = precision+1.  */
+
+                                    *p++ = digits[--ndigits];
+                                    if ((flags & FLAG_ALT) || precision > 0)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        while (ndigits > 0)
+                                          {
+                                            --ndigits;
+                                            *p++ = digits[ndigits];
+                                          }
+                                      }
+
+                                    free (digits);
+                                  }
+
+                                *p++ = dp->conversion; /* 'e' or 'E' */
+#   if WIDE_CHAR_VERSION
+                                {
+                                  static const wchar_t decimal_format[] =
+                                    /* Produce the same number of exponent digits
+                                       as the native printf implementation.  */
+#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                                    { '%', '+', '.', '3', 'd', '\0' };
+#    else
+                                    { '%', '+', '.', '2', 'd', '\0' };
+#    endif
+                                  SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                                }
+                                while (*p != '\0')
+                                  p++;
+#   else
+                                {
+                                  static const char decimal_format[] =
+                                    /* Produce the same number of exponent digits
+                                       as the native printf implementation.  */
+#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                                    "%+.3d";
+#    else
+                                    "%+.2d";
+#    endif
+                                  if (sizeof (DCHAR_T) == 1)
+                                    {
+                                      sprintf ((char *) p, decimal_format, exponent);
+                                      while (*p != '\0')
+                                        p++;
+                                    }
+                                  else
+                                    {
+                                      char expbuf[6 + 1];
+                                      const char *ep;
+                                      sprintf (expbuf, decimal_format, exponent);
+                                      for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                        p++;
+                                    }
+                                }
+#   endif
+                              }
+                            else if (dp->conversion == 'g' || dp->conversion == 'G')
+                              {
+                                if (precision == 0)
+                                  precision = 1;
+                                /* precision >= 1.  */
+
+                                if (arg == 0.0)
+                                  /* The exponent is 0, >= -4, < precision.
+                                     Use fixed-point notation.  */
+                                  {
+                                    size_t ndigits = precision;
+                                    /* Number of trailing zeroes that have to be
+                                       dropped.  */
+                                    size_t nzeroes =
+                                      (flags & FLAG_ALT ? 0 : precision - 1);
+
+                                    --ndigits;
+                                    *p++ = '0';
+                                    if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                      {
+                                        *p++ = decimal_point_char ();
+                                        while (ndigits > nzeroes)
+                                          {
+                                            --ndigits;
+                                            *p++ = '0';
+                                          }
+                                      }
+                                  }
+                                else
+                                  {
+                                    /* arg > 0.0.  */
+                                    int exponent;
+                                    int adjusted;
+                                    char *digits;
+                                    size_t ndigits;
+                                    size_t nzeroes;
+
+                                    exponent = floorlog10 (arg);
+                                    adjusted = 0;
+                                    for (;;)
+                                      {
+                                        digits =
+                                          scale10_round_decimal_double (arg,
+                                                                        (int)(precision - 1) - exponent);
+                                        if (digits == NULL)
+                                          goto out_of_memory;
+                                        ndigits = strlen (digits);
+
+                                        if (ndigits == precision)
+                                          break;
+                                        if (ndigits < precision - 1
+                                            || ndigits > precision + 1)
+                                          /* The exponent was not guessed
+                                             precisely enough.  */
+                                          abort ();
+                                        if (adjusted)
+                                          /* None of two values of exponent is
+                                             the right one.  Prevent an endless
+                                             loop.  */
+                                          abort ();
+                                        free (digits);
+                                        if (ndigits < precision)
+                                          exponent -= 1;
+                                        else
+                                          exponent += 1;
+                                        adjusted = 1;
+                                      }
+                                    /* Here ndigits = precision.  */
+                                    if (is_borderline (digits, precision - 1))
+                                      {
+                                        /* Maybe the exponent guess was too high
+                                           and a smaller exponent can be reached
+                                           by turning a 10...0 into 9...9x.  */
+                                        char *digits2 =
+                                          scale10_round_decimal_double (arg,
+                                                                        (int)(precision - 1) - exponent + 1);
+                                        if (digits2 == NULL)
+                                          {
+                                            free (digits);
+                                            goto out_of_memory;
+                                          }
+                                        if (strlen (digits2) == precision)
+                                          {
+                                            free (digits);
+                                            digits = digits2;
+                                            exponent -= 1;
+                                          }
+                                        else
+                                          free (digits2);
+                                      }
+                                    /* Here ndigits = precision.  */
+
+                                    /* Determine the number of trailing zeroes
+                                       that have to be dropped.  */
+                                    nzeroes = 0;
+                                    if ((flags & FLAG_ALT) == 0)
+                                      while (nzeroes < ndigits
+                                             && digits[nzeroes] == '0')
+                                        nzeroes++;
+
+                                    /* The exponent is now determined.  */
+                                    if (exponent >= -4
+                                        && exponent < (long)precision)
+                                      {
+                                        /* Fixed-point notation:
+                                           max(exponent,0)+1 digits, then the
+                                           decimal point, then the remaining
+                                           digits without trailing zeroes.  */
+                                        if (exponent >= 0)
+                                          {
+                                            size_t count = exponent + 1;
+                                            /* Note: count <= precision = ndigits.  */
+                                            for (; count > 0; count--)
+                                              *p++ = digits[--ndigits];
+                                            if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                              {
+                                                *p++ = decimal_point_char ();
+                                                while (ndigits > nzeroes)
+                                                  {
+                                                    --ndigits;
+                                                    *p++ = digits[ndigits];
+                                                  }
+                                              }
+                                          }
+                                        else
+                                          {
+                                            size_t count = -exponent - 1;
+                                            *p++ = '0';
+                                            *p++ = decimal_point_char ();
+                                            for (; count > 0; count--)
+                                              *p++ = '0';
+                                            while (ndigits > nzeroes)
+                                              {
+                                                --ndigits;
+                                                *p++ = digits[ndigits];
+                                              }
+                                          }
+                                      }
+                                    else
+                                      {
+                                        /* Exponential notation.  */
+                                        *p++ = digits[--ndigits];
+                                        if ((flags & FLAG_ALT) || ndigits > nzeroes)
+                                          {
+                                            *p++ = decimal_point_char ();
+                                            while (ndigits > nzeroes)
+                                              {
+                                                --ndigits;
+                                                *p++ = digits[ndigits];
+                                              }
+                                          }
+                                        *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
+#   if WIDE_CHAR_VERSION
+                                        {
+                                          static const wchar_t decimal_format[] =
+                                            /* Produce the same number of exponent digits
+                                               as the native printf implementation.  */
+#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                                            { '%', '+', '.', '3', 'd', '\0' };
+#    else
+                                            { '%', '+', '.', '2', 'd', '\0' };
+#    endif
+                                          SNPRINTF (p, 6 + 1, decimal_format, exponent);
+                                        }
+                                        while (*p != '\0')
+                                          p++;
+#   else
+                                        {
+                                          static const char decimal_format[] =
+                                            /* Produce the same number of exponent digits
+                                               as the native printf implementation.  */
+#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                                            "%+.3d";
+#    else
+                                            "%+.2d";
+#    endif
+                                          if (sizeof (DCHAR_T) == 1)
+                                            {
+                                              sprintf ((char *) p, decimal_format, exponent);
+                                              while (*p != '\0')
+                                                p++;
+                                            }
+                                          else
+                                            {
+                                              char expbuf[6 + 1];
+                                              const char *ep;
+                                              sprintf (expbuf, decimal_format, exponent);
+                                              for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                                p++;
+                                            }
+                                        }
+#   endif
+                                      }
+
+                                    free (digits);
+                                  }
+                              }
+                            else
+                              abort ();
+#  else
+                            /* arg is finite.  */
+                            if (!(arg == 0.0))
+                              abort ();
+
+                            pad_ptr = p;
+
+                            if (dp->conversion == 'f' || dp->conversion == 'F')
+                              {
+                                *p++ = '0';
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > 0; precision--)
+                                      *p++ = '0';
+                                  }
+                              }
+                            else if (dp->conversion == 'e' || dp->conversion == 'E')
+                              {
+                                *p++ = '0';
+                                if ((flags & FLAG_ALT) || precision > 0)
+                                  {
+                                    *p++ = decimal_point_char ();
+                                    for (; precision > 0; precision--)
+                                      *p++ = '0';
+                                  }
+                                *p++ = dp->conversion; /* 'e' or 'E' */
+                                *p++ = '+';
+                                /* Produce the same number of exponent digits as
+                                   the native printf implementation.  */
+#   if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                                *p++ = '0';
+#   endif
+                                *p++ = '0';
+                                *p++ = '0';
+                              }
+                            else if (dp->conversion == 'g' || dp->conversion == 'G')
+                              {
+                                *p++ = '0';
+                                if (flags & FLAG_ALT)
+                                  {
+                                    size_t ndigits =
+                                      (precision > 0 ? precision - 1 : 0);
+                                    *p++ = decimal_point_char ();
+                                    for (; ndigits > 0; --ndigits)
+                                      *p++ = '0';
+                                  }
+                              }
+                            else
+                              abort ();
 #  endif
 #  endif
-                               *p++ = '0';
-                               *p++ = '0';
-                             }
-                           else if (dp->conversion == 'g' || dp->conversion == 'G')
-                             {
-                               *p++ = '0';
-                               if (flags & FLAG_ALT)
-                                 {
-                                   size_t ndigits =
-                                     (precision > 0 ? precision - 1 : 0);
-                                   *p++ = decimal_point_char ();
-                                   for (; ndigits > 0; --ndigits)
-                                     *p++ = '0';
-                                 }
-                             }
-                           else
-                             abort ();
-                         }
-                     }
-                 }
+                          }
+                      }
+                  }
 # endif
 
 # endif
 
-               /* The generated string now extends from tmp to p, with the
-                  zero padding insertion point being at pad_ptr.  */
-               if (has_width && p - tmp < width)
-                 {
-                   size_t pad = width - (p - tmp);
-                   DCHAR_T *end = p + pad;
-
-                   if (flags & FLAG_LEFT)
-                     {
-                       /* Pad with spaces on the right.  */
-                       for (; pad > 0; pad--)
-                         *p++ = ' ';
-                     }
-                   else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
-                     {
-                       /* Pad with zeroes.  */
-                       DCHAR_T *q = end;
-
-                       while (p > pad_ptr)
-                         *--q = *--p;
-                       for (; pad > 0; pad--)
-                         *p++ = '0';
-                     }
-                   else
-                     {
-                       /* Pad with spaces on the left.  */
-                       DCHAR_T *q = end;
-
-                       while (p > tmp)
-                         *--q = *--p;
-                       for (; pad > 0; pad--)
-                         *p++ = ' ';
-                     }
-
-                   p = end;
-                 }
-
-               {
-                 size_t count = p - tmp;
-
-                 if (count >= tmp_length)
-                   /* tmp_length was incorrectly calculated - fix the
-                      code above!  */
-                   abort ();
-
-                 /* Make room for the result.  */
-                 if (count >= allocated - length)
-                   {
-                     size_t n = xsum (length, count);
-
-                     ENSURE_ALLOCATION (n);
-                   }
-
-                 /* Append the result.  */
-                 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
-                 if (tmp != tmpbuf)
-                   free (tmp);
-                 length += count;
-               }
-             }
+                /* The generated string now extends from tmp to p, with the
+                   zero padding insertion point being at pad_ptr.  */
+                if (has_width && p - tmp < width)
+                  {
+                    size_t pad = width - (p - tmp);
+                    DCHAR_T *end = p + pad;
+
+                    if (flags & FLAG_LEFT)
+                      {
+                        /* Pad with spaces on the right.  */
+                        for (; pad > 0; pad--)
+                          *p++ = ' ';
+                      }
+                    else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
+                      {
+                        /* Pad with zeroes.  */
+                        DCHAR_T *q = end;
+
+                        while (p > pad_ptr)
+                          *--q = *--p;
+                        for (; pad > 0; pad--)
+                          *p++ = '0';
+                      }
+                    else
+                      {
+                        /* Pad with spaces on the left.  */
+                        DCHAR_T *q = end;
+
+                        while (p > tmp)
+                          *--q = *--p;
+                        for (; pad > 0; pad--)
+                          *p++ = ' ';
+                      }
+
+                    p = end;
+                  }
+
+                {
+                  size_t count = p - tmp;
+
+                  if (count >= tmp_length)
+                    /* tmp_length was incorrectly calculated - fix the
+                       code above!  */
+                    abort ();
+
+                  /* Make room for the result.  */
+                  if (count >= allocated - length)
+                    {
+                      size_t n = xsum (length, count);
+
+                      ENSURE_ALLOCATION (n);
+                    }
+
+                  /* Append the result.  */
+                  memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+                  if (tmp != tmpbuf)
+                    free (tmp);
+                  length += count;
+                }
+              }
+#endif
+            else
+              {
+                arg_type type = a.arg[dp->arg_index].type;
+                int flags = dp->flags;
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+                int has_width;
+                size_t width;
+#endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+                int has_precision;
+                size_t precision;
 #endif
 #endif
-           else
-             {
-               arg_type type = a.arg[dp->arg_index].type;
-               int flags = dp->flags;
-#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
-               int has_width;
-               size_t width;
+#if NEED_PRINTF_UNBOUNDED_PRECISION
+                int prec_ourselves;
+#else
+#               define prec_ourselves 0
 #endif
 #endif
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
-               int pad_ourselves;
+#if NEED_PRINTF_FLAG_LEFTADJUST
+#               define pad_ourselves 1
+#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+                int pad_ourselves;
 #else
 #else
-#              define pad_ourselves 0
+#               define pad_ourselves 0
 #endif
 #endif
-               TCHAR_T *fbp;
-               unsigned int prefix_count;
-               int prefixes[2];
+                TCHAR_T *fbp;
+                unsigned int prefix_count;
+                int prefixes[2] IF_LINT (= { 0 });
 #if !USE_SNPRINTF
 #if !USE_SNPRINTF
-               size_t tmp_length;
-               TCHAR_T tmpbuf[700];
-               TCHAR_T *tmp;
+                size_t tmp_length;
+                TCHAR_T tmpbuf[700];
+                TCHAR_T *tmp;
 #endif
 
 #endif
 
-#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
-               has_width = 0;
-               width = 0;
-               if (dp->width_start != dp->width_end)
-                 {
-                   if (dp->width_arg_index != ARG_NONE)
-                     {
-                       int arg;
-
-                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
-                         abort ();
-                       arg = a.arg[dp->width_arg_index].a.a_int;
-                       if (arg < 0)
-                         {
-                           /* "A negative field width is taken as a '-' flag
-                               followed by a positive field width."  */
-                           flags |= FLAG_LEFT;
-                           width = (unsigned int) (-arg);
-                         }
-                       else
-                         width = arg;
-                     }
-                   else
-                     {
-                       const FCHAR_T *digitp = dp->width_start;
-
-                       do
-                         width = xsum (xtimes (width, 10), *digitp++ - '0');
-                       while (digitp != dp->width_end);
-                     }
-                   has_width = 1;
-                 }
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+                has_width = 0;
+                width = 0;
+                if (dp->width_start != dp->width_end)
+                  {
+                    if (dp->width_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->width_arg_index].a.a_int;
+                        if (arg < 0)
+                          {
+                            /* "A negative field width is taken as a '-' flag
+                                followed by a positive field width."  */
+                            flags |= FLAG_LEFT;
+                            width = (unsigned int) (-arg);
+                          }
+                        else
+                          width = arg;
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->width_start;
+
+                        do
+                          width = xsum (xtimes (width, 10), *digitp++ - '0');
+                        while (digitp != dp->width_end);
+                      }
+                    has_width = 1;
+                  }
 #endif
 
 #endif
 
-#if !USE_SNPRINTF
-               /* Allocate a temporary buffer of sufficient size for calling
-                  sprintf.  */
-               {
-                 size_t precision;
-
-                 precision = 6;
-                 if (dp->precision_start != dp->precision_end)
-                   {
-                     if (dp->precision_arg_index != ARG_NONE)
-                       {
-                         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 FCHAR_T *digitp = dp->precision_start + 1;
-
-                         precision = 0;
-                         while (digitp != dp->precision_end)
-                           precision = xsum (xtimes (precision, 10), *digitp++ - '0');
-                       }
-                   }
-
-                 switch (dp->conversion)
-                   {
-
-                   case 'd': case 'i': case 'u':
-# if HAVE_LONG_LONG_INT
-                     if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
-                       tmp_length =
-                         (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
-                                         * 0.30103 /* binary -> decimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     else
-# endif
-                     if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
-                       tmp_length =
-                         (unsigned int) (sizeof (unsigned long) * CHAR_BIT
-                                         * 0.30103 /* binary -> decimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     else
-                       tmp_length =
-                         (unsigned int) (sizeof (unsigned int) * CHAR_BIT
-                                         * 0.30103 /* binary -> decimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     if (tmp_length < precision)
-                       tmp_length = precision;
-                     /* Multiply by 2, as an estimate for FLAG_GROUP.  */
-                     tmp_length = xsum (tmp_length, tmp_length);
-                     /* Add 1, to account for a leading sign.  */
-                     tmp_length = xsum (tmp_length, 1);
-                     break;
-
-                   case 'o':
-# if HAVE_LONG_LONG_INT
-                     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 */
-                     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 */
-                     else
-                       tmp_length =
-                         (unsigned int) (sizeof (unsigned int) * CHAR_BIT
-                                         * 0.333334 /* binary -> octal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     if (tmp_length < precision)
-                       tmp_length = precision;
-                     /* Add 1, to account for a leading sign.  */
-                     tmp_length = xsum (tmp_length, 1);
-                     break;
-
-                   case 'x': case 'X':
-# if HAVE_LONG_LONG_INT
-                     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 */
-                     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 */
-                     else
-                       tmp_length =
-                         (unsigned int) (sizeof (unsigned int) * CHAR_BIT
-                                         * 0.25 /* binary -> hexadecimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     if (tmp_length < precision)
-                       tmp_length = precision;
-                     /* Add 2, to account for a leading sign or alternate form.  */
-                     tmp_length = xsum (tmp_length, 2);
-                     break;
-
-                   case 'f': case 'F':
-                     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 */
-                         + 10; /* sign, decimal point etc. */
-                     else
-                       tmp_length =
-                         (unsigned int) (DBL_MAX_EXP
-                                         * 0.30103 /* binary -> decimal */
-                                         * 2 /* estimate for FLAG_GROUP */
-                                        )
-                         + 1 /* turn floor into ceil */
-                         + 10; /* sign, decimal point etc. */
-                     tmp_length = xsum (tmp_length, precision);
-                     break;
-
-                   case 'e': case 'E': case 'g': case 'G':
-                     tmp_length =
-                       12; /* sign, decimal point, exponent etc. */
-                     tmp_length = xsum (tmp_length, precision);
-                     break;
-
-                   case 'a': case 'A':
-                     if (type == TYPE_LONGDOUBLE)
-                       tmp_length =
-                         (unsigned int) (LDBL_DIG
-                                         * 0.831 /* decimal -> hexadecimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     else
-                       tmp_length =
-                         (unsigned int) (DBL_DIG
-                                         * 0.831 /* decimal -> hexadecimal */
-                                        )
-                         + 1; /* turn floor into ceil */
-                     if (tmp_length < precision)
-                       tmp_length = precision;
-                     /* Account for sign, decimal point etc. */
-                     tmp_length = xsum (tmp_length, 12);
-                     break;
-
-                   case 'c':
-# if HAVE_WINT_T && !WIDE_CHAR_VERSION
-                     if (type == TYPE_WIDE_CHAR)
-                       tmp_length = MB_CUR_MAX;
-                     else
-# endif
-                       tmp_length = 1;
-                     break;
-
-                   case 's':
-# if HAVE_WCHAR_T
-                     if (type == TYPE_WIDE_STRING)
-                       {
-                         tmp_length =
-                           local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
-
-#  if !WIDE_CHAR_VERSION
-                         tmp_length = xtimes (tmp_length, MB_CUR_MAX);
-#  endif
-                       }
-                     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 ENABLE_UNISTDIO
-                 /* Padding considers the number of characters, therefore the
-                    number of elements after padding may be
-                      > max (tmp_length, width)
-                    but is certainly
-                      <= tmp_length + width.  */
-                 tmp_length = xsum (tmp_length, width);
-# else
-                 /* Padding considers the number of elements, says POSIX.  */
-                 if (tmp_length < width)
-                   tmp_length = width;
-# endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+                has_precision = 0;
+                precision = 6;
+                if (dp->precision_start != dp->precision_end)
+                  {
+                    if (dp->precision_arg_index != ARG_NONE)
+                      {
+                        int arg;
+
+                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                          abort ();
+                        arg = a.arg[dp->precision_arg_index].a.a_int;
+                        /* "A negative precision is taken as if the precision
+                            were omitted."  */
+                        if (arg >= 0)
+                          {
+                            precision = arg;
+                            has_precision = 1;
+                          }
+                      }
+                    else
+                      {
+                        const FCHAR_T *digitp = dp->precision_start + 1;
+
+                        precision = 0;
+                        while (digitp != dp->precision_end)
+                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+                        has_precision = 1;
+                      }
+                  }
+#endif
 
 
-                 tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
-               }
-
-               if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T))
-                 tmp = tmpbuf;
-               else
-                 {
-                   size_t tmp_memsize = xtimes (tmp_length, sizeof (TCHAR_T));
-
-                   if (size_overflow_p (tmp_memsize))
-                     /* Overflow, would lead to out of memory.  */
-                     goto out_of_memory;
-                   tmp = (TCHAR_T *) malloc (tmp_memsize);
-                   if (tmp == NULL)
-                     /* Out of memory.  */
-                     goto out_of_memory;
-                 }
+                /* Decide whether to handle the precision ourselves.  */
+#if NEED_PRINTF_UNBOUNDED_PRECISION
+                switch (dp->conversion)
+                  {
+                  case 'd': case 'i': case 'u':
+                  case 'o':
+                  case 'x': case 'X': case 'p':
+                    prec_ourselves = has_precision && (precision > 0);
+                    break;
+                  default:
+                    prec_ourselves = 0;
+                    break;
+                  }
 #endif
 
 #endif
 
-               /* Decide whether to perform the padding ourselves.  */
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
-               switch (dp->conversion)
-                 {
+                /* Decide whether to perform the padding ourselves.  */
+#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
+                switch (dp->conversion)
+                  {
 # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
 # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
-                 /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
-                    to perform the padding after this conversion.  Functions
-                    with unistdio extensions perform the padding based on
-                    character count rather than element count.  */
-                 case 'c': case 's':
+                  /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
+                     to perform the padding after this conversion.  Functions
+                     with unistdio extensions perform the padding based on
+                     character count rather than element count.  */
+                  case 'c': case 's':
 # endif
 # if NEED_PRINTF_FLAG_ZERO
 # endif
 # if NEED_PRINTF_FLAG_ZERO
-                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
-                 case 'a': case 'A':
+                  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+                  case 'a': case 'A':
 # endif
 # endif
-                   pad_ourselves = 1;
-                   break;
-                 default:
-                   pad_ourselves = 0;
-                   break;
-                 }
+                    pad_ourselves = 1;
+                    break;
+                  default:
+                    pad_ourselves = prec_ourselves;
+                    break;
+                  }
+#endif
+
+#if !USE_SNPRINTF
+                /* Allocate a temporary buffer of sufficient size for calling
+                   sprintf.  */
+                tmp_length =
+                  MAX_ROOM_NEEDED (&a, dp->arg_index, dp->conversion, type,
+                                   flags, width, has_precision, precision,
+                                   pad_ourselves);
+
+                if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T))
+                  tmp = tmpbuf;
+                else
+                  {
+                    size_t tmp_memsize = xtimes (tmp_length, sizeof (TCHAR_T));
+
+                    if (size_overflow_p (tmp_memsize))
+                      /* Overflow, would lead to out of memory.  */
+                      goto out_of_memory;
+                    tmp = (TCHAR_T *) malloc (tmp_memsize);
+                    if (tmp == NULL)
+                      /* Out of memory.  */
+                      goto out_of_memory;
+                  }
 #endif
 
 #endif
 
-               /* Construct the format string for calling snprintf or
-                  sprintf.  */
-               fbp = buf;
-               *fbp++ = '%';
+                /* Construct the format string for calling snprintf or
+                   sprintf.  */
+                fbp = buf;
+                *fbp++ = '%';
 #if NEED_PRINTF_FLAG_GROUPING
 #if NEED_PRINTF_FLAG_GROUPING
-               /* The underlying implementation doesn't support the ' flag.
-                  Produce no grouping characters in this case; this is
-                  acceptable because the grouping is locale dependent.  */
+                /* The underlying implementation doesn't support the ' flag.
+                   Produce no grouping characters in this case; this is
+                   acceptable because the grouping is locale dependent.  */
 #else
 #else
-               if (flags & FLAG_GROUP)
-                 *fbp++ = '\'';
+                if (flags & FLAG_GROUP)
+                  *fbp++ = '\'';
 #endif
 #endif
-               if (flags & FLAG_LEFT)
-                 *fbp++ = '-';
-               if (flags & FLAG_SHOWSIGN)
-                 *fbp++ = '+';
-               if (flags & FLAG_SPACE)
-                 *fbp++ = ' ';
-               if (flags & FLAG_ALT)
-                 *fbp++ = '#';
-               if (!pad_ourselves)
-                 {
-                   if (flags & FLAG_ZERO)
-                     *fbp++ = '0';
-                   if (dp->width_start != dp->width_end)
-                     {
-                       size_t n = dp->width_end - dp->width_start;
-                       /* The width specification is known to consist only
-                          of standard ASCII characters.  */
-                       if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
-                         {
-                           memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T));
-                           fbp += n;
-                         }
-                       else
-                         {
-                           const FCHAR_T *mp = dp->width_start;
-                           do
-                             *fbp++ = (unsigned char) *mp++;
-                           while (--n > 0);
-                         }
-                     }
-                 }
-               if (dp->precision_start != dp->precision_end)
-                 {
-                   size_t n = dp->precision_end - dp->precision_start;
-                   /* The precision specification is known to consist only
-                      of standard ASCII characters.  */
-                   if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
-                     {
-                       memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T));
-                       fbp += n;
-                     }
-                   else
-                     {
-                       const FCHAR_T *mp = dp->precision_start;
-                       do
-                         *fbp++ = (unsigned char) *mp++;
-                       while (--n > 0);
-                     }
-                 }
-
-               switch (type)
-                 {
+                if (flags & FLAG_LEFT)
+                  *fbp++ = '-';
+                if (flags & FLAG_SHOWSIGN)
+                  *fbp++ = '+';
+                if (flags & FLAG_SPACE)
+                  *fbp++ = ' ';
+                if (flags & FLAG_ALT)
+                  *fbp++ = '#';
+                if (!pad_ourselves)
+                  {
+                    if (flags & FLAG_ZERO)
+                      *fbp++ = '0';
+                    if (dp->width_start != dp->width_end)
+                      {
+                        size_t n = dp->width_end - dp->width_start;
+                        /* The width specification is known to consist only
+                           of standard ASCII characters.  */
+                        if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
+                          {
+                            memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T));
+                            fbp += n;
+                          }
+                        else
+                          {
+                            const FCHAR_T *mp = dp->width_start;
+                            do
+                              *fbp++ = (unsigned char) *mp++;
+                            while (--n > 0);
+                          }
+                      }
+                  }
+                if (!prec_ourselves)
+                  {
+                    if (dp->precision_start != dp->precision_end)
+                      {
+                        size_t n = dp->precision_end - dp->precision_start;
+                        /* The precision specification is known to consist only
+                           of standard ASCII characters.  */
+                        if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
+                          {
+                            memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T));
+                            fbp += n;
+                          }
+                        else
+                          {
+                            const FCHAR_T *mp = dp->precision_start;
+                            do
+                              *fbp++ = (unsigned char) *mp++;
+                            while (--n > 0);
+                          }
+                      }
+                  }
+
+                switch (type)
+                  {
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                 case TYPE_LONGLONGINT:
-                 case TYPE_ULONGLONGINT:
+                  case TYPE_LONGLONGINT:
+                  case TYPE_ULONGLONGINT:
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-                   *fbp++ = 'I';
-                   *fbp++ = '6';
-                   *fbp++ = '4';
-                   break;
+                    *fbp++ = 'I';
+                    *fbp++ = '6';
+                    *fbp++ = '4';
+                    break;
 # else
 # else
-                   *fbp++ = 'l';
-                   /*FALLTHROUGH*/
+                    *fbp++ = 'l';
+                    /*FALLTHROUGH*/
 # endif
 #endif
 # endif
 #endif
-                 case TYPE_LONGINT:
-                 case TYPE_ULONGINT:
+                  case TYPE_LONGINT:
+                  case TYPE_ULONGINT:
 #if HAVE_WINT_T
 #if HAVE_WINT_T
-                 case TYPE_WIDE_CHAR:
+                  case TYPE_WIDE_CHAR:
 #endif
 #if HAVE_WCHAR_T
 #endif
 #if HAVE_WCHAR_T
-                 case TYPE_WIDE_STRING:
+                  case TYPE_WIDE_STRING:
 #endif
 #endif
-                   *fbp++ = 'l';
-                   break;
-                 case TYPE_LONGDOUBLE:
-                   *fbp++ = 'L';
-                   break;
-                 default:
-                   break;
-                 }
+                    *fbp++ = 'l';
+                    break;
+                  case TYPE_LONGDOUBLE:
+                    *fbp++ = 'L';
+                    break;
+                  default:
+                    break;
+                  }
 #if NEED_PRINTF_DIRECTIVE_F
 #if NEED_PRINTF_DIRECTIVE_F
-               if (dp->conversion == 'F')
-                 *fbp = 'f';
-               else
+                if (dp->conversion == 'F')
+                  *fbp = 'f';
+                else
 #endif
 #endif
-                 *fbp = dp->conversion;
+                  *fbp = dp->conversion;
 #if USE_SNPRINTF
 #if USE_SNPRINTF
-               fbp[1] = '%';
-               fbp[2] = 'n';
-               fbp[3] = '\0';
+# if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
+                fbp[1] = '%';
+                fbp[2] = 'n';
+                fbp[3] = '\0';
+# else
+                /* On glibc2 systems from glibc >= 2.3 - probably also older
+                   ones - we know that snprintf's returns value conforms to
+                   ISO C 99: the gl_SNPRINTF_DIRECTIVE_N test passes.
+                   Therefore we can avoid using %n in this situation.
+                   On glibc2 systems from 2004-10-18 or newer, the use of %n
+                   in format strings in writable memory may crash the program
+                   (if compiled with _FORTIFY_SOURCE=2), so we should avoid it
+                   in this situation.  */
+                /* On native Win32 systems (such as mingw), we can avoid using
+                   %n because:
+                     - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
+                       snprintf does not write more than the specified number
+                       of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
+                       '4', '5', '6' into buf, not '4', '5', '\0'.)
+                     - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
+                       allows us to recognize the case of an insufficient
+                       buffer size: it returns -1 in this case.
+                   On native Win32 systems (such as mingw) where the OS is
+                   Windows Vista, the use of %n in format strings by default
+                   crashes the program. See
+                     <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+                     <http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx>
+                   So we should avoid %n in this situation.  */
+                fbp[1] = '\0';
+# endif
 #else
 #else
-               fbp[1] = '\0';
+                fbp[1] = '\0';
 #endif
 
 #endif
 
-               /* Construct the arguments for calling snprintf or sprintf.  */
-               prefix_count = 0;
-               if (!pad_ourselves && dp->width_arg_index != ARG_NONE)
-                 {
-                   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 != ARG_NONE)
-                 {
-                   if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
-                     abort ();
-                   prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
-                 }
+                /* Construct the arguments for calling snprintf or sprintf.  */
+                prefix_count = 0;
+                if (!pad_ourselves && dp->width_arg_index != ARG_NONE)
+                  {
+                    if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                      abort ();
+                    prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
+                  }
+                if (!prec_ourselves && dp->precision_arg_index != ARG_NONE)
+                  {
+                    if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                      abort ();
+                    prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
+                  }
 
 #if USE_SNPRINTF
 
 #if USE_SNPRINTF
-               /* The SNPRINTF result is appended after result[0..length].
-                  The latter is an array of DCHAR_T; SNPRINTF appends an
-                  array of TCHAR_T to it.  This is possible because
-                  sizeof (TCHAR_T) divides sizeof (DCHAR_T) and
-                  alignof (TCHAR_T) <= alignof (DCHAR_T).  */
+                /* The SNPRINTF result is appended after result[0..length].
+                   The latter is an array of DCHAR_T; SNPRINTF appends an
+                   array of TCHAR_T to it.  This is possible because
+                   sizeof (TCHAR_T) divides sizeof (DCHAR_T) and
+                   alignof (TCHAR_T) <= alignof (DCHAR_T).  */
 # define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T))
 # define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T))
-               /* Prepare checking whether snprintf returns the count
-                  via %n.  */
-               ENSURE_ALLOCATION (xsum (length, 1));
-               *(TCHAR_T *) (result + length) = '\0';
+                /* Ensure that maxlen below will be >= 2.  Needed on BeOS,
+                   where an snprintf() with maxlen==1 acts like sprintf().  */
+                ENSURE_ALLOCATION (xsum (length,
+                                         (2 + TCHARS_PER_DCHAR - 1)
+                                         / TCHARS_PER_DCHAR));
+                /* Prepare checking whether snprintf returns the count
+                   via %n.  */
+                *(TCHAR_T *) (result + length) = '\0';
 #endif
 
 #endif
 
-               for (;;)
-                 {
-                   int count = -1;
+                for (;;)
+                  {
+                    int count = -1;
 
 #if USE_SNPRINTF
 
 #if USE_SNPRINTF
-                   int retcount = 0;
-                   size_t maxlen = allocated - length;
-                   /* SNPRINTF can fail if its second argument is
-                      > INT_MAX.  */
-                   if (maxlen > INT_MAX / TCHARS_PER_DCHAR)
-                     goto overflow;
-                   maxlen = maxlen * TCHARS_PER_DCHAR;
+                    int retcount = 0;
+                    size_t maxlen = allocated - length;
+                    /* SNPRINTF can fail if its second argument is
+                       > INT_MAX.  */
+                    if (maxlen > INT_MAX / TCHARS_PER_DCHAR)
+                      maxlen = INT_MAX / TCHARS_PER_DCHAR;
+                    maxlen = maxlen * TCHARS_PER_DCHAR;
 # define SNPRINTF_BUF(arg) \
 # define SNPRINTF_BUF(arg) \
-                   switch (prefix_count)                                   \
-                     {                                                     \
-                     case 0:                                               \
-                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
-                                            maxlen, buf,                   \
-                                            arg, &count);                  \
-                       break;                                              \
-                     case 1:                                               \
-                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
-                                            maxlen, buf,                   \
-                                            prefixes[0], arg, &count);     \
-                       break;                                              \
-                     case 2:                                               \
-                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
-                                            maxlen, buf,                   \
-                                            prefixes[0], prefixes[1], arg, \
-                                            &count);                       \
-                       break;                                              \
-                     default:                                              \
-                       abort ();                                           \
-                     }
+                    switch (prefix_count)                                   \
+                      {                                                     \
+                      case 0:                                               \
+                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \
+                                             maxlen, buf,                   \
+                                             arg, &count);                  \
+                        break;                                              \
+                      case 1:                                               \
+                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \
+                                             maxlen, buf,                   \
+                                             prefixes[0], arg, &count);     \
+                        break;                                              \
+                      case 2:                                               \
+                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \
+                                             maxlen, buf,                   \
+                                             prefixes[0], prefixes[1], arg, \
+                                             &count);                       \
+                        break;                                              \
+                      default:                                              \
+                        abort ();                                           \
+                      }
 #else
 # define SNPRINTF_BUF(arg) \
 #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 ();                                           \
-                     }
+                    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
 
 #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;
+                    errno = 0;
+                    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;
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                     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;
+                      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
 #endif
-                     case TYPE_DOUBLE:
-                       {
-                         double arg = a.arg[dp->arg_index].a.a_double;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
-                     case TYPE_LONGDOUBLE:
-                       {
-                         long double arg = a.arg[dp->arg_index].a.a_longdouble;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
-                     case TYPE_CHAR:
-                       {
-                         int arg = a.arg[dp->arg_index].a.a_char;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
+                      case TYPE_DOUBLE:
+                        {
+                          double arg = a.arg[dp->arg_index].a.a_double;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
+                      case TYPE_LONGDOUBLE:
+                        {
+                          long double arg = a.arg[dp->arg_index].a.a_longdouble;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
+                      case TYPE_CHAR:
+                        {
+                          int arg = a.arg[dp->arg_index].a.a_char;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
 #if HAVE_WINT_T
 #if HAVE_WINT_T
-                     case TYPE_WIDE_CHAR:
-                       {
-                         wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
+                      case TYPE_WIDE_CHAR:
+                        {
+                          wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
 #endif
 #endif
-                     case TYPE_STRING:
-                       {
-                         const char *arg = a.arg[dp->arg_index].a.a_string;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
+                      case TYPE_STRING:
+                        {
+                          const char *arg = a.arg[dp->arg_index].a.a_string;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
 #if HAVE_WCHAR_T
 #if HAVE_WCHAR_T
-                     case TYPE_WIDE_STRING:
-                       {
-                         const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
+                      case TYPE_WIDE_STRING:
+                        {
+                          const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
 #endif
 #endif
-                     case TYPE_POINTER:
-                       {
-                         void *arg = a.arg[dp->arg_index].a.a_pointer;
-                         SNPRINTF_BUF (arg);
-                       }
-                       break;
-                     default:
-                       abort ();
-                     }
+                      case TYPE_POINTER:
+                        {
+                          void *arg = a.arg[dp->arg_index].a.a_pointer;
+                          SNPRINTF_BUF (arg);
+                        }
+                        break;
+                      default:
+                        abort ();
+                      }
 
 #if USE_SNPRINTF
 
 #if USE_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
-                           && ((TCHAR_T *) (result + length)) [count] != '\0')
-                         abort ();
-                       /* Portability hack.  */
-                       if (retcount > count)
-                         count = retcount;
-                     }
-                   else
-                     {
-                       /* snprintf() doesn't understand the '%n'
-                          directive.  */
-                       if (fbp[1] != '\0')
-                         {
-                           /* Don't use the '%n' directive; instead, look
-                              at the snprintf() return value.  */
-                           fbp[1] = '\0';
-                           continue;
-                         }
-                       else
-                         {
-                           /* Look at the snprintf() return value.  */
-                           if (retcount < 0)
-                             {
-                               /* HP-UX 10.20 snprintf() is doubly deficient:
-                                  It doesn't understand the '%n' directive,
-                                  *and* it returns -1 (rather than the length
-                                  that would have been required) when the
-                                  buffer is too small.  */
-                               size_t bigger_need =
-                                 xsum (xtimes (allocated, 2), 12);
-                               ENSURE_ALLOCATION (bigger_need);
-                               continue;
-                             }
-                           else
-                             count = retcount;
-                         }
-                     }
+                    /* 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
+                            && ((TCHAR_T *) (result + length)) [count] != '\0')
+                          abort ();
+                        /* Portability hack.  */
+                        if (retcount > count)
+                          count = retcount;
+                      }
+                    else
+                      {
+                        /* snprintf() doesn't understand the '%n'
+                           directive.  */
+                        if (fbp[1] != '\0')
+                          {
+                            /* Don't use the '%n' directive; instead, look
+                               at the snprintf() return value.  */
+                            fbp[1] = '\0';
+                            continue;
+                          }
+                        else
+                          {
+                            /* Look at the snprintf() return value.  */
+                            if (retcount < 0)
+                              {
+# if !HAVE_SNPRINTF_RETVAL_C99
+                                /* HP-UX 10.20 snprintf() is doubly deficient:
+                                   It doesn't understand the '%n' directive,
+                                   *and* it returns -1 (rather than the length
+                                   that would have been required) when the
+                                   buffer is too small.
+                                   But a failure at this point can also come
+                                   from other reasons than a too small buffer,
+                                   such as an invalid wide string argument to
+                                   the %ls directive, or possibly an invalid
+                                   floating-point argument.  */
+                                size_t tmp_length =
+                                  MAX_ROOM_NEEDED (&a, dp->arg_index,
+                                                   dp->conversion, type, flags,
+                                                   width, has_precision,
+                                                   precision, pad_ourselves);
+
+                                if (maxlen < tmp_length)
+                                  {
+                                    /* Make more room.  But try to do through
+                                       this reallocation only once.  */
+                                    size_t bigger_need =
+                                      xsum (length,
+                                            xsum (tmp_length,
+                                                  TCHARS_PER_DCHAR - 1)
+                                            / TCHARS_PER_DCHAR);
+                                    /* And always grow proportionally.
+                                       (There may be several arguments, each
+                                       needing a little more room than the
+                                       previous one.)  */
+                                    size_t bigger_need2 =
+                                      xsum (xtimes (allocated, 2), 12);
+                                    if (bigger_need < bigger_need2)
+                                      bigger_need = bigger_need2;
+                                    ENSURE_ALLOCATION (bigger_need);
+                                    continue;
+                                  }
+# endif
+                              }
+                            else
+                              count = retcount;
+                          }
+                      }
 #endif
 
 #endif
 
-                   /* Attempt to handle failure.  */
-                   if (count < 0)
-                     {
-                       if (!(result == resultbuf || result == NULL))
-                         free (result);
-                       if (buf_malloced != NULL)
-                         free (buf_malloced);
-                       CLEANUP ();
-                       errno = EINVAL;
-                       return NULL;
-                     }
+                    /* Attempt to handle failure.  */
+                    if (count < 0)
+                      {
+                        /* SNPRINTF or sprintf failed.  Save and use the errno
+                           that it has set, if any.  */
+                        int saved_errno = errno;
+
+                        if (!(result == resultbuf || result == NULL))
+                          free (result);
+                        if (buf_malloced != NULL)
+                          free (buf_malloced);
+                        CLEANUP ();
+                        errno =
+                          (saved_errno != 0
+                           ? saved_errno
+                           : (dp->conversion == 'c' || dp->conversion == 's'
+                              ? EILSEQ
+                              : EINVAL));
+                        return NULL;
+                      }
 
 #if USE_SNPRINTF
 
 #if USE_SNPRINTF
-                   /* Handle overflow of the allocated buffer.  */
-                   if (count >= maxlen)
-                     {
-                       /* Need at least count * sizeof (TCHAR_T) bytes.  But
-                          allocate proportionally, to avoid looping eternally
-                          if snprintf() reports a too small count.  */
-                       size_t n =
-                         xmax (xsum (length,
-                                     (count + TCHARS_PER_DCHAR - 1)
-                                     / TCHARS_PER_DCHAR),
-                               xtimes (allocated, 2));
-
-                       ENSURE_ALLOCATION (n);
-                       continue;
-                     }
+                    /* Handle overflow of the allocated buffer.
+                       If such an overflow occurs, a C99 compliant snprintf()
+                       returns a count >= maxlen.  However, a non-compliant
+                       snprintf() function returns only count = maxlen - 1.  To
+                       cover both cases, test whether count >= maxlen - 1.  */
+                    if ((unsigned int) count + 1 >= maxlen)
+                      {
+                        /* If maxlen already has attained its allowed maximum,
+                           allocating more memory will not increase maxlen.
+                           Instead of looping, bail out.  */
+                        if (maxlen == INT_MAX / TCHARS_PER_DCHAR)
+                          goto overflow;
+                        else
+                          {
+                            /* Need at least (count + 1) * sizeof (TCHAR_T)
+                               bytes.  (The +1 is for the trailing NUL.)
+                               But ask for (count + 2) * sizeof (TCHAR_T)
+                               bytes, so that in the next round, we likely get
+                                 maxlen > (unsigned int) count + 1
+                               and so we don't get here again.
+                               And allocate proportionally, to avoid looping
+                               eternally if snprintf() reports a too small
+                               count.  */
+                            size_t n =
+                              xmax (xsum (length,
+                                          ((unsigned int) count + 2
+                                           + TCHARS_PER_DCHAR - 1)
+                                          / TCHARS_PER_DCHAR),
+                                    xtimes (allocated, 2));
+
+                            ENSURE_ALLOCATION (n);
+                            continue;
+                          }
+                      }
 #endif
 
 #endif
 
-#if !DCHAR_IS_TCHAR
-# if !USE_SNPRINTF
-                   if (count >= tmp_length)
-                     /* tmp_length was incorrectly calculated - fix the
-                        code above!  */
-                     abort ();
+#if NEED_PRINTF_UNBOUNDED_PRECISION
+                    if (prec_ourselves)
+                      {
+                        /* Handle the precision.  */
+                        TCHAR_T *prec_ptr =
+# if USE_SNPRINTF
+                          (TCHAR_T *) (result + length);
+# else
+                          tmp;
 # endif
 # endif
+                        size_t prefix_count;
+                        size_t move;
+
+                        prefix_count = 0;
+                        /* Put the additional zeroes after the sign.  */
+                        if (count >= 1
+                            && (*prec_ptr == '-' || *prec_ptr == '+'
+                                || *prec_ptr == ' '))
+                          prefix_count = 1;
+                        /* Put the additional zeroes after the 0x prefix if
+                           (flags & FLAG_ALT) || (dp->conversion == 'p').  */
+                        else if (count >= 2
+                                 && prec_ptr[0] == '0'
+                                 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X'))
+                          prefix_count = 2;
+
+                        move = count - prefix_count;
+                        if (precision > move)
+                          {
+                            /* Insert zeroes.  */
+                            size_t insert = precision - move;
+                            TCHAR_T *prec_end;
 
 
-                   /* Convert from TCHAR_T[] to DCHAR_T[].  */
-                   if (dp->conversion == 'c' || dp->conversion == 's')
-                     {
-                       /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
-                          TYPE_WIDE_STRING.
-                          The result string is not certainly ASCII.  */
-                       const TCHAR_T *tmpsrc;
-                       DCHAR_T *tmpdst;
-                       size_t tmpdst_len;
-                       /* This code assumes that TCHAR_T is 'char'.  */
-                       typedef int TCHAR_T_verify
-                                   [2 * (sizeof (TCHAR_T) == 1) - 1];
 # if USE_SNPRINTF
 # if USE_SNPRINTF
-                       tmpsrc = (TCHAR_T *) (result + length);
+                            size_t n =
+                              xsum (length,
+                                    (count + insert + TCHARS_PER_DCHAR - 1)
+                                    / TCHARS_PER_DCHAR);
+                            length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+                            ENSURE_ALLOCATION (n);
+                            length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR;
+                            prec_ptr = (TCHAR_T *) (result + length);
+# endif
+
+                            prec_end = prec_ptr + count;
+                            prec_ptr += prefix_count;
+
+                            while (prec_end > prec_ptr)
+                              {
+                                prec_end--;
+                                prec_end[insert] = prec_end[0];
+                              }
+
+                            prec_end += insert;
+                            do
+                              *--prec_end = '0';
+                            while (prec_end > prec_ptr);
+
+                            count += insert;
+                          }
+                      }
+#endif
+
+#if !USE_SNPRINTF
+                    if (count >= tmp_length)
+                      /* tmp_length was incorrectly calculated - fix the
+                         code above!  */
+                      abort ();
+#endif
+
+#if !DCHAR_IS_TCHAR
+                    /* Convert from TCHAR_T[] to DCHAR_T[].  */
+                    if (dp->conversion == 'c' || dp->conversion == 's')
+                      {
+                        /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
+                           TYPE_WIDE_STRING.
+                           The result string is not certainly ASCII.  */
+                        const TCHAR_T *tmpsrc;
+                        DCHAR_T *tmpdst;
+                        size_t tmpdst_len;
+                        /* This code assumes that TCHAR_T is 'char'.  */
+                        typedef int TCHAR_T_verify
+                                    [2 * (sizeof (TCHAR_T) == 1) - 1];
+# if USE_SNPRINTF
+                        tmpsrc = (TCHAR_T *) (result + length);
 # else
 # else
-                       tmpsrc = tmp;
+                        tmpsrc = tmp;
 # endif
 # endif
-                       tmpdst = NULL;
-                       tmpdst_len = 0;
-                       if (DCHAR_CONV_FROM_ENCODING (locale_charset (),
-                                                     iconveh_question_mark,
-                                                     tmpsrc, count,
-                                                     NULL,
-                                                     &tmpdst, &tmpdst_len)
-                           < 0)
-                         {
-                           int saved_errno = errno;
-                           if (!(result == resultbuf || result == NULL))
-                             free (result);
-                           if (buf_malloced != NULL)
-                             free (buf_malloced);
-                           CLEANUP ();
-                           errno = saved_errno;
-                           return NULL;
-                         }
-                       ENSURE_ALLOCATION (xsum (length, tmpdst_len));
-                       DCHAR_CPY (result + length, tmpdst, tmpdst_len);
-                       free (tmpdst);
-                       count = tmpdst_len;
-                     }
-                   else
-                     {
-                       /* The result string is ASCII.
-                          Simple 1:1 conversion.  */
+                        tmpdst =
+                          DCHAR_CONV_FROM_ENCODING (locale_charset (),
+                                                    iconveh_question_mark,
+                                                    tmpsrc, count,
+                                                    NULL,
+                                                    NULL, &tmpdst_len);
+                        if (tmpdst == NULL)
+                          {
+                            int saved_errno = errno;
+                            if (!(result == resultbuf || result == NULL))
+                              free (result);
+                            if (buf_malloced != NULL)
+                              free (buf_malloced);
+                            CLEANUP ();
+                            errno = saved_errno;
+                            return NULL;
+                          }
+                        ENSURE_ALLOCATION (xsum (length, tmpdst_len));
+                        DCHAR_CPY (result + length, tmpdst, tmpdst_len);
+                        free (tmpdst);
+                        count = tmpdst_len;
+                      }
+                    else
+                      {
+                        /* The result string is ASCII.
+                           Simple 1:1 conversion.  */
 # if USE_SNPRINTF
 # if USE_SNPRINTF
-                       /* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a
-                          no-op conversion, in-place on the array starting
-                          at (result + length).  */
-                       if (sizeof (DCHAR_T) != sizeof (TCHAR_T))
+                        /* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a
+                           no-op conversion, in-place on the array starting
+                           at (result + length).  */
+                        if (sizeof (DCHAR_T) != sizeof (TCHAR_T))
 # endif
 # endif
-                         {
-                           const TCHAR_T *tmpsrc;
-                           DCHAR_T *tmpdst;
-                           size_t n;
+                          {
+                            const TCHAR_T *tmpsrc;
+                            DCHAR_T *tmpdst;
+                            size_t n;
 
 # if USE_SNPRINTF
 
 # if USE_SNPRINTF
-                           if (result == resultbuf)
-                             {
-                               tmpsrc = (TCHAR_T *) (result + length);
-                               /* ENSURE_ALLOCATION will not move tmpsrc
-                                  (because it's part of resultbuf).  */
-                               ENSURE_ALLOCATION (xsum (length, count));
-                             }
-                           else
-                             {
-                               /* ENSURE_ALLOCATION will move the array
-                                  (because it uses realloc().  */
-                               ENSURE_ALLOCATION (xsum (length, count));
-                               tmpsrc = (TCHAR_T *) (result + length);
-                             }
+                            if (result == resultbuf)
+                              {
+                                tmpsrc = (TCHAR_T *) (result + length);
+                                /* ENSURE_ALLOCATION will not move tmpsrc
+                                   (because it's part of resultbuf).  */
+                                ENSURE_ALLOCATION (xsum (length, count));
+                              }
+                            else
+                              {
+                                /* ENSURE_ALLOCATION will move the array
+                                   (because it uses realloc().  */
+                                ENSURE_ALLOCATION (xsum (length, count));
+                                tmpsrc = (TCHAR_T *) (result + length);
+                              }
 # else
 # else
-                           tmpsrc = tmp;
-                           ENSURE_ALLOCATION (xsum (length, count));
+                            tmpsrc = tmp;
+                            ENSURE_ALLOCATION (xsum (length, count));
 # endif
 # endif
-                           tmpdst = result + length;
-                           /* Copy backwards, because of overlapping.  */
-                           tmpsrc += count;
-                           tmpdst += count;
-                           for (n = count; n > 0; n--)
-                             *--tmpdst = (unsigned char) *--tmpsrc;
-                         }
-                     }
+                            tmpdst = result + length;
+                            /* Copy backwards, because of overlapping.  */
+                            tmpsrc += count;
+                            tmpdst += count;
+                            for (n = count; n > 0; n--)
+                              *--tmpdst = (unsigned char) *--tmpsrc;
+                          }
+                      }
 #endif
 
 #if DCHAR_IS_TCHAR && !USE_SNPRINTF
 #endif
 
 #if DCHAR_IS_TCHAR && !USE_SNPRINTF
-                   /* Make room for the result.  */
-                   if (count > allocated - length)
-                     {
-                       /* Need at least count elements.  But allocate
-                          proportionally.  */
-                       size_t n =
-                         xmax (xsum (length, count), xtimes (allocated, 2));
-
-                       ENSURE_ALLOCATION (n);
-                     }
+                    /* Make room for the result.  */
+                    if (count > allocated - length)
+                      {
+                        /* Need at least count elements.  But allocate
+                           proportionally.  */
+                        size_t n =
+                          xmax (xsum (length, count), xtimes (allocated, 2));
+
+                        ENSURE_ALLOCATION (n);
+                      }
 #endif
 
 #endif
 
-                   /* Here count <= allocated - length.  */
+                    /* Here count <= allocated - length.  */
 
 
-                   /* Perform padding.  */
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
-                   if (pad_ourselves && has_width)
-                     {
-                       size_t w;
+                    /* Perform padding.  */
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+                    if (pad_ourselves && has_width)
+                      {
+                        size_t w;
 # if ENABLE_UNISTDIO
 # if ENABLE_UNISTDIO
-                       /* Outside POSIX, it's preferrable to compare the width
-                          against the number of _characters_ of the converted
-                          value.  */
-                       w = DCHAR_MBSNLEN (result + length, count);
+                        /* Outside POSIX, it's preferrable to compare the width
+                           against the number of _characters_ of the converted
+                           value.  */
+                        w = DCHAR_MBSNLEN (result + length, count);
 # else
 # else
-                       /* The width is compared against the number of _bytes_
-                          of the converted value, says POSIX.  */
-                       w = count;
+                        /* The width is compared against the number of _bytes_
+                           of the converted value, says POSIX.  */
+                        w = count;
 # endif
 # endif
-                       if (w < width)
-                         {
-                           size_t pad = width - w;
+                        if (w < width)
+                          {
+                            size_t pad = width - w;
+
+                            /* Make room for the result.  */
+                            if (xsum (count, pad) > allocated - length)
+                              {
+                                /* Need at least count + pad elements.  But
+                                   allocate proportionally.  */
+                                size_t n =
+                                  xmax (xsum3 (length, count, pad),
+                                        xtimes (allocated, 2));
+
 # if USE_SNPRINTF
 # if USE_SNPRINTF
-                           /* Make room for the result.  */
-                           if (xsum (count, pad) > allocated - length)
-                             {
-                               /* Need at least count + pad elements.  But
-                                  allocate proportionally.  */
-                               size_t n =
-                                 xmax (xsum3 (length, count, pad),
-                                       xtimes (allocated, 2));
-
-                               length += count;
-                               ENSURE_ALLOCATION (n);
-                               length -= count;
-                             }
-                           /* Here count + pad <= allocated - length.  */
+                                length += count;
+                                ENSURE_ALLOCATION (n);
+                                length -= count;
+# else
+                                ENSURE_ALLOCATION (n);
 # endif
 # endif
-                           {
+                              }
+                            /* Here count + pad <= allocated - length.  */
+
+                            {
 # if !DCHAR_IS_TCHAR || USE_SNPRINTF
 # if !DCHAR_IS_TCHAR || USE_SNPRINTF
-                             DCHAR_T * const rp = result + length;
+                              DCHAR_T * const rp = result + length;
 # else
 # else
-                             DCHAR_T * const rp = tmp;
+                              DCHAR_T * const rp = tmp;
 # endif
 # endif
-                             DCHAR_T *p = rp + count;
-                             DCHAR_T *end = p + pad;
-# if NEED_PRINTF_FLAG_ZERO
-                             DCHAR_T *pad_ptr;
-#  if !DCHAR_IS_TCHAR
-                             if (dp->conversion == 'c'
-                                 || dp->conversion == 's')
-                               /* No zero-padding for string directives.  */
-                               pad_ptr = NULL;
-                             else
-#  endif
-                               {
-                                 pad_ptr = (*rp == '-' ? rp + 1 : rp);
-                                 /* No zero-padding of "inf" and "nan".  */
-                                 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
-                                     || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
-                                   pad_ptr = NULL;
-                               }
-# endif
-                             /* The generated string now extends from rp to p,
-                                with the zero padding insertion point being at
-                                pad_ptr.  */
-
-                             count = count + pad; /* = end - rp */
-
-                             if (flags & FLAG_LEFT)
-                               {
-                                 /* Pad with spaces on the right.  */
-                                 for (; pad > 0; pad--)
-                                   *p++ = ' ';
-                               }
-# if NEED_PRINTF_FLAG_ZERO
-                             else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
-                               {
-                                 /* Pad with zeroes.  */
-                                 DCHAR_T *q = end;
-
-                                 while (p > pad_ptr)
-                                   *--q = *--p;
-                                 for (; pad > 0; pad--)
-                                   *p++ = '0';
-                               }
+                              DCHAR_T *p = rp + count;
+                              DCHAR_T *end = p + pad;
+                              DCHAR_T *pad_ptr;
+# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
+                              if (dp->conversion == 'c'
+                                  || dp->conversion == 's')
+                                /* No zero-padding for string directives.  */
+                                pad_ptr = NULL;
+                              else
 # endif
 # endif
-                             else
-                               {
-                                 /* Pad with spaces on the left.  */
-                                 DCHAR_T *q = end;
-
-                                 while (p > rp)
-                                   *--q = *--p;
-                                 for (; pad > 0; pad--)
-                                   *p++ = ' ';
-                               }
-                           }
-                         }
-                     }
-#endif
-
-#if DCHAR_IS_TCHAR && !USE_SNPRINTF
-                   if (count >= tmp_length)
-                     /* tmp_length was incorrectly calculated - fix the
-                        code above!  */
-                     abort ();
+                                {
+                                  pad_ptr = (*rp == '-' ? rp + 1 : rp);
+                                  /* No zero-padding of "inf" and "nan".  */
+                                  if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
+                                      || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
+                                    pad_ptr = NULL;
+                                }
+                              /* The generated string now extends from rp to p,
+                                 with the zero padding insertion point being at
+                                 pad_ptr.  */
+
+                              count = count + pad; /* = end - rp */
+
+                              if (flags & FLAG_LEFT)
+                                {
+                                  /* Pad with spaces on the right.  */
+                                  for (; pad > 0; pad--)
+                                    *p++ = ' ';
+                                }
+                              else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
+                                {
+                                  /* Pad with zeroes.  */
+                                  DCHAR_T *q = end;
+
+                                  while (p > pad_ptr)
+                                    *--q = *--p;
+                                  for (; pad > 0; pad--)
+                                    *p++ = '0';
+                                }
+                              else
+                                {
+                                  /* Pad with spaces on the left.  */
+                                  DCHAR_T *q = end;
+
+                                  while (p > rp)
+                                    *--q = *--p;
+                                  for (; pad > 0; pad--)
+                                    *p++ = ' ';
+                                }
+                            }
+                          }
+                      }
 #endif
 
 #endif
 
-                   /* Here still count <= allocated - length.  */
+                    /* Here still count <= allocated - length.  */
 
 #if !DCHAR_IS_TCHAR || USE_SNPRINTF
 
 #if !DCHAR_IS_TCHAR || USE_SNPRINTF
-                   /* The snprintf() result did fit.  */
+                    /* The snprintf() result did fit.  */
 #else
 #else
-                   /* Append the sprintf() result.  */
-                   memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+                    /* Append the sprintf() result.  */
+                    memcpy (result + length, tmp, count * sizeof (DCHAR_T));
 #endif
 #if !USE_SNPRINTF
 #endif
 #if !USE_SNPRINTF
-                   if (tmp != tmpbuf)
-                     free (tmp);
+                    if (tmp != tmpbuf)
+                      free (tmp);
 #endif
 
 #if NEED_PRINTF_DIRECTIVE_F
 #endif
 
 #if NEED_PRINTF_DIRECTIVE_F
-                   if (dp->conversion == 'F')
-                     {
-                       /* Convert the %f result to upper case for %F.  */
-                       DCHAR_T *rp = result + length;
-                       size_t rc;
-                       for (rc = count; rc > 0; rc--, rp++)
-                         if (*rp >= 'a' && *rp <= 'z')
-                           *rp = *rp - 'a' + 'A';
-                     }
+                    if (dp->conversion == 'F')
+                      {
+                        /* Convert the %f result to upper case for %F.  */
+                        DCHAR_T *rp = result + length;
+                        size_t rc;
+                        for (rc = count; rc > 0; rc--, rp++)
+                          if (*rp >= 'a' && *rp <= 'z')
+                            *rp = *rp - 'a' + 'A';
+                      }
 #endif
 
 #endif
 
-                   length += count;
-                   break;
-                 }
-             }
-         }
+                    length += count;
+                    break;
+                  }
+#undef pad_ourselves
+#undef prec_ourselves
+              }
+          }
       }
 
     /* Add the final NUL.  */
       }
 
     /* Add the final NUL.  */
@@ -3915,12 +5510,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 
     if (result != resultbuf && length + 1 < allocated)
       {
 
     if (result != resultbuf && length + 1 < allocated)
       {
-       /* Shrink the allocated memory if possible.  */
-       DCHAR_T *memory;
+        /* Shrink the allocated memory if possible.  */
+        DCHAR_T *memory;
 
 
-       memory = (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T));
-       if (memory != NULL)
-         result = memory;
+        memory = (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T));
+        if (memory != NULL)
+          result = memory;
       }
 
     if (buf_malloced != NULL)
       }
 
     if (buf_malloced != NULL)
@@ -3933,6 +5528,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
        not have this limitation.  */
     return result;
 
        not have this limitation.  */
     return result;
 
+#if USE_SNPRINTF
   overflow:
     if (!(result == resultbuf || result == NULL))
       free (result);
   overflow:
     if (!(result == resultbuf || result == NULL))
       free (result);
@@ -3941,6 +5537,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
     CLEANUP ();
     errno = EOVERFLOW;
     return NULL;
     CLEANUP ();
     errno = EOVERFLOW;
     return NULL;
+#endif
 
   out_of_memory:
     if (!(result == resultbuf || result == NULL))
 
   out_of_memory:
     if (!(result == resultbuf || result == NULL))
@@ -3954,12 +5551,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
   }
 }
 
   }
 }
 
+#undef MAX_ROOM_NEEDED
 #undef TCHARS_PER_DCHAR
 #undef SNPRINTF
 #undef USE_SNPRINTF
 #undef TCHARS_PER_DCHAR
 #undef SNPRINTF
 #undef USE_SNPRINTF
+#undef DCHAR_SET
+#undef DCHAR_CPY
 #undef PRINTF_PARSE
 #undef DIRECTIVES
 #undef DIRECTIVE
 #undef PRINTF_PARSE
 #undef DIRECTIVES
 #undef DIRECTIVE
+#undef DCHAR_IS_TCHAR
 #undef TCHAR_T
 #undef DCHAR_T
 #undef FCHAR_T
 #undef TCHAR_T
 #undef DCHAR_T
 #undef FCHAR_T