changeset 8840:792e05ae7ac8

Fix *printf result for NaN, Inf, -0.0 on mingw.
author Bruno Haible <bruno@clisp.org>
date Sat, 19 May 2007 14:52:36 +0000
parents 5efc1d668039
children 6a8178e3452e
files ChangeLog doc/functions/fprintf.texi doc/functions/printf.texi doc/functions/snprintf.texi doc/functions/sprintf.texi doc/functions/vfprintf.texi doc/functions/vprintf.texi doc/functions/vsnprintf.texi doc/functions/vsprintf.texi lib/vasnprintf.c m4/fprintf-posix.m4 m4/printf.m4 m4/snprintf-posix.m4 m4/sprintf-posix.m4 m4/vasnprintf-posix.m4 m4/vasnprintf.m4 m4/vasprintf-posix.m4 m4/vfprintf-posix.m4 m4/vsnprintf-posix.m4 m4/vsprintf-posix.m4
diffstat 20 files changed, 749 insertions(+), 426 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2007-05-19  Bruno Haible  <bruno@clisp.org>
+
+	Fix *printf result for NaN, Inf, -0.0 on mingw.
+	* m4/printf.m4 (gl_PRINTF_INFINITE): New macro.
+	* lib/vasnprintf.c: Include math.h and isnan.h.
+	(is_infinite_or_zero): New function.
+	(VASNPRINTF): Fix also the handling of infinite or zero 'double'
+	values in the %f, %F, %e, %E, %g, %G directives.
+	* m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_INFINITE): New macro.
+	* m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_POSIX): Invoke
+	gl_PRINTF_INFINITE and test its result. Invoke
+	gl_PREREQ_VASNPRINTF_INFINITE.
+	* 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.
+	* 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-19  Bruno Haible  <bruno@clisp.org>
 
 	* lib/vasnprintf.c (convert_to_decimal): Add an extra_zeroes argument.
--- a/doc/functions/fprintf.texi
+++ b/doc/functions/fprintf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/printf.texi
+++ b/doc/functions/printf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/snprintf.texi
+++ b/doc/functions/snprintf.texi
@@ -20,6 +20,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/sprintf.texi
+++ b/doc/functions/sprintf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/vfprintf.texi
+++ b/doc/functions/vfprintf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/vprintf.texi
+++ b/doc/functions/vprintf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/vsnprintf.texi
+++ b/doc/functions/vsnprintf.texi
@@ -20,6 +20,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/doc/functions/vsprintf.texi
+++ b/doc/functions/vsprintf.texi
@@ -13,6 +13,10 @@
 @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 @code{"%f"}, @code{"%e"}, @code{"%g"} of Infinity and NaN yields an
+incorrect result on some platforms:
+mingw.
+@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw, BeOS.
 @item
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -53,6 +53,16 @@
 /* Checked size_t computations.  */
 #include "xsize.h"
 
+#if NEED_PRINTF_INFINITE && !defined IN_LIBINTL
+# include <math.h>
+# include "isnan.h"
+#endif
+
+#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+# include <math.h>
+# include "float+.h"
+#endif
+
 #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
 # include <math.h>
 # include "isnan.h"
@@ -62,11 +72,6 @@
 # include "fpucw.h"
 #endif
 
-#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
-# include <math.h>
-# include "float+.h"
-#endif
-
 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
 #ifndef EOVERFLOW
 # define EOVERFLOW E2BIG
@@ -164,6 +169,17 @@
 # endif
 #endif
 
+#if NEED_PRINTF_INFINITE && !defined IN_LIBINTL
+
+/* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */
+static int
+is_infinite_or_zero (double x)
+{
+  return isnan (x) || x + x == x;
+}
+
+#endif
+
 #if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
 
 /* Converting 'long double' to decimal without rare rounding bugs requires
@@ -1257,18 +1273,29 @@
 		    abort ();
 		  }
 	      }
-#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+#if (NEED_PRINTF_INFINITE || 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)
+		     && (0
+# if NEED_PRINTF_INFINITE
+			 || (a.arg[dp->arg_index].type == TYPE_DOUBLE
+			     /* The systems (mingw) which produce wrong output
+				for Inf and -Inf also do so for NaN and -0.0.
+				Therefore we treat these cases here as well.  */
+			     && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double))
+# endif
+# if NEED_PRINTF_LONG_DOUBLE
+			 || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
+# endif
+			))
 	      {
+		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;
-		long double arg;
 		size_t tmp_length;
 		CHAR_T tmpbuf[700];
 		CHAR_T *tmp;
@@ -1337,19 +1364,38 @@
 		      }
 		  }
 
