X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fstrtod.c;h=e554a84fddb48ae8619a60b88cdc142f6c40404d;hb=46f5f314f34a08c9305758482d7d2fdb0e999d09;hp=64b62ffd21c180a7fb8f79a10fd7a9eba60f9cd8;hpb=fd9f58dc85f6a45cd244c78a54ad4610c01dbb15;p=gnulib.git diff --git a/lib/strtod.c b/lib/strtod.c index 64b62ffd2..e554a84fd 100644 --- a/lib/strtod.c +++ b/lib/strtod.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1992, 1997, 1999, 2003, 2006, 2008-2010 Free Software +/* Copyright (C) 1991-1992, 1997, 1999, 2003, 2006, 2008-2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -24,15 +24,13 @@ #include #include #include +#include #include "c-ctype.h" #ifndef HAVE_LDEXP_IN_LIBC #define HAVE_LDEXP_IN_LIBC 0 #endif -#ifndef HAVE_RAW_DECL_STRTOD -#define HAVE_RAW_DECL_STRTOD 0 -#endif /* Return true if C is a space in the current locale, avoiding problems with signed char and isspace. */ @@ -148,7 +146,7 @@ parse_number (const char *nptr, else { /* The value of the digit doesn't matter, since we have already - gotten as many digits as can be represented in a `double'. + gotten as many digits as can be represented in a 'double'. This doesn't necessarily mean the result will overflow. The exponent may reduce it to within range. @@ -189,6 +187,21 @@ parse_number (const char *nptr, static double underlying_strtod (const char *, char **); +/* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0. + ICC 10.0 has a bug when optimizing the expression -zero. + The expression -DBL_MIN * DBL_MIN does not work when cross-compiling + to PowerPC on Mac OS X 10.5. */ +#if defined __hpux || defined __sgi || defined __ICC +static double +compute_minus_zero (void) +{ + return -DBL_MIN * DBL_MIN; +} +# define minus_zero compute_minus_zero () +#else +double minus_zero = -0.0; +#endif + /* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the character after the last one used in the number is put in *ENDPTR. */ double @@ -202,6 +215,7 @@ strtod (const char *nptr, char **endptr) const char *s = nptr; const char *end; char *endbuf; + int saved_errno; /* Eat whitespace. */ while (locale_isspace (*s)) @@ -212,6 +226,7 @@ strtod (const char *nptr, char **endptr) if (*s == '-' || *s == '+') ++s; + saved_errno = errno; num = underlying_strtod (s, &endbuf); end = endbuf; @@ -239,6 +254,35 @@ strtod (const char *nptr, char **endptr) end = p; } } + else + { + /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the + underlying strtod on a copy of the original string + truncated to avoid the bug. */ + const char *e = s + 1; + while (e < end && c_tolower (*e) != 'e') + e++; + if (e < end && ! c_isdigit (e[1 + (e[1] == '-' || e[1] == '+')])) + { + char *dup = strdup (s); + errno = saved_errno; + if (!dup) + { + /* Not really our day, is it. Rounding errors are + better than outright failure. */ + num = parse_number (s, 10, 10, 1, 'e', &endbuf); + } + else + { + dup[e - s] = '\0'; + num = underlying_strtod (dup, &endbuf); + saved_errno = errno; + free (dup); + errno = saved_errno; + } + end = e; + } + } s = end; } @@ -256,6 +300,7 @@ strtod (const char *nptr, char **endptr) && c_tolower (s[4]) == 'y') s += 5; num = HUGE_VAL; + errno = saved_errno; } else if (c_tolower (*s) == 'n' && c_tolower (s[1]) == 'a' @@ -278,6 +323,7 @@ strtod (const char *nptr, char **endptr) to interpreting n-char-sequence as a hexadecimal number. */ if (s != end) num = NAN; + errno = saved_errno; } else { @@ -288,27 +334,18 @@ strtod (const char *nptr, char **endptr) if (endptr != NULL) *endptr = (char *) s; + /* Special case -0.0, since at least ICC miscompiles negation. We + can't use copysign(), as that drags in -lm on some platforms. */ + if (!num && negative) + return minus_zero; return negative ? -num : num; } -/* The "underlying" strtod implementation. This must be defined +/* The underlying strtod implementation. This must be defined after strtod because it #undefs strtod. */ static double underlying_strtod (const char *nptr, char **endptr) { - if (HAVE_RAW_DECL_STRTOD) - { - /* Prefer the native strtod if available. Usually it should - work and it should give more-accurate results than our - approximation. */ - #undef strtod - return strtod (nptr, endptr); - } - else - { - /* Approximate strtod well enough for this module. There's no - need to handle anything but finite unsigned decimal - numbers with nonnull ENDPTR. */ - return parse_number (nptr, 10, 10, 1, 'e', endptr); - } +#undef strtod + return strtod (nptr, endptr); }