# HG changeset patch # User Bruno Haible # Date 1173050939 0 # Node ID 2c9de3b6ba5ba049795400692ccd6958213dea80 # Parent a601c63691bf6ad40e529b83aea985af2c31d08f New module 'vasnprintf-posix'. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2007-03-04 Bruno Haible + + * 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. + 2007-03-04 Bruno Haible Compile progreloc.c only if --enable-relocatable is specified. diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -49,6 +49,15 @@ /* 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,6 +266,472 @@ 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; diff --git a/m4/printf.m4 b/m4/printf.m4 new file mode 100644 --- /dev/null +++ b/m4/printf.m4 @@ -0,0 +1,357 @@ +# 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 +#include +#include +#include +#if HAVE_STDINT_H_WITH_UINTMAX +# include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +# include +#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 +#include +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 +#include +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 +#include +/* 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 +#include +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 +#include +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 # # . # . # # diff --git a/m4/vasnprintf-posix.m4 b/m4/vasnprintf-posix.m4 new file mode 100644 --- /dev/null +++ b/m4/vasnprintf-posix.m4 @@ -0,0 +1,29 @@ +# 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 +]) diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4 --- a/m4/vasnprintf.m4 +++ b/m4/vasnprintf.m4 @@ -1,5 +1,5 @@ -# vasnprintf.m4 serial 7 -dnl Copyright (C) 2002-2004, 2006 Free Software Foundation, Inc. +# 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,18 +7,24 @@ AC_DEFUN([gl_FUNC_VASNPRINTF], [ AC_REQUIRE([gl_EOVERFLOW]) - AC_REPLACE_FUNCS(vasnprintf) + AC_CHECK_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 + 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], [ diff --git a/modules/vasnprintf-posix b/modules/vasnprintf-posix new file mode 100644 --- /dev/null +++ b/modules/vasnprintf-posix @@ -0,0 +1,29 @@ +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 +