dolfptoa.c revision 132451
154359Sroberto/*
254359Sroberto * dolfptoa - do the grunge work of converting an l_fp number to decimal
354359Sroberto */
454359Sroberto#include <stdio.h>
554359Sroberto
654359Sroberto#include "ntp_fp.h"
754359Sroberto#include "lib_strbuf.h"
854359Sroberto#include "ntp_string.h"
954359Sroberto#include "ntp_stdlib.h"
1054359Sroberto
1154359Srobertochar *
1254359Srobertodolfptoa(
1354359Sroberto	u_long fpi,
1454359Sroberto	u_long fpv,
1554359Sroberto	int neg,
16132451Sroberto	short ndec,
1754359Sroberto	int msec
1854359Sroberto	)
1954359Sroberto{
2054359Sroberto	register u_char *cp, *cpend;
2154359Sroberto	register u_long lwork;
2254359Sroberto	register int dec;
2354359Sroberto	u_char cbuf[24];
2454359Sroberto	u_char *cpdec;
2554359Sroberto	char *buf;
2654359Sroberto	char *bp;
2754359Sroberto
2854359Sroberto	/*
2954359Sroberto	 * Get a string buffer before starting
3054359Sroberto	 */
3154359Sroberto	LIB_GETBUF(buf);
3254359Sroberto
3354359Sroberto	/*
3454359Sroberto	 * Zero the character buffer
3554359Sroberto	 */
3654359Sroberto	memset((char *) cbuf, 0, sizeof(cbuf));
3754359Sroberto
3854359Sroberto	/*
3954359Sroberto	 * Work on the integral part.  This is biased by what I know
4054359Sroberto	 * compiles fairly well for a 68000.
4154359Sroberto	 */
4254359Sroberto	cp = cpend = &cbuf[10];
4354359Sroberto	lwork = fpi;
4454359Sroberto	if (lwork & 0xffff0000) {
4554359Sroberto		register u_long lten = 10;
4654359Sroberto		register u_long ltmp;
4754359Sroberto
4854359Sroberto		do {
4954359Sroberto			ltmp = lwork;
5054359Sroberto			lwork /= lten;
5154359Sroberto			ltmp -= (lwork << 3) + (lwork << 1);
5254359Sroberto			*--cp = (u_char)ltmp;
5354359Sroberto		} while (lwork & 0xffff0000);
5454359Sroberto	}
5554359Sroberto	if (lwork != 0) {
5654359Sroberto		register u_short sten = 10;
5754359Sroberto		register u_short stmp;
5854359Sroberto		register u_short swork = (u_short)lwork;
5954359Sroberto
6054359Sroberto		do {
6154359Sroberto			stmp = swork;
62132451Sroberto			swork = (u_short) (swork/sten);
63132451Sroberto			stmp = (u_short)(stmp - ((swork<<3) + (swork<<1)));
6454359Sroberto			*--cp = (u_char)stmp;
6554359Sroberto		} while (swork != 0);
6654359Sroberto	}
6754359Sroberto
6854359Sroberto	/*
6954359Sroberto	 * Done that, now deal with the problem of the fraction.  First
7054359Sroberto	 * determine the number of decimal places.
7154359Sroberto	 */
7254359Sroberto	if (msec) {
7354359Sroberto		dec = ndec + 3;
7454359Sroberto		if (dec < 3)
7554359Sroberto		    dec = 3;
7654359Sroberto		cpdec = &cbuf[13];
7754359Sroberto	} else {
7854359Sroberto		dec = ndec;
7954359Sroberto		if (dec < 0)
8054359Sroberto		    dec = 0;
8154359Sroberto		cpdec = &cbuf[10];
8254359Sroberto	}
8354359Sroberto	if (dec > 12)
8454359Sroberto	    dec = 12;
8554359Sroberto
8654359Sroberto	/*
8754359Sroberto	 * If there's a fraction to deal with, do so.
8854359Sroberto	 */
8954359Sroberto	if (fpv != 0) {
9054359Sroberto		l_fp work;
9154359Sroberto
9254359Sroberto		work.l_ui = 0;
9354359Sroberto		work.l_uf = fpv;
9454359Sroberto		while (dec > 0) {
9554359Sroberto			l_fp ftmp;
9654359Sroberto
9754359Sroberto			dec--;
9854359Sroberto			/*
9954359Sroberto			 * The scheme here is to multiply the
10054359Sroberto			 * fraction (0.1234...) by ten.  This moves
10154359Sroberto			 * a junk of BCD into the units part.
10254359Sroberto			 * record that and iterate.
10354359Sroberto			 */
10454359Sroberto			work.l_ui = 0;
10554359Sroberto			L_LSHIFT(&work);
10654359Sroberto			ftmp = work;
10754359Sroberto			L_LSHIFT(&work);
10854359Sroberto			L_LSHIFT(&work);
10954359Sroberto			L_ADD(&work, &ftmp);
11054359Sroberto			*cpend++ = (u_char)work.l_ui;
11154359Sroberto			if (work.l_uf == 0)
11254359Sroberto			    break;
11354359Sroberto		}
11454359Sroberto
11554359Sroberto		/*
11654359Sroberto		 * Rounding is rotten
11754359Sroberto		 */
11854359Sroberto		if (work.l_uf & 0x80000000) {
11954359Sroberto			register u_char *tp = cpend;
12054359Sroberto
12154359Sroberto			*(--tp) += 1;
12254359Sroberto			while (*tp >= 10) {
12354359Sroberto				*tp = 0;
12454359Sroberto				*(--tp) += 1;
12554359Sroberto			};
12654359Sroberto			if (tp < cp)
12754359Sroberto			    cp = tp;
12854359Sroberto		}
12954359Sroberto	}
13054359Sroberto	cpend += dec;
13154359Sroberto
13254359Sroberto
13354359Sroberto	/*
13454359Sroberto	 * We've now got the fraction in cbuf[], with cp pointing at
13554359Sroberto	 * the first character, cpend pointing past the last, and
13654359Sroberto	 * cpdec pointing at the first character past the decimal.
13754359Sroberto	 * Remove leading zeros, then format the number into the
13854359Sroberto	 * buffer.
13954359Sroberto	 */
14054359Sroberto	while (cp < cpdec) {
14154359Sroberto		if (*cp != 0)
14254359Sroberto		    break;
14354359Sroberto		cp++;
14454359Sroberto	}
14554359Sroberto	if (cp == cpdec)
14654359Sroberto	    --cp;
14754359Sroberto
14854359Sroberto	bp = buf;
14954359Sroberto	if (neg)
15054359Sroberto	    *bp++ = '-';
15154359Sroberto	while (cp < cpend) {
15254359Sroberto		if (cp == cpdec)
15354359Sroberto		    *bp++ = '.';
15454359Sroberto		*bp++ = (char)(*cp++ + '0');	/* ascii dependent? */
15554359Sroberto	}
15654359Sroberto	*bp = '\0';
15754359Sroberto
15854359Sroberto	/*
15954359Sroberto	 * Done!
16054359Sroberto	 */
16154359Sroberto	return buf;
16254359Sroberto}
163