diff options
Diffstat (limited to 'src/stdlib')
-rw-r--r-- | src/stdlib/strtod.c | 30 | ||||
-rw-r--r-- | src/stdlib/strtof.c | 6 | ||||
-rw-r--r-- | src/stdlib/strtold.c | 96 |
3 files changed, 29 insertions, 103 deletions
diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c index 388058fe..ecfabdf1 100644 --- a/src/stdlib/strtod.c +++ b/src/stdlib/strtod.c @@ -1,6 +1,34 @@ #include <stdlib.h> +#include "shgetc.h" +#include "floatscan.h" +#include "stdio_impl.h" + +static long double strtox(const char *s, char **p, int prec) +{ + char *t = (char *)s; + while (isspace(*t)) t++; + FILE f = { + .buf = (void *)t, .rpos = (void *)t, + .rend = (void *)-1, .lock = -1 + }; + shlim(&f, 0); + long double y = __floatscan(&f, -1, prec, 1); + off_t cnt = shcnt(&f); + if (p) *p = cnt ? t + cnt : (char *)s; + return y; +} + +float strtof(const char *s, char **p) +{ + return strtox(s, p, 0); +} double strtod(const char *s, char **p) { - return strtold(s, p); + return strtox(s, p, 1); +} + +long double strtold(const char *s, char **p) +{ + return strtox(s, p, 2); } diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c deleted file mode 100644 index 07b32df4..00000000 --- a/src/stdlib/strtof.c +++ /dev/null @@ -1,6 +0,0 @@ -#include <stdlib.h> - -float strtof(const char *s, char **p) -{ - return strtold(s, p); -} diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c deleted file mode 100644 index ec464c15..00000000 --- a/src/stdlib/strtold.c +++ /dev/null @@ -1,96 +0,0 @@ -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> - -static int valid_exp(const unsigned char *s) -{ - return isdigit(*s) || ((s[0]=='+'||s[0]=='-') && isdigit(s[1])); -} - -long double strtold(const char *s1, char **p) -{ - const unsigned char *s = (void *)s1; - long double x = 0; - long double frac; - int sign = 0; - int nonzero = 0; - int radix = '.'; - long e; - int saved_errno = errno; - - if (!p) p = (char **)&s1; - - /* Initial whitespace */ - for (; isspace(*s); s++); - - /* Optional sign */ - if (*s == '-') sign = *s++; - else if (*s == '+') s++; - - /* Handle infinities and NaNs. */ - if ((s[0]|32)=='i' && (s[1]|32)=='n' && (s[2]|32)=='f') { - *p = (char *)s + 3; - return sign ? -1.0/0.0 : 1.0/0.0; - } else if ((s[0]|32)=='n' && (s[1]|32)=='a' && (s[2]|32)=='n') { - *p = (char *)s + 3; - return 0.0/0.0; - } - - /* Possible hex float */ - if (s[0]=='0' && (s[1]|32)=='x') { - /* Mantissa must be non-degenerate */ - if (!isxdigit(s[2]) && (s[2]!=radix || !isxdigit(s[3]))) { - /* Decimal float 0, 'x' extraneous */ - *p = (char *)++s; - return 0; - } - /* We have a real hex float */ - s += 2; - for (; isxdigit(*s); s++) { - x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'+10); - if (*s!='0') nonzero=1; - } - if (*s == radix) { - frac = 1.0/16.0; - for (s++; isxdigit(*s); s++) { - x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'+10); - frac *= 1.0/16.0; - if (*s!='0') nonzero=1; - } - } - if ((*s|32) == 'p' && valid_exp(s+1)) { - e = strtol((void *)(s+1), (void *)&s, 10); - for (; e>0; e--) x *= 2.0; - for (; e<0; e++) x *= 0.5; - } - goto finish; - } - - /* Mantissa must be non-degenerate */ - if (!isdigit(s[0]) && (s[0]!=radix || !isdigit(s[1]))) { - *p = (char *)s1; - return 0; - } - - for (; isdigit(*s); s++) { - x = 10*x + *s-'0'; - if (*s!='0') nonzero=1; - } - if (*s == radix) { - frac = 10.0; - for (s++; isdigit(*s); s++) { - x += (*s-'0') / frac; - frac *= 10.0; - if (*s!='0') nonzero=1; - } - } - if ((*s|32)=='e' && valid_exp(s+1)) { - e = strtol((void *)++s, (void *)&s, 10); - for (; e>0; e--) x *= 10.0; - for (; e<0; e++) x /= 10.0; - } -finish: - errno = ((nonzero && !x) || !(1.0/x)) ? ERANGE : saved_errno; - *p = (char*)s; - return sign ? -x : x; -} |