From 1217289737588e65b088b3535428b27c7287d699 Mon Sep 17 00:00:00 2001 From: Manuel Novoa III Date: Fri, 1 Aug 2003 20:08:59 +0000 Subject: Add a new *scanf implementation, includeing the *wscanf functions. Should be standards compliant and with several optional features, including support for hexadecimal float notation, locale awareness, glibc-like locale-specific digit grouping with the `'' flag, and positional arg support. I tested it pretty well (finding several bugs in glibc's scanf in the process), but it is brand new so be aware. The *wprintf functions now support floating point output. Also, a couple of bugs were squashed. Finally, %a/%A conversions are now implemented. Implement the glibc xlocale interface for thread-specific locale support. Also add the various *_l(args, locale_t loc_arg) funcs. NOTE!!! setlocale() is NOT threadsafe! NOTE!!! The strto{floating point} conversion functions are now locale aware. The also now support hexadecimal floating point notation. Add the wcsto{floating point} conversion functions. Fix a bug in mktime() related to dst. Note that unlike glibc's mktime, uClibc's version always normalizes the struct tm before attempting to determine the correct dst setting if tm_isdst == -1 on entry. Add a stub version of the libintl functions. (untested) Fixed a known memory leak in setlocale() related to the collation data. Add lots of new config options (which Erik agreed to sort out :-), including finally exposing some of the stripped down stdio configs. Be careful with those though, as they haven't been tested in a long time. (temporary) GOTCHAs... The ctype functions are currently incorrect for 8-bit locales. They will be fixed shortly. The ctype functions are now table-based, resulting in larger staticly linked binaries. I'll be adding an option to use the old approach in the stub locale configuration. --- libc/stdlib/strtod.c | 711 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 533 insertions(+), 178 deletions(-) (limited to 'libc/stdlib/strtod.c') diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c index 7359d5cf9..c4d95bab1 100644 --- a/libc/stdlib/strtod.c +++ b/libc/stdlib/strtod.c @@ -1,263 +1,618 @@ -/* - * Copyright (C) 2000 Manuel Novoa III +/* Copyright (C) 2000, 2003 Manuel Novoa III * - * Notes: + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * The primary objective of this implementation was minimal size while - * providing robustness and resonable accuracy. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* Notes: + * + * The primary objective of this implementation was minimal size and + * portablility, while providing robustness and resonable accuracy. * * This implementation depends on IEEE floating point behavior and expects * to be able to generate +/- infinity as a result. * * There are a number of compile-time options below. + */ + +/* July 27, 2003 + * + * General cleanup and some minor size optimizations. + * Change implementation to support __strtofpmax() rather than strtod(). + * Now all the strto{floating pt}() funcs are implemented in terms of + * of the internal __strtofpmax() function. + * Support "nan", "inf", and "infinity" strings (case-insensitive). + * Support hexadecimal floating point notation. + * Support wchar variants. + * Support xlocale variants. + * + * TODO: * + * Consider accumulating blocks of digits in longs to save floating pt mults. + * This would likely be much better on anything that only supported floats + * where DECIMAL_DIG == 9. Actually, if floats have FLT_MAX_10_EXP == 38, + * we could calculate almost all the exponent multipliers (p_base) in + * long arithmetic as well. */ -/*****************************************************************************/ -/* OPTIONS */ -/*****************************************************************************/ +/**********************************************************************/ +/* OPTIONS */ +/**********************************************************************/ -/* Set if we want to scale with a O(log2(exp)) multiplications. */ -#define _STRTOD_LOG_SCALING 1 +/* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */ +#define _STRTOD_NAN_INF_STRINGS 1 -/* Set if we want strtod to set errno appropriately. */ -/* NOTE: Implies all options below and pulls in _zero_or_inf_check. */ -#define _STRTOD_ERRNO 0 +/* Defined if we want support hexadecimal floating point notation. (C99) */ +/* Note! Now controlled by uClibc configuration. See below. */ +#define _STRTOD_HEXADECIMAL_FLOATS 1 -/* Set if we want support for the endptr arg. */ +/* Defined if we want to scale with a O(log2(exp)) multiplications. + * This is generally a good thing to do unless you are really tight + * on space and do not expect to convert values of large magnitude. */ + +#define _STRTOD_LOG_SCALING 1 + +/* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! + * + * Clearing any of the options below this point is not advised (or tested). + * + * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! */ + +/* Defined if we want strtod to set errno appropriately. */ +/* NOTE: Implies all options below. */ +#define _STRTOD_ERRNO 1 + +/* Defined if we want support for the endptr arg. */ /* Implied by _STRTOD_ERRNO. */ -#define _STRTOD_ENDPTR 1 +#define _STRTOD_ENDPTR 1 -/* Set if we want to prevent overflow in accumulating the exponent. */ -#define _STRTOD_RESTRICT_EXP 1 +/* Defined if we want to prevent overflow in accumulating the exponent. */ +/* Implied by _STRTOD_ERRNO. */ +#define _STRTOD_RESTRICT_EXP 1 -/* Set if we want to process mantissa digits more intelligently. */ +/* Defined if we want to process mantissa digits more intelligently. */ /* Implied by _STRTOD_ERRNO. */ #define _STRTOD_RESTRICT_DIGITS 1 -/* Set if we want to skip scaling 0 for the exponent. */ +/* Defined if we want to skip scaling 0 for the exponent. */ /* Implied by _STRTOD_ERRNO. */ -#define _STRTOD_ZERO_CHECK 0 +#define _STRTOD_ZERO_CHECK 1 -/*****************************************************************************/ -/* Don't change anything that follows. */ -/*****************************************************************************/ +/**********************************************************************/ +/* Don't change anything that follows. */ +/**********************************************************************/ -#if _STRTOD_ERRNO +#ifdef _STRTOD_ERRNO #undef _STRTOD_ENDPTR #undef _STRTOD_RESTRICT_EXP #undef _STRTOD_RESTRICT_DIGITS #undef _STRTOD_ZERO_CHECK -#define _STRTOD_ENDPTR 1 -#define _STRTOD_RESTRICT_EXP 1 +#define _STRTOD_ENDPTR 1 +#define _STRTOD_RESTRICT_EXP 1 #define _STRTOD_RESTRICT_DIGITS 1 -#define _STRTOD_ZERO_CHECK 1 +#define _STRTOD_ZERO_CHECK 1 #endif -/*****************************************************************************/ +/**********************************************************************/ +#define _ISOC99_SOURCE 1 +#define _GNU_SOURCE #include - +#include +#include +#include +#include #include +#include + +#include -#if _STRTOD_RESTRICT_DIGITS -#define MAX_SIG_DIGITS 20 -#define EXP_DENORM_ADJUST MAX_SIG_DIGITS -#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + EXP_DENORM_ADJUST - DBL_MIN_10_EXP) +#ifdef __UCLIBC_HAS_WCHAR__ + +#include +#include +#include -#if DBL_DIG > MAX_SIG_DIGITS -#error need to adjust MAX_SIG_DIGITS #endif -#include +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#endif /* __UCLIBC_HAS_XLOCALE__ */ + + + +/* Handle _STRTOD_HEXADECIMAL_FLOATS via uClibc config now. */ +#undef _STRTOD_HEXADECIMAL_FLOATS +#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ +#define _STRTOD_HEXADECIMAL_FLOATS 1 +#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ + +/**********************************************************************/ + +#undef _STRTOD_FPMAX + +#if FPMAX_TYPE == 3 + +#define NEED_STRTOLD_WRAPPER +#define NEED_STRTOD_WRAPPER +#define NEED_STRTOF_WRAPPER + +#elif FPMAX_TYPE == 2 + +#define NEED_STRTOD_WRAPPER +#define NEED_STRTOF_WRAPPER + +#elif FPMAX_TYPE == 1 + +#define NEED_STRTOF_WRAPPER + +#else + +#error unknown FPMAX_TYPE! + +#endif + +extern void __fp_range_check(__fpmax_t y, __fpmax_t x); + +/**********************************************************************/ + +#ifdef _STRTOD_RESTRICT_DIGITS +#define EXP_DENORM_ADJUST DECIMAL_DIG +#define MAX_ALLOWED_EXP (DECIMAL_DIG + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP) + #if MAX_ALLOWED_EXP > INT_MAX #error size assumption violated for MAX_ALLOWED_EXP #endif #else /* We want some excess if we're not restricting mantissa digits. */ -#define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2) +#define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2) #endif -#include -/* Note: For i386 the macro resulted in smaller code than the function call. */ -#if 1 -#undef isdigit -#define isdigit(x) ( (x >= '0') && (x <= '9') ) + +#if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS) +#undef _STRTOD_NEED_NUM_DIGITS +#define _STRTOD_NEED_NUM_DIGITS 1 #endif -#if _STRTOD_ERRNO -#include -extern int _zero_or_inf_check(double x); +/**********************************************************************/ +#if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l) + +#if defined(L___wcstofpmax) || defined(L___wcstofpmax_l) + +#define __strtofpmax __wcstofpmax +#define __strtofpmax_l __wcstofpmax_l + +#define Wchar wchar_t +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) iswspace_l((C), locale_arg) +#else +#define ISSPACE(C) iswspace((C)) +#endif + +#else /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */ + +#define Wchar char +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) isspace_l((C), locale_arg) +#else +#define ISSPACE(C) isspace((C)) #endif -double strtod(const char *str, char **endptr) +#endif /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */ + + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) + +__fpmax_t __strtofpmax(const Wchar *str, Wchar **endptr, int exponent_power) { - double number; -#if _STRTOD_LOG_SCALING - double p10; + return __strtofpmax_l(str, endptr, exponent_power, __UCLIBC_CURLOCALE); +} + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + +__fpmax_t __XL(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power + __LOCALE_PARAM ) +{ + __fpmax_t number; + __fpmax_t p_base = 10; /* Adjusted to 16 in the hex case. */ + Wchar *pos0; +#ifdef _STRTOD_ENDPTR + Wchar *pos1; #endif - char *pos0; -#if _STRTOD_ENDPTR - char *pos1; + Wchar *pos = (Wchar *) str; + int exponent_temp; + int negative; /* A flag for the number, a multiplier for the exponent. */ +#ifdef _STRTOD_NEED_NUM_DIGITS + int num_digits; +#endif +#ifdef __UCLIBC_HAS_LOCALE__ + const char *decpt = __LOCALE_PTR->decimal_point; +#if defined(L___wcstofpmax) || defined(L___wcstofpmax) + wchar_t decpt_wc = __LOCALE_PTR->decimal_point; +#else + int decpt_len = __LOCALE_PTR->decimal_point_len; #endif - char *pos = (char *) str; - int exponent_power; - int exponent_temp; - int negative; -#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR - int num_digits; #endif - while (isspace(*pos)) { /* skip leading whitespace */ - ++pos; - } +#ifdef _STRTOD_HEXADECIMAL_FLOATS + Wchar expchar = 'e'; + Wchar *poshex = NULL; + __uint16_t is_mask = _ISdigit; +#define EXPCHAR expchar +#define IS_X_DIGIT(C) __isctype((C), is_mask) +#else /* _STRTOD_HEXADECIMAL_FLOATS */ +#define EXPCHAR 'e' +#define IS_X_DIGIT(C) isdigit((C)) +#endif /* _STRTOD_HEXADECIMAL_FLOATS */ + + while (ISSPACE(*pos)) { /* Skip leading whitespace. */ + ++pos; + } + + negative = 0; + switch(*pos) { /* Handle optional sign. */ + case '-': negative = 1; /* Fall through to increment position. */ + case '+': ++pos; + } - negative = 0; - switch(*pos) { /* handle optional sign */ - case '-': negative = 1; /* fall through to increment position */ - case '+': ++pos; - } +#ifdef _STRTOD_HEXADECIMAL_FLOATS + if ((*pos == '0') && (((pos[1])|0x20) == 'x')) { + poshex = ++pos; /* Save position of 'x' in case no digits */ + ++pos; /* and advance past it. */ + is_mask = _ISxdigit; /* Used by IS_X_DIGIT. */ + expchar = 'p'; /* Adjust exponent char. */ + p_base = 16; /* Adjust base multiplier. */ + } +#endif - number = 0.; -#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR - num_digits = -1; + number = 0.; +#ifdef _STRTOD_NEED_NUM_DIGITS + num_digits = -1; #endif - exponent_power = 0; - pos0 = NULL; +/* exponent_power = 0; */ + pos0 = NULL; LOOP: - while (isdigit(*pos)) { /* process string of digits */ -#if _STRTOD_RESTRICT_DIGITS - if (num_digits < 0) { /* first time through? */ - ++num_digits; /* we've now seen a digit */ + while (IS_X_DIGIT(*pos)) { /* Process string of (hex) digits. */ +#ifdef _STRTOD_RESTRICT_DIGITS + if (num_digits < 0) { /* First time through? */ + ++num_digits; /* We've now seen a digit. */ + } + if (num_digits || (*pos != '0')) { /* Had/have nonzero. */ + ++num_digits; + if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */ +#ifdef _STRTOD_HEXADECIMAL_FLOATS + number = number * p_base + + (isdigit(*pos) + ? (*pos - '0') + : (((*pos)|0x20) - ('a' - 10))); +#else /* _STRTOD_HEXADECIMAL_FLOATS */ + number = number * p_base + (*pos - '0'); +#endif /* _STRTOD_HEXADECIMAL_FLOATS */ + } + } +#else /* _STRTOD_RESTRICT_DIGITS */ +#ifdef _STRTOD_NEED_NUM_DIGITS + ++num_digits; +#endif +#ifdef _STRTOD_HEXADECIMAL_FLOATS + number = number * p_base + + (isdigit(*pos) + ? (*pos - '0') + : (((*pos)|0x20) - ('a' - 10))); +#else /* _STRTOD_HEXADECIMAL_FLOATS */ + number = number * p_base + (*pos - '0'); +#endif /* _STRTOD_HEXADECIMAL_FLOATS */ +#endif /* _STRTOD_RESTRICT_DIGITS */ + ++pos; } - if (num_digits || (*pos != '0')) { /* had/have nonzero */ - ++num_digits; - if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */ - number = number * 10. + (*pos - '0'); - } + +#ifdef __UCLIBC_HAS_LOCALE__ +#if defined(L___wcstofpmax) || defined(L___wcstofpmax) + if (!pos0 && (*pos == decpt_wc)) { /* First decimal point? */ + pos0 = ++pos; + goto LOOP; } #else -#if _STRTOD_ENDPTR - ++num_digits; + if (!pos0 && !memcmp(pos, decpt, decpt_len)) { /* First decimal point? */ + pos0 = (pos += decpt_len); + goto LOOP; + } #endif - number = number * 10. + (*pos - '0'); +#else /* __UCLIBC_HAS_LOCALE__ */ + if ((*pos == '.') && !pos0) { /* First decimal point? */ + pos0 = ++pos; /* Save position of decimal point */ + goto LOOP; /* and process rest of digits. */ + } +#endif /* __UCLIBC_HAS_LOCALE__ */ + +#ifdef _STRTOD_NEED_NUM_DIGITS + if (num_digits<0) { /* Must have at least one digit. */ +#ifdef _STRTOD_HEXADECIMAL_FLOATS + if (poshex) { /* Back up to '0' in '0x' prefix. */ + pos = poshex; + goto DONE; + } +#endif /* _STRTOD_HEXADECIMAL_FLOATS */ + +#ifdef _STRTOD_NAN_INF_STRINGS + if (!pos0) { /* No decimal point, so check for inf/nan. */ + /* Note: nan is the first string so 'number = i/0.;' works. */ + static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0"; + int i = 0; + +#ifdef __UCLIBC_HAS_LOCALE__ + /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/ +#undef _tolower +#define _tolower(C) ((C)|0x20) +#endif /* __UCLIBC_HAS_LOCALE__ */ + + do { + /* Unfortunately, we have no memcasecmp(). */ + int j = 0; + while (_tolower(pos[j]) == nan_inf_str[i+1+j]) { + ++j; + if (!nan_inf_str[i+1+j]) { + number = i / 0.; + if (negative) { /* Correct for sign. */ + number = -number; + } + pos += nan_inf_str[i] - 2; + goto DONE; + } + } + i += nan_inf_str[i]; + } while (nan_inf_str[i]); + } + +#endif /* STRTOD_NAN_INF_STRINGS */ +#ifdef _STRTOD_ENDPTR + pos = (Wchar *) str; #endif - ++pos; - } - - if ((*pos == '.') && !pos0) { /* is this the first decimal point? */ - pos0 = ++pos; /* save position of decimal point */ - goto LOOP; /* and process rest of digits */ - } + goto DONE; + } +#endif /* _STRTOD_NEED_NUM_DIGITS */ -#if _STRTOD_ENDPTR - if (num_digits<0) { /* must have at least one digit */ - pos = (char *) str; - goto DONE; - } +#ifdef _STRTOD_RESTRICT_DIGITS + if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */ + exponent_power += num_digits - DECIMAL_DIG; + } #endif -#if _STRTOD_RESTRICT_DIGITS - if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */ - exponent_power += num_digits - MAX_SIG_DIGITS; - } -#endif + if (pos0) { + exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */ + } + +#ifdef _STRTOD_HEXADECIMAL_FLOATS + if (poshex) { + exponent_power *= 4; /* Above is 2**4, but below is 2. */ + p_base = 2; + } +#endif /* _STRTOD_HEXADECIMAL_FLOATS */ - if (pos0) { - exponent_power += pos0 - pos; /* adjust exponent for decimal point */ - } + if (negative) { /* Correct for sign. */ + number = -number; + } - if (negative) { /* correct for sign */ - number = -number; - negative = 0; /* reset for exponent processing below */ - } + /* process an exponent string */ + if (((*pos)|0x20) == EXPCHAR) { +#ifdef _STRTOD_ENDPTR + pos1 = pos; +#endif + negative = 1; + switch(*++pos) { /* Handle optional sign. */ + case '-': negative = -1; /* Fall through to increment pos. */ + case '+': ++pos; + } + + pos0 = pos; + exponent_temp = 0; + while (isdigit(*pos)) { /* Process string of digits. */ +#ifdef _STRTOD_RESTRICT_EXP + if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */ + exponent_temp = exponent_temp * 10 + (*pos - '0'); + } +#else + exponent_temp = exponent_temp * 10 + (*pos - '0'); +#endif + ++pos; + } - /* process an exponent string */ - if (*pos == 'e' || *pos == 'E') { -#if _STRTOD_ENDPTR - pos1 = pos; +#ifdef _STRTOD_ENDPTR + if (pos == pos0) { /* No digits? */ + pos = pos1; /* Back up to {e|E}/{p|P}. */ + } /* else */ #endif - switch(*++pos) { /* handle optional sign */ - case '-': negative = 1; /* fall through to increment pos */ - case '+': ++pos; + + exponent_power += negative * exponent_temp; } - pos0 = pos; - exponent_temp = 0; - while (isdigit(*pos)) { /* process string of digits */ -#if _STRTOD_RESTRICT_EXP - if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */ - exponent_temp = exponent_temp * 10 + (*pos - '0'); - } -#else - exponent_temp = exponent_temp * 10 + (*pos - '0'); +#ifdef _STRTOD_ZERO_CHECK + if (number == 0.) { + goto DONE; + } #endif - ++pos; + + /* scale the result */ +#ifdef _STRTOD_LOG_SCALING + exponent_temp = exponent_power; + + if (exponent_temp < 0) { + exponent_temp = -exponent_temp; } -#if _STRTOD_ENDPTR - if (pos == pos0) { /* were there no digits? */ - pos = pos1; /* back up to e|E */ - } /* else */ + while (exponent_temp) { + if (exponent_temp & 1) { + if (exponent_power < 0) { + /* Warning... caluclating a factor for the exponent and + * then dividing could easily be faster. But doing so + * might cause problems when dealing with denormals. */ + number /= p_base; + } else { + number *= p_base; + } + } + exponent_temp >>= 1; + p_base *= p_base; + } + +#else /* _STRTOD_LOG_SCALING */ + while (exponent_power) { + if (exponent_power < 0) { + number /= p_base; + exponent_power++; + } else { + number *= p_base; + exponent_power--; + } + } +#endif /* _STRTOD_LOG_SCALING */ + +#ifdef _STRTOD_ERRNO + if (__FPMAX_ZERO_OR_INF_CHECK(number)) { + __set_errno(ERANGE); + } #endif - if (negative) { - exponent_power -= exponent_temp; - } else { - exponent_power += exponent_temp; + + DONE: +#ifdef _STRTOD_ENDPTR + if (endptr) { + *endptr = pos; } - } - -#if _STRTOD_ZERO_CHECK - if (number == 0.) { - goto DONE; - } -#endif - - /* scale the result */ -#if _STRTOD_LOG_SCALING - exponent_temp = exponent_power; - p10 = 10.; - - if (exponent_temp < 0) { - exponent_temp = -exponent_temp; - } - - while (exponent_temp) { - if (exponent_temp & 1) { - if (exponent_power < 0) { - number /= p10; - } else { - number *= p10; - } +#endif + + return number; +} + +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + +#endif +/**********************************************************************/ +#ifdef L___fp_range_check +#if defined(NEED_STRTOF_WRAPPER) || defined(NEED_STRTOD_WRAPPER) + +extern void __fp_range_check(__fpmax_t y, __fpmax_t x) +{ + if (__FPMAX_ZERO_OR_INF_CHECK(y) /* y is 0 or +/- infinity */ + && (y != 0) /* y is not 0 (could have x>0, y==0 if underflow) */ + && !__FPMAX_ZERO_OR_INF_CHECK(x) /* x is not 0 or +/- infinity */ + ) { + __set_errno(ERANGE); /* Then x is not in y's range. */ } - exponent_temp >>= 1; - p10 *= p10; - } +} + +#endif +#endif +/**********************************************************************/ +#if defined(L_strtof) || defined(L_strtof_l) || defined(L_wcstof) || defined(L_wcstof_l) +#if defined(NEED_STRTOF_WRAPPER) + +#if defined(L_wcstof) || defined(L_wcstof_l) +#define strtof wcstof +#define strtof_l wcstof_l +#define __strtofpmax __wcstofpmax +#define __strtofpmax_l __wcstofpmax_l +#define Wchar wchar_t #else - while (exponent_power) { - if (exponent_power < 0) { - number /= 10.; - exponent_power++; - } else { - number *= 10.; - exponent_power--; - } - } +#define Wchar char #endif -#if _STRTOD_ERRNO - if (_zero_or_inf_check(number)) { - __set_errno(ERANGE); - } + +float __XL(strtof)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) +{ +#if FPMAX_TYPE == 1 + return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); +#else + __fpmax_t x; + float y; + + x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); + y = (float) x; + + __fp_range_check(y, x); + + return y; #endif +} - DONE: -#if _STRTOD_ENDPTR - if (endptr) { - *endptr = pos; - } #endif +#endif +/**********************************************************************/ +#if defined(L_strtod) || defined(L_strtod_l) || defined(L_wcstod) || defined(L_wcstod_l) +#if defined(NEED_STRTOD_WRAPPER) + +#if defined(L_wcstod) || defined(L_wcstod_l) +#define strtod wcstod +#define strtod_l wcstod_l +#define __strtofpmax __wcstofpmax +#define __strtofpmax_l __wcstofpmax_l +#define Wchar wchar_t +#else +#define Wchar char +#endif + +double __XL(strtod)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) +{ +#if FPMAX_TYPE == 2 + return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); +#else + __fpmax_t x; + double y; + + x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); + y = (double) x; + + __fp_range_check(y, x); - return number; + return y; +#endif } + +#endif +#endif +/**********************************************************************/ +#if defined(L_strtold) || defined(L_strtold_l) || defined(L_wcstold) || defined(L_wcstold_l) +#if defined(NEED_STRTOLD_WRAPPER) + +#if defined(L_wcstold) || defined(L_wcstold_l) +#define strtold wcstold +#define strtold_l wcstold_l +#define __strtofpmax __wcstofpmax +#define __strtofpmax_l __wcstofpmax_l +#define Wchar wchar_t +#else +#define Wchar char +#endif + +long double __XL(strtold)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) +{ +#if FPMAX_TYPE == 3 + return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); +#else + __fpmax_t x; + long double y; + + x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); + y = (long double) x; + + __fp_range_check(y, x); + + return y; +#endif +} + +#endif +#endif +/**********************************************************************/ -- cgit v1.2.3