xref: /plan9/sys/src/libc/port/charstod.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier /*
53e12c5d1SDavid du Colombier  * Reads a floating-point number by interpreting successive characters
63e12c5d1SDavid du Colombier  * returned by (*f)(vp).  The last call it makes to f terminates the
73e12c5d1SDavid du Colombier  * scan, so is not a character in the number.  It may therefore be
83e12c5d1SDavid du Colombier  * necessary to back up the input stream up one byte after calling charstod.
93e12c5d1SDavid du Colombier  */
103e12c5d1SDavid du Colombier 
1159cc4ca5SDavid du Colombier #define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
1259cc4ca5SDavid du Colombier 
133e12c5d1SDavid du Colombier double
charstod(int (* f)(void *),void * vp)143e12c5d1SDavid du Colombier charstod(int(*f)(void*), void *vp)
153e12c5d1SDavid du Colombier {
16*9a747e4fSDavid du Colombier 	char str[400], *s, *e, *start;
1759cc4ca5SDavid du Colombier 	int c;
183e12c5d1SDavid du Colombier 
1959cc4ca5SDavid du Colombier 	s = str;
2059cc4ca5SDavid du Colombier 	e = str + sizeof str - 1;
213e12c5d1SDavid du Colombier 	c = (*f)(vp);
223e12c5d1SDavid du Colombier 	while(c == ' ' || c == '\t')
233e12c5d1SDavid du Colombier 		c = (*f)(vp);
243e12c5d1SDavid du Colombier 	if(c == '-' || c == '+'){
2559cc4ca5SDavid du Colombier 		ADVANCE;
263e12c5d1SDavid du Colombier 	}
27*9a747e4fSDavid du Colombier 	start = s;
283e12c5d1SDavid du Colombier 	while(c >= '0' && c <= '9'){
2959cc4ca5SDavid du Colombier 		ADVANCE;
303e12c5d1SDavid du Colombier 	}
3159cc4ca5SDavid du Colombier 	if(c == '.'){
3259cc4ca5SDavid du Colombier 		ADVANCE;
333e12c5d1SDavid du Colombier 		while(c >= '0' && c <= '9'){
3459cc4ca5SDavid du Colombier 			ADVANCE;
3559cc4ca5SDavid du Colombier 		}
363e12c5d1SDavid du Colombier 	}
37*9a747e4fSDavid du Colombier 	if(s > start && (c == 'e' || c == 'E')){
3859cc4ca5SDavid du Colombier 		ADVANCE;
393e12c5d1SDavid du Colombier 		if(c == '-' || c == '+'){
4059cc4ca5SDavid du Colombier 			ADVANCE;
413e12c5d1SDavid du Colombier 		}
423e12c5d1SDavid du Colombier 		while(c >= '0' && c <= '9'){
4359cc4ca5SDavid du Colombier 			ADVANCE;
443e12c5d1SDavid du Colombier 		}
45*9a747e4fSDavid du Colombier 	}else if(s == start && (c == 'i' || c == 'I')){
4659cc4ca5SDavid du Colombier 		ADVANCE;
4759cc4ca5SDavid du Colombier 		if(c != 'n' && c != 'N')
4859cc4ca5SDavid du Colombier 			return NaN();
4959cc4ca5SDavid du Colombier 		ADVANCE;
5059cc4ca5SDavid du Colombier 		if(c != 'f' && c != 'F')
5159cc4ca5SDavid du Colombier 			return NaN();
5259cc4ca5SDavid du Colombier 		ADVANCE;
5359cc4ca5SDavid du Colombier 		if(c != 'i' && c != 'I')
5459cc4ca5SDavid du Colombier 			return NaN();
5559cc4ca5SDavid du Colombier 		ADVANCE;
5659cc4ca5SDavid du Colombier 		if(c != 'n' && c != 'N')
5759cc4ca5SDavid du Colombier 			return NaN();
5859cc4ca5SDavid du Colombier 		ADVANCE;
5959cc4ca5SDavid du Colombier 		if(c != 'i' && c != 'I')
6059cc4ca5SDavid du Colombier 			return NaN();
6159cc4ca5SDavid du Colombier 		ADVANCE;
6259cc4ca5SDavid du Colombier 		if(c != 't' && c != 'T')
6359cc4ca5SDavid du Colombier 			return NaN();
6459cc4ca5SDavid du Colombier 		ADVANCE;
6559cc4ca5SDavid du Colombier 		if(c != 'y' && c != 'Y')
6659cc4ca5SDavid du Colombier 			return NaN();
6759cc4ca5SDavid du Colombier 		ADVANCE;  /* so caller can back up uniformly */
6859cc4ca5SDavid du Colombier 		USED(c);
69*9a747e4fSDavid du Colombier 	}else if(s == str && (c == 'n' || c == 'N')){
7059cc4ca5SDavid du Colombier 		ADVANCE;
7159cc4ca5SDavid du Colombier 		if(c != 'a' && c != 'A')
7259cc4ca5SDavid du Colombier 			return NaN();
7359cc4ca5SDavid du Colombier 		ADVANCE;
7459cc4ca5SDavid du Colombier 		if(c != 'n' && c != 'N')
7559cc4ca5SDavid du Colombier 			return NaN();
7659cc4ca5SDavid du Colombier 		ADVANCE;  /* so caller can back up uniformly */
7759cc4ca5SDavid du Colombier 		USED(c);
783e12c5d1SDavid du Colombier 	}
7959cc4ca5SDavid du Colombier 	*s = 0;
8059cc4ca5SDavid du Colombier 	return strtod(str, &s);
813e12c5d1SDavid du Colombier }
82