[PATCH] printf: Enable grouping decimal values

Jeff Johnston jjohnstn@redhat.com
Thu Feb 4 18:30:00 GMT 2010


On 01/02/10 03:47 PM, Corinna Vinschen wrote:
> Hi,
>
> the below patch is derived from NetBSD code.  It enables printf/wprintf
> grouping using the thousands' grouping character from the locale
> information when the ' (single quote) flag character has been specified
> in decimal conversions (i, d, u, f, F, g, G), as specified by POSIX-1.2008.
>
> The grouping flag character was originally guarded by the
> _WANT_IO_C99_FORMATS macro, so I left that intact.  The entire grouping
> code is still only available with _WANT_IO_C99_FORMATS set.
>
> A new macro has been introduced from the NetBSD code, called PRINTANDPAD.
> It allowed to simplify printing of float values and taking over the
> NetBSD code almost unchanged.  The most important change was to allow
> thousands_sep to be a multibyte character in _VFPRINTF_R.  NetBSD erroneously
> assumes that thousands_sep is a singlebyte char.
>
> Tested on Cygwin using different locales using different decimal points,
> thousands separators (including multibyte), and different groupings.
>
> Ok to apply?
>

This is a tough patch to review because of all the format changes and 
ifdefs in the patch itself.

I did notice one spot where the size is being calculated and the 
grouping ptr is moved to do this calculation.  I can't see anywhere 
where you are resetting grouping before the output is written.  This 
seems like a mistake, but perhaps I am missing something.

-- Jeff J.

