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