xref: /freebsd/contrib/ntp/libntp/atolfp.c (revision c0b746e5e8d9479f05b3749cbf1f73b8928719bd)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * atolfp - convert an ascii string to an l_fp number
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #include <stdio.h>
5c0b746e5SOllivier Robert #include <ctype.h>
6c0b746e5SOllivier Robert 
7c0b746e5SOllivier Robert #include "ntp_fp.h"
8c0b746e5SOllivier Robert #include "ntp_string.h"
9c0b746e5SOllivier Robert 
10c0b746e5SOllivier Robert /*
11c0b746e5SOllivier Robert  * Powers of 10
12c0b746e5SOllivier Robert  */
13c0b746e5SOllivier Robert static u_long ten_to_the_n[10] = {
14c0b746e5SOllivier Robert 	0,
15c0b746e5SOllivier Robert 	10,
16c0b746e5SOllivier Robert 	100,
17c0b746e5SOllivier Robert 	1000,
18c0b746e5SOllivier Robert 	10000,
19c0b746e5SOllivier Robert 	100000,
20c0b746e5SOllivier Robert 	1000000,
21c0b746e5SOllivier Robert 	10000000,
22c0b746e5SOllivier Robert 	100000000,
23c0b746e5SOllivier Robert 	1000000000,
24c0b746e5SOllivier Robert };
25c0b746e5SOllivier Robert 
26c0b746e5SOllivier Robert 
27c0b746e5SOllivier Robert int
28c0b746e5SOllivier Robert atolfp(
29c0b746e5SOllivier Robert 	const char *str,
30c0b746e5SOllivier Robert 	l_fp *lfp
31c0b746e5SOllivier Robert 	)
32c0b746e5SOllivier Robert {
33c0b746e5SOllivier Robert 	register const char *cp;
34c0b746e5SOllivier Robert 	register u_long dec_i;
35c0b746e5SOllivier Robert 	register u_long dec_f;
36c0b746e5SOllivier Robert 	char *ind;
37c0b746e5SOllivier Robert 	int ndec;
38c0b746e5SOllivier Robert 	int isneg;
39c0b746e5SOllivier Robert 	static const char *digits = "0123456789";
40c0b746e5SOllivier Robert 
41c0b746e5SOllivier Robert 	isneg = 0;
42c0b746e5SOllivier Robert 	dec_i = dec_f = 0;
43c0b746e5SOllivier Robert 	ndec = 0;
44c0b746e5SOllivier Robert 	cp = str;
45c0b746e5SOllivier Robert 
46c0b746e5SOllivier Robert 	/*
47c0b746e5SOllivier Robert 	 * We understand numbers of the form:
48c0b746e5SOllivier Robert 	 *
49c0b746e5SOllivier Robert 	 * [spaces][-|+][digits][.][digits][spaces|\n|\0]
50c0b746e5SOllivier Robert 	 */
51c0b746e5SOllivier Robert 	while (isspace((int)*cp))
52c0b746e5SOllivier Robert 	    cp++;
53c0b746e5SOllivier Robert 
54c0b746e5SOllivier Robert 	if (*cp == '-') {
55c0b746e5SOllivier Robert 		cp++;
56c0b746e5SOllivier Robert 		isneg = 1;
57c0b746e5SOllivier Robert 	}
58c0b746e5SOllivier Robert 
59c0b746e5SOllivier Robert 	if (*cp == '+')
60c0b746e5SOllivier Robert 	    cp++;
61c0b746e5SOllivier Robert 
62c0b746e5SOllivier Robert 	if (*cp != '.' && !isdigit((int)*cp))
63c0b746e5SOllivier Robert 	    return 0;
64c0b746e5SOllivier Robert 
65c0b746e5SOllivier Robert 	while (*cp != '\0' && (ind = strchr(digits, *cp)) != NULL) {
66c0b746e5SOllivier Robert 		dec_i = (dec_i << 3) + (dec_i << 1);	/* multiply by 10 */
67c0b746e5SOllivier Robert 		dec_i += (ind - digits);
68c0b746e5SOllivier Robert 		cp++;
69c0b746e5SOllivier Robert 	}
70c0b746e5SOllivier Robert 
71c0b746e5SOllivier Robert 	if (*cp != '\0' && !isspace((int)*cp)) {
72c0b746e5SOllivier Robert 		if (*cp++ != '.')
73c0b746e5SOllivier Robert 		    return 0;
74c0b746e5SOllivier Robert 
75c0b746e5SOllivier Robert 		while (ndec < 9 && *cp != '\0'
76c0b746e5SOllivier Robert 		       && (ind = strchr(digits, *cp)) != NULL) {
77c0b746e5SOllivier Robert 			ndec++;
78c0b746e5SOllivier Robert 			dec_f = (dec_f << 3) + (dec_f << 1);	/* *10 */
79c0b746e5SOllivier Robert 			dec_f += (ind - digits);
80c0b746e5SOllivier Robert 			cp++;
81c0b746e5SOllivier Robert 		}
82c0b746e5SOllivier Robert 
83c0b746e5SOllivier Robert 		while (isdigit((int)*cp))
84c0b746e5SOllivier Robert 		    cp++;
85c0b746e5SOllivier Robert 
86c0b746e5SOllivier Robert 		if (*cp != '\0' && !isspace((int)*cp))
87c0b746e5SOllivier Robert 		    return 0;
88c0b746e5SOllivier Robert 	}
89c0b746e5SOllivier Robert 
90c0b746e5SOllivier Robert 	if (ndec > 0) {
91c0b746e5SOllivier Robert 		register u_long tmp;
92c0b746e5SOllivier Robert 		register u_long bit;
93c0b746e5SOllivier Robert 		register u_long ten_fact;
94c0b746e5SOllivier Robert 
95c0b746e5SOllivier Robert 		ten_fact = ten_to_the_n[ndec];
96c0b746e5SOllivier Robert 
97c0b746e5SOllivier Robert 		tmp = 0;
98c0b746e5SOllivier Robert 		bit = 0x80000000;
99c0b746e5SOllivier Robert 		while (bit != 0) {
100c0b746e5SOllivier Robert 			dec_f <<= 1;
101c0b746e5SOllivier Robert 			if (dec_f >= ten_fact) {
102c0b746e5SOllivier Robert 				tmp |= bit;
103c0b746e5SOllivier Robert 				dec_f -= ten_fact;
104c0b746e5SOllivier Robert 			}
105c0b746e5SOllivier Robert 			bit >>= 1;
106c0b746e5SOllivier Robert 		}
107c0b746e5SOllivier Robert 		if ((dec_f << 1) > ten_fact)
108c0b746e5SOllivier Robert 		    tmp++;
109c0b746e5SOllivier Robert 		dec_f = tmp;
110c0b746e5SOllivier Robert 	}
111c0b746e5SOllivier Robert 
112c0b746e5SOllivier Robert 	if (isneg)
113c0b746e5SOllivier Robert 	    M_NEG(dec_i, dec_f);
114c0b746e5SOllivier Robert 
115c0b746e5SOllivier Robert 	lfp->l_ui = dec_i;
116c0b746e5SOllivier Robert 	lfp->l_uf = dec_f;
117c0b746e5SOllivier Robert 	return 1;
118c0b746e5SOllivier Robert }
119