www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2008/03/04/14:29:15

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: V01U2FsdGVkX19BUPYnzidBcJH+tlnFbFtkC+xmwScypLS2d+Gfly
rqG0KqXhOc1P8/
From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
To: djgpp-workers AT delorie DOT com
Subject: Implementation of support for numeric conversion specifier.
Date: Tue, 4 Mar 2008 19:27:01 +0100
User-Agent: KMail/1.9.5
MIME-Version: 1.0
Message-Id: <200803041927.04679.juan.guerrero@gmx.de>
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

Some years ago I already proposed a patch to provide support for numeric
conversion specifier.
  <http://www.delorie.com/archives/browse.cgi?p=djgpp-workers/2003/04/09/02:50:13>
It was rejected due to the use of malloc to allocate arrays to store format
and position information at runtime.
  <http://www.delorie.com/archives/browse.cgi?p=djgpp-workers/2003/04/12/05:03:33>
This is a rewrite from scratch.  This time no information is stored thus no
memory allocation is done at runtime.  When the format string is parsed and
a numeric conversion specifier (%n$ or *n$) is found the function
__traverse_argument_list is called and it gets the number of the argument to
be fetched, lets say n, the format string and the argument list.  The function
always traverses the argument list from the beginning, extracting the format or
promotion information for the variables to be discarted during the traversal of
the list from the format string and stops after having accessed the n-1 variable.
Now the stack pointer points at the n-th variable, that is the variable that the
calling function wants to read from the list/stack, and the function returns.
The design goal is not to be fast but not to relay neither on dynamically
growing data structures at runtime nor on statically defined data structures
at compile time.  The patch also contains the code for %[aA] conversion
specifier support that I had submitted some time ago.

As usual suggestions, objections, comments are welcome.


Regards,
Juan M. Guerrero





2008-03-03  Juan Manuell Guerrero  <juan DOT guerrero AT gmx DOT de>

	* src/libc/ansi/stdio/doprnt.c: Implementation of support for numeric
	conversion specifier, %a and %A conversion specifier and grouping
	conversion qualifier.
	(__traverse_argument_list): New function.
	(__grouping_format): New function.
	(cvtl): Support for %a and %A conversion specifier added.

	* src/libc/ansi/stdio/printf.txh: Info about grouping conversion
	qualifier, a, A, F and numeric convertion specifiers for printf
	added.

	* src/docs/kb/wc204.txi: Info about grouping conversion qualifier,
	a, A, F and numeric convertion specifiers for doprnt.c and printf
	family of functions added.

	* tests/cygnus/convert.c (test_nan_inf): Tests adjusted for the use
	of nan/NAN and inf/INF (C99 strings) instead of Inf and NaN strings.

	*tests/libc/ansi/stdio/makefile: Testcase file printf3.c for testing
	%[aA] conversion specifier added.  Testcase file printf4.c for testing
	numeric conversion specifier added.

	* tests/libc/ansi/stdio/printf3.c: New file.  Implements tests for
	%a and %A conversion specifier.

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







diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi	2005-05-11 20:06:08 +0000
+++ djgpp/src/docs/kb/wc204.txi	2008-03-04 19:06:06 +0000
@@ -1094,3 +1094,21 @@ formats for @code{"%x"} and @code{"%X"} 
 
 @pindex djasm AT r{, cr4 register}
 @code{djasm} recognises the fourth control register, @code{cr4}.
+
+@findex _doprnt AT r{, and C99 conversion specifiers}
+@findex printf AT r{, and C99 conversion specifiers}
+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 C99 conversion qualifiers}
+@findex printf AT r{, and C99 conversion qualifiers}
+The @code{'} conversion qualifier is 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	2007-12-11 07:27:40 +0000
+++ djgpp/src/libc/ansi/stdio/doprnt.c	2008-03-04 19:08:30 +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 */
@@ -12,14 +13,17 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <locale.h>
-#include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <math.h>
+#include <limits.h>
 #include <libc/file.h>
 #include <libc/local.h>
 #include <libc/ieee.h>
 
-static char decimal = '.';
+static char decimal_point;
+static char thousands_sep;
+static char *grouping;
 
 /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
 #define	MAXEXP		308
@@ -34,12 +38,22 @@ static char decimal = '.';
 
 #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 {                                                         \
+    const char *digit = (case) ? UPPER_DIGITS : LOWER_DIGITS;  \
+    register type _value = (type)(value);                      \
+                                                               \
+    do {                                                       \
+      *--(string) = digit[(_value) % (base)];                  \
+    } while ((_value) /= (base));                              \
+  } while (0)
 
 static int nan_p = 0;
 
@@ -58,14 +72,18 @@ static __inline__ char tochar(int n)
 
 /* have to deal with the negative buffer count kludge */
 
-#define	LONGINT		0x01		/* long integer */
-#define	LONGDBL		0x02		/* long double */
-#define	SHORTINT	0x04		/* short integer */
-#define	CHARINT		0x08		/* char */
-#define	ALT		0x10		/* alternate form */
-#define	LADJUST		0x20		/* left adjustment */
-#define	ZEROPAD		0x40		/* zero (as opposed to blank) pad */
-#define	HEXPREFIX	0x80		/* add 0x or 0X prefix */
+#define	LONGINT		0x001		/* long integer */
+#define	LONGDBL		0x002		/* long double */
+#define	SHORTINT	0x004		/* short integer */
+#define	CHARINT		0x008		/* char */
+#define	FLOAT		0x010		/* %f, %F, %g or %G decimal conversions */
+#define	ALT		0x020		/* alternate form */
+#define	LADJUST		0x040		/* left adjustment */
+#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
+#define	HEXPREFIX	0x100		/* add 0x or 0X prefix */
+#define	UPPERCASE	0x200		/* INF/NAN for [AEFG] */
+#define	GROUPING	0x400		/* non monetary thousands grouping */
+#define	FINITENUMBER	0x800		/* not set if NAN, INF or Unnormal */
 
 static int cvtl(long double number, int prec, int flags, char *signp,
 	        unsigned char fmtch, char *startp, char *endp);
@@ -73,11 +91,18 @@ static char *doprnt_roundl(long double f
 			   char *end, char ch, char *signp);
 static char *exponentl(char *p, int expv, unsigned char fmtch);
 #ifdef __GO32__
-static int isspeciall(long double d, char *bufp);
+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 char UNNORMAL_REP[] = "Unnormal";
+static const char UNNORMAL_REP[] = "Unnormal";
+static const char LOWER_DIGITS[] = "0123456789abcdef";
+static const char UPPER_DIGITS[] = "0123456789ABCDEF";
+static const char INF_REP[2][4] = {"inf", "INF"};  /* inf for [aefg] and INF for [AEFG] */
+static const char NAN_REP[2][4] = {"nan", "NAN"};  /* nan for [aefg] and NAN for [AEFG] */
 
 int
 _doprnt(const char *fmt0, va_list argp, FILE *fp)
