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