-		arg = a.arg[dp->arg_index].a.a_longdouble;
+		/* POSIX specifies the default precision to be 6 for %f, %F,
+		   %e, %E, but not for %g, %G.  Implementations appear to use
+		   the same default precision also for %g, %G.  */
+		if (!has_precision)
+		  precision = 6;
 
 		/* Allocate a temporary buffer of sufficient size.  */
+# if NEED_PRINTF_INFINITE && NEED_PRINTF_LONG_DOUBLE
+		tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0);
+# elif NEED_PRINTF_LONG_DOUBLE
 		tmp_length = LDBL_DIG + 1;
+# elif NEED_PRINTF_INFINITE
+		tmp_length = 0;
+# endif
 		if (tmp_length < precision)
 		  tmp_length = precision;
-		if (dp->conversion == 'f' || dp->conversion == 'F')
-		  if (!(isnanl (arg) || arg + arg == arg))
+# if NEED_PRINTF_LONG_DOUBLE
+#  if NEED_PRINTF_INFINITE
+		if (type == TYPE_LONGDOUBLE)
+#  endif
+		  if (dp->conversion == 'f' || dp->conversion == 'F')
 		    {
-		      int exponent = floorlog10l (arg < 0 ? -arg : arg);
-		      if (exponent >= 0 && tmp_length < exponent + precision)
-			tmp_length = exponent + precision;
+		      long double arg = a.arg[dp->arg_index].a.a_longdouble;
+		      if (!(isnanl (arg) || arg + arg == arg))
+			{
+			  /* arg is finite and nonzero.  */
+			  int exponent = floorlog10l (arg < 0 ? -arg : arg);
+			  if (exponent >= 0 && tmp_length < exponent + precision)
+			    tmp_length = exponent + precision;
+			}
 		    }
+# endif
 		/* Account for sign, decimal point etc. */
 		tmp_length = xsum (tmp_length, 12);
 
@@ -1376,156 +1422,88 @@
 		pad_ptr = NULL;
 		p = tmp;
 
-		if (isnanl (arg))
+# if NEED_PRINTF_LONG_DOUBLE
+#  if NEED_PRINTF_INFINITE
+		if (type == TYPE_LONGDOUBLE)
+#  endif
 		  {
-		    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
+		    long double arg = a.arg[dp->arg_index].a.a_longdouble;
 
-		    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 (isnanl (arg))
 		      {
 			if (dp->conversion >= 'A' && dp->conversion <= 'Z')
 			  {
-			    *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+			    *p++ = 'N'; *p++ = 'A'; *p++ = 'N';
 			  }
 			else
 			  {
-			    *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+			    *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
 			  }
 		      }
 		    else
 		      {
-			pad_ptr = p;
+			int sign = 0;
+			DECL_LONG_DOUBLE_ROUNDING
 
-			if (dp->conversion == 'f' || dp->conversion == 'F')
+			BEGIN_LONG_DOUBLE_ROUNDING ();
+
+			if (signbit (arg)) /* arg < 0.0L or negative zero */
 			  {
-			    char *digits;
-			    size_t ndigits;
-
-			    if (!has_precision)
-			      precision = 6;
+			    sign = -1;
+			    arg = -arg;
+			  }
 
-			    digits =
-			      scale10_round_decimal_long_double (arg, precision);
-			    if (digits == NULL)
+			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')
 			      {
-				END_LONG_DOUBLE_ROUNDING ();
-				goto out_of_memory;
+				*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
 			      }
-			    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];
-				  }
+				*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
 			      }
