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