From fbace81684f8cbb80a2048c01dc545af247f5cb7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 20 Nov 2015 18:14:58 +0100 Subject: [PATCH] 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 --- 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 | 46 +- newlib/libc/stdlib/strtorx.c | 129 +++ winsup/cygwin/ChangeLog | 4 + winsup/cygwin/common.din | 2 +- 14 files changed, 1371 insertions(+), 21 deletions(-) create mode 100644 newlib/libc/stdlib/strtodg.c create mode 100644 newlib/libc/stdlib/strtorx.c diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 27e19a1ab..7bc7b1d56 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,28 @@ +2015-11-20 Corinna Vinschen + + * 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 * libc/stdlib/strtod.c (match): Move from here... diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h index afdde3f96..fd6315b06 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 6794f9b7e..1520ceab8 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 5fd153de6..e2e08db0e 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 9db0feb2a..33d4a0c2e 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 9db9cea7b..d0368c054 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 5029e58de..07506aac1 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 60ca1e80c..a44413cd6 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 8472e7db0..afda63e73 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 000000000..70ec17906 --- /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 +#include +#include +#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 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_r (struct _reent *ptr, const char *__restrict s00, + char **__restrict se) +{ +#ifdef _LDBL_EQ_DBL + /* On platforms where long double is as wide as double. */ + return _strtod_r (ptr, s00, se); +#else + long double result; + + _strtorx_r (ptr, s00, se, FLT_ROUNDS, &result); + return result; +#endif +} + long double strtold (const char *__restrict s00, char **__restrict se) { -#ifdef _LDBL_EQ_DBL - return strtod(s00, se); -#else - return _strtold (s00, se); -#endif + 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 000000000..85d872241 --- /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 +#include +#include +#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 49bac71e6..a75169644 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,7 @@ +2015-11-20 Corinna Vinschen + + * common.din (strtold): Drop redirection to _strtold. + 2015-11-18 Corinna Vinschen * sec_acl.cc (get_posix_access): Skip merging permissions if current diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din index 0b0e19635..d7f4d2495 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