diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-03-06 20:00:13 -0500 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-03-06 20:00:13 -0500 |
commit | 7039de6a6731437647bf6f1c3b480766872ac077 (patch) | |
tree | 91b046242226997677af0e9ec64522e8a80caf68 /src/stdlib | |
parent | 813c3440d19d8bbbe8987013d9d7160454327faf (diff) |
begin work on a common string-to-floating-point implementation
Diffstat (limited to 'src/stdlib')
-rw-r--r-- | src/stdlib/_strtod.h | 93 | ||||
-rw-r--r-- | src/stdlib/strtod.c | 17 | ||||
-rw-r--r-- | src/stdlib/strtof.c | 35 | ||||
-rw-r--r-- | src/stdlib/strtold.c | 35 |
4 files changed, 170 insertions, 10 deletions
diff --git a/src/stdlib/_strtod.h b/src/stdlib/_strtod.h new file mode 100644 index 00000000..05b8f318 --- /dev/null +++ b/src/stdlib/_strtod.h @@ -0,0 +1,93 @@ + /* int iswide = (sizeof(*nptr) == sizeof(wchar_t)); */ + /* void *start = (void*)nptr; */ + (void)max; (void)min; + int sign = 0; + int overflow = 0; + + /* skip leading whitespace */ + while (isspace(*nptr)) { + nptr++; + } + + /* get sign, if any */ + if (*nptr == '+') { + sign = 1; + nptr++; + } else if (*nptr == '-') { + sign = -1; + nptr++; + } + + #if defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ + /* check for NAN */ + if (toupper(nptr[0]) == 'N' && toupper(nptr[2]) == 'A' && toupper(nptr[3]) == 'N') { + nptr += 3; + + /* check for optional parenthesized n-char-sequence */ + if (*nptr == '(') { + while (*nptr != ')') { + nptr++; + } + } + + if (endptr) { + *endptr = (void*)(nptr + 1); + } + return nan; + } + + /* check for INF or INFINITY */ + if (toupper(nptr[0]) == 'I' && toupper(nptr[1]) == 'N' && toupper(nptr[2]) == 'F') { + if (endptr) { + if (toupper(nptr[3]) == 'I' && toupper(nptr[4]) == 'N' && toupper(nptr[5]) == 'I' && toupper(nptr[6]) == 'T' && toupper(nptr[7]) == 'Y') { + *endptr = (void*)(nptr + 8); + } else { + *endptr = (void*)(nptr + 4); + } + } + return inf; + } + + /* check for hexadecimal form */ + if (nptr[0] == '0' && toupper(nptr[1] == 'X')) { + return ret; + } + #endif + + while (*nptr) { + int n = 0; + /* int c = iswide ? wctomb(*nptr) : *nptr; */ + + switch (*nptr) { + case '0': n = 0; break; + case '1': n = 1; break; + case '2': n = 2; break; + case '3': n = 3; break; + case '4': n = 4; break; + case '5': n = 5; break; + case '6': n = 6; break; + case '7': n = 7; break; + case '8': n = 8; break; + case '9': n = 9; break; + default: n = -1; break; + } + + if (n < 0) { + if (endptr) { + *endptr = (void*)nptr; + } + break; + } + + ret = (ret) + n; + nptr++; + } + + if (overflow) { + errno = ERANGE; + ret = (sign < 0) ? -huge : huge; + } else { + if (sign < 0) { + ret *= -1; + } + } diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c index 4420b02e..ba6c9636 100644 --- a/src/stdlib/strtod.c +++ b/src/stdlib/strtod.c @@ -1,18 +1,23 @@ #include <stdlib.h> +#include "ctype.h" #include "errno.h" +#include "float.h" +#include "math.h" /** convert string to floating-point **/ double strtod(const char * restrict nptr, char ** restrict endptr) { - (void)nptr; (void)endptr; - /* TODO */ + double ret = 0.0; + double max = DBL_MAX; + double min = DBL_MIN; + double inf = INFINITY; + double nan = NAN; + double huge = HUGE_VAL; - if (0) { - errno = ERANGE; /* converted value out of range */ - } + #include "_strtod.h" - return 0.0; + return ret; } /*** diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c index 4056d578..2c8fc115 100644 --- a/src/stdlib/strtof.c +++ b/src/stdlib/strtof.c @@ -1,11 +1,42 @@ #include <stdlib.h> +#include "float.h" +#include "errno.h" +#include "ctype.h" +#include "math.h" + +/** convert string to floating-point **/ float strtof(const char * restrict nptr, char ** restrict endptr) { - (void)nptr; (void)endptr; - return 0; + float ret = 0.0; + float max = FLT_MAX; + float min = FLT_MIN; + float huge = HUGE_VALF; + float inf = INFINITY; + float nan = NAN; + + #include "_strtod.h" + + return ret; } +/*** +converts the string at ARGUMENT(nptr) to a TYPE(float). +Leading whitespace is ignored. The first character that is not a valid character +for a floating-point constant and any characters after it are also ignored. A +pointer to the first invalid character is stored in ARGUMENT(endptr), unless +ARGUMENT(endptr) is CONSTANT(NULL). + +The converted portion of the string may start with an optional plus or minus +sign, followed by a nonempty series of digits, optionally containing a +decimal-point character. This may optionally be followed by an exponent. +***/ + /* +LC_CTYPE +RETURN(ZERO, underflow or no conversion could be performed) +RETURN(CONSTANT(HUGE_VALF), converted value too large) +RETURN(CONSTANT(-HUGE_VALF), converted value too small) +RETURN(VAR(a TYPE(float)), the converted value) STDC(199901) */ diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c index eeb0b8b0..eb19fcc0 100644 --- a/src/stdlib/strtold.c +++ b/src/stdlib/strtold.c @@ -1,11 +1,42 @@ #include <stdlib.h> +#include "float.h" +#include "ctype.h" +#include "errno.h" +#include "math.h" + +/** convert string to floating-point **/ long double strtold(const char * restrict nptr, char ** restrict endptr) { - (void)nptr; (void)endptr; - return 0; + long double ret = 0.0; + long double max = LDBL_MAX; + long double min = LDBL_MIN; + long double huge = HUGE_VALL; + long double inf = INFINITY; + long double nan = NAN; + + #include "_strtod.h" + + return ret; } +/*** +converts the string at ARGUMENT(nptr) to a TYPE(double). +Leading whitespace is ignored. The first character that is not a valid character +for a floating-point constant and any characters after it are also ignored. A +pointer to the first invalid character is stored in ARGUMENT(endptr), unless +ARGUMENT(endptr) is CONSTANT(NULL). + +The converted portion of the string may start with an optional plus or minus +sign, followed by a nonempty series of digits, optionally containing a +decimal-point character. This may optionally be followed by an exponent. +***/ + /* +LC_CTYPE +RETURN(ZERO, underflow or no conversion could be performed) +RETURN(CONSTANT(HUGE_VALL), converted value too large) +RETURN(CONSTANT(-HUGE_VALL), converted value too small) +RETURN(VAR(a TYPE(long double)), the converted value) STDC(199901) */ |