svn commit: r187421 - head/lib/libc/stdio

David Schultz das at FreeBSD.org
Sun Jan 18 22:19:39 PST 2009


Author: das
Date: Mon Jan 19 06:19:38 2009
New Revision: 187421
URL: http://svn.freebsd.org/changeset/base/187421

Log:
  Add support for multibyte decimal_point encodings, e.g., U+066B.

Modified:
  head/lib/libc/stdio/vfprintf.c
  head/lib/libc/stdio/vfwprintf.c

Modified: head/lib/libc/stdio/vfprintf.c
==============================================================================
--- head/lib/libc/stdio/vfprintf.c	Mon Jan 19 05:20:52 2009	(r187420)
+++ head/lib/libc/stdio/vfprintf.c	Mon Jan 19 06:19:38 2009	(r187421)
@@ -251,6 +251,7 @@ __vfprintf(FILE *fp, const char *fmt0, v
 	 * 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, v
 #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 */

Modified: head/lib/libc/stdio/vfwprintf.c
==============================================================================
--- head/lib/libc/stdio/vfwprintf.c	Mon Jan 19 05:20:52 2009	(r187420)
+++ head/lib/libc/stdio/vfwprintf.c	Mon Jan 19 06:19:38 2009	(r187421)
@@ -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,
 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 *fmt
 	 * 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 *fmt
 	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);


More information about the svn-src-all mailing list