delete trailing whitespace from control files
[debian/gzip] / lib / vasnprintf.c
index 3fbba53e2359f6f51cb703854c0273b92b2939bf..57571750a0b21a17b67122e764db3838d7bfb78e 100644 (file)
@@ -1,7 +1,5 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* vsprintf with automatic memory allocation.
-   Copyright (C) 1999, 2002-2010 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2002-2018 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
@@ -14,8 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   with this program; if not, see <https://www.gnu.org/licenses/>.  */
 
 /* This file can be parametrized with the following macros:
      VASNPRINTF         The name of the function being defined.
@@ -90,6 +87,8 @@
 /* Checked size_t computations.  */
 #include "xsize.h"
 
+#include "verify.h"
+
 #if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
 # include <math.h>
 # include "float+.h"
 # include "fpucw.h"
 #endif
 
+#ifndef FALLTHROUGH
+# if __GNUC__ < 7
+#  define FALLTHROUGH ((void) 0)
+# else
+#  define FALLTHROUGH __attribute__ ((__fallthrough__))
+# endif
+#endif
+
 /* Default parameters.  */
 #ifndef VASNPRINTF
 # if WIDE_CHAR_VERSION
 # 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
+#   define USE_MSVC__SNPRINTF 1
+#  endif
 # else
    /* Unix.  */
 #  define SNPRINTF swprintf
 #  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
+    /* MSVC versions < 14 did not have snprintf, only _snprintf.  */
+#   define SNPRINTF _snprintf
+#   define USE_MSVC__SNPRINTF 1
+#  endif
 # else
    /* Unix.  */
 #  define SNPRINTF snprintf
 
 /* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
    warnings in this file.  Use -Dlint to suppress them.  */
-#ifdef lint
+#if defined GCC_LINT || defined lint
 # define IF_LINT(Code) Code
 #else
 # define IF_LINT(Code) /* empty */
 #undef remainder
 #define remainder rem
 
-#if !USE_SNPRINTF && !WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION
 # if (HAVE_STRNLEN && !defined _AIX)
 #  define local_strnlen strnlen
 # else
@@ -212,7 +235,7 @@ local_strnlen (const char *string, size_t maxlen)
 # endif
 #endif
 
-#if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T && (WIDE_CHAR_VERSION || DCHAR_IS_TCHAR)
+#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
 # if HAVE_WCSLEN
 #  define local_wcslen wcslen
 # else
@@ -235,7 +258,7 @@ local_wcslen (const wchar_t *s)
 # endif
 #endif
 
-#if !USE_SNPRINTF && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
 # if HAVE_WCSNLEN
 #  define local_wcsnlen wcsnlen
 # else
@@ -263,10 +286,10 @@ decimal_point_char (void)
 {
   const char *point;
   /* Determine it in a multithread-safe way.  We know nl_langinfo is
-     multithread-safe on glibc systems and MacOS X systems, but is not required
+     multithread-safe on glibc systems and Mac OS 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__))
+#  if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__))
   point = nl_langinfo (RADIXCHAR);
 #  elif 1
   char pointbuf[5];
@@ -311,11 +334,11 @@ is_infinite_or_zerol (long double x)
 
 typedef unsigned int mp_limb_t;
 # define GMP_LIMB_BITS 32
-typedef int mp_limb_verify[2 * (sizeof (mp_limb_t) * CHAR_BIT == GMP_LIMB_BITS) - 1];
+verify (sizeof (mp_limb_t) * CHAR_BIT == GMP_LIMB_BITS);
 
 typedef unsigned long long mp_twolimb_t;
 # define GMP_TWOLIMB_BITS 64
-typedef int mp_twolimb_verify[2 * (sizeof (mp_twolimb_t) * CHAR_BIT == GMP_TWOLIMB_BITS) - 1];
+verify (sizeof (mp_twolimb_t) * CHAR_BIT == GMP_TWOLIMB_BITS);
 
 /* Representation of a bignum >= 0.  */
 typedef struct
@@ -540,32 +563,61 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
       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)
