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