Mercurial > hg > octave-lyh > gnulib-hg
changeset 13655:d813f5516d9a
strtod: work around IRIX 6.5 bug
IRIX mis-parses "1e 1" as 10.0 and "" instead of 1.0 and "e 1".
Because the original parse may differ from the reparse in terms
of whether the value overflows, we have to do an errno dance.
* lib/strtod.c (strtod): Reparse number on shorter string if
exponent parse was invalid.
* tests/test-strtod.c (main): Add check for "0x1p 2".
Reported by Tom G. Christensen.
Signed-off-by: Eric Blake <eblake@redhat.com>
author | Eric Blake <eblake@redhat.com> |
---|---|
date | Wed, 01 Sep 2010 21:34:44 -0600 |
parents | 80cff54a83b0 |
children | bc9f00d2bbf1 |
files | ChangeLog lib/strtod.c tests/test-strtod.c |
diffstat | 3 files changed, 68 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2010-09-08 Eric Blake <eblake@redhat.com> + strtod: work around IRIX 6.5 bug + * lib/strtod.c (strtod): Reparse number on shorter string if + exponent parse was invalid. + * tests/test-strtod.c (main): Add check for "0x1p 2". + Reported by Tom G. Christensen. + getopt: optimize previous patch * m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Correctly check for empty variable. Speed up awk script.
--- a/lib/strtod.c +++ b/lib/strtod.c @@ -24,6 +24,7 @@ #include <limits.h> #include <math.h> #include <stdbool.h> +#include <string.h> #include "c-ctype.h" @@ -202,6 +203,7 @@ const char *s = nptr; const char *end; char *endbuf; + int saved_errno; /* Eat whitespace. */ while (locale_isspace (*s)) @@ -212,6 +214,7 @@ if (*s == '-' || *s == '+') ++s; + saved_errno = errno; num = underlying_strtod (s, &endbuf); end = endbuf; @@ -239,6 +242,35 @@ 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; }
--- a/tests/test-strtod.c +++ b/tests/test-strtod.c @@ -558,6 +558,26 @@ ASSERT (ptr == input + 10); ASSERT (errno == ERANGE); } + { + const char input[] = "1E 1000000"; + char *ptr; + double result; + errno = 0; + result = strtod (input, &ptr); + ASSERT (result == 1.0); /* HP-UX 11.11, IRIX 6.5, OSF/1 4.0 */ + ASSERT (ptr == input + 1); /* HP-UX 11.11, IRIX 6.5 */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1P 1000000"; + char *ptr; + double result; + errno = 0; + result = strtod (input, &ptr); + ASSERT (result == 1.0); /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */ + ASSERT (ptr == input + 3); /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */ + ASSERT (errno == 0); + } /* Infinity. */ { @@ -831,6 +851,16 @@ ASSERT (ptr == input + 6); /* NetBSD 3.0, OpenBSD 4.0, AIX 5.1, HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */ ASSERT (errno == 0); } + { + const char input[] = "0x1p 2"; + char *ptr; + double result; + errno = 0; + result = strtod (input, &ptr); + ASSERT (result == 1.0); /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */ + ASSERT (ptr == input + 3); /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */ + ASSERT (errno == 0); + } /* Large buffers. */ {