summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2009-01-19 06:19:38 +0000
committerdas <das@FreeBSD.org>2009-01-19 06:19:38 +0000
commitdf3bc34671810c7f72a3bcd6c81d9a53ff3607da (patch)
tree751115c6a871fd58923fe7ddbce039a23793bae3 /lib
parentca829de63359cda67703edd7be3645ce04a56a31 (diff)
downloadFreeBSD-src-df3bc34671810c7f72a3bcd6c81d9a53ff3607da.zip
FreeBSD-src-df3bc34671810c7f72a3bcd6c81d9a53ff3607da.tar.gz
Add support for multibyte decimal_point encodings, e.g., U+066B.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/stdio/vfprintf.c16
-rw-r--r--lib/libc/stdio/vfwprintf.c42
2 files changed, 35 insertions, 23 deletions
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index d312e7b..19076ab 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -251,6 +251,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
* F: at least two digits for decimal, at least one digit for hex
*/
char *decimal_point; /* locale specific decimal point */
+ int decpt_len; /* length of decimal_point */
int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
@@ -389,6 +390,8 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
#ifndef NO_FLOATING_POINT
dtoaresult = NULL;
decimal_point = localeconv()->decimal_point;
+ /* The overwhelmingly common case is decpt_len == 1. */
+ decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
#endif
/*
@@ -672,7 +675,7 @@ fp_common:
expsize = exponent(expstr, expt - 1, expchar);
size = expsize + prec;
if (prec > 1 || flags & ALT)
- ++size;
+ size += decpt_len;
} else {
/* space for digits before decimal point */
if (expt > 0)
@@ -681,7 +684,7 @@ fp_common:
size = 1;
/* space for decimal pt and following digits */
if (prec || flags & ALT)
- size += prec + 1;
+ size += prec + decpt_len;
if (grouping && expt > 0) {
/* space for thousands' grouping */
nseps = nrepeats = 0;
@@ -920,7 +923,7 @@ number: if ((dprec = prec) >= 0)
if (expt <= 0) {
PRINT(zeroes, 1);
if (prec || flags & ALT)
- PRINT(decimal_point, 1);
+ PRINT(decimal_point,decpt_len);
PAD(-expt, zeroes);
/* already handled initial 0's */
prec += expt;
@@ -945,14 +948,13 @@ number: if ((dprec = prec) >= 0)
cp = dtoaend;
}
if (prec || flags & ALT)
- PRINT(decimal_point,1);
+ PRINT(decimal_point,decpt_len);
}
PRINTANDPAD(cp, dtoaend, prec, zeroes);
} else { /* %[eE] or sufficiently long %[gG] */
if (prec > 1 || flags & ALT) {
- buf[0] = *cp++;
- buf[1] = *decimal_point;
- PRINT(buf, 2);
+ PRINT(cp++, 1);
+ PRINT(decimal_point, decpt_len);
PRINT(cp, ndig-1);
PAD(prec - ndig, zeroes);
} else /* XeYYY */
diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c
index 937134c..28a87f1 100644
--- a/lib/libc/stdio/vfwprintf.c
+++ b/lib/libc/stdio/vfwprintf.c
@@ -74,6 +74,22 @@ static wchar_t *__mbsconv(char *, int);
#define CHAR wchar_t
#include "printfcommon.h"
+static const mbstate_t initial_mbs;
+
+static inline wchar_t
+get_decpt(void)
+{
+ mbstate_t mbs;
+ wchar_t decpt;
+ int nconv;
+
+ mbs = initial_mbs;
+ nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ decpt = '.'; /* failsafe */
+ return (decpt);
+}
+
/*
* Flush out all the vectors defined by the given uio,
* then reset it so that it can be reused.
@@ -147,7 +163,6 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
static wint_t
__xfputwc(wchar_t wc, FILE *fp)
{
- static const mbstate_t initial;
mbstate_t mbs;
char buf[MB_LEN_MAX];
struct __suio uio;
@@ -157,7 +172,7 @@ __xfputwc(wchar_t wc, FILE *fp)
if ((fp->_flags & __SSTR) == 0)
return (__fputwc(wc, fp));
- mbs = initial;
+ mbs = initial_mbs;
if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
@@ -179,7 +194,6 @@ __xfputwc(wchar_t wc, FILE *fp)
static wchar_t *
__mbsconv(char *mbsarg, int prec)
{
- static const mbstate_t initial;
mbstate_t mbs;
wchar_t *convbuf, *wcp;
const char *p;
@@ -199,7 +213,7 @@ __mbsconv(char *mbsarg, int prec)
*/
p = mbsarg;
insize = nchars = 0;
- mbs = initial;
+ mbs = initial_mbs;
while (nchars != (size_t)prec) {
nconv = mbrlen(p, MB_CUR_MAX, &mbs);
if (nconv == 0 || nconv == (size_t)-1 ||
@@ -226,7 +240,7 @@ __mbsconv(char *mbsarg, int prec)
return (NULL);
wcp = convbuf;
p = mbsarg;
- mbs = initial;
+ mbs = initial_mbs;
while (insize != 0) {
nconv = mbrtowc(wcp, p, insize, &mbs);
if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
@@ -305,7 +319,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
* D: expchar holds this character; '\0' if no exponent, e.g. %f
* F: at least two digits for decimal, at least one digit for hex
*/
- char *decimal_point; /* locale specific decimal point */
+ wchar_t decimal_point; /* locale specific decimal point */
int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
@@ -438,7 +452,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
io_init(&io, fp);
ret = 0;
#ifndef NO_FLOATING_POINT
- decimal_point = localeconv()->decimal_point;
+ decimal_point = get_decpt();
#endif
/*
@@ -965,10 +979,8 @@ number: if ((dprec = prec) >= 0)
if (!expchar) { /* %[fF] or sufficiently short %[gG] */
if (expt <= 0) {
PRINT(zeroes, 1);
- if (prec || flags & ALT) {
- buf[0] = *decimal_point;
- PRINT(buf, 1);
- }
+ if (prec || flags & ALT)
+ PRINT(&decimal_point, 1);
PAD(-expt, zeroes);
/* already handled initial 0's */
prec += expt;
@@ -993,16 +1005,14 @@ number: if ((dprec = prec) >= 0)
if (cp > convbuf + ndig)
cp = convbuf + ndig;
}
- if (prec || flags & ALT) {
- buf[0] = *decimal_point;
- PRINT(buf, 1);
- }
+ if (prec || flags & ALT)
+ PRINT(&decimal_point, 1);
}
PRINTANDPAD(cp, convbuf + ndig, prec, zeroes);
} else { /* %[eE] or sufficiently long %[gG] */
if (prec > 1 || flags & ALT) {
buf[0] = *cp++;
- buf[1] = *decimal_point;
+ buf[1] = decimal_point;
PRINT(buf, 2);
PRINT(cp, ndig-1);
PAD(prec - ndig, zeroes);
OpenPOWER on IntegriCloud