From 120594079a3b71d430e6183130eac6691c52312a Mon Sep 17 00:00:00 2001 From: lilei19 Date: Thu, 12 Jan 2023 18:54:53 +0800 Subject: [PATCH] add function for strtof --- LICENSE | 1 + libs/libc/stdlib/Make.defs | 4 +- libs/libc/stdlib/lib_strtod.c | 343 ------------ libs/libc/stdlib/lib_strtof.c | 343 ------------ libs/libc/stdlib/lib_strtold.c | 980 +++++++++++++++++++++++++-------- 5 files changed, 749 insertions(+), 922 deletions(-) delete mode 100644 libs/libc/stdlib/lib_strtod.c delete mode 100644 libs/libc/stdlib/lib_strtof.c diff --git a/LICENSE b/LICENSE index 09d6c548ff..a071cbda57 100644 --- a/LICENSE +++ b/LICENSE @@ -5891,6 +5891,7 @@ POSSIBILITY OF SUCH DAMAGE. libs/libc/math/scalbnf.c libs/libc/math/scalbn.c libs/libc/math/scalbnl.c +libs/libc/stdlib/lib_strtof.c ====================== Copyright © 2005-2020 Rich Felker, et al. diff --git a/libs/libc/stdlib/Make.defs b/libs/libc/stdlib/Make.defs index 2692f315d6..b150568112 100644 --- a/libs/libc/stdlib/Make.defs +++ b/libs/libc/stdlib/Make.defs @@ -24,8 +24,8 @@ CSRCS += lib_abs.c lib_abort.c lib_atof.c lib_atoi.c lib_getprogname.c CSRCS += lib_atol.c lib_atoll.c lib_div.c lib_ldiv.c lib_lldiv.c lib_exit.c CSRCS += lib_itoa.c lib_labs.c lib_llabs.c lib_realpath.c lib_bsearch.c CSRCS += lib_rand.c lib_rand48.c lib_qsort.c lib_srand.c lib_strtol.c -CSRCS += lib_strtoll.c lib_strtoul.c lib_strtoull.c lib_strtod.c lib_strtof.c -CSRCS += lib_strtold.c lib_checkbase.c lib_mktemp.c lib_mkstemp.c lib_mkdtemp.c +CSRCS += lib_strtoll.c lib_strtoul.c lib_strtoull.c lib_strtold.c +CSRCS += lib_checkbase.c lib_mktemp.c lib_mkstemp.c lib_mkdtemp.c CSRCS += lib_aligned_alloc.c lib_posix_memalign.c lib_valloc.c lib_mblen.c CSRCS += lib_mbtowc.c lib_wctomb.c lib_mbstowcs.c lib_wcstombs.c CSRCS += lib_atexit.c lib_cxa_atexit.c lib_onexit.c diff --git a/libs/libc/stdlib/lib_strtod.c b/libs/libc/stdlib/lib_strtod.c deleted file mode 100644 index 6085e9cf58..0000000000 --- a/libs/libc/stdlib/lib_strtod.c +++ /dev/null @@ -1,343 +0,0 @@ -/**************************************************************************** - * libs/libc/stdlib/lib_strtod.c - * Convert string to double - * - * Copyright (C) 2002 Michael Ringgaard. All rights reserved. - * Copyright (C) 2006-2007 H. Peter Anvin. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -#include -#include -#include - -#include - -#ifdef CONFIG_HAVE_DOUBLE - -/**************************************************************************** - * Pre-processor definitions - ****************************************************************************/ - -/* These are predefined with GCC, but could be issues for other compilers. If - * not defined, an arbitrary big number is put in for now. These should be - * added to nuttx/compiler for your compiler. - */ - -#if !defined(__DBL_MIN_EXP__) || !defined(__DBL_MAX_EXP__) -# ifdef CONFIG_CPP_HAVE_WARNING -# warning "Size of exponent is unknown" -# endif -# undef __DBL_MIN_EXP__ -# define __DBL_MIN_EXP__ (-1021) -# undef __DBL_MAX_EXP__ -# define __DBL_MAX_EXP__ (1024) -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static inline int is_real(double x) -{ - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ - - const double divzero = 0.0; - const double infinite = 1.0 / divzero; - return (x < infinite) && (x >= -infinite); -} - -static bool chtod(char c, double base, FAR double *number) -{ - /* This function is to determine if c is keyword - * Then set number + base - */ - - double tmp = base; - - if (isdigit(c)) - { - tmp = c - '0'; - } - else if (c >= 'a' && c <= 'f') - { - tmp = c - 'a' + 10; - } - else if (c >= 'A' && c <= 'F') - { - tmp = c - 'A' + 10; - } - - if (tmp >= base) - { - return false; - } - - *number = *number * base + tmp; - return true; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: strtod - * - * Description: - * Convert a string to a double value - * - * NOTE: This implementation is limited as compared to POSIX: - * - Hexadecimal input is not supported - * - INF, INFINITY, NAN, and NAN(...) are not supported - * - ****************************************************************************/ - -double strtod(FAR const char *str, FAR char **endptr) -{ - double number; - int exponent; - int negative; - FAR char *p = (FAR char *) str; - double p10; - int n; - int num_digits; - int num_decimals; - - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ - - const double divzero = 0.0; - const double infinite = 1.0 / divzero; - - /* Skip leading whitespace */ - - while (isspace(*p)) - { - p++; - } - - /* Handle optional sign */ - - negative = 0; - switch (*p) - { - case '-': - negative = 1; /* Fall through to increment position */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - p10 = 10.; - number = 0.; - exponent = 0; - num_digits = 0; - num_decimals = 0; - - /* Process optional 0x prefix */ - - if (*p == '0' && tolower(*(p + 1)) == 'x') - { - p += 2; - p10 = 16.; - } - - /* Process string of digits */ - - while (chtod(*p, p10, &number)) - { - p++; - num_digits++; - } - - /* Process decimal part */ - - if (*p == '.') - { - p++; - - while (chtod(*p, p10, &number)) - { - p++; - num_digits++; - num_decimals++; - } - - exponent -= num_decimals; - } - - if (num_digits == 0) - { - set_errno(ERANGE); - number = 0.0; - p = (FAR char *)str; - goto errout; - } - - /* Correct for sign */ - - if (negative) - { - number = -number; - } - - /* Process an exponent string */ - - if ((p10 == 10. && (*p == 'e' || *p == 'E')) - || (p10 == 16. && (*p == 'p' || *p == 'P'))) - { - /* if the Hexadecimal system */ - - if (p10 == 16.) - { - exponent *= 4; - p10 = 2.0; - } - - /* Handle optional sign */ - - negative = 0; - switch (*++p) - { - case '-': - negative = 1; /* Fall through to increment pos */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - /* Process string of digits */ - - if (!isdigit(*p)) - { - set_errno(ERANGE); - number = 0.0; - p = (FAR char *)str; - goto errout; - } - - n = 0; - while (isdigit(*p)) - { - n = n * 10 + (*p - '0'); - p++; - } - - if (negative) - { - exponent -= n; - } - else - { - exponent += n; - } - } - - if (exponent < __DBL_MIN_EXP__ || - exponent > __DBL_MAX_EXP__) - { - set_errno(ERANGE); - if (exponent < __DBL_MIN_EXP__) - { - number = divzero; - } - else - { - number = infinite; - } - - goto errout; - } - - /* Scale the result */ - - n = exponent; - if (n < 0) - { - n = -n; - } - - while (n) - { - if (n & 1) - { - if (exponent < 0) - { - number /= p10; - } - else - { - number *= p10; - } - } - - n >>= 1; - p10 *= p10; - } - - if (!is_real(number)) - { - set_errno(ERANGE); - } - -errout: - if (endptr) - { - *endptr = p; - } - - return number; -} - -#endif /* CONFIG_HAVE_DOUBLE */ diff --git a/libs/libc/stdlib/lib_strtof.c b/libs/libc/stdlib/lib_strtof.c deleted file mode 100644 index 49cda38723..0000000000 --- a/libs/libc/stdlib/lib_strtof.c +++ /dev/null @@ -1,343 +0,0 @@ -/**************************************************************************** - * libs/libc/stdlib/lib_strtof.c - * Convert string to float - * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. - * - * A pretty straight forward conversion fo strtod(): - * - * Copyright (C) 2002 Michael Ringgaard. All rights reserved. - * Copyright (C) 2006-2007 H. Peter Anvin. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -#include -#include -#include - -#include - -/**************************************************************************** - * Pre-processor definitions - ****************************************************************************/ - -/* These are predefined with GCC, but could be issues for other compilers. If - * not defined, an arbitrary big number is put in for now. These should be - * added to nuttx/compiler for your compiler. - */ - -#if !defined(__FLT_MIN_EXP__) || !defined(__FLT_MAX_EXP__) -# ifdef CONFIG_CPP_HAVE_WARNING -# warning "Size of exponent is unknown" -# endif -# undef __FLT_MIN_EXP__ -# define __FLT_MIN_EXP__ (-125) -# undef __FLT_MAX_EXP__ -# define __FLT_MAX_EXP__ (128) -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static inline int is_real(float x) -{ - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ - - float divzero = 0.0F; - const float infinite = 1.0F / divzero; - return (x < infinite) && (x >= -infinite); -} - -static bool chtof(char c, float base, FAR float *number) -{ - /* This function is to determine if c is keyword - * Then set number + base - */ - - float tmp = base; - - if (isdigit(c)) - { - tmp = c - '0'; - } - else if (c >= 'a' && c <= 'f') - { - tmp = c - 'a' + 10; - } - else if (c >= 'A' && c <= 'F') - { - tmp = c - 'A' + 10; - } - - if (tmp >= base) - { - return false; - } - - *number = *number * base + tmp; - return true; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: strtof - * - * Description: - * Convert a string to a float value - * - * NOTE: This implementation is limited as compared to POSIX: - * - Hexadecimal input is not supported - * - INF, INFINITY, NAN, and NAN(...) are not supported - * - ****************************************************************************/ - -float strtof(FAR const char *str, FAR char **endptr) -{ - float number; - int exponent; - int negative; - FAR char *p = (FAR char *) str; - float p10; - int n; - int num_digits; - int num_decimals; - - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ - - float divzero = 0.0F; - const float infinite = 1.0F / divzero; - - /* Skip leading whitespace */ - - while (isspace(*p)) - { - p++; - } - - /* Handle optional sign */ - - negative = 0; - switch (*p) - { - case '-': - negative = 1; /* Fall through to increment position */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - p10 = 10.0f; - number = 0.0F; - exponent = 0; - num_digits = 0; - num_decimals = 0; - - /* Process optional 0x prefix */ - - if (*p == '0' && tolower(*(p + 1)) == 'x') - { - p += 2; - p10 = 16.0f; - } - - /* Process string of digits */ - - while (chtof(*p, p10, &number)) - { - p++; - num_digits++; - } - - /* Process decimal part */ - - if (*p == '.') - { - p++; - - while (chtof(*p, p10, &number)) - { - p++; - num_digits++; - num_decimals++; - } - - exponent -= num_decimals; - } - - if (num_digits == 0) - { - set_errno(ERANGE); - number = 0.0F; - p = (FAR char *)str; - goto errout; - } - - /* Correct for sign */ - - if (negative) - { - number = -number; - } - - /* Process an exponent string */ - - if ((p10 == 10.0f && (*p == 'e' || *p == 'E')) - || (p10 == 16.0f && (*p == 'p' || *p == 'P'))) - { - /* if the Hexadecimal system */ - - if (p10 == 16.0f) - { - exponent *= 4; - p10 = 2.0f; - } - - /* Handle optional sign */ - - negative = 0; - switch (*++p) - { - case '-': - negative = 1; /* Fall through to increment pos */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - /* Process string of digits */ - - if (!isdigit(*p)) - { - set_errno(ERANGE); - number = 0.0F; - p = (FAR char *)str; - goto errout; - } - - n = 0; - while (isdigit(*p)) - { - n = n * 10 + (*p - '0'); - p++; - } - - if (negative) - { - exponent -= n; - } - else - { - exponent += n; - } - } - - if (exponent < __FLT_MIN_EXP__ || - exponent > __FLT_MAX_EXP__) - { - set_errno(ERANGE); - if (exponent < __FLT_MIN_EXP__) - { - number = divzero; - } - else - { - number = infinite; - } - - goto errout; - } - - /* Scale the result */ - - n = exponent; - if (n < 0) - { - n = -n; - } - - while (n) - { - if (n & 1) - { - if (exponent < 0) - { - number /= p10; - } - else - { - number *= p10; - } - } - - n >>= 1; - p10 *= p10; - } - - if (!is_real(number)) - { - set_errno(ERANGE); - } - -errout: - if (endptr) - { - *endptr = p; - } - - return number; -} diff --git a/libs/libc/stdlib/lib_strtold.c b/libs/libc/stdlib/lib_strtold.c index a043412d04..13ed2ccf1d 100644 --- a/libs/libc/stdlib/lib_strtold.c +++ b/libs/libc/stdlib/lib_strtold.c @@ -1,35 +1,29 @@ /**************************************************************************** * libs/libc/stdlib/lib_strtold.c - * Convert string to long double + * Convert string to float and (long) double * - * Copyright (C) 2002 Michael Ringgaard. All rights reserved. - * Copyright (C) 2006-2007 H. Peter Anvin. + * A pretty straight forward conversion of strtod(): * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Copyright © 2005-2020 Rich Felker, et al. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************/ @@ -40,11 +34,14 @@ #include #include -#include +#include +#include #include +#include +#include +#include #include - -#ifdef CONFIG_HAVE_LONG_DOUBLE +#include /**************************************************************************** * Pre-processor definitions @@ -55,234 +52,749 @@ * added to nuttx/compiler for your compiler. */ -#if !defined(__LDBL_MIN_EXP__) || !defined(__LDBL_MAX_EXP__) -# ifdef CONFIG_CPP_HAVE_WARNING -# warning "Size of exponent is unknown" -# endif -# undef __LDBL_MIN_EXP__ -# define __LDBL_MIN_EXP__ (-1021) -# undef __LDBL_MAX_EXP__ -# define __LDBL_MAX_EXP__ (1024) +#ifdef CONFIG_HAVE_LONG_DOUBLE +# define long_double long double +# define ldbl_max LDBL_MAX +# define ldbl_min LDBL_MIN +# define ldbl_min_exp LDBL_MIN_EXP +# define ldbl_mant_dig LDBL_MANT_DIG +# define ldbl_max_10_exp LDBL_MAX_10_EXP +# define ldbl_min_10_exp LDBL_MIN_10_EXP +#elif defined(CONFIG_HAVE_DOUBLE) +# define long_double double +# define ldbl_max DBL_MAX +# define ldbl_min DBL_MIN +# define ldbl_min_exp LDBL_MIN_EXP +# define ldbl_mant_dig DBL_MANT_DIG +# define ldbl_max_10_exp DBL_MAX_10_EXP +# define ldbl_min_10_exp DBL_MIN_10_EXP +#else +# define long_double float +# define ldbl_max FLT_MAX +# define ldbl_min FLT_MIN +# define ldbl_min_exp LDBL_MIN_EXP +# define ldbl_mant_dig FLT_MANT_DIG +# define ldbl_max_10_exp FLT_MAX_10_EXP +# define ldbl_min_10_exp FLT_MIN_10_EXP #endif +#ifdef CONFIG_HAVE_LONG_LONG +# define long_long long long +# define llong_min LLONG_MIN +#else +# define long_long long +# define llong_min LONG_MIN +#endif + +#define shgetc(f) (*(f)++) +#define shunget(f) ((f)--) +#define ifexist(a,b) do { if ((*a) != NULL) {*(a) = (b);} } while (0) + /**************************************************************************** * Private Functions ****************************************************************************/ -static inline int is_real(long double x) -{ - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ +/**************************************************************************** + * Name: scanexp + * + * Description: + * Gets the sum number of a string which the value of + * each character between 0 and 9 + * + * Input Parameters: + * f - The string + * flag - 1: The value of the f will be change, 0: not change + * + * Returned Value: + * The sum number + * + ****************************************************************************/ - const long double divzero = 0.0L; - const long double infinite = 1.0L / divzero; - return (x < infinite) && (x >= -infinite); +static long_long scanexp(FAR char **f, bool flag) +{ + FAR char *s = *f; + int c; + long_long y = 0; + bool neg = 0; + + c = shgetc(s); + + if (c == '+' || c == '-') + { + neg = (c == '-'); + c = shgetc(s); + } + + while (isdigit(c)) + { + y = 10 * y + c - '0'; + c = shgetc(s); + } + + shunget(s); + if (flag) + { + ifexist(f, s); + } + + return neg ? -y : y; +} + +/**************************************************************************** + * Name: ifallzero + * + * Description: + * To find out if all the next number characters are all zero + * + * Input Parameters: + * f - The string + * flag - 1:The value of the f will be change , 0: not change + * + * Returned Value: + * true - Yes (like: 0000st) + * false - No (like: 0001st) + * + ****************************************************************************/ + +static bool ifallzero(FAR char **f, bool flag) +{ + FAR char *s = *f; + int c; + + c = shgetc(s); + + while (c == '0') + { + c = shgetc(s); + } + + shunget(s); + if (flag) + { + *f = s; + } + + return !isdigit(c); +} + +/**************************************************************************** + * Name: chtou + * + * Description: + * Determine whether c is a keyword then set the + * value of the number add base + * + * Input Parameters: + * c - Hexadecimal: 0 - f(F), decimal: 0 - 9 + * base - Hexadecimal(16) decimal(10) + * number - IF c is a keyword, number += (the value of c) + * + * Returned Value: + * true - c is a keyword of hexadecimal or decimal + * + ****************************************************************************/ + +static bool chtou(char c, int base, FAR uint32_t *number) +{ + int tmp = base; + + if (isdigit(c)) + { + tmp = c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + tmp = c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + tmp = c - 'A' + 10; + } + + if (tmp >= base) + { + return false; + } + + *number = *number * base + tmp; + + return true; +} + +/**************************************************************************** + * Name: scalbnx + * + * Description: + * Implement functionality similar to scalbnl + * + * Returned Value: + * Get a value of number * base ^ exp + * + ****************************************************************************/ + +static long_double scalbnx(long_double number, + long_double base, long_long exp) +{ + long_long e = exp; + + if (e < 0) + { + exp *= -1; + } + + while (exp) + { + if (exp & 1) + { + if (e < 0) + { + number /= base; + } + else + { + number *= base; + } + } + + exp >>= 1; + base *= base; + } + + return number; +} + +/**************************************************************************** + * Name: decfloat + * + * Description: + * Convert a decimal string to a long_double value + * + * Input Parameters: + * ptr - A decimal string + * endptr - If have ,the part that holds all but the numbers + * + * Returned Value: + * A long_double number about ptr + * + ****************************************************************************/ + +static long_double decfloat(FAR char *ptr, FAR char **endptr) +{ + FAR char *f; + FAR char *s; + + int c; + int k; + int gotrad; + uint32_t x; + long_double y; + long_long num_digit; + long_long num_decimal; + + const long_double zero = 0.; + const long p10s[] = + { + 10, 100, 1000, 10000, 100000, + 1000000, 10000000, 100000000 + }; + + f = ptr; + num_digit = 0; + num_decimal = 0; + + /* Don't let leading zeros consume buffer space */ + + ifallzero(&f, 1); + c = shgetc(f); + + /* get the digit and decimal */ + + for (; isdigit(c); c = shgetc(f)) + { + num_digit++; + } + + if (c == '.') + { + s = f; + + if (ifallzero(&f, 1)) + { + c = shgetc(f); + num_digit++; + } + else + { + f = s; + c = shgetc(f); + for (; isdigit(c); c = shgetc(f)) + { + num_digit++; + num_decimal--; + } + } + } + + if (num_digit == 0) + { + shunget(f); + ifexist(endptr, f); + return zero; + } + + if ((c | 32) == 'e') + { + num_decimal = scanexp(&f, 1) + num_decimal; + if (num_decimal <= llong_min / 100) + { + ifexist(endptr, f); + return zero; + } + } + else + { + shunget(f); + } + + ifexist(endptr, f); + f = ptr; + + k = 0; + x = 0; + y = 0.; + gotrad = 0; + + while (chtou(*f, 10, &x) || *f == '.') + { + if (*f == '.') + { + if (gotrad) + { + break; + } + + c = shgetc(f); + s = f; + if (ifallzero(&s, 1)) + { + f = s; + break; + } + + gotrad = 1; + continue; + } + + f++; + if (++k == 9) + { + k = 0; + y = 1000000000 * y + x; + x = 0; + } + } + + if (num_digit <= 9 && num_decimal == 0) + { + return x; + } + else if (num_digit + num_decimal > ldbl_max_10_exp) + { + errno = ERANGE; + return ldbl_max * ldbl_max; + } + else if (num_digit + num_decimal < ldbl_min_10_exp) + { + errno = ERANGE; + return ldbl_min * ldbl_min; + } + + if (k % 9) + { + y = y * p10s[k % 9 - 1] + x; + } + + y *= 1.; + y = scalbnx(y, 10., num_decimal); + return y; +} + +/**************************************************************************** + * Name: hexfloat + * + * Description: + * Convert a hexadecimal string to a long_double value + * + * Input Parameters: + * ptr - The hexadecimal string + * endptr - If have ,the part that holds all but the numbers + * bits - LDBL_MANT_DIG + * emin - LDBL_MIN_EXP - bits + * + * Returned Value: + * A long_double number about ptr + * + ****************************************************************************/ + +static long_double hexfloat(FAR char *ptr, + FAR char **endptr, int bits, int emin) +{ + FAR char *f = ptr; + int d; + int c; + int gottail = 0; + int gotrad = 0; + int gotdig = 0; + uint32_t x = 0; + long_double y = 0; + long_double scale = 1; + long_double bias = 0; + long_long rp = 0; + long_long dc = 0; + long_long e2 = 0; + + const long_double zero = 0.; + + c = shgetc(f); + + /* Skip leading zeros */ + + for (; c == '0'; c = shgetc(f)) + { + gotdig = 1; + } + + if (c == '.') + { + gotrad = 1; + c = shgetc(f); + + /* Count zeros after the radix point before significand */ + + for (rp = 0; c == '0'; c = shgetc(f), rp--) + { + gotdig = 1; + } + } + + for (; c - '0' < 10 || (c | 32) - 'a' < 6 || c == '.'; c = shgetc(f)) + { + if (c == '.') + { + if (gotrad) + { + break; + } + + rp = dc; + gotrad = 1; + } + else + { + gotdig = 1; + if (c > '9') + { + d = (c | 32) + 10 - 'a'; + } + else + { + d = c - '0'; + } + + if (dc < 8) + { + x = x * 16 + d; + } + else if (dc < ldbl_mant_dig / 4 + 1) + { + y += d * (scale /= 16); + } + else if (d && !gottail) + { + y += 0.5 * scale; + gottail = 1; + } + + dc++; + } + } + + if (!gotdig) + { + shunget(f); + shunget(f); + if (gotrad) + { + shunget(f); + } + + ifexist(endptr, f); + return zero; + } + + if (!gotrad) + { + rp = dc; + } + + while (dc < 8) + { + x *= 16, dc++; + } + + if ((c | 32) == 'p') + { + e2 = scanexp(&f, 1); + if (e2 == llong_min) + { + shunget(f); + e2 = 0; + } + } + else + { + shunget(f); + } + + ifexist(endptr, f); + e2 += 4 * rp - 32; + if (!x) + { + return zero; + } + + if (e2 > -emin) + { + errno = ERANGE; + return ldbl_max * ldbl_max; + } + + if (e2 < emin - 2 * ldbl_mant_dig) + { + errno = ERANGE; + return ldbl_min * ldbl_min; + } + + while (x < 0x80000000) + { + if (y >= 0.5) + { + x += x + 1; + y += y - 1; + } + else + { + x += x; + y += y; + } + + e2--; + } + + if (bits > 32 + e2 - emin) + { + bits = 32 + e2 - emin; + if (bits < 0) + { + bits = 0; + } + } + + if (bits < ldbl_mant_dig) + { + bias = scalbnx(1, 2., 32 + ldbl_mant_dig - bits - 1); + } + + if (bits < 32 && y && !(x & 1)) + { + x++, y = 0; + } + + y = bias + x + y; + y -= bias; + + /* If it's a wrong number we will set errno and return it */ + + if (!y) + { + errno = ERANGE; + } + + return scalbnx(y, 2., e2); +} + +/**************************************************************************** + * Name: strtox + * + * Description: + * Convert a string to a long_double value + * + * Input Parameters: + * str - The string + * endptr - If have ,the part that holds all but the numbers + * flags - 1: string -> float + * 2: string -> double + * 3: string- > long double + * + * Returned Value: + * A long_double number about str + * + ****************************************************************************/ + +static long_double strtox(FAR const char *str, FAR char **endptr, int flag) +{ + FAR char *s = (FAR char *)str; + int negative = 0; + long_double y = 0; + int i = 0; + + int bits; + int emin; + + switch (flag) + { + case 1: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP - bits; + break; + case 2: + bits = DBL_MANT_DIG, + emin = DBL_MIN_EXP - bits; + break; + case 3: + bits = LDBL_MANT_DIG, + emin = LDBL_MIN_EXP - bits; + default: + return 0; + } + + /* Skip leading whitespace */ + + while (isspace(*s)) + { + s++; + } + + /* Handle optional sign */ + + switch (*s) + { + case '-': + negative = 1; /* Fall through to increment position */ + + case '+': + s++; + + default: + break; + } + + for (i = 0; i < 8 && (*s | 32) == "infinity"[i]; i++) + { + s++; + } + + if (i == 3 || i == 8) + { + ifexist(endptr, s); + return negative ? -INFINITY : INFINITY; + } + + s -= i; + for (i = 0; i < 3 && (*s | 32) == "nan"[i]; i++) + { + s++; + } + + if (i == 3) + { + ifexist(endptr, s); + return NAN; + } + + /* Process optional 0x prefix */ + + if (*s == '0' && (*(s + 1) | 32) == 'x') + { + s += 2; + y = hexfloat(s, endptr, bits, emin); + } + else + { + y = decfloat(s, endptr); + } + + return negative ? -y : y; } /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: strtof + * + * Description: + * Convert a string to a float value + * + * Input Parameters: + * str - The string + * endptr - If have ,the part that holds all but the numbers + * + * Returned Value: + * A float number about str + * + ****************************************************************************/ + +float strtof(FAR const char *str, FAR char **endptr) +{ + return strtox(str, endptr, 1); +} + +/**************************************************************************** + * Name: strtod + * + * Description: + * Convert a string to a double value + * + * Input Parameters: + * str - The string + * endptr - If have ,the part that holds all but the numbers + * + * Returned Value: + * A double number about str + * + ****************************************************************************/ + +#ifdef CONFIG_HAVE_DOUBLE + +double strtod(FAR const char *str, FAR char **endptr) +{ + return strtox(str, endptr, 2); +} + +#endif /* CONFIG_HAVE_DOUBLE */ + /**************************************************************************** * Name: strtold * * Description: * Convert a string to a long double value * - * NOTE: This implementation is limited as compared to POSIX: - * - Hexadecimal input is not supported - * - INF, INFINITY, NAN, and NAN(...) are not supported + * Input Parameters: + * str - The string + * endptr - If have ,the part that holds all but the numbers + * + * Returned Value: + * A long double number about str * ****************************************************************************/ +#ifdef CONFIG_HAVE_LONG_DOUBLE + long double strtold(FAR const char *str, FAR char **endptr) { - long double number; - int exponent; - int negative; - FAR char *p = (FAR char *) str; - long double p10; - int n; - int num_digits; - int num_decimals; - - /* NOTE: Windows MSVC restrictions, MSVC doesn't allow division through a - * zero literal, but allows it through non-const variable set to zero - */ - - const long double divzero = 0.0L; - const long double infinite = 1.0L / divzero; - - /* Skip leading whitespace */ - - while (isspace(*p)) - { - p++; - } - - /* Handle optional sign */ - - negative = 0; - switch (*p) - { - case '-': - negative = 1; /* Fall through to increment position */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - number = 0.0L; - exponent = 0; - num_digits = 0; - num_decimals = 0; - - /* Process string of digits */ - - while (isdigit(*p)) - { - number = number * 10.0L + (long double)(*p - '0'); - p++; - num_digits++; - } - - /* Process decimal part */ - - if (*p == '.') - { - p++; - - while (isdigit(*p)) - { - number = number * 10.0L + (long double)(*p - '0'); - p++; - num_digits++; - num_decimals++; - } - - exponent -= num_decimals; - } - - if (num_digits == 0) - { - set_errno(ERANGE); - number = 0.0L; - p = (FAR char *)str; - goto errout; - } - - /* Correct for sign */ - - if (negative) - { - number = -number; - } - - /* Process an exponent string */ - - if (*p == 'e' || *p == 'E') - { - /* Handle optional sign */ - - negative = 0; - switch (*++p) - { - case '-': - negative = 1; /* Fall through to increment pos */ - - /* FALLTHROUGH */ - - case '+': - p++; - - /* FALLTHROUGH */ - - default: - break; - } - - /* Process string of digits */ - - if (!isdigit(*p)) - { - set_errno(ERANGE); - number = 0.0L; - p = (FAR char *)str; - goto errout; - } - - n = 0; - while (isdigit(*p)) - { - n = n * 10 + (*p - '0'); - p++; - } - - if (negative) - { - exponent -= n; - } - else - { - exponent += n; - } - } - - if (exponent < __LDBL_MIN_EXP__ || - exponent > __LDBL_MAX_EXP__) - { - set_errno(ERANGE); - number = infinite; - goto errout; - } - - /* Scale the result */ - - p10 = 10.0L; - n = exponent; - if (n < 0) - { - n = -n; - } - - while (n) - { - if (n & 1) - { - if (exponent < 0) - { - number /= p10; - } - else - { - number *= p10; - } - } - - n >>= 1; - p10 *= p10; - } - - if (!is_real(number)) - { - set_errno(ERANGE); - } - -errout: - if (endptr) - { - *endptr = p; - } - - return number; + return strtox(str, endptr, 3); } -#endif /* CONFIG_HAVE_LONG_DOUBLE */ +#endif /* CONFIG_HAVE_LONG_DOUBLE */ \ No newline at end of file