changeset 8804:6ce313658b4d

Work around an incorrect implementation of the 0 flag on most platforms.
author Bruno Haible <bruno@clisp.org>
date Sun, 06 May 2007 23:02:10 +0000
parents 6c1d98929550
children c6df1b1d2c81
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 tests/test-snprintf-posix.h tests/test-sprintf-posix.h tests/test-vasnprintf-posix.c tests/test-vasprintf-posix.c
diffstat 24 files changed, 935 insertions(+), 168 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2007-05-06  Bruno Haible  <bruno@clisp.org>
+
+	* lib/vasnprintf.c (VASNPRINTF) [NEED_PRINTF_FLAG_ZERO]: Perform the
+	padding ourselves for the floating-point directives.
+	* m4/printf.m4 (gl_PRINTF_FLAG_ZERO): New macro.
+	* m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_FLAG_ZERO): New macro.
+	* m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_POSIX): Invoke
+	gl_PRINTF_FLAG_ZERO and test its result. Invoke
+	gl_PREREQ_VASNPRINTF_FLAG_ZERO.
+	* m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_POSIX): Likewise.
+	* m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_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.
+	* tests/test-snprintf-posix.h (test_function): Also check the width
+	and some flags in the %f directive.
+	* tests/test-sprintf-posix.h (test_function): Likewise.
+	* tests/test-vasnprintf-posix.c (test_function): Likewise.
+	* tests/test-vasprintf-posix.c (test_function): 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-06  Bruno Haible  <bruno@clisp.org>
 
 	* lib/vasnprintf.c (VASNPRINTF) [NEED_PRINTF_FLAG_GROUPING]: Don't
--- a/doc/functions/fprintf.texi
+++ b/doc/functions/fprintf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/printf.texi
+++ b/doc/functions/printf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/snprintf.texi
+++ b/doc/functions/snprintf.texi
@@ -34,6 +34,10 @@
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
 @item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
+@item
 This function does not truncate the result as specified in C99 on some platforms:
 mingw.
 @item
@@ -51,10 +55,6 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/sprintf.texi
+++ b/doc/functions/sprintf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/vfprintf.texi
+++ b/doc/functions/vfprintf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/vprintf.texi
+++ b/doc/functions/vprintf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/vsnprintf.texi
+++ b/doc/functions/vsnprintf.texi
@@ -34,6 +34,10 @@
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
 @item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
+@item
 This function does not truncate the result as specified in C99 on some platforms:
 mingw.
 @item
@@ -51,10 +55,6 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/doc/functions/vsprintf.texi
+++ b/doc/functions/vsprintf.texi
@@ -26,15 +26,15 @@
 @item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, mingw.
+@item
+printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
+with zeroes) on some platforms:
+MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, AIX 5.2, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-printf @code{"%010f"} of NaN and Infinity yields an incorrect result (padded
-with zeroes) on some platforms:
-FreeBSD 6.0.
-@item
 printf of @samp{long double} numbers is unsupported on some platforms:
 mingw.
 @end itemize
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -756,42 +756,65 @@
 	    else
 	      {
 		arg_type type = a.arg[dp->arg_index].type;
-		CHAR_T *p;
+		int flags = dp->flags;
+#if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO
+		int has_width;
+		size_t width;
+#endif
+#if NEED_PRINTF_FLAG_ZERO
+		int pad_ourselves;
+#else
+#		define pad_ourselves 0
+#endif
+		CHAR_T *fbp;
 		unsigned int prefix_count;
 		int prefixes[2];
 #if !USE_SNPRINTF
 		size_t tmp_length;
 		CHAR_T tmpbuf[700];
 		CHAR_T *tmp;
+#endif
 
+#if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO
+		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;
+		  }
+#endif
+
+#if !USE_SNPRINTF
 		/* Allocate a temporary buffer of sufficient size for calling
 		   sprintf.  */
 		{
-		  size_t width;
 		  size_t precision;
 
-		  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;
-			  width = (arg < 0 ? (unsigned int) (-arg) : arg);
-			}
-		      else
-			{
-			  const CHAR_T *digitp = dp->width_start;
-
-			  do
-			    width = xsum (xtimes (width, 10), *digitp++ - '0');
-			  while (digitp != dp->width_end);
-			}
-		    }
-
 		  precision = 6;
 		  if (dp->precision_start != dp->precision_end)
 		    {
@@ -1008,39 +1031,56 @@
 		  }
 #endif
 
