mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-08 17:42:12 +03:00
2.5-18.1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* Floating point output for `printf'.
|
||||
Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-2003, 2006, 2007 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
|
||||
@@ -71,7 +71,11 @@
|
||||
{ \
|
||||
register const int outc = (ch); \
|
||||
if (putc (outc, fp) == EOF) \
|
||||
return -1; \
|
||||
{ \
|
||||
if (buffer_malloced) \
|
||||
free (wbuffer); \
|
||||
return -1; \
|
||||
} \
|
||||
++done; \
|
||||
} while (0)
|
||||
|
||||
@@ -82,7 +86,11 @@
|
||||
if (len > 20) \
|
||||
{ \
|
||||
if (PUT (fp, wide ? (const char *) wptr : ptr, outlen) != outlen) \
|
||||
return -1; \
|
||||
{ \
|
||||
if (buffer_malloced) \
|
||||
free (wbuffer); \
|
||||
return -1; \
|
||||
} \
|
||||
ptr += outlen; \
|
||||
done += outlen; \
|
||||
} \
|
||||
@@ -101,7 +109,11 @@
|
||||
do \
|
||||
{ \
|
||||
if (PAD (fp, ch, len) != len) \
|
||||
return -1; \
|
||||
{ \
|
||||
if (buffer_malloced) \
|
||||
free (wbuffer); \
|
||||
return -1; \
|
||||
} \
|
||||
done += len; \
|
||||
} \
|
||||
while (0)
|
||||
@@ -138,9 +150,9 @@ static wchar_t *group_number (wchar_t *buf, wchar_t *bufend,
|
||||
|
||||
|
||||
int
|
||||
__printf_fp (FILE *fp,
|
||||
const struct printf_info *info,
|
||||
const void *const *args)
|
||||
___printf_fp (FILE *fp,
|
||||
const struct printf_info *info,
|
||||
const void *const *args)
|
||||
{
|
||||
/* The floating-point value to output. */
|
||||
union
|
||||
@@ -199,6 +211,11 @@ __printf_fp (FILE *fp,
|
||||
/* Nonzero if this is output on a wide character stream. */
|
||||
int wide = info->wide;
|
||||
|
||||
/* Buffer in which we produce the output. */
|
||||
wchar_t *wbuffer = NULL;
|
||||
/* Flag whether wbuffer is malloc'ed or not. */
|
||||
int buffer_malloced = 0;
|
||||
|
||||
auto wchar_t hack_digit (void);
|
||||
|
||||
wchar_t hack_digit (void)
|
||||
@@ -775,7 +792,7 @@ __printf_fp (FILE *fp,
|
||||
else
|
||||
{
|
||||
/* This is a special case. We don't need a factor because the
|
||||
numbers are in the range of 0.0 <= fp < 8.0. We simply
|
||||
numbers are in the range of 1.0 <= |fp| < 8.0. We simply
|
||||
shift it to the right place and divide it by 1.0 to get the
|
||||
leading digit. (Of course this division is not really made.) */
|
||||
assert (0 <= exponent && exponent < 3 &&
|
||||
@@ -789,17 +806,18 @@ __printf_fp (FILE *fp,
|
||||
|
||||
{
|
||||
int width = info->width;
|
||||
wchar_t *wbuffer, *wstartp, *wcp;
|
||||
int buffer_malloced;
|
||||
wchar_t *wstartp, *wcp;
|
||||
int chars_needed;
|
||||
int expscale;
|
||||
int intdig_max, intdig_no = 0;
|
||||
int fracdig_min, fracdig_max, fracdig_no = 0;
|
||||
int fracdig_min;
|
||||
int fracdig_max;
|
||||
int dig_max;
|
||||
int significant;
|
||||
int ngroups = 0;
|
||||
char spec = _tolower (info->spec);
|
||||
|
||||
if (_tolower (info->spec) == 'e')
|
||||
if (spec == 'e')
|
||||
{
|
||||
type = info->spec;
|
||||
intdig_max = 1;
|
||||
@@ -809,7 +827,7 @@ __printf_fp (FILE *fp,
|
||||
dig_max = INT_MAX; /* Unlimited. */
|
||||
significant = 1; /* Does not matter here. */
|
||||
}
|
||||
else if (_tolower (info->spec) == 'f')
|
||||
else if (spec == 'f')
|
||||
{
|
||||
type = 'f';
|
||||
fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
|
||||
@@ -906,7 +924,9 @@ __printf_fp (FILE *fp,
|
||||
}
|
||||
|
||||
/* Generate the needed number of fractional digits. */
|
||||
while (fracdig_no < fracdig_min
|
||||
int fracdig_no = 0;
|
||||
int added_zeros = 0;
|
||||
while (fracdig_no < fracdig_min + added_zeros
|
||||
|| (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0)))
|
||||
{
|
||||
++fracdig_no;
|
||||
@@ -917,7 +937,7 @@ __printf_fp (FILE *fp,
|
||||
{
|
||||
++fracdig_max;
|
||||
if (fracdig_min > 0)
|
||||
++fracdig_min;
|
||||
++added_zeros;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,11 +974,23 @@ __printf_fp (FILE *fp,
|
||||
{
|
||||
/* Process fractional digits. Terminate if not rounded or
|
||||
radix character is reached. */
|
||||
int removed = 0;
|
||||
while (*--wtp != decimalwc && *wtp == L'9')
|
||||
*wtp = '0';
|
||||
{
|
||||
*wtp = L'0';
|
||||
++removed;
|
||||
}
|
||||
if (removed == fracdig_min && added_zeros > 0)
|
||||
--added_zeros;
|
||||
if (*wtp != decimalwc)
|
||||
/* Round up. */
|
||||
(*wtp)++;
|
||||
else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt,
|
||||
0))
|
||||
/* This is a special case: the rounded number is 1.0,
|
||||
the format is 'g' or 'G', and the alternative format
|
||||
is selected. This means the result must be "1.". */
|
||||
--added_zeros;
|
||||
}
|
||||
|
||||
if (fracdig_no == 0 || *wtp == decimalwc)
|
||||
@@ -980,6 +1012,12 @@ __printf_fp (FILE *fp,
|
||||
{
|
||||
*wstartp = '1';
|
||||
exponent += expsign == 0 ? 1 : -1;
|
||||
|
||||
/* The above exponent adjustment could lead to 1.0e-00,
|
||||
e.g. for 0.999999999. Make sure exponent 0 always
|
||||
uses + sign. */
|
||||
if (exponent == 0)
|
||||
expsign = 0;
|
||||
}
|
||||
else if (intdig_no == dig_max)
|
||||
{
|
||||
@@ -1025,7 +1063,7 @@ __printf_fp (FILE *fp,
|
||||
|
||||
do_expo:
|
||||
/* Now remove unnecessary '0' at the end of the string. */
|
||||
while (fracdig_no > fracdig_min && *(wcp - 1) == L'0')
|
||||
while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L'0')
|
||||
{
|
||||
--wcp;
|
||||
--fracdig_no;
|
||||
@@ -1043,26 +1081,46 @@ __printf_fp (FILE *fp,
|
||||
/* Write the exponent if it is needed. */
|
||||
if (type != 'f')
|
||||
{
|
||||
*wcp++ = (wchar_t) type;
|
||||
*wcp++ = expsign ? L'-' : L'+';
|
||||
|
||||
/* Find the magnitude of the exponent. */
|
||||
expscale = 10;
|
||||
while (expscale <= exponent)
|
||||
expscale *= 10;
|
||||
|
||||
if (exponent < 10)
|
||||
/* Exponent always has at least two digits. */
|
||||
*wcp++ = L'0';
|
||||
if (__builtin_expect (expsign != 0 && exponent == 4 && spec == 'g', 0))
|
||||
{
|
||||
/* This is another special case. The exponent of the number is
|
||||
really smaller than -4, which requires the 'e'/'E' format.
|
||||
But after rounding the number has an exponent of -4. */
|
||||
assert (wcp >= wstartp + 1);
|
||||
assert (wstartp[0] == L'1');
|
||||
__wmemcpy (wstartp, L"0.0001", 6);
|
||||
wstartp[1] = decimalwc;
|
||||
if (wcp >= wstartp + 2)
|
||||
{
|
||||
wmemset (wstartp + 6, L'0', wcp - (wstartp + 2));
|
||||
wcp += 4;
|
||||
}
|
||||
else
|
||||
wcp += 5;
|
||||
}
|
||||
else
|
||||
do
|
||||
{
|
||||
expscale /= 10;
|
||||
*wcp++ = L'0' + (exponent / expscale);
|
||||
exponent %= expscale;
|
||||
}
|
||||
while (expscale > 10);
|
||||
*wcp++ = L'0' + exponent;
|
||||
{
|
||||
*wcp++ = (wchar_t) type;
|
||||
*wcp++ = expsign ? L'-' : L'+';
|
||||
|
||||
/* Find the magnitude of the exponent. */
|
||||
expscale = 10;
|
||||
while (expscale <= exponent)
|
||||
expscale *= 10;
|
||||
|
||||
if (exponent < 10)
|
||||
/* Exponent always has at least two digits. */
|
||||
*wcp++ = L'0';
|
||||
else
|
||||
do
|
||||
{
|
||||
expscale /= 10;
|
||||
*wcp++ = L'0' + (exponent / expscale);
|
||||
exponent %= expscale;
|
||||
}
|
||||
while (expscale > 10);
|
||||
*wcp++ = L'0' + exponent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute number of characters which must be filled with the padding
|
||||
@@ -1108,8 +1166,12 @@ __printf_fp (FILE *fp,
|
||||
buffer = (char *) malloc (2 + chars_needed + decimal_len
|
||||
+ ngroups * thousands_sep_len);
|
||||
if (buffer == NULL)
|
||||
/* Signal an error to the caller. */
|
||||
return -1;
|
||||
{
|
||||
/* Signal an error to the caller. */
|
||||
if (buffer_malloced)
|
||||
free (wbuffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
buffer = (char *) alloca (2 + chars_needed + decimal_len
|
||||
@@ -1153,7 +1215,8 @@ __printf_fp (FILE *fp,
|
||||
}
|
||||
return done;
|
||||
}
|
||||
libc_hidden_def (__printf_fp)
|
||||
ldbl_hidden_def (___printf_fp, __printf_fp)
|
||||
ldbl_strong_alias (___printf_fp, __printf_fp)
|
||||
|
||||
/* Return the number of extra grouping characters that will be inserted
|
||||
into a number with INTDIG_MAX integer digits. */
|
||||
|
Reference in New Issue
Block a user