+			  }
+			else
+			  {
+			    pad_ptr = p;
+
+			    if (dp->conversion == 'f' || dp->conversion == 'F')
+			      {
+				char *digits;
+				size_t ndigits;
 
-			    free (digits);
-			  }
-			else if (dp->conversion == 'e' || dp->conversion == 'E')
-			  {
-			    int exponent;
+				digits =
+				  scale10_round_decimal_long_double (arg, precision);
+				if (digits == NULL)
+				  {
+				    END_LONG_DOUBLE_ROUNDING ();
+				    goto out_of_memory;
+				  }
+				ndigits = strlen (digits);
 
-			    if (!has_precision)
-			      precision = 6;
-
-			    if (arg == 0.0L)
-			      {
-				exponent = 0;
-				*p++ = '0';
+				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 > 0; precision--)
+				    for (; precision > ndigits; 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;
@@ -1535,116 +1513,212 @@
 
 				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;
+			    else if (dp->conversion == 'e' || dp->conversion == 'E')
+			      {
+				int exponent;
 
-			    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)
+				if (arg == 0.0L)
 				  {
-				    *p++ = decimal_point_char ();
-				    while (ndigits > nzeroes)
+				    exponent = 0;
+				    *p++ = '0';
+				    if ((flags & FLAG_ALT) || precision > 0)
 				      {
-					--ndigits;
-					*p++ = '0';
+					*p++ = decimal_point_char ();
+					for (; precision > 0; precision--)
+					  *p++ = '0';
 				      }
 				  }
-			      }
-			    else
-			      {
-				/* arg > 0.0L.  */
-				int exponent;
-				int adjusted;
-				char *digits;
-				size_t ndigits;
-				size_t nzeroes;
+				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;
+				      }
 
-				exponent = floorlog10l (arg);
-				adjusted = 0;
-				for (;;)
+				    /* 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')
+			      {
+				if (precision == 0)
+				  precision = 1;
+				/* precision >= 1.  */
+
+				if (arg == 0.0L)
+				  /* The exponent is 0, >= -4, < precision.
+				     Use fixed-point notation.  */
 				  {
-				    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);
+				    size_t ndigits = precision;
+				    /* Number of trailing zeroes that have to be
+				       dropped.  */
+				    size_t nzeroes =
+				      (flags & FLAG_ALT ? 0 : precision - 1);
 
-				    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;
+				    --ndigits;
+				    *p++ = '0';
+				    if ((flags & FLAG_ALT) || ndigits > nzeroes)
+				      {
+					*p++ = decimal_point_char ();
+					while (ndigits > nzeroes)
+					  {
+					    --ndigits;
+					    *p++ = '0';
+					  }
+				      }
 				  }
-				/* Here ndigits = precision.  */
+				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);
 
-				/* 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++;
+					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)
+				    /* The exponent is now determined.  */
+				    if (exponent >= -4
+					&& exponent < (long)precision)
 				      {
-					size_t count = exponent + 1;
-					/* Note: count <= precision = ndigits.  */
-					for (; count > 0; count--)
-					  *p++ = digits[--ndigits];
+					/* 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 ();
@@ -1654,57 +1728,132 @@
 						*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++;
 				      }
-				    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];
-					  }
-				      }
+
+				    free (digits);
 				  }
-				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);
+			      }
+			    else
+			      abort ();
+			  }
+
+			END_LONG_DOUBLE_ROUNDING ();
+		      }
+		  }
+#  if NEED_PRINTF_INFINITE
+		else
+#  endif
 # endif
-				    while (*p != '\0')
-				      p++;
-				  }
+# if NEED_PRINTF_INFINITE
+		  {
+		    /* Simpler than above: handle only NaN, Infinity, zero.  */
+		    double arg = a.arg[dp->arg_index].a.a_double;
+
+		    if (isnan (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;
 
-				free (digits);
+			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.0 && arg + arg == arg)
+			  {
+			    if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+			      {
+				*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+			      }
+			    else
+			      {
+				*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
 			      }
 			  }
 			else
-			  abort ();
-		      }
+			  {
+			    if (!(arg == 0.0))
+			      abort ();
+
+			    pad_ptr = p;
 
-		    END_LONG_DOUBLE_ROUNDING ();
+			    if (dp->conversion == 'f' || dp->conversion == 'F')
+			      {
+				*p++ = '0';
+				if ((flags & FLAG_ALT) || precision > 0)
+				  {
+				    *p++ = decimal_point_char ();
+				    for (; precision > 0; precision--)
+				      *p++ = '0';
+				  }
+			      }
+			    else if (dp->conversion == 'e' || dp->conversion == 'E')
+			      {
+				*p++ = '0';
+				if ((flags & FLAG_ALT) || precision > 0)
+				  {
+				    *p++ = decimal_point_char ();
+				    for (; precision > 0; precision--)
+				      *p++ = '0';
+				  }
+				*p++ = dp->conversion; /* 'e' or 'E' */
+				*p++ = '+';
+				/* Produce the same number of exponent digits as
+				   the native printf implementation.  */
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+				*p++ = '0';
+# endif
+				*p++ = '0';
+				*p++ = '0';
+			      }
+			    else if (dp->conversion == 'g' || dp->conversion == 'G')
+			      {
+				*p++ = '0';
+				if (flags & FLAG_ALT)
+				  {
+				    size_t ndigits =
+				      (precision > 0 ? precision - 1 : 0);
+				    *p++ = decimal_point_char ();
+				    for (; ndigits > 0; --ndigits)
+				      *p++ = '0';
+				  }
+			      }
+			    else
+			      abort ();
+			  }
+		      }
 		  }
