summaryrefslogtreecommitdiffstats
path: root/newlib/libc/stdlib/strtold.c
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2015-11-20 18:14:58 +0100
committerCorinna Vinschen <corinna@vinschen.de>2015-11-20 18:14:58 +0100
commitfbace81684f8cbb80a2048c01dc545af247f5cb7 (patch)
tree01de6c0263b16465d7904f2cf6710cfc64925f88 /newlib/libc/stdlib/strtold.c
parent51bf1b81f3c4c7c02d8101f8ab6eb5609892e728 (diff)
downloadcygnal-fbace81684f8cbb80a2048c01dc545af247f5cb7.tar.gz
cygnal-fbace81684f8cbb80a2048c01dc545af247f5cb7.tar.bz2
cygnal-fbace81684f8cbb80a2048c01dc545af247f5cb7.zip
Import correctly working strtold from David M. Gay.
* libc/stdlib/Makefile.am (GENERAL_SOURCES): Add strtodg.c and strtorx.c. * libc/stdlib/Makefile.in: Regenerate. * libc/stdlib/strtodg.c: New file implementing generic string to long double conversion. * libc/stdlib/strtorx.c: New file, implementing IEEE format string to long double conversion. * libc/stdlib/mprec.h (_strtodg_r): Declare. (_strtorx_r): Declare. * libc/stdlib/gdtoa.h (__UShort): Define. * libc/stdlib/strtold.c (__flt_rounds): Define for i386 and x86_64 target. (FLT_ROUNDS): Define, as 0 on platforms missing a __flt_rounds function. (_strtold_r): Converted from strtold. Call _strtorx_r on targets supporting distinct long doubles. (strtold): Just call _strtold_r. * libc/include/stdlib.h (_strtold_r): Declare. * libc/stdlib/ldtoa.c (_strtold): Comment out. Explain why. * libc/stdio/vfscanf.c (__SVFSCANF_R): Call _strtold_r instead of _strtold. * libc/machine/powerpc/vfscanf.c (__svfscanf_r): Ditto. * common.din (strtold): Drop redirection to _strtold. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'newlib/libc/stdlib/strtold.c')
-rw-r--r--newlib/libc/stdlib/strtold.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/newlib/libc/stdlib/strtold.c b/newlib/libc/stdlib/strtold.c
index a620251ee..96254eb49 100644
--- a/newlib/libc/stdlib/strtold.c
+++ b/newlib/libc/stdlib/strtold.c
@@ -32,17 +32,49 @@ POSSIBILITY OF SUCH DAMAGE.
#include "local.h"
#ifdef _HAVE_LONG_DOUBLE
-extern long double _strtold (const char *, char **);
-/* On platforms where long double is as wide as double. */
+#if defined (__x86_64__) || defined (__i386__)
+static const int map[] = {
+ 1, /* round to nearest */
+ 3, /* round to zero */
+ 2, /* round to negative infinity */
+ 0 /* round to positive infinity */
+};
+
+int
+__flt_rounds(void)
+{
+ int x;
+
+ /* Assume that the x87 and the SSE unit agree on the rounding mode. */
+ __asm("fnstcw %0" : "=m" (x));
+ return (map[(x >> 10) & 0x03]);
+}
+#define FLT_ROUNDS __flt_rounds()
+#else
+#define FLT_ROUNDS 0
+#endif
+
long double
-strtold (const char *__restrict s00, char **__restrict se)
+_strtold_r (struct _reent *ptr, const char *__restrict s00,
+ char **__restrict se)
{
#ifdef _LDBL_EQ_DBL
- return strtod(s00, se);
+ /* On platforms where long double is as wide as double. */
+ return _strtod_r (ptr, s00, se);
#else
- return _strtold (s00, se);
+ long double result;
+
+ _strtorx_r (ptr, s00, se, FLT_ROUNDS, &result);
+ return result;
#endif
}
+
+long double
+strtold (const char *__restrict s00, char **__restrict se)
+{
+ return _strtold_r (_REENT, s00, se);
+}
+
#endif /* _HAVE_LONG_DOUBLE */