dolfptoa.c revision 259065
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	 * 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}
174