diff options
author | Roland McGrath <roland@gnu.org> | 1995-03-16 05:32:45 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-03-16 05:32:45 +0000 |
commit | f0bf9cb92c28c9ec0ac3376d87055e9d14610082 (patch) | |
tree | c058250695dd90b4eb5b870620826727d559f925 /stdlib/strtod.c | |
parent | 67a3a8ac7fef11753205c69da9df9c4ef30f6076 (diff) | |
download | glibc-f0bf9cb92c28c9ec0ac3376d87055e9d14610082.tar glibc-f0bf9cb92c28c9ec0ac3376d87055e9d14610082.tar.gz glibc-f0bf9cb92c28c9ec0ac3376d87055e9d14610082.tar.bz2 glibc-f0bf9cb92c28c9ec0ac3376d87055e9d14610082.zip |
Thu Mar 16 00:04:41 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* locale/C-ctype.c: New correct data generated by drepper.
* Rules: Don't use $(libc.a).
Parsing of grouped numbers contributed by Ulrich Drepper.
* stdlib/strtol.c (__strtol_internal): Renamed from strtol. Take
new flag arg; if nonzero, parse locale-dependent thousands
grouping and interpret only the prefix that is correctly grouped.
(strtol): Define this to call _strtol_internal with zero for the flag.
Use a weak symbol for the definition.
* stdlib/strtod.c (strtod, __strtod_internal): Likewise.
Check for the exponent of the number overflowing the float format.
* stdlib/stdlib.h (__strtof, __strtold): Declarations removed.
(__strto{f,d,ld,l,ul,q,uq}_internal): Declare these functions.
[__OPTIMIZE__]: Define inline functions calling those.
* stdlib/grouping.h: New file, written by drepper.
* stdlib/Makefile (distribute): Add grouping.h.
* stdio/vfscanf.c: Grok %' modifier to numeric conversions. Call
__strtoX_internal with the grouping flag set iff the modifier is
present.
Wed Mar 15 00:40:54 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* sysdeps/generic/memchr.c: Fix typos: limit.h -> limits.h.
* mach/Machrules: Produce static deps for all object flavors.
[interface-library]: Remove all these variables and rules.
($(interface-library)-routines): Define this variable.
(extra-libs): Append $(interface-library) to this.
* mach/Makefile (interface-library): Omit .a suffix.
* hurd/Makefile: Likewise.
Tue Mar 14 23:40:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* stdio/internals.c (flushbuf): If !FLUSH_ONLY, don't skip out
early if no new data in buffer after priming.
* Makerules (object-suffixes, libtypes): Move all these variables
to Makeconfig.
* Makeconfig (object-suffixes, libtypes): Moved here from Makerules.
* Makerules (build-extra-lib): New canned sequence.
* sysdeps/mach/hurd/euidaccess.c: Include fcntl.h. Declare ERR;
fix uses of FILE and PORT. Remove bogus weak alias for `access'.
* sysdeps/mach/hurd/dirfd.c: Include hurd/fd.h and errno.h.
Add missing semicolon.
* sysdeps/mach/hurd/opendir.c: Include hurd/fd.h. Use a `struct
hurd_fd *' temp var, since DIRP->__fd is a `void *'.
* sysdeps/mach/hurd/readdir.c: Include hurd/fd.h.
* stdlib/wcstombs.c: #if 0 out code for non-ASCII chars until the
locale data format is implemented.
* sysdeps/mach/hurd/i386/trampoline.c (_hurd_setup_sighandler):
Pass &__sigreturn on the stack to the trampoline code, so it is
not position-dependent.
* stdio/printf_fp.c (NDEBUG): Define this to disable assert.
Don't include <stdarg.h>.
(__printf_fp): Last arg ARGS is now `const void **const';
dereference ARGS[0] instead of using va_arg.
* locale/setlocale.c: In LC_ALL case, initialize CATEGORY before
loop to install data.
* locale/loadlocale.c (_nl_category_num_items): Use _NL_ITEM_INDEX
to extract number from item code.
(_nl_load_locale): Close the descriptor when finished.
* malloc/realloc.c (_realloc_internal): Call _malloc_internal in
place of malloc.
* time/tzfile.c (__tzfile_default): Initialize RULE_STDOFF to zero.
Diffstat (limited to 'stdlib/strtod.c')
-rw-r--r-- | stdlib/strtod.c | 149 |
1 files changed, 91 insertions, 58 deletions
diff --git a/stdlib/strtod.c b/stdlib/strtod.c index 2f0e972893..8f71d136de 100644 --- a/stdlib/strtod.c +++ b/stdlib/strtod.c @@ -102,10 +102,11 @@ static const mp_limb _tens_in_limb[MAX_DIG_PER_LIMB + 1] = #define RETURN_LIMB_SIZE howmany (MANT_DIG, BITS_PER_MP_LIMB) #define RETURN(val,end) \ - do { if (endptr != 0) *endptr = (char *) end; return val; } while (0) + do { if (endptr != 0) *endptr = (char *) (end); return (val); } while (0) /* Maximum size necessary for mpn integers to hold floating point numbers. */ -#define MPNSIZE (howmany (MAX_EXP + 2 * MANT_DIG, BITS_PER_MP_LIMB) + 2) +#define MPNSIZE (howmany (MAX_EXP + 2 * MANT_DIG, BITS_PER_MP_LIMB) \ + + 2) /* Declare an mpn integer variable that big. */ #define MPN_VAR(name) mp_limb name[MPNSIZE]; mp_size_t name##size /* Copy an mpn integer value. */ @@ -276,15 +277,23 @@ __mpn_lshift_1 (mp_limb *ptr, mp_size_t size, unsigned int count, mp_limb limb) } +#define INTERNAL(x) INTERNAL1(x) +#define INTERNAL1(x) __##x##_internal + +/* This file defines a function to check for correct grouping. */ +#include "grouping.h" + + /* Return a floating point number with the value of the given string NPTR. Set *ENDPTR to the character after the last used one. If the number is smaller than the smallest representable number, set `errno' to ERANGE and return 0.0. If the number is too big to be represented, set `errno' to ERANGE and return HUGE_VAL with the approriate sign. */ FLOAT -STRTOF (nptr, endptr) - const char *nptr; - char **endptr; +INTERNAL (STRTOF) (nptr, endptr, group) + const char *nptr; + char **endptr; + int group; { int negative; /* The sign of the number. */ MPN_VAR (num); /* MP representation of the number. */ @@ -301,9 +310,9 @@ STRTOF (nptr, endptr) int bits; /* Running pointer after the last character processed in the string. */ - const char *cp; + const char *cp, *tp; /* Start of significant part of the number. */ - const char *startp; + const char *startp, *start_of_digits; /* Points at the character following the integer and fractional digits. */ const char *expp; /* Total number of digit and number of digits in integer part. */ @@ -313,60 +322,29 @@ STRTOF (nptr, endptr) /* The radix character of the current locale. */ wchar_t decimal; -#ifdef USE_GROUPING /* The thousands character of the current locale. */ wchar_t thousands; /* The numeric grouping specification of the current locale, in the format described in <locale.h>. */ const char *grouping; - /* Check the grouping of the integer part at [BEGIN,END). - Return zero iff a separator is found out of place. */ - int grouping_ok (const char *begin, const char *end) + if (group) { - if (grouping) - while (end > begin) - { - const char *p = end; - do - --p; - while (*p != thousands && p > begin); - if (end - 1 - p != *grouping++) - return 0; /* Wrong number of digits in this group. */ - end = p; /* Correct group; trim it off the end. */ - - if (*grouping == 0) - --grouping; /* Same grouping repeats in next iteration. */ - else if (*grouping == CHAR_MAX || *grouping < 0) - { - /* No further grouping allowed. */ - while (end > begin) - if (*--end == thousands) - return 0; - } - } - return 1; - } - /* Return with no conversion if the grouping of [STARTP,CP) is bad. */ -#define CHECK_GROUPING if (! grouping_ok (startp, cp)) RETURN (0.0, nptr); else - - grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); - if (*grouping <= 0 || *grouping == CHAR_MAX) - grouping = NULL; - else - { - /* Figure out the thousands seperator character. */ - if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), - strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) - thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); - if (thousands == L'\0') + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + if (*grouping <= 0 || *grouping == CHAR_MAX) grouping = NULL; + else + { + /* Figure out the thousands separator character. */ + if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), + strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) + thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); + if (thousands == L'\0') + grouping = NULL; + } } -#else -#define grouping NULL -#define thousands L'\0' -#define CHECK_GROUPING ((void) 0) -#endif + else + grouping = NULL; /* Find the locale's decimal point character. */ if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT), @@ -402,18 +380,21 @@ STRTOF (nptr, endptr) RETURN (0.0, nptr); /* Record the start of the digits, in case we will check their grouping. */ - startp = cp; + start_of_digits = startp = cp; /* Ignore leading zeroes. This helps us to avoid useless computations. */ while (c == '0' || (thousands != L'\0' && c == thousands)) c = *++cp; - CHECK_GROUPING; - /* If no other digit but a '0' is found the result is 0.0. Return current read pointer. */ if (!isdigit (c) && c != decimal) - RETURN (0.0, cp); + { + tp = correctly_grouped_prefix (start_of_digits, cp, thousands, grouping); + /* If TP is at the start of the digits, there was no correctly + grouped prefix of the string; so no number found. */ + RETURN (0.0, tp == start_of_digits ? nptr : tp); + } /* Remember first significant digit and read following characters until the decimal point, exponent character or any non-FP number character. */ @@ -432,7 +413,37 @@ STRTOF (nptr, endptr) c = *++cp; } - CHECK_GROUPING; + if (grouping && dig_no > 0) + { + /* Check the grouping of the digits. */ + tp = correctly_grouped_prefix (start_of_digits, cp, thousands, grouping); + if (cp != tp) + { + /* Less than the entire string was correctly grouped. */ + + if (tp == start_of_digits) + /* No valid group of numbers at all: no valid number. */ + RETURN (0.0, nptr); + + if (tp < startp) + /* The number is validly grouped, but consists + only of zeroes. The whole value is zero. */ + RETURN (0.0, tp); + + /* Recompute DIG_NO so we won't read more digits than + are properly grouped. */ + cp = tp; + dig_no = 0; + for (tp = startp; tp < cp; ++tp) + if (isdigit (*tp)) + ++dig_no; + + int_no = dig_no; + lead_zero = 0; + + goto number_parsed; + } + } if (dig_no >= NDIG) /* Too many digits to be representable. Assigning this to EXPONENT @@ -528,6 +539,8 @@ STRTOF (nptr, endptr) assert (dig_no >= int_no); } + number_parsed: + /* The whole string is parsed. Store the address of the next character. */ if (endptr) *endptr = (char *) cp; @@ -546,7 +559,7 @@ STRTOF (nptr, endptr) exponent -= incr; } - if (int_no + exponent > MAX_10_EXP) + if (int_no + exponent > MAX_10_EXP + 1) { errno = ERANGE; return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; @@ -607,6 +620,14 @@ STRTOF (nptr, endptr) count_leading_zeros (bits, num[numsize - 1]); bits = numsize * BITS_PER_MP_LIMB - bits; + /* Now we know the exponent of the number in base two. + Check it against the maximum possible exponent. */ + if (bits > MAX_EXP) + { + errno = ERANGE; + return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; + } + /* We have already the first BITS bits of the result. Together with the information whether more non-zero bits follow this is enough to determine the result. */ @@ -1059,3 +1080,15 @@ STRTOF (nptr, endptr) /* NOTREACHED */ } + +/* External user entry point. */ + +weak_symbol (STRTOF) + +FLOAT +STRTOF (nptr, endptr) + const char *nptr; + char **endptr; +{ + return INTERNAL (STRTOF) (nptr, endptr, 0); +} |