diff options
author | Nick Clifton <nickc@redhat.com> | 2015-01-29 11:37:26 +0300 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2015-01-29 11:37:26 +0300 |
commit | 1f3dd905527d64569f10397f5e1b4d6a97fd5ae6 (patch) | |
tree | 9d995c313b216dd24677820130ae6351b0e42416 /newlib/libc | |
parent | 3e4183d15bbdbf4ae0086f970aedca11d577561b (diff) |
* libc/stdlib/wcstold.c (wcstold): Add implementation for when
long double is not the same as double.
Diffstat (limited to 'newlib/libc')
-rw-r--r-- | newlib/libc/stdlib/wcstold.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/newlib/libc/stdlib/wcstold.c b/newlib/libc/stdlib/wcstold.c index 0ed0e5a5f..44729aeb1 100644 --- a/newlib/libc/stdlib/wcstold.c +++ b/newlib/libc/stdlib/wcstold.c @@ -29,14 +29,82 @@ POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> +#include <locale.h> #include "local.h" -/* On platforms where long double is as wide as double. */ -#ifdef _LDBL_EQ_DBL +extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); + long double wcstold (const wchar_t *__restrict nptr, wchar_t **__restrict endptr) { +#ifdef _LDBL_EQ_DBL +/* On platforms where long double is as wide as double. */ return wcstod(nptr, endptr); -} -#endif /* _LDBL_EQ_DBL */ +#else /* This is a duplicate of the code in wcstod.c, but converted to long double. */ + + static const mbstate_t initial; + mbstate_t mbs; + long double val; + char *buf, *end; + const wchar_t *wcp; + size_t len; + + while (iswspace (*nptr)) + nptr++; + + /* Convert the supplied numeric wide char string to multibyte. */ + wcp = nptr; + mbs = initial; + if ((len = wcsrtombs (NULL, &wcp, 0, &mbs)) == (size_t)-1) + { + if (endptr != NULL) + *endptr = (wchar_t *) nptr; + return 0.0L; + } + + if ((buf = malloc (len + 1)) == NULL) + return 0.0L; + + mbs = initial; + wcsrtombs (buf, &wcp, len + 1, &mbs); + + val = strtold (buf, &end); + + /* We only know where the number ended in the _multibyte_ + representation of the string. If the caller wants to know + where it ended, count multibyte characters to find the + corresponding position in the wide char string. */ + + if (endptr != NULL) + { + /* The only valid multibyte char in a float converted by + strtold/wcstold 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 ()->decimal_point); + if (len > 1) + { + char *d = strstr (buf, localeconv ()->decimal_point); + + if (d && d < end) + end -= len - 1; + } + + *endptr = (wchar_t *) nptr + (end - buf); + } + + free (buf); + + return val; +#endif /* _LDBL_EQ_DBL */ +} |