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/Makefile | 48 +++- libc/stdlib/stdlib.c | 252 +++++++++++++----- libc/stdlib/strtod.c | 711 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 766 insertions(+), 245 deletions(-) (limited to 'libc/stdlib') diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile index 59a5a6e0c..01765c1f6 100644 --- a/libc/stdlib/Makefile +++ b/libc/stdlib/Makefile @@ -38,31 +38,57 @@ MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o \ qsort.o bsearch.o \ llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o # (aliases) strtoq.o strtouq.o +ifeq ($(UCLIBC_HAS_XLOCALE),y) + +MOBJx = +MOBJx += strtol_l.o strtoul_l.o _stdlib_strto_l_l.o \ + strtoll_l.o strtoull_l.o _stdlib_strto_ll_l.o +endif + +MSRC1 = strtod.c +MOBJ1 = +MOBJ1x = + ifeq ($(UCLIBC_HAS_FLOATS),y) MOBJ += atof.o + MOBJ1 += strtod.o strtof.o strtold.o __strtofpmax.o __fp_range_check.o +ifeq ($(UCLIBC_HAS_XLOCALE),y) + MOBJ1x += strtod_l.o strtof_l.o strtold_l.o __strtofpmax_l.o +endif +ifeq ($(UCLIBC_HAS_WCHAR),y) + MOBJ1 += wcstod.o wcstof.o wcstold.o __wcstofpmax.o +ifeq ($(UCLIBC_HAS_XLOCALE),y) + MOBJ1x += wcstod_l.o wcstof_l.o wcstold_l.o __wcstofpmax_l.o +endif +endif endif ifeq ($(UCLIBC_HAS_WCHAR),y) MOBJ += mblen.o mbtowc.o wctomb.o mbstowcs.o wcstombs.o \ _stdlib_mb_cur_max.o _stdlib_wcsto_l.o _stdlib_wcsto_ll.o \ wcstol.o wcstoul.o wcstoll.o wcstoull.o +ifeq ($(UCLIBC_HAS_XLOCALE),y) + MOBJx += _stdlib_wcsto_l_l.o _stdlib_wcsto_ll_l.o \ + wcstol_l.o wcstoul_l.o wcstoll_l.o wcstoull_l.o +endif +endif # (aliases) wcstoq.o wcstouq.o # wcstod wcstof wcstold -endif -MSRC2=atexit.c -MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o +MSRC2 = atexit.c +MOBJ2 = atexit.o on_exit.o __exit_handler.o exit.o + CSRC = abort.c getenv.c mkdtemp.c mktemp.c realpath.c mkstemp.c mkstemp64.c \ rand.c random.c random_r.c setenv.c system.c div.c ldiv.c getpt.c \ ptsname.c grantpt.c unlockpt.c gcvt.c drand48-iter.c jrand48.c \ jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \ nrand48_r.c rand_r.c srand48.c srand48_r.c calloc.c valloc.c ifeq ($(UCLIBC_HAS_FLOATS),y) - CSRC += strtod.c strtof.c strtold.c drand48.c drand48_r.c erand48.c erand48_r.c + CSRC += drand48.c drand48_r.c erand48.c erand48_r.c endif COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(MOBJ) $(MOBJ2) $(COBJS) +OBJS=$(MOBJ) $(MOBJx) $(MOBJ1) $(MOBJ1x) $(MOBJ2) $(COBJS) all: $(OBJS) $(LIBC) @@ -75,6 +101,18 @@ $(MOBJ): $(MSRC) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o +$(MOBJx): $(MSRC) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(MOBJ1): $(MSRC1) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + +$(MOBJ1x): $(MSRC1) + $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o + $(STRIPTOOL) -x -R .note -R .comment $*.o + $(MOBJ2): $(MSRC2) $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o $(STRIPTOOL) -x -R .note -R .comment $*.o diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index 122289c2c..68b1af8b7 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -56,15 +56,24 @@ #define strtoull __ignore_strtoull #define wcstoll __ignore_wcstoll #define wcstoull __ignore_wcstoull +#define strtoll_l __ignore_strtoll_l +#define strtoull_l __ignore_strtoull_l +#define wcstoll_l __ignore_wcstoll_l +#define wcstoull_l __ignore_wcstoull_l #endif #include +#include #ifdef __UCLIBC_HAS_WCHAR__ -#include #include #include +#include + +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#endif /* __UCLIBC_HAS_XLOCALE__ */ /* TODO: clean up the following... */ @@ -75,15 +84,23 @@ #endif #ifdef __UCLIBC_HAS_LOCALE__ -#define ENCODING (__global_locale.encoding) + +#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding) #ifndef __CTYPE_HAS_UTF_8_LOCALES +#ifdef L_mblen +/* emit only once */ #warning __CTYPE_HAS_UTF_8_LOCALES not set! #endif -#else +#endif + +#else /* __UCLIBC_HAS_LOCALE__ */ + #ifdef __UCLIBC_MJN3_ONLY__ +#ifdef L_mblen +/* emit only once */ #warning devel checks #endif -#define ENCODING (__ctype_encoding_7_bit) +#endif #ifdef __CTYPE_HAS_8_BIT_LOCALES #error __CTYPE_HAS_8_BIT_LOCALES is defined! #endif @@ -92,7 +109,7 @@ #endif #endif -#endif +#endif /* __UCLIBC_HAS_LOCALE__ */ #if UINT_MAX == ULONG_MAX #undef atoi @@ -105,9 +122,44 @@ #undef strtoull #undef wcstoll #undef wcstoull +#undef strtoll_l +#undef strtoull_l +#undef wcstoll_l +#undef wcstoull_l #endif /* __UCLIBC_HAS_WCHAR__ */ /**********************************************************************/ +#ifdef __UCLIBC_HAS_XLOCALE__ + +extern unsigned long +_stdlib_strto_l_l(register const char * __restrict str, + char ** __restrict endptr, int base, int sflag, + __locale_t locale_arg); + +#if defined(ULLONG_MAX) +extern unsigned long long +_stdlib_strto_ll_l(register const char * __restrict str, + char ** __restrict endptr, int base, int sflag, + __locale_t locale_arg); +#endif + +#ifdef __UCLIBC_HAS_WCHAR__ +extern unsigned long +_stdlib_wcsto_l_l(register const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base, int sflag, + __locale_t locale_arg); + +#if defined(ULLONG_MAX) +extern unsigned long long +_stdlib_wcsto_ll_l(register const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base, int sflag, + __locale_t locale_arg); +#endif +#endif /* __UCLIBC_HAS_WCHAR__ */ + +#endif /* __UCLIBC_HAS_XLOCALE__ */ + + extern unsigned long _stdlib_strto_l(register const char * __restrict str, @@ -130,7 +182,6 @@ _stdlib_wcsto_ll(register const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base, int sflag); #endif #endif /* __UCLIBC_HAS_WCHAR__ */ - /**********************************************************************/ #ifdef L_atof @@ -235,73 +286,82 @@ long long atoll(const char *nptr) #endif /**********************************************************************/ -#ifdef L_strtol +#if defined(L_strtol) || defined(L_strtol_l) -#if ULONG_MAX == UINTMAX_MAX +#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtol_l) strong_alias(strtol,strtoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -strong_alias(strtol,strtoll) +strong_alias(__XL(strtol),__XL(strtoll)) #endif -long strtol(const char * __restrict str, char ** __restrict endptr, int base) +long __XL(strtol)(const char * __restrict str, char ** __restrict endptr, + int base __LOCALE_PARAM ) { - return _stdlib_strto_l(str, endptr, base, 1); + return __XL(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG ); } #endif /**********************************************************************/ -#ifdef L_strtoll +#if defined(L_strtoll) || defined(L_strtoll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) +#if !defined(L_strtoll_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(strtoll,strtoimax) #endif strong_alias(strtoll,strtoq) +#endif -long long strtoll(const char * __restrict str, - char ** __restrict endptr, int base) +long long __XL(strtoll)(const char * __restrict str, + char ** __restrict endptr, int base + __LOCALE_PARAM ) { - return (long long) _stdlib_strto_ll(str, endptr, base, 1); + return (long long) __XL(_stdlib_strto_ll)(str, endptr, base, 1 + __LOCALE_ARG ); } #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ -#ifdef L_strtoul +#if defined(L_strtoul) || defined(L_strtoul_l) -#if ULONG_MAX == UINTMAX_MAX +#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtoul_l) strong_alias(strtoul,strtoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -strong_alias(strtoul,strtoull) +strong_alias(__XL(strtoul),__XL(strtoull)) #endif -unsigned long strtoul(const char * __restrict str, - char ** __restrict endptr, int base) +unsigned long __XL(strtoul)(const char * __restrict str, + char ** __restrict endptr, int base + __LOCALE_PARAM ) { - return _stdlib_strto_l(str, endptr, base, 0); + return __XL(_stdlib_strto_l)(str, endptr, base, 0 __LOCALE_ARG ); } #endif /**********************************************************************/ -#ifdef L_strtoull +#if defined(L_strtoull) || defined(L_strtoull_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) +#if !defined(L_strtoull_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(strtoull,strtoumax) #endif strong_alias(strtoull,strtouq) +#endif -unsigned long long strtoull(const char * __restrict str, - char ** __restrict endptr, int base) +unsigned long long __XL(strtoull)(const char * __restrict str, + char ** __restrict endptr, int base + __LOCALE_PARAM ) { - return _stdlib_strto_ll(str, endptr, base, 0); + return __XL(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG ); } #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ @@ -327,26 +387,54 @@ unsigned long long strtoull(const char * __restrict str, #endif /**********************************************************************/ -#ifdef L__stdlib_wcsto_l +#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) #define L__stdlib_strto_l #endif -#ifdef L__stdlib_strto_l +#if defined(L__stdlib_strto_l) || defined(L__stdlib_strto_l_l) + +#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) -#ifdef L__stdlib_wcsto_l #define _stdlib_strto_l _stdlib_wcsto_l +#define _stdlib_strto_l_l _stdlib_wcsto_l_l #define Wchar wchar_t -#define ISSPACE iswspace +#define Wuchar __uwchar_t +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) iswspace_l((C), locale_arg) #else +#define ISSPACE(C) iswspace((C)) +#endif + +#else /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ + #define Wchar char -#define ISSPACE isspace +#define Wuchar unsigned char +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) isspace_l((C), locale_arg) +#else +#define ISSPACE(C) isspace((C)) #endif +#endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) + +unsigned long _stdlib_strto_l(register const Wchar * __restrict str, + Wchar ** __restrict endptr, int base, + int sflag) +{ + return _stdlib_strto_l_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); +} + + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + /* This is the main work fuction which handles both strtol (sflag = 1) and * strtoul (sflag = 0). */ -unsigned long _stdlib_strto_l(register const Wchar * __restrict str, - Wchar ** __restrict endptr, int base, int sflag) +unsigned long __XL(_stdlib_strto_l)(register const Wchar * __restrict str, + Wchar ** __restrict endptr, int base, + int sflag __LOCALE_PARAM ) { unsigned long number, cutoff; #if _STRTO_ENDPTR @@ -361,7 +449,7 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str, SET_FAIL(str); - while (ISSPACE(*str)) { /* Skip leading whitespace. */ + while (ISSPACE(*str)) { /* Skip leading whitespace. */ ++str; } @@ -394,7 +482,7 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str, cutoff_digit = ULONG_MAX % base; cutoff = ULONG_MAX / base; do { - digit = (((unsigned char)(*str - '0')) <= 9) + digit = (((Wuchar)(*str - '0')) <= 9) ? (*str - '0') : ((*str >= 'A') ? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */ @@ -436,31 +524,60 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str, return negative ? (unsigned long)(-((long)number)) : number; } +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + + #endif /**********************************************************************/ -#ifdef L__stdlib_wcsto_ll +#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) #define L__stdlib_strto_ll #endif -#ifdef L__stdlib_strto_ll +#if defined(L__stdlib_strto_ll) || defined(L__stdlib_strto_ll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -#ifdef L__stdlib_wcsto_ll +#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) #define _stdlib_strto_ll _stdlib_wcsto_ll +#define _stdlib_strto_ll_l _stdlib_wcsto_ll_l #define Wchar wchar_t -#define ISSPACE iswspace +#define Wuchar __uwchar_t +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) iswspace_l((C), locale_arg) #else +#define ISSPACE(C) iswspace((C)) +#endif + +#else /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ + #define Wchar char -#define ISSPACE isspace +#define Wuchar unsigned char +#ifdef __UCLIBC_DO_XLOCALE +#define ISSPACE(C) isspace_l((C), locale_arg) +#else +#define ISSPACE(C) isspace((C)) #endif -/* This is the main work fuction which handles both strtoll (sflag = 1) and - * strtoull (sflag = 0). */ +#endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag) +{ + return _stdlib_strto_ll_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); +} + + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + +/* This is the main work fuction which handles both strtoll (sflag = 1) and + * strtoull (sflag = 0). */ + +unsigned long long __XL(_stdlib_strto_ll)(register const Wchar * __restrict str, + Wchar ** __restrict endptr, int base, + int sflag __LOCALE_PARAM ) { unsigned long long number; #if _STRTO_ENDPTR @@ -507,7 +624,7 @@ unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str, if (((unsigned)(base - 2)) < 35) { /* Legal base. */ do { - digit = (((unsigned char)(*str - '0')) <= 9) + digit = (((Wuchar)(*str - '0')) <= 9) ? (*str - '0') : ((*str >= 'A') ? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */ @@ -560,6 +677,8 @@ unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str, return negative ? (unsigned long long)(-((long long)number)) : number; } +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif @@ -715,7 +834,7 @@ void ssort (void *base, size_t _stdlib_mb_cur_max(void) { #ifdef __CTYPE_HAS_UTF_8_LOCALES - return __global_locale.mb_cur_max; + return __UCLIBC_CURLOCALE_DATA.mb_cur_max; #else #ifdef __CTYPE_HAS_8_BIT_LOCALES #ifdef __UCLIBC_MJN3_ONLY__ @@ -824,73 +943,82 @@ size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) #endif /**********************************************************************/ -#ifdef L_wcstol +#if defined(L_wcstol) || defined(L_wcstol_l) -#if ULONG_MAX == UINTMAX_MAX +#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l) strong_alias(wcstol,wcstoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -strong_alias(wcstol,wcstoll) +strong_alias(__XL(wcstol),__XL(wcstoll)) #endif -long wcstol(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base) +long __XL(wcstol)(const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base __LOCALE_PARAM ) { - return _stdlib_wcsto_l(str, endptr, base, 1); + return __XL(_stdlib_wcsto_l)(str, endptr, base, 1 __LOCALE_ARG ); } #endif /**********************************************************************/ -#ifdef L_wcstoll +#if defined(L_wcstoll) || defined(L_wcstoll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) +#if !defined(L_wcstoll_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(wcstoll,wcstoimax) #endif strong_alias(wcstoll,wcstoq) +#endif -long long wcstoll(const wchar_t * __restrict str, - wchar_t ** __restrict endptr, int base) +long long __XL(wcstoll)(const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base + __LOCALE_PARAM ) { - return (long long) _stdlib_wcsto_ll(str, endptr, base, 1); + return (long long) __XL(_stdlib_wcsto_ll)(str, endptr, base, 1 + __LOCALE_ARG ); } #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ -#ifdef L_wcstoul +#if defined(L_wcstoul) || defined(L_wcstoul_l) -#if ULONG_MAX == UINTMAX_MAX +#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l) strong_alias(wcstoul,wcstoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -strong_alias(wcstoul,wcstoull) +strong_alias(__XL(wcstoul),__XL(wcstoull)) #endif -unsigned long wcstoul(const wchar_t * __restrict str, - wchar_t ** __restrict endptr, int base) +unsigned long __XL(wcstoul)(const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base + __LOCALE_PARAM ) { - return _stdlib_wcsto_l(str, endptr, base, 0); + return __XL(_stdlib_wcsto_l)(str, endptr, base, 0 __LOCALE_ARG ); } #endif /**********************************************************************/ -#ifdef L_wcstoull +#if defined(L_wcstoull) || defined(L_wcstoull_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) +#if !defined(L_wcstoull_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(wcstoull,wcstoumax) #endif strong_alias(wcstoull,wcstouq) +#endif -unsigned long long wcstoull(const wchar_t * __restrict str, - wchar_t ** __restrict endptr, int base) +unsigned long long __XL(wcstoull)(const wchar_t * __restrict str, + wchar_t ** __restrict endptr, int base + __LOCALE_PARAM ) { - return _stdlib_wcsto_ll(str, endptr, base, 0); + return __XL(_stdlib_wcsto_ll)(str, endptr, base, 0 __LOCALE_ARG ); } #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ 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