+		/* Decide whether to perform the padding ourselves.  */
+#if NEED_PRINTF_FLAG_ZERO
+		switch (dp->conversion)
+		  {
+		  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+		  case 'a': case 'A':
+		    pad_ourselves = 1;
+		    break;
+		  default:
+		    pad_ourselves = 0;
+		    break;
+		  }
+#endif
+
 		/* Construct the format string for calling snprintf or
 		   sprintf.  */
-		p = buf;
-		*p++ = '%';
+		fbp = buf;
+		*fbp++ = '%';
 #if NEED_PRINTF_FLAG_GROUPING
 		/* The underlying implementation doesn't support the ' flag.
 		   Produce no grouping characters in this case; this is
 		   acceptable because the grouping is locale dependent.  */
 #else
-		if (dp->flags & FLAG_GROUP)
-		  *p++ = '\'';
+		if (flags & FLAG_GROUP)
+		  *fbp++ = '\'';
 #endif
-		if (dp->flags & FLAG_LEFT)
-		  *p++ = '-';
-		if (dp->flags & FLAG_SHOWSIGN)
-		  *p++ = '+';
-		if (dp->flags & FLAG_SPACE)
-		  *p++ = ' ';
-		if (dp->flags & FLAG_ALT)
-		  *p++ = '#';
-		if (dp->flags & FLAG_ZERO)
-		  *p++ = '0';
-		if (dp->width_start != dp->width_end)
+		if (flags & FLAG_LEFT)
+		  *fbp++ = '-';
+		if (flags & FLAG_SHOWSIGN)
+		  *fbp++ = '+';
+		if (flags & FLAG_SPACE)
+		  *fbp++ = ' ';
+		if (flags & FLAG_ALT)
+		  *fbp++ = '#';
+		if (!pad_ourselves)
 		  {
-		    size_t n = dp->width_end - dp->width_start;
-		    memcpy (p, dp->width_start, n * sizeof (CHAR_T));
-		    p += n;
+		    if (flags & FLAG_ZERO)
+		      *fbp++ = '0';
+		    if (dp->width_start != dp->width_end)
+		      {
+			size_t n = dp->width_end - dp->width_start;
+			memcpy (fbp, dp->width_start, n * sizeof (CHAR_T));
+			fbp += n;
+		      }
 		  }
 		if (dp->precision_start != dp->precision_end)
 		  {
 		    size_t n = dp->precision_end - dp->precision_start;
-		    memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
-		    p += n;
+		    memcpy (fbp, dp->precision_start, n * sizeof (CHAR_T));
+		    fbp += n;
 		  }
 
 		switch (type)
@@ -1048,7 +1088,7 @@
 #if HAVE_LONG_LONG_INT
 		  case TYPE_LONGLONGINT:
 		  case TYPE_ULONGLONGINT:
-		    *p++ = 'l';
+		    *fbp++ = 'l';
 		    /*FALLTHROUGH*/
 #endif
 		  case TYPE_LONGINT:
@@ -1059,31 +1099,31 @@
 #if HAVE_WCHAR_T
 		  case TYPE_WIDE_STRING:
 #endif
-		    *p++ = 'l';
+		    *fbp++ = 'l';
 		    break;
 		  case TYPE_LONGDOUBLE:
-		    *p++ = 'L';
+		    *fbp++ = 'L';
 		    break;
 		  default:
 		    break;
 		  }
 #if NEED_PRINTF_DIRECTIVE_F
 		if (dp->conversion == 'F')
-		  *p = 'f';
+		  *fbp = 'f';
 		else
 #endif
-		  *p = dp->conversion;
+		  *fbp = dp->conversion;
 #if USE_SNPRINTF
-		p[1] = '%';
-		p[2] = 'n';
-		p[3] = '\0';
+		fbp[1] = '%';
+		fbp[2] = 'n';
+		fbp[3] = '\0';
 #else