+        /* Determine s = GMP_LIMB_BITS - integer_length (msd).
+           Code copied from gnulib's integer_length.c.  */
+# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+        s = __builtin_clz (msd);
+# else
+#  if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT
+        if (GMP_LIMB_BITS <= DBL_MANT_BIT)
           {
-            msd = msd >> 2;
-            s -= 2;
+            /* Use 'double' operations.
+               Assumes an IEEE 754 'double' implementation.  */
+#   define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7)
+#   define DBL_EXP_BIAS (DBL_EXP_MASK / 2 - 1)
+#   define NWORDS \
+     ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
+            union { double value; unsigned int word[NWORDS]; } m;
+
+            /* Use a single integer to floating-point conversion.  */
+            m.value = msd;
+
+            s = GMP_LIMB_BITS
+                - (((m.word[DBL_EXPBIT0_WORD] >> DBL_EXPBIT0_BIT) & DBL_EXP_MASK)
+                   - DBL_EXP_BIAS);
           }
-        if (msd >= 0x2)
+        else
+#   undef NWORDS
+#  endif
           {
-            msd = msd >> 1;
-            s -= 1;
+            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;
+              }
           }
+# endif
       }
       /* 0 <= s < GMP_LIMB_BITS.
          Copy b, shifting it left by s bits.  */
@@ -808,7 +860,9 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
   size_t a_len = a.nlimbs;
   /* 0.03345 is slightly larger than log(2)/(9*log(10)).  */
   size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1);
-  char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes));
+  /* We need extra_zeroes bytes for zeroes, followed by c_len bytes for the
+     digits of a, followed by 1 byte for the terminating NUL.  */
+  char *c_ptr = (char *) malloc (xsum (xsum (extra_zeroes, c_len), 1));
   if (c_ptr != NULL)
     {
       char *d_ptr = c_ptr;
@@ -872,9 +926,9 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
   y = frexpl (x, &exp);
   if (!(y >= 0.0L && y < 1.0L))
     abort ();
-  /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * LDBL_MANT_BIT), and the
+  /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the
      latter is an integer.  */
-  /* Convert the mantissa (y * LDBL_MANT_BIT) to a sequence of limbs.
+  /* Convert the mantissa (y * 2^LDBL_MANT_BIT) to a sequence of limbs.
      I'm not sure whether it's safe to cast a 'long double' value between
      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',
@@ -922,11 +976,11 @@ decode_long_double (long double x, int *ep, mpn_t *mp)
         abort ();
       m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
     }
-#if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess
-         precision.  */
+#  if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess
+           precision.  */
   if (!(y == 0.0L))
     abort ();
-#endif
+#  endif
   /* Normalise.  */
   while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
     m.nlimbs--;
@@ -960,9 +1014,9 @@ decode_double (double x, int *ep, mpn_t *mp)
   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
+  /* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * 2^DBL_MANT_BIT), and the
      latter is an integer.  */
