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