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 /* 39182007Sroberto * safeguard against sign extensions and other mishaps on 64 bit platforms 40182007Sroberto * the code following is designed for and only for 32-bit inputs and 41182007Sroberto * only 32-bit worth of input are supplied. 42182007Sroberto */ 43182007Sroberto fpi &= 0xffffffff; 44182007Sroberto fpv &= 0xffffffff; 45182007Sroberto 46182007Sroberto /* 4754359Sroberto * Work on the integral part. This is biased by what I know 4854359Sroberto * compiles fairly well for a 68000. 4954359Sroberto */ 5054359Sroberto cp = cpend = &cbuf[10]; 5154359Sroberto lwork = fpi; 5254359Sroberto if (lwork & 0xffff0000) { 5354359Sroberto register u_long lten = 10; 5454359Sroberto register u_long ltmp; 5554359Sroberto 5654359Sroberto do { 5754359Sroberto ltmp = lwork; 5854359Sroberto lwork /= lten; 5954359Sroberto ltmp -= (lwork << 3) + (lwork << 1); 60182007Sroberto if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ 6154359Sroberto *--cp = (u_char)ltmp; 6254359Sroberto } while (lwork & 0xffff0000); 6354359Sroberto } 6454359Sroberto if (lwork != 0) { 6554359Sroberto register u_short sten = 10; 6654359Sroberto register u_short stmp; 6754359Sroberto register u_short swork = (u_short)lwork; 6854359Sroberto 6954359Sroberto do { 7054359Sroberto stmp = swork; 71132451Sroberto swork = (u_short) (swork/sten); 72132451Sroberto stmp = (u_short)(stmp - ((swork<<3) + (swork<<1))); 73182007Sroberto if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ 7454359Sroberto *--cp = (u_char)stmp; 7554359Sroberto } while (swork != 0); 7654359Sroberto } 7754359Sroberto 7854359Sroberto /* 7954359Sroberto * Done that, now deal with the problem of the fraction. First 8054359Sroberto * determine the number of decimal places. 8154359Sroberto */ 8254359Sroberto if (msec) { 8354359Sroberto dec = ndec + 3; 8454359Sroberto if (dec < 3) 8554359Sroberto dec = 3; 8654359Sroberto cpdec = &cbuf[13]; 8754359Sroberto } else { 8854359Sroberto dec = ndec; 8954359Sroberto if (dec < 0) 9054359Sroberto dec = 0; 9154359Sroberto cpdec = &cbuf[10]; 9254359Sroberto } 9354359Sroberto if (dec > 12) 9454359Sroberto dec = 12; 9554359Sroberto 9654359Sroberto /* 9754359Sroberto * If there's a fraction to deal with, do so. 9854359Sroberto */ 9954359Sroberto if (fpv != 0) { 10054359Sroberto l_fp work; 10154359Sroberto 10254359Sroberto work.l_ui = 0; 10354359Sroberto work.l_uf = fpv; 10454359Sroberto while (dec > 0) { 10554359Sroberto l_fp ftmp; 10654359Sroberto 10754359Sroberto dec--; 10854359Sroberto /* 10954359Sroberto * The scheme here is to multiply the 11054359Sroberto * fraction (0.1234...) by ten. This moves 11154359Sroberto * a junk of BCD into the units part. 11254359Sroberto * record that and iterate. 11354359Sroberto */ 11454359Sroberto work.l_ui = 0; 11554359Sroberto L_LSHIFT(&work); 11654359Sroberto ftmp = work; 11754359Sroberto L_LSHIFT(&work); 11854359Sroberto L_LSHIFT(&work); 11954359Sroberto L_ADD(&work, &ftmp); 12054359Sroberto *cpend++ = (u_char)work.l_ui; 12154359Sroberto if (work.l_uf == 0) 12254359Sroberto break; 123182007Sroberto if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */ 12454359Sroberto } 12554359Sroberto 12654359Sroberto /* 12754359Sroberto * Rounding is rotten 12854359Sroberto */ 12954359Sroberto if (work.l_uf & 0x80000000) { 13054359Sroberto register u_char *tp = cpend; 13154359Sroberto 13254359Sroberto *(--tp) += 1; 13354359Sroberto while (*tp >= 10) { 13454359Sroberto *tp = 0; 13554359Sroberto *(--tp) += 1; 13654359Sroberto }; 13754359Sroberto if (tp < cp) 13854359Sroberto cp = tp; 13954359Sroberto } 14054359Sroberto } 14154359Sroberto cpend += dec; 14254359Sroberto 14354359Sroberto 14454359Sroberto /* 14554359Sroberto * We've now got the fraction in cbuf[], with cp pointing at 14654359Sroberto * the first character, cpend pointing past the last, and 14754359Sroberto * cpdec pointing at the first character past the decimal. 14854359Sroberto * Remove leading zeros, then format the number into the 14954359Sroberto * buffer. 15054359Sroberto */ 15154359Sroberto while (cp < cpdec) { 15254359Sroberto if (*cp != 0) 15354359Sroberto break; 15454359Sroberto cp++; 15554359Sroberto } 15654359Sroberto if (cp == cpdec) 15754359Sroberto --cp; 15854359Sroberto 15954359Sroberto bp = buf; 16054359Sroberto if (neg) 16154359Sroberto *bp++ = '-'; 16254359Sroberto while (cp < cpend) { 16354359Sroberto if (cp == cpdec) 16454359Sroberto *bp++ = '.'; 16554359Sroberto *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */ 16654359Sroberto } 16754359Sroberto *bp = '\0'; 16854359Sroberto 16954359Sroberto /* 17054359Sroberto * Done! 17154359Sroberto */ 17254359Sroberto return buf; 17354359Sroberto} 174