-  /* Convert the mantissa (y * DBL_MANT_BIT) to a sequence of limbs.
+  /* Convert the mantissa (y * 2^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',
@@ -1476,6 +1530,258 @@ is_borderline (const char *digits, size_t precision)
 
 #endif
 
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+
+/* 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 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,
             const FCHAR_T *format, va_list args)
@@ -1488,8 +1794,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
     return NULL;
 
 #define CLEANUP() \
-  free (d.dir);                                                         \
-  if (a.arg)                                                            \
+  if (d.dir != d.direct_alloc_dir)                                      \
+    free (d.dir);                                                       \
+  if (a.arg != a.direct_alloc_arg)                                      \
     free (a.arg);
 
   if (PRINTF_FETCHARGS (args, &a) < 0)
@@ -1592,7 +1899,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
             else
               {
                 do
-                  result[length++] = (unsigned char) *cp++;
+                  result[length++] = *cp++;
                 while (--n > 0);
               }
           }
@@ -1663,15 +1970,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                           abort ();
                         arg = a.arg[dp->width_arg_index].a.a_int;
+                        width = arg;
                         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);
+                            width = -width;
                           }
-                        else
-                          width = arg;
                       }
                     else
                       {
@@ -1779,8 +2085,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           characters = 0;
                         }
 
-                      if (has_width && width > characters
-                          && !(dp->flags & FLAG_LEFT))
+                      if (characters < width && !(dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -1833,8 +2138,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       }
 # endif
 
-                      if (has_width && width > characters
-                          && (dp->flags & FLAG_LEFT))
+                      if (characters < width && (dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -1907,8 +2211,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           characters = 0;
                         }
 
-                      if (has_width && width > characters
-                          && !(dp->flags & FLAG_LEFT))
+                      if (characters < width && !(dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -1961,8 +2264,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       }
 # endif
 
-                      if (has_width && width > characters
-                          && (dp->flags & FLAG_LEFT))
+                      if (characters < width && (dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -2035,8 +2337,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           characters = 0;
                         }
 
-                      if (has_width && width > characters
-                          && !(dp->flags & FLAG_LEFT))
+                      if (characters < width && !(dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -2089,8 +2390,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       }
 # endif
 
-                      if (has_width && width > characters
-                          && (dp->flags & FLAG_LEFT))
+                      if (characters < width && (dp->flags & FLAG_LEFT))
                         {
                           size_t n = width - characters;
                           ENSURE_ALLOCATION (xsum (length, n));
@@ -2105,7 +2405,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   }
               }
 #endif
-#if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
             else if (dp->conversion == 's'
 # if WIDE_CHAR_VERSION
                      && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2141,15 +2441,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                           abort ();
                         arg = a.arg[dp->width_arg_index].a.a_int;
+                        width = arg;
                         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);
+                            width = -width;
                           }
-                        else
-                          width = arg;
                       }
                     else
                       {
@@ -2279,8 +2578,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       characters = 0;
                     }
 
-                  if (has_width && width > characters
-                      && !(dp->flags & FLAG_LEFT))
+                  if (characters < width && !(dp->flags & FLAG_LEFT))
                     {
                       size_t n = width - characters;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2341,8 +2639,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         }
                     }
 
-                  if (has_width && width > characters
-                      && (dp->flags & FLAG_LEFT))
+                  if (characters < width && (dp->flags & FLAG_LEFT))
                     {
                       size_t n = width - characters;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2358,7 +2655,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   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];
+                  verify (sizeof (TCHAR_T) == 1);
                   TCHAR_T *tmpsrc;
                   DCHAR_T *tmpdst;
                   size_t tmpdst_len;
@@ -2399,7 +2696,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                               errno = EILSEQ;
                               return NULL;
                             }
-                          if (precision < count)
+                          if (precision < (unsigned int) count)
                             break;
                           arg_end++;
                           characters += count;
@@ -2519,7 +2816,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   if (has_width)
                     {
 #  if ENABLE_UNISTDIO
-                      /* Outside POSIX, it's preferrable to compare the width
+                      /* Outside POSIX, it's preferable to compare the width
                          against the number of _characters_ of the converted
                          value.  */
                       w = DCHAR_MBSNLEN (result + length, characters);
@@ -2533,8 +2830,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     /* w doesn't matter.  */
                     w = 0;
 
-                  if (has_width && width > w
-                      && !(dp->flags & FLAG_LEFT))
+                  if (w < width && !(dp->flags & FLAG_LEFT))
                     {
                       size_t n = width - w;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2594,8 +2890,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           count = wctomb (cbuf, *arg);
 #   endif
                           if (count <= 0)
-                            /* Inconsistency.  */
-                            abort ();
+                            {
+                              /* 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;
@@ -2609,8 +2913,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   length += tmpdst_len;
 #  endif
 
-                  if (has_width && width > w
-                      && (dp->flags & FLAG_LEFT))
+                  if (w < width && (dp->flags & FLAG_LEFT))
                     {
                       size_t n = width - w;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2618,8 +2921,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       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')
@@ -2637,17 +2940,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
               {
                 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;
+                size_t count;
                 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)
                   {
@@ -2658,15 +2960,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                           abort ();
                         arg = a.arg[dp->width_arg_index].a.a_int;
+                        width = arg;
                         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);
+                            width = -width;
                           }
-                        else
-                          width = arg;
                       }
                     else
                       {
@@ -2676,7 +2977,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           width = xsum (xtimes (width, 10), *digitp++ - '0');
                         while (digitp != dp->width_end);
                       }
-                    has_width = 1;
                   }
 
                 has_precision = 0;
@@ -3052,11 +3352,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     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)
+                count = p - tmp;
+
+                if (count < width)
                   {
-                    size_t pad = width - (p - tmp);
+                    size_t pad = width - count;
                     DCHAR_T *end = p + pad;
 
                     if (flags & FLAG_LEFT)
@@ -3089,28 +3392,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     p = end;
                   }
 
-                {
-                  size_t count = p - tmp;
+                count = p - tmp;
 
-                  if (count >= tmp_length)
-                    /* tmp_length was incorrectly calculated - fix the
-                       code above!  */
-                    abort ();
+                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);
+                /* Make room for the result.  */
+                if (count >= allocated - length)
+                  {
+                    size_t n = xsum (length, count);
 
-                      ENSURE_ALLOCATION (n);
-                    }
+                    ENSURE_ALLOCATION (n);
+                  }
 
