]>
Commit | Line | Data |
---|---|---|
34e8f829 A |
1 | --- wcstod.c.orig 2008-10-09 11:50:53.000000000 -0700 |
2 | +++ wcstod.c 2008-10-29 00:50:24.000000000 -0700 | |
3 | @@ -27,9 +27,31 @@ | |
3d9156a7 A |
4 | #include <sys/cdefs.h> |
5 | __FBSDID("$FreeBSD: src/lib/libc/locale/wcstod.c,v 1.4 2004/04/07 09:47:56 tjr Exp $"); | |
6 | ||
7 | +#include "xlocale_private.h" | |
8 | + | |
9 | #include <stdlib.h> | |
10 | #include <wchar.h> | |
11 | #include <wctype.h> | |
224c7076 | 12 | +#include <_simple.h> |
34e8f829 A |
13 | + |
14 | +/* | |
15 | + * __wcs_end_offset calculates the offset to the end within the wide character | |
16 | + * string, assuming numbers and letters are single bytes in multibyte | |
17 | + * representation, get the actual decimal string for localeconv_l. If the | |
18 | + * decimal point was within the string, compensate for the fact that the | |
19 | + * (possible more than one byte) decimal point one takes one wide character. | |
20 | + */ | |
21 | +__private_extern__ size_t | |
22 | +__wcs_end_offset(const char * __restrict buf, const char * __restrict end, locale_t loc) | |
23 | +{ | |
24 | + const char *decimalpoint = localeconv_l(loc)->decimal_point; | |
25 | + size_t n = end - buf; | |
26 | + char *p; | |
27 | + | |
28 | + if ((p = strnstr(buf, decimalpoint, n)) != NULL) | |
29 | + n -= strlen(decimalpoint) - 1; | |
30 | + return n; | |
31 | +} | |
224c7076 A |
32 | |
33 | /* | |
34 | * Convert a string to a double-precision number. | |
34e8f829 A |
35 | @@ -38,45 +60,48 @@ __FBSDID("$FreeBSD: src/lib/libc/locale/ |
36 | * have to duplicate the code of strtod() here, we convert the supplied | |
37 | * wide character string to multibyte and call strtod() on the result. | |
38 | * This assumes that the multibyte encoding is compatible with ASCII | |
39 | - * for at least the digits, radix character and letters. | |
40 | + * for at least the digits and letters. The radix character can be more | |
41 | + * than one byte. | |
3d9156a7 | 42 | */ |
34e8f829 | 43 | + |
3d9156a7 A |
44 | double |
45 | -wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) | |
46 | +wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, | |
47 | + locale_t loc) | |
48 | { | |
49 | static const mbstate_t initial; | |
50 | mbstate_t mbs; | |
224c7076 A |
51 | double val; |
52 | char *buf, *end; | |
53 | - const wchar_t *wcp; | |
3d9156a7 | 54 | size_t len; |
224c7076 A |
55 | + locale_t ctype; |
56 | + _SIMPLE_STRING b; | |
57 | + char mb[MB_CUR_MAX + 1]; | |
58 | + const wchar_t *nptr0 = nptr; | |
59 | + const wchar_t *first; | |
34e8f829 | 60 | + |
3d9156a7 | 61 | + NORMALIZE_LOCALE(loc); |
224c7076 | 62 | + ctype = __numeric_ctype(loc); |
34e8f829 A |
63 | |
64 | - while (iswspace(*nptr)) | |
224c7076 | 65 | + while (iswspace_l(*nptr, ctype)) |
3d9156a7 A |
66 | nptr++; |
67 | ||
224c7076 A |
68 | - /* |
69 | - * Convert the supplied numeric wide char. string to multibyte. | |
70 | - * | |
71 | - * We could attempt to find the end of the numeric portion of the | |
72 | - * wide char. string to avoid converting unneeded characters but | |
73 | - * choose not to bother; optimising the uncommon case where | |
74 | - * the input string contains a lot of text after the number | |
75 | - * duplicates a lot of strtod()'s functionality and slows down the | |
76 | - * most common cases. | |
77 | - */ | |
78 | - wcp = nptr; | |
79 | - mbs = initial; | |
3d9156a7 | 80 | - if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) { |
224c7076 A |
81 | - if (endptr != NULL) |
82 | - *endptr = (wchar_t *)nptr; | |
83 | - return (0.0); | |
84 | - } | |
85 | - if ((buf = malloc(len + 1)) == NULL) | |
86 | + if ((b = _simple_salloc()) == NULL) | |
3d9156a7 | 87 | return (0.0); |
224c7076 A |
88 | + |
89 | + first = nptr; | |
3d9156a7 A |
90 | mbs = initial; |
91 | - wcsrtombs(buf, &wcp, len + 1, &mbs); | |
224c7076 A |
92 | + while (*nptr && (len = wcrtomb_l(mb, *nptr, &mbs, ctype)) != (size_t)-1) { |
93 | + mb[len] = 0; | |
94 | + if (_simple_sappend(b, mb) < 0) { /* no memory */ | |
95 | + _simple_sfree(b); | |
96 | + return (0.0); | |
97 | + } | |
98 | + nptr++; | |
99 | + } | |
3d9156a7 A |
100 | |
101 | /* Let strtod() do most of the work for us. */ | |
102 | - val = strtod(buf, &end); | |
224c7076 | 103 | + buf = _simple_string(b); |
3d9156a7 A |
104 | + val = strtod_l(buf, &end, loc); |
105 | ||
106 | /* | |
107 | * We only know where the number ended in the _multibyte_ | |
34e8f829 | 108 | @@ -86,9 +111,15 @@ wcstod(const wchar_t * __restrict nptr, |
224c7076 A |
109 | */ |
110 | if (endptr != NULL) | |
111 | /* XXX Assume each wide char is one byte. */ | |
112 | - *endptr = (wchar_t *)nptr + (end - buf); | |
34e8f829 | 113 | + *endptr = (end == buf) ? (wchar_t *)nptr0 : ((wchar_t *)first + __wcs_end_offset(buf, end, loc)); |
224c7076 A |
114 | |
115 | - free(buf); | |
116 | + _simple_sfree(b); | |
3d9156a7 A |
117 | |
118 | return (val); | |
224c7076 | 119 | } |
3d9156a7 A |
120 | + |
121 | +double | |
122 | +wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) | |
123 | +{ | |
124 | + return wcstod_l(nptr, endptr, __current_locale()); | |
224c7076 | 125 | +} |