Initial import from FreeBSD RELENG_4:
[games.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         int 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          * Work on the integral part.  This is biased by what I know
40          * compiles fairly well for a 68000.
41          */
42         cp = cpend = &cbuf[10];
43         lwork = fpi;
44         if (lwork & 0xffff0000) {
45                 register u_long lten = 10;
46                 register u_long ltmp;
47
48                 do {
49                         ltmp = lwork;
50                         lwork /= lten;
51                         ltmp -= (lwork << 3) + (lwork << 1);
52                         *--cp = (u_char)ltmp;
53                 } while (lwork & 0xffff0000);
54         }
55         if (lwork != 0) {
56                 register u_short sten = 10;
57                 register u_short stmp;
58                 register u_short swork = (u_short)lwork;
59
60                 do {
61                         stmp = swork;
62                         swork /= sten;
63                         stmp -= (swork<<3) + (swork<<1);
64                         *--cp = (u_char)stmp;
65                 } while (swork != 0);
66         }
67
68         /*
69          * Done that, now deal with the problem of the fraction.  First
70          * determine the number of decimal places.
71          */
72         if (msec) {
73                 dec = ndec + 3;
74                 if (dec < 3)
75                     dec = 3;
76                 cpdec = &cbuf[13];
77         } else {
78                 dec = ndec;
79                 if (dec < 0)
80                     dec = 0;
81                 cpdec = &cbuf[10];
82         }
83         if (dec > 12)
84             dec = 12;
85         
86         /*
87          * If there's a fraction to deal with, do so.
88          */
89         if (fpv != 0) {
90                 l_fp work;
91
92                 work.l_ui = 0;
93                 work.l_uf = fpv;
94                 while (dec > 0) {
95                         l_fp ftmp;
96
97                         dec--;
98                         /*
99                          * The scheme here is to multiply the
100                          * fraction (0.1234...) by ten.  This moves
101                          * a junk of BCD into the units part.
102                          * record that and iterate.
103                          */
104                         work.l_ui = 0;
105                         L_LSHIFT(&work);
106                         ftmp = work;
107                         L_LSHIFT(&work);
108                         L_LSHIFT(&work);
109                         L_ADD(&work, &ftmp);
110                         *cpend++ = (u_char)work.l_ui;
111                         if (work.l_uf == 0)
112                             break;
113                 }
114
115                 /*
116                  * Rounding is rotten
117                  */
118                 if (work.l_uf & 0x80000000) {
119                         register u_char *tp = cpend;
120
121                         *(--tp) += 1;
122                         while (*tp >= 10) {
123                                 *tp = 0;
124                                 *(--tp) += 1;
125                         };
126                         if (tp < cp)
127                             cp = tp;
128                 }
129         }
130         cpend += dec;
131
132
133         /*
134          * We've now got the fraction in cbuf[], with cp pointing at
135          * the first character, cpend pointing past the last, and
136          * cpdec pointing at the first character past the decimal.
137          * Remove leading zeros, then format the number into the
138          * buffer.
139          */
140         while (cp < cpdec) {
141                 if (*cp != 0)
142                     break;
143                 cp++;
144         }
145         if (cp == cpdec)
146             --cp;
147
148         bp = buf;
149         if (neg)
150             *bp++ = '-';
151         while (cp < cpend) {
152                 if (cp == cpdec)
153                     *bp++ = '.';
154                 *bp++ = (char)(*cp++ + '0');    /* ascii dependent? */
155         }
156         *bp = '\0';
157
158         /*
159          * Done!
160          */
161         return buf;
162 }