From: Bruno Haible Date: Wed, 6 Jun 2007 01:46:06 +0000 (+0000) Subject: Do the extra handling of NaN and Inf also the %a / %A. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dbb309c3e57b1e4c3ae477a08dc075dac8fd8542;p=pspp Do the extra handling of NaN and Inf also the %a / %A. Swap two code blocks. --- diff --git a/ChangeLog b/ChangeLog index e727af8eb6..ede4cb3e4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-06-05 Bruno Haible + + * lib/vasnprintf.c (VASNPRINTF): Do the extra handling of NaN and Inf + also the %a / %A. Handle the %a / %A code before this extra handling. + 2007-06-05 Bruno Haible * lib/vasnprintf.c [NEED_PRINTF_LONG_DOUBLE || diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 3f65e9dbf8..ac1a26067d 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -1291,31 +1291,10 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); } } -#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') - && (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_DIRECTIVE_A && !defined IN_LIBINTL + else if (dp->conversion == 'a' || dp->conversion == 'A') { -# 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; @@ -1389,38 +1368,21 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } - /* 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 (type == TYPE_LONGDOUBLE) + tmp_length = + (unsigned int) ((LDBL_DIG + 1) + * 0.831 /* decimal -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ + else + tmp_length = + (unsigned int) ((DBL_DIG + 1) + * 0.831 /* decimal -> hexadecimal */ + ) + + 1; /* turn floor into ceil */ if (tmp_length < precision) tmp_length = precision; -# if NEED_PRINTF_LONG_DOUBLE -# if NEED_PRINTF_INFINITE_DOUBLE - if (type == TYPE_LONGDOUBLE) -# endif - if (dp->conversion == 'f' || dp->conversion == 'F') - { - long double arg = a.arg[dp->arg_index].a.a_longdouble; - if (!(isnanl (arg) || arg + arg == arg)) - { - /* arg is finite and nonzero. */ - int exponent = floorlog10l (arg < 0 ? -arg : arg); - if (exponent >= 0 && tmp_length < exponent + precision) - tmp_length = exponent + precision; - } - } -# endif /* Account for sign, decimal point etc. */ tmp_length = xsum (tmp_length, 12); @@ -1446,17 +1408,13 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar pad_ptr = NULL; p = tmp; - -# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE -# if NEED_PRINTF_INFINITE_DOUBLE if (type == TYPE_LONGDOUBLE) -# endif { long double arg = a.arg[dp->arg_index].a.a_longdouble; if (isnanl (arg)) { - if (dp->conversion >= 'A' && dp->conversion <= 'Z') + if (dp->conversion == 'A') { *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } @@ -1487,7 +1445,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (arg > 0.0L && arg + arg == arg) { - if (dp->conversion >= 'A' && dp->conversion <= 'Z') + if (dp->conversion == 'A') { *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; } @@ -1498,302 +1456,102 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { -# if NEED_PRINTF_LONG_DOUBLE - pad_ptr = p; + int exponent; + long double mantissa; - if (dp->conversion == 'f' || dp->conversion == 'F') + if (arg > 0.0L) + mantissa = printf_frexpl (arg, &exponent); + else { - char *digits; - size_t ndigits; - - digits = - scale10_round_decimal_long_double (arg, precision); - if (digits == NULL) - { - END_LONG_DOUBLE_ROUNDING (); - goto out_of_memory; - } - ndigits = strlen (digits); - - if (ndigits > precision) - do - { - --ndigits; - *p++ = digits[ndigits]; - } - while (ndigits > precision); - else - *p++ = '0'; - /* Here ndigits <= precision. */ - if ((flags & FLAG_ALT) || precision > 0) - { - *p++ = decimal_point_char (); - for (; precision > ndigits; precision--) - *p++ = '0'; - while (ndigits > 0) - { - --ndigits; - *p++ = digits[ndigits]; - } - } - - free (digits); + exponent = 0; + mantissa = 0.0L; } - else if (dp->conversion == 'e' || dp->conversion == 'E') + + if (has_precision + && precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1) { - int exponent; + /* Round the mantissa. */ + long double tail = mantissa; + size_t q; - 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 + for (q = precision; ; q--) { - /* arg > 0.0L. */ - int adjusted; - char *digits; - size_t ndigits; - - exponent = floorlog10l (arg); - adjusted = 0; - for (;;) + int digit = (int) tail; + tail -= digit; + if (q == 0) { - 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; + if (digit & 1 ? tail >= 0.5L : tail > 0.5L) + tail = 1 - tail; else - exponent += 1; - adjusted = 1; - } - - /* Here ndigits = precision+1. */ - *p++ = digits[--ndigits]; - if ((flags & FLAG_ALT) || precision > 0) - { - *p++ = decimal_point_char (); - while (ndigits > 0) - { - --ndigits; - *p++ = digits[ndigits]; - } + tail = - tail; + break; } - - free (digits); + tail *= 16.0L; } + if (tail != 0.0L) + for (q = precision; q > 0; q--) + tail *= 0.0625L; + mantissa += tail; + } - *p++ = dp->conversion; /* 'e' or 'E' */ -# if WIDE_CHAR_VERSION + *p++ = '0'; + *p++ = dp->conversion - 'A' + 'X'; + pad_ptr = p; + { + int digit; + + digit = (int) mantissa; + mantissa -= digit; + *p++ = '0' + digit; + if ((flags & FLAG_ALT) + || mantissa > 0.0L || precision > 0) { - static const wchar_t decimal_format[] = - { '%', '+', '.', '2', 'd', '\0' }; - SNPRINTF (p, 6 + 1, decimal_format, exponent); + *p++ = decimal_point_char (); + /* This loop terminates because we assume + that FLT_RADIX is a power of 2. */ + while (mantissa > 0.0L) + { + mantissa *= 16.0L; + digit = (int) mantissa; + mantissa -= digit; + *p++ = digit + + (digit < 10 + ? '0' + : dp->conversion - 10); + if (precision > 0) + precision--; + } + while (precision > 0) + { + *p++ = '0'; + precision--; + } } -# else - sprintf (p, "%+.2d", exponent); -# endif - while (*p != '\0') - p++; } - else if (dp->conversion == 'g' || dp->conversion == 'G') + *p++ = dp->conversion - 'A' + 'P'; +# if WIDE_CHAR_VERSION { - if (precision == 0) - precision = 1; - /* precision >= 1. */ - - if (arg == 0.0L) - /* The exponent is 0, >= -4, < precision. - Use fixed-point notation. */ - { - size_t ndigits = precision; - /* Number of trailing zeroes that have to be - dropped. */ - size_t nzeroes = - (flags & FLAG_ALT ? 0 : precision - 1); - - --ndigits; - *p++ = '0'; - if ((flags & FLAG_ALT) || ndigits > nzeroes) - { - *p++ = decimal_point_char (); - while (ndigits > nzeroes) - { - --ndigits; - *p++ = '0'; - } - } - } - else - { - /* arg > 0.0L. */ - int exponent; - int adjusted; - char *digits; - size_t ndigits; - size_t nzeroes; - - exponent = floorlog10l (arg); - adjusted = 0; - for (;;) - { - digits = - scale10_round_decimal_long_double (arg, - (int)(precision - 1) - exponent); - if (digits == NULL) - { - END_LONG_DOUBLE_ROUNDING (); - goto out_of_memory; - } - ndigits = strlen (digits); - - if (ndigits == precision) - break; - if (ndigits < precision - 1 - || ndigits > precision + 1) - /* The exponent was not guessed - precisely enough. */ - abort (); - if (adjusted) - /* None of two values of exponent is - the right one. Prevent an endless - loop. */ - abort (); - free (digits); - if (ndigits < precision) - exponent -= 1; - else - exponent += 1; - adjusted = 1; - } - /* Here ndigits = precision. */ - - /* Determine the number of trailing zeroes - that have to be dropped. */ - nzeroes = 0; - if ((flags & FLAG_ALT) == 0) - while (nzeroes < ndigits - && digits[nzeroes] == '0') - nzeroes++; - - /* The exponent is now determined. */ - if (exponent >= -4 - && exponent < (long)precision) - { - /* Fixed-point notation: - max(exponent,0)+1 digits, then the - decimal point, then the remaining - digits without trailing zeroes. */ - if (exponent >= 0) - { - size_t count = exponent + 1; - /* Note: count <= precision = ndigits. */ - for (; count > 0; count--) - *p++ = digits[--ndigits]; - if ((flags & FLAG_ALT) || ndigits > nzeroes) - { - *p++ = decimal_point_char (); - while (ndigits > nzeroes) - { - --ndigits; - *p++ = digits[ndigits]; - } - } - } - else - { - size_t count = -exponent - 1; - *p++ = '0'; - *p++ = decimal_point_char (); - for (; count > 0; count--) - *p++ = '0'; - while (ndigits > nzeroes) - { - --ndigits; - *p++ = digits[ndigits]; - } - } - } - else - { - /* Exponential notation. */ - *p++ = digits[--ndigits]; - if ((flags & FLAG_ALT) || ndigits > nzeroes) - { - *p++ = decimal_point_char (); - while (ndigits > nzeroes) - { - --ndigits; - *p++ = digits[ndigits]; - } - } - *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ -# 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); - } + static const wchar_t decimal_format[] = + { '%', '+', 'd', '\0' }; + SNPRINTF (p, 6 + 1, decimal_format, exponent); } - else - abort (); -# else - /* arg is finite. */ - abort (); -# endif +# else + sprintf (p, "%+d", exponent); +# endif + while (*p != '\0') + p++; } 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') + if (dp->conversion == 'A') { *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } @@ -1806,7 +1564,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { int sign = 0; - if (signbit (arg)) /* arg < 0.0L or negative zero */ + if (signbit (arg)) /* arg < 0.0 or negative zero */ { sign = -1; arg = -arg; @@ -1821,7 +1579,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (arg > 0.0 && arg + arg == arg) { - if (dp->conversion >= 'A' && dp->conversion <= 'Z') + if (dp->conversion == 'A') { *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; } @@ -1832,59 +1590,93 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - if (!(arg == 0.0)) - abort (); + int exponent; + double mantissa; - pad_ptr = p; + if (arg > 0.0) + mantissa = printf_frexp (arg, &exponent); + else + { + exponent = 0; + mantissa = 0.0; + } - if (dp->conversion == 'f' || dp->conversion == 'F') + if (has_precision + && precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1) { - *p++ = '0'; - if ((flags & FLAG_ALT) || precision > 0) + /* Round the mantissa. */ + double tail = mantissa; + size_t q; + + for (q = precision; ; q--) { - *p++ = decimal_point_char (); - for (; precision > 0; precision--) - *p++ = '0'; + int digit = (int) tail; + tail -= digit; + if (q == 0) + { + if (digit & 1 ? tail >= 0.5 : tail > 0.5) + tail = 1 - tail; + else + tail = - tail; + break; + } + tail *= 16.0; } + if (tail != 0.0) + for (q = precision; q > 0; q--) + tail *= 0.0625; + mantissa += tail; } - 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 - 'A' + 'X'; + pad_ptr = p; + { + int digit; + + digit = (int) mantissa; + mantissa -= digit; + *p++ = '0' + digit; + if ((flags & FLAG_ALT) + || mantissa > 0.0 || precision > 0) + { + *p++ = decimal_point_char (); + /* This loop terminates because we assume + that FLT_RADIX is a power of 2. */ + while (mantissa > 0.0) + { + mantissa *= 16.0; + digit = (int) mantissa; + mantissa -= digit; + *p++ = digit + + (digit < 10 + ? '0' + : dp->conversion - 10); + if (precision > 0) + precision--; + } + while (precision > 0) + { *p++ = '0'; - } - *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'; + precision--; + } + } } - else if (dp->conversion == 'g' || dp->conversion == 'G') + *p++ = dp->conversion - 'A' + 'P'; +# if WIDE_CHAR_VERSION { - *p++ = '0'; - if (flags & FLAG_ALT) - { - size_t ndigits = - (precision > 0 ? precision - 1 : 0); - *p++ = decimal_point_char (); - for (; ndigits > 0; --ndigits) - *p++ = '0'; - } + static const wchar_t decimal_format[] = + { '%', '+', 'd', '\0' }; + SNPRINTF (p, 6 + 1, decimal_format, exponent); } - else - abort (); +# else + sprintf (p, "%+d", exponent); +# endif + while (*p != '\0') + p++; } } } -# 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) @@ -1946,10 +1738,32 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } #endif -#if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL - else if (dp->conversion == 'a' || dp->conversion == 'A') +#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL + else if ((dp->conversion == 'f' || dp->conversion == 'F' + || dp->conversion == 'e' || dp->conversion == 'E' + || dp->conversion == 'g' || dp->conversion == 'G' + || dp->conversion == 'a' || dp->conversion == 'A') + && (0 +# if NEED_PRINTF_INFINITE_DOUBLE + || (a.arg[dp->arg_index].type == TYPE_DOUBLE + /* The systems (mingw) which produce wrong output + for Inf, -Inf, and NaN also do so for -0.0. + Therefore we treat this case here as well. */ + && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double)) +# 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; @@ -2023,21 +1837,38 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } + /* 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 (type == TYPE_LONGDOUBLE) - tmp_length = - (unsigned int) ((LDBL_DIG + 1) - * 0.831 /* decimal -> hexadecimal */ - ) - + 1; /* turn floor into ceil */ - else - tmp_length = - (unsigned int) ((DBL_DIG + 1) - * 0.831 /* decimal -> hexadecimal */ - ) - + 1; /* turn floor into ceil */ +# if 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 NEED_PRINTF_LONG_DOUBLE +# if NEED_PRINTF_INFINITE_DOUBLE + if (type == TYPE_LONGDOUBLE) +# endif + if (dp->conversion == 'f' || dp->conversion == 'F') + { + long double arg = a.arg[dp->arg_index].a.a_longdouble; + if (!(isnanl (arg) || arg + arg == arg)) + { + /* arg is finite and nonzero. */ + int exponent = floorlog10l (arg < 0 ? -arg : arg); + if (exponent >= 0 && tmp_length < exponent + precision) + tmp_length = exponent + precision; + } + } +# endif /* Account for sign, decimal point etc. */ tmp_length = xsum (tmp_length, 12); @@ -2063,13 +1894,17 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar pad_ptr = NULL; p = tmp; + +# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE +# if NEED_PRINTF_INFINITE_DOUBLE if (type == TYPE_LONGDOUBLE) +# endif { long double arg = a.arg[dp->arg_index].a.a_longdouble; if (isnanl (arg)) { - if (dp->conversion == 'A') + if (dp->conversion >= 'A' && dp->conversion <= 'Z') { *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } @@ -2100,7 +1935,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (arg > 0.0L && arg + arg == arg) { - if (dp->conversion == 'A') + if (dp->conversion >= 'A' && dp->conversion <= 'Z') { *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; } @@ -2111,102 +1946,302 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - int exponent; - long double mantissa; +# if NEED_PRINTF_LONG_DOUBLE + pad_ptr = p; - if (arg > 0.0L) - mantissa = printf_frexpl (arg, &exponent); - else + if (dp->conversion == 'f' || dp->conversion == 'F') { - exponent = 0; - mantissa = 0.0L; + char *digits; + size_t ndigits; + + digits = + scale10_round_decimal_long_double (arg, precision); + if (digits == NULL) + { + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; + } + ndigits = strlen (digits); + + if (ndigits > precision) + do + { + --ndigits; + *p++ = digits[ndigits]; + } + while (ndigits > precision); + else + *p++ = '0'; + /* Here ndigits <= precision. */ + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + for (; precision > ndigits; precision--) + *p++ = '0'; + while (ndigits > 0) + { + --ndigits; + *p++ = digits[ndigits]; + } + } + + free (digits); } + else if (dp->conversion == 'e' || dp->conversion == 'E') + { + int exponent; - if (has_precision - && precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1) + if (arg == 0.0L) + { + exponent = 0; + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; + } + } + else + { + /* arg > 0.0L. */ + int adjusted; + char *digits; + size_t ndigits; + + exponent = floorlog10l (arg); + adjusted = 0; + for (;;) + { + digits = + scale10_round_decimal_long_double (arg, + (int)precision - exponent); + if (digits == NULL) + { + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; + } + ndigits = strlen (digits); + + if (ndigits == precision + 1) + break; + if (ndigits < precision + || ndigits > precision + 2) + /* The exponent was not guessed + precisely enough. */ + abort (); + if (adjusted) + /* None of two values of exponent is + the right one. Prevent an endless + loop. */ + abort (); + free (digits); + if (ndigits == precision) + exponent -= 1; + else + exponent += 1; + adjusted = 1; + } + + /* Here ndigits = precision+1. */ + *p++ = digits[--ndigits]; + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + while (ndigits > 0) + { + --ndigits; + *p++ = digits[ndigits]; + } + } + + free (digits); + } + + *p++ = dp->conversion; /* 'e' or 'E' */ +# 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') { - /* Round the mantissa. */ - long double tail = mantissa; - size_t q; + if (precision == 0) + precision = 1; + /* precision >= 1. */ + + if (arg == 0.0L) + /* The exponent is 0, >= -4, < precision. + Use fixed-point notation. */ + { + size_t ndigits = precision; + /* Number of trailing zeroes that have to be + dropped. */ + size_t nzeroes = + (flags & FLAG_ALT ? 0 : precision - 1); + + --ndigits; + *p++ = '0'; + if ((flags & FLAG_ALT) || ndigits > nzeroes) + { + *p++ = decimal_point_char (); + while (ndigits > nzeroes) + { + --ndigits; + *p++ = '0'; + } + } + } + else + { + /* arg > 0.0L. */ + int exponent; + int adjusted; + char *digits; + size_t ndigits; + size_t nzeroes; + + exponent = floorlog10l (arg); + adjusted = 0; + for (;;) + { + digits = + scale10_round_decimal_long_double (arg, + (int)(precision - 1) - exponent); + if (digits == NULL) + { + END_LONG_DOUBLE_ROUNDING (); + goto out_of_memory; + } + ndigits = strlen (digits); + + if (ndigits == precision) + break; + if (ndigits < precision - 1 + || ndigits > precision + 1) + /* The exponent was not guessed + precisely enough. */ + abort (); + if (adjusted) + /* None of two values of exponent is + the right one. Prevent an endless + loop. */ + abort (); + free (digits); + if (ndigits < precision) + exponent -= 1; + else + exponent += 1; + adjusted = 1; + } + /* Here ndigits = precision. */ + + /* Determine the number of trailing zeroes + that have to be dropped. */ + nzeroes = 0; + if ((flags & FLAG_ALT) == 0) + while (nzeroes < ndigits + && digits[nzeroes] == '0') + nzeroes++; - for (q = precision; ; q--) - { - int digit = (int) tail; - tail -= digit; - if (q == 0) + /* The exponent is now determined. */ + if (exponent >= -4 + && exponent < (long)precision) { - if (digit & 1 ? tail >= 0.5L : tail > 0.5L) - tail = 1 - tail; + /* 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 - tail = - tail; - break; + { + 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++; } - tail *= 16.0L; - } - if (tail != 0.0L) - for (q = precision; q > 0; q--) - tail *= 0.0625L; - mantissa += tail; - } - - *p++ = '0'; - *p++ = dp->conversion - 'A' + 'X'; - pad_ptr = p; - { - int digit; - digit = (int) mantissa; - mantissa -= digit; - *p++ = '0' + digit; - if ((flags & FLAG_ALT) - || mantissa > 0.0L || precision > 0) - { - *p++ = decimal_point_char (); - /* This loop terminates because we assume - that FLT_RADIX is a power of 2. */ - while (mantissa > 0.0L) - { - mantissa *= 16.0L; - digit = (int) mantissa; - mantissa -= digit; - *p++ = digit - + (digit < 10 - ? '0' - : dp->conversion - 10); - if (precision > 0) - precision--; - } - while (precision > 0) - { - *p++ = '0'; - precision--; - } - } - } - *p++ = dp->conversion - 'A' + 'P'; -# if WIDE_CHAR_VERSION - { - static const wchar_t decimal_format[] = - { '%', '+', 'd', '\0' }; - SNPRINTF (p, 6 + 1, decimal_format, exponent); + free (digits); + } } -# else - sprintf (p, "%+d", exponent); -# endif - while (*p != '\0') - p++; + 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') + if (dp->conversion >= 'A' && dp->conversion <= 'Z') { *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; } @@ -2219,7 +2254,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { int sign = 0; - if (signbit (arg)) /* arg < 0.0 or negative zero */ + if (signbit (arg)) /* arg < 0.0L or negative zero */ { sign = -1; arg = -arg; @@ -2234,7 +2269,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (arg > 0.0 && arg + arg == arg) { - if (dp->conversion == 'A') + if (dp->conversion >= 'A' && dp->conversion <= 'Z') { *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; } @@ -2245,93 +2280,59 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - int exponent; - double mantissa; + if (!(arg == 0.0)) + abort (); - if (arg > 0.0) - mantissa = printf_frexp (arg, &exponent); - else - { - exponent = 0; - mantissa = 0.0; - } + pad_ptr = p; - if (has_precision - && precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1) + if (dp->conversion == 'f' || dp->conversion == 'F') { - /* Round the mantissa. */ - double tail = mantissa; - size_t q; - - for (q = precision; ; q--) + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) { - int digit = (int) tail; - tail -= digit; - if (q == 0) - { - if (digit & 1 ? tail >= 0.5 : tail > 0.5) - tail = 1 - tail; - else - tail = - tail; - break; - } - tail *= 16.0; + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; } - if (tail != 0.0) - for (q = precision; q > 0; q--) - tail *= 0.0625; - mantissa += tail; } - - *p++ = '0'; - *p++ = dp->conversion - 'A' + 'X'; - pad_ptr = p; - { - int digit; - - digit = (int) mantissa; - mantissa -= digit; - *p++ = '0' + digit; - if ((flags & FLAG_ALT) - || mantissa > 0.0 || precision > 0) - { - *p++ = decimal_point_char (); - /* This loop terminates because we assume - that FLT_RADIX is a power of 2. */ - while (mantissa > 0.0) - { - mantissa *= 16.0; - digit = (int) mantissa; - mantissa -= digit; - *p++ = digit - + (digit < 10 - ? '0' - : dp->conversion - 10); - if (precision > 0) - precision--; - } - while (precision > 0) - { + 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'; - precision--; - } - } + } + *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'; } - *p++ = dp->conversion - 'A' + 'P'; -# if WIDE_CHAR_VERSION + else if (dp->conversion == 'g' || dp->conversion == 'G') { - static const wchar_t decimal_format[] = - { '%', '+', 'd', '\0' }; - SNPRINTF (p, 6 + 1, decimal_format, exponent); + *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 - sprintf (p, "%+d", exponent); -# endif - while (*p != '\0') - p++; + else + abort (); } } } +# endif + /* The generated string now extends from tmp to p, with the zero padding insertion point being at pad_ptr. */ if (has_width && p - tmp < width)