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