/src/ntp-dev/libntp/dolfptoa.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
21 | 0 | u_char *cp, *cpend, *cpdec; |
22 | 0 | int dec; |
23 | 0 | u_char cbuf[24]; |
24 | 0 | char *buf, *bp; |
25 | | |
26 | | /* |
27 | | * Get a string buffer before starting |
28 | | */ |
29 | 0 | LIB_GETBUF(buf); |
30 | | |
31 | | /* |
32 | | * Zero the character buffer |
33 | | */ |
34 | 0 | 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 | 0 | cp = cpend = cpdec = &cbuf[10]; |
43 | 0 | for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { |
44 | | /* can add another digit */ |
45 | 0 | u_int32 digit; |
46 | | |
47 | 0 | digit = fpi; |
48 | 0 | fpi /= 10U; |
49 | 0 | digit -= (fpi << 3) + (fpi << 1); /* i*10 */ |
50 | 0 | *--cp = (u_char)digit; |
51 | 0 | } |
52 | | |
53 | | /* |
54 | | * Done that, now deal with the problem of the fraction. First |
55 | | * determine the number of decimal places. |
56 | | */ |
57 | 0 | dec = ndec; |
58 | 0 | if (dec < 0) |
59 | 0 | dec = 0; |
60 | 0 | if (msec) { |
61 | 0 | dec += 3; |
62 | 0 | cpdec += 3; |
63 | 0 | } |
64 | 0 | if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) |
65 | 0 | dec = (int)(sizeof(cbuf) - (cpend - cbuf)); |
66 | | |
67 | | /* |
68 | | * If there's a fraction to deal with, do so. |
69 | | */ |
70 | 0 | for (/*NOP*/; dec > 0 && fpv != 0; dec--) { |
71 | 0 | 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 | 0 | digit = 0; |
80 | 0 | M_LSHIFT(digit, fpv); |
81 | 0 | tmph = digit; |
82 | 0 | tmpl = fpv; |
83 | 0 | M_LSHIFT(digit, fpv); |
84 | 0 | M_LSHIFT(digit, fpv); |
85 | 0 | M_ADD(digit, fpv, tmph, tmpl); |
86 | 0 | *cpend++ = (u_char)digit; |
87 | 0 | } |
88 | | |
89 | | /* decide whether to round or simply extend by zeros */ |
90 | 0 | if (dec > 0) { |
91 | | /* only '0' digits left -- just reposition end */ |
92 | 0 | cpend += dec; |
93 | 0 | } else { |
94 | | /* some bits remain in 'fpv'; do round */ |
95 | 0 | u_char *tp = cpend; |
96 | 0 | int carry = ((fpv & 0x80000000) != 0); |
97 | |
|
98 | 0 | for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { |
99 | 0 | *--tp += 1; |
100 | 0 | if (*tp == 10) |
101 | 0 | *tp = 0; |
102 | 0 | else |
103 | 0 | carry = FALSE; |
104 | 0 | } |
105 | |
|
106 | 0 | if (tp < cp) /* rounding from 999 to 1000 or similiar? */ |
107 | 0 | cp = tp; |
108 | 0 | } |
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 | 0 | while (cp < cpdec && *cp == 0) |
118 | 0 | cp++; |
119 | 0 | if (cp >= cpdec) |
120 | 0 | cp = cpdec - 1; |
121 | |
|
122 | 0 | bp = buf; |
123 | 0 | if (neg) |
124 | 0 | *bp++ = '-'; |
125 | 0 | while (cp < cpend) { |
126 | 0 | if (cp == cpdec) |
127 | 0 | *bp++ = '.'; |
128 | 0 | *bp++ = (char)(*cp++) + '0'; |
129 | 0 | } |
130 | 0 | *bp = '\0'; |
131 | | |
132 | | /* |
133 | | * Done! |
134 | | */ |
135 | 0 | return buf; |
136 | 0 | } |
137 | | |
138 | | |
139 | | char * |
140 | | mfptoa( |
141 | | u_int32 fpi, |
142 | | u_int32 fpf, |
143 | | short ndec |
144 | | ) |
145 | 0 | { |
146 | 0 | int isneg; |
147 | |
|
148 | 0 | isneg = M_ISNEG(fpi); |
149 | 0 | if (isneg) { |
150 | 0 | M_NEG(fpi, fpf); |
151 | 0 | } |
152 | |
|
153 | 0 | return dolfptoa(fpi, fpf, isneg, ndec, FALSE); |
154 | 0 | } |
155 | | |
156 | | |
157 | | char * |
158 | | mfptoms( |
159 | | u_int32 fpi, |
160 | | u_int32 fpf, |
161 | | short ndec |
162 | | ) |
163 | 0 | { |
164 | 0 | int isneg; |
165 | |
|
166 | 0 | isneg = M_ISNEG(fpi); |
167 | 0 | if (isneg) { |
168 | 0 | M_NEG(fpi, fpf); |
169 | 0 | } |
170 | |
|
171 | 0 | return dolfptoa(fpi, fpf, isneg, ndec, TRUE); |
172 | 0 | } |
173 | | |
174 | | |