Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-01-29 11:37:26 +0300
committerNick Clifton <nickc@redhat.com>2015-01-29 11:37:26 +0300
commit1f3dd905527d64569f10397f5e1b4d6a97fd5ae6 (patch)
tree9d995c313b216dd24677820130ae6351b0e42416 /newlib/libc
parent3e4183d15bbdbf4ae0086f970aedca11d577561b (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.c76
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 */
+}