-                  /* Append the result.  */
-                  memcpy (result + length, tmp, count * sizeof (DCHAR_T));
-                  if (tmp != tmpbuf)
-                    free (tmp);
-                  length += count;
-                }
+                /* Append the result.  */
+                memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+                if (tmp != tmpbuf)
+                  free (tmp);
+                length += count;
               }
 #endif
 #if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
@@ -3144,8 +3445,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 arg_type type = a.arg[dp->arg_index].type;
 # endif
                 int flags = dp->flags;
-                int has_width;
                 size_t width;
+                size_t count;
                 int has_precision;
                 size_t precision;
                 size_t tmp_length;
@@ -3154,7 +3455,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 DCHAR_T *pad_ptr;
                 DCHAR_T *p;
 
-                has_width = 0;
                 width = 0;
                 if (dp->width_start != dp->width_end)
                   {
@@ -3165,15 +3465,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                           abort ();
                         arg = a.arg[dp->width_arg_index].a.a_int;
+                        width = arg;
                         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);
+                            width = -width;
                           }
-                        else
-                          width = arg;
                       }
                     else
                       {
@@ -3183,7 +3482,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           width = xsum (xtimes (width, 10), *digitp++ - '0');
                         while (digitp != dp->width_end);
                       }
-                    has_width = 1;
                   }
 
                 has_precision = 0;
