Respect locale while handling of \' flag.

In original version grouping was hardcoded. It assumed that thousands
separator should be inserted to separate each 3 numbers. I.e. grouping
string "\003" was assumed for all cases. In correct case (per POSIX)
vfprintf should respect locale defined non-monetary (LC_NUMERIC
category) grouping sequence.

Also simplify thousands_sep handling.
This commit is contained in:
Alexey Zelkin 2001-12-13 19:45:41 +00:00
parent dd22788a1d
commit 98ee763522

View File

@ -114,8 +114,8 @@ enum typeid {
static int __sprint __P((FILE *, struct __suio *));
static int __sbprintf __P((FILE *, const char *, va_list)) __printflike(2, 0);
static char * __ujtoa __P((uintmax_t, char *, int, int, char *, const char *));
static char * __ultoa __P((u_long, char *, int, int, char *, const char *));
static char * __ujtoa __P((uintmax_t, char *, int, int, char *, int, char, const char *));
static char * __ultoa __P((u_long, char *, int, int, char *, int, char, const char *));
static void __find_arguments __P((const char *, va_list, union arg **));
static void __grow_type_table __P((int, enum typeid **, int *));
@ -185,7 +185,7 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
*/
static char *
__ultoa(u_long val, char *endp, int base, int octzero, char *xdigs,
const char *thousep)
int needgrp, char thousep, const char *grp)
{
register char *cp = endp;
register long sval;
@ -216,9 +216,20 @@ __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs,
sval = val;
do {
*--cp = to_char(sval % 10);
if (++ndig == 3 && thousep && *thousep != '\0') {
*--cp = *thousep;
ndig++;
/*
* If (*grp == CHAR_MAX) then no more grouping
* should be performed.
*/
if (needgrp && ndig == *grp && *grp != CHAR_MAX) {
*--cp = thousep;
ndig = 0;
/*
* If (*(grp+1) == '\0') then we have to
* use *grp character (last grouping rule)
* for all next cases
*/
if (*(grp+1) != '\0') grp++;
}
sval /= 10;
} while (sval != 0);
@ -249,7 +260,7 @@ __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs,
/* Identical to __ultoa, but for intmax_t. */
static char *
__ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs,
const char *thousep)
int needgrp, char thousep, const char *grp)
{
char *cp = endp;
intmax_t sval;
@ -259,7 +270,7 @@ __ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs,
/* (perhaps instead we should run until small, then call __ultoa?) */
if (val <= ULONG_MAX)
return (__ultoa((u_long)val, endp, base, octzero, xdigs,
thousep));
needgrp, thousep, grp));
switch (base) {
case 10:
if (val < 10) {
@ -275,10 +286,21 @@ __ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs,
sval = val;
do {
*--cp = to_char(sval % 10);
if (++ndig == 3 && thousep && *thousep != '\0') {
*--cp = *thousep;
ndig++;
/*
* If (*grp == CHAR_MAX) then no more grouping
* should be performed.
*/
if (needgrp && *grp != CHAR_MAX && ndig == *grp) {
*--cp = thousep;
ndig = 0;
}
/*
* If (*(grp+1) == '\0') then we have to
* use *grp character (last grouping rule)
* for all next cases
*/
if (*(grp+1) != '\0') grp++;
}
sval /= 10;
} while (sval != 0);
break;
@ -323,7 +345,7 @@ vfprintf(FILE *fp, const char *fmt0, va_list ap)
#include <math.h>
#include "floatio.h"
#define BUF ((MAXEXP*4/3)+MAXFRACT+1) /* + decimal point */
#define BUF ((MAXEXP*2)+MAXFRACT+1) /* + decimal point */
#define DEFPREC 6
static char *cvt __P((double, int, int, char *, int *, int, int *, char **));
@ -331,7 +353,7 @@ static int exponent __P((char *, int, int));
#else /* no FLOATING_POINT */
#define BUF 90
#define BUF 136
#endif /* FLOATING_POINT */
@ -349,11 +371,12 @@ static int exponent __P((char *, int, int));
#define SHORTINT 0x040 /* short integer */
#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
#define FPT 0x100 /* Floating point number */
#define GROUPING 0x200 /* use grouping ("'" flag) */
/* C99 additional size modifiers: */
#define SIZET 0x200 /* size_t */
#define PTRDIFFT 0x400 /* ptrdiff_t */
#define INTMAXT 0x800 /* intmax_t */
#define CHARINT 0x1000 /* print char using int format */
#define SIZET 0x400 /* size_t */
#define PTRDIFFT 0x800 /* ptrdiff_t */
#define INTMAXT 0x1000 /* intmax_t */
#define CHARINT 0x2000 /* print char using int format */
/*
* Non-MT-safe version
@ -371,7 +394,8 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format (%.3d), or -1 */
char sign; /* sign prefix (' ', '+', '-', or \0) */
const char *thousands_sep; /* locale specific thousands separator */
char thousands_sep; /* locale specific thousands separator */
const char *grouping; /* locale specific numeric grouping rules */
#ifdef FLOATING_POINT
char *decimal_point; /* locale specific decimal point */
char softsign; /* temporary negative sign for floats */
@ -500,9 +524,10 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
} else { \
val = GETARG (int); \
}
thousands_sep = NULL;
thousands_sep = '\0';
grouping = NULL;
#ifdef FLOATING_POINT
dtoaresult = NULL;
decimal_point = localeconv()->decimal_point;
@ -582,7 +607,9 @@ reswitch: switch (ch) {
sign = '+';
goto rflag;
case '\'':
thousands_sep = localeconv()->thousands_sep;
flags |= GROUPING;
thousands_sep = *(localeconv()->thousands_sep);
grouping = localeconv()->grouping;
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
@ -686,6 +713,14 @@ reswitch: switch (ch) {
#endif
case 'e':
case 'E':
/*
* Grouping apply to %i, %d, %u, %f, %F, %g, %G
* conversion specifiers only. For other conversions
* behavior is undefined.
* -- POSIX
*/
flags &= ~GROUPING;
/*FALLTHROUGH*/
case 'f':
case 'F':
goto fp_begin;
@ -851,6 +886,8 @@ fp_begin: if (prec == -1)
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
flags |= HEXPREFIX;
flags &= ~GROUPING;
/* unsigned conversions */
nosign: sign = '\0';
/*
@ -870,11 +907,15 @@ number: if ((dprec = prec) >= 0)
if (flags & INTMAX_SIZE) {
if (ujval != 0 || prec != 0)
cp = __ujtoa(ujval, cp, base,
flags & ALT, xdigs, thousands_sep);
flags & ALT, xdigs,
flags & GROUPING, thousands_sep,
grouping);
} else {
if (ulval != 0 || prec != 0)
cp = __ultoa(ulval, cp, base,
flags & ALT, xdigs, thousands_sep);
flags & ALT, xdigs,
flags & GROUPING, thousands_sep,
grouping);
}
size = buf + BUF - cp;
break;