X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvasnprintf.c;h=c60888cdefed45c438985814773d9165a7971b84;hb=a3a70ebafd7f2fdc069d43e8a26fc246dd7fe5bb;hp=f67211b95f5fa2abd8524a4d44b78d755816f2cc;hpb=7f5e623b09aeb3ea32039bb45bcce22a598615d5;p=gnulib.git diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index f67211b95..c60888cde 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -53,6 +53,21 @@ /* Checked size_t computations. */ #include "xsize.h" +#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL +# include +# include "float+.h" +#endif + +#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL +# include +# include "isnan.h" +#endif + +#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL +# include +# include "isnanl-nolibm.h" +#endif + #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL # include # include "isnan.h" @@ -62,11 +77,6 @@ # include "fpucw.h" #endif -#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL -# include -# include "float+.h" -#endif - /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ #ifndef EOVERFLOW # define EOVERFLOW E2BIG @@ -164,6 +174,28 @@ decimal_point_char () # endif #endif +#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL + +/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ +static int +is_infinite_or_zero (double x) +{ + return isnan (x) || x + x == x; +} + +#endif + +#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL + +/* Equivalent to !isfinite(x), but does not require libm. */ +static int +is_infinitel (long double x) +{ + return isnanl (x) || (x + x == x && x != 0.0L); +} + +#endif + #if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL /* Converting 'long double' to decimal without rare rounding bugs requires @@ -656,22 +688,25 @@ divide (mpn_t a, mpn_t b, mpn_t *q) return roomptr; } -/* Convert a bignum a >= 0 to decimal representation. +/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal + representation. Destroys the contents of a. Return the allocated memory - containing the decimal digits in low-to-high order, terminated with a NUL character - in case of success, NULL in case of memory allocation failure. */ static char * -convert_to_decimal (mpn_t a) +convert_to_decimal (mpn_t a, size_t extra_zeroes) { mp_limb_t *a_ptr = a.limbs; 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 (c_len); + char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes)); if (c_ptr != NULL) { char *d_ptr = c_ptr; + for (; extra_zeroes > 0; extra_zeroes--) + *d_ptr++ = '0'; while (a_len > 0) { /* Divide a by 10^9, in-place. */ @@ -789,16 +824,18 @@ decode_long_double (long double x, int *ep, mpn_t *mp) } /* Assuming x is finite and >= 0, and n is an integer: - Compute y = round (x * 10^n) as a bignum >= 0. - Return the allocated memory in case of success, NULL in case of memory - allocation failure. */ -static void * -scale10_round_long_double (long double x, int n, mpn_t *yp) + Returns the decimal representation of round (x * 10^n). + Return the allocated memory - containing the decimal digits in low-to-high + order, terminated with a NUL character - in case of success, NULL in case + of memory allocation failure. */ +static char * +scale10_round_decimal_long_double (long double x, int n) { int e; mpn_t m; void *memory = decode_long_double (x, &e, &m); int s; + size_t extra_zeroes; unsigned int abs_n; unsigned int abs_s; mp_limb_t *pow5_ptr; @@ -806,6 +843,9 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) unsigned int s_limbs; unsigned int s_bits; mpn_t pow5; + mpn_t z; + void *z_memory; + char *digits; if (memory == NULL) return NULL; @@ -813,6 +853,17 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m) = round (2^s * 5^n * m). */ s = e + n; + extra_zeroes = 0; + /* Factor out a common power of 10 if possible. */ + if (s > 0 && n > 0) + { + extra_zeroes = (s < n ? s : n); + s -= extra_zeroes; + n -= extra_zeroes; + } + /* Here y = round (2^s * 5^n * m) * 10^extra_zeroes. + Before converting to decimal, we need to compute + z = round (2^s * 5^n * m). */ /* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same sign. 2.322 is slightly larger than log(5)/log(2). */ abs_n = (n >= 0 ? n : -n); @@ -895,18 +946,12 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) if (n >= 0) { /* Multiply m with pow5. No division needed. */ - void *result_memory = multiply (m, pow5, yp); - free (pow5_ptr); - free (memory); - return result_memory; + z_memory = multiply (m, pow5, &z); } else { /* Divide m by pow5 and round. */ - void *result_memory = divide (m, pow5, yp); - free (pow5_ptr); - free (memory); - return result_memory; + z_memory = divide (m, pow5, &z); } } else @@ -920,7 +965,6 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) mpn_t numerator; mpn_t denominator; void *tmp_memory; - void *result_memory; tmp_memory = multiply (m, pow5, &numerator); if (tmp_memory == NULL) { @@ -938,11 +982,8 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) denominator.limbs = ptr; denominator.nlimbs = s_limbs + 1; } - result_memory = divide (numerator, denominator, yp); + z_memory = divide (numerator, denominator, &z); free (tmp_memory); - free (pow5_ptr); - free (memory); - return result_memory; } else { @@ -950,7 +991,6 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) Multiply m with 2^s, then divide by pow5. */ mpn_t numerator; mp_limb_t *num_ptr; - void *result_memory; num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1) * sizeof (mp_limb_t)); if (num_ptr == NULL) @@ -990,32 +1030,19 @@ scale10_round_long_double (long double x, int n, mpn_t *yp) numerator.limbs = num_ptr; numerator.nlimbs = destptr - num_ptr; } - result_memory = divide (numerator, pow5, yp); + z_memory = divide (numerator, pow5, &z); free (num_ptr); - free (pow5_ptr); - free (memory); - return result_memory; } } -} + free (pow5_ptr); + free (memory); -/* Assuming x is finite and >= 0, and n is an integer: - Returns the decimal representation of round (x * 10^n). - Return the allocated memory - containing the decimal digits in low-to-high - order, terminated with a NUL character - in case of success, NULL in case - of memory allocation failure. */ -static char * -scale10_round_decimal_long_double (long double x, int n) -{ - mpn_t y; - void *memory; - char *digits; + /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ - memory = scale10_round_long_double (x, n, &y); - if (memory == NULL) + if (z_memory == NULL) return NULL; - digits = convert_to_decimal (y); - free (memory); + digits = convert_to_decimal (z, extra_zeroes); + free (z_memory); return digits; } @@ -1262,18 +1289,36 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); } } -#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL +#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL else if ((dp->conversion == 'f' || dp->conversion == 'F' || dp->conversion == 'e' || dp->conversion == 'E' || dp->conversion == 'g' || dp->conversion == 'G') - && a.arg[dp->arg_index].type == TYPE_LONGDOUBLE) + && (0 +# if NEED_PRINTF_INFINITE_DOUBLE + || (a.arg[dp->arg_index].type == TYPE_DOUBLE + /* The systems (mingw) which produce wrong output + for Inf, -Inf, and NaN also do so for -0.0. + Therefore we treat this case here as well. */ + && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double)) +# endif +# if NEED_PRINTF_LONG_DOUBLE + || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE +# elif NEED_PRINTF_INFINITE_LONG_DOUBLE + || (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE + /* Some systems produce wrong output for Inf, + -Inf, and NaN. */ + && is_infinitel (a.arg[dp->arg_index].a.a_longdouble)) +# endif + )) { +# if NEED_PRINTF_INFINITE_DOUBLE && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) + arg_type type = a.arg[dp->arg_index].type; +# endif int flags = dp->flags; int has_width; size_t width; int has_precision; size_t precision; - long double arg; size_t tmp_length; CHAR_T tmpbuf[700]; CHAR_T *tmp; @@ -1342,19 +1387,38 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } - arg = a.arg[dp->arg_index].a.a_longdouble; + /* POSIX specifies the default precision to be 6 for %f, %F, + %e, %E, but not for %g, %G. Implementations appear to use + the same default precision also for %g, %G. */ + if (!has_precision) + precision = 6; /* Allocate a temporary buffer of sufficient size. */ +# if NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE + tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0); +# elif NEED_PRINTF_LONG_DOUBLE tmp_length = LDBL_DIG + 1; +# else + tmp_length = 0; +# endif if (tmp_length < precision) tmp_length = precision; - if (dp->conversion == 'f' || dp->conversion == 'F') - if (!(isnanl (arg) || arg + arg == arg)) +# if NEED_PRINTF_LONG_DOUBLE +# if NEED_PRINTF_INFINITE_DOUBLE + if (type == TYPE_LONGDOUBLE) +# endif + if (dp->conversion == 'f' || dp->conversion == 'F') { - int exponent = floorlog10l (arg < 0 ? -arg : arg); - if (exponent >= 0 && tmp_length < exponent + precision) - tmp_length = exponent + precision; + long double arg = a.arg[dp->arg_index].a.a_longdouble; + if (!(isnanl (arg) || arg + arg == arg)) + { + /* arg is finite and nonzero. */ + int exponent = floorlog10l (arg < 0 ? -arg : arg); + if (exponent >= 0 && tmp_length < exponent + precision) + tmp_length = exponent + precision; + } } +# endif /* Account for sign, decimal point etc. */ tmp_length = xsum (tmp_length, 12); @@ -1381,156 +1445,89 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar pad_ptr = NULL; p = tmp; - if (isnanl (arg)) - { - if (dp->conversion >= 'A' && dp->conversion <= 'Z') - { - *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; - } - else - { - *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; - } - } - else +# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE +# if NEED_PRINTF_INFINITE_DOUBLE + if (type == TYPE_LONGDOUBLE) +# endif { - int sign = 0; - DECL_LONG_DOUBLE_ROUNDING - - BEGIN_LONG_DOUBLE_ROUNDING (); - - if (signbit (arg)) /* arg < 0.0L or negative zero */ - { - sign = -1; - arg = -arg; - } - - if (sign < 0) - *p++ = '-'; - else if (flags & FLAG_SHOWSIGN) - *p++ = '+'; - else if (flags & FLAG_SPACE) - *p++ = ' '; + long double arg = a.arg[dp->arg_index].a.a_longdouble; - if (arg > 0.0L && arg + arg == arg) + if (isnanl (arg)) { if (dp->conversion >= 'A' && dp->conversion <= 'Z') { - *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; + *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } else { - *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; + *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; } } else { - pad_ptr = p; + int sign = 0; + DECL_LONG_DOUBLE_ROUNDING + + BEGIN_LONG_DOUBLE_ROUNDING (); - if (dp->conversion == 'f' || dp->conversion == 'F') + if (signbit (arg)) /* arg < 0.0L or negative zero */ { - char *digits; - size_t ndigits; + sign = -1; + arg = -arg; + } - if (!has_precision) - precision = 6; + if (sign < 0) + *p++ = '-'; + else if (flags & FLAG_SHOWSIGN) + *p++ = '+'; + else if (flags & FLAG_SPACE) + *p++ = ' '; - digits = - scale10_round_decimal_long_double (arg, precision); - if (digits == NULL) + if (arg > 0.0L && arg + arg == arg) + { + if (dp->conversion >= 'A' && dp->conversion <= 'Z') { - END_LONG_DOUBLE_ROUNDING (); - goto out_of_memory; + *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; } - ndigits = strlen (digits); - - if (ndigits > precision) - do - { - --ndigits; - *p++ = digits[ndigits]; - } - while (ndigits > precision); else - *p++ = '0'; - /* Here ndigits <= precision. */ - if ((flags & FLAG_ALT) || precision > 0) { - *p++ = decimal_point_char (); - for (; precision > ndigits; precision--) - *p++ = '0'; - while (ndigits > 0) - { - --ndigits; - *p++ = digits[ndigits]; - } + *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; } - - free (digits); } - else if (dp->conversion == 'e' || dp->conversion == 'E') + else { - int exponent; - - if (!has_precision) - precision = 6; +# if NEED_PRINTF_LONG_DOUBLE + pad_ptr = p; - if (arg == 0.0L) - { - exponent = 0; - *p++ = '0'; - if ((flags & FLAG_ALT) || precision > 0) - { - *p++ = decimal_point_char (); - for (; precision > 0; precision--) - *p++ = '0'; - } - } - else + if (dp->conversion == 'f' || dp->conversion == 'F') { - /* arg > 0.0L. */ - int adjusted; char *digits; size_t ndigits; - exponent = floorlog10l (arg); - adjusted = 0; - for (;;) + digits = + scale10_round_decimal_long_double (arg, precision); + if (digits == NULL) { - digits = - scale10_round_decimal_long_double (arg, - (int)precision - exponent); - if (digits == NULL) - { - END_LONG_DOUBLE_ROUNDING (); - goto out_of_memory; - } - ndigits = strlen (digits); - - if (ndigits == precision + 1) - break; - if (ndigits < precision - || ndigits > precision + 2) - /* The exponent was not guessed precisely - enough. */ - abort (); - if (adjusted) - /* None of two values of exponent is the - right one. Prevent an endless loop. */ - abort (); - free (digits); - if (ndigits == precision) - exponent -= 1; - else - exponent += 1; - adjusted = 1; + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; } + ndigits = strlen (digits); - /* Here ndigits = precision+1. */ - *p++ = digits[--ndigits]; + if (ndigits > precision) + do + { + --ndigits; + *p++ = digits[ndigits]; + } + while (ndigits > precision); + else + *p++ = '0'; + /* Here ndigits <= precision. */ if ((flags & FLAG_ALT) || precision > 0) { *p++ = decimal_point_char (); + for (; precision > ndigits; precision--) + *p++ = '0'; while (ndigits > 0) { --ndigits; @@ -1540,176 +1537,351 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar free (digits); } - - *p++ = dp->conversion; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION - { - static const wchar_t decimal_format[] = - { '%', '+', '.', '2', 'd', '\0' }; - SNPRINTF (p, 6 + 1, decimal_format, exponent); - } -# else - sprintf (p, "%+.2d", exponent); -# endif - while (*p != '\0') - p++; - } - else if (dp->conversion == 'g' || dp->conversion == 'G') - { - /* This is not specified by POSIX, but - implementations appear to do this. */ - if (!has_precision) - precision = 6; - - if (precision == 0) - precision = 1; - /* precision >= 1. */ - - if (arg == 0.0L) - /* The exponent is 0, >= -4, < precision. - Use fixed-point notation. */ - { - size_t ndigits = precision; - /* Number of trailing zeroes that have to be - dropped. */ - size_t nzeroes = - (flags & FLAG_ALT ? 0 : precision - 1); - - --ndigits; - *p++ = '0'; - if ((flags & FLAG_ALT) || ndigits > nzeroes) - { - *p++ = decimal_point_char (); - while (ndigits > nzeroes) - { - --ndigits; - *p++ = '0'; - } - } - } - else + else if (dp->conversion == 'e' || dp->conversion == 'E') { - /* arg > 0.0L. */ int exponent; - int adjusted; - char *digits; - size_t ndigits; - size_t nzeroes; - exponent = floorlog10l (arg); - adjusted = 0; - for (;;) + if (arg == 0.0L) { - digits = - scale10_round_decimal_long_double (arg, - (int)(precision - 1) - exponent); - if (digits == NULL) + exponent = 0; + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) { - END_LONG_DOUBLE_ROUNDING (); - goto out_of_memory; + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; } - ndigits = strlen (digits); - - if (ndigits == precision) - break; - if (ndigits < precision - 1 - || ndigits > precision + 1) - /* The exponent was not guessed precisely - enough. */ - abort (); - if (adjusted) - /* None of two values of exponent is the - right one. Prevent an endless loop. */ - abort (); - free (digits); - if (ndigits < precision) - exponent -= 1; - else - exponent += 1; - adjusted = 1; } - /* Here ndigits = precision. */ - - /* Determine the number of trailing zeroes that - have to be dropped. */ - nzeroes = 0; - if ((flags & FLAG_ALT) == 0) - while (nzeroes < ndigits - && digits[nzeroes] == '0') - nzeroes++; - - /* The exponent is now determined. */ - if (exponent >= -4 && exponent < (long)precision) + else { - /* Fixed-point notation: max(exponent,0)+1 - digits, then the decimal point, then the - remaining digits without trailing zeroes. */ - if (exponent >= 0) + /* arg > 0.0L. */ + int adjusted; + char *digits; + size_t ndigits; + + exponent = floorlog10l (arg); + adjusted = 0; + for (;;) { - size_t count = exponent + 1; - /* Note: count <= precision = ndigits. */ - for (; count > 0; count--) - *p++ = digits[--ndigits]; - if ((flags & FLAG_ALT) || ndigits > nzeroes) + digits = + scale10_round_decimal_long_double (arg, + (int)precision - exponent); + if (digits == NULL) { - *p++ = decimal_point_char (); - while (ndigits > nzeroes) - { - --ndigits; - *p++ = digits[ndigits]; - } + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; } + ndigits = strlen (digits); + + if (ndigits == precision + 1) + break; + if (ndigits < precision + || ndigits > precision + 2) + /* The exponent was not guessed + precisely enough. */ + abort (); + if (adjusted) + /* None of two values of exponent is + the right one. Prevent an endless + loop. */ + abort (); + free (digits); + if (ndigits == precision) + exponent -= 1; + else + exponent += 1; + adjusted = 1; } - else + + /* Here ndigits = precision+1. */ + *p++ = digits[--ndigits]; + if ((flags & FLAG_ALT) || precision > 0) { - size_t count = -exponent - 1; - *p++ = '0'; *p++ = decimal_point_char (); - for (; count > 0; count--) - *p++ = '0'; - while (ndigits > nzeroes) + while (ndigits > 0) { --ndigits; *p++ = digits[ndigits]; } } + + free (digits); } - else + + *p++ = dp->conversion; /* 'e' or 'E' */ +# if WIDE_CHAR_VERSION + { + static const wchar_t decimal_format[] = + { '%', '+', '.', '2', 'd', '\0' }; + SNPRINTF (p, 6 + 1, decimal_format, exponent); + } +# else + sprintf (p, "%+.2d", exponent); +# endif + while (*p != '\0') + p++; + } + else if (dp->conversion == 'g' || dp->conversion == 'G') + { + if (precision == 0) + precision = 1; + /* precision >= 1. */ + + if (arg == 0.0L) + /* The exponent is 0, >= -4, < precision. + Use fixed-point notation. */ { - /* Exponential notation. */ - *p++ = digits[--ndigits]; + size_t ndigits = precision; + /* Number of trailing zeroes that have to be + dropped. */ + size_t nzeroes = + (flags & FLAG_ALT ? 0 : precision - 1); + + --ndigits; + *p++ = '0'; if ((flags & FLAG_ALT) || ndigits > nzeroes) { *p++ = decimal_point_char (); while (ndigits > nzeroes) { --ndigits; - *p++ = digits[ndigits]; + *p++ = '0'; } } - *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION - { - static const wchar_t decimal_format[] = - { '%', '+', '.', '2', 'd', '\0' }; - SNPRINTF (p, 6 + 1, decimal_format, exponent); - } -# else - sprintf (p, "%+.2d", exponent); -# endif - while (*p != '\0') - p++; } + else + { + /* arg > 0.0L. */ + int exponent; + int adjusted; + char *digits; + size_t ndigits; + size_t nzeroes; + + exponent = floorlog10l (arg); + adjusted = 0; + for (;;) + { + digits = + scale10_round_decimal_long_double (arg, + (int)(precision - 1) - exponent); + if (digits == NULL) + { + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; + } + ndigits = strlen (digits); + + if (ndigits == precision) + break; + if (ndigits < precision - 1 + || ndigits > precision + 1) + /* The exponent was not guessed + precisely enough. */ + abort (); + if (adjusted) + /* None of two values of exponent is + the right one. Prevent an endless + loop. */ + abort (); + free (digits); + if (ndigits < precision) + exponent -= 1; + else + exponent += 1; + adjusted = 1; + } + /* Here ndigits = precision. */ + + /* Determine the number of trailing zeroes + that have to be dropped. */ + nzeroes = 0; + if ((flags & FLAG_ALT) == 0) + while (nzeroes < ndigits + && digits[nzeroes] == '0') + nzeroes++; + + /* The exponent is now determined. */ + if (exponent >= -4 + && exponent < (long)precision) + { + /* Fixed-point notation: + max(exponent,0)+1 digits, then the + decimal point, then the remaining + digits without trailing zeroes. */ + if (exponent >= 0) + { + size_t count = exponent + 1; + /* Note: count <= precision = ndigits. */ + for (; count > 0; count--) + *p++ = digits[--ndigits]; + if ((flags & FLAG_ALT) || ndigits > nzeroes) + { + *p++ = decimal_point_char (); + while (ndigits > nzeroes) + { + --ndigits; + *p++ = digits[ndigits]; + } + } + } + else + { + size_t count = -exponent - 1; + *p++ = '0'; + *p++ = decimal_point_char (); + for (; count > 0; count--) + *p++ = '0'; + while (ndigits > nzeroes) + { + --ndigits; + *p++ = digits[ndigits]; + } + } + } + else + { + /* Exponential notation. */ + *p++ = digits[--ndigits]; + if ((flags & FLAG_ALT) || ndigits > nzeroes) + { + *p++ = decimal_point_char (); + while (ndigits > nzeroes) + { + --ndigits; + *p++ = digits[ndigits]; + } + } + *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ +# if WIDE_CHAR_VERSION + { + static const wchar_t decimal_format[] = + { '%', '+', '.', '2', 'd', '\0' }; + SNPRINTF (p, 6 + 1, decimal_format, exponent); + } +# else + sprintf (p, "%+.2d", exponent); +# endif + while (*p != '\0') + p++; + } - free (digits); + free (digits); + } } + else + abort (); +# else + /* arg is finite. */ + abort (); +# endif + } + + END_LONG_DOUBLE_ROUNDING (); + } + } +# if NEED_PRINTF_INFINITE_DOUBLE + else +# endif +# endif +# if NEED_PRINTF_INFINITE_DOUBLE + { + /* Simpler than above: handle only NaN, Infinity, zero. */ + double arg = a.arg[dp->arg_index].a.a_double; + + if (isnan (arg)) + { + if (dp->conversion >= 'A' && dp->conversion <= 'Z') + { + *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } else - abort (); + { + *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; + } } + else + { + int sign = 0; + + if (signbit (arg)) /* arg < 0.0L or negative zero */ + { + sign = -1; + arg = -arg; + } + + if (sign < 0) + *p++ = '-'; + else if (flags & FLAG_SHOWSIGN) + *p++ = '+'; + else if (flags & FLAG_SPACE) + *p++ = ' '; + + if (arg > 0.0 && arg + arg == arg) + { + if (dp->conversion >= 'A' && dp->conversion <= 'Z') + { + *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; + } + else + { + *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; + } + } + else + { + if (!(arg == 0.0)) + abort (); + + pad_ptr = p; - END_LONG_DOUBLE_ROUNDING (); + if (dp->conversion == 'f' || dp->conversion == 'F') + { + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; + } + } + else if (dp->conversion == 'e' || dp->conversion == 'E') + { + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; + } + *p++ = dp->conversion; /* 'e' or 'E' */ + *p++ = '+'; + /* Produce the same number of exponent digits as + the native printf implementation. */ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + *p++ = '0'; +# endif + *p++ = '0'; + *p++ = '0'; + } + else if (dp->conversion == 'g' || dp->conversion == 'G') + { + *p++ = '0'; + if (flags & FLAG_ALT) + { + size_t ndigits = + (precision > 0 ? precision - 1 : 0); + *p++ = decimal_point_char (); + for (; ndigits > 0; --ndigits) + *p++ = '0'; + } + } + else + abort (); + } + } } +# endif /* The generated string now extends from tmp to p, with the zero padding insertion point being at pad_ptr. */ @@ -2841,6 +3013,23 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar return NULL; } + /* Make room for the result. */ + if (count >= maxlen) + { + /* Need at least count bytes. But allocate + proportionally, to avoid looping eternally if + snprintf() reports a too small count. */ + size_t n = + xmax (xsum (length, count), xtimes (allocated, 2)); + + ENSURE_ALLOCATION (n); +#if USE_SNPRINTF + continue; +#else + maxlen = allocated - length; +#endif + } + /* Perform padding. */ #if NEED_PRINTF_FLAG_ZERO if (pad_ourselves && has_width && count < width) @@ -2853,14 +3042,15 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar proportionally, to avoid looping eternally if snprintf() reports a too small count. */ size_t n = - xmax (xsum (length, width), + xmax (xsum (length + 1, width), xtimes (allocated, 2)); length += count; ENSURE_ALLOCATION (n); length -= count; - maxlen = allocated - length; /* >= width */ + maxlen = allocated - length; /* > width */ } + /* Here width < maxlen. */ # endif { # if USE_SNPRINTF @@ -2919,20 +3109,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); #endif - /* Make room for the result. */ - if (count >= maxlen) - { - /* Need at least count bytes. But allocate - proportionally, to avoid looping eternally if - snprintf() reports a too small count. */ - size_t n = - xmax (xsum (length, count), xtimes (allocated, 2)); - - ENSURE_ALLOCATION (n); -#if USE_SNPRINTF - continue; -#endif - } + /* Here still count < maxlen. */ #if USE_SNPRINTF /* The snprintf() result did fit. */