@@ -88,24 +113,30 @@ _doprnt(const char *fmt0, va_list argp, 
   int n;			/* random handy integer */
   char *t;			/* buffer pointer */
   long double _ldouble;		/* double and long double precision arguments
-				   %L.[eEfgG] */
+				   %L.[aAeEfFgG] */
   unsigned long long _ulonglong=0; /* integer arguments %[diouxX] */
   int base;			/* base for [diouxX] conversion */
   int dprec;			/* decimal precision in [diouxX] */
   int fieldsz;			/* field size expanded by sign, etc */
   int flags;			/* flags as above */
-  int fpprec;			/* `extra' floating precision in [eEfgG] */
+  int fpprec;			/* `extra' floating precision in [eEfFgG] */
   int prec;			/* precision from format (%.3d), or -1 */
   int realsz;			/* field size expanded by decimal precision */
   int size;			/* size of converted field or string */
   int width;			/* width from format (%8d), or 0 */
   char sign;			/* sign prefix (' ', '+', '-', or \0) */
   char softsign;		/* temporary negative sign for floats */
-  const char *digs;		/* digits for [diouxX] conversion */
-  char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
+  char buf[BUF];		/* space for %c, %[diouxX], %[aAeEfFgG] */
   int neg_ldouble = 0;		/* non-zero if _ldouble is negative */
+  struct lconv *locale_info;    /* current locale information */
+  int using_numeric_conv_spec;  /* 1 if using numeric specifier, 0 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 */
+
 
-  decimal = localeconv()->decimal_point[0];
+  locale_info = localeconv();
+  decimal_point = locale_info->decimal_point[0];
 
   if (fp->_flag & _IORW)
   {
@@ -115,10 +146,13 @@ _doprnt(const char *fmt0, va_list argp, 
   if ((fp->_flag & _IOWRT) == 0)
     return (EOF);
 
+  using_numeric_conv_spec = 0;
+  arg_list = argp;
   fmt = fmt0;
-  digs = "0123456789abcdef";
   for (cnt = 0;; ++fmt)
   {
+    _longdouble_union_t ldvalue;
+
     while ((ch = *fmt) && ch != '%')
     {
       PUTC (ch);
@@ -127,12 +161,24 @@ _doprnt(const char *fmt0, va_list argp, 
     }
     if (!ch)
       return cnt;
+    base = 0;
     flags = 0; dprec = 0; fpprec = 0; width = 0;
     prec = -1;
     sign = '\0';
   rflag:
     switch (*++fmt)
     {
+    case '\'':
+       /*
+        *  If the locale is C or POSIX
+        *  this is defacto a NOP because
+        *  neither thousands_sep nor grouping
+        *  are set.
+        */
+       flags |= GROUPING;
+       thousands_sep = locale_info->thousands_sep[0];
+       grouping = locale_info->grouping;
+       goto rflag;
     case ' ':
       /*
        * ``If the space and + flags both appear, the space
@@ -152,6 +198,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 = 1;
+        argp = __traverse_argument_list(n, fmt0, arg_list);
+      }
+      else
+        fmt = pos;
       if ((width = va_arg(argp, int)) >= 0)
 	goto rflag;
       width = -width;
@@ -164,7 +220,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 = 1;
+          argp = __traverse_argument_list(n, fmt0, arg_list);
+        }
+        else
+          fmt = pos;
+        n = va_arg(argp, int);
+      }
       else
       {
 	n = 0;
@@ -188,14 +256,22 @@ _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 = 1;
+        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;
@@ -205,7 +281,7 @@ _doprnt(const char *fmt0, va_list argp, 
       }
       goto rflag;
     case 'l':
-      if (flags&LONGINT)
+      if (flags & LONGINT)
 	flags |= LONGDBL; /* for 'll' - long long */
       else
 	flags |= LONGINT;
@@ -229,6 +305,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)
       {
@@ -236,30 +314,54 @@ _doprnt(const char *fmt0, va_list argp, 
 	sign = '-';
       }
       base = 10;
+      flags |= FINITENUMBER;
       goto number;
-    case 'e':
+    case 'A':
     case 'E':
+    case 'F':
+    case 'G':
+      flags |= UPPERCASE;
+    case 'a':
+    case 'e':
     case 'f':
     case 'g':
-    case 'G':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
+      flags |= FLOAT;
+      if (*fmt == 'A' || *fmt == 'a')
+        flags |= HEXPREFIX;
       if (flags & LONGDBL)
 	_ldouble = va_arg(argp, long double);
       else
 	_ldouble = (long double)va_arg(argp, double);
+
+      ldvalue.ld = _ldouble;
+      if (ldvalue.ldt.exponent != 0x7FFF)
+        flags |= FINITENUMBER;
+
       /*
        * don't do unrealistic precision; just pad it with
        * zeroes later, so buffer size stays rational.
        */
       if (prec > MAXFRACT)
       {
-	if (*fmt != 'g' && (*fmt != 'G' || (flags&ALT)))
+	if (*fmt != 'g' && (*fmt != 'G' || (flags & ALT)))
 	  fpprec = prec - MAXFRACT;
 	prec = MAXFRACT;
       }
       else if (prec == -1)
       {
-	if (flags&LONGINT)
+	if (flags & LONGINT)
 	  prec = DEFLPREC;
+	else if (flags & HEXPREFIX)
+          /*
+           *  C99 imposes that precision must be sufficient
+           *  for an exact representation of the mantissa.
+           *  If no explicit precision is given, the required
+           *  precision for exact representation will be
+           *  determinated in the convertion function itself.
+           */
+	  prec = -1;
 	else
 	  prec = DEFPREC;
       }
@@ -275,11 +377,7 @@ _doprnt(const char *fmt0, va_list argp, 
       }
       else
       {
-	_longdouble_union_t ip;
-
-	ip.ld = _ldouble;
-
-	if (ip.ldt.sign)
+	if (ldvalue.ldt.sign)
 	  neg_ldouble = 1;
 	else
 	  neg_ldouble = 0;
@@ -288,7 +386,7 @@ _doprnt(const char *fmt0, va_list argp, 
       /*
        * cvt may have to round up past the "start" of the
        * buffer, i.e. ``intf("%.2f", (double)9.999);'';
-       * if the first char isn't NULL, it did.
+       * if the first char isn't NUL, it did.
        */
       *buf = '\0';
       size = cvtl(_ldouble, prec, flags, &softsign, *fmt, buf,
@@ -303,8 +401,11 @@ _doprnt(const char *fmt0, va_list argp, 
 	sign = '-';
       nan_p = 0;
       t = *buf ? buf : buf + 1;
+      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)
@@ -320,8 +421,11 @@ _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;
       goto nosign;
     case 'p':
       /*
@@ -332,10 +436,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)
@@ -364,15 +472,21 @@ _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;
       goto nosign;
     case 'X':
-      digs = "0123456789ABCDEF";
+      flags |= UPPERCASE;
       /* FALLTHROUGH */
     case 'x':
+      if (using_numeric_conv_spec)
+        argp = to_be_printed;
       ARG(unsigned);
       base = 16;
+      flags |= FINITENUMBER;
       /* leading 0x/X only if non-zero */
       if (flags & ALT && _ulonglong != 0)
 	flags |= HEXPREFIX;
@@ -399,31 +513,32 @@ _doprnt(const char *fmt0, va_list argp, 
       if (_ulonglong != 0 || prec != 0)
       {
         /* conversion is done separately since operations
-	  with long long are much slower */
-#define CONVERT(type) \
-	{ \
-	  register type _n = (type)_ulonglong; \
-	  do { \
-	    *--t = digs[_n % base]; \
-	    _n /= base; \
-	  } while (_n); \
-	}
-	if (flags&LONGDBL)
-	  CONVERT(unsigned long long) /* no ; */
-	else
-	  CONVERT(unsigned long) /* no ; */
-#undef CONVERT
+           with long long are much slower */
+        if (flags & LONGDBL)
+          CONVERT(unsigned long long, _ulonglong, base, t, flags & UPPERCASE);
+        else
+          CONVERT(unsigned long, _ulonglong, base, t, flags & UPPERCASE);
+
         if (flags & ALT && base == 8 && *t != '0')
           *--t = '0';		/* octal leading 0 */
       }
 
-      digs = "0123456789abcdef";
       size = buf + BUF - t;
 
     pforw:
+      if (flags & FINITENUMBER && flags & GROUPING && base == 10 && thousands_sep && *grouping != CHAR_MAX)
+      {
+        register char *p;
+
+        for (p = buf; *t; *p++ = *t++)
+          ;  /*  The function expects the string to be formated at the beginning of the buffer.  */
+        t = __grouping_format(buf, p, buf + BUF, flags);
+        size = buf + BUF - t;
+      }
+
       /*
        * All reasonable formats wind up here.  At this point,
-       * `t' points to a string which (if not flags&LADJUST)
+       * `t' points to a string which (if not flags & LADJUST)
        * should be padded out to `width' places.  If
        * flags&ZEROPAD, it should first be prefixed by any
        * sign or other prefix; otherwise, it should be blank
@@ -443,23 +558,23 @@ _doprnt(const char *fmt0, va_list argp, 
       realsz = dprec > fieldsz ? dprec : fieldsz;
       if (sign)
 	realsz++;
-      if (flags & HEXPREFIX)
-	realsz += 2;
+      if ((flags & HEXPREFIX) && (flags & FINITENUMBER))
+	realsz += 2;  /* hex leading 0x */
 
       /* right-adjusting blank padding */
-      if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
+      if ((flags & (LADJUST | ZEROPAD)) == 0 && width)
 	for (n = realsz; n < width; n++)
 	  PUTC(' ');
       /* prefix */
       if (sign)
 	PUTC(sign);
-      if (flags & HEXPREFIX)
+      if ((flags & HEXPREFIX) && (flags & FINITENUMBER))
       {
 	PUTC('0');
-	PUTC((char)*fmt);
+	PUTC((*fmt == 'A') ? 'X' : (*fmt == 'a') ? 'x' : (char)*fmt);
       }
       /* right-adjusting zero padding */
-      if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+      if ((flags & (LADJUST | ZEROPAD)) == ZEROPAD)
 	for (n = realsz; n < width; n++)
 	  PUTC('0');
       /* leading zeroes from decimal precision */
@@ -525,9 +640,197 @@ cvtl(long double number, int prec, int f
   int doingzero=0;     /* We're displaying 0.0 */
   long double integer, tmp;
 
-  if ((expcnt = isspeciall(number, startp)))
+  if ((expcnt = isspeciall(number, startp, flags)))
     return(expcnt);
 
+  if (fmtch == 'a' || fmtch == 'A')
+  {
+    /*
+     *  We are dealing with intel's extended double format.
+     *  The 64-bit mantissa explicitly contains the leading integer binary digit.
+     *  C99 standard defines hex float format as: 0xh.hhhp+d
+     *  where h is a hex digit, d is a decimal digit and p represents base 2.
+     *  The 64 bit of the mantissa can be subdivided into 16 nibbles,
+     *  so exact hex representation of the binary coded mantissa is
+     *  possible.  To get a single hex digit in the integer part of
+     *  the mantissa the period must be shifted by three places
+     *  to the right if the number is a normalized finite one.
+     *  If it is a denormalized finite number, then it may become necessary
+     *  to shift the period by ont to fifteen places.  Accordingly the exponent
+     *  must be adjusted.
+     */
+#undef  FALSE
+#define FALSE                           0
+#undef  TRUE
+#define TRUE                            1
+#define CHAR_SIZE                       8
+#define HEX_DIGIT_SIZE                  4
+#define IEEE754_LONG_DOUBLE_BIAS        0x3fff
+
+
+    long_double_t ip = *(long_double_t *)(void *)&number;
+    char *fraction_part;
+    int left_shifts, precision_given, positive_exponent, exponent = ip.exponent;
+    unsigned long long int mantissa = (unsigned long long int) ip.mantissah << 32 | ip.mantissal;
+
+    p = endp;
+    t = startp;
+    precision_given = (prec != -1) ? TRUE : FALSE;
+
+    /*
+     *  Compute the amount of left shifts necessary
+     *  to have one single hex digit (nibble) in the
+     *  integer part of the mantissa.  For normalized
+     *  finite numbers these are 3.  For denormalized
+     *  finte numbers these will range from 1 to 15.
+     *  Accordingly to this value the exponent will be
+     *  adjusted.
+     */
+    left_shifts = 0;  /*  No shifts for 0.0  */
+    if (mantissa)
+    {
+      unsigned long long int m = mantissa;
+
+      for (; (mantissa & 0x8000000000000000ULL) == 0; left_shifts++)
+        mantissa <<= 1;
+      if (left_shifts)  /*  Denormalized finite.  */
+      {
+        if (precision_given == FALSE)
+          mantissa = m;
+
+        if (left_shifts < (int)(sizeof(mantissa) * CHAR_SIZE - HEX_DIGIT_SIZE))
+        {
+          /*
+           *  For an exact representation of the mantissa
+           *  there must be a integral number of nibbles
+           *  (hex digit) in the fraction part of the mantissa.
+           *  A fraction part of a nibble will be shifted
+           *  into the integer part of the mantissa.
+           *  The converted mantisssa will look like:
+           *    0xh.hhhh
+           *  and the exponent will be adjusted accordingly.
+           */
+          unsigned int bin_digits, digits = (sizeof(mantissa) * CHAR_SIZE - 1 - left_shifts) % HEX_DIGIT_SIZE;  /*  Number of digits that do not build a nibble in the fraction part.  */
+
+          /*
+           *  Shift the period to the left
+           *  until no fraction of a nibble remains
+           *  in the fraction part of the mantissa.
+           */
+          for (bin_digits = 0; bin_digits < digits; bin_digits++)
+            left_shifts++;
+
+          /*
+           *  If no binary digits are shifted into the integer part,
+           *  then the nibble of the integer part must be filled with zeros.
+           */
+          if (precision_given == TRUE && bin_digits == 0)
+            mantissa >>= (HEX_DIGIT_SIZE - 1);
+        }
+        else
+          left_shifts = sizeof(mantissa) * CHAR_SIZE - 1;
+      }
+      else              /*  Normalized finite.  */
+        left_shifts = HEX_DIGIT_SIZE - 1;
+    }
+
+    /*
+     *  Mantissa.
+     *  The mantissa representation shall be exact
+     *  except that trailing zeros may be omitted.
+     */
+    if (precision_given == TRUE)
+    {
+      unsigned int fraction_hex_digits = sizeof(mantissa) * CHAR_SIZE / HEX_DIGIT_SIZE - 1;  /*  Number of hex digits (nibbles) in the fraction part.  */
+
+      if (prec < (int)fraction_hex_digits)
+      {
+        /*
+         *  If requested precision is less than the size of
+         *  the mantissa's fraction do rounding to even.
+         */
+#define MUST_ROUND_TO_EVEN(value)  ((((value) & 0x0fULL) == 0x08ULL) && ((((value) & 0xf0ULL) >> HEX_DIGIT_SIZE) % 2))
+        unsigned int n = fraction_hex_digits - prec - 1;  /*  One nibble more than precision.  */
+
+        mantissa >>= n * HEX_DIGIT_SIZE;  /*  The least significant nibble will determinate the rounding.  */
+        if (((mantissa & 0x0fULL) > 0x08ULL) || MUST_ROUND_TO_EVEN(mantissa))
+          mantissa += 0x10ULL;            /*  Round up.  */
+        mantissa >>= HEX_DIGIT_SIZE;      /*  Discard least significant nibble used for rounding.  */
+
+        n = fraction_hex_digits - n;
+        if ((mantissa >> (n * HEX_DIGIT_SIZE)) & 0x01ULL)  /*  Carry ?  */
+        {
+          /*
+           *  The rounding has produced a 2 hex digit long integer part
+           *  of the mantissa, so the mantissa must be shifted to the right
+           *  by one hex digit and the exponent adjusted accordingly.
+           */
+          mantissa >>= HEX_DIGIT_SIZE;
+          left_shifts -= HEX_DIGIT_SIZE;
+        }
+#undef MUST_ROUND_TO_EVEN
+      }
+    }
+
+    CONVERT(unsigned long long int, mantissa, 16, p, fmtch == 'A');
+    *t++ = *p++;
+    *t++ = decimal_point;
+
+    fraction_part = t;
+    for (; p < endp; *t++ = *p++)
+      ;
+    if (precision_given == FALSE)
+    {
+      /*
+       *  C99 imposes that, if the precision is omitted,
+       *  the precision must be sufficient for an exact
+       *  representation of the mantissa except that the
+       *  trailing zeros may be omitted.
+       */
+      while (*--t == '0')
+        ;  /*  Discart trailing zeros. */
+      t++;  /*  Points to first free place.  */
+    }
+    else
+      while (t - fraction_part < prec && t < endp)
+        *t++ = '0';  /*  Pad with zeros to the right.  At the end of the loop points to first free place.  */
+    if (t[-1] == decimal_point && !(flags & ALT))
+      t--;  /*  Do not output a decimal point.  */
+
+    /*
+     *  Exponent.
+     */
+    if (exponent == 0)
+    {
+      if (mantissa)     /*  Denormalized finite number.  */
+        exponent = 1 - IEEE754_LONG_DOUBLE_BIAS;
+    }
+    else                /*  Normalized finite number.  */
+      exponent -= IEEE754_LONG_DOUBLE_BIAS;
+    exponent -= left_shifts;
+    if (exponent < 0)
+    {
+      exponent = -exponent;
+      positive_exponent = FALSE;
+    }
+    else
+      positive_exponent = TRUE;
+
+    CONVERT(int, exponent, 10, p, flags & UPPERCASE);
+    *--p = (positive_exponent) ? '+' : '-';
+    *--p = (flags & UPPERCASE) ? 'P' : 'p';
+    for (; p < endp; *t++ = *p++)
+      ;
+
+    return t - startp;
+
+#undef IEEE754_LONG_DOUBLE_BIAS
+#undef HEX_DIGIT_SIZE
+#undef CHAR_SIZE
+#undef FALSE
+#undef TRUE
+  }
+
   dotrim = expcnt = gformat = 0;
   /* fract = modfl(number, &integer); */
   integer = number;
@@ -572,11 +875,12 @@ cvtl(long double number, int prec, int f
   number = integer;
   fract = modfl(number, &integer);
   /* If integer is zero then we need to look at where the sig figs are */
-  if (integer<1) {
-        /* If fract is zero the zero before the decimal point is a sig fig */
-        if (fract==0.0) doingzero=1;
-        /* If fract is non-zero all sig figs are in fractional part */
-        else doextradps=1;
+  if (integer < 1)
+  {
+    /* If fract is zero the zero before the decimal point is a sig fig */
+    if (fract == 0.0) doingzero = 1;
+    /* If fract is non-zero all sig figs are in fractional part */
+    else doextradps = 1;
   }
   /*
    * get integer portion of number; put into the end of the buffer.
@@ -595,6 +899,7 @@ cvtl(long double number, int prec, int f
   switch(fmtch)
   {
   case 'f':
+  case 'F':
     /* reverse integer into beginning of buffer */
     if (expcnt)
       for (; ++p < endp; *t++ = *p);
@@ -604,8 +909,8 @@ cvtl(long double number, int prec, int f
      * if precision required or alternate flag set, add in a
      * decimal point.
      */
-    if (prec || flags&ALT)
-      *t++ = decimal;
+    if (prec || (flags & ALT))
+      *t++ = decimal_point;
     /* if requires more precision and some fraction left */
     if (fract)
     {
@@ -626,8 +931,8 @@ cvtl(long double number, int prec, int f
     if (expcnt)
     {
       *t++ = *++p;
-      if (prec || flags&ALT)
-	*t++ = decimal;
+      if (prec || (flags & ALT))
+	*t++ = decimal_point;
       /* if requires more precision and some integer left */
       for (; prec && ++p < endp; --prec)
 	*t++ = *p;
@@ -683,14 +988,14 @@ cvtl(long double number, int prec, int f
 	  break;
       }
       *t++ = tochar((int)tmp);
-      if (prec || flags&ALT)
-	*t++ = decimal;
+      if (prec || (flags & ALT))
+	*t++ = decimal_point;
     }
     else
     {
       *t++ = '0';
-      if (prec || flags&ALT)
-	*t++ = decimal;
+      if (prec || (flags & ALT))
+	*t++ = decimal_point;
     }
     /* if requires more precision and some fraction left */
     if (fract)
@@ -708,10 +1013,10 @@ cvtl(long double number, int prec, int f
     for (; prec--; *t++ = '0');
 
     /* unless alternate flag, trim any g/G format trailing 0's */
-    if (gformat && !(flags&ALT))
+    if (gformat && !(flags & ALT))
     {
       while (t > startp && *--t == '0');
-      if (*t == decimal)
+      if (*t == decimal_point)
 	--t;
       ++t;
     }
@@ -760,10 +1065,10 @@ cvtl(long double number, int prec, int f
      * if precision required or alternate flag set, add in a
      * decimal point.  If no digits yet, add in leading 0.
      */
-    if (prec || flags&ALT)
+    if (prec || flags & ALT)
     {
       dotrim = 1;
-      *t++ = decimal;
+      *t++ = decimal_point;
     }
     else
       dotrim = 0;
@@ -775,8 +1080,9 @@ cvtl(long double number, int prec, int f
       /* If we're not adding 0s
        * or we are but they're sig figs:
        * decrement the precision */
-      if ((doextradps!=1) || ((int)tmp!=0)) {
-        doextradps=0;
+      if ((doextradps != 1) || ((int)tmp != 0))
+      {
+        doextradps = 0;
         prec--;
       }
     }
@@ -784,12 +1090,12 @@ cvtl(long double number, int prec, int f
       startp = doprnt_roundl(fract, (int *)NULL, startp, t - 1,
 			     (char)0, signp);
     /* alternate format, adds 0's for precision, else trim 0's */
-    if (flags&ALT)
+    if (flags & ALT)
       for (; prec--; *t++ = '0');
     else if (dotrim)
     {
       while (t > startp && *--t == '0');
-      if (*t != decimal)
+      if (*t != decimal_point)
 	++t;
     }
   }
@@ -807,7 +1113,7 @@ doprnt_roundl(long double fract, int *ex
     if (fract == 0.5L)
     {
       char *e = end;
-      if (*e == decimal)
+      if (*e == decimal_point)
 	e--;
       if (*e == '0' || *e == '2' || *e == '4'
 	  || *e == '6' || *e == '8')
@@ -824,7 +1130,7 @@ doprnt_roundl(long double fract, int *ex
   if (tmp > 4)
     for (;; --end)
     {
-      if (*end == decimal)
+      if (*end == decimal_point)
 	--end;
       if (++*end <= '9')
 	break;
@@ -848,7 +1154,7 @@ doprnt_roundl(long double fract, int *ex
   else if (*signp == '-')
     for (;; --end)
     {
-      if (*end == decimal)
+      if (*end == decimal_point)
 	--end;
       if (*end != '0')
 	break;
@@ -890,44 +1196,239 @@ exponentl(char *p, int expv, unsigned ch
 }
 
 static int
-isspeciall(long double d, char *bufp)
+isspeciall(long double d, char *bufp, int flags)
 {
-  typedef struct {
-    unsigned manl:32;
-    unsigned manh:32;
-    unsigned exp:15;
-    unsigned sign:1;
-  } IEEExp;
-
-  typedef union {
-    IEEExp ip;
-    long double ldouble;  /* double and long double precision arguments */
-  } ip_union;
+  _longdouble_union_t ldvalue;
+  int style = (flags & UPPERCASE) ? 1 : 0;
 
-  ip_union ip;
-
-  ip.ldouble = d;
+  ldvalue.ld = d;
 
   nan_p = 0;  /* don't assume the static is 0 (emacs) */
 
   /* Unnormals: the MSB of mantissa is non-zero, but the exponent is
      not zero either.  */
-  if ((ip.ip.manh & 0x80000000U) == 0 && ip.ip.exp != 0)
+  if ((ldvalue.ldt.mantissah & 0x80000000U) == 0 && ldvalue.ldt.exponent != 0)
   {
-    if (ip.ip.sign)
+    if (ldvalue.ldt.sign)
       *bufp++ = '-';
     strcpy(bufp, UNNORMAL_REP);
-    return strlen(bufp) + ip.ip.sign;
+    return strlen(bufp) + ldvalue.ldt.sign;
   }
-  if (ip.ip.exp != 0x7fff)
+  if (ldvalue.ldt.exponent != 0x7fff)
     return(0);
-  if ((ip.ip.manh & 0x7fffffff) || ip.ip.manl)
+  if ((ldvalue.ldt.mantissah & 0x7fffffff) || ldvalue.ldt.mantissal)
   {
-    strcpy(bufp, "NaN");
-    nan_p = ip.ip.sign ? -1 : 1; /* kludge: we don't need the sign, it's
-				    not nice, but it should work */
+    strcpy(bufp, NAN_REP[style]);
+    nan_p = ldvalue.ldt.sign ? -1 : 1; /* kludge: we don't need the sign, it's
+                                          not nice, but it should work */
   }
   else
-    (void)strcpy(bufp, "Inf");
+    (void)strcpy(bufp, INF_REP[style]);
   return(3);
 }
+
+static __inline__ char *
+__grouping_format(char *string_start, char *string_end, char *buffer_end, int flags)
+{
+  /*
+   *  Format the string representing the integer portion of a decimal
+   *  conversion using non-mometary thousands' grouping characters.
+   *  It is assumed that STRING_START points at the beginning and 
+   *  STRING_END points to the end of the string to be formatted.
+   *  BUFFER_END points to the end of the buffer that will store
+   *  the formated string.
+   */
+
+  ptrdiff_t grouping_size;
+  register char *pos, *src, *dst;
+
+
+  src = string_end;
+  dst = buffer_end;
+
+  /*
+   *  The fractional portion of the result of a decimal conversion
+   *  (%f, %F, %g or %G) is left unaltered.
+   */
+  if (flags & FLOAT)
+    for (; *src != decimal_point; *--dst = *--src)
+      ;  /*  Copy fractional portion to the end of the buffer.  */
+
+  pos = dst;
+  grouping_size = (ptrdiff_t)*grouping;
+  if (grouping_size == (ptrdiff_t)CHAR_MAX)
+    for (; src > string_start; *--dst = *--src)
+      ;  /*  Group the remainder digits together.  */
+  else
+    for (; src > string_start; *--dst = *--src)
+      if (pos - dst == grouping_size)
+      {
+        *--dst = thousands_sep;
+        pos = dst;
+        if (grouping_size)
+        {
+          grouping++;
+          if (*grouping == (ptrdiff_t)CHAR_MAX)
+            grouping_size = 0;  /*  Group the remainder digits together.  */
+          else if (*grouping)
+            grouping_size = (ptrdiff_t)*grouping;  /*  Get next size of group of digits to be formatted.  */
+        }
+      }
+
+  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; /* discart 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);  /* discart */
+        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);  /* discart */
+          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);  /* discart */
+        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);  /* discart */
+        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);  /* discart */
+        else
+          va_arg(argp, double);  /* discart */
+        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);  /* discart */
+        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 *);  /* discart */
+        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	2003-01-29 12:28:44 +0000
+++ djgpp/src/libc/ansi/stdio/printf.txh	2008-03-04 19:06:06 +0000
@@ -13,8 +13,23 @@ int printf(const char *format, @dots{});
 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
 
@@ -24,6 +39,13 @@ an optional flag, which may alter the co
 
 @table @code
 
+@item '
+
+The integer part of the result of a decimal conversion (@code{%i},
+@code{%d}, @code{%u}, @code{%f}, @code{%F}, @code{%g} or @code{%G})
+will be formatted with thousands' grouping characters.
+The non-monetary grouping character is used.
+
 @item -
 
 left-justify the field.
@@ -54,6 +76,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
+specification, 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
 
@@ -63,6 +90,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
+specification, 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
 
@@ -101,6 +133,17 @@ The conversion type specifier:
 
 @table @code
 
+@item a
+@itemx A
+
+A floating point number (float or double) printed in the style
+@code{"[-]0xh.hhhhp[+|-]d"}, where @code{h} represents a hexadecimal
+digit, @code{d} represents a decimal digit and @code{p} stands for the
+base 2.  For long double, use @code{"La"} or @code{"LA"}.  The case of
+the exponent, the case of the letters @code{"abcdef"} and the case of
+@code{"x"} matches the specifier case.  The representation always has
+an exponent.
+
 @item c
 
 A single character.
@@ -122,6 +165,7 @@ A floating point number (float or double
 case.  The representation always has an exponent.
 
 @item f
+@item F
 
 A floating point number (float or double).  For long double, use
 @code{"Lf"}.  The representation never has an exponent.
@@ -202,3 +246,37 @@ in the ANSI C99 standard.
 @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/cygnus/convert.c djgpp/tests/cygnus/convert.c
--- djgpp.orig/tests/cygnus/convert.c	1999-04-04 08:13:22 +0000
+++ djgpp/tests/cygnus/convert.c	2008-03-04 19:06:06 +0000
@@ -283,16 +283,29 @@ _DEFUN_VOID(test_nan_inf)
   newfunc("nan print");
   line(1);
   sprintf(buffer,"%e", nan());
-  test_sok(buffer,"NaN");
+  test_sok(buffer,"nan");
   line(2);
   sprintf(buffer,"%e", -nan());
-  test_sok(buffer,"NaN");
+  test_sok(buffer,"nan");
   line(3);
   sprintf(buffer,"%+e", nan());
-  test_sok(buffer,"+NaN");
+  test_sok(buffer,"+nan");
   line(4);
   sprintf(buffer,"%+e", -nan());
-  test_sok(buffer,"-NaN");
+  test_sok(buffer,"-nan");
+  newfunc("NAN print");
+  line(1);
+  sprintf(buffer,"%E", nan());
+  test_sok(buffer,"NAN");
+  line(2);
+  sprintf(buffer,"%E", -nan());
+  test_sok(buffer,"NAN");
+  line(3);
+  sprintf(buffer,"%+E", nan());
+  test_sok(buffer,"+NAN");
+  line(4);
+  sprintf(buffer,"%+E", -nan());
+  test_sok(buffer,"-NAN");
   newfunc("nanf");
   line(1);
   flt_inf_nan.value = nanf();
@@ -305,16 +318,29 @@ _DEFUN_VOID(test_nan_inf)
   newfunc("nanf print");
   line(1);
   sprintf(buffer,"%f", nanf());
-  test_sok(buffer,"NaN");
+  test_sok(buffer,"nan");
   line(2);
   sprintf(buffer,"%f", -nanf());
-  test_sok(buffer,"NaN");
+  test_sok(buffer,"nan");
   line(3);
   sprintf(buffer,"%+f", nanf());
-  test_sok(buffer,"+NaN");
+  test_sok(buffer,"+nan");
   line(4);
   sprintf(buffer,"%+f", -nanf());
-  test_sok(buffer,"-NaN");
+  test_sok(buffer,"-nan");
+  newfunc("NANf print");
+  line(1);
+  sprintf(buffer,"%F", nanf());
+  test_sok(buffer,"NAN");
+  line(2);
+  sprintf(buffer,"%F", -nanf());
+  test_sok(buffer,"NAN");
+  line(3);
+  sprintf(buffer,"%+F", nanf());
+  test_sok(buffer,"+NAN");
+  line(4);
+  sprintf(buffer,"%+F", -nanf());
+  test_sok(buffer,"-NAN");
   newfunc("infinity");
   line(1);
   inf_nan.value = infinity();
@@ -327,16 +353,29 @@ _DEFUN_VOID(test_nan_inf)
   newfunc("infinity print");
   line(1);
   sprintf(buffer,"%e", infinity());
-  test_sok(buffer,"Inf");
+  test_sok(buffer,"inf");
   line(2);
   sprintf(buffer,"%e", -infinity());
-  test_sok(buffer,"-Inf");
+  test_sok(buffer,"-inf");
   line(3);
   sprintf(buffer,"%+e", infinity());
-  test_sok(buffer,"+Inf");
+  test_sok(buffer,"+inf");
   line(4);
   sprintf(buffer,"%+e", -infinity());
-  test_sok(buffer,"-Inf");
+  test_sok(buffer,"-inf");
+  newfunc("INFINITY print");
+  line(1);
+  sprintf(buffer,"%E", infinity());
+  test_sok(buffer,"INF");
+  line(2);
+  sprintf(buffer,"%E", -infinity());
+  test_sok(buffer,"-INF");
+  line(3);
+  sprintf(buffer,"%+E", infinity());
+  test_sok(buffer,"+INF");
+  line(4);
+  sprintf(buffer,"%+E", -infinity());
+  test_sok(buffer,"-INF");
   newfunc("infinityf");
   line(1);
   flt_inf_nan.value = infinityf();
@@ -349,16 +388,29 @@ _DEFUN_VOID(test_nan_inf)
   newfunc("infinityf print");
   line(1);
   sprintf(buffer,"%f", infinityf());
-  test_sok(buffer,"Inf");
+  test_sok(buffer,"inf");
   line(2);
   sprintf(buffer,"%f", -infinityf());
-  test_sok(buffer,"-Inf");
+  test_sok(buffer,"-inf");
   line(3);
   sprintf(buffer,"%+f", infinityf());
-  test_sok(buffer,"+Inf");
+  test_sok(buffer,"+inf");
   line(4);
   sprintf(buffer,"%+f", -infinityf());
-  test_sok(buffer,"-Inf");
+  test_sok(buffer,"-inf");
+  newfunc("INFINITYf print");
+  line(1);
+  sprintf(buffer,"%F", infinityf());
+  test_sok(buffer,"INF");
+  line(2);
+  sprintf(buffer,"%F", -infinityf());
+  test_sok(buffer,"-INF");
+  line(3);
+  sprintf(buffer,"%+F", infinityf());
+  test_sok(buffer,"+INF");
+  line(4);
+  sprintf(buffer,"%+F", -infinityf());
+  test_sok(buffer,"-INF");
 #ifdef __DJGPP__
   _fpreset();
 #endif
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdio/makefile djgpp/tests/libc/ansi/stdio/makefile
--- djgpp.orig/tests/libc/ansi/stdio/makefile	2003-11-23 21:14:48 +0000
+++ djgpp/tests/libc/ansi/stdio/makefile	2008-03-04 19:06:06 +0000
@@ -16,6 +16,8 @@ SRC += hello.c
 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/printf3.c djgpp/tests/libc/ansi/stdio/printf3.c
--- djgpp.orig/tests/libc/ansi/stdio/printf3.c	1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/printf3.c	2008-03-04 19:06:06 +0000
@@ -0,0 +1,475 @@
+/*
+ * printf3.c
+ * Test cases for %a and %A conversion specifiers new to the ANSI C99 standard.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libc/ieee.h>
+
+#define LOWER_CASE 0
+#define UPPER_CASE 1
+
+static const char *to_be_printed[30][2] = {
+  /*
+   *  Long double test.
+   *  Normalized Finite.
+   */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /*  0: No precision given. Exact mantissa representation requested.  */
+  {"0xf.123456789ab0000p+0", "-0XF.123456789AB0000P+0"},  /*  1: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0xf.000000000000000p+0", "-0XF.000000000000000P+0"},  /*  2: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0xf.123456789fp+0",      "-0XF.123456789FP+0"},       /*  3: 9 precision digits. Rounding to even.  */
+  {"0xf.1234567891p+0",      "-0XF.1234567891P+0"},       /*  4: 9 precision digits. Rounding to even.  */
+  {"0xf.1234567898p+0",      "-0XF.1234567898P+0"},       /*  5: 9 precision digits. Rounding to even.  */
+  {"0xf.123456788p+0",       "-0XF.123456788P+0"},        /*  6: 8 precision digits. Rounding to even.  */
+  {"0xf.f00000000000000p+0", "-0XF.F00000000000000P+0"},  /*  7: 0 precision digits. Rounding to even.  */
+  {"0xf.100000000000000p+0", "-0XF.100000000000000P+0"},  /*  8: 0 precision digits. Rounding to even.  */
+  {"0x8.fedcba987654321p+0", "-0X8.FEDCBA987654321P+0"},  /*  9: 0 precision digits. Alternate flag given.  */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /* 10: 6 precision digits and 20 digits of field width.  */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /* 11: 6 precision digits and 20 digits of field width and zero padding.  */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /* 12: 6 precision digits and 20 digits of field width and zero padding and a sign.  */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /* 13: 30 precision digits and 40 digits of field width and zero padding and a sign.  */
+
+  /*
+   *  Long double test.
+   *  Denormalized Finite.
+   *
+   *  Long doubles as defined by intel's fpu.
+   *  bias: 0x3fff
+   *  Smallest licit exponent: -(bias - 1) = -16382
+   *  Radix is 2.
+   *  Mantissa of 64 bits with explicit integer bit.  Makes possible exact hex representation of mantissa.
+   *  Shifting binary point by 3 places to the right allows to represent the integer part of the mantissa
+   *  with one single hex digit. 
+   */
+  {"0x7.fffffffffffffffp-(16382 + 3)",  "-0X7.FFFFFFFFFFFFFFFP-(16382 + 3)"},  /* 14: No precision given. Exact mantissa representation requested.  */
+  {"0x0.123456789abcdefp-(16382 + 3)",  "-0X0.123456789ABCDEFP-(16382 + 3)"},  /* 15: No precision given. Exact mantissa representation requested.  */
+  {"0x0.800000000000000p-(16382 + 3)",  "-0X0.800000000000000P-(16382 + 3)"},  /* 16: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0x0.000000012345678p-(16382 + 3)",  "-0X0.000000012345678P-(16382 + 3)"},  /* 17: 3 precision digits. Rounding to even.  */
+  {"0x0.000000012345678p-(16382 + 3)",  "-0X0.000000012345678P-(16382 + 3)"},  /* 18: 12 precision digits. Rounding to even. Padding with 0.  */
+  {"0x0.0000000f1000000p-(16382 + 3)",  "-0X0.0000000F1000000P-(16382 + 3)"},  /* 19: 0 precision digits. Rounding to even.  */
+  {"0x0.0000000ff000000p-(16382 + 3)",  "-0X0.0000000FF000000P-(16382 + 3)"},  /* 20: 0 precision digits. Rounding to even.  */
+  {"0x0.000000080000000p-(16382 + 3)",  "-0X0.000000080000000P-(16382 + 3)"},  /* 21: 0 precision digits. Alternate flag given.  */
+  {"0x0.000000012345678p-(16382 + 3)",  "-0X0.000000012345678P-(16382 + 3)"},  /* 22: 6 precision digits and 20 digits of field width.  */
+  {"0x0.000000012345678p-(16382 + 3)",  "-0X0.000000012345678P-(16382 + 3)"},  /* 23: 6 precision digits and 20 digits of field width and zero padding.  */
+  {"+0x0.000000012345678p-(16382 + 3)", "-0X0.000000012345678P-(16382 + 3)"},  /* 24: 6 precision digits and 20 digits of field width and zero padding and a sign.  */
+  {"+0x0.123456789abcdefp-(16382 + 3)", "-0X0.123456789ABCDEFP-(16382 + 3)"},  /* 25: 30 precision digits and 50 digits of field width and zero padding and a sign.  */
+
+  /*
+   *  Long double test.
+   *  Zero, INF, NAN and Unnormal.
+   */
+  {"0x0.0p+0",      "-0X0.0P+0"},     /* 26: No precision given. Exact mantissa representation requested.  */
+  {"infinity",      "-INFINITY"},     /* 27: No precision given. Exact mantissa representation requested.  */
+  {"not a number",  "NOT A NUMBER"},  /* 28: No precision given. Exact mantissa representation requested.  */
+  {"Unnormal",      "-Unnormal"}      /* 29: No precision given. Exact mantissa representation requested.  */
+};
+
+static const char *should_looks_like[30][2] = {
+  /*
+   *  Long double test.
+   *  Normalized Finite.
+   */
+  {"0xf.123456789abcdefp+0", "-0XF.123456789ABCDEFP+0"},  /*  0: No precision given. Exact mantissa representation requested.  */
+  {"0xf.123456789abp+0",     "-0XF.123456789ABP+0"},      /*  1: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0xfp+0",                 "-0XFP+0"},                  /*  2: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0xf.12345678ap+0",       "-0XF.12345678AP+0"},        /*  3: 9 precision digits. Rounding to even.  */
+  {"0xf.123456789p+0",       "-0XF.123456789P+0"},        /*  4: 9 precision digits. Rounding to even.  */
+  {"0xf.12345678ap+0",       "-0XF.12345678AP+0"},        /*  5: 9 precision digits. Rounding to even.  */
+  {"0xf.12345678p+0",        "-0XF.12345678P+0"},         /*  6: 8 precision digits. Rounding to even.  */
+  {"0x1p+4",                 "-0X1P+4"},                  /*  7: 0 precision digits. Rounding to even.  */
+  {"0xfp+0",                 "-0XFP+0"},                  /*  8: 0 precision digits. Rounding to even.  */
+  {"0x9.p+0",                "-0X9.P+0"},                 /*  9: 0 precision digits. Alternate flag given.  */
+  {"       0xf.123456p+0",   "      -0XF.123456P+0"},     /* 10: 6 precision digits and 20 digits of field width.  */
+  {"0x0000000f.123456p+0",   "-0X000000F.123456P+0"},     /* 11: 6 precision digits and 20 digits of field width and zero padding.  */
+  {"+0x000000f.123456p+0",   "-0X000000F.123456P+0"},     /* 12: 6 precision digits and 20 digits of field width and zero padding and a sign.  */
+  {"+0x00f.123456789abcdef000000000000000p+0",
+   "-0X00F.123456789ABCDEF000000000000000P+0"},           /* 13: 30 precision digits and 40 digits of field width and zero padding and a sign.  */
+
+  /*
+   *  Long double test.
+   *  Denormalized Finite.
+   */
+  {"0x7.fffffffffffffffp-16385",  "-0X7.FFFFFFFFFFFFFFFP-16385"},  /* 14: No precision given. Exact mantissa representation requested.  */
+  {"0x1.23456789abcdefp-16389",   "-0X1.23456789ABCDEFP-16389"},   /* 15: No precision given. Exact mantissa representation requested.  */
+  {"0x8p-16389",                  "-0X8P-16389"},                  /* 16: No precision given. Exact mantissa representation requested. Trailing zeros will be omitted.  */
+  {"0x1.234p-16417",              "-0X1.234P-16417"},              /* 17: 3 precision digits. Rounding to even.  */
+  {"0x1.234567800000p-16417",     "-0X1.234567800000P-16417"},     /* 18: 12 precision digits. Rounding to even. Padding with 0.  */
+  {"0xfp-16417",                  "-0XFP-16417"},                  /* 19: 0 precision digits. Rounding to even.  */
+  {"0x1p-16413",                  "-0X1P-16413"},                  /* 20: 0 precision digits. Rounding to even.  */
+  {"0x8.p-16417",                 "-0X8.P-16417"},                 /* 21: 0 precision digits. Alternate flag given.  */
+  {"   0x1.234568p-16417",   "  -0X1.234568P-16417"},              /* 22: 6 precision digits and 20 digits of field width.  */
+  {"0x0001.234568p-16417",   "-0X001.234568P-16417"},              /* 23: 6 precision digits and 20 digits of field width and zero padding.  */
+  {"+0x001.234568p-16417",   "-0X001.234568P-16417"},              /* 24: 6 precision digits and 20 digits of field width and zero padding and a sign.  */
+  {"+0x000000001.23456789abcdef0000000000000000p-16389",
+   "-0X000000001.23456789ABCDEF0000000000000000P-16389"},          /* 25: 30 precision digits and 50 digits of field width and zero padding and a sign.  */
+
+  /*
+   *  Long double test.
+   *  Zero, INF, NAN and Unnormal.
+   */
+  {"0x0p+0",    "-0X0P+0"},    /* 26: No precision given. Exact mantissa representation requested.  */
+  {"inf",       "-INF"},       /* 27: No precision given. Exact mantissa representation requested.  */
+  {"nan",       "NAN"},        /* 28: No precision given. Exact mantissa representation requested.  */
+  {"Unnormal",  "-Unnormal"},  /* 29: No precision given. Exact mantissa representation requested.  */
+};
+
+static long_double_t number[] = {
+/*   mantissal    mantissah    exp             sgn  */
+  {0x89ABCDEFU, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  0: 0xF.123456789ABCDEFp+0  */
+  {0x89AB0000U, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  1: 0xF.123456700000000p+0  */
+  {0x00000000U, 0xF0000000U, 0x3FFFU + 0x03U, 0x0U},  /*  2: 0xF.000000000000000p+0  */
+  {0x89F00000U, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  3: 0xF.123456789Fp+0  */
+  {0x89100000U, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  4: 0xF.1234567891p+0  */
+  {0x89800000U, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  5: 0xF.1234567898p+0  */
+  {0x88000000U, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /*  6: 0xF.123456788p+0  */
+  {0x00000000U, 0xFF000000U, 0x3FFFU + 0x03U, 0x0U},  /*  7: 0xF.F00000000000000p+0  */
+  {0x00000000U, 0xF1000000U, 0x3FFFU + 0x03U, 0x0U},  /*  8: 0xF.F00000000000000p+0  */
+  {0x87654321U, 0x8FEDCBA9U, 0x3FFFU + 0x03U, 0x0U},  /*  9: 0x8.FEDCBA987654321p+0  */
+  {0x89ABCDEFU, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /* 10: 0xF.123456789ABCDEFp+0  */
+  {0x89ABCDEFU, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /* 11: 0xF.123456789ABCDEFp+0  */
+  {0x89ABCDEFU, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /* 12: 0xF.123456789ABCDEFp+0  */
+  {0x89ABCDEFU, 0xF1234567U, 0x3FFFU + 0x03U, 0x0U},  /* 13: 0xF.123456789ABCDEFp+0  */
+
+  {0xFFFFFFFFU, 0x7FFFFFFFU, 0x0000U,         0x0U},  /* 14: 0x7.FFFFFFFFFFFFFFFp-16385  */
+  {0x89ABCDEFU, 0x01234567U, 0x0000U,         0x0U},  /* 15: 0x0.123456789ABCDEFp-16385  */
+  {0x00000000U, 0x08000000U, 0x0000U,         0x0U},  /* 16: 0x0.800000000000000p-16385  */
+  {0x12345678U, 0x00000000U, 0x0000U,         0x0U},  /* 17: 0x0.000000012345678p-16385  */
+  {0x12345678U, 0x00000000U, 0x0000U,         0x0U},  /* 18: 0x0.000000012345678p-16385  */
+  {0xF1000000U, 0x00000000U, 0x0000U,         0x0U},  /* 19: 0x0.0000000F1000000p-16385  */
+  {0xFF000000U, 0x00000000U, 0x0000U,         0x0U},  /* 20: 0x0.0000000FF000000p-16385  */
+  {0x80000000U, 0x00000000U, 0x0000U,         0x0U},  /* 21: 0x0.000000080000000p-16385  */
+  {0x12345678U, 0x00000000U, 0x0000U,         0x0U},  /* 22: 0x0.000000012345678p-16385  */
+  {0x12345678U, 0x00000000U, 0x0000U,         0x0U},  /* 23: 0x0.000000012345678p-16385  */
+  {0x12345678U, 0x00000000U, 0x0000U,         0x0U},  /* 24: 0x0.000000012345678p-16385  */
+  {0x89ABCDEFU, 0x01234567U, 0x0000U,         0x0U},  /* 25: 0x0.123456789ABCDEFp-16385  */
+
+  {0x00000000U, 0x00000000U, 0x0000U,         0x0U},  /* 26: 0x0.000000000000000p+0  */
+  {0x00000000U, 0x80000000U, 0x7FFFU,         0x0U},  /* 27: INFINITY  */
+  {0x00000000U, 0xC0000000U, 0x7FFFU,         0x0U},  /* 28: NAN  */
+  {0x00000000U, 0x00000000U, 0x7FFFU,         0x0U},  /* 29: Unnormal  */
+};
+
+
+
+int
+main (void)
+{
+  _longdouble_union_t value;
+  unsigned int i = 0;
+
+  printf("Testing normalized finite numbers.\n");
+  printf("Printing value without specifying a precison.  Mantissa representation shall be exact.\n");
+  printf("Test: %u\n", i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value without specifying a precison.\nMantissa representation shall be exact.\nTrailing zeros will always be omitted.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 9 digits of precison.  Rounding to even.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9La: %.9La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9LA: %.9LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9La: %.9La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9LA: %.9LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9La: %.9La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.9LA: %.9LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 8 digits of precison.  Rounding to even.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.8La: %.8La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.8LA: %.8LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 0 digits of precison.  Rounding to even.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0La: %.0La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0LA: %.0LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0La: %.0La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0LA: %.0LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 0 digits of precison and alternate flag given.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:       %s\n"
+         "value printed with %%#.0La: %#.0La\n"
+         "should be:                 %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:       %s\n"
+         "value printed with %%#.0LA: %#.0LA\n"
+         "should be:                 %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:        %s\n"
+         "value printed with %%20.6La: %20.6La\n"
+         "should be:                  %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:       %s\n"
+         "value printed with %%20.6LA: %20.6LA\n"
+         "should be:                  %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits and zero padding.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:         %s\n"
+         "value printed with %%020.6La: %020.6La\n"
+         "should be:                   %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:         %s\n"
+         "value printed with %%020.6LA: %020.6LA\n"
+         "should be:                   %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits and zero padding and a sign.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:           %s\n"
+         "value printed with %%+020.6La: %+020.6La\n"
+         "should be:                    %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:          %s\n"
+         "value printed with %%+020.6LA: %+020.6LA\n"
+         "should be:                    %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 30 digits of precison and field width of 40 digits and zero padding and a sign.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:            %s\n"
+         "value printed with %%+040.30La: %+040.30La\n"
+         "should be:                     %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:           %s\n"
+         "value printed with %%+040.30LA: %+040.30LA\n"
+         "should be:                     %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+
+
+  printf("\n\nTesting denormalized finite numbers.  Smallest exponent: -16382.\nTo get a single nibble in the integer part of the mantissa\nthe exponent must be incremented by 3.\n");
+  printf("Printing value without specifying a precison.  Mantissa representation shall be exact.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value without specifying a precison.  Mantissa representation shall be exact.\nTrailing zeros will always be omitted.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 3 digits of precison.  Rounding to even.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.3La: %.3La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.3LA: %.3LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 12 digits of precison.  Rounding to even.\nPadding with 0 if precision is greater than number of significant digits in the mantissa.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:       %s\n"
+         "value printed with %%.12La: %.12La\n"
+         "should be:                 %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:       %s\n"
+         "value printed with %%.12LA: %.12LA\n"
+         "should be:                 %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 0 digits of precison.  Rounding to even.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0La: %.0La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0LA: %.0LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0La: %.0La\n"
+         "should be:                %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:      %s\n"
+         "value printed with %%.0LA: %.0LA\n"
+         "should be:                %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 0 digits of precison and alternate flag given.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:       %s\n"
+         "value printed with %%#.0La: %#.0La\n"
+         "should be:                 %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:       %s\n"
+         "value printed with %%#.0LA: %#.0LA\n"
+         "should be:                 %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:        %s\n"
+         "value printed with %%20.6La: %20.6La\n"
+         "should be:                  %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:       %s\n"
+         "value printed with %%20.6LA: %20.6LA\n"
+         "should be:                  %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits and zero padding.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:         %s\n"
+         "value printed with %%020.6La: %020.6La\n"
+         "should be:                   %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:         %s\n"
+         "value printed with %%020.6LA: %020.6LA\n"
+         "should be:                   %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 6 digits of precison and field width of 20 digits and zero padding and a sign.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:          %s\n"
+         "value printed with %%+020.6La: %+020.6La\n"
+         "should be:                    %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:          %s\n"
+         "value printed with %%+020.6LA: %+020.6LA\n"
+         "should be:                    %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  printf("\nPrinting value with 30 digits of precison and field width of 50 digits and zero padding and a sign.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:           %s\n"
+         "value printed with %%+050.30La: %+050.30La\n"
+         "should be:                     %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:           %s\n"
+         "value printed with %%+050.30LA: %+050.30LA\n"
+         "should be:                     %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+
+
+  printf("\n\nTesting 0.0, NAN, INF and Unnormal.\n");
+  printf("Printing value without specifying a precison.\n");
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], value.ld, should_looks_like[i][UPPER_CASE]);
+
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], value.ld, should_looks_like[i][UPPER_CASE]);
+  printf("Test: %u\n", ++i);
+  value.ldt = number[i];
+  printf("value to be printed:    %s\n"
+         "value printed with %%La: %La\n"
+         "should be:              %s\n\n", to_be_printed[i][LOWER_CASE], value.ld, should_looks_like[i][LOWER_CASE]);
+  printf("value to be printed:    %s\n"
+         "value printed with %%LA: %LA\n"
+         "should be:              %s\n\n", to_be_printed[i][UPPER_CASE], -value.ld, should_looks_like[i][UPPER_CASE]);
+
+
+  return(EXIT_SUCCESS);
+}
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-03-04 19:06:06 +0000
@@ -0,0 +1,54 @@
+/*
+ * printf4.c
+ * Test cases for numeric conversion specifiers.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+  char *weekday[] = {"Sabado", "Samstag", "Saturday"};
+  char *month[] = {"febrero", "Februar", "february"};
+  int day = 2;
+  int hour = 10;
+  int min = 20;
+  int width = 2;
+  int precision = 2;
+  double dvalue[] = {10.01, 20.02, 30.03};
+  int i;
+  char format[64];
+
+
+
+  printf("Printing language-independent date and time:\n");
+
+  printf("En castellano:\n");
+  printf("%5$s, %2$d de %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n", month[0], day, hour, min, weekday[0], width, precision);
+
+  printf("Auf deutsch:\n");
+  printf("%5$s, %2$d. %1$s, %3$*6$.*7$d:%4$*6$.*7$d\n", month[1], day, hour, min, weekday[1], width, precision);
+
+  printf("In english:\n");
+  printf("%5$s, %1$s %2$d, %3$*6$.*7$d:%4$*6$.*7$d\n", month[2], day, hour, min, weekday[2], width, precision);
+
+
+
+  printf("\n\nUsing a field width of %d and precision of %d.\n", width, precision);
+  strcpy(format, "%*.*f  %*.*f  %*.*f");
+  printf("Printing without numeric conversion specifier using format string \"%s\".\n", format);
+  strcat(format, "\n");
+  printf(format, width, precision, dvalue[0], width, precision, dvalue[1], width, precision, dvalue[2]);
+
+  strcpy(format, "%3$*1$.*2$f  %4$*1$.*2$f  %5$*1$.*2$f");
+  printf("Printing with numeric conversion specifier using format string \"%s\".\n", format);
+  strcat(format, "\n");
+  printf(format, width, precision, dvalue[0], dvalue[1], dvalue[2]);
+
+  strcpy(format, "%5$*1$.*2$f  %4$*1$.*2$f  %3$*1$.*2$f");
+  printf("Printing in inverse order with numeric conversion specifier using format string \"%s\".\n", format);
+  strcat(format, "\n");
+  printf("%5$*1$.*2$f  %4$*1$.*2$f  %3$*1$.*2$f\n", width, precision, dvalue[0], dvalue[1], dvalue[2]);
+
+  return 0;
+}

- Raw text -


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