https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=fbace81684f8cbb80a2048c01dc545af247f5cb7

commit fbace81684f8cbb80a2048c01dc545af247f5cb7
Author: Corinna Vinschen <cori...@vinschen.de>
Date:   Fri Nov 20 18:14:58 2015 +0100

    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 <cori...@vinschen.de>

Diff:
---
 newlib/ChangeLog                      |   25 +
 newlib/libc/include/stdlib.h          |    1 +
 newlib/libc/machine/powerpc/vfscanf.c |    3 +-
 newlib/libc/stdio/vfscanf.c           |    6 +-
 newlib/libc/stdlib/Makefile.am        |    2 +
 newlib/libc/stdlib/Makefile.in        |   27 +-
 newlib/libc/stdlib/gdtoa.h            |    2 +
 newlib/libc/stdlib/ldtoa.c            |    4 +-
 newlib/libc/stdlib/mprec.h            |    5 +
 newlib/libc/stdlib/strtodg.c          | 1136 +++++++++++++++++++++++++++++++++
 newlib/libc/stdlib/strtold.c          |   42 +-
 newlib/libc/stdlib/strtorx.c          |  129 ++++
 winsup/cygwin/ChangeLog               |    4 +
 winsup/cygwin/common.din              |    2 +-
 14 files changed, 1369 insertions(+), 19 deletions(-)

diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index 27e19a1..7bc7b1d 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -1,5 +1,30 @@
 2015-11-20  Corinna Vinschen  <cori...@vinschen.de>
 
+       * 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.
+
+2015-11-20  Corinna Vinschen  <cori...@vinschen.de>
+
        * libc/stdlib/strtod.c (match): Move from here...
        * libc/stdlib/gdtoa-hexnan.c (match): ...to here.
        * libc/stdlib/mprec.h (match): Declare and add __match define.
diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h
index afdde3f..fd6315b 100644
--- a/newlib/libc/include/stdlib.h
+++ b/newlib/libc/include/stdlib.h
@@ -274,6 +274,7 @@ _VOID       _EXFUN(qsort_r,(_PTR __base, size_t __nmemb, 
size_t __size, int (*_compar)
 
 /* On platforms where long double equals double.  */
 #ifdef _HAVE_LONG_DOUBLE
+extern long double _strtold_r (struct _reent *, const char *__restrict, char 
**__restrict);
 #if !defined(__STRICT_ANSI__) || \
   (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
   (defined(__cplusplus) && __cplusplus >= 201103L)
diff --git a/newlib/libc/machine/powerpc/vfscanf.c 
b/newlib/libc/machine/powerpc/vfscanf.c
index 6794f9b..1520cea 100644
--- a/newlib/libc/machine/powerpc/vfscanf.c
+++ b/newlib/libc/machine/powerpc/vfscanf.c
@@ -131,7 +131,6 @@ Supporting OS subroutines required:
 #define _NO_LONGDBL
 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
 #undef _NO_LONGDBL
-extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
 #endif
 
 #define _NO_LONGLONG
@@ -1211,7 +1210,7 @@ __svfscanf_r (rptr, fp, fmt0, ap)
 #ifdef _NO_LONGDBL
              res = _strtod_r (rptr, buf, NULL);
 #else  /* !_NO_LONGDBL */
-             res = _strtold (buf, NULL);
+             res = _strtold_r (rptr, buf, NULL);
 #endif /* !_NO_LONGDBL */
              if (flags & LONG)
                {
diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c
index 5fd153d..e2e08db 100644
--- a/newlib/libc/stdio/vfscanf.c
+++ b/newlib/libc/stdio/vfscanf.c
@@ -170,7 +170,6 @@ Supporting OS subroutines required:
 #define _NO_LONGDBL
 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
 #undef _NO_LONGDBL
-extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
 #endif
 
 #include "floatio.h"
@@ -1596,12 +1595,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
                  sprintf (exp_start, "e%ld", new_exp);
                }
 
-             /* Current _strtold routine is markedly slower than
+             /* FIXME: Is that still true?
+                Current _strtold routine is markedly slower than
                 _strtod_r.  Only use it if we have a long double
                 result.  */
 #ifndef _NO_LONGDBL /* !_NO_LONGDBL */
              if (flags & LONGDBL)
-               qres = _strtold (buf, NULL);
+               qres = _strtold_r (rptr, buf, NULL);
              else
 #endif
                res = _strtod_r (rptr, buf, NULL);
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 9db0feb..33d4a0c 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -53,7 +53,9 @@ GENERAL_SOURCES = \
        reallocf.c      \
        sb_charsets.c   \
        strtod.c        \
+       strtodg.c       \
        strtol.c        \
+       strtorx.c       \
        strtoul.c       \
        utoa.c          \
        wcstod.c        \
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index 9db9cea..d0368c0 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -105,7 +105,8 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) 
lib_a-__atexit.$(OBJEXT) \
        lib_a-rand.$(OBJEXT) lib_a-rand_r.$(OBJEXT) \
        lib_a-realloc.$(OBJEXT) lib_a-reallocf.$(OBJEXT) \
        lib_a-sb_charsets.$(OBJEXT) lib_a-strtod.$(OBJEXT) \
-       lib_a-strtol.$(OBJEXT) lib_a-strtoul.$(OBJEXT) \
+       lib_a-strtodg.$(OBJEXT) lib_a-strtol.$(OBJEXT) \
+       lib_a-strtorx.$(OBJEXT) lib_a-strtoul.$(OBJEXT) \
        lib_a-utoa.$(OBJEXT) lib_a-wcstod.$(OBJEXT) \
        lib_a-wcstol.$(OBJEXT) lib_a-wcstoul.$(OBJEXT) \
        lib_a-wcstombs.$(OBJEXT) lib_a-wcstombs_r.$(OBJEXT) \
@@ -157,9 +158,10 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo 
__exp10.lo \
        itoa.lo labs.lo ldiv.lo ldtoa.lo malloc.lo mblen.lo mblen_r.lo \
        mbstowcs.lo mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo \
        mprec.lo mstats.lo quick_exit.lo rand.lo rand_r.lo realloc.lo \
-       reallocf.lo sb_charsets.lo strtod.lo strtol.lo strtoul.lo \
-       utoa.lo wcstod.lo wcstol.lo wcstoul.lo wcstombs.lo \
-       wcstombs_r.lo wctomb.lo wctomb_r.lo $(am__objects_8)
+       reallocf.lo sb_charsets.lo strtod.lo strtodg.lo strtol.lo \
+       strtorx.lo strtoul.lo utoa.lo wcstod.lo wcstol.lo wcstoul.lo \
+       wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
+       $(am__objects_8)
 am__objects_10 = cxa_atexit.lo cxa_finalize.lo drand48.lo ecvtbuf.lo \
        efgcvt.lo erand48.lo jrand48.lo lcong48.lo lrand48.lo \
        mrand48.lo msize.lo mtrim.lo nrand48.lo rand48.lo seed48.lo \
@@ -361,8 +363,9 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c 
__exp10.c \
        ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c mbstowcs_r.c \
        mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c quick_exit.c \
        rand.c rand_r.c realloc.c reallocf.c sb_charsets.c strtod.c \
-       strtol.c strtoul.c utoa.c wcstod.c wcstol.c wcstoul.c \
-       wcstombs.c wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
+       strtodg.c strtol.c strtorx.c strtoul.c utoa.c wcstod.c \
+       wcstol.c wcstoul.c wcstombs.c wcstombs_r.c wctomb.c wctomb_r.c \
+       $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -895,12 +898,24 @@ lib_a-strtod.o: strtod.c
 lib_a-strtod.obj: strtod.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtod.obj `if test -f 
'strtod.c'; then $(CYGPATH_W) 'strtod.c'; else $(CYGPATH_W) 
'$(srcdir)/strtod.c'; fi`
 
+lib_a-strtodg.o: strtodg.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtodg.o `test -f 
'strtodg.c' || echo '$(srcdir)/'`strtodg.c
+
+lib_a-strtodg.obj: strtodg.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtodg.obj `if test -f 
'strtodg.c'; then $(CYGPATH_W) 'strtodg.c'; else $(CYGPATH_W) 
'$(srcdir)/strtodg.c'; fi`
+
 lib_a-strtol.o: strtol.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtol.o `test -f 'strtol.c' 
|| echo '$(srcdir)/'`strtol.c
 
 lib_a-strtol.obj: strtol.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtol.obj `if test -f 
'strtol.c'; then $(CYGPATH_W) 'strtol.c'; else $(CYGPATH_W) 
'$(srcdir)/strtol.c'; fi`
 
+lib_a-strtorx.o: strtorx.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtorx.o `test -f 
'strtorx.c' || echo '$(srcdir)/'`strtorx.c
+
+lib_a-strtorx.obj: strtorx.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtorx.obj `if test -f 
'strtorx.c'; then $(CYGPATH_W) 'strtorx.c'; else $(CYGPATH_W) 
'$(srcdir)/strtorx.c'; fi`
+
 lib_a-strtoul.o: strtoul.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) 
$(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strtoul.o `test -f 
'strtoul.c' || echo '$(srcdir)/'`strtoul.c
 
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 5029e58..07506aa 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -70,3 +70,5 @@ enum {        /* FPI.rounding values: same as FLT_ROUNDS */
        };
 
 #endif /* GDTOA_H_INCLUDED */
+
+typedef unsigned short __UShort;
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 60ca1e8..a44413c 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -3280,7 +3280,7 @@ bxit:
 }
 
 
-
+#if 0 /* Broken, unusable implementation of strtold */
 
 /*
 ;                                                              ASCTOQ
@@ -3644,7 +3644,7 @@ aexit:
   return lenldstr;
 }
 
-
+#endif
 
 /* y = largest integer not greater than x
  * (truncated toward minus infinity)
diff --git a/newlib/libc/stdlib/mprec.h b/newlib/libc/stdlib/mprec.h
index 8472e7d..afda63e 100644
--- a/newlib/libc/stdlib/mprec.h
+++ b/newlib/libc/stdlib/mprec.h
@@ -404,6 +404,11 @@ int                _EXFUN(gethex,(struct _reent *p, _CONST 
char **sp, _CONST struct FPI *fpi,
 double         _EXFUN(ratio,(_Bigint *a, _Bigint *b));
 __ULong                _EXFUN(any_on,(_Bigint *b, int k));
 void           _EXFUN(copybits,(__ULong *c, int n, _Bigint *b));
+#if defined (_HAVE_LONG_DOUBLE) && !defined (_LDBL_EQ_DBL)
+int            _EXFUN(_strtorx_r,(struct _reent *, _CONST char *, char **, 
int, void *));
+int            _EXFUN(_strtodg_r,(struct _reent *p, _CONST char *s00, char 
**se, struct FPI *fpi, Long *exp, __ULong *bits));
+#endif /* _HAVE_LONG_DOUBLE && !_LDBL_EQ_DBL */
+
 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || 
defined(_SMALL_HEXDIG)
 unsigned char _EXFUN(__hexdig_fun,(unsigned char));
 #endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && 
!defined(_SMALL_HEXDIG) */
diff --git a/newlib/libc/stdlib/strtodg.c b/newlib/libc/stdlib/strtodg.c
new file mode 100644
index 0000000..70ec179
--- /dev/null
+++ b/newlib/libc/stdlib/strtodg.c
@@ -0,0 +1,1136 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2001 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").     */
+
+#include <_ansi.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mprec.h"
+#include "gdtoa.h"
+#include "gd_qnan.h"
+
+#include "locale.h"
+
+ static const int
+fivesbits[] = {         0,  3,  5,  7, 10, 12, 14, 17, 19, 21,
+               24, 26, 28, 31, 33, 35, 38, 40, 42, 45,
+               47, 49, 52
+#ifdef VAX
+               , 54, 56
+#endif
+               };
+
+static _Bigint *
+#ifdef KR_headers
+sum(p, a, b) struct _reent *p; _Bigint *a; _Bigint *b;
+#else
+sum(struct _reent *p, _Bigint *a, _Bigint *b)
+#endif
+{
+       _Bigint *c;
+       __ULong carry, *xc, *xa, *xb, *xe, y;
+#ifdef Pack_32
+       __ULong z;
+#endif
+
+       if (a->_wds < b->_wds) {
+               c = b; b = a; a = c;
+               }
+       c = Balloc(p, a->_k);
+       c->_wds = a->_wds;
+       carry = 0;
+       xa = a->_x;
+       xb = b->_x;
+       xc = c->_x;
+       xe = xc + b->_wds;
+#ifdef Pack_32
+       do {
+               y = (*xa & 0xffff) + (*xb & 0xffff) + carry;
+               carry = (y & 0x10000) >> 16;
+               z = (*xa++ >> 16) + (*xb++ >> 16) + carry;
+               carry = (z & 0x10000) >> 16;
+               Storeinc(xc, z, y);
+               }
+               while(xc < xe);
+       xe += a->_wds - b->_wds;
+       while(xc < xe) {
+               y = (*xa & 0xffff) + carry;
+               carry = (y & 0x10000) >> 16;
+               z = (*xa++ >> 16) + carry;
+               carry = (z & 0x10000) >> 16;
+               Storeinc(xc, z, y);
+               }
+#else
+       do {
+               y = *xa++ + *xb++ + carry;
+               carry = (y & 0x10000) >> 16;
+               *xc++ = y & 0xffff;
+               }
+               while(xc < xe);
+       xe += a->_wds - b->_wds;
+       while(xc < xe) {
+               y = *xa++ + carry;
+               carry = (y & 0x10000) >> 16;
+               *xc++ = y & 0xffff;
+               }
+#endif
+       if (carry) {
+               if (c->_wds == c->_maxwds) {
+                       b = Balloc(p, c->_k + 1);
+                       Bcopy(b, c);
+                       Bfree(p, c);
+                       c = b;
+                       }
+               c->_x[c->_wds++] = 1;
+               }
+       return c;
+       }
+
+static void
+#ifdef KR_headers
+rshift(b, k) _Bigint *b; int k;
+#else
+rshift(_Bigint *b, int k)
+#endif
+{
+       __ULong *x, *x1, *xe, y;
+       int n;
+
+       x = x1 = b->_x;
+       n = k >> kshift;
+       if (n < b->_wds) {
+               xe = x + b->_wds;
+               x += n;
+               if (k &= kmask) {
+                       n = ULbits - k;
+                       y = *x++ >> k;
+                       while(x < xe) {
+                               *x1++ = (y | (*x << n)) & ALL_ON;
+                               y = *x++ >> k;
+                               }
+                       if ((*x1 = y) !=0)
+                               x1++;
+                       }
+               else
+                       while(x < xe)
+                               *x1++ = *x++;
+               }
+       if ((b->_wds = x1 - b->_x) == 0)
+               b->_x[0] = 0;
+       }
+
+static int
+#ifdef KR_headers
+trailz(b) _Bigint *b;
+#else
+trailz(_Bigint *b)
+#endif
+{
+       __ULong L, *x, *xe;
+       int n = 0;
+
+       x = b->_x;
+       xe = x + b->_wds;
+       for(n = 0; x < xe && !*x; x++)
+               n += ULbits;
+       if (x < xe) {
+               L = *x;
+               n += lo0bits(&L);
+               }
+       return n;
+       }
+
+ _Bigint *
+#ifdef KR_headers
+increment(p, b) struct _reent *p; _Bigint *b;
+#else
+increment(struct _reent *p, _Bigint *b)
+#endif
+{
+       __ULong *x, *xe;
+       _Bigint *b1;
+#ifdef Pack_16
+       __ULong carry = 1, y;
+#endif
+
+       x = b->_x;
+       xe = x + b->_wds;
+#ifdef Pack_32
+       do {
+               if (*x < (__ULong)0xffffffffL) {
+                       ++*x;
+                       return b;
+                       }
+               *x++ = 0;
+               } while(x < xe);
+#else
+       do {
+               y = *x + carry;
+               carry = y >> 16;
+               *x++ = y & 0xffff;
+               if (!carry)
+                       return b;
+               } while(x < xe);
+       if (carry)
+#endif
+       {
+               if (b->_wds >= b->_maxwds) {
+                       b1 = Balloc(p,b->_k+1);
+                       Bcopy(b1,b);
+                       Bfree(p,b);
+                       b = b1;
+                       }
+               b->_x[b->_wds++] = 1;
+               }
+       return b;
+       }
+
+ int
+#ifdef KR_headers
+decrement(b) _Bigint *b;
+#else
+decrement(_Bigint *b)
+#endif
+{
+       __ULong *x, *xe;
+#ifdef Pack_16
+       __ULong borrow = 1, y;
+#endif
+
+       x = b->_x;
+       xe = x + b->_wds;
+#ifdef Pack_32
+       do {
+               if (*x) {
+                       --*x;
+                       break;
+                       }
+               *x++ = 0xffffffffL;
+               }
+               while(x < xe);
+#else
+       do {
+               y = *x - borrow;
+               borrow = (y & 0x10000) >> 16;
+               *x++ = y & 0xffff;
+               } while(borrow && x < xe);
+#endif
+       return STRTOG_Inexlo;
+       }
+
+ static int
+#ifdef KR_headers
+all_on(b, n) _Bigint *b; int n;
+#else
+all_on(_Bigint *b, int n)
+#endif
+{
+       __ULong *x, *xe;
+
+       x = b->_x;
+       xe = x + (n >> kshift);
+       while(x < xe)
+               if ((*x++ & ALL_ON) != ALL_ON)
+                       return 0;
+       if (n &= kmask)
+               return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON;
+       return 1;
+       }
+
+ _Bigint *
+#ifdef KR_headers
+set_ones(p, b, n) struct _reent *p; _Bigint *b; int n;
+#else
+set_ones(struct _reent *p, _Bigint *b, int n)
+#endif
+{
+       int k;
+       __ULong *x, *xe;
+
+       k = (n + ((1 << kshift) - 1)) >> kshift;
+       if (b->_k < k) {
+               Bfree(p,b);
+               b = Balloc(p,k);
+               }
+       k = n >> kshift;
+       if (n &= kmask)
+               k++;
+       b->_wds = k;
+       x = b->_x;
+       xe = x + k;
+       while(x < xe)
+               *x++ = ALL_ON;
+       if (n)
+               x[-1] >>= ULbits - n;
+       return b;
+       }
+
+ static int
+rvOK
+#ifdef KR_headers
+ (p, d, fpi, exp, bits, exact, rd, irv)
+ struct _reent *p; double d; FPI *fpi; Long *exp; __ULong *bits; int exact, 
rd, *irv;
+#else
+ (struct _reent *p, double d, FPI *fpi, Long *exp, __ULong *bits, int exact, 
int rd, int *irv)
+#endif
+{
+       _Bigint *b;
+       __ULong carry, inex, lostbits;
+       int bdif, e, j, k, k1, nb, rv;
+
+       carry = rv = 0;
+       b = d2b(p, d, &e, &bdif);
+       bdif -= nb = fpi->nbits;
+       e += bdif;
+       if (bdif <= 0) {
+               if (exact)
+                       goto trunc;
+               goto ret;
+               }
+       if (P == nb) {
+               if (
+#ifndef IMPRECISE_INEXACT
+                       exact &&
+#endif
+                       fpi->rounding ==
+#ifdef RND_PRODQUOT
+                                       FPI_Round_near
+#else
+                                       Flt_Rounds
+#endif
+                       ) goto trunc;
+               goto ret;
+               }
+       switch(rd) {
+         case 1:
+               goto trunc;
+         case 2:
+               break;
+         default: /* round near */
+               k = bdif - 1;
+               if (k < 0)
+                       goto trunc;
+               if (!k) {
+                       if (!exact)
+                               goto ret;
+                       if (b->_x[0] & 2)
+                               break;
+                       goto trunc;
+                       }
+               if (b->_x[k>>kshift] & ((__ULong)1 << (k & kmask)))
+                       break;
+               goto trunc;
+         }
+       /* "break" cases: round up 1 bit, then truncate; bdif > 0 */
+       carry = 1;
+ trunc:
+       inex = lostbits = 0;
+       if (bdif > 0) {
+               if ( (lostbits = any_on(b, bdif)) !=0)
+                       inex = STRTOG_Inexlo;
+               rshift(b, bdif);
+               if (carry) {
+                       inex = STRTOG_Inexhi;
+                       b = increment(p, b);
+                       if ( (j = nb & kmask) !=0)
+                               j = ULbits - j;
+                       if (hi0bits(b->_x[b->_wds - 1]) != j) {
+                               if (!lostbits)
+                                       lostbits = b->_x[0] & 1;
+                               rshift(b, 1);
+                               e++;
+                               }
+                       }
+               }
+       else if (bdif < 0)
+               b = lshift(p, b, -bdif);
+       if (e < fpi->emin) {
+               k = fpi->emin - e;
+               e = fpi->emin;
+               if (k > nb || fpi->sudden_underflow) {
+                       b->_wds = inex = 0;
+                       *irv = STRTOG_Underflow | STRTOG_Inexlo;
+                       }
+               else {
+                       k1 = k - 1;
+                       if (k1 > 0 && !lostbits)
+                               lostbits = any_on(b, k1);
+                       if (!lostbits && !exact)
+                               goto ret;
+                       lostbits |=
+                         carry = b->_x[k1>>kshift] & (1 << (k1 & kmask));
+                       rshift(b, k);
+                       *irv = STRTOG_Denormal;
+                       if (carry) {
+                               b = increment(p, b);
+                               inex = STRTOG_Inexhi | STRTOG_Underflow;
+                               }
+                       else if (lostbits)
+                               inex = STRTOG_Inexlo | STRTOG_Underflow;
+                       }
+               }
+       else if (e > fpi->emax) {
+               e = fpi->emax + 1;
+               *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
+#ifndef NO_ERRNO
+               errno = ERANGE;
+#endif
+               b->_wds = inex = 0;
+               }
+       *exp = e;
+       copybits(bits, nb, b);
+       *irv |= inex;
+       rv = 1;
+ ret:
+       Bfree(p,b);
+       return rv;
+       }
+
+ static int
+#ifdef KR_headers
+mantbits(d) double d;
+#else
+mantbits(U d)
+#endif
+{
+       __ULong L;
+#ifdef VAX
+       L = word1(d) << 16 | word1(d) >> 16;
+       if (L)
+#else
+       if ( (L = word1(d)) !=0)
+#endif
+               return P - lo0bits(&L);
+#ifdef VAX
+       L = word0(d) << 16 | word0(d) >> 16 | Exp_msk11;
+#else
+       L = word0(d) | Exp_msk1;
+#endif
+       return P - 32 - lo0bits(&L);
+       }
+
+ int
+_strtodg_r
+#ifdef KR_headers
+       (p, s00, se, fpi, exp, bits)
+       struct _reent *p; const char *s00; char **se; FPI *fpi; Long *exp; 
__ULong *bits;
+#else
+       (struct _reent *p, const char *s00, char **se, FPI *fpi, Long *exp, 
__ULong *bits)
+#endif
+{
+       int abe, abits, asub;
+       int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm;
+       int dsign, e, e1, e2, emin, esign, finished, i, inex, irv;
+       int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign;
+       int sudden_underflow;
+       const char *s, *s0, *s1;
+       //double adj, adj0, rv, tol;
+       double adj0, tol;
+       U adj, rv;
+       Long L;
+       __ULong y, z;
+       _Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
+
+       irv = STRTOG_Zero;
+       denorm = sign = nz0 = nz = 0;
+       dval(rv) = 0.;
+       rvb = 0;
+       nbits = fpi->nbits;
+       for(s = s00;;s++) switch(*s) {
+               case '-':
+                       sign = 1;
+                       /* no break */
+               case '+':
+                       if (*++s)
+                               goto break2;
+                       /* no break */
+               case 0:
+                       sign = 0;
+                       irv = STRTOG_NoNumber;
+                       s = s00;
+                       goto ret;
+               case '\t':
+               case '\n':
+               case '\v':
+               case '\f':
+               case '\r':
+               case ' ':
+                       continue;
+               default:
+                       goto break2;
+               }
+ break2:
+       if (*s == '0') {
+#ifndef NO_HEX_FP
+               switch(s[1]) {
+                 case 'x':
+                 case 'X':
+                       irv = gethex(p, &s, fpi, exp, &rvb, sign);
+                       if (irv == STRTOG_NoNumber) {
+                               s = s00;
+                               sign = 0;
+                               }
+                       goto ret;
+                 }
+#endif
+               nz0 = 1;
+               while(*++s == '0') ;
+               if (!*s)
+                       goto ret;
+               }
+       sudden_underflow = fpi->sudden_underflow;
+       s0 = s;
+       y = z = 0;
+       for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+               if (nd < 9)
+                       y = 10*y + c - '0';
+               else if (nd < 16)
+                       z = 10*z + c - '0';
+       nd0 = nd;
+#ifdef USE_LOCALE
+       if (c == *localeconv()->decimal_point)
+#else
+       if (c == '.')
+#endif
+               {
+               decpt = 1;
+               c = *++s;
+               if (!nd) {
+                       for(; c == '0'; c = *++s)
+                               nz++;
+                       if (c > '0' && c <= '9') {
+                               s0 = s;
+                               nf += nz;
+                               nz = 0;
+                               goto have_dig;
+                               }
+                       goto dig_done;
+                       }
+               for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+                       nz++;
+                       if (c -= '0') {
+                               nf += nz;
+                               for(i = 1; i < nz; i++)
+                                       if (nd++ < 9)
+                                               y *= 10;
+                                       else if (nd <= DBL_DIG + 1)
+                                               z *= 10;
+                               if (nd++ < 9)
+                                       y = 10*y + c;
+                               else if (nd <= DBL_DIG + 1)
+                                       z = 10*z + c;
+                               nz = 0;
+                               }
+                       }
+               }
+ dig_done:
+       e = 0;
+       if (c == 'e' || c == 'E') {
+               if (!nd && !nz && !nz0) {
+                       irv = STRTOG_NoNumber;
+                       s = s00;
+                       goto ret;
+                       }
+               s00 = s;
+               esign = 0;
+               switch(c = *++s) {
+                       case '-':
+                               esign = 1;
+                       case '+':
+                               c = *++s;
+                       }
+               if (c >= '0' && c <= '9') {
+                       while(c == '0')
+                               c = *++s;
+                       if (c > '0' && c <= '9') {
+                               L = c - '0';
+                               s1 = s;
+                               while((c = *++s) >= '0' && c <= '9')
+                                       L = 10*L + c - '0';
+                               if (s - s1 > 8 || L > 19999)
+                                       /* Avoid confusion from exponents
+                                        * so large that e might overflow.
+                                        */
+                                       e = 19999; /* safe for 16 bit ints */
+                               else
+                                       e = (int)L;
+                               if (esign)
+                                       e = -e;
+                               }
+                       else
+                               e = 0;
+                       }
+               else
+                       s = s00;
+               }
+       if (!nd) {
+               if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+                       /* Check for Nan and Infinity */
+                       if (!decpt)
+                        switch(c) {
+                         case 'i':
+                         case 'I':
+                               if (match(&s,"nf")) {
+                                       --s;
+                                       if (!match(&s,"inity"))
+                                               ++s;
+                                       irv = STRTOG_Infinite;
+                                       goto infnanexp;
+                                       }
+                               break;
+                         case 'n':
+                         case 'N':
+                               if (match(&s, "an")) {
+                                       irv = STRTOG_NaN;
+                                       *exp = fpi->emax + 1;
+#ifndef No_Hex_NaN
+                                       if (*s == '(') /*)*/
+                                               irv = hexnan(&s, fpi, bits);
+#endif
+                                       goto infnanexp;
+                                       }
+                         }
+#endif /* INFNAN_CHECK */
+                       irv = STRTOG_NoNumber;
+                       s = s00;
+                       }
+               goto ret;
+               }
+
+       irv = STRTOG_Normal;
+       e1 = e -= nf;
+       rd = 0;
+       switch(fpi->rounding & 3) {
+         case FPI_Round_up:
+               rd = 2 - sign;
+               break;
+         case FPI_Round_zero:
+               rd = 1;
+               break;
+         case FPI_Round_down:
+               rd = 1 + sign;
+         }
+
+       /* Now we have nd0 digits, starting at s0, followed by a
+        * decimal point, followed by nd-nd0 digits.  The number we're
+        * after is the integer represented by those digits times
+        * 10**e */
+
+       if (!nd0)
+               nd0 = nd;
+       k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+       dval(rv) = y;
+       if (k > 9)
+               dval(rv) = tens[k - 9] * dval(rv) + z;
+       bd0 = 0;
+       if (nbits <= P && nd <= DBL_DIG) {
+               if (!e) {
+                       if (rvOK(p, dval(rv), fpi, exp, bits, 1, rd, &irv))
+                               goto ret;
+                       }
+               else if (e > 0) {
+                       if (e <= Ten_pmax) {
+#ifdef VAX
+                               goto vax_ovfl_check;
+#else
+                               i = fivesbits[e] + mantbits(rv) <= P;
+                               /* rv = */ rounded_product(dval(rv), tens[e]);
+                               if (rvOK(p, dval(rv), fpi, exp, bits, i, rd, 
&irv))
+                                       goto ret;
+                               e1 -= e;
+                               goto rv_notOK;
+#endif
+                               }
+                       i = DBL_DIG - nd;
+                       if (e <= Ten_pmax + i) {
+                               /* A fancier test would sometimes let us do
+                                * this for larger i values.
+                                */
+                               e2 = e - i;
+                               e1 -= i;
+                               dval(rv) *= tens[i];
+#ifdef VAX
+                               /* VAX exponent range is so narrow we must
+                                * worry about overflow here...
+                                */
+ vax_ovfl_check:
+                               dval(adj) = dval(rv);
+                               word0(adj) -= P*Exp_msk1;
+                               /* adj = */ rounded_product(dval(adj), 
tens[e2]);
+                               if ((word0(adj) & Exp_mask)
+                                > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+                                       goto rv_notOK;
+                               word0(adj) += P*Exp_msk1;
+                               dval(rv) = dval(adj);
+#else
+                               /* rv = */ rounded_product(dval(rv), tens[e2]);
+#endif
+                               if (rvOK(p, dval(rv), fpi, exp, bits, 0, rd, 
&irv))
+                                       goto ret;
+                               e1 -= e2;
+                               }
+                       }
+#ifndef Inaccurate_Divide
+               else if (e >= -Ten_pmax) {
+                       /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+                       if (rvOK(p, dval(rv), fpi, exp, bits, 0, rd, &irv))
+                               goto ret;
+                       e1 -= e;
+                       }
+#endif
+               }
+ rv_notOK:
+       e1 += nd - k;
+
+       /* Get starting approximation = rv * 10**e1 */
+
+       e2 = 0;
+       if (e1 > 0) {
+               if ( (i = e1 & 15) !=0)
+                       dval(rv) *= tens[i];
+               if (e1 &= ~15) {
+                       e1 >>= 4;
+                       while(e1 >= (1 << n_bigtens-1)) {
+                               e2 += ((word0(rv) & Exp_mask)
+                                       >> Exp_shift1) - Bias;
+                               word0(rv) &= ~Exp_mask;
+                               word0(rv) |= Bias << Exp_shift1;
+                               dval(rv) *= bigtens[n_bigtens-1];
+                               e1 -= 1 << n_bigtens-1;
+                               }
+                       e2 += ((word0(rv) & Exp_mask) >> Exp_shift1) - Bias;
+                       word0(rv) &= ~Exp_mask;
+                       word0(rv) |= Bias << Exp_shift1;
+                       for(j = 0; e1 > 0; j++, e1 >>= 1)
+                               if (e1 & 1)
+                                       dval(rv) *= bigtens[j];
+                       }
+               }
+       else if (e1 < 0) {
+               e1 = -e1;
+               if ( (i = e1 & 15) !=0)
+                       dval(rv) /= tens[i];
+               if (e1 &= ~15) {
+                       e1 >>= 4;
+                       while(e1 >= (1 << n_bigtens-1)) {
+                               e2 += ((word0(rv) & Exp_mask)
+                                       >> Exp_shift1) - Bias;
+                               word0(rv) &= ~Exp_mask;
+                               word0(rv) |= Bias << Exp_shift1;
+                               dval(rv) *= tinytens[n_bigtens-1];
+                               e1 -= 1 << n_bigtens-1;
+                               }
+                       e2 += ((word0(rv) & Exp_mask) >> Exp_shift1) - Bias;
+                       word0(rv) &= ~Exp_mask;
+                       word0(rv) |= Bias << Exp_shift1;
+                       for(j = 0; e1 > 0; j++, e1 >>= 1)
+                               if (e1 & 1)
+                                       dval(rv) *= tinytens[j];
+                       }
+               }
+#ifdef IBM
+       /* e2 is a correction to the (base 2) exponent of the return
+        * value, reflecting adjustments above to avoid overflow in the
+        * native arithmetic.  For native IBM (base 16) arithmetic, we
+        * must multiply e2 by 4 to change from base 16 to 2.
+        */
+       e2 <<= 2;
+#endif
+       rvb = d2b(p, dval(rv), &rve, &rvbits);  /* rv = rvb * 2^rve */
+       rve += e2;
+       if ((j = rvbits - nbits) > 0) {
+               rshift(rvb, j);
+               rvbits = nbits;
+               rve += j;
+               }
+       bb0 = 0;        /* trailing zero bits in rvb */
+       e2 = rve + rvbits - nbits;
+       if (e2 > fpi->emax + 1)
+               goto huge;
+       rve1 = rve + rvbits - nbits;
+       if (e2 < (emin = fpi->emin)) {
+               denorm = 1;
+               j = rve - emin;
+               if (j > 0) {
+                       rvb = lshift(p, rvb, j);
+                       rvbits += j;
+                       }
+               else if (j < 0) {
+                       rvbits += j;
+                       if (rvbits <= 0) {
+                               if (rvbits < -1) {
+ ufl:
+                                       rvb->_wds = 0;
+                                       rvb->_x[0] = 0;
+                                       *exp = emin;
+                                       irv = STRTOG_Underflow | STRTOG_Inexlo;
+                                       goto ret;
+                                       }
+                               rvb->_x[0] = rvb->_wds = rvbits = 1;
+                               }
+                       else
+                               rshift(rvb, -j);
+                       }
+               rve = rve1 = emin;
+               if (sudden_underflow && e2 + 1 < emin)
+                       goto ufl;
+               }
+
+       /* Now the hard part -- adjusting rv to the correct value.*/
+
+       /* Put digits into bd: true value = bd * 10^e */
+
+       bd0 = s2b(p, s0, nd0, nd, y);
+
+       for(;;) {
+               bd = Balloc(p,bd0->_k);
+               Bcopy(bd, bd0);
+               bb = Balloc(p,rvb->_k);
+               Bcopy(bb, rvb);
+               bbbits = rvbits - bb0;
+               bbe = rve + bb0;
+               bs = i2b(p, 1);
+
+               if (e >= 0) {
+                       bb2 = bb5 = 0;
+                       bd2 = bd5 = e;
+                       }
+               else {
+                       bb2 = bb5 = -e;
+                       bd2 = bd5 = 0;
+                       }
+               if (bbe >= 0)
+                       bb2 += bbe;
+               else
+                       bd2 -= bbe;
+               bs2 = bb2;
+               j = nbits + 1 - bbbits;
+               i = bbe + bbbits - nbits;
+               if (i < emin)   /* denormal */
+                       j += i - emin;
+               bb2 += j;
+               bd2 += j;
+               i = bb2 < bd2 ? bb2 : bd2;
+               if (i > bs2)
+                       i = bs2;
+               if (i > 0) {
+                       bb2 -= i;
+                       bd2 -= i;
+                       bs2 -= i;
+                       }
+               if (bb5 > 0) {
+                       bs = pow5mult(p, bs, bb5);
+                       bb1 = mult(p, bs, bb);
+                       Bfree(p,bb);
+                       bb = bb1;
+                       }
+               bb2 -= bb0;
+               if (bb2 > 0)
+                       bb = lshift(p, bb, bb2);
+               else if (bb2 < 0)
+                       rshift(bb, -bb2);
+               if (bd5 > 0)
+                       bd = pow5mult(p, bd, bd5);
+               if (bd2 > 0)
+                       bd = lshift(p, bd, bd2);
+               if (bs2 > 0)
+                       bs = lshift(p, bs, bs2);
+               asub = 1;
+               inex = STRTOG_Inexhi;
+               delta = diff(p, bb, bd);
+               if (delta->_wds <= 1 && !delta->_x[0])
+                       break;
+               dsign = delta->_sign;
+               delta->_sign = finished = 0;
+               L = 0;
+               i = cmp(delta, bs);
+               if (rd && i <= 0) {
+                       irv = STRTOG_Normal;
+                       if ( (finished = dsign ^ (rd&1)) !=0) {
+                               if (dsign != 0) {
+                                       irv |= STRTOG_Inexhi;
+                                       goto adj1;
+                                       }
+                               irv |= STRTOG_Inexlo;
+                               if (rve1 == emin)
+                                       goto adj1;
+                               for(i = 0, j = nbits; j >= ULbits;
+                                               i++, j -= ULbits) {
+                                       if (rvb->_x[i] & ALL_ON)
+                                               goto adj1;
+                                       }
+                               if (j > 1 && lo0bits(rvb->_x + i) < j - 1)
+                                       goto adj1;
+                               rve = rve1 - 1;
+                               rvb = set_ones(p, rvb, rvbits = nbits);
+                               break;
+                               }
+                       irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi;
+                       break;
+                       }
+               if (i < 0) {
+                       /* Error is less than half an ulp -- check for
+                        * special case of mantissa a power of two.
+                        */
+                       irv = dsign
+                               ? STRTOG_Normal | STRTOG_Inexlo
+                               : STRTOG_Normal | STRTOG_Inexhi;
+                       if (dsign || bbbits > 1 || denorm || rve1 == emin)
+                               break;
+                       delta = lshift(p, delta,1);
+                       if (cmp(delta, bs) > 0) {
+                               irv = STRTOG_Normal | STRTOG_Inexlo;
+                               goto drop_down;
+                               }
+                       break;
+                       }
+               if (i == 0) {
+                       /* exactly half-way between */
+                       if (dsign) {
+                               if (denorm && all_on(rvb, rvbits)) {
+                                       /*boundary case -- increment exponent*/
+                                       rvb->_wds = 1;
+                                       rvb->_x[0] = 1;
+                                       rve = emin + nbits - (rvbits = 1);
+                                       irv = STRTOG_Normal | STRTOG_Inexhi;
+                                       denorm = 0;
+                                       break;
+                                       }
+                               irv = STRTOG_Normal | STRTOG_Inexlo;
+                               }
+                       else if (bbbits == 1) {
+                               irv = STRTOG_Normal;
+ drop_down:
+                               /* boundary case -- decrement exponent */
+                               if (rve1 == emin) {
+                                       irv = STRTOG_Normal | STRTOG_Inexhi;
+                                       if (rvb->_wds == 1 && rvb->_x[0] == 1)
+                                               sudden_underflow = 1;
+                                       break;
+                                       }
+                               rve -= nbits;
+                               rvb = set_ones(p, rvb, rvbits = nbits);
+                               break;
+                               }
+                       else
+                               irv = STRTOG_Normal | STRTOG_Inexhi;
+                       if (bbbits < nbits && !denorm || !(rvb->_x[0] & 1))
+                               break;
+                       if (dsign) {
+                               rvb = increment(p, rvb);
+                               j = kmask & (ULbits - (rvbits & kmask));
+                               if (hi0bits(rvb->_x[rvb->_wds - 1]) != j)
+                                       rvbits++;
+                               irv = STRTOG_Normal | STRTOG_Inexhi;
+                               }
+                       else {
+                               if (bbbits == 1)
+                                       goto undfl;
+                               decrement(rvb);
+                               irv = STRTOG_Normal | STRTOG_Inexlo;
+                               }
+                       break;
+                       }
+               if ((dval(adj) = ratio(delta, bs)) <= 2.) {
+ adj1:
+                       inex = STRTOG_Inexlo;
+                       if (dsign) {
+                               asub = 0;
+                               inex = STRTOG_Inexhi;
+                               }
+                       else if (denorm && bbbits <= 1) {
+ undfl:
+                               rvb->_wds = 0;
+                               rve = emin;
+                               irv = STRTOG_Underflow | STRTOG_Inexlo;
+                               break;
+                               }
+                       adj0 = dval(adj) = 1.;
+                       }
+               else {
+                       adj0 = dval(adj) *= 0.5;
+                       if (dsign) {
+                               asub = 0;
+                               inex = STRTOG_Inexlo;
+                               }
+                       if (dval(adj) < 2147483647.) {
+                               L = adj0;
+                               adj0 -= L;
+                               switch(rd) {
+                                 case 0:
+                                       if (adj0 >= .5)
+                                               goto inc_L;
+                                       break;
+                                 case 1:
+                                       if (asub && adj0 > 0.)
+                                               goto inc_L;
+                                       break;
+                                 case 2:
+                                       if (!asub && adj0 > 0.) {
+ inc_L:
+                                               L++;
+                                               inex = STRTOG_Inexact - inex;
+                                               }
+                                 }
+                               dval(adj) = L;
+                               }
+                       }
+               y = rve + rvbits;
+
+               /* adj *= ulp(dval(rv)); */
+               /* if (asub) rv -= adj; else rv += adj; */
+
+               if (!denorm && rvbits < nbits) {
+                       rvb = lshift(p, rvb, j = nbits - rvbits);
+                       rve -= j;
+                       rvbits = nbits;
+                       }
+               ab = d2b(p, dval(adj), &abe, &abits);
+               if (abe < 0)
+                       rshift(ab, -abe);
+               else if (abe > 0)
+                       ab = lshift(p, ab, abe);
+               rvb0 = rvb;
+               if (asub) {
+                       /* rv -= adj; */
+                       j = hi0bits(rvb->_x[rvb->_wds-1]);
+                       rvb = diff(p, rvb, ab);
+                       k = rvb0->_wds - 1;
+                       if (denorm)
+                               /* do nothing */;
+                       else if (rvb->_wds <= k
+                               || hi0bits( rvb->_x[k]) >
+                                  hi0bits(rvb0->_x[k])) {
+                               /* unlikely; can only have lost 1 high bit */
+                               if (rve1 == emin) {
+                                       --rvbits;
+                                       denorm = 1;
+                                       }
+                               else {
+                                       rvb = lshift(p, rvb, 1);
+                                       --rve;
+                                       --rve1;
+                                       L = finished = 0;
+                                       }
+                               }
+                       }
+               else {
+                       rvb = sum(p, rvb, ab);
+                       k = rvb->_wds - 1;
+                       if (k >= rvb0->_wds
+                        || hi0bits(rvb->_x[k]) < hi0bits(rvb0->_x[k])) {
+                               if (denorm) {
+                                       if (++rvbits == nbits)
+                                               denorm = 0;
+                                       }
+                               else {
+                                       rshift(rvb, 1);
+                                       rve++;
+                                       rve1++;
+                                       L = 0;
+                                       }
+                               }
+                       }
+               Bfree(p,ab);
+               Bfree(p,rvb0);
+               if (finished)
+                       break;
+
+               z = rve + rvbits;
+               if (y == z && L) {
+                       /* Can we stop now? */
+                       tol = dval(adj) * 5e-16; /* > max rel error */
+                       dval(adj) = adj0 - .5;
+                       if (dval(adj) < -tol) {
+                               if (adj0 > tol) {
+                                       irv |= inex;
+                                       break;
+                                       }
+                               }
+                       else if (dval(adj) > tol && adj0 < 1. - tol) {
+                               irv |= inex;
+                               break;
+                               }
+                       }
+               bb0 = denorm ? 0 : trailz(rvb);
+               Bfree(p,bb);
+               Bfree(p,bd);
+               Bfree(p,bs);
+               Bfree(p,delta);
+               }
+       if (!denorm && (j = nbits - rvbits)) {
+               if (j > 0)
+                       rvb = lshift(p, rvb, j);
+               else
+                       rshift(rvb, -j);
+               rve -= j;
+               }
+       *exp = rve;
+       Bfree(p,bb);
+       Bfree(p,bd);
+       Bfree(p,bs);
+       Bfree(p,bd0);
+       Bfree(p,delta);
+       if (rve > fpi->emax) {
+ huge:
+               rvb->_wds = 0;
+               irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
+#ifndef NO_ERRNO
+               errno = ERANGE;
+#endif
+ infnanexp:
+               *exp = fpi->emax + 1;
+               }
+ ret:
+       if (denorm) {
+               if (sudden_underflow) {
+                       rvb->_wds = 0;
+                       irv = STRTOG_Underflow | STRTOG_Inexlo;
+                       }
+               else  {
+                       irv = (irv & ~STRTOG_Retmask) |
+                               (rvb->_wds > 0 ? STRTOG_Denormal : STRTOG_Zero);
+                       if (irv & STRTOG_Inexact)
+                               irv |= STRTOG_Underflow;
+                       }
+               }
+       if (se)
+               *se = (char *)s;
+       if (sign)
+               irv |= STRTOG_Neg;
+       if (rvb) {
+               copybits(bits, nbits, rvb);
+               Bfree(p,rvb);
+               }
+       return irv;
+       }
diff --git a/newlib/libc/stdlib/strtold.c b/newlib/libc/stdlib/strtold.c
index a620251..96254eb 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 */
 
