From 7cd87873c8336cb43c0452df4b11238f014be8a1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 3 Nov 2007 16:52:20 +0100 Subject: [PATCH] Fix *printf behaviour in out-of-memory situations on MacOS X and *BSD. --- doc/functions/fprintf.texi | 3 + doc/functions/printf.texi | 3 + doc/functions/snprintf.texi | 3 + doc/functions/sprintf.texi | 3 + doc/functions/vfprintf.texi | 3 + doc/functions/vprintf.texi | 3 + doc/functions/vsnprintf.texi | 3 + doc/functions/vsprintf.texi | 3 + lib/vasnprintf.c | 622 +++++++++++++++++++++++++++++++++++++++++-- m4/fprintf-posix.m4 | 14 +- m4/printf.m4 | 171 +++++++++--- m4/snprintf-posix.m4 | 22 +- m4/sprintf-posix.m4 | 14 +- m4/vasnprintf-posix.m4 | 18 +- m4/vasnprintf.m4 | 25 +- m4/vasprintf-posix.m4 | 18 +- m4/vfprintf-posix.m4 | 14 +- m4/vsnprintf-posix.m4 | 22 +- m4/vsprintf-posix.m4 | 14 +- modules/fprintf-posix | 1 + modules/snprintf-posix | 1 + modules/sprintf-posix | 1 + modules/vasnprintf-posix | 1 + modules/vasprintf-posix | 1 + modules/vfprintf-posix | 1 + modules/vsnprintf-posix | 1 + modules/vsprintf-posix | 1 + 27 files changed, 879 insertions(+), 107 deletions(-) diff --git a/doc/functions/fprintf.texi b/doc/functions/fprintf.texi index 47382e37e..5c76d3d87 100644 --- a/doc/functions/fprintf.texi +++ b/doc/functions/fprintf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/functions/printf.texi b/doc/functions/printf.texi index 9a729fd28..dc49ed544 100644 --- a/doc/functions/printf.texi +++ b/doc/functions/printf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/functions/snprintf.texi b/doc/functions/snprintf.texi index fabc2da9b..a2a81bcff 100644 --- a/doc/functions/snprintf.texi +++ b/doc/functions/snprintf.texi @@ -45,6 +45,9 @@ printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. @item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. +@item This function does not truncate the result as specified in C99 on some platforms: mingw. @item diff --git a/doc/functions/sprintf.texi b/doc/functions/sprintf.texi index 3ab986f50..458a36f8a 100644 --- a/doc/functions/sprintf.texi +++ b/doc/functions/sprintf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/functions/vfprintf.texi b/doc/functions/vfprintf.texi index b499323c6..5726dcb0f 100644 --- a/doc/functions/vfprintf.texi +++ b/doc/functions/vfprintf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/functions/vprintf.texi b/doc/functions/vprintf.texi index cb59dfcd4..62f5fe974 100644 --- a/doc/functions/vprintf.texi +++ b/doc/functions/vprintf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/functions/vsnprintf.texi b/doc/functions/vsnprintf.texi index 99e792db6..36d477807 100644 --- a/doc/functions/vsnprintf.texi +++ b/doc/functions/vsnprintf.texi @@ -45,6 +45,9 @@ printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. @item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. +@item This function does not truncate the result as specified in C99 on some platforms: mingw. @item diff --git a/doc/functions/vsprintf.texi b/doc/functions/vsprintf.texi index 1da495971..bc0ed4c01 100644 --- a/doc/functions/vsprintf.texi +++ b/doc/functions/vsprintf.texi @@ -37,6 +37,9 @@ NetBSD 3.0, Cygwin 2006, mingw. printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded with zeroes) on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 2007, mingw. +@item +This function can crash in out-of-memory conditions on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 6b4d6c6a5..55202cbe8 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -88,18 +88,17 @@ /* Checked size_t computations. */ #include "xsize.h" -#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL +#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL # include # include "float+.h" -# include "fpucw.h" #endif -#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL +#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL # include # include "isnan.h" #endif -#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL +#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL # include # include "isnanl-nolibm.h" # include "fpucw.h" @@ -200,7 +199,7 @@ local_wcslen (const wchar_t *s) /* Here we need to call the native sprintf, not rpl_sprintf. */ #undef sprintf -#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL +#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL /* Determine the decimal-point character according to the current locale. */ # ifndef decimal_point_char_defined # define decimal_point_char_defined 1 @@ -227,7 +226,7 @@ decimal_point_char () # endif #endif -#if NEED_PRINTF_INFINITE_DOUBLE && !defined IN_LIBINTL +#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL /* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ static int @@ -238,7 +237,7 @@ is_infinite_or_zero (double x) #endif -#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !defined IN_LIBINTL +#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL /* Equivalent to !isfinite(x), but does not require libm. */ static int @@ -249,7 +248,7 @@ is_infinitel (long double x) #endif -#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL +#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL /* Converting 'long double' to decimal without rare rounding bugs requires real bignums. We use the naming conventions of GNU gmp, but vastly simpler @@ -795,6 +794,8 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes) return c_ptr; } +# if NEED_PRINTF_LONG_DOUBLE + /* Assuming x is finite and >= 0: write x as x = 2^e * m, where m is a bignum. Return the allocated memory in case of success, NULL in case of memory @@ -823,8 +824,8 @@ decode_long_double (long double x, int *ep, mpn_t *mp) 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', doesn't matter). */ -# if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0 -# if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2 +# if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0 +# if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2 { mp_limb_t hi, lo; y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2)); @@ -839,7 +840,7 @@ decode_long_double (long double x, int *ep, mpn_t *mp) abort (); m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo; } -# else +# else { mp_limb_t d; y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS); @@ -849,8 +850,8 @@ decode_long_double (long double x, int *ep, mpn_t *mp) abort (); m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d; } +# endif # endif -# endif for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; ) { mp_limb_t hi, lo; @@ -876,17 +877,101 @@ decode_long_double (long double x, int *ep, mpn_t *mp) return m.limbs; } -/* Assuming x is finite and >= 0, and n is an integer: +# endif + +# if NEED_PRINTF_DOUBLE + +/* Assuming x is finite and >= 0: + write x as x = 2^e * m, where m is a bignum. + Return the allocated memory in case of success, NULL in case of memory + allocation failure. */ +static void * +decode_double (double x, int *ep, mpn_t *mp) +{ + mpn_t m; + int exp; + double y; + size_t i; + + /* Allocate memory for result. */ + m.nlimbs = (DBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; + m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t)); + if (m.limbs == NULL) + return NULL; + /* Split into exponential part and mantissa. */ + 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 + latter is an integer. */ + /* Convert the mantissa (y * 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', + doesn't matter). */ +# if (DBL_MANT_BIT % GMP_LIMB_BITS) != 0 +# if (DBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2 + { + mp_limb_t hi, lo; + y *= (mp_limb_t) 1 << (DBL_MANT_BIT % (GMP_LIMB_BITS / 2)); + hi = (int) y; + y -= hi; + if (!(y >= 0.0 && y < 1.0)) + abort (); + y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); + lo = (int) y; + y -= lo; + if (!(y >= 0.0 && y < 1.0)) + abort (); + m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo; + } +# else + { + mp_limb_t d; + y *= (mp_limb_t) 1 << (DBL_MANT_BIT % GMP_LIMB_BITS); + d = (int) y; + y -= d; + if (!(y >= 0.0 && y < 1.0)) + abort (); + m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = d; + } +# endif +# endif + for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; ) + { + mp_limb_t hi, lo; + y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); + hi = (int) y; + y -= hi; + if (!(y >= 0.0 && y < 1.0)) + abort (); + y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); + lo = (int) y; + y -= lo; + if (!(y >= 0.0 && y < 1.0)) + abort (); + m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo; + } + if (!(y == 0.0)) + abort (); + /* Normalise. */ + while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0) + m.nlimbs--; + *mp = m; + *ep = exp - DBL_MANT_BIT; + return m.limbs; +} + +# endif + +/* Assuming x = 2^e * m 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) +scale10_round_decimal_decoded (int e, mpn_t m, void *memory, 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; @@ -1099,6 +1184,44 @@ scale10_round_decimal_long_double (long double x, int n) return digits; } +# if NEED_PRINTF_LONG_DOUBLE + +/* 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) +{ + int e; + mpn_t m; + void *memory = decode_long_double (x, &e, &m); + return scale10_round_decimal_decoded (e, m, memory, n); +} + +# endif + +# if NEED_PRINTF_DOUBLE + +/* 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_double (double x, int n) +{ + int e; + mpn_t m; + void *memory = decode_double (x, &e, &m); + return scale10_round_decimal_decoded (e, m, memory, n); +} + +# endif + +# if NEED_PRINTF_LONG_DOUBLE + /* Assuming x is finite and > 0: Return an approximation for n with 10^n <= x < 10^(n+1). The approximation is usually the right n, but may be off by 1 sometimes. */ @@ -1186,6 +1309,99 @@ floorlog10l (long double x) return (int) l + (l < 0 ? -1 : 0); } +# endif + +# if NEED_PRINTF_DOUBLE + +/* Assuming x is finite and > 0: + Return an approximation for n with 10^n <= x < 10^(n+1). + The approximation is usually the right n, but may be off by 1 sometimes. */ +static int +floorlog10 (double x) +{ + int exp; + double y; + double z; + double l; + + /* Split into exponential part and mantissa. */ + y = frexp (x, &exp); + if (!(y >= 0.0 && y < 1.0)) + abort (); + if (y == 0.0) + return INT_MIN; + if (y < 0.5) + { + while (y < (1.0 / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2)))) + { + y *= 1.0 * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2)); + exp -= GMP_LIMB_BITS; + } + if (y < (1.0 / (1 << 16))) + { + y *= 1.0 * (1 << 16); + exp -= 16; + } + if (y < (1.0 / (1 << 8))) + { + y *= 1.0 * (1 << 8); + exp -= 8; + } + if (y < (1.0 / (1 << 4))) + { + y *= 1.0 * (1 << 4); + exp -= 4; + } + if (y < (1.0 / (1 << 2))) + { + y *= 1.0 * (1 << 2); + exp -= 2; + } + if (y < (1.0 / (1 << 1))) + { + y *= 1.0 * (1 << 1); + exp -= 1; + } + } + if (!(y >= 0.5 && y < 1.0)) + abort (); + /* Compute an approximation for l = log2(x) = exp + log2(y). */ + l = exp; + z = y; + if (z < 0.70710678118654752444) + { + z *= 1.4142135623730950488; + l -= 0.5; + } + if (z < 0.8408964152537145431) + { + z *= 1.1892071150027210667; + l -= 0.25; + } + if (z < 0.91700404320467123175) + { + z *= 1.0905077326652576592; + l -= 0.125; + } + if (z < 0.9576032806985736469) + { + z *= 1.0442737824274138403; + l -= 0.0625; + } + /* Now 0.95 <= z <= 1.01. */ + z = 1 - z; + /* log(1-z) = - z - z^2/2 - z^3/3 - z^4/4 - ... + Four terms are enough to get an approximation with error < 10^-7. */ + l -= z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25))); + /* Finally multiply with log(2)/log(10), yields an approximation for + log10(x). */ + l *= 0.30102999566398119523; + /* Round down to the next integer. */ + return (int) l + (l < 0 ? -1 : 0); +} + +# endif + #endif DCHAR_T * @@ -2290,13 +2506,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } #endif -#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_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 +# if NEED_PRINTF_DOUBLE + || a.arg[dp->arg_index].type == TYPE_DOUBLE +# elif 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. @@ -2313,7 +2531,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # endif )) { -# if NEED_PRINTF_INFINITE_DOUBLE && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) +# if (NEED_PRINTF_DOUBLE || 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; @@ -2396,17 +2614,21 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, precision = 6; /* Allocate a temporary buffer of sufficient size. */ -# if NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE +# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE + tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1); +# elif 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; +# elif NEED_PRINTF_DOUBLE + tmp_length = DBL_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 NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE if (type == TYPE_LONGDOUBLE) # endif if (dp->conversion == 'f' || dp->conversion == 'F') @@ -2421,6 +2643,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } } # endif +# if NEED_PRINTF_DOUBLE +# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE + if (type == TYPE_DOUBLE) +# endif + if (dp->conversion == 'f' || dp->conversion == 'F') + { + double arg = a.arg[dp->arg_index].a.a_double; + if (!(isnan (arg) || arg + arg == arg)) + { + /* arg is finite and nonzero. */ + int exponent = floorlog10 (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); @@ -2448,7 +2686,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, p = tmp; # if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE -# if NEED_PRINTF_INFINITE_DOUBLE +# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE if (type == TYPE_LONGDOUBLE) # endif { @@ -2808,13 +3046,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, END_LONG_DOUBLE_ROUNDING (); } } -# if NEED_PRINTF_INFINITE_DOUBLE +# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE else # endif # endif -# if NEED_PRINTF_INFINITE_DOUBLE +# if NEED_PRINTF_DOUBLE || 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)) @@ -2832,7 +3069,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, { 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; @@ -2858,6 +3095,332 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } else { +# if NEED_PRINTF_DOUBLE + pad_ptr = p; + + if (dp->conversion == 'f' || dp->conversion == 'F') + { + char *digits; + size_t ndigits; + + digits = + scale10_round_decimal_double (arg, precision); + if (digits == NULL) + 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 (arg == 0.0) + { + exponent = 0; + *p++ = '0'; + if ((flags & FLAG_ALT) || precision > 0) + { + *p++ = decimal_point_char (); + for (; precision > 0; precision--) + *p++ = '0'; + } + } + else + { + /* arg > 0.0. */ + int adjusted; + char *digits; + size_t ndigits; + + exponent = floorlog10 (arg); + adjusted = 0; + for (;;) + { + digits = + scale10_round_decimal_double (arg, + (int)precision - exponent); + if (digits == NULL) + 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[] = + /* Produce the same number of exponent digits + as the native printf implementation. */ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + { '%', '+', '.', '3', 'd', '\0' }; +# else + { '%', '+', '.', '2', 'd', '\0' }; +# endif + SNPRINTF (p, 6 + 1, decimal_format, exponent); + } + while (*p != '\0') + p++; +# else + { + static const char decimal_format[] = + /* Produce the same number of exponent digits + as the native printf implementation. */ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + "%+.3d"; +# else + "%+.2d"; +# endif + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, decimal_format, exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, decimal_format, exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } + } +# endif + } + else if (dp->conversion == 'g' || dp->conversion == 'G') + { + if (precision == 0) + precision = 1; + /* precision >= 1. */ + + if (arg == 0.0) + /* 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.0. */ + int exponent; + int adjusted; + char *digits; + size_t ndigits; + size_t nzeroes; + + exponent = floorlog10 (arg); + adjusted = 0; + for (;;) + { + digits = + scale10_round_decimal_double (arg, + (int)(precision - 1) - exponent); + if (digits == NULL) + 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[] = + /* Produce the same number of exponent digits + as the native printf implementation. */ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + { '%', '+', '.', '3', 'd', '\0' }; +# else + { '%', '+', '.', '2', 'd', '\0' }; +# endif + SNPRINTF (p, 6 + 1, decimal_format, exponent); + } + while (*p != '\0') + p++; +# else + { + static const char decimal_format[] = + /* Produce the same number of exponent digits + as the native printf implementation. */ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + "%+.3d"; +# else + "%+.2d"; +# endif + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, decimal_format, exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, decimal_format, exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } + } +# endif + } + + free (digits); + } + } + else + abort (); +# else + /* arg is finite. */ if (!(arg == 0.0)) abort (); @@ -2886,9 +3449,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, *p++ = '+'; /* Produce the same number of exponent digits as the native printf implementation. */ -# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ *p++ = '0'; -# endif +# endif *p++ = '0'; *p++ = '0'; } @@ -2906,6 +3469,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, } else abort (); +# endif } } } diff --git a/m4/fprintf-posix.m4 b/m4/fprintf-posix.m4 index dfade559f..9908f9412 100644 --- a/m4/fprintf-posix.m4 +++ b/m4/fprintf-posix.m4 @@ -1,4 +1,4 @@ -# fprintf-posix.m4 serial 7 +# fprintf-posix.m4 serial 8 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_fprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -38,9 +39,13 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - # fprintf exists and is already POSIX - # compliant. - gl_cv_func_fprintf_posix=yes + case "$gl_cv_func_printf_enomem" in + *yes) + # fprintf exists and is already + # POSIX compliant. + gl_cv_func_fprintf_posix=yes + ;; + esac ;; esac ;; @@ -69,6 +74,7 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_FPRINTF fi diff --git a/m4/printf.m4 b/m4/printf.m4 index 8de382b4f..ab5698edc 100644 --- a/m4/printf.m4 +++ b/m4/printf.m4 @@ -1,4 +1,4 @@ -# printf.m4 serial 17 +# printf.m4 serial 18 dnl Copyright (C) 2003, 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -721,6 +721,109 @@ changequote([,])dnl ]) ]) +dnl Test whether the *printf family of functions recovers gracefully in case +dnl of an out-of-memory condition, or whether it crashes the entire program. +dnl Result is gl_cv_func_printf_enomem. + +AC_DEFUN([gl_PRINTF_ENOMEM], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether printf survives out-of-memory conditions], + [gl_cv_func_printf_enomem], + [ + if test "$cross_compiling" = no; then + AC_LANG_CONFTEST([AC_LANG_SOURCE([ +changequote(,)dnl +#include +#include +#include +#include +#include +int main() +{ + struct rlimit limit; + int ret; + /* Some printf implementations allocate temporary space with malloc. */ + /* On BSD systems, malloc() is limited by RLIMIT_DATA. */ +#ifdef RLIMIT_DATA + if (getrlimit (RLIMIT_DATA, &limit) < 0) + return 77; + if (limit.rlim_max == RLIM_INFINITY || limit.rlim_max > 5000000) + limit.rlim_max = 5000000; + limit.rlim_cur = limit.rlim_max; + if (setrlimit (RLIMIT_DATA, &limit) < 0) + return 77; +#endif + /* On Linux systems, malloc() is limited by RLIMIT_AS. */ +#ifdef RLIMIT_AS + if (getrlimit (RLIMIT_AS, &limit) < 0) + return 77; + if (limit.rlim_max == RLIM_INFINITY || limit.rlim_max > 5000000) + limit.rlim_max = 5000000; + limit.rlim_cur = limit.rlim_max; + if (setrlimit (RLIMIT_AS, &limit) < 0) + return 77; +#endif + /* Some printf implementations allocate temporary space on the stack. */ +#ifdef RLIMIT_STACK + if (getrlimit (RLIMIT_STACK, &limit) < 0) + return 77; + if (limit.rlim_max == RLIM_INFINITY || limit.rlim_max > 5000000) + limit.rlim_max = 5000000; + limit.rlim_cur = limit.rlim_max; + if (setrlimit (RLIMIT_STACK, &limit) < 0) + return 77; +#endif + ret = printf ("%.5000000f", 1.0); + return !(ret == 5000002 || (ret < 0 && errno == ENOMEM)); +} +changequote([,])dnl + ])]) + if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then + (./conftest + result=$? + if test $result != 0 && test $result != 77; then result=1; fi + exit $result + ) >/dev/null 2>/dev/null + case $? in + 0) gl_cv_func_printf_enomem="yes" ;; + 77) gl_cv_func_printf_enomem="guessing no" ;; + *) gl_cv_func_printf_enomem="no" ;; + esac + else + gl_cv_func_printf_enomem="guessing no" + fi + rm -fr conftest* + else +changequote(,)dnl + case "$host_os" in + # Guess yes on glibc systems. + *-gnu*) gl_cv_func_printf_enomem="guessing yes";; + # Guess yes on Solaris. + solaris*) gl_cv_func_printf_enomem="guessing yes";; + # Guess yes on AIX. + aix*) gl_cv_func_printf_enomem="guessing yes";; + # Guess yes on HP-UX/hppa. + hpux*) case "$host_cpu" in + hppa*) gl_cv_func_printf_enomem="guessing yes";; + *) gl_cv_func_printf_enomem="guessing no";; + esac + ;; + # Guess yes on IRIX. + irix*) gl_cv_func_printf_enomem="guessing yes";; + # Guess yes on OSF/1. + osf*) gl_cv_func_printf_enomem="guessing yes";; + # Guess yes on BeOS. + beos*) gl_cv_func_printf_enomem="guessing yes";; + # If we don't know, assume the worst. + *) gl_cv_func_printf_enomem="guessing no";; + esac +changequote([,])dnl + fi + ]) +]) + dnl Test whether the snprintf function exists. (ISO C99, POSIX:2001) dnl Result is ac_cv_func_snprintf. @@ -1039,11 +1142,12 @@ dnl 7 = gl_PRINTF_DIRECTIVE_N dnl 8 = gl_PRINTF_POSITIONS dnl 9 = gl_PRINTF_FLAG_GROUPING dnl 10 = gl_PRINTF_FLAG_ZERO -dnl 11 = gl_SNPRINTF_PRESENCE -dnl 12 = gl_SNPRINTF_TRUNCATION_C99 -dnl 13 = gl_SNPRINTF_RETVAL_C99 -dnl 14 = gl_SNPRINTF_DIRECTIVE_N -dnl 15 = gl_VSNPRINTF_ZEROSIZE_C99 +dnl 11 = gl_PRINTF_ENOMEM +dnl 12 = gl_SNPRINTF_PRESENCE +dnl 13 = gl_SNPRINTF_TRUNCATION_C99 +dnl 14 = gl_SNPRINTF_RETVAL_C99 +dnl 15 = gl_SNPRINTF_DIRECTIVE_N +dnl 16 = gl_VSNPRINTF_ZEROSIZE_C99 dnl dnl 1 = checking whether printf supports size specifiers as in C99... dnl 2 = checking whether printf supports 'long double' arguments... @@ -1055,33 +1159,34 @@ dnl 7 = checking whether printf supports the 'n' directive... dnl 8 = checking whether printf supports POSIX/XSI format strings with positions... dnl 9 = checking whether printf supports the grouping flag... dnl 10 = checking whether printf supports the zero flag correctly... -dnl 11 = checking for snprintf... -dnl 12 = checking whether snprintf truncates the result as in C99... -dnl 13 = checking whether snprintf returns a byte count as in C99... -dnl 14 = checking whether snprintf fully supports the 'n' directive... -dnl 15 = checking whether vsnprintf respects a zero size as in C99... +dnl 11 = checking whether printf survives out-of-memory conditions... +dnl 12 = checking for snprintf... +dnl 13 = checking whether snprintf truncates the result as in C99... +dnl 14 = checking whether snprintf returns a byte count as in C99... +dnl 15 = checking whether snprintf fully supports the 'n' directive... +dnl 16 = checking whether vsnprintf respects a zero size as in C99... dnl dnl . = yes, # = no. dnl -dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -dnl glibc 2.5 . . . . . . . . . . . . . . . -dnl glibc 2.3.6 . . . . # . . . . . . . . . . -dnl FreeBSD 5.4, 6.1 . . . . # . . . . # . . . . . -dnl MacOS X 10.3.9 . . . . # . . . . # . . . . . -dnl OpenBSD 3.9, 4.0 . ? ? ? # ? . . ? ? . . . ? ? -dnl Cygwin 2007 (= Cygwin 1.5.24) . . . . # # . . . # . . . . . -dnl Cygwin 2006 (= Cygwin 1.5.19) # . . . # # . . # # . . . . . -dnl Solaris 10 . . # # # . . . . # . . . . . -dnl Solaris 2.6 ... 9 # . # # # # . . . # . . . . . -dnl Solaris 2.5.1 # . # # # # . . . # # # # # # -dnl AIX 5.2 . . # # # . . . . # . . . . . -dnl AIX 4.3.2, 5.1 # . # # # # . . . # . . . . . -dnl HP-UX 11.31 . . . . # . . . . # . . # # . -dnl HP-UX 10.20, 11.{00,11,23} # . . . # # . . . # . . # # # -dnl IRIX 6.5 # . # # # # . . . # . . # . . -dnl OSF/1 5.1 # . # # # # . . . # . . # . # -dnl OSF/1 4.0d # . # # # # . . . # # # # # # -dnl NetBSD 4.0 . ? ? ? ? ? . . ? ? . . . ? ? -dnl NetBSD 3.0 . . . . # # . # # # . . . . . -dnl BeOS # # . # # # . # . . . . . . . -dnl mingw # # # # # # . # # # . # # # . +dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 +dnl glibc 2.5 . . . . . . . . . . . . . . . . +dnl glibc 2.3.6 . . . . # . . . . . . . . . . . +dnl FreeBSD 5.4, 6.1 . . . . # . . . . # # . . . . . +dnl MacOS X 10.3.9 . . . . # . . . . # # . . . . . +dnl OpenBSD 3.9, 4.0 . ? ? ? # ? . . ? ? ? . . . ? ? +dnl Cygwin 2007 (= Cygwin 1.5.24) . . . . # # . . . # ? . . . . . +dnl Cygwin 2006 (= Cygwin 1.5.19) # . . . # # . . # # ? . . . . . +dnl Solaris 10 . . # # # . . . . # . . . . . . +dnl Solaris 2.6 ... 9 # . # # # # . . . # . . . . . . +dnl Solaris 2.5.1 # . # # # # . . . # . # # # # # +dnl AIX 5.2 . . # # # . . . . # . . . . . . +dnl AIX 4.3.2, 5.1 # . # # # # . . . # . . . . . . +dnl HP-UX 11.31 . . . . # . . . . # . . . # # . +dnl HP-UX 10.20, 11.{00,11,23} # . . . # # . . . # . . . # # # +dnl IRIX 6.5 # . # # # # . . . # . . . # . . +dnl OSF/1 5.1 # . # # # # . . . # . . . # . # +dnl OSF/1 4.0d # . # # # # . . . # . # # # # # +dnl NetBSD 4.0 . ? ? ? ? ? . . ? ? ? . . . ? ? +dnl NetBSD 3.0 . . . . # # . # # # # . . . . . +dnl BeOS # # . # # # . # . . ? . . . . . +dnl mingw # # # # # # . # # # ? . # # # . diff --git a/m4/snprintf-posix.m4 b/m4/snprintf-posix.m4 index d7d451124..6353d9c63 100644 --- a/m4/snprintf-posix.m4 +++ b/m4/snprintf-posix.m4 @@ -1,4 +1,4 @@ -# snprintf-posix.m4 serial 8 +# snprintf-posix.m4 serial 9 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_snprintf_posix=no AC_CHECK_FUNCS([snprintf]) if test $ac_cv_func_snprintf = yes; then @@ -44,17 +45,21 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - case "$gl_cv_func_snprintf_truncation_c99" in + case "$gl_cv_func_printf_enomem" in *yes) - case "$gl_cv_func_snprintf_retval_c99" in + case "$gl_cv_func_snprintf_truncation_c99" in *yes) - case "$gl_cv_func_snprintf_directive_n" in + case "$gl_cv_func_snprintf_retval_c99" in *yes) - case "$gl_cv_func_vsnprintf_zerosize_c99" in + case "$gl_cv_func_snprintf_directive_n" in *yes) - # snprintf exists and is - # already POSIX compliant. - gl_cv_func_snprintf_posix=yes + case "$gl_cv_func_vsnprintf_zerosize_c99" in + *yes) + # snprintf exists and is + # already POSIX compliant. + gl_cv_func_snprintf_posix=yes + ;; + esac ;; esac ;; @@ -92,6 +97,7 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_SNPRINTF fi diff --git a/m4/sprintf-posix.m4 b/m4/sprintf-posix.m4 index 6fc75231f..8e6fcaa86 100644 --- a/m4/sprintf-posix.m4 +++ b/m4/sprintf-posix.m4 @@ -1,4 +1,4 @@ -# sprintf-posix.m4 serial 7 +# sprintf-posix.m4 serial 8 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_sprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -38,9 +39,13 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - # sprintf exists and is already POSIX - # compliant. - gl_cv_func_sprintf_posix=yes + case "$gl_cv_func_printf_enomem" in + *yes) + # sprintf exists and is already + # POSIX compliant. + gl_cv_func_sprintf_posix=yes + ;; + esac ;; esac ;; @@ -69,6 +74,7 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_SPRINTF fi diff --git a/m4/vasnprintf-posix.m4 b/m4/vasnprintf-posix.m4 index ecc075f8c..73b10bafa 100644 --- a/m4/vasnprintf-posix.m4 +++ b/m4/vasnprintf-posix.m4 @@ -1,4 +1,4 @@ -# vasnprintf-posix.m4 serial 8 +# vasnprintf-posix.m4 serial 9 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_vasnprintf_posix=no AC_CHECK_FUNCS_ONCE([vasnprintf]) case "$gl_cv_func_printf_sizes_c99" in @@ -39,11 +40,15 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - if test $ac_cv_func_vasnprintf = yes; then - # vasnprintf exists and is already - # POSIX compliant. - gl_cv_func_vasnprintf_posix=yes - fi + case "$gl_cv_func_printf_enomem" in + *yes) + if test $ac_cv_func_vasnprintf = yes; then + # vasnprintf exists and is already + # POSIX compliant. + gl_cv_func_vasnprintf_posix=yes + fi + ;; + esac ;; esac ;; @@ -72,6 +77,7 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF fi ]) diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4 index ef2de787f..e9733354e 100644 --- a/m4/vasnprintf.m4 +++ b/m4/vasnprintf.m4 @@ -1,4 +1,4 @@ -# vasnprintf.m4 serial 20 +# vasnprintf.m4 serial 21 dnl Copyright (C) 2002-2004, 2006-2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -178,6 +178,28 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_ZERO], esac ]) +# Extra prerequisites of lib/vasnprintf.c for surviving out-of-memory +# conditions. +AC_DEFUN([gl_PREREQ_VASNPRINTF_ENOMEM], +[ + AC_REQUIRE([gl_PRINTF_ENOMEM]) + case "$gl_cv_func_printf_enomem" in + *yes) + ;; + *) + AC_DEFINE([NEED_PRINTF_ENOMEM], 1, + [Define if the vasnprintf implementation needs special code for + surviving out-of-memory conditions.]) + AC_DEFINE([NEED_PRINTF_DOUBLE], 1, + [Define if the vasnprintf implementation needs special code for + 'double' arguments.]) + AC_DEFINE([NEED_PRINTF_LONG_DOUBLE], 1, + [Define if the vasnprintf implementation needs special code for + 'long double' arguments.]) + ;; + esac +]) + # Prerequisites of lib/vasnprintf.c including all extras for POSIX compliance. AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_EXTRAS], [ @@ -189,6 +211,7 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_EXTRAS], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM ]) # Prerequisites of lib/asnprintf.c. diff --git a/m4/vasprintf-posix.m4 b/m4/vasprintf-posix.m4 index ab26ef594..9d63ea3ee 100644 --- a/m4/vasprintf-posix.m4 +++ b/m4/vasprintf-posix.m4 @@ -1,4 +1,4 @@ -# vasprintf-posix.m4 serial 8 +# vasprintf-posix.m4 serial 9 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_vasprintf_posix=no AC_CHECK_FUNCS([vasprintf]) case "$gl_cv_func_printf_sizes_c99" in @@ -39,11 +40,15 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - if test $ac_cv_func_vasprintf = yes; then - # vasprintf exists and is already - # POSIX compliant. - gl_cv_func_vasprintf_posix=yes - fi + case "$gl_cv_func_printf_enomem" in + *yes) + if test $ac_cv_func_vasprintf = yes; then + # vasprintf exists and is already + # POSIX compliant. + gl_cv_func_vasprintf_posix=yes + fi + ;; + esac ;; esac ;; @@ -72,6 +77,7 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_VASPRINTF fi diff --git a/m4/vfprintf-posix.m4 b/m4/vfprintf-posix.m4 index aefa6fdf3..da2b19a56 100644 --- a/m4/vfprintf-posix.m4 +++ b/m4/vfprintf-posix.m4 @@ -1,4 +1,4 @@ -# vfprintf-posix.m4 serial 7 +# vfprintf-posix.m4 serial 8 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_vfprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -38,9 +39,13 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - # vfprintf exists and is already - # POSIX compliant. - gl_cv_func_vfprintf_posix=yes + case "$gl_cv_func_printf_enomem" in + *yes) + # vfprintf exists and is already + # POSIX compliant. + gl_cv_func_vfprintf_posix=yes + ;; + esac ;; esac ;; @@ -69,6 +74,7 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_VFPRINTF fi diff --git a/m4/vsnprintf-posix.m4 b/m4/vsnprintf-posix.m4 index a4855f3b2..aaf5d2c2c 100644 --- a/m4/vsnprintf-posix.m4 +++ b/m4/vsnprintf-posix.m4 @@ -1,4 +1,4 @@ -# vsnprintf-posix.m4 serial 8 +# vsnprintf-posix.m4 serial 9 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_vsnprintf_posix=no AC_CHECK_FUNCS([vsnprintf]) if test $ac_cv_func_vsnprintf = yes; then @@ -45,17 +46,21 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - case "$gl_cv_func_snprintf_truncation_c99" in + case "$gl_cv_func_printf_enomem" in *yes) - case "$gl_cv_func_snprintf_retval_c99" in + case "$gl_cv_func_snprintf_truncation_c99" in *yes) - case "$gl_cv_func_snprintf_directive_n" in + case "$gl_cv_func_snprintf_retval_c99" in *yes) - case "$gl_cv_func_vsnprintf_zerosize_c99" in + case "$gl_cv_func_snprintf_directive_n" in *yes) - # vsnprintf exists and is - # already POSIX compliant. - gl_cv_func_vsnprintf_posix=yes + case "$gl_cv_func_vsnprintf_zerosize_c99" in + *yes) + # vsnprintf exists and is + # already POSIX compliant. + gl_cv_func_vsnprintf_posix=yes + ;; + esac ;; esac ;; @@ -93,6 +98,7 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_VSNPRINTF fi diff --git a/m4/vsprintf-posix.m4 b/m4/vsprintf-posix.m4 index 144fc585a..48ca6eff6 100644 --- a/m4/vsprintf-posix.m4 +++ b/m4/vsprintf-posix.m4 @@ -1,4 +1,4 @@ -# vsprintf-posix.m4 serial 7 +# vsprintf-posix.m4 serial 8 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -17,6 +17,7 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], AC_REQUIRE([gl_PRINTF_POSITIONS]) AC_REQUIRE([gl_PRINTF_FLAG_GROUPING]) AC_REQUIRE([gl_PRINTF_FLAG_ZERO]) + AC_REQUIRE([gl_PRINTF_ENOMEM]) gl_cv_func_vsprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -38,9 +39,13 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], *yes) case "$gl_cv_func_printf_flag_zero" in *yes) - # vsprintf exists and is already - # POSIX compliant. - gl_cv_func_vsprintf_posix=yes + case "$gl_cv_func_printf_enomem" in + *yes) + # vsprintf exists and is already + # POSIX compliant. + gl_cv_func_vsprintf_posix=yes + ;; + esac ;; esac ;; @@ -69,6 +74,7 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING gl_PREREQ_VASNPRINTF_FLAG_ZERO + gl_PREREQ_VASNPRINTF_ENOMEM gl_REPLACE_VASNPRINTF gl_REPLACE_VSPRINTF fi diff --git a/modules/fprintf-posix b/modules/fprintf-posix index 40e606c12..22db09c90 100644 --- a/modules/fprintf-posix +++ b/modules/fprintf-posix @@ -12,6 +12,7 @@ fseterr vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/snprintf-posix b/modules/snprintf-posix index 0a5e8d693..62fad88e8 100644 --- a/modules/snprintf-posix +++ b/modules/snprintf-posix @@ -11,6 +11,7 @@ snprintf vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/sprintf-posix b/modules/sprintf-posix index 0ae1ef443..2fb663269 100644 --- a/modules/sprintf-posix +++ b/modules/sprintf-posix @@ -11,6 +11,7 @@ stdio vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/vasnprintf-posix b/modules/vasnprintf-posix index b70171824..c2a927f59 100644 --- a/modules/vasnprintf-posix +++ b/modules/vasnprintf-posix @@ -10,6 +10,7 @@ Depends-on: vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/vasprintf-posix b/modules/vasprintf-posix index 2b75dff79..e9f898ab9 100644 --- a/modules/vasprintf-posix +++ b/modules/vasprintf-posix @@ -10,6 +10,7 @@ vasprintf vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/vfprintf-posix b/modules/vfprintf-posix index 7d0b8cd39..31352f22d 100644 --- a/modules/vfprintf-posix +++ b/modules/vfprintf-posix @@ -12,6 +12,7 @@ fseterr vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/vsnprintf-posix b/modules/vsnprintf-posix index fc499995a..c86b7e4da 100644 --- a/modules/vsnprintf-posix +++ b/modules/vsnprintf-posix @@ -11,6 +11,7 @@ vsnprintf vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix index d96745cfc..aaf7b5d10 100644 --- a/modules/vsprintf-posix +++ b/modules/vsprintf-posix @@ -11,6 +11,7 @@ stdio vasnprintf isnan-nolibm isnanl-nolibm +frexp-nolibm frexpl-nolibm printf-frexp printf-frexpl -- 2.11.0