-		p[1] = '\0';
+		fbp[1] = '\0';
 #endif
 
 		/* Construct the arguments for calling snprintf or sprintf.  */
 		prefix_count = 0;
-		if (dp->width_arg_index != ARG_NONE)
+		if (!pad_ourselves && dp->width_arg_index != ARG_NONE)
 		  {
 		    if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
 		      abort ();
@@ -1288,11 +1328,11 @@
 		      {
 			/* snprintf() doesn't understand the '%n'
 			   directive.  */
-			if (p[1] != '\0')
+			if (fbp[1] != '\0')
 			  {
 			    /* Don't use the '%n' directive; instead, look
 			       at the snprintf() return value.  */
-			    p[1] = '\0';
+			    fbp[1] = '\0';
 			    continue;
 			  }
 			else
@@ -1328,6 +1368,77 @@
 			return NULL;
 		      }
 
+		    /* Perform padding.  */
+#if NEED_PRINTF_FLAG_ZERO
+		    if (pad_ourselves && has_width && count < width)
+		      {
+# if USE_SNPRINTF
+			/* Make room for the result.  */
+			if (width >= maxlen)
+			  {
+			    /* Need at least width bytes.  But allocate
+			       proportionally, to avoid looping eternally if
+			       snprintf() reports a too small count.  */
+			    size_t n =
+			      xmax (xsum (length, width),
+				    xtimes (allocated, 2));
+
+			    length += count;
+			    ENSURE_ALLOCATION (n);
+			    length -= count;
+			    maxlen = allocated - length; /* >= width */
+			  }
+# endif
+			{
+# if USE_SNPRINTF
+			  CHAR_T * const rp = result + length;
+# else
+			  CHAR_T * const rp = tmp;
+# endif
+			  CHAR_T *p = rp + count;
+			  size_t pad = width - count;
+			  CHAR_T *end = p + pad;
+			  CHAR_T *pad_ptr = (*rp == '-' ? rp + 1 : rp);
+			  /* No zero-padding of "inf" and "nan".  */
+			  if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
+			      || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
+			    pad_ptr = NULL;
+			  /* The generated string now extends from rp to p,
+			     with the zero padding insertion point being at
+			     pad_ptr.  */
+
+			  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 > rp)
+				*--q = *--p;
+			      for (; pad > 0; pad--)
+				*p++ = ' ';
+			    }
+
+			  count = width; /* = count + pad = end - rp */
+			}
+		      }
+#endif
+
 #if !USE_SNPRINTF
 		    if (count >= tmp_length)
 		      /* tmp_length was incorrectly calculated - fix the
--- a/m4/fprintf-posix.m4
+++ b/m4/fprintf-posix.m4
@@ -1,4 +1,4 @@
-# fprintf-posix.m4 serial 4
+# fprintf-posix.m4 serial 5
 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,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_fprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
@@ -26,8 +27,12 @@
                     *yes)
                       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
                       ;;
@@ -44,6 +49,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_FPRINTF
   fi
--- a/m4/printf.m4
+++ b/m4/printf.m4
@@ -1,4 +1,4 @@
-# printf.m4 serial 8
+# printf.m4 serial 9
 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,
@@ -318,6 +318,45 @@
     ])
 ])
 
+dnl Test whether the *printf family of functions supports padding of non-finite
+dnl values with the 0 flag correctly. (ISO C99 + TC1 + TC2.) See
+dnl <http://lists.gnu.org/archive/html/bug-gnulib/2007-04/msg00107.html>
+dnl Result is gl_cv_func_printf_flag_zero.
+
+AC_DEFUN([gl_PRINTF_FLAG_ZERO],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether printf supports the zero flag correctly],
+    [gl_cv_func_printf_flag_zero],
+    [
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <string.h>
+static char buf[100];
+int main ()
+{
+  if (sprintf (buf, "%010f", 1.0 / 0.0, 33, 44, 55) < 0
+      || (strcmp (buf, "       inf") != 0
+          && strcmp (buf, "  infinity") != 0))
+    return 1;
+  return 0;
+}], [gl_cv_func_printf_flag_zero=yes], [gl_cv_func_printf_flag_zero=no],
+      [
+changequote(,)dnl
+       case "$host_os" in
+                 # Guess yes on glibc systems.
+         *-gnu*) gl_cv_func_printf_flag_zero="guessing yes";;
+                 # Guess yes on BeOS.
+         beos*)  gl_cv_func_printf_flag_zero="guessing yes";;
+                 # If we don't know, assume the worst.
+         *)      gl_cv_func_printf_flag_zero="guessing no";;
+       esac
+changequote([,])dnl
+      ])
+    ])
+])
+
 dnl Test whether the snprintf function exists. (ISO C99, POSIX:2001)
 dnl Result is ac_cv_func_snprintf.
 
@@ -625,11 +664,12 @@
 dnl 4 = gl_PRINTF_DIRECTIVE_N
 dnl 5 = gl_PRINTF_POSITIONS
 dnl 6 = gl_PRINTF_FLAG_GROUPING
-dnl 7 = gl_SNPRINTF_PRESENCE
-dnl 8 = gl_SNPRINTF_TRUNCATION_C99
-dnl 9 = gl_SNPRINTF_RETVAL_C99
-dnl 10 = gl_SNPRINTF_DIRECTIVE_N
-dnl 11 = gl_VSNPRINTF_ZEROSIZE_C99
+dnl 7 = gl_PRINTF_FLAG_ZERO
+dnl 8 = gl_SNPRINTF_PRESENCE
+dnl 9 = gl_SNPRINTF_TRUNCATION_C99
+dnl 10 = gl_SNPRINTF_RETVAL_C99
+dnl 11 = gl_SNPRINTF_DIRECTIVE_N
+dnl 12 = gl_VSNPRINTF_ZEROSIZE_C99
 dnl
 dnl 1 = checking whether printf supports size specifiers as in C99...
 dnl 2 = checking whether printf supports the 'a' and 'A' directives...
@@ -637,33 +677,34 @@
 dnl 4 = checking whether printf supports the 'n' directive...
 dnl 5 = checking whether printf supports POSIX/XSI format strings with positions...
 dnl 6 = checking whether printf supports the grouping flag...
-dnl 7 = checking for snprintf...
-dnl 8 = checking whether snprintf truncates the result as in C99...
-dnl 9 = checking whether snprintf returns a byte count as in C99...
-dnl 10 = checking whether snprintf fully supports the 'n' directive...
-dnl 11 = checking whether vsnprintf respects a zero size as in C99...
+dnl 7 = checking whether printf supports the zero flag correctly...
+dnl 8 = checking for snprintf...
+dnl 9 = checking whether snprintf truncates the result as in C99...
+dnl 10 = checking whether snprintf returns a byte count as in C99...
+dnl 11 = checking whether snprintf fully supports the 'n' directive...
+dnl 12 = checking whether vsnprintf respects a zero size as in C99...
 dnl
 dnl . = yes, # = no.
 dnl
-dnl                                        1  2  3  4  5  6  7  8  9 10 11
-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                          .  #  #  .  .  ?  .  .  .  .  ?
-dnl   Cygwin 2006                          #  #  #  .  .  ?  .  .  .  .  ?
-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
+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                          .  #  #  .  .  ?  ?  .  .  .  .  ?
+dnl   Cygwin 2006                          #  #  #  .  .  ?  ?  .  .  .  .  ?
+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                                #  #  #  .  #  #  #  .  #  #  #  .
--- a/m4/snprintf-posix.m4
+++ b/m4/snprintf-posix.m4
@@ -1,4 +1,4 @@
-# snprintf-posix.m4 serial 5
+# snprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_snprintf_posix=no
   AC_CHECK_FUNCS([snprintf])
   if test $ac_cv_func_snprintf = yes; then
@@ -32,17 +33,21 @@
                       *yes)
                         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
                                         ;;
@@ -68,6 +73,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_SNPRINTF
   fi
--- a/m4/sprintf-posix.m4
+++ b/m4/sprintf-posix.m4
@@ -1,4 +1,4 @@
-# sprintf-posix.m4 serial 4
+# sprintf-posix.m4 serial 5
 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,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_sprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
@@ -26,8 +27,12 @@
                     *yes)
                       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
                       ;;
@@ -44,6 +49,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_SPRINTF
   fi
--- a/m4/vasnprintf-posix.m4
+++ b/m4/vasnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasnprintf-posix.m4 serial 5
+# vasnprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_vasnprintf_posix=no
   AC_CHECK_FUNCS_ONCE([vasnprintf])
   case "$gl_cv_func_printf_sizes_c99" in
@@ -27,10 +28,15 @@
                     *yes)
                       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
                       ;;
@@ -47,6 +53,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
   fi
 ])
--- a/m4/vasnprintf.m4
+++ b/m4/vasnprintf.m4
@@ -1,4 +1,4 @@
-# vasnprintf.m4 serial 14
+# vasnprintf.m4 serial 15
 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,
@@ -105,6 +105,21 @@
   esac
 ])
 
+# Extra prerequisites of lib/vasnprintf.c for supporting the 0 flag.
+AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_ZERO],
+[
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
+  case "$gl_cv_func_printf_flag_zero" in
+    *yes)
+      ;;
+    *)
+      AC_DEFINE([NEED_PRINTF_FLAG_ZERO], 1,
+        [Define if the vasnprintf implementation needs special code for the
+         0 flag.])
+      ;;
+  esac
+])
+
 # Prerequisites of lib/asnprintf.c.
 AC_DEFUN([gl_PREREQ_ASNPRINTF],
 [
--- a/m4/vasprintf-posix.m4
+++ b/m4/vasprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasprintf-posix.m4 serial 5
+# vasprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_vasprintf_posix=no
   AC_CHECK_FUNCS([vasprintf])
   case "$gl_cv_func_printf_sizes_c99" in
@@ -27,10 +28,15 @@
                     *yes)
                       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
                       ;;
@@ -47,6 +53,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_VASPRINTF
   fi
--- a/m4/vfprintf-posix.m4
+++ b/m4/vfprintf-posix.m4
@@ -1,4 +1,4 @@
-# vfprintf-posix.m4 serial 4
+# vfprintf-posix.m4 serial 5
 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,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_vfprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
@@ -26,8 +27,12 @@
                     *yes)
                       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
                       ;;
@@ -44,6 +49,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_VFPRINTF
   fi
--- a/m4/vsnprintf-posix.m4
+++ b/m4/vsnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsnprintf-posix.m4 serial 5
+# vsnprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_vsnprintf_posix=no
   AC_CHECK_FUNCS([vsnprintf])
   if test $ac_cv_func_vsnprintf = yes; then
@@ -33,17 +34,21 @@
                       *yes)
                         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
                                         ;;
@@ -69,6 +74,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_VSNPRINTF
   fi
--- a/m4/vsprintf-posix.m4
+++ b/m4/vsprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsprintf-posix.m4 serial 4
+# vsprintf-posix.m4 serial 5
 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,
@@ -13,6 +13,7 @@
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
   AC_REQUIRE([gl_PRINTF_POSITIONS])
   AC_REQUIRE([gl_PRINTF_FLAG_GROUPING])
+  AC_REQUIRE([gl_PRINTF_FLAG_ZERO])
   gl_cv_func_vsprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
@@ -26,8 +27,12 @@
                     *yes)
                       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
                       ;;
@@ -44,6 +49,7 @@
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+    gl_PREREQ_VASNPRINTF_FLAG_ZERO
     gl_REPLACE_VASNPRINTF
     gl_REPLACE_VSPRINTF
   fi
--- a/tests/test-snprintf-posix.h
+++ b/tests/test-snprintf-posix.h
@@ -683,7 +683,61 @@
     ASSERT (retval == strlen (result));
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%-10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%+f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SPACE.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "% f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%#f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%#.f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char result[100];
     int retval =
       my_snprintf (result, sizeof (result), "%015f %d", 1234.0, 33, 44, 55);
@@ -700,6 +754,14 @@
     ASSERT (retval == strlen (result));
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%015f %d", NaN (), 33, 44, 55);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   { /* Precision.  */
     char result[100];
     int retval =