diff --git a/newlib/libc/stdlib/strtorx.c b/newlib/libc/stdlib/strtorx.c
new file mode 100644
index 0000000..85d8722
--- /dev/null
+++ b/newlib/libc/stdlib/strtorx.c
@@ -0,0 +1,129 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").     */
+
+#include <_ansi.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mprec.h"
+#include "gdtoa.h"
+#include "gd_qnan.h"
+
+#ifdef _HAVE_LONG_DOUBLE
+
+#undef _0
+#undef _1
+
+/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
+
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#define _2 2
+#define _3 3
+#define _4 4
+#endif
+#ifdef IEEE_8087
+#define _0 4
+#define _1 3
+#define _2 2
+#define _3 1
+#define _4 0
+#endif
+
+ void
+#ifdef KR_headers
+ULtox(L, bits, exp, k) __UShort *L; __ULong *bits; Long exp; int k;
+#else
+ULtox(__UShort *L, __ULong *bits, Long exp, int k)
+#endif
+{
+       switch(k & STRTOG_Retmask) {
+         case STRTOG_NoNumber:
+         case STRTOG_Zero:
+               L[0] = L[1] = L[2] = L[3] = L[4] = 0;
+               break;
+
+         case STRTOG_Denormal:
+               L[_0] = 0;
+               goto normal_bits;
+
+         case STRTOG_Normal:
+         case STRTOG_NaNbits:
+               L[_0] = exp + 0x3fff + 63;
+ normal_bits:
+               L[_4] = (__UShort)bits[0];
+               L[_3] = (__UShort)(bits[0] >> 16);
+               L[_2] = (__UShort)bits[1];
+               L[_1] = (__UShort)(bits[1] >> 16);
+               break;
+
+         case STRTOG_Infinite:
+               L[_0] = 0x7fff;
+               L[_1] = L[_2] = L[_3] = L[_4] = 0;
+               break;
+
+         case STRTOG_NaN:
+               L[0] = ldus_QNAN0;
+               L[1] = ldus_QNAN1;
+               L[2] = ldus_QNAN2;
+               L[3] = ldus_QNAN3;
+               L[4] = ldus_QNAN4;
+         }
+       if (k & STRTOG_Neg)
+               L[_0] |= 0x8000;
+       }
+
+ int
+#ifdef KR_headers
+_strtorx_r(p, s, sp, rounding, L) struct _reent *p; const char *s; char **sp; 
int rounding; void *L;
+#else
+_strtorx_r(struct _reent *p, const char *s, char **sp, int rounding, void *L)
+#endif
+{
+       static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI };
+       FPI *fpi, fpi1;
+       __ULong bits[2];
+       Long exp;
+       int k;
+
+       fpi = &fpi0;
+       if (rounding != FPI_Round_near) {
+               fpi1 = fpi0;
+               fpi1.rounding = rounding;
+               fpi = &fpi1;
+               }
+       k = _strtodg_r(p, s, sp, fpi, &exp, bits);
+       ULtox((__UShort*)L, bits, exp, k);
+       return k;
+       }
+
+#endif /* _HAVE_LONG_DOUBLE */
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 49bac71..a751696 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,7 @@
+2015-11-20  Corinna Vinschen  <cori...@vinschen.de>
+
+       * common.din (strtold): Drop redirection to _strtold.
+
 2015-11-18  Corinna Vinschen  <cori...@vinschen.de>
 
        * sec_acl.cc (get_posix_access): Skip merging permissions if current
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 0b0e196..d7f4d24 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1199,7 +1199,7 @@ strtoimax = strtoll NOSIGFE
 strtok NOSIGFE
 strtok_r NOSIGFE
 strtol NOSIGFE
-strtold = _strtold SIGFE
+strtold SIGFE
 strtoll NOSIGFE
 strtosigno NOSIGFE
 strtoul NOSIGFE

Reply via email to