diff options
Diffstat (limited to 'src/stdlib/strtold.c')
| -rw-r--r-- | src/stdlib/strtold.c | 93 | 
1 files changed, 93 insertions, 0 deletions
| diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c new file mode 100644 index 00000000..54f80469 --- /dev/null +++ b/src/stdlib/strtold.c @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +long double strtold(const char *s1, char **p) +{ +	const unsigned char *s = s1; +	long double x = 0; +	long double frac; +	int sign = 0; +	int nonzero = 0; +	int radix = '.'; +	long e; + +	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'); +			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'); +				frac *= 1.0/16.0; +				if (*s!='0') nonzero=1; +			} +		} +		if ((*s|32) == 'p') { +			e = strtol(s+1, (void *)&s, 10); +			for (; e>0; e--) x *= 2.0; +			for (; e<0; e++) x *= 0.5; +		} +		if ((nonzero && !x) || !(1.0/x)) +			errno = ERANGE; +		*p = (char *)s; +		return sign ? -x : x; +	} + +	/* 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') { +		e = strtol(++s, (void *)&s, 10); +		for (; e>0; e--) x *= 10.0; +		for (; e<0; e++) x /= 10.0; +	} +	if ((nonzero && !x) || !(1.0/x)) +		errno = ERANGE; +	*p = (char*)s; +	return sign ? -x : x; +} | 