@@ -775,7 +837,61 @@
     ASSERT (retval == strlen (result));
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%-10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%+Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SPACE.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "% Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%#Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%#.Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char result[100];
     int retval =
       my_snprintf (result, sizeof (result), "%015Lf %d", 1234.0L, 33, 44, 55);
@@ -792,6 +908,15 @@
     ASSERT (retval == strlen (result));
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    static long double zero = 0.0L;
+    char result[100];
+    int retval =
+      my_snprintf (result, sizeof (result), "%015Lf %d", zero / zero, 33, 44, 55);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   { /* Precision.  */
     char result[100];
     int retval =
--- a/tests/test-sprintf-posix.h
+++ b/tests/test-sprintf-posix.h
@@ -669,7 +669,55 @@
     ASSERT (retval == strlen (result));
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%10f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%-10f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%+f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SPACE.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "% f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%#f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%#.f %d", 1.75, 33, 44, 55);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char result[1000];
     int retval =
       my_sprintf (result, "%015f %d", 1234.0, 33, 44, 55);
@@ -686,6 +734,14 @@
     ASSERT (retval == strlen (result));
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%015f %d", NaN (), 33, 44, 55);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   { /* Precision.  */
     char result[1000];
     int retval =
@@ -761,7 +817,55 @@
     ASSERT (retval == strlen (result));
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%-10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%+Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_SPACE.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "% Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%#Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ALT.  */
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%#.Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char result[1000];
     int retval =
       my_sprintf (result, "%015Lf %d", 1234.0L, 33, 44, 55);