+# endif
 
 		/* The generated string now extends from tmp to p, with the
 		   zero padding insertion point being at pad_ptr.  */
--- a/m4/fprintf-posix.m4
+++ b/m4/fprintf-posix.m4
@@ -1,4 +1,4 @@
-# fprintf-posix.m4 serial 6
+# fprintf-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_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -18,23 +19,27 @@
   gl_cv_func_fprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -52,6 +57,7 @@
       ;;
   esac
   if test $gl_cv_func_fprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/printf.m4
+++ b/m4/printf.m4
@@ -1,4 +1,4 @@
-# printf.m4 serial 10
+# printf.m4 serial 11
 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,54 @@
     ])
 ])
 
+dnl Test whether the *printf family of functions supports infinite 'double'
+dnl arguments in the %f, %e, %g directives. (ISO C99, POSIX:2001)
+dnl Result is gl_cv_func_printf_infinite.
+
+AC_DEFUN([gl_PRINTF_INFINITE],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether printf supports infinite 'double' arguments],
+    [gl_cv_func_printf_infinite], 
+    [
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <string.h>
+static char buf[100];
+int main ()
+{
+  if (sprintf (buf, "%f", 1.0 / 0.0) < 0
+      || (strcmp (buf, "inf") != 0 && strcmp (buf, "infinity") != 0))
+    return 1;
+  if (sprintf (buf, "%f", -1.0 / 0.0) < 0
+      || (strcmp (buf, "-inf") != 0 && strcmp (buf, "-infinity") != 0))
+    return 1;
+  if (sprintf (buf, "%e", 1.0 / 0.0) < 0
+      || (strcmp (buf, "inf") != 0 && strcmp (buf, "infinity") != 0))
+    return 1;
+  if (sprintf (buf, "%e", -1.0 / 0.0) < 0
+      || (strcmp (buf, "-inf") != 0 && strcmp (buf, "-infinity") != 0))
+    return 1;
+  if (sprintf (buf, "%g", 1.0 / 0.0) < 0
+      || (strcmp (buf, "inf") != 0 && strcmp (buf, "infinity") != 0))
+    return 1;
+  if (sprintf (buf, "%g", -1.0 / 0.0) < 0
+      || (strcmp (buf, "-inf") != 0 && strcmp (buf, "-infinity") != 0))
+    return 1;
+  return 0;
+}], [gl_cv_func_printf_infinite=yes], [gl_cv_func_printf_infinite=no],
+      [
+changequote(,)dnl
+       case "$host_os" in
+         mingw* | pw*) gl_cv_func_printf_infinite="guessing no";;
+         *)            gl_cv_func_printf_infinite="guessing yes";;
+       esac
+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.
@@ -705,54 +753,56 @@
 dnl The results of these tests on various platforms are:
 dnl
 dnl 1 = gl_PRINTF_SIZES_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 2 = gl_PRINTF_INFINITE
