154359Sroberto/* 254359Sroberto * dolfptoa - do the grunge work of converting an l_fp number to decimal 354359Sroberto */ 4290001Sglebius#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( 14290001Sglebius u_int32 fpi, 15290001Sglebius u_int32 fpv, 1654359Sroberto int neg, 17132451Sroberto short ndec, 1854359Sroberto int msec 1954359Sroberto ) 2054359Sroberto{ 21290001Sglebius u_char *cp, *cpend, *cpdec; 22290001Sglebius int dec; 2354359Sroberto u_char cbuf[24]; 24290001Sglebius 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 */ 34290001Sglebius ZERO(cbuf); 3554359Sroberto 3654359Sroberto /* 37290001Sglebius * Work on the integral part. This should work reasonable on 38290001Sglebius * all machines with 32 bit arithmetic. Please note that 32 bits 39290001Sglebius * can *always* be represented with at most 10 decimal digits, 40290001Sglebius * including a possible rounding from the fractional part. 4154359Sroberto */ 42290001Sglebius cp = cpend = cpdec = &cbuf[10]; 43293896Sglebius for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { 44290001Sglebius /* can add another digit */ 45290001Sglebius u_int32 digit; 46290001Sglebius 47290001Sglebius digit = fpi; 48290001Sglebius fpi /= 10U; 49290001Sglebius digit -= (fpi << 3) + (fpi << 1); /* i*10 */ 50290001Sglebius *--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 */ 57290001Sglebius dec = ndec; 58290001Sglebius if (dec < 0) 59290001Sglebius dec = 0; 6054359Sroberto if (msec) { 61290001Sglebius dec += 3; 62290001Sglebius cpdec += 3; 6354359Sroberto } 64290001Sglebius if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) 65293896Sglebius dec = (int)(sizeof(cbuf) - (cpend - cbuf)); 6654359Sroberto 6754359Sroberto /* 6854359Sroberto * If there's a fraction to deal with, do so. 6954359Sroberto */ 70290001Sglebius for (/*NOP*/; dec > 0 && fpv != 0; dec--) { 71290001Sglebius u_int32 digit, tmph, tmpl; 72290001Sglebius 7354359Sroberto /* 74290001Sglebius * The scheme here is to multiply the fraction 75290001Sglebius * (0.1234...) by ten. This moves a junk of BCD into 76290001Sglebius * the units part. record that and iterate. 77290001Sglebius * multiply by shift/add in two dwords. 7854359Sroberto */ 79290001Sglebius digit = 0; 80290001Sglebius M_LSHIFT(digit, fpv); 81290001Sglebius tmph = digit; 82290001Sglebius tmpl = fpv; 83290001Sglebius M_LSHIFT(digit, fpv); 84290001Sglebius M_LSHIFT(digit, fpv); 85290001Sglebius M_ADD(digit, fpv, tmph, tmpl); 86290001Sglebius *cpend++ = (u_char)digit; 87290001Sglebius } 8854359Sroberto 89290001Sglebius /* decide whether to round or simply extend by zeros */ 90290001Sglebius if (dec > 0) { 91290001Sglebius /* only '0' digits left -- just reposition end */ 92290001Sglebius cpend += dec; 93290001Sglebius } else { 94290001Sglebius /* some bits remain in 'fpv'; do round */ 95290001Sglebius u_char *tp = cpend; 96290001Sglebius int carry = ((fpv & 0x80000000) != 0); 97290001Sglebius 98293896Sglebius for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { 99290001Sglebius *--tp += 1; 100290001Sglebius if (*tp == 10) 10154359Sroberto *tp = 0; 102290001Sglebius else 103290001Sglebius carry = FALSE; 10454359Sroberto } 105290001Sglebius 106290001Sglebius if (tp < cp) /* rounding from 999 to 1000 or similiar? */ 107290001Sglebius 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 */ 117290001Sglebius while (cp < cpdec && *cp == 0) 11854359Sroberto cp++; 119290001Sglebius if (cp >= cpdec) 120290001Sglebius cp = cpdec - 1; 12154359Sroberto 12254359Sroberto bp = buf; 12354359Sroberto if (neg) 124290001Sglebius *bp++ = '-'; 12554359Sroberto while (cp < cpend) { 12654359Sroberto if (cp == cpdec) 127290001Sglebius *bp++ = '.'; 128290001Sglebius *bp++ = (char)(*cp++) + '0'; 12954359Sroberto } 13054359Sroberto *bp = '\0'; 13154359Sroberto 13254359Sroberto /* 13354359Sroberto * Done! 13454359Sroberto */ 13554359Sroberto return buf; 13654359Sroberto} 137290001Sglebius 138290001Sglebius 139290001Sglebiuschar * 140290001Sglebiusmfptoa( 141290001Sglebius u_int32 fpi, 142290001Sglebius u_int32 fpf, 143290001Sglebius short ndec 144290001Sglebius ) 145290001Sglebius{ 146290001Sglebius int isneg; 147290001Sglebius 148290001Sglebius isneg = M_ISNEG(fpi); 149290001Sglebius if (isneg) { 150290001Sglebius M_NEG(fpi, fpf); 151290001Sglebius } 152290001Sglebius 153290001Sglebius return dolfptoa(fpi, fpf, isneg, ndec, FALSE); 154290001Sglebius} 155290001Sglebius 156290001Sglebius 157290001Sglebiuschar * 158290001Sglebiusmfptoms( 159290001Sglebius u_int32 fpi, 160290001Sglebius u_int32 fpf, 161290001Sglebius short ndec 162290001Sglebius ) 163290001Sglebius{ 164290001Sglebius int isneg; 165290001Sglebius 166290001Sglebius isneg = M_ISNEG(fpi); 167290001Sglebius if (isneg) { 168290001Sglebius M_NEG(fpi, fpf); 169290001Sglebius } 170290001Sglebius 171290001Sglebius return dolfptoa(fpi, fpf, isneg, ndec, TRUE); 172290001Sglebius} 173290001Sglebius 174290001Sglebius 175