@@ -778,6 +882,15 @@
     ASSERT (retval == strlen (result));
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    static long double zero = 0.0L;
+    char result[1000];
+    int retval =
+      my_sprintf (result, "%015Lf %d", zero / zero, 33, 44, 55);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   { /* Precision.  */
     char result[1000];
     int retval =
--- a/tests/test-vasnprintf-posix.c
+++ b/tests/test-vasnprintf-posix.c
@@ -837,7 +837,67 @@
     free (result);
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%-10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%+f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SPACE.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "% f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%#f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%#.f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     size_t length;
     char *result =
       my_asnprintf (NULL, &length, "%015f %d", 1234.0, 33, 44, 55);
@@ -858,6 +918,16 @@
     free (result);
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%015f %d", NaN (), 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
   { /* Precision.  */
     size_t length;
     char *result =
@@ -951,7 +1021,67 @@
     free (result);
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%-10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%+Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SPACE.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "% Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%#Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%#.Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     size_t length;
     char *result =
       my_asnprintf (NULL, &length, "%015Lf %d", 1234.0L, 33, 44, 55);
@@ -972,6 +1102,17 @@
     free (result);
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    static long double zero = 0.0L;
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%015Lf %d", zero / zero, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
   { /* Precision.  */
     size_t length;
     char *result =
--- a/tests/test-vasprintf-posix.c
+++ b/tests/test-vasprintf-posix.c
@@ -818,7 +818,67 @@
     free (result);
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%-10f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%+f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SPACE.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "% f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%#f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%#.f %d", 1.75, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char *result;
     int retval =
       my_asprintf (&result, "%015f %d", 1234.0, 33, 44, 55);
@@ -839,6 +899,16 @@
     free (result);
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%015f %d", NaN (), 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
   { /* Precision.  */
     char *result;
     int retval =
@@ -932,7 +1002,67 @@
     free (result);
   }
 
-  { /* FLAG_ZERO.  */
+  { /* Width.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "  1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%-10Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000   33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SHOWSIGN.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%+Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "+1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_SPACE.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "% Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, " 1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%#Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "1.750000 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ALT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%#.Lf %d", 1.75L, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "2. 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_ZERO with finite number.  */
     char *result;
     int retval =
       my_asprintf (&result, "%015Lf %d", 1234.0L, 33, 44, 55);
@@ -953,6 +1083,17 @@
     free (result);
   }
 
+  { /* FLAG_ZERO with NaN.  */
+    static long double zero = 0.0L;
+    char *result;
+    int retval =
+      my_asprintf (&result, "%015Lf %d", zero / zero, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "            nan 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
   { /* Precision.  */
     char *result;
     int retval =