Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / libntp / dolfptoa.c
blobe204f44184c5ef71e18430b12957902b054a984b
1 /* $NetBSD: dolfptoa.c,v 1.2 2003/12/04 16:23:36 drochner Exp $ */
3 /*
4 * dolfptoa - do the grunge work of converting an l_fp number to decimal
5 */
6 #include <stdio.h>
8 #include "ntp_fp.h"
9 #include "lib_strbuf.h"
10 #include "ntp_string.h"
11 #include "ntp_stdlib.h"
13 char *
14 dolfptoa(
15 u_long fpi,
16 u_long fpv,
17 int neg,
18 short ndec,
19 int msec
22 register u_char *cp, *cpend;
23 register u_long lwork;
24 register int dec;
25 u_char cbuf[24];
26 u_char *cpdec;
27 char *buf;
28 char *bp;
31 * Get a string buffer before starting
33 LIB_GETBUF(buf);
36 * Zero the character buffer
38 memset((char *) cbuf, 0, sizeof(cbuf));
41 * safeguard against sign extensions and other mishaps on 64 bit platforms
42 * the code following is designed for and only for 32-bit inputs and
43 * only 32-bit worth of input are supplied.
45 fpi &= 0xffffffff;
46 fpv &= 0xffffffff;
49 * Work on the integral part. This is biased by what I know
50 * compiles fairly well for a 68000.
52 cp = cpend = &cbuf[10];
53 lwork = fpi;
54 if (lwork & 0xffff0000) {
55 register u_long lten = 10;
56 register u_long ltmp;
58 do {
59 ltmp = lwork;
60 lwork /= lten;
61 ltmp -= (lwork << 3) + (lwork << 1);
62 if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */
63 *--cp = (u_char)ltmp;
64 } while (lwork & 0xffff0000);
66 if (lwork != 0) {
67 register u_short sten = 10;
68 register u_short stmp;
69 register u_short swork = (u_short)lwork;
71 do {
72 stmp = swork;
73 swork = (u_short) (swork/sten);
74 stmp = (u_short)(stmp - ((swork<<3) + (swork<<1)));
75 if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */
76 *--cp = (u_char)stmp;
77 } while (swork != 0);
81 * Done that, now deal with the problem of the fraction. First
82 * determine the number of decimal places.
84 if (msec) {
85 dec = ndec + 3;
86 if (dec < 3)
87 dec = 3;
88 cpdec = &cbuf[13];
89 } else {
90 dec = ndec;
91 if (dec < 0)
92 dec = 0;
93 cpdec = &cbuf[10];
95 if (dec > 12)
96 dec = 12;
99 * If there's a fraction to deal with, do so.
101 if (fpv != 0) {
102 l_fp work;
104 work.l_ui = 0;
105 work.l_uf = fpv;
106 while (dec > 0) {
107 l_fp ftmp;
109 dec--;
111 * The scheme here is to multiply the
112 * fraction (0.1234...) by ten. This moves
113 * a junk of BCD into the units part.
114 * record that and iterate.
116 work.l_ui = 0;
117 L_LSHIFT(&work);
118 ftmp = work;
119 L_LSHIFT(&work);
120 L_LSHIFT(&work);
121 L_ADD(&work, &ftmp);
122 *cpend++ = (u_char)work.l_ui;
123 if (work.l_uf == 0)
124 break;
125 if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */
129 * Rounding is rotten
131 if (work.l_uf & 0x80000000) {
132 register u_char *tp = cpend;
134 *(--tp) += 1;
135 while (*tp >= 10) {
136 *tp = 0;
137 *(--tp) += 1;
139 if (tp < cp)
140 cp = tp;
143 cpend += dec;
147 * We've now got the fraction in cbuf[], with cp pointing at
148 * the first character, cpend pointing past the last, and
149 * cpdec pointing at the first character past the decimal.
150 * Remove leading zeros, then format the number into the
151 * buffer.
153 while (cp < cpdec) {
154 if (*cp != 0)
155 break;
156 cp++;
158 if (cp == cpdec)
159 --cp;
161 bp = buf;
162 if (neg)
163 *bp++ = '-';
164 while (cp < cpend) {
165 if (cp == cpdec)
166 *bp++ = '.';
167 *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */
169 *bp = '\0';
172 * Done!
174 return buf;