> Thanks,
> Corinna
>
>
> 	* libc/stdio/vfprintf.c: Include locale.h also if _WANT_IO_C99_FORMATS
> 	is defined.  Raise conversion buffer size to make sure it has enough
> 	room for numbers plus grouping character.  Define GROUPING flag.
> 	(_VFPRINTF_R): Add PRINTANDPAD macro.  Handle grouping flag character.
> 	Handle grouping for decimal integer and float values.
> 	* libc/stdio/vfwprintf.c: Ditto.
>
>
> Index: libc/stdio/vfprintf.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/vfprintf.c,v
> retrieving revision 1.77
> diff -u -p -r1.77 vfprintf.c
> --- libc/stdio/vfprintf.c	14 Jan 2010 12:48:58 -0000	1.77
> +++ libc/stdio/vfprintf.c	1 Feb 2010 20:40:44 -0000
> @@ -375,8 +375,10 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
>   #endif /* !STRING_ONLY */
>
>
> -#ifdef FLOATING_POINT
> +#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
>   # include<locale.h>
> +#endif
> +#ifdef FLOATING_POINT
>   # include<math.h>
>
>   /* For %La, an exponent of 15 bits occupies the exponent character, a
> @@ -423,8 +425,16 @@ static int exponent(char *, int, int);
>      reentrant storage shared with mprec.  All other formats that use
>      buf get by with fewer characters.  Making BUF slightly bigger
>      reduces the need for malloc in %.*a and %S, when large precision or
> -   long strings are processed.  */
> +   long strings are processed.
> +   The bigger size of 100 bytes is used on systems which allow number
> +   strings using the locale's grouping character.  Since that's a multibyte
> +   value, we should use a conservative value.
> +   */
> +#ifdef _WANT_IO_C99_FORMATS
> +#define	BUF		100
> +#else
>   #define	BUF		40
> +#endif
>   #if defined _MB_CAPABLE&&  MB_LEN_MAX>  BUF
>   # undef BUF
>   # define BUF MB_LEN_MAX
> @@ -508,6 +518,9 @@ _EXFUN(get_arg, (struct _reent *data, in
>   #else /* define as 0, to make SARG and UARG occupy fewer instructions  */
>   # define CHARINT	0
>   #endif
> +#ifdef _WANT_IO_C99_FORMATS
> +# define GROUPING	0x400		/* use grouping ("'" flag) */
> +#endif
>
>   int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
>
> @@ -552,6 +565,12 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
>   	int width;		/* width from format (%8d), or 0 */
>   	int prec;		/* precision from format (%.3d), or -1 */
>   	char sign;		/* sign prefix (' ', '+', '-', or \0) */
> +#ifdef _WANT_IO_C99_FORMATS
> +				/* locale specific numeric grouping */
> +	char *thousands_sep;
> +	size_t thsnd_len;
> +	const char *grouping;
> +#endif
>   #ifdef FLOATING_POINT
>   	char *decimal_point = _localeconv_r (data)->decimal_point;
>   	size_t decp_len = strlen (decimal_point);
> @@ -560,9 +579,16 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
>   # define _fpvalue (_double_.fp)
>   	int expt;		/* integer value of exponent */
>   	int expsize = 0;	/* character count for expstr */
> -	int ndig = 0;		/* actual number of digits returned by cvt */
>   	char expstr[MAXEXPLEN];	/* buffer for exponent string */
> +	int lead;		/* sig figs before decimal or group sep */
>   #endif /* FLOATING_POINT */
> +#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
> +	int ndig = 0;		/* actual number of digits returned by cvt */
> +#endif
> +#ifdef _WANT_IO_C99_FORMATS
> +	int nseps;		/* number of group separators with ' */
> +	int nrepeats;		/* number of repeats of the last group */
> +#endif
>   	u_quad_t _uquad;	/* integer arguments %[diouxX] */
>   	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
>   	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
> @@ -617,6 +643,14 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
>   		PRINT (with, n); \
>   	} \
>   }
> +#define PRINTANDPAD(p, ep, len, with) { \
> +	int n = (ep) - (p); \
> +	if (n>  (len)) \
> +		n = (len); \
> +	if (n>  0) \
> +		PRINT((p), n); \
> +	PAD((len) - (n>  0 ? n : 0), (with)); \
> +}
>   #define	FLUSH() { \
>   	if (uio.uio_resid&&  __SPRINT(data, fp,&uio)) \
>   		goto error; \
> @@ -757,6 +791,12 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
>   		width = 0;
>   		prec = -1;
>   		sign = '\0';
> +#ifdef FLOATING_POINT
> +		lead = 0;
> +#endif
> +#ifdef _WANT_IO_C99_FORMATS
> +		nseps = nrepeats = 0;
> +#endif
>   #ifndef _NO_POS_ARGS
>   		N = arg_index;
>   		is_pos_arg = 0;
> @@ -766,12 +806,12 @@ rflag:		ch = *fmt++;
>   reswitch:	switch (ch) {
>   #ifdef _WANT_IO_C99_FORMATS
>   		case '\'':
> -		  /* The ' flag is required by POSIX, but not C99.
> -		     In the C locale, LC_NUMERIC requires
> -		     thousands_sep to be the empty string.  And since
> -		     no other locales are supported (yet), this flag
> -		     is currently a no-op.  */
> -		  goto rflag;
> +			thousands_sep = _localeconv_r (data)->thousands_sep;
> +			thsnd_len = strlen (thousands_sep);
> +			grouping = _localeconv_r (data)->grouping;
> +			if (thsnd_len>  0&&  grouping&&  *grouping)
> +			  flags |= GROUPING;
> +			goto rflag;
>   #endif
>   		case ' ':
>   			/*
> @@ -1140,22 +1180,46 @@ reswitch:	switch (ch) {
>   				size = expsize + ndig;
>   				if (ndig>  1 || flags&  ALT)
>   					++size;
> -			} else if (ch == 'f') {		/* f fmt */
> -				if (expt>  0) {
> +# ifdef _WANT_IO_C99_FORMATS
> +				flags&= ~GROUPING;
> +# endif
> +			} else {
> +				if (ch == 'f') {		/* f fmt */
> +					if (expt>  0) {
> +						size = expt;
> +						if (prec || flags&  ALT)
> +							size += prec + 1;
> +					} else	/* "0.X" */
> +						size = (prec || flags&  ALT)
> +							  ? prec + 2
> +							  : 1;
> +				} else if (expt>= ndig) { /* fixed g fmt */
>   					size = expt;
> -					if (prec || flags&  ALT)
> -						size += prec + 1;
> -				} else	/* "0.X" */
> -					size = (prec || flags&  ALT)
> -						  ? prec + 2
> -						  : 1;
> -			} else if (expt>= ndig) {	/* fixed g fmt */
> -				size = expt;
> -				if (flags&  ALT)
> -					++size;
> -			} else
> -				size = ndig + (expt>  0 ?
> -					1 : 2 - expt);
> +					if (flags&  ALT)
> +						++size;
> +				} else
> +					size = ndig + (expt>  0 ?
> +						1 : 2 - expt);
> +# ifdef _WANT_IO_C99_FORMATS
> +				if ((flags&  GROUPING)&&  expt>  0) {
> +					/* space for thousands' grouping */
> +					nseps = nrepeats = 0;
> +					lead = expt;
> +					while (*grouping != CHAR_MAX) {
> +						if (lead<= *grouping)
> +							break;
> +						lead -= *grouping;
> +						if (grouping[1]) {
> +							nseps++;
> +							grouping++;

********** here you are altering "grouping", but only size is being 
calculated.  ************************
> +						} else
> +							nrepeats++;
> +					}
> +					size += (nseps + nrepeats) * thsnd_len;
> +				} else
> +# endif
> +					lead = expt;
> +			}
>
>   			if (softsign)
>   				sign = '-';
> @@ -1184,6 +1248,9 @@ reswitch:	switch (ch) {
>   		case 'o':
>   			_uquad = UARG ();
>   			base = OCT;
> +#ifdef _WANT_IO_C99_FORMATS
> +			flags&= ~GROUPING;
> +#endif
>   			goto nosign;
>   		case 'p':
>   			/*
> @@ -1320,6 +1387,9 @@ hex:			_uquad = UARG ();
>   				flags |= HEXPREFIX;
>   			}
>
> +#ifdef _WANT_IO_C99_FORMATS
> +			flags&= ~GROUPING;
> +#endif
>   			/* unsigned conversions */
>   nosign:			sign = '\0';
>   			/*
> @@ -1355,11 +1425,37 @@ number:			if ((dprec = prec)>= 0)
>
>   				case DEC:
>   					/* many numbers are 1 digit */
> -					while (_uquad>= 10) {
> -						*--cp = to_char (_uquad % 10);
> -						_uquad /= 10;
> +					if (_uquad<  10) {
> +						*--cp = to_char(_uquad);
> +						break;
>   					}
> -					*--cp = to_char (_uquad);
> +#ifdef _WANT_IO_C99_FORMATS
> +					ndig = 0;
> +#endif
> +					do {
> +					  *--cp = to_char (_uquad % 10);
> +#ifdef _WANT_IO_C99_FORMATS
> +					  ndig++;
> +					  /* If (*grouping == CHAR_MAX) then no
> +					     more grouping */
> +					  if ((flags&  GROUPING)
> +					&&  ndig == *grouping
> +					&&  *grouping != CHAR_MAX
> +					&&  _uquad>  9) {
> +					    cp -= thsnd_len;
> +					    strncpy (cp, thousands_sep,
> +						     thsnd_len);
> +					    ndig = 0;
> +					    /* If (grouping[1] == '\0') then we
> +					       have to use *grouping character
> +					       (last grouping rule) for all
> +					       next cases. */
> +					    if (grouping[1] != '\0')
> +					      grouping++;
> +					  }
> +#endif
> +					  _uquad /= 10;
> +					} while (_uquad != 0);
>   					break;
>
>   				case HEX:
> @@ -1459,16 +1555,33 @@ number:			if ((dprec = prec)>= 0)
>   						PAD (-expt, zeroes);
>   						PRINT (cp, ndig);
>   					}
> -				} else if (expt>= ndig) {
> -					PRINT (cp, ndig);
> -					PAD (expt - ndig, zeroes);
> -					if (flags&  ALT)
> -						PRINT (decimal_point, decp_len);
>   				} else {
> -					PRINT (cp, expt);
> -					cp += expt;
> -					PRINT (decimal_point, decp_len);
> -					PRINT (cp, ndig - expt);
> +					char *convbuf = cp;
> +					PRINTANDPAD(cp, convbuf + ndig,
> +						    lead, zeroes);
> +					cp += lead;
> +#ifdef _WANT_IO_C99_FORMATS
> +					if (flags&  GROUPING) {
> +					    while (nseps>  0 || nrepeats>  0) {
> +						if (nrepeats>  0)
> +						    nrepeats--;
> +						else {
> +						    grouping--;
> +						    nseps--;
> +						}
> +						PRINT(thousands_sep, thsnd_len);
> +						PRINTANDPAD (cp, convbuf + ndig,
> +							     *grouping, zeroes);
> +						cp += *grouping;
> +					    }
> +					    if (cp>  convbuf + ndig)
> +						cp = convbuf + ndig;
> +					}
> +#endif
> +					if (prec || flags&  ALT)
> +					    PRINT (decimal_point, decp_len);
> +					PRINTANDPAD (cp, convbuf + ndig,
> +						     ndig - expt, zeroes);
>   				}
>   			} else {	/* 'a', 'A', 'e', or 'E' */
>   				if (ndig>  1 || flags&  ALT) {
> Index: libc/stdio/vfwprintf.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/vfwprintf.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 vfwprintf.c
> --- libc/stdio/vfwprintf.c	12 Mar 2009 10:27:10 -0000	1.2
> +++ libc/stdio/vfwprintf.c	1 Feb 2010 20:40:44 -0000
> @@ -201,8 +201,10 @@ _DEFUN(__sbwprintf, (rptr, fp, fmt, ap),
>   #endif /* !STRING_ONLY */
>
>
> -#ifdef FLOATING_POINT
> +#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
>   # include<locale.h>
> +#endif
> +#ifdef FLOATING_POINT
>   # include<math.h>
>
>   /* For %La, an exponent of 15 bits occupies the exponent character, a
> @@ -249,8 +251,16 @@ static int wexponent(wchar_t *, int, int
>      reentrant storage shared with mprec.  All other formats that use
>      buf get by with fewer characters.  Making BUF slightly bigger
>      reduces the need for malloc in %.*a and %ls/%S, when large precision or
> -   long strings are processed.  */
> +   long strings are processed.
> +   The bigger size of 100 bytes is used on systems which allow number
> +   strings using the locale's grouping character.  Since that's a multibyte
> +   value, we should use a conservative value.
> +   */
> +#ifdef _WANT_IO_C99_FORMATS
> +#define BUF             100
> +#else
>   #define	BUF		40
> +#endif
>   #if defined _MB_CAPABLE&&  MB_LEN_MAX>  BUF
>   # undef BUF
>   # define BUF MB_LEN_MAX
> @@ -336,6 +346,9 @@ _EXFUN(get_arg, (struct _reent *data, in
>   #else /* define as 0, to make SARG and UARG occupy fewer instructions  */
>   # define CHARINT	0
>   #endif
> +#ifdef _WANT_IO_C99_FORMATS
> +# define GROUPING	0x400		/* use grouping ("'" flag) */
> +#endif
>
>   #ifndef STRING_ONLY
>   int
> @@ -378,19 +391,31 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap
>   	int width;		/* width from format (%8d), or 0 */
>   	int prec;		/* precision from format (%.3d), or -1 */
>   	wchar_t sign;		/* sign prefix (' ', '+', '-', or \0) */
> -#ifdef FLOATING_POINT
> -	wchar_t decimal_point;
> +#ifdef _WANT_IO_C99_FORMATS
> +				/* locale specific numeric grouping */
> +	wchar_t thousands_sep;
> +	const char *grouping;
> +#endif
>   #ifdef _MB_CAPABLE
>   	mbstate_t state;        /* mbtowc calls from library must not change state */
>   #endif
> +#ifdef FLOATING_POINT
> +	wchar_t decimal_point;
>   	wchar_t softsign;		/* temporary negative sign for floats */
>   	union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
>   # define _fpvalue (_double_.fp)
>   	int expt;		/* integer value of exponent */
>   	int expsize = 0;	/* character count for expstr */
> -	int ndig = 0;		/* actual number of digits returned by wcvt */
>   	wchar_t expstr[MAXEXPLEN];	/* buffer for exponent string */
> +	int lead;		/* sig figs before decimal or group sep */
>   #endif /* FLOATING_POINT */
> +#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
> +	int ndig = 0;		/* actual number of digits returned by cvt */
> +#endif
> +#ifdef _WANT_IO_C99_FORMATS
> +	int nseps;		/* number of group separators with ' */
> +	int nrepeats;		/* number of repeats of the last group */
> +#endif
>   	u_quad_t _uquad;	/* integer arguments %[diouxX] */
>   	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
>   	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
> @@ -419,9 +444,16 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap
>
>   #ifdef FLOATING_POINT
>   #ifdef _MB_CAPABLE
> -	memset (&state, '\0', sizeof (state));
> -	_mbrtowc_r (data,&decimal_point, _localeconv_r (data)->decimal_point,
> -		    MB_CUR_MAX,&state);
> +	{
> +	  size_t nconv;
> +
> +	  memset (&state, '\0', sizeof (state));
> +	  nconv = _mbrtowc_r (data,&decimal_point,
> +			      _localeconv_r (data)->decimal_point,
> +			      MB_CUR_MAX,&state);
> +	  if (nconv == (size_t) -1 || nconv == (size_t) -2)
> +	    decimal_point = L'.';
> +	}
>   #else
>   	decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point;
>   #endif
> @@ -449,6 +481,14 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap
>   		PRINT (with, n); \
>   	} \
>   }
> +#define PRINTANDPAD(p, ep, len, with) { \
> +	int n = (ep) - (p); \
> +	if (n>  (len)) \
> +		n = (len); \
> +	if (n>  0) \
> +		PRINT((p), n); \
> +	PAD((len) - (n>  0 ? n : 0), (with)); \
> +}
>   #define	FLUSH() { \
>   	if (uio.uio_resid&&  __SPRINT(data, fp,&uio)) \
>   		goto error; \
> @@ -570,6 +610,12 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap
>   		width = 0;
>   		prec = -1;
>   		sign = L'\0';
> +#ifdef FLOATING_POINT
> +		lead = 0;
> +#endif
> +#ifdef _WANT_IO_C99_FORMATS
> +		nseps = nrepeats = 0;
> +#endif
>   #ifndef _NO_POS_ARGS
>   		N = arg_index;
>   		is_pos_arg = 0;
> @@ -579,8 +625,23 @@ rflag:		ch = *fmt++;
>   reswitch:	switch (ch) {
>   #ifdef _WANT_IO_C99_FORMATS
>   		case L'\'':
> -		  /* The ' flag is required by POSIX, but not C99.
> -		     FIXME:  this flag is currently a no-op.  */
> +#ifdef _MB_CAPABLE
> +		  {
> +		    size_t nconv;
> +
> +		    memset (&state, '\0', sizeof (state));
> +		    nconv = _mbrtowc_r (data,&thousands_sep,
> +					_localeconv_r (data)->thousands_sep,
> +					MB_CUR_MAX,&state);
> +		    if (nconv == (size_t) -1 || nconv == (size_t) -2)
> +		      thousands_sep = L'\0';
> +		  }
> +#else
> +		  thousands_sep = (wchar_t) *_localeconv_r(data)->thousands_sep;
> +#endif
> +		  grouping = _localeconv_r (data)->grouping;
> +		  if (thousands_sep&&  grouping&&  *grouping)
> +		    flags |= GROUPING;
>   		  goto rflag;
>   #endif
>   		case L' ':
> @@ -942,23 +1003,46 @@ reswitch:	switch (ch) {
>   				size = expsize + ndig;
>   				if (ndig>  1 || flags&  ALT)
>   					++size;
> -			} else if (ch == L'f') {		/* f fmt */
> -				if (expt>  0) {
> +# ifdef _WANT_IO_C99_FORMATS
> +				flags&= ~GROUPING;
> +# endif
> +			} else {
> +				if (ch == L'f') {		/* f fmt */
> +					if (expt>  0) {
> +						size = expt;
> +						if (prec || flags&  ALT)
> +							size += prec + 1;
> +					} else	/* "0.X" */
> +						size = (prec || flags&  ALT)
> +							  ? prec + 2
> +							  : 1;
> +				} else if (expt>= ndig) { /* fixed g fmt */
>   					size = expt;
> -					if (prec || flags&  ALT)
> -						size += prec + 1;
> -				} else	/* "0.X" */
> -					size = (prec || flags&  ALT)
> -						  ? prec + 2
> -						  : 1;
> -			} else if (expt>= ndig) {	/* fixed g fmt */
> -				size = expt;
> -				if (flags&  ALT)
> -					++size;
> -			} else
> -				size = ndig + (expt>  0 ?
> -					1 : 2 - expt);
> -
> +					if (flags&  ALT)
> +						++size;
> +				} else
> +					size = ndig + (expt>  0 ?
> +						1 : 2 - expt);
> +# ifdef _WANT_IO_C99_FORMATS
> +				if ((flags&  GROUPING)&&  expt>  0) {
> +					/* space for thousands' grouping */
> +					nseps = nrepeats = 0;
> +					lead = expt;
> +					while (*grouping != CHAR_MAX) {
> +						if (lead<= *grouping)
> +							break;
> +						lead -= *grouping;
> +						if (grouping[1]) {
> +							nseps++;
> +							grouping++;
> +						} else
> +							nrepeats++;
> +					}
> +					size += nseps + nrepeats;
> +				} else
> +# endif
> +				lead = expt;
> +			}
>   			if (softsign)
>   				sign = L'-';
>   			break;
> @@ -983,6 +1067,9 @@ reswitch:	switch (ch) {
>   		case L'o':
>   			_uquad = UARG ();
>   			base = OCT;
> +#ifdef _WANT_IO_C99_FORMATS
> +			flags&= ~GROUPING;
> +#endif
>   			goto nosign;
>   		case L'p':
>   			/*
> @@ -1106,6 +1193,9 @@ hex:			_uquad = UARG ();
>   				flags |= HEXPREFIX;
>   			}
>
> +#ifdef _WANT_IO_C99_FORMATS
> +			flags&= ~GROUPING;
> +#endif
>   			/* unsigned conversions */
>   nosign:			sign = L'\0';
>   			/*
> @@ -1141,11 +1231,35 @@ number:			if ((dprec = prec)>= 0)
>
>   				case DEC:
>   					/* many numbers are 1 digit */
> -					while (_uquad>= 10) {
> -						*--cp = to_char (_uquad % 10);
> -						_uquad /= 10;
> +					if (_uquad<  10) {
> +						*--cp = to_char(_uquad);
> +						break;
>   					}
> -					*--cp = to_char (_uquad);
> +#ifdef _WANT_IO_C99_FORMATS
> +					ndig = 0;
> +#endif
> +					do {
> +					  *--cp = to_char (_uquad % 10);
> +#ifdef _WANT_IO_C99_FORMATS
> +					  ndig++;
> +					  /* If (*grouping == CHAR_MAX) then no
> +					     more grouping */
> +					  if ((flags&  GROUPING)
> +					&&  ndig == *grouping
> +					&&  *grouping != CHAR_MAX
> +					&&  _uquad>  9) {
> +					    *--cp = thousands_sep;
> +					    ndig = 0;
> +					    /* If (grouping[1] == '\0') then we
> +					       have to use *grouping character
> +					       (last grouping rule) for all
> +					       next cases. */
> +					    if (grouping[1] != '\0')
> +					      grouping++;
> +					  }
> +#endif
> +					  _uquad /= 10;
> +					} while (_uquad != 0);
>   					break;
>
>   				case HEX:
> @@ -1245,17 +1359,35 @@ number:			if ((dprec = prec)>= 0)
>   						PAD (-expt, zeroes);
>   						PRINT (cp, ndig);
>   					}
> -				} else if (expt>= ndig) {
> -					PRINT (cp, ndig);
> -					PAD (expt - ndig, zeroes);
> -					if (flags&  ALT)
> -						PRINT (&decimal_point, 1);
>   				} else {
> -					PRINT (cp, expt);
> -					cp += expt;
> -					PRINT (&decimal_point, 1);
> -					PRINT (cp, ndig - expt);
> +					wchar_t *convbuf = cp;
> +					PRINTANDPAD(cp, convbuf + ndig,
> +						    lead, zeroes);
> +					cp += lead;
> +#ifdef _WANT_IO_C99_FORMATS
> +					if (flags&  GROUPING) {
> +					    while (nseps>  0 || nrepeats>  0) {
> +						if (nrepeats>  0)
> +						    nrepeats--;
> +						else {
> +						    grouping--;
> +						    nseps--;
> +						}
> +						PRINT (&thousands_sep, 1);
> +						PRINTANDPAD (cp, convbuf + ndig,
> +							     *grouping, zeroes);
> +						cp += *grouping;
> +					    }
> +					    if (cp>  convbuf + ndig)
> +						cp = convbuf + ndig;
> +					}
> +#endif
> +					if (prec || flags&  ALT)
> +					    PRINT (&decimal_point, 1);
> +					PRINTANDPAD (cp, convbuf + ndig,
> +						     ndig - expt, zeroes);
>   				}
> +
>   			} else {	/* 'a', 'A', 'e', or 'E' */
>   				if (ndig>  1 || flags&  ALT) {
>   					PRINT (cp, 1);
>
>



More information about the Newlib mailing list