+dnl 3 = gl_PRINTF_LONG_DOUBLE
+dnl 4 = gl_PRINTF_DIRECTIVE_A
+dnl 5 = gl_PRINTF_DIRECTIVE_F
+dnl 6 = gl_PRINTF_DIRECTIVE_N
+dnl 7 = gl_PRINTF_POSITIONS
+dnl 8 = gl_PRINTF_FLAG_GROUPING
+dnl 9 = gl_PRINTF_FLAG_ZERO
+dnl 10 = gl_SNPRINTF_PRESENCE
+dnl 11 = gl_SNPRINTF_TRUNCATION_C99
+dnl 12 = gl_SNPRINTF_RETVAL_C99
+dnl 13 = gl_SNPRINTF_DIRECTIVE_N
+dnl 14 = gl_VSNPRINTF_ZEROSIZE_C99
 dnl
 dnl 1 = checking whether printf supports size specifiers as in C99...
-dnl 2 = checking whether printf supports 'long double' arguments...
-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 2 = checking whether printf supports infinite 'double' arguments...
+dnl 3 = checking whether printf supports 'long double' arguments...
+dnl 4 = checking whether printf supports the 'a' and 'A' directives...
+dnl 5 = checking whether printf supports the 'F' directive...
+dnl 6 = checking whether printf supports the 'n' directive...
+dnl 7 = checking whether printf supports POSIX/XSI format strings with positions...
+dnl 8 = checking whether printf supports the grouping flag...
+dnl 9 = checking whether printf supports the zero flag correctly...
+dnl 10 = checking for snprintf...
+dnl 11 = checking whether snprintf truncates the result as in C99...
+dnl 12 = checking whether snprintf returns a byte count as in C99...
+dnl 13 = checking whether snprintf fully supports the 'n' directive...
+dnl 14 = checking whether vsnprintf respects a zero size as in C99...
 dnl
 dnl . = yes, # = no.
 dnl
-dnl                                        1  2  3  4  5  6  7  8  9 10 11 12 13
-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 14
+dnl   glibc 2.5                         .  .  .  .  .  .  .  .  .  .  .  .  .  .
+dnl   glibc 2.3.6                       .  .  .  #  .  .  .  .  .  .  .  .  .  .
+dnl   FreeBSD 5.4, 6.1                  .  .  ?  ?  .  .  .  .  #  .  .  .  .  .
+dnl   MacOS X 10.3.9                    .  .  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   OpenBSD 3.9, 4.0                  .  ?  ?  #  ?  .  .  ?  ?  .  .  .  ?  ?
+dnl   Cygwin 2007 (= Cygwin 1.5.24)     .  ?  ?  #  #  .  .  .  #  .  .  .  .  .
+dnl   Cygwin 2006 (= Cygwin 1.5.19)     #  ?  ?  #  #  .  .  #  #  .  .  .  .  .
+dnl   Solaris 10                        .  ?  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   Solaris 2.6 ... 9                 #  ?  .  #  #  .  .  .  #  .  .  .  .  .
+dnl   Solaris 2.5.1                     #  ?  .  #  #  .  .  .  #  #  #  #  #  #
+dnl   AIX 5.2                           .  ?  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   AIX 4.3.2, 5.1                    #  ?  .  #  #  .  .  .  #  .  .  .  .  .
+dnl   HP-UX 11.31                       .  .  .  #  .  .  .  .  #  .  .  #  #  .
+dnl   HP-UX 10.20, 11.{00,11,23}        #  .  .  #  #  .  .  .  #  .  .  #  #  #
+dnl   IRIX 6.5                          #  ?  .  #  #  .  .  .  #  .  .  #  .  .
+dnl   OSF/1 5.1                         #  ?  .  #  #  .  .  .  #  .  .  #  .  #
+dnl   OSF/1 4.0d                        #  ?  .  #  #  .  .  .  #  #  #  #  #  #
+dnl   NetBSD 4.0                        .  ?  ?  ?  ?  .  .  ?  ?  .  .  .  ?  ?
+dnl   NetBSD 3.0                        .  ?  ?  #  #  .  #  #  #  .  .  .  .  .
+dnl   BeOS                              #  ?  #  #  #  .  #  .  .  .  .  .  .  .
+dnl   mingw                             #  #  #  #  #  .  #  #  #  .  #  #  #  .
--- a/m4/snprintf-posix.m4
+++ b/m4/snprintf-posix.m4
@@ -1,4 +1,4 @@
-# snprintf-posix.m4 serial 7
+# snprintf-posix.m4 serial 8
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -24,31 +25,35 @@
     gl_VSNPRINTF_ZEROSIZE_C99
     case "$gl_cv_func_printf_sizes_c99" in
       *yes)
