From 060ad6de5ed9d89902ebe99c2c39c982dcedc5b9 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 18 May 2007 18:26:01 +0000 Subject: [PATCH] Add support for 'long double' number output. --- ChangeLog | 44 ++ doc/functions/fprintf.texi | 6 +- doc/functions/printf.texi | 6 +- doc/functions/snprintf.texi | 6 +- doc/functions/sprintf.texi | 6 +- doc/functions/vfprintf.texi | 6 +- doc/functions/vprintf.texi | 6 +- doc/functions/vsnprintf.texi | 6 +- doc/functions/vsprintf.texi | 6 +- lib/vasnprintf.c | 1459 ++++++++++++++++++++++++++++++++++++++++++ m4/fprintf-posix.m4 | 25 +- m4/printf.m4 | 135 ++-- m4/snprintf-posix.m4 | 34 +- m4/sprintf-posix.m4 | 25 +- m4/vasnprintf-posix.m4 | 30 +- m4/vasnprintf.m4 | 18 +- m4/vasprintf-posix.m4 | 30 +- m4/vfprintf-posix.m4 | 25 +- m4/vsnprintf-posix.m4 | 34 +- m4/vsprintf-posix.m4 | 25 +- modules/fprintf-posix | 1 + modules/snprintf-posix | 1 + modules/sprintf-posix | 1 + modules/vasnprintf | 1 + modules/vasnprintf-posix | 1 + modules/vasprintf-posix | 1 + modules/vfprintf-posix | 1 + modules/vsnprintf-posix | 1 + modules/vsprintf-posix | 1 + 29 files changed, 1783 insertions(+), 158 deletions(-) diff --git a/ChangeLog b/ChangeLog index 41e6cb24f..2e5c19335 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,49 @@ 2007-05-18 Bruno Haible + Add support for 'long double' number output. + * m4/printf.m4 (gl_PRINTF_LONG_DOUBLE): New macro. + * lib/vasnprintf.c: Include math.h and float+.h. + (mp_limb_t): New type. + (GMP_LIMB_BITS): New macro. + (mp_twolimb_t): New type. + (GMP_TWOLIMB_BITS): New macro. + (mpn_t): New type. + (multiply, divide, convert_to_decimal, decode_long_double, + scale10_round_long_double, scale10_round_decimal_long_double, + floorlog10l): New functions. + (VASNPRINTF) [NEED_PRINTF_LONG_DOUBLE]: Implement 'long double' support + for the %f, %F, %e, %E, %g, %G directives. + * m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_LONG_DOUBLE): New macro. + * m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_POSIX): Invoke + gl_PRINTF_LONG_DOUBLE and test its result. Invoke + gl_PREREQ_VASNPRINTF_LONG_DOUBLE. + * m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_POSIX): Likewise. + * m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_POSIX): Likewise. + * m4/vasnprintf-posix.m4 (gl_FUNC_VASNPRINTF_POSIX): Likewise. + * m4/vasprintf-posix.m4 (gl_FUNC_VASPRINTF_POSIX): Likewise. + * m4/vfprintf-posix.m4 (gl_FUNC_VFPRINTF_POSIX): Likewise. + * m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_POSIX): Likewise. + * m4/vsprintf-posix.m4 (gl_FUNC_VSPRINTF_POSIX): Likewise. + * modules/fprintf-posix (Depends-on): Add frexpl-nolibm. + * modules/snprintf-posix (Depends-on): Likewise. + * modules/sprintf-posix (Depends-on): Likewise. + * modules/vasnprintf-posix (Depends-on): Likewise. + * modules/vasprintf-posix (Depends-on): Likewise. + * modules/vfprintf-posix (Depends-on): Likewise. + * modules/vsnprintf-posix (Depends-on): Likewise. + * modules/vsprintf-posix (Depends-on): Likewise. + * modules/vasnprintf (Files): Add lib/float+.h. + * doc/functions/fprintf.texi: Update. + * doc/functions/printf.texi: Update. + * doc/functions/snprintf.texi: Update. + * doc/functions/sprintf.texi: Update. + * doc/functions/vfprintf.texi: Update. + * doc/functions/vprintf.texi: Update. + * doc/functions/vsnprintf.texi: Update. + * doc/functions/vsprintf.texi: Update. + +2007-05-18 Bruno Haible + * lib/vasnprintf.c (USE_SNPRINTF): Define to 0 on BeOS. 2007-05-18 Bruno Haible diff --git a/doc/functions/fprintf.texi b/doc/functions/fprintf.texi index b964475a1..fc366df6b 100644 --- a/doc/functions/fprintf.texi +++ b/doc/functions/fprintf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/printf.texi b/doc/functions/printf.texi index 662ce0652..741e1975f 100644 --- a/doc/functions/printf.texi +++ b/doc/functions/printf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/snprintf.texi b/doc/functions/snprintf.texi index 75ad7d0ab..2f3e315e2 100644 --- a/doc/functions/snprintf.texi +++ b/doc/functions/snprintf.texi @@ -20,6 +20,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -54,7 +57,4 @@ OSF/1 5.1. Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/sprintf.texi b/doc/functions/sprintf.texi index 14929f276..b04e3d060 100644 --- a/doc/functions/sprintf.texi +++ b/doc/functions/sprintf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/vfprintf.texi b/doc/functions/vfprintf.texi index 6a4c32712..830d3cbc9 100644 --- a/doc/functions/vfprintf.texi +++ b/doc/functions/vfprintf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/vprintf.texi b/doc/functions/vprintf.texi index c8ac1ef08..e57a2f30d 100644 --- a/doc/functions/vprintf.texi +++ b/doc/functions/vprintf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/vsnprintf.texi b/doc/functions/vsnprintf.texi index 4209ce215..b938bd7ca 100644 --- a/doc/functions/vsnprintf.texi +++ b/doc/functions/vsnprintf.texi @@ -20,6 +20,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -54,7 +57,4 @@ HP-UX 11, OSF/1 5.1. Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/doc/functions/vsprintf.texi b/doc/functions/vsprintf.texi index be4967876..ce6a3c298 100644 --- a/doc/functions/vsprintf.texi +++ b/doc/functions/vsprintf.texi @@ -13,6 +13,9 @@ This function does not support size specifiers as in C99 (@code{hh}, @code{ll}, @code{j}, @code{t}, @code{z}) on some platforms: AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS. @item +printf of @samp{long double} numbers is unsupported on some platforms: +mingw, BeOS. +@item This function does not support the @samp{a} and @samp{A} directives on some platforms: glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS. @@ -34,7 +37,4 @@ MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, Portability problems not fixed by Gnulib: @itemize -@item -printf of @samp{long double} numbers is unsupported on some platforms: -mingw. @end itemize diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index a740ebf65..fdca88685 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -62,6 +62,11 @@ # 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 @@ -159,6 +164,950 @@ decimal_point_char () # endif #endif +#if NEED_PRINTF_LONG_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 + (and slower) algorithms. */ + +typedef unsigned int mp_limb_t; +# define GMP_LIMB_BITS 32 +typedef int mp_limb_verify[2 * (sizeof (mp_limb_t) * CHAR_BIT == GMP_LIMB_BITS) - 1]; + +typedef unsigned long long mp_twolimb_t; +# define GMP_TWOLIMB_BITS 64 +typedef int mp_twolimb_verify[2 * (sizeof (mp_twolimb_t) * CHAR_BIT == GMP_TWOLIMB_BITS) - 1]; + +/* Representation of a bignum >= 0. */ +typedef struct +{ + size_t nlimbs; + mp_limb_t *limbs; /* Bits in little-endian order, allocated with malloc(). */ +} mpn_t; + +/* Compute the product of two bignums >= 0. + Return the allocated memory in case of success, NULL in case of memory + allocation failure. */ +static void * +multiply (mpn_t src1, mpn_t src2, mpn_t *dest) +{ + const mp_limb_t *p1; + const mp_limb_t *p2; + size_t len1; + size_t len2; + + if (src1.nlimbs <= src2.nlimbs) + { + len1 = src1.nlimbs; + p1 = src1.limbs; + len2 = src2.nlimbs; + p2 = src2.limbs; + } + else + { + len1 = src2.nlimbs; + p1 = src2.limbs; + len2 = src1.nlimbs; + p2 = src1.limbs; + } + /* Now 0 <= len1 <= len2. */ + if (len1 == 0) + { + /* src1 or src2 is zero. */ + dest->nlimbs = 0; + dest->limbs = (mp_limb_t *) malloc (1); + } + else + { + /* Here 1 <= len1 <= len2. */ + size_t dlen; + mp_limb_t *dp; + size_t k, i, j; + + dlen = len1 + len2; + dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); + if (dp == NULL) + return NULL; + for (k = len2; k > 0; ) + dp[--k] = 0; + for (i = 0; i < len1; i++) + { + mp_limb_t digit1 = p1[i]; + mp_twolimb_t carry = 0; + for (j = 0; j < len2; j++) + { + mp_limb_t digit2 = p2[j]; + carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2; + carry += dp[i + j]; + dp[i + j] = (mp_limb_t) carry; + carry = carry >> GMP_LIMB_BITS; + } + dp[i + len2] = (mp_limb_t) carry; + } + /* Normalise. */ + while (dlen > 0 && dp[dlen - 1] == 0) + dlen--; + dest->nlimbs = dlen; + dest->limbs = dp; + } + return dest->limbs; +} + +/* Compute the quotient of a bignum a >= 0 and a bignum b > 0. + a is written as a = q * b + r with 0 <= r < b. q is the quotient, r + the remainder. + Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd, + q is incremented. + Return the allocated memory in case of success, NULL in case of memory + allocation failure. */ +static void * +divide (mpn_t a, mpn_t b, mpn_t *q) +{ + /* Algorithm: + First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]] + with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS). + If m=n=1, perform a single-precision division: + r:=0, j:=m, + while j>0 do + {Here (q[m-1]*beta^(m-1)+...+q[j]*beta^j) * b[0] + r*beta^j = + = a[m-1]*beta^(m-1)+...+a[j]*beta^j und 0<=r=n>1, perform a multiple-precision division: + We have a/b < beta^(m-n+1). + s:=intDsize-1-(hightest bit in b[n-1]), 0<=s=beta/2. + For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).} + Compute q* : + q* := floor((r[j+n]*beta+r[j+n-1])/b[n-1]). + In case of overflow (q* >= beta) set q* := beta-1. + Compute c2 := ((r[j+n]*beta+r[j+n-1]) - q* * b[n-1])*beta + r[j+n-2] + and c3 := b[n-2] * q*. + {We have 0 <= c2 < 2*beta^2, even 0 <= c2 < beta^2 if no overflow + occurred. Furthermore 0 <= c3 < beta^2. + If there was overflow and + r[j+n]*beta+r[j+n-1] - q* * b[n-1] >= beta, i.e. c2 >= beta^2, + the next test can be skipped.} + While c3 > c2, {Here 0 <= c2 < c3 < beta^2} + Put q* := q* - 1, c2 := c2 + b[n-1]*beta, c3 := c3 - b[n-2]. + If q* > 0: + Put r := r - b * q* * beta^j. In detail: + [r[n+j],...,r[j]] := [r[n+j],...,r[j]] - q* * [b[n-1],...,b[0]]. + hence: u:=0, for i:=0 to n-1 do + u := u + q* * b[i], + r[j+i]:=r[j+i]-(u mod beta) (+ beta, if carry), + u:=u div beta (+ 1, if carry in subtraction) + r[n+j]:=r[n+j]-u. + {Since always u = (q* * [b[i-1],...,b[0]] div beta^i) + 1 + < q* + 1 <= beta, + the carry u does not overflow.} + If a negative carry occurs, put q* := q* - 1 + and [r[n+j],...,r[j]] := [r[n+j],...,r[j]] + [0,b[n-1],...,b[0]]. + Set q[j] := q*. + Normalise [q[m-n],..,q[0]]; this yields the quotient q. + Shift [r[n-1],...,r[0]] right by s bits and normalise; this yields the + rest r. + The room for q[j] can be allocated at the memory location of r[n+j]. + Finally, round-to-even: + Shift r left by 1 bit. + If r > b or if r = b and q[0] is odd, q := q+1. + */ + const mp_limb_t *a_ptr = a.limbs; + size_t a_len = a.nlimbs; + const mp_limb_t *b_ptr = b.limbs; + size_t b_len = b.nlimbs; + mp_limb_t *roomptr; + mp_limb_t *tmp_roomptr = NULL; + mp_limb_t *q_ptr; + size_t q_len; + mp_limb_t *r_ptr; + size_t r_len; + + /* Allocate room for a_len+2 digits. + (Need a_len+1 digits for the real division and 1 more digit for the + final rounding of q.) */ + roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t)); + if (roomptr == NULL) + return NULL; + + /* Normalise a. */ + while (a_len > 0 && a_ptr[a_len - 1] == 0) + a_len--; + + /* Normalise b. */ + for (;;) + { + if (b_len == 0) + /* Division by zero. */ + abort (); + if (b_ptr[b_len - 1] == 0) + b_len--; + else + break; + } + + /* Here m = a_len >= 0 and n = b_len > 0. */ + + if (a_len < b_len) + { + /* m beta^(m-2) <= a/b < beta^m */ + r_ptr = roomptr; + q_ptr = roomptr + 1; + { + mp_limb_t den = b_ptr[0]; + mp_limb_t remainder = 0; + const mp_limb_t *sourceptr = a_ptr + a_len; + mp_limb_t *destptr = q_ptr + a_len; + size_t count; + for (count = a_len; count > 0; count--) + { + mp_twolimb_t num = + ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr; + *--destptr = num / den; + remainder = num % den; + } + /* Normalise and store r. */ + if (remainder > 0) + { + r_ptr[0] = remainder; + r_len = 1; + } + else + r_len = 0; + /* Normalise q. */ + q_len = a_len; + if (q_ptr[q_len - 1] == 0) + q_len--; + } + } + else + { + /* n>1: multiple precision division. + beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n ==> + beta^(m-n-1) <= a/b < beta^(m-n+1). */ + /* Determine s. */ + size_t s; + { + mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */ + s = 31; + if (msd >= 0x10000) + { + msd = msd >> 16; + s -= 16; + } + if (msd >= 0x100) + { + msd = msd >> 8; + s -= 8; + } + if (msd >= 0x10) + { + msd = msd >> 4; + s -= 4; + } + if (msd >= 0x4) + { + msd = msd >> 2; + s -= 2; + } + if (msd >= 0x2) + { + msd = msd >> 1; + s -= 1; + } + } + /* 0 <= s < GMP_LIMB_BITS. + Copy b, shifting it left by s bits. */ + if (s > 0) + { + tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t)); + if (tmp_roomptr == NULL) + { + free (roomptr); + return NULL; + } + { + const mp_limb_t *sourceptr = b_ptr; + mp_limb_t *destptr = tmp_roomptr; + mp_twolimb_t accu = 0; + size_t count; + for (count = b_len; count > 0; count--) + { + accu += (mp_twolimb_t) *sourceptr++ << s; + *destptr++ = (mp_limb_t) accu; + accu = accu >> GMP_LIMB_BITS; + } + /* accu must be zero, since that was how s was determined. */ + if (accu != 0) + abort (); + } + b_ptr = tmp_roomptr; + } + /* Copy a, shifting it left by s bits, yields r. + Memory layout: + At the beginning: r = roomptr[0..a_len], + at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len] */ + r_ptr = roomptr; + if (s == 0) + { + memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t)); + r_ptr[a_len] = 0; + } + else + { + const mp_limb_t *sourceptr = a_ptr; + mp_limb_t *destptr = r_ptr; + mp_twolimb_t accu = 0; + size_t count; + for (count = a_len; count > 0; count--) + { + accu += (mp_twolimb_t) *sourceptr++ << s; + *destptr++ = (mp_limb_t) accu; + accu = accu >> GMP_LIMB_BITS; + } + *destptr++ = (mp_limb_t) accu; + } + q_ptr = roomptr + b_len; + q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */ + { + size_t j = a_len - b_len; /* m-n */ + mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */ + mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */ + mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */ + ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd; + /* Division loop, traversed m-n+1 times. + j counts down, b is unchanged, beta/2 <= b[n-1] < beta. */ + for (;;) + { + mp_limb_t q_star; + mp_limb_t c1; + if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */ + { + /* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow. */ + mp_twolimb_t num = + ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS) + | r_ptr[j + b_len - 1]; + q_star = num / b_msd; + c1 = num % b_msd; + } + else + { + /* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1]. */ + q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */ + /* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta + <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta + <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) + {<= beta !}. + If yes, jump directly to the subtraction loop. + (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta + <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */ + if (r_ptr[j + b_len] > b_msd + || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd) + /* r[j+n] >= b[n-1]+1 or + r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a + carry. */ + goto subtract; + } + /* q_star = q*, + c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, 0, decrease it by + b[n-1]*beta+b[n-2]. Because of b[n-1]*beta+b[n-2] >= beta^2/2 + this can happen only twice. */ + if (c3 > c2) + { + q_star = q_star - 1; /* q* := q* - 1 */ + if (c3 - c2 > b_msdd) + q_star = q_star - 1; /* q* := q* - 1 */ + } + } + if (q_star > 0) + subtract: + { + /* Subtract r := r - b * q* * beta^j. */ + mp_limb_t cr; + { + const mp_limb_t *sourceptr = b_ptr; + mp_limb_t *destptr = r_ptr + j; + mp_twolimb_t carry = 0; + size_t count; + for (count = b_len; count > 0; count--) + { + /* Here 0 <= carry <= q*. */ + carry = + carry + + (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++ + + (mp_limb_t) ~(*destptr); + /* Here 0 <= carry <= beta*q* + beta-1. */ + *destptr++ = ~(mp_limb_t) carry; + carry = carry >> GMP_LIMB_BITS; /* <= q* */ + } + cr = (mp_limb_t) carry; + } + /* Subtract cr from r_ptr[j + b_len], then forget about + r_ptr[j + b_len]. */ + if (cr > r_ptr[j + b_len]) + { + /* Subtraction gave a carry. */ + q_star = q_star - 1; /* q* := q* - 1 */ + /* Add b back. */ + { + const mp_limb_t *sourceptr = b_ptr; + mp_limb_t *destptr = r_ptr + j; + mp_limb_t carry = 0; + size_t count; + for (count = b_len; count > 0; count--) + { + mp_limb_t source1 = *sourceptr++; + mp_limb_t source2 = *destptr; + *destptr++ = source1 + source2 + carry; + carry = + (carry + ? source1 >= (mp_limb_t) ~source2 + : source1 > (mp_limb_t) ~source2); + } + } + /* Forget about the carry and about r[j+n]. */ + } + } + /* q* is determined. Store it as q[j]. */ + q_ptr[j] = q_star; + if (j == 0) + break; + j--; + } + } + r_len = b_len; + /* Normalise q. */ + if (q_ptr[q_len - 1] == 0) + q_len--; +# if 0 /* Not needed here, since we need r only to compare it with b/2, and + b is shifted left by s bits. */ + /* Shift r right by s bits. */ + if (s > 0) + { + mp_limb_t ptr = r_ptr + r_len; + mp_twolimb_t accu = 0; + size_t count; + for (count = r_len; count > 0; count--) + { + accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS; + accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s); + *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS); + } + } +# endif + /* Normalise r. */ + while (r_len > 0 && r_ptr[r_len - 1] == 0) + r_len--; + } + /* Compare r << 1 with b. */ + if (r_len > b_len) + goto increment_q; + { + size_t i; + for (i = b_len; i > 0; ) + { + i--; + { + mp_limb_t r_i = + (i + 1 < r_len ? r_ptr[i + 1] >> (GMP_LIMB_BITS - 1) : 0) + | (i < r_len ? r_ptr[i] << 1 : 0); + mp_limb_t b_i = b_ptr[i]; + if (r_i > b_i) + goto increment_q; + if (r_i < b_i) + goto keep_q; + } + } + } + if (q_len > 0 && ((q_ptr[0] & 1) != 0)) + /* q is odd. */ + increment_q: + { + size_t i; + for (i = 0; i < q_len; i++) + if (++(q_ptr[i]) != 0) + goto keep_q; + q_ptr[q_len++] = 1; + } + keep_q: + if (tmp_roomptr != NULL) + free (tmp_roomptr); + q->limbs = q_ptr; + q->nlimbs = q_len; + return roomptr; +} + +/* Convert a bignum a >= 0 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) +{ + 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); + if (c_ptr != NULL) + { + char *d_ptr = c_ptr; + while (a_len > 0) + { + /* Divide a by 10^9, in-place. */ + mp_limb_t remainder = 0; + mp_limb_t *ptr = a_ptr + a_len; + size_t count; + for (count = a_len; count > 0; count--) + { + mp_twolimb_t num = + ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr; + *ptr = num / 1000000000; + remainder = num % 1000000000; + } + /* Store the remainder as 9 decimal digits. */ + for (count = 9; count > 0; count--) + { + *d_ptr++ = '0' + (remainder % 10); + remainder = remainder / 10; + } + /* Normalize a. */ + if (a_ptr[a_len - 1] == 0) + a_len--; + } + /* Remove leading zeroes. */ + while (d_ptr > c_ptr && d_ptr[-1] == '0') + d_ptr--; + /* But keep at least one zero. */ + if (d_ptr == c_ptr) + *d_ptr++ = '0'; + /* Terminate the string. */ + *d_ptr = '\0'; + } + return c_ptr; +} + +/* 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_long_double (long double x, int *ep, mpn_t *mp) +{ + mpn_t m; + int exp; + long double y; + size_t i; + + /* Allocate memory for result. */ + m.nlimbs = (LDBL_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 = frexpl (x, &exp); + if (!(y >= 0.0L && y < 1.0L)) + abort (); + /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * LDBL_MANT_BIT), and the + latter is an integer. */ + /* Convert the mantissa (y * LDBL_MANT_BIT) to a sequence of limbs. + I'm not sure whether it's safe to cast a 'long double' value between + 2^31 and 2^32 to 'unsigned int', therefore play safe and cast only + 'long double' values between 0 and 2^16 (to 'unsigned int' or 'int', + doesn't matter). */ +# 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)); + hi = (int) y; + y -= hi; + if (!(y >= 0.0L && y < 1.0L)) + abort (); + y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); + lo = (int) y; + y -= lo; + if (!(y >= 0.0L && y < 1.0L)) + abort (); + m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo; + } +# else + { + mp_limb_t d; + y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS); + d = (int) y; + y -= d; + if (!(y >= 0.0L && y < 1.0L)) + abort (); + m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d; + } +# endif +# endif + for (i = LDBL_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.0L && y < 1.0L)) + abort (); + y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); + lo = (int) y; + y -= lo; + if (!(y >= 0.0L && y < 1.0L)) + abort (); + m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo; + } + if (!(y == 0.0L)) + abort (); + /* Normalise. */ + while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0) + m.nlimbs--; + *mp = m; + *ep = exp - LDBL_MANT_BIT; + return m.limbs; +} + +/* 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) +{ + int e; + mpn_t m; + void *memory = decode_long_double (x, &e, &m); + int s; + unsigned int abs_n; + unsigned int abs_s; + mp_limb_t *pow5_ptr; + size_t pow5_len; + unsigned int s_limbs; + unsigned int s_bits; + mpn_t pow5; + + if (memory == NULL) + return NULL; + /* x = 2^e * m, hence + y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m) + = round (2^s * 5^n * m). */ + s = e + n; + /* 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); + abs_s = (s >= 0 ? s : -s); + pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1 + + abs_s / GMP_LIMB_BITS + 1) + * sizeof (mp_limb_t)); + if (pow5_ptr == NULL) + { + free (memory); + return NULL; + } + /* Initialize with 1. */ + pow5_ptr[0] = 1; + pow5_len = 1; + /* Multiply with 5^|n|. */ + if (abs_n > 0) + { + static mp_limb_t const small_pow5[13 + 1] = + { + 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, + 48828125, 244140625, 1220703125 + }; + unsigned int n13; + for (n13 = 0; n13 <= abs_n; n13 += 13) + { + mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13]; + size_t j; + mp_twolimb_t carry = 0; + for (j = 0; j < pow5_len; j++) + { + mp_limb_t digit2 = pow5_ptr[j]; + carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2; + pow5_ptr[j] = (mp_limb_t) carry; + carry = carry >> GMP_LIMB_BITS; + } + if (carry > 0) + pow5_ptr[pow5_len++] = (mp_limb_t) carry; + } + } + s_limbs = abs_s / GMP_LIMB_BITS; + s_bits = abs_s % GMP_LIMB_BITS; + if (n >= 0 ? s >= 0 : s <= 0) + { + /* Multiply with 2^|s|. */ + if (s_bits > 0) + { + mp_limb_t *ptr = pow5_ptr; + mp_twolimb_t accu = 0; + size_t count; + for (count = pow5_len; count > 0; count--) + { + accu += (mp_twolimb_t) *ptr << s_bits; + *ptr++ = (mp_limb_t) accu; + accu = accu >> GMP_LIMB_BITS; + } + if (accu > 0) + { + *ptr = (mp_limb_t) accu; + pow5_len++; + } + } + if (s_limbs > 0) + { + size_t count; + for (count = pow5_len; count > 0;) + { + count--; + pow5_ptr[s_limbs + count] = pow5_ptr[count]; + } + for (count = s_limbs; count > 0;) + { + count--; + pow5_ptr[count] = 0; + } + pow5_len += s_limbs; + } + pow5.limbs = pow5_ptr; + pow5.nlimbs = pow5_len; + 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; + } + else + { + /* Divide m by pow5 and round. */ + void *result_memory = divide (m, pow5, yp); + free (pow5_ptr); + free (memory); + return result_memory; + } + } + else + { + pow5.limbs = pow5_ptr; + pow5.nlimbs = pow5_len; + if (n >= 0) + { + /* n >= 0, s < 0. + Multiply m with pow5, then divide by 2^|s|. */ + mpn_t numerator; + mpn_t denominator; + void *tmp_memory; + void *result_memory; + tmp_memory = multiply (m, pow5, &numerator); + if (tmp_memory == NULL) + { + free (pow5_ptr); + free (memory); + return NULL; + } + /* Construct 2^|s|. */ + { + mp_limb_t *ptr = pow5_ptr + pow5_len; + size_t i; + for (i = 0; i < s_limbs; i++) + ptr[i] = 0; + ptr[s_limbs] = (mp_limb_t) 1 << s_bits; + denominator.limbs = ptr; + denominator.nlimbs = s_limbs + 1; + } + result_memory = divide (numerator, denominator, yp); + free (tmp_memory); + free (pow5_ptr); + free (memory); + return result_memory; + } + else + { + /* n < 0, s > 0. + 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) + { + free (pow5_ptr); + free (memory); + return NULL; + } + { + mp_limb_t *destptr = num_ptr; + { + size_t i; + for (i = 0; i < s_limbs; i++) + *destptr++ = 0; + } + if (s_bits > 0) + { + const mp_limb_t *sourceptr = m.limbs; + mp_twolimb_t accu = 0; + size_t count; + for (count = m.nlimbs; count > 0; count--) + { + accu += (mp_twolimb_t) *sourceptr++ << s; + *destptr++ = (mp_limb_t) accu; + accu = accu >> GMP_LIMB_BITS; + } + if (accu > 0) + *destptr++ = (mp_limb_t) accu; + } + else + { + const mp_limb_t *sourceptr = m.limbs; + size_t count; + for (count = m.nlimbs; count > 0; count--) + *destptr++ = *sourceptr++; + } + numerator.limbs = num_ptr; + numerator.nlimbs = destptr - num_ptr; + } + result_memory = divide (numerator, pow5, yp); + free (num_ptr); + free (pow5_ptr); + free (memory); + return result_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; + + memory = scale10_round_long_double (x, n, &y); + if (memory == NULL) + return NULL; + digits = convert_to_decimal (y); + free (memory); + return digits; +} + +/* 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 +floorlog10l (long double x) +{ + int exp; + long double y; + double z; + double l; + + /* Split into exponential part and mantissa. */ + y = frexpl (x, &exp); + if (!(y >= 0.0L && y < 1.0L)) + abort (); + if (y == 0.0L) + return INT_MIN; + if (y < 0.5L) + { + while (y < (1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2)))) + { + y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2)); + exp -= GMP_LIMB_BITS; + } + if (y < (1.0L / (1 << 16))) + { + y *= 1.0L * (1 << 16); + exp -= 16; + } + if (y < (1.0L / (1 << 8))) + { + y *= 1.0L * (1 << 8); + exp -= 8; + } + if (y < (1.0L / (1 << 4))) + { + y *= 1.0L * (1 << 4); + exp -= 4; + } + if (y < (1.0L / (1 << 2))) + { + y *= 1.0L * (1 << 2); + exp -= 2; + } + if (y < (1.0L / (1 << 1))) + { + y *= 1.0L * (1 << 1); + exp -= 1; + } + } + if (!(y >= 0.5L && y < 1.0L)) + 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 + CHAR_T * VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) { @@ -313,6 +1262,516 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); } } +#if 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) + { + 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; + CHAR_T *pad_ptr; + CHAR_T *p; + + has_width = 0; + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + if (arg < 0) + { + /* "A negative field width is taken as a '-' flag + followed by a positive field width." */ + flags |= FLAG_LEFT; + width = (unsigned int) (-arg); + } + else + width = arg; + } + else + { + const CHAR_T *digitp = dp->width_start; + + do + width = xsum (xtimes (width, 10), *digitp++ - '0'); + while (digitp != dp->width_end); + } + has_width = 1; + } + + has_precision = 0; + precision = 0; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + /* "A negative precision is taken as if the precision + were omitted." */ + if (arg >= 0) + { + precision = arg; + has_precision = 1; + } + } + else + { + const CHAR_T *digitp = dp->precision_start + 1; + + precision = 0; + while (digitp != dp->precision_end) + precision = xsum (xtimes (precision, 10), *digitp++ - '0'); + has_precision = 1; + } + } + + arg = a.arg[dp->arg_index].a.a_longdouble; + + /* Allocate a temporary buffer of sufficient size. */ + tmp_length = LDBL_DIG + 1; + if (tmp_length < precision) + tmp_length = precision; + if (dp->conversion == 'f' || dp->conversion == 'F') + if (!(isnanl (arg) || arg + arg == arg)) + { + int exponent = floorlog10l (arg < 0 ? -arg : arg); + if (exponent >= 0 && tmp_length < exponent + precision) + tmp_length = exponent + precision; + } + /* Account for sign, decimal point etc. */ + tmp_length = xsum (tmp_length, 12); + + if (tmp_length < width) + tmp_length = width; + + tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ + + if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) + tmp = tmpbuf; + else + { + size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); + + if (size_overflow_p (tmp_memsize)) + /* Overflow, would lead to out of memory. */ + goto out_of_memory; + tmp = (CHAR_T *) malloc (tmp_memsize); + if (tmp == NULL) + /* Out of memory. */ + goto out_of_memory; + } + + 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 + { + 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++ = ' '; + + if (arg > 0.0L && arg + arg == arg) + { + if (dp->conversion >= 'A' && dp->conversion <= 'Z') + { + *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; + } + else + { + *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; + } + } + else + { + pad_ptr = p; + + if (dp->conversion == 'f' || dp->conversion == 'F') + { + char *digits; + size_t ndigits; + + if (!has_precision) + precision = 6; + + 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 = 6; + + 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') + { + /* 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 + { + /* 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); + } + } + else + abort (); + } + + END_LONG_DOUBLE_ROUNDING (); + } + + /* 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) + { + size_t pad = width - (p - tmp); + CHAR_T *end = p + pad; + + if (flags & FLAG_LEFT) + { + /* Pad with spaces on the right. */ + for (; pad > 0; pad--) + *p++ = ' '; + } + else if ((flags & FLAG_ZERO) && pad_ptr != NULL) + { + /* Pad with zeroes. */ + CHAR_T *q = end; + + while (p > pad_ptr) + *--q = *--p; + for (; pad > 0; pad--) + *p++ = '0'; + } + else + { + /* Pad with spaces on the left. */ + CHAR_T *q = end; + + while (p > tmp) + *--q = *--p; + for (; pad > 0; pad--) + *p++ = ' '; + } + + p = end; + } + + { + size_t count = p - tmp; + + if (count >= tmp_length) + /* tmp_length was incorrectly calculated - fix the + code above! */ + abort (); + + /* Make room for the result. */ + if (count >= allocated - length) + { + size_t n = xsum (length, count); + + ENSURE_ALLOCATION (n); + } + + /* Append the result. */ + memcpy (result + length, tmp, count * sizeof (CHAR_T)); + if (tmp != tmpbuf) + free (tmp); + length += count; + } + } +#endif #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL else if (dp->conversion == 'a' || dp->conversion == 'A') { diff --git a/m4/fprintf-posix.m4 b/m4/fprintf-posix.m4 index 064527bea..fe5c7cdde 100644 --- a/m4/fprintf-posix.m4 +++ b/m4/fprintf-posix.m4 @@ -1,4 +1,4 @@ -# fprintf-posix.m4 serial 5 +# fprintf-posix.m4 serial 6 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -17,20 +18,25 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], gl_cv_func_fprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - # fprintf exists and is already POSIX compliant. - gl_cv_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 + ;; + esac ;; esac ;; @@ -46,6 +52,7 @@ AC_DEFUN([gl_FUNC_FPRINTF_POSIX], ;; esac if test $gl_cv_func_fprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/printf.m4 b/m4/printf.m4 index 09f974674..32325bf06 100644 --- a/m4/printf.m4 +++ b/m4/printf.m4 @@ -1,4 +1,4 @@ -# printf.m4 serial 9 +# printf.m4 serial 10 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, @@ -81,6 +81,49 @@ changequote([,])dnl ]) ]) +dnl Test whether the *printf family of functions supports 'long double' +dnl arguments together with the 'L' size specifier. (ISO C99, POSIX:2001) +dnl Result is gl_cv_func_printf_long_double. + +AC_DEFUN([gl_PRINTF_LONG_DOUBLE], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether printf supports 'long double' arguments], + [gl_cv_func_printf_long_double], + [ + AC_TRY_RUN([ +#include +#include +static char buf[100]; +int main () +{ + buf[0] = '\0'; + if (sprintf (buf, "%Lf %d", 1.75L, 33, 44, 55) < 0 + || strcmp (buf, "1.750000 33") != 0) + return 1; + buf[0] = '\0'; + if (sprintf (buf, "%Le %d", 1.75L, 33, 44, 55) < 0 + || strcmp (buf, "1.750000e+00 33") != 0) + return 1; + buf[0] = '\0'; + if (sprintf (buf, "%Lg %d", 1.75L, 33, 44, 55) < 0 + || strcmp (buf, "1.75 33") != 0) + return 1; + return 0; +}], [gl_cv_func_printf_long_double=yes], [gl_cv_func_printf_long_double=no], + [ +changequote(,)dnl + case "$host_os" in + beos*) gl_cv_func_printf_long_double="guessing no";; + mingw* | pw*) gl_cv_func_printf_long_double="guessing no";; + *) gl_cv_func_printf_long_double="guessing yes";; + esac +changequote([,])dnl + ]) + ]) +]) + dnl Test whether the *printf family of functions supports the 'a' and 'A' dnl conversion specifier for hexadecimal output of floating-point numbers. dnl (ISO C99, POSIX:2001) @@ -662,52 +705,54 @@ changequote([,])dnl dnl The results of these tests on various platforms are: dnl dnl 1 = gl_PRINTF_SIZES_C99 -dnl 2 = gl_PRINTF_DIRECTIVE_A -dnl 3 = gl_PRINTF_DIRECTIVE_F -dnl 4 = gl_PRINTF_DIRECTIVE_N -dnl 5 = gl_PRINTF_POSITIONS -dnl 6 = gl_PRINTF_FLAG_GROUPING -dnl 7 = gl_PRINTF_FLAG_ZERO -dnl 8 = gl_SNPRINTF_PRESENCE -dnl 9 = gl_SNPRINTF_TRUNCATION_C99 -dnl 10 = gl_SNPRINTF_RETVAL_C99 -dnl 11 = gl_SNPRINTF_DIRECTIVE_N -dnl 12 = gl_VSNPRINTF_ZEROSIZE_C99 +dnl 2 = gl_PRINTF_LONG_DOUBLE +dnl 3 = gl_PRINTF_DIRECTIVE_A +dnl 4 = gl_PRINTF_DIRECTIVE_F +dnl 5 = gl_PRINTF_DIRECTIVE_N +dnl 6 = gl_PRINTF_POSITIONS +dnl 7 = gl_PRINTF_FLAG_GROUPING +dnl 8 = gl_PRINTF_FLAG_ZERO +dnl 9 = gl_SNPRINTF_PRESENCE +dnl 10 = gl_SNPRINTF_TRUNCATION_C99 +dnl 11 = gl_SNPRINTF_RETVAL_C99 +dnl 12 = gl_SNPRINTF_DIRECTIVE_N +dnl 13 = gl_VSNPRINTF_ZEROSIZE_C99 dnl dnl 1 = checking whether printf supports size specifiers as in C99... -dnl 2 = checking whether printf supports the 'a' and 'A' directives... -dnl 3 = checking whether printf supports the 'F' directive... -dnl 4 = checking whether printf supports the 'n' directive... -dnl 5 = checking whether printf supports POSIX/XSI format strings with positions... -dnl 6 = checking whether printf supports the grouping flag... -dnl 7 = checking whether printf supports the zero flag correctly... -dnl 8 = checking for snprintf... -dnl 9 = checking whether snprintf truncates the result as in C99... -dnl 10 = checking whether snprintf returns a byte count as in C99... -dnl 11 = checking whether snprintf fully supports the 'n' directive... -dnl 12 = checking whether vsnprintf respects a zero size as in C99... +dnl 2 = checking whether printf supports 'long double' arguments... +dnl 3 = checking whether printf supports the 'a' and 'A' directives... +dnl 4 = checking whether printf supports the 'F' directive... +dnl 5 = checking whether printf supports the 'n' directive... +dnl 6 = checking whether printf supports POSIX/XSI format strings with positions... +dnl 7 = checking whether printf supports the grouping flag... +dnl 8 = checking whether printf supports the zero flag correctly... +dnl 9 = checking for snprintf... +dnl 10 = checking whether snprintf truncates the result as in C99... +dnl 11 = checking whether snprintf returns a byte count as in C99... +dnl 12 = checking whether snprintf fully supports the 'n' directive... +dnl 13 = 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 -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.11, 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 +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.11, 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 e32e4089a..b3d9439fe 100644 --- a/m4/snprintf-posix.m4 +++ b/m4/snprintf-posix.m4 @@ -1,4 +1,4 @@ -# snprintf-posix.m4 serial 6 +# snprintf-posix.m4 serial 7 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -23,29 +24,33 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], gl_VSNPRINTF_ZEROSIZE_C99 case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - case "$gl_cv_func_snprintf_truncation_c99" in + case "$gl_cv_func_printf_flag_zero" 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 ;; @@ -70,6 +75,7 @@ AC_DEFUN([gl_FUNC_SNPRINTF_POSIX], esac fi if test $gl_cv_func_snprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/sprintf-posix.m4 b/m4/sprintf-posix.m4 index 7aadf0767..918758f57 100644 --- a/m4/sprintf-posix.m4 +++ b/m4/sprintf-posix.m4 @@ -1,4 +1,4 @@ -# sprintf-posix.m4 serial 5 +# sprintf-posix.m4 serial 6 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -17,20 +18,25 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], gl_cv_func_sprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - # sprintf exists and is already POSIX compliant. - gl_cv_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 + ;; + esac ;; esac ;; @@ -46,6 +52,7 @@ AC_DEFUN([gl_FUNC_SPRINTF_POSIX], ;; esac if test $gl_cv_func_sprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/vasnprintf-posix.m4 b/m4/vasnprintf-posix.m4 index 68634bf2f..0a9e4a833 100644 --- a/m4/vasnprintf-posix.m4 +++ b/m4/vasnprintf-posix.m4 @@ -1,4 +1,4 @@ -# vasnprintf-posix.m4 serial 6 +# vasnprintf-posix.m4 serial 7 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -18,23 +19,27 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], AC_CHECK_FUNCS_ONCE([vasnprintf]) case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" 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_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 + ;; + esac ;; esac ;; @@ -50,6 +55,7 @@ AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX], ;; esac if test $gl_cv_func_vasnprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4 index 41a5ce180..be1506544 100644 --- a/m4/vasnprintf.m4 +++ b/m4/vasnprintf.m4 @@ -1,4 +1,4 @@ -# vasnprintf.m4 serial 15 +# vasnprintf.m4 serial 16 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, @@ -59,6 +59,22 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF], AC_CHECK_FUNCS(snprintf wcslen) ]) +# Extra prerequisites of lib/vasnprintf.c for supporting 'long double' +# arguments. +AC_DEFUN([gl_PREREQ_VASNPRINTF_LONG_DOUBLE], +[ + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) + case "$gl_cv_func_printf_long_double" in + *yes) + ;; + *) + AC_DEFINE([NEED_PRINTF_LONG_DOUBLE], 1, + [Define if the vasnprintf implementation needs special code for + 'long double' arguments.]) + ;; + esac +]) + # Extra prerequisites of lib/vasnprintf.c for supporting the 'a' directive. AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_A], [ diff --git a/m4/vasprintf-posix.m4 b/m4/vasprintf-posix.m4 index 6cec101a1..8da4023a6 100644 --- a/m4/vasprintf-posix.m4 +++ b/m4/vasprintf-posix.m4 @@ -1,4 +1,4 @@ -# vasprintf-posix.m4 serial 6 +# vasprintf-posix.m4 serial 7 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -18,23 +19,27 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], AC_CHECK_FUNCS([vasprintf]) case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" 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_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 + ;; + esac ;; esac ;; @@ -50,6 +55,7 @@ AC_DEFUN([gl_FUNC_VASPRINTF_POSIX], ;; esac if test $gl_cv_func_vasprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/vfprintf-posix.m4 b/m4/vfprintf-posix.m4 index 60098a241..fc8b62405 100644 --- a/m4/vfprintf-posix.m4 +++ b/m4/vfprintf-posix.m4 @@ -1,4 +1,4 @@ -# vfprintf-posix.m4 serial 5 +# vfprintf-posix.m4 serial 6 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -17,20 +18,25 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], gl_cv_func_vfprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - # vfprintf exists and is already POSIX compliant. - gl_cv_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 + ;; + esac ;; esac ;; @@ -46,6 +52,7 @@ AC_DEFUN([gl_FUNC_VFPRINTF_POSIX], ;; esac if test $gl_cv_func_vfprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/vsnprintf-posix.m4 b/m4/vsnprintf-posix.m4 index 29af67f13..bce47b74e 100644 --- a/m4/vsnprintf-posix.m4 +++ b/m4/vsnprintf-posix.m4 @@ -1,4 +1,4 @@ -# vsnprintf-posix.m4 serial 6 +# vsnprintf-posix.m4 serial 7 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -24,29 +25,33 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], gl_VSNPRINTF_ZEROSIZE_C99 case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - case "$gl_cv_func_snprintf_truncation_c99" in + case "$gl_cv_func_printf_flag_zero" 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 ;; @@ -71,6 +76,7 @@ AC_DEFUN([gl_FUNC_VSNPRINTF_POSIX], esac fi if test $gl_cv_func_vsnprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/m4/vsprintf-posix.m4 b/m4/vsprintf-posix.m4 index 9507d8180..62c864615 100644 --- a/m4/vsprintf-posix.m4 +++ b/m4/vsprintf-posix.m4 @@ -1,4 +1,4 @@ -# vsprintf-posix.m4 serial 5 +# vsprintf-posix.m4 serial 6 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, @@ -8,6 +8,7 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], [ AC_REQUIRE([gl_EOVERFLOW]) AC_REQUIRE([gl_PRINTF_SIZES_C99]) + AC_REQUIRE([gl_PRINTF_LONG_DOUBLE]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_A]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_F]) AC_REQUIRE([gl_PRINTF_DIRECTIVE_N]) @@ -17,20 +18,25 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], gl_cv_func_vsprintf_posix=no case "$gl_cv_func_printf_sizes_c99" in *yes) - case "$gl_cv_func_printf_directive_a" in + case "$gl_cv_func_printf_long_double" in *yes) - case "$gl_cv_func_printf_directive_f" in + case "$gl_cv_func_printf_directive_a" in *yes) - case "$gl_cv_func_printf_directive_n" in + case "$gl_cv_func_printf_directive_f" in *yes) - case "$gl_cv_func_printf_positions" in + case "$gl_cv_func_printf_directive_n" in *yes) - case "$gl_cv_func_printf_flag_grouping" in + case "$gl_cv_func_printf_positions" in *yes) - case "$gl_cv_func_printf_flag_zero" in + case "$gl_cv_func_printf_flag_grouping" in *yes) - # vsprintf exists and is already POSIX compliant. - gl_cv_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 + ;; + esac ;; esac ;; @@ -46,6 +52,7 @@ AC_DEFUN([gl_FUNC_VSPRINTF_POSIX], ;; esac if test $gl_cv_func_vsprintf_posix = no; then + gl_PREREQ_VASNPRINTF_LONG_DOUBLE gl_PREREQ_VASNPRINTF_DIRECTIVE_A gl_PREREQ_VASNPRINTF_DIRECTIVE_F gl_PREREQ_VASNPRINTF_FLAG_GROUPING diff --git a/modules/fprintf-posix b/modules/fprintf-posix index cf440592e..42109be5d 100644 --- a/modules/fprintf-posix +++ b/modules/fprintf-posix @@ -12,6 +12,7 @@ fseterr vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/snprintf-posix b/modules/snprintf-posix index 1ad3423ee..c48083575 100644 --- a/modules/snprintf-posix +++ b/modules/snprintf-posix @@ -11,6 +11,7 @@ snprintf vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/sprintf-posix b/modules/sprintf-posix index a9bb8eeee..fceae7b8a 100644 --- a/modules/sprintf-posix +++ b/modules/sprintf-posix @@ -11,6 +11,7 @@ stdio vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/vasnprintf b/modules/vasnprintf index 5110362c4..ce40449a8 100644 --- a/modules/vasnprintf +++ b/modules/vasnprintf @@ -2,6 +2,7 @@ Description: vsprintf with automatic memory allocation and bounded output size. Files: +lib/float+.h lib/printf-args.h lib/printf-args.c lib/printf-parse.h diff --git a/modules/vasnprintf-posix b/modules/vasnprintf-posix index d25e780fd..9d693af4d 100644 --- a/modules/vasnprintf-posix +++ b/modules/vasnprintf-posix @@ -10,6 +10,7 @@ Depends-on: vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/vasprintf-posix b/modules/vasprintf-posix index 815c483b0..48f902f26 100644 --- a/modules/vasprintf-posix +++ b/modules/vasprintf-posix @@ -10,6 +10,7 @@ vasprintf vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/vfprintf-posix b/modules/vfprintf-posix index b189b07bc..539d52576 100644 --- a/modules/vfprintf-posix +++ b/modules/vfprintf-posix @@ -12,6 +12,7 @@ fseterr vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/vsnprintf-posix b/modules/vsnprintf-posix index bc8614760..f1a5674ec 100644 --- a/modules/vsnprintf-posix +++ b/modules/vsnprintf-posix @@ -11,6 +11,7 @@ vsnprintf vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix index ff6251479..4fc68868c 100644 --- a/modules/vsprintf-posix +++ b/modules/vsprintf-posix @@ -11,6 +11,7 @@ stdio vasnprintf isnan-nolibm isnanl-nolibm +frexpl-nolibm printf-frexp printf-frexpl signbit -- 2.11.0