diff options
Diffstat (limited to 'lib/vasnprintf.c')
| -rw-r--r-- | lib/vasnprintf.c | 339 | 
1 files changed, 186 insertions, 153 deletions
| diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index daaec6ac..daea8164 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -1,5 +1,5 @@  /* vsprintf with automatic memory allocation. -   Copyright (C) 1999, 2002-2010 Free Software Foundation, Inc. +   Copyright (C) 1999, 2002-2015 Free Software Foundation, Inc.     This program is free software; you can redistribute it and/or modify     it under the terms of the GNU Lesser General Public License as published by @@ -12,8 +12,7 @@     GNU Lesser General Public License for more details.     You should have received a copy of the GNU Lesser 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 <http://www.gnu.org/licenses/>.  */  /* This file can be parametrized with the following macros:       VASNPRINTF         The name of the function being defined. @@ -88,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" @@ -274,10 +275,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]; @@ -322,11 +323,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 @@ -551,32 +552,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.  */ @@ -883,9 +913,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', @@ -933,11 +963,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--; @@ -971,9 +1001,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', @@ -1500,7 +1530,7 @@ is_borderline (const char *digits, size_t precision)  /* 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 +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) @@ -1751,8 +1781,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) @@ -1855,7 +1886,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,              else                {                  do -                  result[length++] = (unsigned char) *cp++; +                  result[length++] = *cp++;                  while (--n > 0);                }            } @@ -1926,15 +1957,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                        { @@ -2042,8 +2072,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)); @@ -2096,8 +2125,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)); @@ -2170,8 +2198,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)); @@ -2224,8 +2251,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)); @@ -2298,8 +2324,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)); @@ -2352,8 +2377,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)); @@ -2404,15 +2428,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                        { @@ -2542,8 +2565,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)); @@ -2604,8 +2626,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)); @@ -2621,7 +2642,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; @@ -2782,7 +2803,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); @@ -2796,8 +2817,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)); @@ -2880,8 +2900,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)); @@ -2889,8 +2908,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') @@ -2908,17 +2927,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)                    { @@ -2929,15 +2947,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                        { @@ -2947,7 +2964,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; @@ -3323,11 +3339,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) @@ -3360,28 +3379,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 @@ -3415,8 +3432,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; @@ -3425,7 +3442,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)                    { @@ -3436,15 +3452,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                        { @@ -3454,7 +3469,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; @@ -3894,9 +3908,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)                                                { @@ -3910,10 +3924,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)                                                { @@ -4364,9 +4378,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)                                                { @@ -4380,10 +4394,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)                                                { @@ -4511,9 +4525,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) @@ -4546,36 +4562,36 @@ 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 || !HAVE_SNPRINTF_RETVAL_C99 || !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 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION                  size_t width;  #endif  #if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION @@ -4597,14 +4613,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 || !HAVE_SNPRINTF_RETVAL_C99 || !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 || !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)                    { @@ -4615,15 +4634,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                        { @@ -4633,7 +4651,9 @@ 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 @@ -4751,6 +4771,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) @@ -4769,7 +4793,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);                            }                        } @@ -4790,7 +4814,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);                            }                        } @@ -4834,20 +4858,21 @@ 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 _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. +                   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 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 @@ -4856,7 +4881,7 @@ 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 @@ -4900,6 +4925,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,                  *(TCHAR_T *) (result + length) = '\0';  #endif +                orig_errno = errno; +                  for (;;)                    {                      int count = -1; @@ -5114,7 +5141,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,                                  size_t tmp_length =                                    MAX_ROOM_NEEDED (&a, dp->arg_index,                                                     dp->conversion, type, flags, -                                                   width, has_precision, +                                                   width, +                                                   has_precision,                                                     precision, pad_ourselves);                                  if (maxlen < tmp_length) @@ -5151,18 +5179,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,                          /* 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 = -                          (saved_errno != 0 -                           ? saved_errno -                           : (dp->conversion == 'c' || dp->conversion == 's' -                              ? EILSEQ -                              : EINVAL)); + +                        errno = saved_errno;                          return NULL;                        } @@ -5284,8 +5315,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 @@ -5352,7 +5382,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 @@ -5378,7 +5408,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); @@ -5498,6 +5528,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,                      length += count;                      break;                    } +                errno = orig_errno; +#undef pad_ourselves +#undef prec_ourselves                }            }        } | 
