]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/libntp/dolfptoa.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / libntp / dolfptoa.c
1 /*
2  * dolfptoa - do the grunge work of converting an l_fp number to decimal
3  */
4 #include <stdio.h>
5
6 #include "ntp_fp.h"
7 #include "lib_strbuf.h"
8 #include "ntp_string.h"
9 #include "ntp_stdlib.h"
10
11 char *
12 dolfptoa(
13         u_long fpi,
14         u_long fpv,
15         int neg,
16         short ndec,
17         int msec
18         )
19 {
20         register u_char *cp, *cpend;
21         register u_long lwork;
22         register int dec;
23         u_char cbuf[24];
24         u_char *cpdec;
25         char *buf;
26         char *bp;
27
28         /*
29          * Get a string buffer before starting
30          */
31         LIB_GETBUF(buf);
32
33         /*
34          * Zero the character buffer
35          */
36         memset((char *) cbuf, 0, sizeof(cbuf));
37
38         /*
39          * safeguard against sign extensions and other mishaps on 64 bit platforms
40          * the code following is designed for and only for 32-bit inputs and
41          * only 32-bit worth of input are supplied.
42          */
43         fpi &= 0xffffffff;
44         fpv &= 0xffffffff;
45
46         /*
47          * Work on the integral part.  This is biased by what I know
48          * compiles fairly well for a 68000.
49          */
50         cp = cpend = &cbuf[10];
51         lwork = fpi;
52         if (lwork & 0xffff0000) {
53                 register u_long lten = 10;
54                 register u_long ltmp;
55
56                 do {
57                         ltmp = lwork;
58                         lwork /= lten;
59                         ltmp -= (lwork << 3) + (lwork << 1);
60                         if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */
61                         *--cp = (u_char)ltmp;
62                 } while (lwork & 0xffff0000);
63         }
64         if (lwork != 0) {
65                 register u_short sten = 10;
66                 register u_short stmp;
67                 register u_short swork = (u_short)lwork;
68
69                 do {
70                         stmp = swork;
71                         swork = (u_short) (swork/sten);
72                         stmp = (u_short)(stmp - ((swork<<3) + (swork<<1)));
73                         if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */
74                         *--cp = (u_char)stmp;
75                 } while (swork != 0);
76         }
77
78         /*
79          * Done that, now deal with the problem of the fraction.  First
80          * determine the number of decimal places.
81          */
82         if (msec) {
83                 dec = ndec + 3;
84                 if (dec < 3)
85                     dec = 3;
86                 cpdec = &cbuf[13];
87         } else {
88                 dec = ndec;
89                 if (dec < 0)
90                     dec = 0;
91                 cpdec = &cbuf[10];
92         }
93         if (dec > 12)
94             dec = 12;
95         
96         /*
97          * If there's a fraction to deal with, do so.
98          */
99         if (fpv != 0) {
100                 l_fp work;
101
102                 work.l_ui = 0;
103                 work.l_uf = fpv;
104                 while (dec > 0) {
105                         l_fp ftmp;
106
107                         dec--;
108                         /*
109                          * The scheme here is to multiply the
110                          * fraction (0.1234...) by ten.  This moves
111                          * a junk of BCD into the units part.
112                          * record that and iterate.
113                          */
114                         work.l_ui = 0;
115                         L_LSHIFT(&work);
116                         ftmp = work;
117                         L_LSHIFT(&work);
118                         L_LSHIFT(&work);
119                         L_ADD(&work, &ftmp);
120                         *cpend++ = (u_char)work.l_ui;
121                         if (work.l_uf == 0)
122                             break;
123                         if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */
124                 }
125
126                 /*
127                  * Rounding is rotten
128                  */
129                 if (work.l_uf & 0x80000000) {
130                         register u_char *tp = cpend;
131
132                         *(--tp) += 1;
133                         while (*tp >= 10) {
134                                 *tp = 0;
135                                 *(--tp) += 1;
136                         };
137                         if (tp < cp)
138                             cp = tp;
139                 }
140         }
141         cpend += dec;
142
143
144         /*
145          * We've now got the fraction in cbuf[], with cp pointing at
146          * the first character, cpend pointing past the last, and
147          * cpdec pointing at the first character past the decimal.
148          * Remove leading zeros, then format the number into the
149          * buffer.
150          */
151         while (cp < cpdec) {
152                 if (*cp != 0)
153                     break;
154                 cp++;
155         }
156         if (cp == cpdec)
157             --cp;
158
159         bp = buf;
160         if (neg)
161             *bp++ = '-';
162         while (cp < cpend) {
163                 if (cp == cpdec)
164                     *bp++ = '.';
165                 *bp++ = (char)(*cp++ + '0');    /* ascii dependent? */
166         }
167         *bp = '\0';
168
169         /*
170          * Done!
171          */
172         return buf;
173 }