Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / libntp / atolfp.c
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 }