154359Sroberto/*
254359Sroberto * dolfptoa - do the grunge work of converting an l_fp number to decimal
354359Sroberto */
4280849Scy#include <config.h>
554359Sroberto#include <stdio.h>
654359Sroberto
754359Sroberto#include "ntp_fp.h"
854359Sroberto#include "lib_strbuf.h"
954359Sroberto#include "ntp_string.h"
1054359Sroberto#include "ntp_stdlib.h"
1154359Sroberto
1254359Srobertochar *
1354359Srobertodolfptoa(
14280849Scy	u_int32 fpi,
15280849Scy	u_int32 fpv,
1654359Sroberto	int neg,
17132451Sroberto	short ndec,
1854359Sroberto	int msec
1954359Sroberto	)
2054359Sroberto{
21280849Scy	u_char *cp, *cpend, *cpdec;
22280849Scy	int dec;
2354359Sroberto	u_char cbuf[24];
24280849Scy	char *buf, *bp;
2554359Sroberto
2654359Sroberto	/*
2754359Sroberto	 * Get a string buffer before starting
2854359Sroberto	 */
2954359Sroberto	LIB_GETBUF(buf);
3054359Sroberto
3154359Sroberto	/*
3254359Sroberto	 * Zero the character buffer
3354359Sroberto	 */
34280849Scy	ZERO(cbuf);
3554359Sroberto
3654359Sroberto	/*
37280849Scy	 * Work on the integral part. This should work reasonable on
38280849Scy	 * all machines with 32 bit arithmetic. Please note that 32 bits
39280849Scy	 * can *always* be represented with at most 10 decimal digits,
40280849Scy	 * including a possible rounding from the fractional part.
4154359Sroberto	 */
42280849Scy	cp = cpend = cpdec = &cbuf[10];
43293423Sdelphij	for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
44280849Scy		/* can add another digit */
45280849Scy		u_int32 digit;
46280849Scy
47280849Scy		digit  = fpi;
48280849Scy		fpi   /= 10U;
49280849Scy		digit -= (fpi << 3) + (fpi << 1); /* i*10 */
50280849Scy		*--cp  = (u_char)digit;
5154359Sroberto	}
5254359Sroberto
5354359Sroberto	/*
5454359Sroberto	 * Done that, now deal with the problem of the fraction.  First
5554359Sroberto	 * determine the number of decimal places.
5654359Sroberto	 */
57280849Scy	dec = ndec;
58280849Scy	if (dec < 0)
59280849Scy		dec = 0;
6054359Sroberto	if (msec) {
61280849Scy		dec   += 3;
62280849Scy		cpdec += 3;
6354359Sroberto	}
64280849Scy	if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
65293423Sdelphij		dec = (int)(sizeof(cbuf) - (cpend - cbuf));
6654359Sroberto
6754359Sroberto	/*
6854359Sroberto	 * If there's a fraction to deal with, do so.
6954359Sroberto	 */
70280849Scy	for (/*NOP*/;  dec > 0 && fpv != 0;  dec--)  {
71280849Scy		u_int32 digit, tmph, tmpl;
72280849Scy
7354359Sroberto		/*
74280849Scy		 * The scheme here is to multiply the fraction
75280849Scy		 * (0.1234...) by ten.  This moves a junk of BCD into
76280849Scy		 * the units part.  record that and iterate.
77280849Scy		 * multiply by shift/add in two dwords.
7854359Sroberto		 */
79280849Scy		digit = 0;
80280849Scy		M_LSHIFT(digit, fpv);
81280849Scy		tmph = digit;
82280849Scy		tmpl = fpv;
83280849Scy		M_LSHIFT(digit, fpv);
84280849Scy		M_LSHIFT(digit, fpv);
85280849Scy		M_ADD(digit, fpv, tmph, tmpl);
86280849Scy		*cpend++ = (u_char)digit;
87280849Scy	}
8854359Sroberto
89280849Scy	/* decide whether to round or simply extend by zeros */
90280849Scy	if (dec > 0) {
91280849Scy		/* only '0' digits left -- just reposition end */
92280849Scy		cpend += dec;
93280849Scy	} else {
94280849Scy		/* some bits remain in 'fpv'; do round */
95280849Scy		u_char *tp    = cpend;
96280849Scy		int     carry = ((fpv & 0x80000000) != 0);
97280849Scy
98293423Sdelphij		for (dec = (int)(tp - cbuf);  carry && dec > 0;  dec--) {
99280849Scy			*--tp += 1;
100280849Scy			if (*tp == 10)
10154359Sroberto				*tp = 0;
102280849Scy			else
103280849Scy				carry = FALSE;
10454359Sroberto		}
105280849Scy
106280849Scy		if (tp < cp) /* rounding from 999 to 1000 or similiar? */
107280849Scy			cp = tp;
10854359Sroberto	}
10954359Sroberto
11054359Sroberto	/*
11154359Sroberto	 * We've now got the fraction in cbuf[], with cp pointing at
11254359Sroberto	 * the first character, cpend pointing past the last, and
11354359Sroberto	 * cpdec pointing at the first character past the decimal.
11454359Sroberto	 * Remove leading zeros, then format the number into the
11554359Sroberto	 * buffer.
11654359Sroberto	 */
117280849Scy	while (cp < cpdec && *cp == 0)
11854359Sroberto		cp++;
119280849Scy	if (cp >= cpdec)
120280849Scy		cp = cpdec - 1;
12154359Sroberto
12254359Sroberto	bp = buf;
12354359Sroberto	if (neg)
124280849Scy		*bp++ = '-';
12554359Sroberto	while (cp < cpend) {
12654359Sroberto		if (cp == cpdec)
127280849Scy			*bp++ = '.';
128280849Scy		*bp++ = (char)(*cp++) + '0';
12954359Sroberto	}
13054359Sroberto	*bp = '\0';
13154359Sroberto
13254359Sroberto	/*
13354359Sroberto	 * Done!
13454359Sroberto	 */
13554359Sroberto	return buf;
13654359Sroberto}
137280849Scy
138280849Scy
139280849Scychar *
140280849Scymfptoa(
141280849Scy	u_int32	fpi,
142280849Scy	u_int32	fpf,
143280849Scy	short	ndec
144280849Scy	)
145280849Scy{
146280849Scy	int	isneg;
147280849Scy
148280849Scy	isneg = M_ISNEG(fpi);
149280849Scy	if (isneg) {
150280849Scy		M_NEG(fpi, fpf);
151280849Scy	}
152280849Scy
153280849Scy	return dolfptoa(fpi, fpf, isneg, ndec, FALSE);
154280849Scy}
155280849Scy
156280849Scy
157280849Scychar *
158280849Scymfptoms(
159280849Scy	u_int32	fpi,
160280849Scy	u_int32	fpf,
161280849Scy	short	ndec
162280849Scy	)
163280849Scy{
164280849Scy	int	isneg;
165280849Scy
166280849Scy	isneg = M_ISNEG(fpi);
167280849Scy	if (isneg) {
168280849Scy		M_NEG(fpi, fpf);
169280849Scy	}
170280849Scy
171280849Scy	return dolfptoa(fpi, fpf, isneg, ndec, TRUE);
172280849Scy}
173280849Scy
174280849Scy
175