-        case "$gl_cv_func_printf_long_double" in
+        case "$gl_cv_func_printf_infinite" 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
                                                 ;;
@@ -75,6 +80,7 @@
     esac
   fi
   if test $gl_cv_func_snprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/sprintf-posix.m4
+++ b/m4/sprintf-posix.m4
@@ -1,4 +1,4 @@
-# sprintf-posix.m4 serial 6
+# sprintf-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_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -18,23 +19,27 @@
   gl_cv_func_sprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -52,6 +57,7 @@
       ;;
   esac
   if test $gl_cv_func_sprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/vasnprintf-posix.m4
+++ b/m4/vasnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasnprintf-posix.m4 serial 7
+# vasnprintf-posix.m4 serial 8
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -19,25 +20,29 @@
   AC_CHECK_FUNCS_ONCE([vasnprintf])
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -55,6 +60,7 @@
       ;;
   esac
   if test $gl_cv_func_vasnprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/vasnprintf.m4
+++ b/m4/vasnprintf.m4
@@ -1,4 +1,4 @@
-# vasnprintf.m4 serial 16
+# vasnprintf.m4 serial 17
 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_CHECK_FUNCS(snprintf wcslen)
 ])
 
+# Extra prerequisites of lib/vasnprintf.c for supporting infinite 'double'
+# arguments.
+AC_DEFUN([gl_PREREQ_VASNPRINTF_INFINITE],
+[
+  AC_REQUIRE([gl_PRINTF_INFINITE])
+  case "$gl_cv_func_printf_infinite" in
+    *yes)
+      ;;
+    *)
+      AC_DEFINE([NEED_PRINTF_INFINITE], 1,
+        [Define if the vasnprintf implementation needs special code for
+         infinite 'double' arguments.])
+      ;;
+  esac
+])
+
 # Extra prerequisites of lib/vasnprintf.c for supporting 'long double'
 # arguments.
 AC_DEFUN([gl_PREREQ_VASNPRINTF_LONG_DOUBLE],
--- a/m4/vasprintf-posix.m4
+++ b/m4/vasprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasprintf-posix.m4 serial 7
+# vasprintf-posix.m4 serial 8
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -19,25 +20,29 @@
   AC_CHECK_FUNCS([vasprintf])
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -55,6 +60,7 @@
       ;;
   esac
   if test $gl_cv_func_vasprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/vfprintf-posix.m4
+++ b/m4/vfprintf-posix.m4
@@ -1,4 +1,4 @@
-# vfprintf-posix.m4 serial 6
+# vfprintf-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_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -18,23 +19,27 @@
   gl_cv_func_vfprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -52,6 +57,7 @@
       ;;
   esac
   if test $gl_cv_func_vfprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/vsnprintf-posix.m4
+++ b/m4/vsnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsnprintf-posix.m4 serial 7
+# vsnprintf-posix.m4 serial 8
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -25,31 +26,35 @@
     gl_VSNPRINTF_ZEROSIZE_C99
     case "$gl_cv_func_printf_sizes_c99" in
       *yes)
-        case "$gl_cv_func_printf_long_double" in
+        case "$gl_cv_func_printf_infinite" 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
                                                 ;;
@@ -76,6 +81,7 @@
     esac
   fi
   if test $gl_cv_func_vsnprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
--- a/m4/vsprintf-posix.m4
+++ b/m4/vsprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsprintf-posix.m4 serial 6
+# vsprintf-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_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_INFINITE])
   AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
@@ -18,23 +19,27 @@
   gl_cv_func_vsprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_long_double" in
+      case "$gl_cv_func_printf_infinite" 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
                               ;;
@@ -52,6 +57,7 @@
       ;;
   esac
   if test $gl_cv_func_vsprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_INFINITE
     gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F