wcstold implementation

Nick Clifton nickc@redhat.com
Thu Jan 22 15:28:00 GMT 2015


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 */
 



More information about the Newlib mailing list