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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>