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