xref: /netbsd/external/bsd/ntp/dist/libntp/dolfptoa.c (revision 6550d01e)
1 /*	$NetBSD: dolfptoa.c,v 1.1.1.1 2009/12/13 16:55:02 kardel Exp $	*/
2 
3 /*
4  * dolfptoa - do the grunge work of converting an l_fp number to decimal
5  */
6 #include <stdio.h>
7 
8 #include "ntp_fp.h"
9 #include "lib_strbuf.h"
10 #include "ntp_string.h"
11 #include "ntp_stdlib.h"
12 
13 char *
14 dolfptoa(
15 	u_long fpi,
16 	u_long fpv,
17 	int neg,
18 	short ndec,
19 	int msec
20 	)
21 {
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;
29 
30 	/*
31 	 * Get a string buffer before starting
32 	 */
33 	LIB_GETBUF(buf);
34 
35 	/*
36 	 * Zero the character buffer
37 	 */
38 	memset((char *) cbuf, 0, sizeof(cbuf));
39 
40 	/*
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.
44          */
45 	fpi &= 0xffffffff;
46 	fpv &= 0xffffffff;
47 
48 	/*
49 	 * Work on the integral part.  This is biased by what I know
50 	 * compiles fairly well for a 68000.
51 	 */
52 	cp = cpend = &cbuf[10];
53 	lwork = fpi;
54 	if (lwork & 0xffff0000) {
55 		register u_long lten = 10;
56 		register u_long ltmp;
57 
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);
65 	}
66 	if (lwork != 0) {
67 		register u_short sten = 10;
68 		register u_short stmp;
69 		register u_short swork = (u_short)lwork;
70 
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);
78 	}
79 
80 	/*
81 	 * Done that, now deal with the problem of the fraction.  First
82 	 * determine the number of decimal places.
83 	 */
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];
94 	}
95 	if (dec > 12)
96 	    dec = 12;
97 
98 	/*
99 	 * If there's a fraction to deal with, do so.
100 	 */
101 	if (fpv != 0) {
102 		l_fp work;
103 
104 		work.l_ui = 0;
105 		work.l_uf = fpv;
106 		while (dec > 0) {
107 			l_fp ftmp;
108 
109 			dec--;
110 			/*
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.
115 			 */
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 */
126 		}
127 
128 		/*
129 		 * Rounding is rotten
130 		 */
131 		if (work.l_uf & 0x80000000) {
132 			register u_char *tp = cpend;
133 
134 			*(--tp) += 1;
135 			while (*tp >= 10) {
136 				*tp = 0;
137 				*(--tp) += 1;
138 			};
139 			if (tp < cp)
140 			    cp = tp;
141 		}
142 	}
143 	cpend += dec;
144 
145 
146 	/*
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.
152 	 */
153 	while (cp < cpdec) {
154 		if (*cp != 0)
155 		    break;
156 		cp++;
157 	}
158 	if (cp == cpdec)
159 	    --cp;
160 
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? */
168 	}
169 	*bp = '\0';
170 
171 	/*
172 	 * Done!
173 	 */
174 	return buf;
175 }
176