@@ -3623,9 +3921,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                            digits without trailing zeroes.  */
                                         if (exponent >= 0)
                                           {
-                                            size_t count = exponent + 1;
+                                            size_t ecount = exponent + 1;
                                             /* Note: count <= precision = ndigits.  */
-                                            for (; count > 0; count--)
+                                            for (; ecount > 0; ecount--)
                                               *p++ = digits[--ndigits];
                                             if ((flags & FLAG_ALT) || ndigits > nzeroes)
                                               {
@@ -3639,10 +3937,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           }
                                         else
                                           {
-                                            size_t count = -exponent - 1;
+                                            size_t ecount = -exponent - 1;
                                             *p++ = '0';
                                             *p++ = decimal_point_char ();
-                                            for (; count > 0; count--)
+                                            for (; ecount > 0; ecount--)
                                               *p++ = '0';
                                             while (ndigits > nzeroes)
                                               {
@@ -3947,7 +4245,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                   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__
+#    if defined _WIN32 && ! defined __CYGWIN__
                                     { '%', '+', '.', '3', 'd', '\0' };
 #    else
                                     { '%', '+', '.', '2', 'd', '\0' };
@@ -3961,7 +4259,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                   static const char decimal_format[] =
                                     /* Produce the same number of exponent digits
                                        as the native printf implementation.  */
-#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+#    if defined _WIN32 && ! defined __CYGWIN__
                                     "%+.3d";
 #    else
                                     "%+.2d";
@@ -4093,9 +4391,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                            digits without trailing zeroes.  */
                                         if (exponent >= 0)
                                           {
-                                            size_t count = exponent + 1;
-                                            /* Note: count <= precision = ndigits.  */
-                                            for (; count > 0; count--)
+                                            size_t ecount = exponent + 1;
+                                            /* Note: ecount <= precision = ndigits.  */
+                                            for (; ecount > 0; ecount--)
                                               *p++ = digits[--ndigits];
                                             if ((flags & FLAG_ALT) || ndigits > nzeroes)
                                               {
@@ -4109,10 +4407,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           }
                                         else
                                           {
-                                            size_t count = -exponent - 1;
+                                            size_t ecount = -exponent - 1;
                                             *p++ = '0';
                                             *p++ = decimal_point_char ();
-                                            for (; count > 0; count--)
+                                            for (; ecount > 0; ecount--)
                                               *p++ = '0';
                                             while (ndigits > nzeroes)
                                               {
@@ -4140,7 +4438,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           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__
+#    if defined _WIN32 && ! defined __CYGWIN__
                                             { '%', '+', '.', '3', 'd', '\0' };
 #    else
                                             { '%', '+', '.', '2', 'd', '\0' };
@@ -4154,7 +4452,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                           static const char decimal_format[] =
                                             /* Produce the same number of exponent digits
                                                as the native printf implementation.  */
-#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+#    if defined _WIN32 && ! defined __CYGWIN__
                                             "%+.3d";
 #    else
                                             "%+.2d";
@@ -4212,7 +4510,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                 *p++ = '+';
                                 /* Produce the same number of exponent digits as
                                    the native printf implementation.  */
-#   if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+#   if defined _WIN32 && ! defined __CYGWIN__
                                 *p++ = '0';
 #   endif
                                 *p++ = '0';
@@ -4240,9 +4538,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 
                 /* 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)
+                count = p - tmp;
+
+                if (count < width)
                   {
-                    size_t pad = width - (p - tmp);
+                    size_t pad = width - count;
                     DCHAR_T *end = p + pad;
 
                     if (flags & FLAG_LEFT)
@@ -4275,39 +4575,39 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     p = end;
                   }
 
-                {
-                  size_t count = p - tmp;
+                count = p - tmp;
 
-                  if (count >= tmp_length)
-                    /* tmp_length was incorrectly calculated - fix the
-                       code above!  */
-                    abort ();
+                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);
+                /* Make room for the result.  */
+                if (count >= allocated - length)
+                  {
+                    size_t n = xsum (length, count);
 
-                      ENSURE_ALLOCATION (n);
-                    }
+                    ENSURE_ALLOCATION (n);
+                  }
 
-                  /* Append the result.  */
-                  memcpy (result + length, tmp, count * sizeof (DCHAR_T));
-                  if (tmp != tmpbuf)
-                    free (tmp);
-                  length += count;
-                }
+                /* 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 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 int has_width;
+#endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 size_t width;
 #endif
-#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
                 int has_precision;
                 size_t precision;
 #endif
@@ -4326,14 +4626,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 TCHAR_T *fbp;
                 unsigned int prefix_count;
                 int prefixes[2] IF_LINT (= { 0 });
+                int orig_errno;
 #if !USE_SNPRINTF
                 size_t tmp_length;
                 TCHAR_T tmpbuf[700];
                 TCHAR_T *tmp;
 #endif
 
-#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 has_width = 0;
+#endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 width = 0;
                 if (dp->width_start != dp->width_end)
                   {
@@ -4344,15 +4647,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                           abort ();
                         arg = a.arg[dp->width_arg_index].a.a_int;
+                        width = arg;
                         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);
+                            width = -width;
                           }
-                        else
-                          width = arg;
                       }
                     else
                       {
@@ -4362,11 +4664,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           width = xsum (xtimes (width, 10), *digitp++ - '0');
                         while (digitp != dp->width_end);
                       }
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                     has_width = 1;
+#endif
                   }
 #endif
 
-#if !USE_SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
                 has_precision = 0;
                 precision = 6;
                 if (dp->precision_start != dp->precision_end)
@@ -4439,246 +4743,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if !USE_SNPRINTF
                 /* Allocate a temporary buffer of sufficient size for calling
                    sprintf.  */
-                {
-                  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)
-                        {
-#  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 =
-                            a.arg[dp->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 above.  */
-                          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 above.  */
-                          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 = a.arg[dp->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 */
-                }
+                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;
@@ -4716,6 +4784,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   *fbp++ = ' ';
                 if (flags & FLAG_ALT)
                   *fbp++ = '#';
+#if __GLIBC__ >= 2 && !defined __UCLIBC__
+                if (flags & FLAG_LOCALIZED)
+                  *fbp++ = 'I';
+#endif
                 if (!pad_ourselves)
                   {
                     if (flags & FLAG_ZERO)
@@ -4734,7 +4806,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           {
                             const FCHAR_T *mp = dp->width_start;
                             do
-                              *fbp++ = (unsigned char) *mp++;
+                              *fbp++ = *mp++;
                             while (--n > 0);
                           }
                       }
@@ -4755,7 +4827,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           {
                             const FCHAR_T *mp = dp->precision_start;
                             do
-                              *fbp++ = (unsigned char) *mp++;
+                              *fbp++ = *mp++;
                             while (--n > 0);
                           }
                       }
@@ -4766,16 +4838,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if HAVE_LONG_LONG_INT
                   case TYPE_LONGLONGINT:
                   case TYPE_ULONGLONGINT:
-# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# if defined _WIN32 && ! defined __CYGWIN__
                     *fbp++ = 'I';
                     *fbp++ = '6';
                     *fbp++ = '4';
                     break;
 # else
                     *fbp++ = 'l';
-                    /*FALLTHROUGH*/
 # endif
 #endif
+                    FALLTHROUGH;
                   case TYPE_LONGINT:
                   case TYPE_ULONGINT:
 #if HAVE_WINT_T
@@ -4799,20 +4871,31 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #endif
                   *fbp = dp->conversion;
 #if USE_SNPRINTF
-# if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
+# if ! (((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3))        \
+         && !defined __UCLIBC__)                                            \
+        || (defined __APPLE__ && defined __MACH__)                          \
+        || (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.
+                   ones - we know that snprintf's return value conforms to
+                   ISO C 99: the tests gl_SNPRINTF_RETVAL_C99 and
+                   gl_SNPRINTF_TRUNCATION_C99 pass.
                    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
+                /* On Mac OS X 10.3 or newer, we know that snprintf's return
+                   value conforms to ISO C 99: the tests gl_SNPRINTF_RETVAL_C99
+                   and gl_SNPRINTF_TRUNCATION_C99 pass.
+                   Therefore we can avoid using %n in this situation.
+                   On Mac OS X 10.13 or newer, the use of %n in format strings
+                   in writable memory by default crashes the program, so we
+                   should avoid it in this situation.  */
+                /* On native Windows 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
@@ -4821,11 +4904,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                      - 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
+                   On native Windows 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>
+                     <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+                     <https://msdn.microsoft.com/en-us/library/ms175782.aspx>
                    So we should avoid %n in this situation.  */
                 fbp[1] = '\0';
 # endif
@@ -4865,6 +4948,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 *(TCHAR_T *) (result + length) = '\0';
 #endif
 
+                orig_errno = errno;
+
                 for (;;)
                   {
                     int count = -1;
@@ -4918,6 +5003,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       }
 #endif
 
+                    errno = 0;
                     switch (type)
                       {
                       case TYPE_SCHAR:
@@ -5041,7 +5127,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       {
                         /* Verify that snprintf() has NUL-terminated its
                            result.  */
-                        if (count < maxlen
+                        if ((unsigned int) count < maxlen
                             && ((TCHAR_T *) (result + length)) [count] != '\0')
                           abort ();
                         /* Portability hack.  */
@@ -5064,15 +5150,45 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                             /* Look at the snprintf() return value.  */
                             if (retcount < 0)
                               {
+# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
                                 /* 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;
+                                   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;
@@ -5083,12 +5199,24 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     /* 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 (saved_errno == 0)
+                          {
+                            if (dp->conversion == 'c' || dp->conversion == 's')
+                              saved_errno = EILSEQ;
+                            else
+                              saved_errno = EINVAL;
+                          }
+
                         if (!(result == resultbuf || result == NULL))
                           free (result);
                         if (buf_malloced != NULL)
                           free (buf_malloced);
                         CLEANUP ();
-                        errno = EINVAL;
+
+                        errno = saved_errno;
                         return NULL;
                       }
 
@@ -5210,8 +5338,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         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];
+                        verify (sizeof (TCHAR_T) == 1);
 # if USE_SNPRINTF
                         tmpsrc = (TCHAR_T *) (result + length);
 # else
@@ -5278,7 +5405,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                             tmpsrc += count;
                             tmpdst += count;
                             for (n = count; n > 0; n--)
-                              *--tmpdst = (unsigned char) *--tmpsrc;
+                              *--tmpdst = *--tmpsrc;
                           }
                       }
 #endif
@@ -5304,7 +5431,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       {
                         size_t w;
 # if ENABLE_UNISTDIO
-                        /* Outside POSIX, it's preferrable to compare the width
+                        /* Outside POSIX, it's preferable to compare the width
                            against the number of _characters_ of the converted
                            value.  */
                         w = DCHAR_MBSNLEN (result + length, count);
@@ -5424,6 +5551,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     length += count;
                     break;
                   }
+                errno = orig_errno;
+#undef pad_ourselves
+#undef prec_ourselves
               }
           }
       }
@@ -5475,6 +5605,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
   }
 }
 
+#undef MAX_ROOM_NEEDED
 #undef TCHARS_PER_DCHAR
 #undef SNPRINTF
 #undef USE_SNPRINTF