File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libntp / dolfptoa.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 5 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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: 
   11: char *
   12: dolfptoa(
   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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>