about summary refs log tree commit diff
path: root/src/stdlib/strtold.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib/strtold.c')
-rw-r--r--src/stdlib/strtold.c103
1 files changed, 11 insertions, 92 deletions
diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c
index ec464c15..40ecc122 100644
--- a/src/stdlib/strtold.c
+++ b/src/stdlib/strtold.c
@@ -1,96 +1,15 @@
 #include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
+#include "floatscan.h"
+#include "stdio_impl.h"
 
-static int valid_exp(const unsigned char *s)
+long double strtold(const char *s, char **p)
 {
-	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;
+	FILE f = {
+		.buf = (void *)s, .rpos = (void *)s,
+		.rend = (void *)-1, .lock = -1
+	};
+	off_t cnt;
+	long double y = __floatscan(&f, -1, 2, 1, &cnt);
+	if (p) *p = (char *)s + cnt;
+	return y;
 }