www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2008/04/24/09:31:10

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
X-Recipient: djgpp-workers AT delorie DOT com
X-Authenticated: #27081556
X-Provags-ID: V01U2FsdGVkX19tTwhLwfNt66RLmPVIHkzCqcwlOzvBMjZastWOgL
fJiAurxqO5UvEi
From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
To: djgpp-workers AT delorie DOT com
Subject: Re: Implementation of certain conversion specifiers in _doprnt (patch #4)
Date: Thu, 24 Apr 2008 16:32:26 +0200
User-Agent: KMail/1.9.5
MIME-Version: 1.0
Message-Id: <200804241632.27815.juan.guerrero@gmx.de>
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

Implements numeric conversion specifier and provides test programs.

Regards,
Juan M. Guerrero


2008-04-24  Juan Manuel Guerrero  <juan DOT guerrero AT gmx DOT de>
	Diffs against djgpp CVS head of 2008-04-22.


	* src/libc/ansi/stdio/doprnt.c: Implementation of numeric conversion
	specifier support.  New function __traverse_argument_list added.

	* src/libc/ansi/stdio/printf.txh: Description of numeric conversion
	specifier for printf added.

	* src/docs/kb/wc204.txi: Info about numeric conversion specifier
	support for doprnt.c and printf family of functions added.

	*tests/libc/ansi/stdio/makefile: Testcase file printf4.c for testing
	numeric conversion specifiers added.

	* tests/libc/ansi/stdio/printf4.c: New file.  Implements tests for
	numeric conversion specifiers.

	* tests/libc/ansi/stdio/printf5.c: New file.  Implements tests for
	flags, conversion modifiers and numeric conversion specifiers for
	the printf family of functions.






diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi	2008-04-24 15:09:08 +0000
+++ djgpp/src/docs/kb/wc204.txi	2008-04-24 15:13:20 +0000
@@ -1137,3 +1137,9 @@ of @code{Unnormal}.
 The @code{a}, @code{A} and @code{F} conversion specifiers
 are now supported by @code{_doprnt} and the @code{printf}
 family of functions.
+
+@findex _doprnt AT r{, and numeric conversion specifiers}
+@findex printf AT r{, and numeric conversion specifiers}
+The @code{%n$} and @code{*m$} numeric conversion specifiers
+are now supported by @code{_doprnt} and the @code{printf}
+family of functions.
diff -aprNU3 djgpp.orig/src/libc/ansi/stdio/doprnt.c djgpp/src/libc/ansi/stdio/doprnt.c
--- djgpp.orig/src/libc/ansi/stdio/doprnt.c	2008-04-24 15:09:08 +0000
+++ djgpp/src/libc/ansi/stdio/doprnt.c	2008-04-24 15:13:20 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
@@ -44,12 +45,12 @@ static char *grouping;
 
 #define	PUTC(ch)	(void) putc(ch, fp)
 
-#define ARG(basetype) _ulonglong = \
-		flags&LONGDBL ? va_arg(argp, long long basetype) : \
-		flags&LONGINT ? va_arg(argp, long basetype) : \
-		flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
-		flags&CHARINT ? (char basetype)va_arg(argp, int) : \
-		(basetype)va_arg(argp, int)
+#define ARG(basetype) _ulonglong =                        \
+  flags & LONGDBL  ? va_arg(argp, long long basetype) :   \
+  flags & LONGINT  ? va_arg(argp, long basetype) :        \
+  flags & SHORTINT ? (short basetype)va_arg(argp, int) :  \
+  flags & CHARINT  ? (char basetype)va_arg(argp, int) :   \
+  (basetype)va_arg(argp, int)
 
 #define CONVERT(type, value, base, string, case)               \
   do {                                                         \
@@ -65,20 +66,20 @@ static char *grouping;
                               || ((x).ldt.exponent == 0x0000U && !((x).ldt.mantissah & 0x80000000UL)))
 #define IS_ZERO(x)           ((x).ldt.exponent == 0x0U && (x).ldt.mantissah == 0x0UL && (x).ldt.mantissal == 0x0UL)
 #define IS_NAN(x)            ((x).ldt.exponent == 0x7FFFU && ((x).ldt.mantissah & 0x7FFFFFFFUL || (x).ldt.mantissal))
-#define IS_PSEUDO_NUMBER(x)  (((x).ldt.exponent != 0x0000U && !((x).ldt.mantissah & 0x80000000UL))   /*  Pseudo-NaN, Pseudo-Infinity and Unnormal.  */ \
+#define IS_PSEUDO_NUMBER(x)  (((x).ldt.exponent != 0x0000U && !((x).ldt.mantissah & 0x80000000UL))   /*  Pseudo-NaN, Pseudo-Infinity and Unnormal.  */  \
                               || ((x).ldt.exponent == 0x0000U && (x).ldt.mantissah & 0x80000000UL))  /*  Pseudo-Denormal.  */
 
 static __inline__ int todigit(char c)
 {
-  if (c<='0') return 0;
-  if (c>='9') return 9;
+  if (c <= '0') return 0;
+  if (c >= '9') return 9;
   return c-'0';
 }
 static __inline__ char tochar(int n)
 {
-  if (n>=9) return '9';
-  if (n<=0) return '0';
-  return n+'0';
+  if (n >= 9) return '9';
+  if (n <= 0) return '0';
+  return n + '0';
 }
 
 /* have to deal with the negative buffer count kludge */
