diff options
Diffstat (limited to 'stdlib/strtod_l.c')
-rw-r--r-- | stdlib/strtod_l.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c index a656789f4c..bb7493bff0 100644 --- a/stdlib/strtod_l.c +++ b/stdlib/strtod_l.c @@ -1,5 +1,6 @@ /* Convert string representing a number to float value, using given locale. - Copyright (C) 1997,98,2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1997,1998,2002,2004,2005,2006,2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. @@ -28,6 +29,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, `strtof.c', `wcstod.c', `wcstold.c', and `wcstof.c' to produce the `long double' and `float' versions of the reader. */ #ifndef FLOAT +# include <math_ldbl_opt.h> # define FLOAT double # define FLT DBL # ifdef USE_WIDE_CHAR @@ -68,8 +70,8 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, and _LONG_LONG_LIMB in it can take effect into gmp.h. */ #include <gmp-mparam.h> #include <gmp.h> -#include <gmp-impl.h> -#include <longlong.h> +#include "gmp-impl.h" +#include "longlong.h" #include "fpioconst.h" #define NDEBUG 1 @@ -100,7 +102,9 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, # define ISDIGIT(Ch) __iswdigit_l ((Ch), loc) # define ISXDIGIT(Ch) __iswxdigit_l ((Ch), loc) # define TOLOWER(Ch) __towlower_l ((Ch), loc) -# define STRNCASECMP(S1, S2, N) __wcsncasecmp_l ((S1), (S2), (N), loc) +# define TOLOWER_C(Ch) __towlower_l ((Ch), _nl_C_locobj_ptr) +# define STRNCASECMP(S1, S2, N) \ + __wcsncasecmp_l ((S1), (S2), (N), _nl_C_locobj_ptr) # define STRTOULL(S, E, B) ____wcstoull_l_internal ((S), (E), (B), 0, loc) #else # define STRING_TYPE char @@ -110,7 +114,9 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, # define ISDIGIT(Ch) __isdigit_l ((Ch), loc) # define ISXDIGIT(Ch) __isxdigit_l ((Ch), loc) # define TOLOWER(Ch) __tolower_l ((Ch), loc) -# define STRNCASECMP(S1, S2, N) __strncasecmp_l ((S1), (S2), (N), loc) +# define TOLOWER_C(Ch) __tolower_l ((Ch), _nl_C_locobj_ptr) +# define STRNCASECMP(S1, S2, N) \ + __strncasecmp_l ((S1), (S2), (N), _nl_C_locobj_ptr) # define STRTOULL(S, E, B) ____strtoull_l_internal ((S), (E), (B), 0, loc) #endif @@ -402,6 +408,9 @@ __mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count, #define INTERNAL(x) INTERNAL1(x) #define INTERNAL1(x) __##x##_internal +#ifndef ____STRTOF_INTERNAL +# define ____STRTOF_INTERNAL INTERNAL (__STRTOF) +#endif /* This file defines a function to check for correct grouping. */ #include "grouping.h" @@ -413,7 +422,7 @@ __mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count, return 0.0. If the number is too big to be represented, set `errno' to ERANGE and return HUGE_VAL with the appropriate sign. */ FLOAT -INTERNAL (__STRTOF) (nptr, endptr, group, loc) +____STRTOF_INTERNAL (nptr, endptr, group, loc) const STRING_TYPE *nptr; STRING_TYPE **endptr; int group; @@ -554,7 +563,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) else if (c < L_('0') || c > L_('9')) { /* Check for `INF' or `INFINITY'. */ - if (TOLOWER (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0) + if (TOLOWER_C (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0) { /* Return +/- infinity. */ if (endptr != NULL) @@ -565,7 +574,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; } - if (TOLOWER (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0) + if (TOLOWER_C (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0) { /* Return NaN. */ FLOAT retval = NAN; @@ -642,10 +651,11 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) if (c != '0') { for (cnt = 0; thousands[cnt] != '\0'; ++cnt) - if (c != thousands[cnt]) + if (thousands[cnt] != cp[cnt]) break; if (thousands[cnt] != '\0') break; + cp += cnt - 1; } c = *++cp; } @@ -654,20 +664,29 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) /* If no other digit but a '0' is found the result is 0.0. Return current read pointer. */ - if ((c < L_('0') || c > L_('9')) - && (base == 16 && (c < (CHAR_TYPE) TOLOWER (L_('a')) - || c > (CHAR_TYPE) TOLOWER (L_('f')))) + if (!((c >= L_('0') && c <= L_('9')) + || (base == 16 && ((CHAR_TYPE) TOLOWER (c) >= L_('a') + && (CHAR_TYPE) TOLOWER (c) <= L_('f'))) + || ( #ifdef USE_WIDE_CHAR - && c != (wint_t) decimal + c == (wint_t) decimal #else - && ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt) - if (decimal[cnt] != cp[cnt]) - break; - decimal[cnt] != '\0'; }) + ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt) + if (decimal[cnt] != cp[cnt]) + break; + decimal[cnt] == '\0'; }) #endif - && (base == 16 && (cp == start_of_digits - || (CHAR_TYPE) TOLOWER (c) != L_('p'))) - && (base != 16 && (CHAR_TYPE) TOLOWER (c) != L_('e'))) + /* '0x.' alone is not a valid hexadecimal number. + '.' alone is not valid either, but that has been checked + already earlier. */ + && (base != 16 + || cp != start_of_digits + || (cp[decimal_len] >= L_('0') && cp[decimal_len] <= L_('9')) + || ((CHAR_TYPE) TOLOWER (cp[decimal_len]) >= L_('a') + && (CHAR_TYPE) TOLOWER (cp[decimal_len]) <= L_('f')))) + || (base == 16 && (cp != start_of_digits + && (CHAR_TYPE) TOLOWER (c) == L_('p'))) + || (base != 16 && (CHAR_TYPE) TOLOWER (c) == L_('e')))) { #ifdef USE_WIDE_CHAR tp = __correctly_grouped_prefixwc (start_of_digits, cp, thousands, @@ -707,13 +726,14 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) break; if (thousands[cnt] != '\0') break; + cp += cnt - 1; } #endif } c = *++cp; } - if (grouping && dig_no > 0) + if (grouping && cp > start_of_digits) { /* Check the grouping of the digits. */ #ifdef USE_WIDE_CHAR @@ -751,13 +771,15 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) } } - /* We have the number digits in the integer part. Whether these are all or - any is really a fractional digit will be decided later. */ + /* We have the number of digits in the integer part. Whether these + are all or any is really a fractional digit will be decided + later. */ int_no = dig_no; lead_zero = int_no == 0 ? -1 : 0; - /* Read the fractional digits. A special case are the 'american style' - numbers like `16.' i.e. with decimal but without trailing digits. */ + /* Read the fractional digits. A special case are the 'american + style' numbers like `16.' i.e. with decimal point but without + trailing digits. */ if ( #ifdef USE_WIDE_CHAR c == (wint_t) decimal @@ -807,15 +829,16 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) if (base == 16) exp_limit = (exp_negative ? -MIN_EXP + MANT_DIG + 4 * int_no : - MAX_EXP - 4 * int_no + lead_zero); + MAX_EXP - 4 * int_no + 4 * lead_zero + 3); else exp_limit = (exp_negative ? -MIN_10_EXP + MANT_DIG + int_no : - MAX_10_EXP - int_no + lead_zero); + MAX_10_EXP - int_no + lead_zero + 1); do { exponent *= 10; + exponent += c - L_('0'); if (exponent > exp_limit) /* The exponent is too large/small to represent a valid @@ -845,7 +868,6 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) /* NOTREACHED */ } - exponent += c - L_('0'); c = *++cp; } while (c >= L_('0') && c <= L_('9')); @@ -880,7 +902,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) --expp; --dig_no; --int_no; - ++exponent; + exponent += base == 16 ? 4 : 1; } while (dig_no > 0 && exponent < 0); @@ -1553,7 +1575,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc) /* NOTREACHED */ } #if defined _LIBC && !defined USE_WIDE_CHAR -libc_hidden_def (INTERNAL (__STRTOF)) +libc_hidden_def (____STRTOF_INTERNAL) #endif /* External user entry point. */ @@ -1567,6 +1589,23 @@ __STRTOF (nptr, endptr, loc) STRING_TYPE **endptr; __locale_t loc; { - return INTERNAL (__STRTOF) (nptr, endptr, 0, loc); + return ____STRTOF_INTERNAL (nptr, endptr, 0, loc); } weak_alias (__STRTOF, STRTOF) + +#ifdef LONG_DOUBLE_COMPAT +# if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1) +# ifdef USE_WIDE_CHAR +compat_symbol (libc, __wcstod_l, __wcstold_l, GLIBC_2_1); +# else +compat_symbol (libc, __strtod_l, __strtold_l, GLIBC_2_1); +# endif +# endif +# if LONG_DOUBLE_COMPAT(libc, GLIBC_2_3) +# ifdef USE_WIDE_CHAR +compat_symbol (libc, wcstod_l, wcstold_l, GLIBC_2_3); +# else +compat_symbol (libc, strtod_l, strtold_l, GLIBC_2_3); +# endif +# endif +#endif |