xref: /plan9/sys/src/ape/lib/ap/gen/strtod.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <math.h>
2*3e12c5d1SDavid du Colombier #include <errno.h>
3*3e12c5d1SDavid du Colombier 
4*3e12c5d1SDavid du Colombier /*
5*3e12c5d1SDavid du Colombier  * bug: should detect overflow, set errno = ERANGE, and return +/- HUGE_VAL
6*3e12c5d1SDavid du Colombier  */
7*3e12c5d1SDavid du Colombier double
strtod(const char * cp,char ** endptr)8*3e12c5d1SDavid du Colombier strtod(const char *cp, char **endptr)
9*3e12c5d1SDavid du Colombier {
10*3e12c5d1SDavid du Colombier 	double num, dem;
11*3e12c5d1SDavid du Colombier 	extern double pow10(int);
12*3e12c5d1SDavid du Colombier 	int neg, eneg, dig, predig, exp, c;
13*3e12c5d1SDavid du Colombier 	const char *p;
14*3e12c5d1SDavid du Colombier 
15*3e12c5d1SDavid du Colombier 	p = cp;
16*3e12c5d1SDavid du Colombier 	num = 0;
17*3e12c5d1SDavid du Colombier 	neg = 0;
18*3e12c5d1SDavid du Colombier 	dig = 0;
19*3e12c5d1SDavid du Colombier 	predig = 0;
20*3e12c5d1SDavid du Colombier 	exp = 0;
21*3e12c5d1SDavid du Colombier 	eneg = 0;
22*3e12c5d1SDavid du Colombier 
23*3e12c5d1SDavid du Colombier 	c = *p++;
24*3e12c5d1SDavid du Colombier 	while(c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r')
25*3e12c5d1SDavid du Colombier 		c = *p++;
26*3e12c5d1SDavid du Colombier 	if(c == '-' || c == '+'){
27*3e12c5d1SDavid du Colombier 		if(c == '-')
28*3e12c5d1SDavid du Colombier 			neg = 1;
29*3e12c5d1SDavid du Colombier 		c = *p++;
30*3e12c5d1SDavid du Colombier 	}
31*3e12c5d1SDavid du Colombier 	while(c >= '0' && c <= '9'){
32*3e12c5d1SDavid du Colombier 		num = num*10 + c-'0';
33*3e12c5d1SDavid du Colombier 		predig++;
34*3e12c5d1SDavid du Colombier 		c = *p++;
35*3e12c5d1SDavid du Colombier 	}
36*3e12c5d1SDavid du Colombier 	if(c == '.')
37*3e12c5d1SDavid du Colombier 		c = *p++;
38*3e12c5d1SDavid du Colombier 	while(c >= '0' && c <= '9'){
39*3e12c5d1SDavid du Colombier 		num = num*10 + c-'0';
40*3e12c5d1SDavid du Colombier 		dig++;
41*3e12c5d1SDavid du Colombier 		c = *p++;
42*3e12c5d1SDavid du Colombier 	}
43*3e12c5d1SDavid du Colombier 	if(dig+predig == 0){
44*3e12c5d1SDavid du Colombier 		if(endptr)
45*3e12c5d1SDavid du Colombier 			*endptr = (char *)cp;
46*3e12c5d1SDavid du Colombier 		return 0.0;
47*3e12c5d1SDavid du Colombier 	}
48*3e12c5d1SDavid du Colombier 	if(c == 'e' || c == 'E'){
49*3e12c5d1SDavid du Colombier 		c = *p++;
50*3e12c5d1SDavid du Colombier 		if(c == '-' || c == '+'){
51*3e12c5d1SDavid du Colombier 			if(c == '-'){
52*3e12c5d1SDavid du Colombier 				dig = -dig;
53*3e12c5d1SDavid du Colombier 				eneg = 1;
54*3e12c5d1SDavid du Colombier 			}
55*3e12c5d1SDavid du Colombier 			c = *p++;
56*3e12c5d1SDavid du Colombier 		}
57*3e12c5d1SDavid du Colombier 		while(c >= '0' && c <= '9'){
58*3e12c5d1SDavid du Colombier 			exp = exp*10 + c-'0';
59*3e12c5d1SDavid du Colombier 			c = *p++;
60*3e12c5d1SDavid du Colombier 		}
61*3e12c5d1SDavid du Colombier 	}
62*3e12c5d1SDavid du Colombier 	exp -= dig;
63*3e12c5d1SDavid du Colombier 	if(exp < 0){
64*3e12c5d1SDavid du Colombier 		exp = -exp;
65*3e12c5d1SDavid du Colombier 		eneg = !eneg;
66*3e12c5d1SDavid du Colombier 	}
67*3e12c5d1SDavid du Colombier 	dem = pow10(exp);
68*3e12c5d1SDavid du Colombier 	if(dem==HUGE_VAL)
69*3e12c5d1SDavid du Colombier 		num = eneg? 0.0 : HUGE_VAL;
70*3e12c5d1SDavid du Colombier 	else if(dem==0)
71*3e12c5d1SDavid du Colombier 		num = eneg? HUGE_VAL : 0.0;
72*3e12c5d1SDavid du Colombier 	else if(eneg)
73*3e12c5d1SDavid du Colombier 		num /= dem;
74*3e12c5d1SDavid du Colombier 	else
75*3e12c5d1SDavid du Colombier 		num *= dem;
76*3e12c5d1SDavid du Colombier 	if(neg)
77*3e12c5d1SDavid du Colombier 		num = -num;
78*3e12c5d1SDavid du Colombier 	if(endptr){
79*3e12c5d1SDavid du Colombier 		*endptr = (char *)--p;
80*3e12c5d1SDavid du Colombier 		/*
81*3e12c5d1SDavid du Colombier 		 * Fix cases like 2.3e+
82*3e12c5d1SDavid du Colombier 		 */
83*3e12c5d1SDavid du Colombier 		while(p > cp){
84*3e12c5d1SDavid du Colombier 			c = *--p;
85*3e12c5d1SDavid du Colombier 			if(c!='-' && c!='+' && c!='e' && c!='E')
86*3e12c5d1SDavid du Colombier 				break;
87*3e12c5d1SDavid du Colombier 			(*endptr)--;
88*3e12c5d1SDavid du Colombier 		}
89*3e12c5d1SDavid du Colombier 	}
90*3e12c5d1SDavid du Colombier 	return num;
91*3e12c5d1SDavid du Colombier }
92