From 1c5e84dd0870cd463d97f2b9183a807c3f711f2f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 16 Jun 2009 17:44:20 +0000 Subject: [PATCH] * libc/stdio/vfprintf.c (_VFPRINTF_R): Use actual length of radix char instead of assuming length 1. * libc/stdlib/gdtoa-gethex.c: Remove use of USE_LOCALE. (gethex): Allow multibyte decimal point. Fix compiler warnings due to different signedness of pointer types. * libc/stdlib/strtod.c: Remove use of USE_LOCALE. (_strtod_r): Allow multibyte decimal point. * libc/stdlib/wcstod.c (_wcstod_r): Evaluate correct wide char endptr position if the decimal point is a multibyte char. --- newlib/ChangeLog | 12 ++++++++++++ newlib/libc/stdio/vfprintf.c | 11 ++++++----- newlib/libc/stdlib/gdtoa-gethex.c | 29 ++++++++++++++++------------- newlib/libc/stdlib/strtod.c | 11 +++-------- newlib/libc/stdlib/wcstod.c | 23 +++++++++++++++++++++-- 5 files changed, 58 insertions(+), 28 deletions(-) diff --git a/newlib/ChangeLog b/newlib/ChangeLog index af250d6af..1378cbb76 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,15 @@ +2009-06-16 Corinna Vinschen + + * libc/stdio/vfprintf.c (_VFPRINTF_R): Use actual length of + radix char instead of assuming length 1. + * libc/stdlib/gdtoa-gethex.c: Remove use of USE_LOCALE. + (gethex): Allow multibyte decimal point. + Fix compiler warnings due to different signedness of pointer types. + * libc/stdlib/strtod.c: Remove use of USE_LOCALE. + (_strtod_r): Allow multibyte decimal point. + * libc/stdlib/wcstod.c (_wcstod_r): Evaluate correct wide char + endptr position if the decimal point is a multibyte char. + 2009-06-16 Craig Howland * libc/ctype/local.h (__locale_charset): Add arguments to diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c index 3497bac80..1d3119b4d 100644 --- a/newlib/libc/stdio/vfprintf.c +++ b/newlib/libc/stdio/vfprintf.c @@ -553,6 +553,7 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), char sign; /* sign prefix (' ', '+', '-', or \0) */ #ifdef FLOATING_POINT char *decimal_point = _localeconv_r (data)->decimal_point; + size_t decp_len = strlen (decimal_point); char softsign; /* temporary negative sign for floats */ union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0}; # define _fpvalue (_double_.fp) @@ -1441,13 +1442,13 @@ number: if ((dprec = prec) >= 0) /* kludge for __dtoa irregularity */ PRINT ("0", 1); if (expt < ndig || flags & ALT) { - PRINT (decimal_point, 1); + PRINT (decimal_point, decp_len); PAD (ndig - 1, zeroes); } } else if (expt <= 0) { PRINT ("0", 1); if (expt || ndig || flags & ALT) { - PRINT (decimal_point, 1); + PRINT (decimal_point, decp_len); PAD (-expt, zeroes); PRINT (cp, ndig); } @@ -1455,18 +1456,18 @@ number: if ((dprec = prec) >= 0) PRINT (cp, ndig); PAD (expt - ndig, zeroes); if (flags & ALT) - PRINT (decimal_point, 1); + PRINT (decimal_point, decp_len); } else { PRINT (cp, expt); cp += expt; - PRINT (decimal_point, 1); + PRINT (decimal_point, decp_len); PRINT (cp, ndig - expt); } } else { /* 'a', 'A', 'e', or 'E' */ if (ndig > 1 || flags & ALT) { PRINT (cp, 1); cp++; - PRINT (decimal_point, 1); + PRINT (decimal_point, decp_len); if (_fpvalue) { PRINT (cp, ndig - 1); } else /* 0.[0..] */ diff --git a/newlib/libc/stdlib/gdtoa-gethex.c b/newlib/libc/stdlib/gdtoa-gethex.c index 92f30fca0..c73b11c08 100644 --- a/newlib/libc/stdlib/gdtoa-gethex.c +++ b/newlib/libc/stdlib/gdtoa-gethex.c @@ -35,10 +35,7 @@ THIS SOFTWARE. #include "mprec.h" #include "gdtoa.h" #include "gd_qnan.h" - -#ifdef USE_LOCALE #include "locale.h" -#endif unsigned char hexdig[256]; @@ -151,11 +148,10 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, sign), int esign, havedig, irv, k, n, nbits, up, zret; __ULong L, lostbits, *x; Long e, e1; -#ifdef USE_LOCALE - unsigned char decimalpoint = *localeconv()->decimal_point; -#else -#define decimalpoint '.' -#endif + unsigned char *decimalpoint = (unsigned char *) + _localeconv_r (ptr)->decimal_point; + size_t decp_len = strlen ((const char *) decimalpoint); + unsigned char decp_end = decimalpoint[decp_len - 1]; if (!hexdig['0']) hexdig_init(); @@ -170,9 +166,10 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, sign), e = 0; if (!hexdig[*s]) { zret = 1; - if (*s != decimalpoint) + if (strncmp ((const char *) s, (const char *) decimalpoint, + decp_len) != 0) goto pcheck; - decpt = ++s; + decpt = (s += decp_len); if (!hexdig[*s]) goto pcheck; while(*s == '0') @@ -184,8 +181,10 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, sign), } while(hexdig[*s]) s++; - if (*s == decimalpoint && !decpt) { - decpt = ++s; + if (strncmp ((const char *) s, (const char *) decimalpoint, + decp_len) == 0 + && !decpt) { + decpt = (s += decp_len); while(hexdig[*s]) s++; } @@ -226,8 +225,12 @@ _DEFUN(gethex, (ptr, sp, fpi, exp, bp, sign), n = 0; L = 0; while(s1 > s0) { - if (*--s1 == decimalpoint) + if (*--s1 == decp_end && s1 - decp_len + 1 >= s0 + && strncmp ((const char *) s1 - decp_len + 1, + (const char *) decimalpoint, decp_len) == 0) { + s1 -= decp_len - 1; /* Note the --s1 above! */ continue; + } if (n == 32) { *x++ = L; L = 0; diff --git a/newlib/libc/stdlib/strtod.c b/newlib/libc/stdlib/strtod.c index fb4caf86f..755e6ec3c 100644 --- a/newlib/libc/stdlib/strtod.c +++ b/newlib/libc/stdlib/strtod.c @@ -122,9 +122,7 @@ THIS SOFTWARE. /* #include */ /* #endif */ -#ifdef USE_LOCALE #include "locale.h" -#endif #ifdef IEEE_Arith #ifndef NO_IEEE_Scale @@ -307,14 +305,11 @@ _DEFUN (_strtod_r, (ptr, s00, se), else if (nd < 16) z = 10*z + c - '0'; nd0 = nd; -#ifdef USE_LOCALE - if (c == *localeconv()->decimal_point) -#else - if (c == '.') -#endif + if (strncmp (s, _localeconv_r (ptr)->decimal_point, + strlen (_localeconv_r (ptr)->decimal_point)) == 0) { decpt = 1; - c = *++s; + c = *(s += strlen (_localeconv_r (ptr)->decimal_point)); if (!nd) { for(; c == '0'; c = *++s) nz++; diff --git a/newlib/libc/stdlib/wcstod.c b/newlib/libc/stdlib/wcstod.c index 11fb922b1..6b8be5e73 100644 --- a/newlib/libc/stdlib/wcstod.c +++ b/newlib/libc/stdlib/wcstod.c @@ -116,8 +116,10 @@ Supporting OS subroutines required: <>, <>, <>, #include <_ansi.h> #include #include +#include #include #include +#include #include double @@ -167,9 +169,26 @@ _DEFUN (_wcstod_r, (ptr, nptr, endptr), * where it ended, count multibyte characters to find the * corresponding position in the wide char string. */ - if (endptr != NULL) - /* XXX Assume each wide char is one byte. */ + if (endptr != NULL) { + /* The only valid multibyte char in a float converted by + strtod/wcstod is the radix char. What we do here is, + figure out if the radix char was in the valid leading + float sequence in the incoming string. If so, the + multibyte float string is strlen(radix char) - 1 bytes + longer than the incoming wide char string has characters. + To fix endptr, reposition end as if the radix char was + just one byte long. The resulting difference (end - buf) + is then equivalent to the number of valid wide characters + in the input string. */ + len = strlen (_localeconv_r (ptr)->decimal_point); + if (len > 1) { + char *d = strstr (buf, + _localeconv_r (ptr)->decimal_point); + if (d && d < end) + end -= len - 1; + } *endptr = (wchar_t *)nptr + (end - buf); + } _free_r(ptr, buf);