dolfptoa.c revision 132451
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
11char *
12dolfptoa(
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	 * 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 = (u_short) (swork/sten);
63			stmp = (u_short)(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}
163