[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
new module 'vasnprintf-posix'
From: |
Bruno Haible |
Subject: |
new module 'vasnprintf-posix' |
Date: |
Mon, 5 Mar 2007 00:28:55 +0100 |
User-agent: |
KMail/1.5.4 |
The module vasnprintf-posix defines a vasnprintf() function that supports
POSIX format strings with all frills.
2007-03-04 Bruno Haible <address@hidden>
* modules/vasnprintf-posix: New file.
* lib/vasnprintf.c: Include isnan.h, isnanl.h, printf-frexp.h,
printf-frexpl.h.
(VASNPRINTF): Handle the 'a' and 'A' directives here, if needed.
* m4/vasnprintf.m4 (gl_REPLACE_VASNPRINTF): New macro, extracted from
gl_FUNC_VASNPRINTF.
(gl_FUNC_VASNPRINTF): Invoke it.
* m4/vasnprintf-posix.m4: New file.
* m4/printf.m4: New file.
=========================== modules/vasnprintf-posix =========================
Description:
POSIX compatible vsprintf with automatic memory allocation and bounded output
size.
Files:
m4/vasnprintf-posix.m4
m4/printf.m4
Depends-on:
vasnprintf
isnan-nolibm
isnanl-nolibm
printf-frexp
printf-frexpl
configure.ac:
gl_FUNC_VASNPRINTF_POSIX
Makefile.am:
Include:
"vasnprintf.h"
License:
LGPL
Maintainer:
Bruno Haible
=========================== m4/vasnprintf-posix.m4 ===========================
# vasnprintf-posix.m4 serial 1
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,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_VASNPRINTF_POSIX],
[
AC_REQUIRE([gl_EOVERFLOW])
AC_REQUIRE([gl_PRINTF_SIZES_C99])
AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
AC_REQUIRE([gl_PRINTF_POSITIONS])
AC_CHECK_FUNCS([vasnprintf])
if expr "$gl_cv_func_printf_sizes_c99" : ".*yes" > /dev/null \
&& expr "$gl_cv_func_printf_directive_a" : ".*yes" > /dev/null \
&& expr "$gl_cv_func_printf_directive_n" : ".*yes" > /dev/null \
&& expr "$gl_cv_func_printf_positions" : ".*yes" > /dev/null \
&& test $ac_cv_func_vasnprintf = yes; then
: # vasnprintf exists and is already POSIX compliant.
else
if ! expr "$gl_cv_func_printf_directive_a" : ".*yes" > /dev/null; then
AC_DEFINE([NEED_PRINTF_DIRECTIVE_A], 1,
[Define if the vasnprintf implementation needs special code for
the 'a' and 'A' directives.])
fi
gl_REPLACE_VASNPRINTF
fi
])
=========================== m4/printf.m4 =====================================
# printf.m4 serial 1
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,
dnl with or without modifications, as long as this notice is preserved.
dnl Test whether the *printf family of functions supports the 'j', 'z', 't',
dnl 'L' size specifiers. (ISO C99, POSIX:2001)
dnl Result is gl_cv_func_printf_sizes_c99.
AC_DEFUN([gl_PRINTF_SIZES_C99],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([gl_AC_HEADER_STDINT_H])
AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
AC_REQUIRE([gt_TYPE_LONGDOUBLE])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether printf supports size specifiers as in C99],
[gl_cv_func_printf_sizes_c99],
[
AC_TRY_RUN([
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#if HAVE_STDINT_H_WITH_UINTMAX
# include <stdint.h>
#endif
#if HAVE_INTTYPES_H_WITH_UINTMAX
# include <inttypes.h>
#endif
static char buf[100];
int main ()
{
#if HAVE_STDINT_H_WITH_UINTMAX || HAVE_INTTYPES_H_WITH_UINTMAX
buf[0] = '\0';
if (sprintf (buf, "%ju %d", (uintmax_t) 12345671, 33, 44, 55) < 0
|| strcmp (buf, "12345671 33") != 0)
return 1;
#endif
buf[0] = '\0';
if (sprintf (buf, "%zu %d", (size_t) 12345672, 33, 44, 55) < 0
|| strcmp (buf, "12345672 33") != 0)
return 1;
buf[0] = '\0';
if (sprintf (buf, "%tu %d", (ptrdiff_t) 12345673, 33, 44, 55) < 0
|| strcmp (buf, "12345673 33") != 0)
return 1;
#if HAVE_LONG_DOUBLE
buf[0] = '\0';
if (sprintf (buf, "%Lg %d", (long double) 1.5, 33, 44, 55) < 0
|| strcmp (buf, "1.5 33") != 0)
return 1;
#endif
return 0;
}], [gl_cv_func_printf_sizes_c99=yes], [gl_cv_func_printf_sizes_c99=no],
[
changequote(,)dnl
case "$host_os" in
dnl Guess yes on glibc systems.
*-gnu*) gl_cv_func_printf_sizes_c99="guessing yes";;
dnl Guess yes on FreeBSD >= 5.
freebsd[1-4]*) gl_cv_func_printf_sizes_c99="guessing no";;
freebsd* | kfreebsd*) gl_cv_func_printf_sizes_c99="guessing yes";;
dnl Gusss yes on MacOS X >= 10.3.
darwin[1-6].*) gl_cv_func_printf_sizes_c99="guessing no";;
darwin*) gl_cv_func_printf_sizes_c99="guessing yes";;
dnl Guess yes on Solaris >= 2.10.
solaris2.[0-9]*) gl_cv_func_printf_sizes_c99="guessing no";;
solaris*) gl_cv_func_printf_sizes_c99="guessing yes";;
dnl Guess yes on NetBSD >= 3.
netbsd[1-2]*) gl_cv_func_printf_sizes_c99="guessing no";;
netbsd*) gl_cv_func_printf_sizes_c99="guessing yes";;
dnl If we don't know, assume the worst.
*) gl_cv_func_printf_sizes_c99="guessing no";;
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)
dnl Result is gl_cv_func_printf_directive_a.
AC_DEFUN([gl_PRINTF_DIRECTIVE_A],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether printf supports the 'a' and 'A' directives],
[gl_cv_func_printf_directive_a],
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
static char buf[100];
int main ()
{
if (sprintf (buf, "%a %d", 3.1416015625, 33, 44, 55) < 0
|| strcmp (buf, "0x1.922p+1 33") != 0)
return 1;
if (sprintf (buf, "%A %d", -3.1416015625, 33, 44, 55) < 0
|| strcmp (buf, "-0X1.922P+1 33") != 0)
return 1;
return 0;
}], [gl_cv_func_printf_directive_a=yes], [gl_cv_func_printf_directive_a=no],
[
changequote(,)dnl
case "$host_os" in
dnl Guess yes on glibc systems.
*-gnu*) gl_cv_func_printf_directive_a="guessing yes";;
dnl Guess yes on FreeBSD >= 5.
freebsd[1-4]*) gl_cv_func_printf_directive_a="guessing no";;
freebsd* | kfreebsd*) gl_cv_func_printf_directive_a="guessing yes";;
dnl Gusss yes on MacOS X >= 10.3.
darwin[1-6].*) gl_cv_func_printf_directive_a="guessing no";;
darwin*) gl_cv_func_printf_directive_a="guessing yes";;
dnl If we don't know, assume the worst.
*) gl_cv_func_printf_directive_a="guessing no";;
esac
changequote([,])dnl
])
])
])
dnl Test whether the *printf family of functions supports the %n format
dnl directive. (ISO C99, POSIX:2001)
dnl Result is gl_cv_func_printf_directive_n.
AC_DEFUN([gl_PRINTF_DIRECTIVE_N],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether printf supports the 'n' directive],
[gl_cv_func_printf_directive_n],
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
static char buf[100];
int main ()
{
int count = -1;
if (sprintf (buf, "%d %n", 123, &count, 33, 44, 55) < 0
|| strcmp (buf, "123 ") != 0
|| count != 4)
return 1;
return 0;
}], [gl_cv_func_printf_directive_n=yes], [gl_cv_func_printf_directive_n=no],
[
changequote(,)dnl
case "$host_os" in
hpux*) gl_cv_func_printf_directive_n="guessing no";;
*) gl_cv_func_printf_directive_n="guessing yes";;
esac
changequote([,])dnl
])
])
])
dnl Test whether the *printf family of functions supports POSIX/XSI format
dnl strings with positions. (POSIX:2001)
dnl Result is gl_cv_func_printf_positions.
AC_DEFUN([gl_PRINTF_POSITIONS],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether printf supports POSIX/XSI format strings with
positions],
[gl_cv_func_printf_positions],
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
/* The string "%2$d %1$d", with dollar characters protected from the shell's
dollar expansion (possibly an autoconf bug). */
static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' };
static char buf[100];
int main ()
{
sprintf (buf, format, 33, 55);
return (strcmp (buf, "55 33") != 0);
}], [gl_cv_func_printf_positions=yes], [gl_cv_func_printf_positions=no],
[
changequote(,)dnl
case "$host_os" in
netbsd*) gl_cv_func_printf_positions="guessing no";;
beos*) gl_cv_func_printf_positions="guessing no";;
mingw* | pw*) gl_cv_func_printf_positions="guessing no";;
*) gl_cv_func_printf_positions="guessing yes";;
esac
changequote([,])dnl
])
])
])
dnl Test whether the snprintf function exists. (ISO C99, POSIX:2001)
dnl Result is ac_cv_func_snprintf.
AC_DEFUN([gl_SNPRINTF_PRESENCE],
[
AC_CHECK_FUNCS_ONCE([snprintf])
])
dnl Test whether the string produced by the snprintf function is always NUL
dnl terminated. (ISO C99, POSIX:2001)
dnl Result is gl_cv_func_snprintf_truncation_c99.
AC_DEFUN([gl_SNPRINTF_TRUNCATION_C99],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether snprintf truncates the result as in C99],
[gl_cv_func_snprintf_truncation_c99],
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
static char buf[100];
int main ()
{
strcpy (buf, "ABCDEF");
snprintf (buf, 3, "%d %d", 4567, 89);
if (memcmp (buf, "45\0DEF", 6) != 0)
return 1;
return 0;
}], [gl_cv_func_snprintf_truncation_c99=yes],
[gl_cv_func_snprintf_truncation_c99=no],
[
changequote(,)dnl
case "$host_os" in
dnl Guess yes on glibc systems.
*-gnu*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on FreeBSD >= 5.
freebsd[1-4]*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
freebsd* | kfreebsd*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Gusss yes on MacOS X >= 10.3.
darwin[1-6].*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
darwin*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on Solaris >= 2.6.
solaris2.[0-5]*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
solaris*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on AIX >= 4.
aix[1-3]*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
aix*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on HP-UX >= 11.
hpux[7-9]* | hpux10*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
hpux*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on IRIX >= 6.5.
irix6.5) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on OSF/1 >= 5.
osf[3-4]*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
osf*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on NetBSD >= 3.
netbsd[1-2]*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
netbsd*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl Guess yes on BeOS.
beos*) gl_cv_func_snprintf_truncation_c99="guessing
yes";;
dnl If we don't know, assume the worst.
*) gl_cv_func_snprintf_truncation_c99="guessing
no";;
esac
changequote([,])dnl
])
])
])
dnl Test whether the return value of the snprintf function is the number
dnl of bytes (excluding the terminating NUL) that would have been produced
dnl if the buffer had been large enough. (ISO C99, POSIX:2001)
dnl Result is gl_cv_func_printf_retval_c99.
AC_DEFUN([gl_SNPRINTF_RETVAL_C99],
[
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
AC_CACHE_CHECK([whether snprintf returns a byte count as in C99],
[gl_cv_func_printf_retval_c99],
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
static char buf[100];
int main ()
{
strcpy (buf, "ABCDEF");
if (snprintf (buf, 3, "%d %d", 4567, 89) != 7)
return 1;
return 0;
}], [gl_cv_func_printf_retval_c99=yes], [gl_cv_func_printf_retval_c99=no],
[
changequote(,)dnl
case "$host_os" in
dnl Guess yes on glibc systems.
*-gnu*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Guess yes on FreeBSD >= 5.
freebsd[1-4]*) gl_cv_func_printf_retval_c99="guessing no";;
freebsd* | kfreebsd*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Gusss yes on MacOS X >= 10.3.
darwin[1-6].*) gl_cv_func_printf_retval_c99="guessing no";;
darwin*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Guess yes on Solaris >= 2.6.
solaris2.[0-5]*) gl_cv_func_printf_retval_c99="guessing no";;
solaris*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Guess yes on AIX >= 4.
aix[1-3]*) gl_cv_func_printf_retval_c99="guessing no";;
aix*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Guess yes on NetBSD >= 3.
netbsd[1-2]*) gl_cv_func_printf_retval_c99="guessing no";;
netbsd*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl Guess yes on BeOS.
beos*) gl_cv_func_printf_retval_c99="guessing yes";;
dnl If we don't know, assume the worst.
*) gl_cv_func_printf_retval_c99="guessing no";;
esac
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_N
dnl 4 = gl_PRINTF_POSITIONS
dnl 5 = gl_SNPRINTF_PRESENCE
dnl 6 = gl_SNPRINTF_TRUNCATION_C99
dnl 7 = gl_SNPRINTF_RETVAL_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 'n' directive...
dnl 4 = checking whether printf supports POSIX/XSI format strings with
positions...
dnl 5 = checking for snprintf...
dnl 6 = checking whether snprintf truncates the result as in C99...
dnl 7 = checking whether snprintf returns a byte count as in C99...
dnl
dnl . = yes, # = no.
dnl
dnl 1 2 3 4 5 6 7
dnl glibc 2.3.6 . . . . . . .
dnl FreeBSD 5.4, 6.1 . . . . . . .
dnl MacOS X 10.3.9 . . . . . . .
dnl Cygwin 2007 . # . . . . .
dnl Solaris 10 . # . . . . .
dnl Solaris 2.6 ... 9 # # . . . . .
dnl Solaris 2.5.1 # # . . # # #
dnl AIX 4.3.2, 5.1 # # . . . . .
dnl HP-UX 11.31 . # . . . . #
dnl HP-UX 11.00, 11.11, 11.23 # # . . . . #
dnl HP-UX 10.20 # # # ? . ? #
dnl IRIX 6.5 # # . . . . #
dnl OSF/1 5.1 # # . . . . #
dnl OSF/1 4.0d # # . . # # #
dnl NetBSD 3.0 . # . # . . .
dnl BeOS # # . # . . .
dnl mingw # # . # . # #
==============================================================================
*** lib/vasnprintf.c 25 Feb 2007 21:17:11 -0000 1.23
--- lib/vasnprintf.c 4 Mar 2007 23:19:38 -0000
***************
*** 49,54 ****
--- 49,63 ----
/* Checked size_t computations. */
#include "xsize.h"
+ #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
+ # include "isnan.h"
+ # include "isnanl.h"
+ # if HAVE_LONG_DOUBLE
+ # include "printf-frexp.h"
+ # include "printf-frexpl.h"
+ # endif
+ #endif
+
#if HAVE_WCHAR_T
# if HAVE_WCSLEN
# define local_wcslen wcslen
***************
*** 257,262 ****
--- 266,737 ----
abort ();
}
}
+ #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
+ else if (dp->conversion == 'a' || dp->conversion == 'A')
+ {
+ arg_type type = a.arg[dp->arg_index].type;
+ int flags = dp->flags;
+ int has_width;
+ size_t width;
+ int has_precision;
+ size_t precision;
+ 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;
+ }
+ }
+
+ /* Allocate a temporary buffer of sufficient size. */
+ # if HAVE_LONG_DOUBLE
+ if (type == TYPE_LONGDOUBLE)
+ tmp_length =
+ (unsigned int) ((LDBL_DIG + 1)
+ * 0.831 /* decimal -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ else
+ # endif
+ tmp_length =
+ (unsigned int) ((DBL_DIG + 1)
+ * 0.831 /* decimal -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = 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 HAVE_LONG_DOUBLE
+ if (type == TYPE_LONGDOUBLE)
+ {
+ long double arg = a.arg[dp->arg_index].a.a_longdouble;
+
+ if (isnanl (arg))
+ {
+ if (dp->conversion == 'A')
+ {
+ *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+ }
+ else
+ {
+ *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+ }
+ }
+ else
+ {
+ int sign = 0;
+
+ if (arg < 0.0L)
+ {
+ sign = -1;
+ arg = -arg;
+ }
+ else if (arg == 0.0L)
+ {
+ /* Distinguish 0.0L and -0.0L. */
+ static long double plus_zero = 0.0L;
+ long double arg_mem = arg;
+ if (memcmp (&plus_zero, &arg_mem, sizeof (long
double)) != 0)
+ {
+ sign = -1;
+ arg = -arg;
+ }
+ }
+
+ if (sign < 0)
+ *p++ = '-';
+ else if (flags & FLAG_SHOWSIGN)
+ *p++ = '+';
+ else if (flags & FLAG_SPACE)
+ *p++ = ' ';
+
+ if (x > 0.0L && x + x == x)
+ {
+ if (dp->conversion == 'A')
+ {
+ *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+ }
+ else
+ {
+ *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+ }
+ }
+ else
+ {
+ int exponent;
+ long double mantissa;
+
+ if (x > 0.0L)
+ mantissa = printf_frexpl (arg, &exponent);
+ else
+ {
+ exponent = 0;
+ mantissa = 0.0L;
+ }
+
+ if (has_precision
+ && precision < (unsigned int) ((LDBL_DIG + 1) *
0.831) + 1)
+ {
+ /* Round the mantissa. */
+ long double tail = arg;
+ size_t q;
+
+ for (q = precision; ; q--)
+ {
+ int digit = (int) tail;
+ tail -= digit;
+ if (q == 0)
+ {
+ if (digit & 1 ? tail >= 0.5L : tail >
0.5L)
+ tail = 1 - tail;
+ else
+ tail = 0;
+ break;
+ }
+ tail *= 16.0L;
+ }
+ if (tail > 0.0L)
+ for (q = precision; q > 0; q--)
+ tail *= 0.0625L;
+ arg += tail;
+ }
+
+ *p++ = '0';
+ *p++ = dp->conversion - 'A' + 'X';
+ pad_ptr = p;
+ {
+ int digit;
+
+ digit = (int) arg;
+ arg -= digit;
+ *p++ = '0' + digit;
+ if ((flags & FLAG_ALT) || arg > 0.0L)
+ {
+ *p++ = '.';
+ /* This loop terminates because we assume
+ that FLT_RADIX is a power of 2. */
+ while (arg > 0.0L)
+ {
+ arg *= 16.0L;
+ digit = (int) arg;
+ arg -= digit;
+ *p++ = digit
+ + (digit < 10
+ ? '0'
+ : dp->conversion - 10);
+ if (precision > 0)
+ precision--;
+ }
+ while (precision > 0)
+ {
+ *p++ = '0';
+ precision--;
+ }
+ }
+ }
+ *p++ = dp->conversion - 'A' + 'P';
+ # if WIDE_CHAR_VERSION
+ {
+ static const wchar_t decimal_format[] =
+ { '%', 'd', '\0' };
+ SNPRINTF (p, 6 + 1, decimal_format, exponent);
+ }
+ # else
+ sprintf (p, "%d", exponent);
+ # endif
+ while (*p != '\0')
+ p++;
+ }
+ }
+ }
+ else
+ # endif
+ {
+ double arg = a.arg[dp->arg_index].a.a_double;
+
+ if (isnan (arg))
+ {
+ if (dp->conversion == 'A')
+ {
+ *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+ }
+ else
+ {
+ *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+ }
+ }
+ else
+ {
+ int sign = 0;
+
+ if (arg < 0.0)
+ {
+ sign = -1;
+ arg = -arg;
+ }
+ else if (arg == 0.0)
+ {
+ /* Distinguish 0.0 and -0.0. */
+ static double plus_zero = 0.0;
+ double arg_mem = arg;
+ if (memcmp (&plus_zero, &arg_mem, sizeof (double))
!= 0)
+ {
+ sign = -1;
+ arg = -arg;
+ }
+ }
+
+ if (sign < 0)
+ *p++ = '-';
+ else if (flags & FLAG_SHOWSIGN)
+ *p++ = '+';
+ else if (flags & FLAG_SPACE)
+ *p++ = ' ';
+
+ if (x > 0.0 && x + x == x)
+ {
+ if (dp->conversion == 'A')
+ {
+ *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+ }
+ else
+ {
+ *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+ }
+ }
+ else
+ {
+ int exponent;
+ double mantissa;
+
+ if (x > 0.0)
+ mantissa = printf_frexp (arg, &exponent);
+ else
+ {
+ exponent = 0;
+ mantissa = 0.0;
+ }
+
+ if (has_precision
+ && precision < (unsigned int) ((DBL_DIG + 1) *
0.831) + 1)
+ {
+ /* Round the mantissa. */
+ double tail = arg;
+ size_t q;
+
+ for (q = precision; ; q--)
+ {
+ int digit = (int) tail;
+ tail -= digit;
+ if (q == 0)
+ {
+ if (digit & 1 ? tail >= 0.5 : tail >
0.5)
+ tail = 1 - tail;
+ else
+ tail = 0;
+ break;
+ }
+ tail *= 16.0;
+ }
+ if (tail > 0.0)
+ for (q = precision; q > 0; q--)
+ tail *= 0.0625;
+ arg += tail;
+ }
+
+ *p++ = '0';
+ *p++ = dp->conversion - 'A' + 'X';
+ pad_ptr = p;
+ {
+ int digit;
+
+ digit = (int) arg;
+ arg -= digit;
+ *p++ = '0' + digit;
+ if ((flags & FLAG_ALT) || arg > 0.0)
+ {
+ *p++ = '.';
+ /* This loop terminates because we assume
+ that FLT_RADIX is a power of 2. */
+ while (arg > 0.0)
+ {
+ arg *= 16.0;
+ digit = (int) arg;
+ arg -= digit;
+ *p++ = digit
+ + (digit < 10
+ ? '0'
+ : dp->conversion - 10);
+ if (precision > 0)
+ precision--;
+ }
+ while (precision > 0)
+ {
+ *p++ = '0';
+ precision--;
+ }
+ }
+ }
+ *p++ = dp->conversion - 'A' + 'P';
+ # if WIDE_CHAR_VERSION
+ {
+ static const wchar_t decimal_format[] =
+ { '%', 'd', '\0' };
+ SNPRINTF (p, 6 + 1, decimal_format, exponent);
+ }
+ # else
+ sprintf (p, "%d", exponent);
+ # endif
+ while (*p != '\0')
+ p++;
+ }
+ }
+ }
+ /* 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
else
{
arg_type type = a.arg[dp->arg_index].type;
*** m4/vasnprintf.m4 27 Oct 2006 17:11:53 -0000 1.10
--- m4/vasnprintf.m4 4 Mar 2007 23:20:46 -0000
***************
*** 1,5 ****
! # vasnprintf.m4 serial 7
! dnl Copyright (C) 2002-2004, 2006 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
--- 1,5 ----
! # vasnprintf.m4 serial 8
! 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,
dnl with or without modifications, as long as this notice is preserved.
***************
*** 7,24 ****
AC_DEFUN([gl_FUNC_VASNPRINTF],
[
AC_REQUIRE([gl_EOVERFLOW])
! AC_REPLACE_FUNCS(vasnprintf)
if test $ac_cv_func_vasnprintf = no; then
! AC_LIBOBJ(printf-args)
! AC_LIBOBJ(printf-parse)
! AC_LIBOBJ(asnprintf)
! gl_PREREQ_PRINTF_ARGS
! gl_PREREQ_PRINTF_PARSE
! gl_PREREQ_VASNPRINTF
! gl_PREREQ_ASNPRINTF
fi
])
# Prequisites of lib/printf-args.h, lib/printf-args.c.
AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
[
--- 7,30 ----
AC_DEFUN([gl_FUNC_VASNPRINTF],
[
AC_REQUIRE([gl_EOVERFLOW])
! AC_CHECK_FUNCS([vasnprintf])
if test $ac_cv_func_vasnprintf = no; then
! gl_REPLACE_VASNPRINTF
fi
])
+ AC_DEFUN([gl_REPLACE_VASNPRINTF],
+ [
+ AC_LIBOBJ([vasnprintf])
+ AC_LIBOBJ([printf-args])
+ AC_LIBOBJ([printf-parse])
+ AC_LIBOBJ([asnprintf])
+ gl_PREREQ_PRINTF_ARGS
+ gl_PREREQ_PRINTF_PARSE
+ gl_PREREQ_VASNPRINTF
+ gl_PREREQ_ASNPRINTF
+ ])
+
# Prequisites of lib/printf-args.h, lib/printf-args.c.
AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
[