This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
wcstold implementation
- From: Nick Clifton <nickc at redhat dot com>
- To: vinschen at redhat dot com, yselkowi at redhat dot com
- Cc: newlib at sourceware dot org
- Date: Thu, 22 Jan 2015 15:11:31 +0000
- Subject: wcstold implementation
- Authentication-results: sourceware.org; auth=none
Hi Corinna, Hi Yaakov,
What do you think of the attached patch for an implementation of
wcstold() for sizeof (long double) > sizeof (double) ? The patch is
against the devo sources, but it could be adapted for FSF newlib
easily enough. One thing that you might not like is that the
_wcstold_r implementation calls _strtold and not _strtold_r. I can
fix this too if you think that it is worth it.
Cheers
Nick
Index: newlib/libc/include/wchar.h
===================================================================
RCS file: /cvs/cvsfiles/devo/newlib/libc/include/wchar.h,v
retrieving revision 1.28
diff -u -3 -p -r1.28 wchar.h
--- newlib/libc/include/wchar.h 18 Jan 2015 16:58:03 -0000 1.28
+++ newlib/libc/include/wchar.h 22 Jan 2015 15:05:48 -0000
@@ -122,6 +122,7 @@ double _EXFUN(_wcstod_r, (struct _reent
/* start-sanitize-redhat */
/* This uses a stub implementation. It is here so that we can compile the PlumHall tests. */
long double _EXFUN(wcstold, (const wchar_t *__restrict, wchar_t **__restrict));
+long double _EXFUN(_wcstold_r, (struct _reent *, const wchar_t *__restrict, wchar_t **__restrict));
/* end-sanitize-redhat */
float _EXFUN(wcstof, (const wchar_t *__restrict, wchar_t **__restrict));
float _EXFUN(_wcstof_r, (struct _reent *, const wchar_t *, wchar_t **));
Index: newlib/libc/stdio/vfwscanf.c
===================================================================
RCS file: /cvs/cvsfiles/devo/newlib/libc/stdio/vfwscanf.c,v
retrieving revision 1.5
diff -u -3 -p -r1.5 vfwscanf.c
--- newlib/libc/stdio/vfwscanf.c 26 Jan 2014 15:13:44 -0000 1.5
+++ newlib/libc/stdio/vfwscanf.c 22 Jan 2015 15:05:48 -0000
@@ -172,7 +172,7 @@ C99, POSIX-1.2008
#define _NO_LONGDBL
#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
#undef _NO_LONGDBL
-extern _LONG_DOUBLE _wcstold_r _PARAMS((wchar_t *s, wchar_t **sptr));
+extern _LONG_DOUBLE _wcstold_r _PARAMS((struct _reent *reent, wchar_t *s, wchar_t **sptr));
#endif
#include "floatio.h"
@@ -1434,8 +1434,7 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, a
swprintf (exp_start, MAX_LONG_LEN, L"e%ld", new_exp);
}
- /* FIXME: We don't have wcstold yet. */
-#if 0//ndef _NO_LONGDBL /* !_NO_LONGDBL */
+#ifndef _NO_LONGDBL
if (flags & LONGDBL)
qres = _wcstold_r (rptr, buf, NULL);
else
Index: newlib/libc/stdlib/wcstod.c
===================================================================
RCS file: /cvs/cvsfiles/devo/newlib/libc/stdlib/wcstod.c,v
retrieving revision 1.6
diff -u -3 -p -r1.6 wcstod.c
--- newlib/libc/stdlib/wcstod.c 26 Jan 2014 15:13:44 -0000 1.6
+++ newlib/libc/stdlib/wcstod.c 22 Jan 2015 15:05:48 -0000
@@ -230,13 +230,3 @@ _DEFUN (wcstof, (nptr, endptr),
}
#endif
-
-/* start-sanitize-redhat */
-/* This is a stub implementation, here in order
- to allow us to compile the PlumHall tests. */
-long double
-wcstold (const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
-{
- return wcstod (nptr, endptr);
-}
-/* end-sanitize-redhat */
Index: newlib/libc/stdlib/wcstold.c
===================================================================
RCS file: /cvs/cvsfiles/devo/newlib/libc/stdlib/wcstold.c,v
retrieving revision 1.2
diff -u -3 -p -r1.2 wcstold.c
--- newlib/libc/stdlib/wcstold.c 26 Jan 2014 15:13:44 -0000 1.2
+++ newlib/libc/stdlib/wcstold.c 22 Jan 2015 15:05:48 -0000
@@ -31,12 +31,104 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include "local.h"
-/* On platforms where long double is as wide as double. */
#ifdef _LDBL_EQ_DBL
+
+/* On platforms where long double is as wide as double. */
+
long double
wcstold (const wchar_t *__restrict nptr, wchar_t **__restrict endptr)
{
return wcstod(nptr, endptr);
}
-#endif /* _LDBL_EQ_DBL */
+
+#else
+
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <locale.h>
+
+extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
+
+/* This is a duplicate of the code in wcstod.c, but converted to long double. */
+
+long double
+_DEFUN (_wcstold_r, (ptr, nptr, endptr),
+ struct _reent *ptr _AND
+ _CONST wchar_t *nptr _AND
+ wchar_t **endptr)
+{
+ 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_r (ptr, NULL, &wcp, 0, &mbs)) == (size_t)-1)
+ {
+ if (endptr != NULL)
+ *endptr = (wchar_t *) nptr;
+ return 0.0L;
+ }
+
+ if ((buf = _malloc_r (ptr, len + 1)) == NULL)
+ return 0.0L;
+
+ mbs = initial;
+ _wcsrtombs_r (ptr, buf, &wcp, len + 1, &mbs);
+
+ /* val = _strtold_r (ptr, buf, &end); */
+ 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_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);
+
+ return val;
+}
+
+#ifndef _REENT_ONLY
+
+long double
+_DEFUN (wcstold, (nptr, endptr),
+ _CONST wchar_t *__restrict nptr _AND wchar_t **__restrict endptr)
+{
+ return _wcstold_r (_REENT, nptr, endptr);
+}
+
+#endif /* _REENT_ONLY */
+#endif /* ! _LDBL_EQ_DBL */