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

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: V01U2FsdGVkX1+Xk2No8BKX18Ti2Qi0qe60DtgXKnNDmKqJ8K1baZ
zM3mXx/rMhu3/L
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 #1)
Date: Thu, 24 Apr 2008 16:27:25 +0200
User-Agent: KMail/1.9.5
MIME-Version: 1.0
Message-Id: <200804241627.27055.juan.guerrero@gmx.de>
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

The goal of this patch is to implement the grouping functionality in _doprnt().
Because there is only C locale it does nothing.  Neitherles the function has
been checked with modified and hardcoded values in the locale structure.
Because certain configure scripts test for this flag it must be implemented.

Regards,
Juan M. Guerrero






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


	* src/libc/ansi/stdio/doprnt.c: New function __grouping_format.  Formats
	the integer portion of the result of a decimal conversion (%i, %d, %u, %f,
	%F, %g and %G) using the non-monetary thousends' grouping character.

	* src/libc/ansi/stdio/printf.c: Info about grouping flag added.

	* src/docs/kb/wc204.txi: Info about implemetation of grouping flag for
	_doprnt added.





diff -aprNU3 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi	2008-04-11 18:50:30 +0000
+++ djgpp/src/docs/kb/wc204.txi	2008-04-23 20:09:36 +0000
@@ -1118,3 +1118,8 @@ The functions @code{strtod}, @code{strto
 @code{_strtold} now understand hex floating point strings like
 @code{[+|-]0xH.HHHp[+|-]DDD} and any variations of case in the
 input string.
+
+@findex _doprnt AT r{, and C99 conversion flags}
+@findex printf AT r{, and C99 conversion flags}
+The @code{'} conversion flag is 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-23 16:37:36 +0000
+++ djgpp/src/libc/ansi/stdio/doprnt.c	2008-04-23 20:10:16 +0000
@@ -12,14 +12,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
@@ -41,8 +44,11 @@ static char decimal = '.';
 		flags&CHARINT ? (char basetype)va_arg(argp, int) : \
 		(basetype)va_arg(argp, int)
 
-#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_FINITE(x)  (((x).ldt.exponent < 0x7FFFU && (x).ldt.exponent > 0x0000U && (x).ldt.mantissah & 0x80000000UL)  \
+                       || ((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))
 
 
 static __inline__ int todigit(char c)
@@ -60,14 +66,17 @@ 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		0x0001		/* long integer */
+#define	LONGDBL		0x0002		/* long double */
+#define	SHORTINT	0x0004		/* short integer */
+#define	CHARINT		0x0008		/* char */
+#define	FLOAT		0x0010		/* %f, %F, %g or %G decimal conversions */
+#define	FINITENUMBER	0x0020		/* not set if NAN, INF or Unnormal */
+#define	ALT		0x0040		/* alternate form */
+#define	LADJUST		0x0080		/* left adjustment */
+#define	ZEROPAD		0x0100		/* zero (as opposed to blank) pad */
+#define	HEXPREFIX	0x0200		/* add 0x or 0X prefix */
+#define	GROUPING	0x0400		/* non monetary thousands grouping */
 
 static int cvtl(long double number, int prec, int flags, char *signp,
 	        unsigned char fmtch, char *startp, char *endp);
@@ -77,10 +86,12 @@ static char *exponentl(char *p, int expv
 #ifdef __GO32__
 static int isspeciall(long double d, char *bufp);
 #endif
+static __inline__ char * __grouping_format(char *string_start, char *string_end, char *buffer_end, int flags);
 
 static char NULL_REP[] = "(null)";
 static char UNNORMAL_REP[] = "Unnormal";
 
+
 int
 _doprnt(const char *fmt0, va_list argp, FILE *fp)
 {
@@ -106,13 +117,15 @@ _doprnt(const char *fmt0, va_list argp, 
   const char *digs;		/* digits for [diouxX] conversion */
   char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
   int neg_ldouble = 0;		/* non-zero if _ldouble is negative */
+  struct lconv *locale_info;    /* current locale information */
 
-  decimal = localeconv()->decimal_point[0];
+  locale_info = localeconv();
+  decimal_point = locale_info->decimal_point[0];
 
   if (fp->_flag & _IORW)
   {
     fp->_flag |= _IOWRT;
-    fp->_flag &= ~(_IOEOF|_IOREAD);
+    fp->_flag &= ~(_IOEOF | _IOREAD);
   }
   if ((fp->_flag & _IOWRT) == 0)
     return (EOF);
@@ -121,6 +134,8 @@ _doprnt(const char *fmt0, va_list argp, 
   digs = "0123456789abcdef";
   for (cnt = 0;; ++fmt)
   {
+    _longdouble_union_t ieee_value;
+
     while ((ch = *fmt) && ch != '%')
     {
       PUTC (ch);
@@ -129,12 +144,22 @@ _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 a NO OP.
+       */
+      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
@@ -197,7 +222,7 @@ _doprnt(const char *fmt0, va_list argp, 
       flags |= LONGDBL;
       goto rflag;
     case 'h':
-      if (flags&SHORTINT) {
+      if (flags & SHORTINT) {
 	/* C99 */
 	/* for 'hh' - char */
 	flags |= CHARINT;
@@ -207,7 +232,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;
@@ -238,37 +263,37 @@ _doprnt(const char *fmt0, va_list argp, 
 	sign = '-';
       }
       base = 10;
+      flags |= FINITENUMBER;
       goto number;
     case 'e':
     case 'E':
     case 'f':
     case 'g':
     case 'G':
+      flags |= FLOAT;
       if (flags & LONGDBL)
 	_ldouble = va_arg(argp, long double);
       else
 	_ldouble = (long double)va_arg(argp, double);
-      if (flags & ZEROPAD)
-      {
-        _longdouble_union_t ip;
-
-        ip.ld = _ldouble;
-        if (ip.ldt.exponent == 0x7fff)
-          flags &= ~ZEROPAD;
-      }
+      ieee_value.ld = _ldouble;
+      if (IS_FINITE(ieee_value))
+        flags |= FINITENUMBER;
+      else if (flags & ZEROPAD)
+        /*  Do not pad with zeros if infinty or NAN.  */
+        flags &= ~ZEROPAD;
       /*
        * 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
 	  prec = DEFPREC;
@@ -302,7 +327,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,
@@ -316,6 +341,7 @@ _doprnt(const char *fmt0, va_list argp, 
       if (softsign || (sign == '+' && neg_ldouble))
 	sign = '-';
       t = *buf ? buf : buf + 1;
+      base = 10;
       goto pforw;
     case 'n':
       if (flags & LONGDBL)
@@ -335,6 +361,7 @@ _doprnt(const char *fmt0, va_list argp, 
     case 'o':
       ARG(unsigned);
       base = 8;
+      flags |= FINITENUMBER;
       goto nosign;
     case 'p':
       /*
@@ -379,6 +406,7 @@ _doprnt(const char *fmt0, va_list argp, 
     case 'u':
       ARG(unsigned);
       base = 10;
+      flags |= FINITENUMBER;
       goto nosign;
     case 'X':
       digs = "0123456789ABCDEF";
@@ -386,8 +414,9 @@ _doprnt(const char *fmt0, va_list argp, 
     case 'x':
       ARG(unsigned);
       base = 16;
+      flags |= FINITENUMBER;
       /* leading 0x/X only if non-zero */
-      if (flags & ALT && _ulonglong != 0)
+      if ((flags & ALT) && _ulonglong != 0)
 	flags |= HEXPREFIX;
 
     nosign:
@@ -412,21 +441,21 @@ _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 ; */
+           with long long are much slower */
+#define CONVERT(type)                            \
+        do {                                     \
+           register type _n = (type)_ulonglong;  \
+           do {                                  \
+             *--t = digs[_n % base];             \
+             _n /= base;                         \
+           } while (_n);                         \
+        } while (0)
+	if (flags & LONGDBL)
+	  CONVERT(unsigned long long);
 	else
-	  CONVERT(unsigned long) /* no ; */
+	  CONVERT(unsigned long);
 #undef CONVERT
-        if (flags & ALT && base == 8 && *t != '0')
+        if ((flags & ALT) && base == 8 && *t != '0')
           *--t = '0';		/* octal leading 0 */
       }
 
@@ -434,6 +463,16 @@ _doprnt(const char *fmt0, va_list argp, 
       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)
@@ -460,7 +499,7 @@ _doprnt(const char *fmt0, va_list argp, 
 	realsz += 2;
 
       /* right-adjusting blank padding */
-      if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
+      if ((flags & (LADJUST | ZEROPAD)) == 0 && width)
 	for (n = realsz; n < width; n++)
 	  PUTC(' ');
       /* prefix */
@@ -472,7 +511,7 @@ _doprnt(const char *fmt0, va_list argp, 
 	PUTC((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 */
@@ -585,11 +624,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.
@@ -617,8 +657,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)
     {
@@ -639,8 +679,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;
@@ -696,14 +736,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)
@@ -721,10 +761,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;
     }
@@ -773,10 +813,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;
@@ -788,8 +828,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--;
       }
     }
@@ -797,12 +838,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;
     }
   }
@@ -820,7 +861,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')
@@ -837,7 +878,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;
@@ -861,7 +902,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;
@@ -939,3 +980,54 @@ isspeciall(long double d, char *bufp)
     (void)strcpy(bufp, "Inf");
   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 remaindaer 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 remaindaer 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.  */
+}
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-04-23 20:09:36 +0000
@@ -24,6 +24,11 @@ an optional flag, which may alter the co
 
 @table @code
 
+@item '
+
+Formats the integer portion of the result of a decimal conversion (%i, %d, %u,
+%f, %F, %g and %G) using the non-monetary thousends' grouping character.
+
 @item -
 
 left-justify the field.

- Raw text -


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