New module 'vasnprintf-posix'.
authorBruno Haible <bruno@clisp.org>
Sun, 4 Mar 2007 23:28:59 +0000 (23:28 +0000)
committerBruno Haible <bruno@clisp.org>
Sun, 4 Mar 2007 23:28:59 +0000 (23:28 +0000)
ChangeLog
lib/vasnprintf.c
m4/printf.m4 [new file with mode: 0644]
m4/vasnprintf-posix.m4 [new file with mode: 0644]
m4/vasnprintf.m4
modules/vasnprintf-posix [new file with mode: 0644]

index b7567bc..2ce2005 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2007-03-04  Bruno Haible  <bruno@clisp.org>
 
+       * 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  <bruno@clisp.org>
+
        Compile progreloc.c only if --enable-relocatable is specified.
        * m4/relocatable.m4 (gl_RELOCATABLE): Arrange to compile progreloc.c
        if --enable-relocatable was specified.
index 33e90d5..8af1063 100644 (file)
 /* 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 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
                    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 (file)
index 0000000..7c97b95
--- /dev/null
@@ -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 <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                           #  #  .  #  .  #  #
diff --git a/m4/vasnprintf-posix.m4 b/m4/vasnprintf-posix.m4
new file mode 100644 (file)
index 0000000..8556794
--- /dev/null
@@ -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
+])
index 72c9a13..4ae3d10 100644 (file)
@@ -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 @@ dnl with or without modifications, as long as this notice is preserved.
 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 (file)
index 0000000..e72337a
--- /dev/null
@@ -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
+