]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/ntp/libntp/dolfptoa.c
o Fix invalid TCP checksums with pf(4). [EN-16:02.pf]
[FreeBSD/releng/9.3.git] / contrib / ntp / libntp / dolfptoa.c
1 /*
2  * dolfptoa - do the grunge work of converting an l_fp number to decimal
3  */
4 #include <config.h>
5 #include <stdio.h>
6
7 #include "ntp_fp.h"
8 #include "lib_strbuf.h"
9 #include "ntp_string.h"
10 #include "ntp_stdlib.h"
11
12 char *
13 dolfptoa(
14         u_int32 fpi,
15         u_int32 fpv,
16         int neg,
17         short ndec,
18         int msec
19         )
20 {
21         u_char *cp, *cpend, *cpdec;
22         int dec;
23         u_char cbuf[24];
24         char *buf, *bp;
25
26         /*
27          * Get a string buffer before starting
28          */
29         LIB_GETBUF(buf);
30
31         /*
32          * Zero the character buffer
33          */
34         ZERO(cbuf);
35
36         /*
37          * Work on the integral part. This should work reasonable on
38          * all machines with 32 bit arithmetic. Please note that 32 bits
39          * can *always* be represented with at most 10 decimal digits,
40          * including a possible rounding from the fractional part.
41          */
42         cp = cpend = cpdec = &cbuf[10];
43         for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
44                 /* can add another digit */
45                 u_int32 digit;
46                 
47                 digit  = fpi;
48                 fpi   /= 10U;
49                 digit -= (fpi << 3) + (fpi << 1); /* i*10 */
50                 *--cp  = (u_char)digit;
51         }
52
53         /*
54          * Done that, now deal with the problem of the fraction.  First
55          * determine the number of decimal places.
56          */
57         dec = ndec;
58         if (dec < 0)
59                 dec = 0;
60         if (msec) {
61                 dec   += 3;
62                 cpdec += 3;
63         }
64         if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
65                 dec = (int)(sizeof(cbuf) - (cpend - cbuf));
66         
67         /*
68          * If there's a fraction to deal with, do so.
69          */
70         for (/*NOP*/;  dec > 0 && fpv != 0;  dec--)  {
71                 u_int32 digit, tmph, tmpl;
72                 
73                 /*
74                  * The scheme here is to multiply the fraction
75                  * (0.1234...) by ten.  This moves a junk of BCD into
76                  * the units part.  record that and iterate.
77                  * multiply by shift/add in two dwords.
78                  */
79                 digit = 0;
80                 M_LSHIFT(digit, fpv);
81                 tmph = digit;
82                 tmpl = fpv;
83                 M_LSHIFT(digit, fpv);
84                 M_LSHIFT(digit, fpv);
85                 M_ADD(digit, fpv, tmph, tmpl);
86                 *cpend++ = (u_char)digit;
87         }
88
89         /* decide whether to round or simply extend by zeros */
90         if (dec > 0) {
91                 /* only '0' digits left -- just reposition end */
92                 cpend += dec; 
93         } else {
94                 /* some bits remain in 'fpv'; do round */
95                 u_char *tp    = cpend;
96                 int     carry = ((fpv & 0x80000000) != 0);
97
98                 for (dec = (int)(tp - cbuf);  carry && dec > 0;  dec--) {
99                         *--tp += 1;
100                         if (*tp == 10)
101                                 *tp = 0;
102                         else 
103                                 carry = FALSE;
104                 }
105
106                 if (tp < cp) /* rounding from 999 to 1000 or similiar? */
107                         cp = tp;
108         }
109
110         /*
111          * We've now got the fraction in cbuf[], with cp pointing at
112          * the first character, cpend pointing past the last, and
113          * cpdec pointing at the first character past the decimal.
114          * Remove leading zeros, then format the number into the
115          * buffer.
116          */
117         while (cp < cpdec && *cp == 0)
118                 cp++;
119         if (cp >= cpdec)
120                 cp = cpdec - 1;
121
122         bp = buf;
123         if (neg)
124                 *bp++ = '-';
125         while (cp < cpend) {
126                 if (cp == cpdec)
127                         *bp++ = '.';
128                 *bp++ = (char)(*cp++) + '0';
129         }
130         *bp = '\0';
131
132         /*
133          * Done!
134          */
135         return buf;
136 }
137
138
139 char *
140 mfptoa(
141         u_int32 fpi,
142         u_int32 fpf,
143         short   ndec
144         )
145 {
146         int     isneg;
147
148         isneg = M_ISNEG(fpi);
149         if (isneg) {
150                 M_NEG(fpi, fpf);
151         }
152
153         return dolfptoa(fpi, fpf, isneg, ndec, FALSE);
154 }
155
156
157 char *
158 mfptoms(
159         u_int32 fpi,
160         u_int32 fpf,
161         short   ndec
162         )
163 {
164         int     isneg;
165
166         isneg = M_ISNEG(fpi);
167         if (isneg) {
168                 M_NEG(fpi, fpf);
169         }
170
171         return dolfptoa(fpi, fpf, isneg, ndec, TRUE);
172 }
173
174