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 } } } |