@@ -105,6 +106,7 @@ static char *exponentl(char *p, int expv
 static int isspeciall(long double d, char *bufp, int flags);
 #endif
 static __inline__ char * __grouping_format(char *string_start, char *string_end, char *buffer_end, int flags);
+static __inline__ va_list __traverse_argument_list(int index_of_arg_to_be_fetched, const char *format_string, va_list arg_list);
 
 static char NULL_REP[] = "(null)";
 static const char LOWER_DIGITS[] = "0123456789abcdef";
@@ -136,6 +138,10 @@ _doprnt(const char *fmt0, va_list argp, 
   char buf[BUF];		/* space for %c, %[diouxX], %[aAeEfFgG] */
   int neg_ldouble = FALSE;	/* TRUE if _ldouble is negative */
   struct lconv *locale_info;    /* current locale information */
+  int using_numeric_conv_spec;  /* TRUE if using numeric specifier, FALSE else */
+  va_list arg_list;		/* argument list */
+  va_list to_be_printed = NULL;	/* argument to be printed if numeric specifier are used */
+  const char *pos;		/* position in format string when checking for numeric conv spec */
 
 
   locale_info = localeconv();
@@ -149,6 +155,8 @@ _doprnt(const char *fmt0, va_list argp, 
   if ((fp->_flag & _IOWRT) == 0)
     return (EOF);
 
+  using_numeric_conv_spec = FALSE;
+  arg_list = argp;
   fmt = fmt0;
   for (cnt = 0;; ++fmt)
   {
@@ -197,6 +205,16 @@ _doprnt(const char *fmt0, va_list argp, 
        *	-- ANSI X3J11
        * They don't exclude field widths read from args.
        */
+      pos = fmt;
+      for (n = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+        n = 10 * n + todigit(*fmt);
+      if (*fmt == '$')
+      {
+        using_numeric_conv_spec = TRUE;
+        argp = __traverse_argument_list(n, fmt0, arg_list);
+      }
+      else
+        fmt = pos;
       if ((width = va_arg(argp, int)) >= 0)
 	goto rflag;
       width = -width;
@@ -209,7 +227,19 @@ _doprnt(const char *fmt0, va_list argp, 
       goto rflag;
     case '.':
       if (*++fmt == '*')
-	n = va_arg(argp, int);
+      {
+        pos = fmt;
+        for (n = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+          n = 10 * n + todigit(*fmt);
+        if (*fmt == '$')
+        {
+          using_numeric_conv_spec = TRUE;
+          argp = __traverse_argument_list(n, fmt0, arg_list);
+        }
+        else
+          fmt = pos;
+        n = va_arg(argp, int);
+      }
       else
       {
 	n = 0;
@@ -233,21 +263,30 @@ _doprnt(const char *fmt0, va_list argp, 
       do {
 	n = 10 * n + todigit(*fmt);
       } while (isascii((unsigned char)*++fmt) && isdigit((unsigned char)*fmt));
-      width = n;
-      --fmt;
+      if (*fmt == '$')
+      {
+        using_numeric_conv_spec = TRUE;
+        to_be_printed = __traverse_argument_list(n, fmt0, arg_list);
+      }
+      else
+      {
+        width = n;
+        --fmt;
+      }
       goto rflag;
     case 'L':
       flags |= LONGDBL;
       goto rflag;
     case 'h':
-      if (flags & SHORTINT) {
+      if (flags & SHORTINT)
+      {
 	/* C99 */
 	/* for 'hh' - char */
 	flags |= CHARINT;
 	flags &= ~SHORTINT;
-      } else {
-	flags |= SHORTINT;
       }
+      else
+	flags |= SHORTINT;
       goto rflag;
     case 'l':
       if (flags & LONGINT)
@@ -274,6 +313,8 @@ _doprnt(const char *fmt0, va_list argp, 
       /*FALLTHROUGH*/
     case 'd':
     case 'i':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       ARG(signed);
       if ((long long)_ulonglong < 0)
       {
@@ -292,6 +333,8 @@ _doprnt(const char *fmt0, va_list argp, 
     case 'e':
     case 'f':
     case 'g':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       flags |= FLOAT;
       if (*fmt == 'A' || *fmt == 'a')
       {
@@ -378,6 +421,8 @@ _doprnt(const char *fmt0, va_list argp, 
       base = flags & HEXPREFIX ? 16 : 10;
       goto pforw;
     case 'n':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       if (flags & LONGDBL)
         *va_arg(argp, long long *) = cnt;
       else if (flags & LONGINT)
@@ -393,6 +438,8 @@ _doprnt(const char *fmt0, va_list argp, 
       flags |= LONGINT;
       /*FALLTHROUGH*/
     case 'o':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       ARG(unsigned);
       base = 8;
       flags |= FINITENUMBER;
@@ -406,10 +453,14 @@ _doprnt(const char *fmt0, va_list argp, 
        *	-- ANSI X3J11
        */
       /* NOSTRICT */
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       _ulonglong = (unsigned long)va_arg(argp, void *);
       base = 16;
       goto nosign;
     case 's':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       if (!(t = va_arg(argp, char *)))
 	t = NULL_REP;
       if (prec >= 0)
@@ -438,6 +489,8 @@ _doprnt(const char *fmt0, va_list argp, 
       flags |= LONGINT;
       /*FALLTHROUGH*/
     case 'u':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       ARG(unsigned);
       base = 10;
       flags |= FINITENUMBER;
@@ -446,6 +499,8 @@ _doprnt(const char *fmt0, va_list argp, 
       flags |= UPPERCASE;
       /* FALLTHROUGH */
     case 'x':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       ARG(unsigned);
       base = 16;
       flags |= FINITENUMBER;
@@ -1251,3 +1306,158 @@ __grouping_format(char *string_start, ch
 
   return (*dst == thousands_sep) ? dst + 1 : dst;  /*  Remove leading thousands separator character.  */
 }
+
+static __inline__ va_list
+__traverse_argument_list(int index_of_arg_to_be_fetched, const char *fmt0, va_list argp)
+{
+  /*
+   *  Traverse an argument list until certain position.
+   *  The argument list of type va_list is traversed
+   *  according to the information extracted from the
+   *  format string fmt. It stops at position given by
+   *  index_of_arg_to_be_fetched so the next access by
+   *  the calling context using va_arg() fetches the
+   *  wanted element from the list.
+   */
+
+  const char *fmt = fmt0;
+  int arg_index = 0, prec_index = 0, list_index;
+  int ch, flags, n = index_of_arg_to_be_fetched + 1;
+  unsigned long long _ulonglong;  /* discard value retrieved by ARG() */
+
+
+  for (list_index = 1; list_index < n;)
+  {
+    while ((ch = *fmt) && ch != '%')
+      fmt++;
+    if (!ch)
+    {
+      if (list_index < n)
+        fmt = fmt0;
+      else
+        return argp;
+    }
+
+    flags = 0;
+  rflag:
+    switch (*++fmt)
+    {
+    /* Flags */
+    case ' ': case '#': case '\'':
+    case '-': case '+':
+      goto rflag;
+
+    /* Numeric conversion specifier field width and precision:  *n$.*m$ */
+    case '*':
+      for (prec_index = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+        prec_index = 10 * prec_index + todigit(*fmt);
+      if (prec_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (prec_index == list_index)
+      {
+        va_arg(argp, int);  /* discard */
+        list_index++;
+      }
+      goto rflag;
+    case '.':
+      if (*++fmt == '*')
+      {
+        for (prec_index = 0, fmt++; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+          prec_index = 10 * prec_index + todigit(*fmt);
+        if (prec_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+          return argp;
+        if (prec_index == list_index)
+        {
+          va_arg(argp, int);  /* discard */
+          list_index++;
+        }
+      }
+      goto rflag;
+
+    /* Numeric conversion specifier %n$ */
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      for (arg_index = 0; isascii((unsigned char)*fmt) && isdigit((unsigned char)*fmt); fmt++)
+        arg_index = 10 * arg_index + todigit(*fmt);
+      goto rflag;
+
+    /* Length modifiers */
+    case 'h': case 't': case 'z':  /* promoted to int */
+      goto rflag;
+    case 'L': /* a, A, e, E, f, F, g, G applies to long double */
+      flags |= LONGDBL;
+      goto rflag;
+    case 'l':
+      if (flags & LONGINT)
+        flags |= LONGDBL; /* d, i o, u, x, X applies to long long */
+      else
+        flags |= LONGINT; /* d, i o, u, x, X applies to long */
+      goto rflag;
+    case 'j': /* d, i o, u, x, X applies to intmax_t */
+      flags |= LONGDBL; /* long long */
+      goto rflag;
+
+    /* Conversion specifiers */
+    case 'c':
+      if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (arg_index == list_index)
+      {
+        va_arg(argp, int);  /* discard */
+        list_index++;
+      }
+      break;
+    case 'D':
+      flags |= LONGINT;
+      /*FALLTHROUGH*/
+    case 'd': case 'i':
+      if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (arg_index == list_index)
+      {
+        ARG(signed);  /* discard */
+        list_index++;
+      }
+      break;
+    case 'A': case 'E': case 'F': case 'G':
+    case 'a': case 'e': case 'f': case 'g':
+      if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (arg_index == list_index)
+      {
+        if (flags & LONGDBL)
+          va_arg(argp, long double);  /* discard */
+        else
+          va_arg(argp, double);  /* discard */
+        list_index++;
+      }
+      break;
+    case 'O': case 'U': case 'X':
+      flags |= LONGINT;
+      /*FALLTHROUGH*/
+    case 'o': case 'u': case 'x':
+      if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (arg_index == list_index)
+      {
+        ARG(unsigned);  /* discard */
+        list_index++;
+      }
+      break;
+    case 'n': case 'p': case 's':
+      if (arg_index == index_of_arg_to_be_fetched && list_index == index_of_arg_to_be_fetched)
+        return argp;
+      if (arg_index == list_index)
+      {
+        va_arg(argp, void *);  /* discard */
+        list_index++;
+      }
+      break;
+
+    case '\0':
+      return argp;
+    }
+  }
+
+  return argp;
+}
diff -aprNU3 djgpp.orig/src/libc/ansi/stdio/printf.txh djgpp/src/libc/ansi/stdio/printf.txh
--- djgpp.orig/src/libc/ansi/stdio/printf.txh	2008-04-24 15:09:44 +0000
+++ djgpp/src/libc/ansi/stdio/printf.txh	2008-04-24 15:13:20 +0000
@@ -13,8 +13,23 @@ int printf(const char *@var{format}, @do
 Sends formatted output from the arguments (@dots{}) to @code{stdout}.
 
 The format string contains regular characters to print, as well as
-conversion specifiers, which begin with a percent symbol.  Each
-conversion speficier contains the following fields:
+conversion specifiers, which begin with a percent symbol.  Conversions can
+be applied to the nth argument after the format string in the argument list,
+rather than to the next unused argument.  In this case, the conversion
+specifier character @code{%} is replaced by the sequence @code{"%n$"}, where
+@code{n} is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position of the argument in the argument list.  The format string
+can contain either numbered argument conversion specifiers (that is, +@code{"%n$"}
+and @code{"*m$"}), or unnumbered argument conversion specifiers (that is @code{%}
+and @code{*}), but not both.  The only exception to this is that @code{%%} can
+be mixed with @code{"%n$"} form.  When numbered argument specifications are
+used, specifying the Nth argument requires that all the leading arguments,
+from the first to the (N-1)th, are specified in the format string.  In format
+strings containing the @code{"%n$"} form of conversion specification, numbered
+arguments in the argument list can be referenced from the format string as many
+times as required.
+
+Each conversion specifier contains the following fields:
 
 @itemize @bullet
 
@@ -59,6 +74,11 @@ A field width specifier, which specifies
 This may also be an asterisk (@code{*}), which means that the actual
 width will be obtained from the next argument.  If the argument is
 negative, it supplies a @code{-} flag and a positive width. 
+In format strings containing the @code{"%n$"} form of a conversion
+specifier, a field width can be indicated by the sequence @code{"*m$"},
+where m is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position in the argument list (after the format argument) of
+an integer argument containing the field width.
 
 @item
 
@@ -68,6 +88,11 @@ The precision specifies the minimum numb
 integer, the number of fraction digits for a floating point number (max
 for @code{g} or @code{G}, actual for others), or the maximum number of
 characters for a string. 
+In format strings containing the @code{"%n$"} form of a conversion
+specifier, a precision can be indicated by the sequence @code{"*m$"},
+where m is a decimal integer in the range [@code{1}, @code{number of the last argument}],
+giving the position in the argument list (after the format argument) of
+an integer argument containing the precision.
 
 @item
 
@@ -221,3 +246,37 @@ specifiers first appeared in the ANSI C9
 @example
 printf("%-3d %10.2f%% Percent of %s\n", index, per[index], name[index]);
 @end example
+
+The following statement can be used to print date and time
+using language-independent format:
+
+@example
+printf(format, weekday, month, day, hour, precision, min);
+@end example
+
+
+For American usage, the format string could look like:
+
+@example
+"%s, %s %d, %d:%.*d\n"
+@end example
+
+The integer precision has the value 2.
+The above example will produce the following message:
+
+@example
+Sunday, October 27, 9:09
+@end example
+
+
+For German usage, the format string could look like:
+
+@example
+"%1$s, %3$d. %2$s, %4$d:%6$.*5$d\n"
+@end example
+
+The above example will produce the following message:
+
+@example
+Sonntag, 27. Oktober, 9:09
+@end example
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/makefile djgpp/tests/libc/ansi/stdio/makefile
--- djgpp.orig/tests/libc/ansi/stdio/makefile	2008-04-24 15:09:08 +0000
+++ djgpp/tests/libc/ansi/stdio/makefile	2008-04-24 15:13:20 +0000
@@ -17,6 +17,7 @@ SRC += mktemp.c
 SRC += printf.c
 SRC += printf2.c
 SRC += printf3.c
+SRC += printf4.c
 SRC += sscanf.c
 SRC += sscanf2.c
 SRC += sscanf3.c
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/printf4.c djgpp/tests/libc/ansi/stdio/printf4.c
--- djgpp.orig/tests/libc/ansi/stdio/printf4.c	1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/printf4.c	2008-04-24 14:33:00 +0000
@@ -0,0 +1,66 @@
+/*
+ * printf4.c
+ * Test cases for numeric conversion specifiers.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libc/unconst.h>
+
+int main(void)
+{
+  int i, width, precision;
+  double darg[] = {1.1, 2.2, 3.3};
+  const char *title[] = {"En castellano:", "Auf deutsch:", "In english:"};
+  const char *format[] = {
+   "%5$s, %2$d de %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+   "%5$s, %2$d. %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+   "%5$s, %1$s %2$d, %3$*6$.*7$d:%4$*6$.*7$d\n"
+  };
+  const char *weekday[] = {"Sabado", "Samstag", "Saturday"};
+  const char *month[] = {"febrero", "Februar", "february"};
+  int day = 2;
+  int hour = 12;
+  int min = 34;
+
+
+  printf("Testing numeric conversion specifiers.\n"
+         "======================================\n");
+
+  width = 10;
+  precision = 1;
+  printf("Printing a sequence of numbers using a given field width and precision\n"
+         "accessing the variables a multiple times in different order.\n"
+         "The sequence of arguments after the format string is:\n"
+         "  width, precision, darg[0], darg[1], darg[2]\n"
+         "with the values:\n"
+         "  width:     %d\n"
+         "  precision: %d\n"
+         "  darg[0]:   %f\n"
+         "  darg[1]:   %f\n"
+         "  darg[2]:   %f\n",
+         width, precision, darg[0], darg[1], darg[2]);
+  printf("Format string: \"%%3$-*1$.*2$f###%%4$*1$.*2$f###%%5$*1$.*2$f\"     <%3$-*1$.*2$f###%4$*1$.*2$f###%5$*1$.*2$f>\n"
+         "Printing again but accessing the arguments in inverse order:\n"
+         "Format string: \"%%5$-*1$.*2$f###%%4$*1$.*2$f###%%3$*1$.*2$f\"     <%5$-*1$.*2$f###%4$*1$.*2$f###%3$*1$.*2$f>\n\n\n",
+         width, precision, darg[0], darg[1], darg[2]);
+
+
+
+  width = 2;
+  precision = 2;
+  printf("Printing Language-Independent Date and Time.\n\n");
+  for (i = 0; i < 3; i++)
+  {
+    char *fmt;
+    int len = strlen(format[i]);
+    printf("%s  ", title[i]);
+    printf(format[i], month[i], day, hour, min, weekday[i], width, precision);
+    fmt = unconst((&format[i][--len]), char *);
+    *fmt = '\0';
+    printf("Produced with:\n"
+           "  printf(\"%1$s\\n\", month[%2$i], day, hour, min, weekday[%2$i], width, precision);\n\n",
+           format[i], i);
+  }
+  return 0;
+}
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/printf5.c djgpp/tests/libc/ansi/stdio/printf5.c
--- djgpp.orig/tests/libc/ansi/stdio/printf5.c	1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/printf5.c	2008-04-24 15:06:16 +0000
@@ -0,0 +1,839 @@
+/*
+ *  This program test flags, conversion modifiers and conversion specifiers
+ *  of the printf familiy of function.  During compilation some warnings
+ *  will be generated, this is part of the test and is intentional.  Thus
+ *  the program can not be compiled with the stock makefile because this
+ *  stops at warnings.  You must manually compile the program taking care
+ *  that the library to be tested is used when linking.
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libc/ieee.h>
+
+
+void flags_test(FILE *out)
+{
+  fprintf(out, "Testing all flags.\n"
+               "==================\n");
+  fprintf(out, "Flag: \"'\"\n"
+               "      The integer portion of the result of a decimal conversion (%%i, %%d, %%u, %%f,\n"
+               "      %%F, %%g, or %%G) shall be formatted with thousands' grouping characters.\n"
+               "      For other conversions the behavior is undefined. The non-monetary grouping\n"
+               "      character is used.\n"
+               "arg: %d   format string: \"%%'d\"   <%'d>\n"
+               "arg: %d   format string: \"%%'i\"   <%'i>\n"
+               "arg: %d   format string: \"%%'u\"   <%'u>\n"
+               "arg: %.1f format string: \"%%'f\"   <%'f>\n"
+               "arg: %.1f format string: \"%%'F\"   <%'F>\n"
+               "arg: %.1f format string: \"%%'g\"   <%'g>\n"
+               "arg: %.1f format string: \"%%'G\"   <%'G>\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0);
+
+
+
+  fprintf(out, "Flag: \"-\"\n"
+               "      The result of the conversion shall be left-justified within the field. The\n"
+               "      conversion is right-justified if this flag is not specified.\n"
+               "arg: %d   format string: \"%%-5d\"   <%-5d>\n"
+               "arg: %d   format string: \"%%5d\"    <%5d>\n"
+               "arg: %d   format string: \"%%-5i\"   <%-5i>\n"
+               "arg: %d   format string: \"%%5i\"    <%5i>\n"
+               "arg: %d   format string: \"%%-5o\"   <%-5o>\n"
+               "arg: %d   format string: \"%% 5o\"   <%5o>\n"
+               "arg: %d   format string: \"%%-5u\"   <%-5u>\n"
+               "arg: %d   format string: \"%%5u\"    <%5u>\n"
+               "arg: %d  format string: \"%%-5x\"   <%-5x>\n"
+               "arg: %d  format string: \"%%5X\"    <%5X>\n"
+               "arg: %.1f format string: \"%%-10a\"  <%-10a>\n"
+               "arg: %.1f format string: \"%%10A\"   <%10A>\n"
+               "arg: %.1f format string: \"%%-15e\"  <%-15e>\n"
+               "arg: %.1f format string: \"%%15E\"   <%15E>\n"
+               "arg: %.1f format string: \"%%-10f\"  <%-10f>\n"
+               "arg: %.1f format string: \"%%10F\"   <%10F>\n"
+               "arg: %.1f format string: \"%%-10g\"  <%-10g>\n"
+               "arg: %.1f format string: \"%%10G\"   <%10G>\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               10, 10,
+               15, 15,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0);
+
+
+
+  fprintf(out, "Flag: \"+\"\n"
+               "      The result of a signed conversion shall always begin with a sign ('+' or\n"
+               "      '-'). The conversion shall begin with a sign only when a negative value\n"
+               "      is converted if this flag is not specified.\n"
+               "arg: %d   format string: \"%%+d\"   <%+d>\n"
+               "arg: %d   format string: \"%%i\"    <%i>\n"
+               "arg: %d   format string: \"%%+o\"   <%+o>    WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%+u\"   <%+u>    WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d  format string: \"%%+x\"   <%+x>    WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d  format string: \"%%+X\"   <%+X>    WARNING: Sign flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %.1f format string: \"%%+a\"   <%+a>\n"
+               "arg: %.1f format string: \"%%A\"    <%A>\n"
+               "arg: %.1f format string: \"%%+e\"   <%+e>\n"
+               "arg: %.1f format string: \"%%E\"    <%E>\n"
+               "arg: %.1f format string: \"%%+f\"   <%+f>\n"
+               "arg: %.1f format string: \"%%F\"    <%F>\n"
+               "arg: %.1f format string: \"%%+g\"   <%+g>\n"
+               "arg: %.1f format string: \"%%G\"    <%G>\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               10, 10,
+               15, 15,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0);
+
+
+
+  fprintf(out, "Flag: \"<space>\"\n"
+               "      If the first character of a signed conversion is not a sign or if a signed\n"
+               "      conversion results in no characters, a <space> shall be prefixed to the\n"
+               "      result. This means that if the <space> and '+' flags both appear, the\n"
+               "      <space> flag shall be ignored.\n"
+               "arg: %d   format string: \"%% i\"   <% i>\n"
+               "arg: %d   format string: \"%%+ i\"  <%+ i>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+               "arg: %d   format string: \"%% d\"   <% d>\n"
+               "arg: %d   format string: \"%% +d\"  <% +d>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+               "arg: %d   format string: \"%% o\"   <% o>    WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%+ o\"  <%+ o>    WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+               "arg: %d   format string: \"%% u\"   <% u>    WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%+ u\"  <%+ u>    WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+               "arg: %d  format string: \"%% x\"   <% x>    WARNING: Space flag used with unsigned magnitude. Flag ignored.\n"
+               "arg: %d  format string: \"%%+ X\"  <%+ X>    WARNING: Sign and space flags used with unsigned magnitude. Flags ignored.\n"
+               "arg: %.1f format string: \"%% a\"   <% a>\n"
+               "arg: %.1f format string: \"%%+ A\"  <%+ A>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+               "arg: %.1f format string: \"%% e\"   <% e>\n"
+               "arg: %.1f format string: \"%% +E\"  <% +E>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+               "arg: %.1f format string: \"%% f\"   <% f>\n"
+               "arg: %.1f format string: \"%%+ F\"  <%+ F>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n"
+               "arg: %.1f format string: \"%% g\"   <% g>\n"
+               "arg: %.1f format string: \"%% +G\"  <% +G>   WARNING: Sign and space flags used simultaneously. Space flag ignored.\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               10, 10,
+               15, 15,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0);
+
+
+
+  fprintf(out, "Flag: \"#\"\n"
+               "      Specifies that the value is to be converted to an alternative form. For o\n"
+               "      conversion, it increases the precision (if necessary) to force the first\n"
+               "      digit of the result to be zero. For x or X conversion specifiers, a non-\n"
+               "      zero result shall have 0x (or 0X) prefixed to it. For a, A, e, E, f, F, g,\n"
+               "      and G conversion specifiers, the result shall always contain a radix\n"
+               "      character, even if no digits follow the radix character. Without this\n"
+               "      flag, a radix character appears in the result of these conversions only if\n"
+               "      a digit follows it. For g and G conversion specifiers, trailing zeros\n"
+               "      shall not be removed from the result as they normally are. For other\n"
+               "      conversion specifiers, the behavior is undefined.\n"
+               "arg: %d   format string: \"%%#d\"   <%#d>   WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%#i\"   <%#i>   WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%#u\"   <%#u>   WARNING: # flag used with decimal magnitude. Flag ignored.\n"
+               "arg: %d   format string: \"%%#o\"   <%#o>\n"
+               "arg: %d   format string: \"%%#o\"   <%#o>\n"
+               "arg: %d   format string: \"%%#x\"   <%#x>\n"
+               "arg: %d   format string: \"%%#X\"   <%#X>\n"
+               "arg: %.1f format string: \"%%a\"    <%a>\n"
+               "arg: %.1f format string: \"%%#A\"   <%#A>\n"
+               "arg: %.1f format string: \"%%1.e\"  <%1.e>\n"
+               "arg: %.1f format string: \"%%#1.E\" <%#1.E>\n"
+               "arg: %.1f format string: \"%%1.f\"  <%1.f>\n"
+               "arg: %.1f format string: \"%%#1.F\" <%#1.F>\n"
+               "arg: %.1f format string: \"%%g\"    <%g>\n"
+               "arg: %.1f format string: \"%%#G\"   <%#G>\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               0, 0,
+               1, 1,
+               0, 0,
+               1.0, 1.0,
+               0.0, 0.0,
+               1.0, 1.0,
+               0.0, 0.0,
+               1.0, 1.0,
+               0.0, 0.0,
+               1.0, 1.0,
+               0.0, 0.0);
+
+
+
+  fprintf(out, "Flag: \"0\"\n"
+               "      For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversion specifiers,\n"
+               "      leading zeros (following any indication of sign or base) are used to pad\n"
+               "      to the field width; no space padding is performed. If the '0' and '-'\n"
+               "      flags both appear, the '0' flag is ignored. For d, i, o, u, x, and X\n"
+               "      conversion specifiers, if a precision is specified, the '0' flag is\n"
+               "      ignored. If the '0' and ''' flags both appear, the grouping characters are\n"
+               "      inserted before zero padding. For other conversions, the behavior is\n"
+               "      undefined.\n"
+               "arg: %d    format string: \"%%05d\"    <%05d>\n"
+               "arg: %d    format string: \"%%-05d\"   <%-05d>            WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d    format string: \"%%05.d\"   <%05.d>\n"
+               "arg: %d    format string: \"%%05i\"    <%05i>\n"
+               "arg: %d    format string: \"%%-05i\"   <%-05i>            WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d    format string: \"%%05.i\"   <%05.i>\n"
+               "arg: %d    format string: \"%%05o\"    <%05o>\n"
+               "arg: %d    format string: \"%%-05o\"   <%-05o>            WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d    format string: \"%%05.o\"   <%05.o>\n"
+               "arg: %d    format string: \"%%05u\"    <%05u>\n"
+               "arg: %d    format string: \"%%-05u\"   <%-05u>            WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d    format string: \"%%05.u\"   <%05.u>\n"
+               "arg: %d   format string: \"%%05x\"    <%05x>\n"
+               "arg: %d   format string: \"%%-05x\"   <%-05x>             WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d   format string: \"%%05.x\"   <%05.x>\n"
+               "arg: %d   format string: \"%%05X\"    <%05X>\n"
+               "arg: %d   format string: \"%%-05X\"   <%-05X>             WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %d   format string: \"%%05.X\"   <%05.X>\n"
+               "arg: %.1f  format string: \"%%0-10a\"  <%0-10a>        WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %.1f  format string: \"%%0+10A\"  <%0+10A>\n"
+               "arg: %.1f  format string: \"%%010A\"   <%010A>\n"
+               "arg: %.1f  format string: \"%%0-15e\"  <%0-15e>   WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %.1f  format string: \"%%0+15E\"  <%0+15E>\n"
+               "arg: %.1f  format string: \"%%015E\"   <%015E>\n"
+               "arg: %.1f  format string: \"%%0-10f\"  <%0-10f>        WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %.1f  format string: \"%%0+10F\"  <%0+10F>\n"
+               "arg: %.1f  format string: \"%%010F\"   <%010F>\n"
+               "arg: %.1f  format string: \"%%0-10g\"  <%0-10g>        WARNING: - and 0 flags used simultaneously. 0 flag ignored.\n"
+               "arg: %.1f  format string: \"%%0+10G\"  <%0+10G>\n"
+               "arg: %.1f  format string: \"%%010G\"   <%010G>\n\n",
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               1, 1,
+               10, 10,
+               10, 10,
+               10, 10,
+               15, 15,
+               15, 15,
+               15, 15,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0,
+               1.0, 1.0);
+}
+
+
+void  length_modifiers_test(FILE *out)
+{
+  char cv, *pcv;
+  short int siv, *psiv;
+  long int liv, *pliv;
+  long long int lliv, *plliv;
+  intmax_t jiv, *pjiv;
+  size_t ziv, *pziv;
+  ptrdiff_t piv, *ppiv;
+  pcv = &cv;
+  psiv = &siv;
+  pliv = &liv;
+  plliv = &lliv;
+  pjiv = &jiv;
+  pziv = &ziv;
+  ppiv = &piv;
+
+
+  fprintf(out, "\n\nTesting all length modifiers.\n"
+               "=============================\n");
+  fprintf(out, "Length modifier: \"hh\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a signed char or unsigned char argument\n"
+               "                 (the argument will have been promoted according to the integer\n"
+               "                 promotions, but its value shall be converted to signed char or\n"
+               "                 unsigned char before printing); or that a following n conversion\n"
+               "                 specifier applies to a pointer to a signed char argument.\n"
+               "arg: CHAR_MAX    format string: \"%%hhd\"   <%hhd>\n"
+               "arg: CHAR_MIN    format string: \"%%hhi\"   <%hhi>\n"
+               "arg: UCHAR_MAX   format string: \"%%hho\"   <%hho>\n"
+               "arg: UCHAR_MAX   format string: \"%%hhu\"   <%hhu>\n"
+               "arg: CHAR_MIN    format string: \"%%hhx\"   <%hhx>\n"
+               "arg: CHAR_MAX    format string: \"%%hhX\"   <%hhX>\n"
+               "arg: -           format string: \"%%hhn\"   (pointer to cv)%hhn\n",
+               CHAR_MAX,
+               CHAR_MIN,
+               UCHAR_MAX,
+               UCHAR_MAX ,
+               CHAR_MIN,
+               CHAR_MAX,
+               pcv);
+  fprintf(out, "cv=%i\n\n", *pcv);
+
+
+
+  fprintf(out, "Length modifier: \"h\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a short or unsigned short argument (the\n"
+               "                 argument will have been promoted according to the integer\n"
+               "                 promotions, but its value shall be converted to short or\n"
+               "                 unsigned short before printing); or that a following n\n"
+               "                 conversion specifier applies to a pointer to a short argument.\n"
+               "arg: SHRT_MAX    format string: \"%%hd\"   <%hd>\n"
+               "arg: SHRT_MIN    format string: \"%%hi\"   <%hi>\n"
+               "arg: USHRT_MAX   format string: \"%%ho\"   <%ho>\n"
+               "arg: USHRT_MAX   format string: \"%%hu\"   <%hu>\n"
+               "arg: SHRT_MIN    format string: \"%%hx\"   <%hx>\n"
+               "arg: SHRT_MAX    format string: \"%%hX\"   <%hX>\n"
+               "arg: -           format string: \"%%hn\"   (pointer to siv)%hn\n",
+               SHRT_MAX,
+               SHRT_MIN,
+               USHRT_MAX,
+               USHRT_MAX,
+               SHRT_MIN,
+               SHRT_MAX,
+               psiv);
+  fprintf(out, "siv=%i\n\n", *psiv);
+
+
+
+  fprintf(out, "Length modifier: \"l\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a long or unsigned long argument; that a\n"
+               "                 following n conversion specifier applies to a pointer to a long\n"
+               "                 argument; that a following c conversion specifier applies to a\n"
+               "                 wint_t argument; that a following s conversion specifier\n"
+               "                 applies to a pointer to a wchar_t argument; or has no effect on\n"
+               "                 a following a, A, e, E, f, F, g, or G conversion specifier.\n"
+               "arg: LONG_MAX    format string: \"%%ld\"   <%ld>\n"
+               "arg: LONG_MIN    format string: \"%%li\"   <%li>\n"
+               "arg: ULONG_MAX   format string: \"%%lo\"   <%lo>\n"
+               "arg: ULONG_MAX   format string: \"%%lu\"   <%lu>\n"
+               "arg: LONG_MIN    format string: \"%%lx\"   <%lx>\n"
+               "arg: LONG_MAX    format string: \"%%lX\"   <%lX>\n"
+               "arg: -           format string: \"%%ln\"   (pointer to liv)%ln\n"
+               "arg: %.1f         format string: \"%%la\"   <%la>\n"
+               "arg: %.1f         format string: \"%%A\"    <%A>\n"
+               "arg: %.1f         format string: \"%%le\"   <%le>\n"
+               "arg: %.1f         format string: \"%%E\"    <%E>\n"
+               "arg: %.1f         format string: \"%%lf\"   <%lf>\n"
+               "arg: %.1f         format string: \"%%F\"    <%F>\n"
+               "arg: %.1f         format string: \"%%lg\"   <%lg>\n"
+               "arg: %.1f         format string: \"%%G\"    <%G>\n",
+               LONG_MAX,
+               LONG_MIN,
+               ULONG_MAX,
+               ULONG_MAX,
+               LONG_MIN,
+               LONG_MAX,
+               pliv,
+               1.1, 1.1,
+               1.1, 1.1,
+               2.2, 2.2,
+               2.2, 2.2,
+               3.3, 3.3,
+               3.3, 3.3,
+               4.4, 4.4,
+               4.4, 4.4);
+  fprintf(out, "liv=%li\n\n", *pliv);
+
+
+
+  fprintf(out, "Length modifier: \"ll\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a long long or unsigned long long argument;\n"
+               "                 or that a following n conversion specifier applies to a pointer\n"
+               "                 to a long long argument.\n"
+               "arg: LONG_LONG_MAX   format string: \"%%lld\"   <%lld>\n"
+               "arg: LONG_LONG_MIN   format string: \"%%lli\"   <%lli>\n"
+               "arg: ULONG_LONG_MAX  format string: \"%%llo\"   <%llo>\n"
+               "arg: ULONG_LONG_MAX  format string: \"%%llu\"   <%llu>\n"
+               "arg: LONG_LONG_MIN   format string: \"%%llx\"   <%llx>\n"
+               "arg: LONG_LONG_MAX   format string: \"%%llX\"   <%llX>\n"
+               "arg: -               format string: \"%%lln\"   (pointer to lliv)%lln\n",
+               LONG_LONG_MAX,
+               LONG_LONG_MIN,
+               ULONG_LONG_MAX,
+               ULONG_LONG_MAX,
+               LONG_LONG_MIN,
+               LONG_LONG_MAX,
+               plliv);
+  fprintf(out, "lliv=%lli\n\n", *plliv);
+
+
+
+  fprintf(out, "Length modifier: \"j\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to an intmax_t or uintmax_t argument; or that\n"
+               "                 a following n conversion specifier applies to a pointer to an\n"
+               "                 intmax_t argument.\n"
+               "arg: LONG_LONG_MAX   format string: \"%%jd\"   <%jd>\n"
+               "arg: LONG_LONG_MIN   format string: \"%%ji\"   <%ji>\n"
+               "arg: ULONG_LONG_MAX  format string: \"%%jo\"   <%jo>\n"
+               "arg: ULONG_LONG_MAX  format string: \"%%ju\"   <%ju>\n"
+               "arg: LONG_LONG_MIN   format string: \"%%jx\"   <%jx>\n"
+               "arg: LONG_LONG_MAX   format string: \"%%jX\"   <%jX>\n"
+               "arg: -               format string: \"%%jn\"   (pointer to jiv)%jn\n",
+               (intmax_t)LONG_LONG_MAX,
+               (intmax_t)LONG_LONG_MIN,
+               (uintmax_t)ULONG_LONG_MAX,
+               (uintmax_t)ULONG_LONG_MAX,
+               (intmax_t)LONG_LONG_MIN,
+               (intmax_t)LONG_LONG_MAX,
+               pjiv);
+  fprintf(out, "jiv=%ji\n\n", *pjiv);
+
+
+
+  fprintf(out, "Length modifier: \"z\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a size_t or the corresponding signed\n"
+               "                 integer type argument; or that a following n conversion\n"
+               "                 specifier applies to a pointer to a signed integer type\n"
+               "                 corresponding to a size_t argument.\n"
+               "arg: LONG_MAX    format string: \"%%zd\"   <%zd>\n"
+               "arg: LONG_MIN    format string: \"%%zi\"   <%zi>\n"
+               "arg: LONG_MAX    format string: \"%%zo\"   <%zo>\n"
+               "arg: LONG_MAX    format string: \"%%zu\"   <%zu>\n"
+               "arg: LONG_MIN    format string: \"%%zx\"   <%zx>\n"
+               "arg: LONG_MAX    format string: \"%%zX\"   <%zX>\n"
+               "arg: -           format string: \"%%zn\"   (pointer to ziv)%zn\n",
+               (size_t)LONG_MAX,
+               (size_t)LONG_MIN,
+               (size_t)LONG_MAX,
+               (size_t)LONG_MAX,
+               (size_t)LONG_MIN,
+               (size_t)LONG_MAX,
+               pziv);
+  fprintf(out, "ziv=%zi\n\n", *pziv);
+
+
+
+  fprintf(out, "Length modifier: \"t\"\n"
+               "                 Specifies that a following d, i, o, u, x, or X conversion\n"
+               "                 specifier applies to a ptrdiff_t or the corresponding\n"
+               "                 unsigned type argument; or that a following n conversion\n"
+               "                 specifier applies to a pointer to a ptrdiff_t argument.\n"
+               "arg: LONG_MAX    format string: \"%%td\"   <%td>\n"
+               "arg: LONG_MIN    format string: \"%%ti\"   <%ti>\n"
+               "arg: LONG_MAX    format string: \"%%to\"   <%to>\n"
+               "arg: ULONG_MAX   format string: \"%%tu\"   <%tu>\n"
+               "arg: LONG_MIN    format string: \"%%tx\"   <%tx>\n"
+               "arg: LONG_MAX    format string: \"%%tX\"   <%tX>\n"
+               "arg: -           format string: \"%%tn\"   (pointer to piv)%tn\n",
+               (ptrdiff_t)LONG_MAX,
+               (ptrdiff_t)LONG_MIN,
+               (ptrdiff_t)LONG_MAX,
+               (ptrdiff_t)ULONG_MAX,
+               (ptrdiff_t)LONG_MIN,
+               (ptrdiff_t)LONG_MAX,
+               ppiv);
+  fprintf(out, "piv=%ti\n\n", *ppiv);
+
+
+
+  fprintf(out, "Length modifier: \"L\"\n"
+               "---------1---------2---------3---------4---------5---------6---------7---------8\n"
+               "                 Specifies that a following a, A, e, E, f, F, g, or G conversion\n"
+               "                 specifier applies to a long double argument.\n"
+               "arg: LDBL_MAX    format string: \"%%La\"   <%La>\n"
+               "arg: LDBL_MIN    format string: \"%%LA\"   <%LA>\n"
+               "arg: LDBL_MAX    format string: \"%%Le\"   <%Le>\n"
+               "arg: LDBL_MIN    format string: \"%%LE\"   <%LE>\n"
+               "arg: LDBL_MAX    format string: \"%%Lf\"   <%Lf>\n"
+               "arg: LDBL_MIN    format string: \"%%LF\"   <%LF>\n"
+               "arg: LDBL_MAX    format string: \"%%Lg\"   <%Lg>\n"
+               "arg: LDBL_MIN    format string: \"%%LG\"   <%LG>\n\n",
+               LDBL_MAX,
+               LDBL_MIN,
+               LDBL_MAX,
+               LDBL_MIN,
+               LDBL_MAX,
+               LDBL_MIN,
+               LDBL_MAX,
+               LDBL_MIN);
+}
+
+
+void numeric_conversion_specifiers_test(FILE *out)
+{
+  int i, width, precision;
+  double darg[] = {1.1, 2.2, 3.3};
+  char *title[] = {"En castellano:", "Auf deutsch:", "In english:"};
+  char *format[] = {
+   "%5$s, %2$d de %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+   "%5$s, %2$d. %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n",
+   "%5$s, %1$s %2$d, %3$*6$.*7$d:%4$*6$.*7$d\n"
+  };
+  char *weekday[] = {"Sabado", "Samstag", "Saturday"};
+  char *month[] = {"febrero", "Februar", "february"};
+  int day = 2;
+  int hour = 12;
+  int min = 34;
+
+
+  fprintf(out, "\n\nTesting numeric conversion specifiers.\n"
+               "======================================\n");
+
+  width = 10;
+  precision = 1;
+  fprintf(out, "Printing a sequence of numbers using a given field width and precision\n"
+               "accessing the variables a multiple times in different order.\n"
+               "The sequence of arguments after the format string is:\n"
+               "  width, precision, darg[0], darg[1], darg[2]\n"
+               "with the values:\n"
+               "  width:     %d\n"
+               "  precision: %d\n"
+               "  darg[0]:   %f\n"
+               "  darg[1]:   %f\n"
+               "  darg[2]:   %f\n",
+               width, precision, darg[0], darg[1], darg[2]);
+  fprintf(out, "Format string: \"%%3$-*1$.*2$f###%%4$*1$.*2$f###%%5$*1$.*2$f\"     <%3$-*1$.*2$f###%4$*1$.*2$f###%5$*1$.*2$f>\n"
+               "Printing again but accessing the arguments in inverse order:\n"
+               "Format string: \"%%5$-*1$.*2$f###%%4$*1$.*2$f###%%3$*1$.*2$f\"     <%5$-*1$.*2$f###%4$*1$.*2$f###%3$*1$.*2$f>\n\n\n",
+               width, precision, darg[0], darg[1], darg[2]);
+
+
+  width = 2;
+  precision = 2;
+  fprintf(out, "Printing Language-Independent Date and Time.\n\n");
+  for (i = 0; i < 3; i++)
+  {
+    int len = strlen(format[i]);
+    fprintf(out, "%s  ", title[i]);
+    fprintf(out, format[i], month[i], day, hour, min, weekday[i], width, precision);
+    format[i][--len] = '\0';
+    fprintf(out, "Produced with:\n"
+                 "  printf(\"%1$s\\n\", month[%2$i], day, hour, min, weekday[%2$i], width, precision);\n\n",
+                 format[i], i);
+  }
+}
+
+
+void printf_test(FILE *out)
+{
+  char buf[100], *strbuf;
+  union {
+    unsigned int word[3];
+    long double value;
+  } x;
+  int strlng;
+
+
+
+  fprintf(out, "\n\nGeneral test of the printf familiy of functions.\n"
+               "================================================\n");
+
+  fprintf(out, "Infinity.\n");
+  sprintf(buf, "%La", 1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%La\"   arg: 1.0L / 0.0L\n"
+               "Shall return: \"inf\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LA", -1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LA\"   arg: -1.0L / 0.0L\n"
+               "Shall return: \"-INF\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Lf", 1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Lf\"   arg: 1.0L / 0.0L\n"
+               "Shall return: \"inf\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LF", -1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LF\"   arg: -1.0L / 0.0L\n"
+               "Shall return: \"-INF\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Le", 1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Le\"   arg: 1.0L / 0.0L\n"
+               "Shall return: \"inf\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LE", -1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LE\"   arg: -1.0L / 0.0L\n"
+               "Shall return: \"-INF\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Lg", 1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Lg\"   arg: 1.0L / 0.0L\n"
+               "Shall return: \"inf\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LG", -1.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LG\"   arg: -1.0L / 0.0L\n"
+               "Shall return: \"-INF\"   returns: \"%s\"\n\n", buf);
+
+  fprintf(out, "NaN.\n");
+  sprintf(buf, "%La", 0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%La\"   arg: 0.0L / 0.0L\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LA", -0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LA\"   arg: -0.0L / 0.0L\n"
+               "Shall return: \"NAN\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Lf", 0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Lf\"   arg: 0.0L / 0.0L\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LF", -0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LF\"   arg: -0.0L / 0.0L\n"
+               "Shall return: \"NAN\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Le", 0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Le\"   arg: 0.0L / 0.0L\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LE", -0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LE\"   arg: -0.0L / 0.0L\n"
+               "Shall return: \"NAN\"   returns: \"%s\"\n", buf);
+  sprintf(buf, "%Lg", 0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%Lg\"   arg: 0.0L / 0.0L\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", buf);
+  sprintf(buf, "%LG", -0.0L / 0.0L);
+  fprintf(out, "fmt str: \"%%LG\"   arg: -0.0L / 0.0L\n"
+               "Shall return: \"NAN\"   returns: \"%s\"\n\n", buf);
+
+
+  x.word[2] = 0x7FFF;
+  x.word[1] = 0xC000000C;
+  x.word[0] = 0x10000001;
+  fprintf(out, "Quiet NaN\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0x7FFF;
+  x.word[1] = 0x80000008;
+  x.word[0] = 0x10000001;
+  fprintf(out, "Signalling NaN\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0x7FFF;
+  x.word[1] = 0x40000004;
+  x.word[0] = 0x10000001;
+  fprintf(out, "Pseudo-NaN\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0xFFFF;
+  x.word[1] = 0x00000000;
+  x.word[0] = 0x00000000;
+  fprintf(out, "Pseudo-Infinity\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0x4004;
+  x.word[1] = 0x00000000;
+  x.word[0] = 0x00000000;
+  fprintf(out, "Pseudo-Zero\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0x0440;
+  x.word[1] = 0x60000006;
+  x.word[0] = 0x10000001;
+  fprintf(out, "Unnormalized number\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+  x.word[2] = 0x0000;
+  x.word[1] = 0x80000008;
+  x.word[0] = 0x10000001;
+  fprintf(out, "Pseudo-Denormal\n");
+  sprintf(buf, "%La", x.value);
+  fprintf(out, "fmt str: \"%%La\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Le", x.value);
+  fprintf(out, "fmt str: \"%%Le\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lf", x.value);
+  fprintf(out, "fmt str: \"%%Lf\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n", x.word[2], x.word[1], x.word[0], buf);
+  sprintf(buf, "%Lg", x.value);
+  fprintf(out, "fmt str: \"%%Lg\"   exp: %#.4x  manthi: %#.8x  mantlo: %#.8x\n"
+               "Shall return: \"nan\"    returns: \"%s\"\n\n", x.word[2], x.word[1], x.word[0], buf);
+
+
+  fprintf(out, "Testing asprintf.\n");
+  fprintf(out, "Code line:   strlng = asprintf(&strbuf, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+  strlng = asprintf(&strbuf, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+  fprintf(out, "Result:      strbuf: \"%s\"   strlng: %d\n", strbuf, strlng);
+  free(strbuf);
+
+  fprintf(out, "Testing asnprintf.\n");
+  strbuf = NULL;
+  fprintf(out, "Code line:   strlng = asnprintf(&strbuf, 0, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+  strlng = asnprintf(&strbuf, 0, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+  fprintf(out, "Result:      strbuf: %s  strlng: %d\n", strbuf, strlng);
+  fprintf(out, "Code line:   strlng = asnprintf(&strbuf, 10, \"Pi = %%.15Lf\", 3.1415926535897932384626433832795L);\n");
+  strlng = asnprintf(&strbuf, 10, "Pi = %.15Lf", 3.1415926535897932384626433832795L);
+  fprintf(out, "Result:      strbuf: 0x%p  strlng: %d\n", strbuf, strlng);
+  fprintf(out, "             strbuf: \"%s\"  mallocated buffer length is %zd chars long plus 1 nul char\n\n", strbuf, strlen(strbuf));
+  free(strbuf);
+
+  fprintf(out, "Testing flags in combination with Infinity and NaN.\n");
+  fprintf(out, "Code line:   sprintf(buf, \"%%0*Lf\", 10, 1.0L / 0.0L);\n");
+  sprintf(buf, "%0*Lf", 10, 1.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%+*Lf\", 10, 1.0L / 0.0L);\n");
+  sprintf(buf, "%+*Lf", 10, 1.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "+inf");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%-*Lf\", 10, 1.0L / 0.0L);\n");
+  sprintf(buf, "%-*Lf", 10, 1.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "inf       ");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%% *Lf\", 10, 1.0L / 0.0L);\n");
+  sprintf(buf, "% *Lf", 10, 1.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%#*Lf\", 10, 1.0L / 0.0L);\n");
+  sprintf(buf, "%#*Lf", 10, 1.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "inf");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%0*Lf\", 10, 0.0L / 0.0L);\n");
+  sprintf(buf, "%0*Lf", 10, 0.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%+*Lf\", 10, 0.0L / 0.0L);\n");
+  sprintf(buf, "%+*Lf", 10, 0.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%-*Lf\", 10, 0.0L / 0.0L);\n");
+  sprintf(buf, "%-*Lf", 10, 0.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "nan       ");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%% *Lf\", 10, 0.0L / 0.0L);\n");
+  sprintf(buf, "% *Lf", 10, 0.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+  fprintf(out, "Code line:   sprintf(buf, \"%%#*Lf\", 10, 0.0L / 0.0L);\n");
+  sprintf(buf, "%#*Lf", 10, 0.0L / 0.0L);
+  asprintf(&strbuf, "%*s", (int)strlen(buf), "nan");
+  fprintf(out, "Shall return: <%s>    returns: <%s>  %s\n", strbuf, buf, strcmp(strbuf, buf) ? "Not OK" : "OK");
+  free(strbuf);
+}
+
+
+int main(void)
+{
+  FILE *out;
+
+  out = fopen("printf5.txt", "w");
+  if (out == NULL)
+  {
+    printf("Can not open test.txt.  Test failed.\n");
+    return 1;
+  }
+
+  printf("Testing:\n"
+         "  printf family of functions...\n");
+  flags_test(out);
+  length_modifiers_test(out);
+  numeric_conversion_specifiers_test(out);
+  printf_test(out);
+  fclose(out);
+
+  printf("The test output is in printf5.txt\n");
+  return 0;
+}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019