154359Sroberto/* 254359Sroberto * dolfptoa - do the grunge work of converting an l_fp number to decimal 354359Sroberto */ 4280849Scy#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( 14280849Scy u_int32 fpi, 15280849Scy u_int32 fpv, 1654359Sroberto int neg, 17132451Sroberto short ndec, 1854359Sroberto int msec 1954359Sroberto ) 2054359Sroberto{ 21280849Scy u_char *cp, *cpend, *cpdec; 22280849Scy int dec; 2354359Sroberto u_char cbuf[24]; 24280849Scy 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 */ 34280849Scy ZERO(cbuf); 3554359Sroberto 3654359Sroberto /* 37280849Scy * Work on the integral part. This should work reasonable on 38280849Scy * all machines with 32 bit arithmetic. Please note that 32 bits 39280849Scy * can *always* be represented with at most 10 decimal digits, 40280849Scy * including a possible rounding from the fractional part. 4154359Sroberto */ 42280849Scy cp = cpend = cpdec = &cbuf[10]; 43293423Sdelphij for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { 44280849Scy /* can add another digit */ 45280849Scy u_int32 digit; 46280849Scy 47280849Scy digit = fpi; 48280849Scy fpi /= 10U; 49280849Scy digit -= (fpi << 3) + (fpi << 1); /* i*10 */ 50280849Scy *--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 */ 57280849Scy dec = ndec; 58280849Scy if (dec < 0) 59280849Scy dec = 0; 6054359Sroberto if (msec) { 61280849Scy dec += 3; 62280849Scy cpdec += 3; 6354359Sroberto } 64280849Scy if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) 65293423Sdelphij dec = (int)(sizeof(cbuf) - (cpend - cbuf)); 6654359Sroberto 6754359Sroberto /* 6854359Sroberto * If there's a fraction to deal with, do so. 6954359Sroberto */ 70280849Scy for (/*NOP*/; dec > 0 && fpv != 0; dec--) { 71280849Scy u_int32 digit, tmph, tmpl; 72280849Scy 7354359Sroberto /* 74280849Scy * The scheme here is to multiply the fraction 75280849Scy * (0.1234...) by ten. This moves a junk of BCD into 76280849Scy * the units part. record that and iterate. 77280849Scy * multiply by shift/add in two dwords. 7854359Sroberto */ 79280849Scy digit = 0; 80280849Scy M_LSHIFT(digit, fpv); 81280849Scy tmph = digit; 82280849Scy tmpl = fpv; 83280849Scy M_LSHIFT(digit, fpv); 84280849Scy M_LSHIFT(digit, fpv); 85280849Scy M_ADD(digit, fpv, tmph, tmpl); 86280849Scy *cpend++ = (u_char)digit; 87280849Scy } 8854359Sroberto 89280849Scy /* decide whether to round or simply extend by zeros */ 90280849Scy if (dec > 0) { 91280849Scy /* only '0' digits left -- just reposition end */ 92280849Scy cpend += dec; 93280849Scy } else { 94280849Scy /* some bits remain in 'fpv'; do round */ 95280849Scy u_char *tp = cpend; 96280849Scy int carry = ((fpv & 0x80000000) != 0); 97280849Scy 98293423Sdelphij for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { 99280849Scy *--tp += 1; 100280849Scy if (*tp == 10) 10154359Sroberto *tp = 0; 102280849Scy else 103280849Scy carry = FALSE; 10454359Sroberto } 105280849Scy 106280849Scy if (tp < cp) /* rounding from 999 to 1000 or similiar? */ 107280849Scy 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 */ 117280849Scy while (cp < cpdec && *cp == 0) 11854359Sroberto cp++; 119280849Scy if (cp >= cpdec) 120280849Scy cp = cpdec - 1; 12154359Sroberto 12254359Sroberto bp = buf; 12354359Sroberto if (neg) 124280849Scy *bp++ = '-'; 12554359Sroberto while (cp < cpend) { 12654359Sroberto if (cp == cpdec) 127280849Scy *bp++ = '.'; 128280849Scy *bp++ = (char)(*cp++) + '0'; 12954359Sroberto } 13054359Sroberto *bp = '\0'; 13154359Sroberto 13254359Sroberto /* 13354359Sroberto * Done! 13454359Sroberto */ 13554359Sroberto return buf; 13654359Sroberto} 137280849Scy 138280849Scy 139280849Scychar * 140280849Scymfptoa( 141280849Scy u_int32 fpi, 142280849Scy u_int32 fpf, 143280849Scy short ndec 144280849Scy ) 145280849Scy{ 146280849Scy int isneg; 147280849Scy 148280849Scy isneg = M_ISNEG(fpi); 149280849Scy if (isneg) { 150280849Scy M_NEG(fpi, fpf); 151280849Scy } 152280849Scy 153280849Scy return dolfptoa(fpi, fpf, isneg, ndec, FALSE); 154280849Scy} 155280849Scy 156280849Scy 157280849Scychar * 158280849Scymfptoms( 159280849Scy u_int32 fpi, 160280849Scy u_int32 fpf, 161280849Scy short ndec 162280849Scy ) 163280849Scy{ 164280849Scy int isneg; 165280849Scy 166280849Scy isneg = M_ISNEG(fpi); 167280849Scy if (isneg) { 168280849Scy M_NEG(fpi, fpf); 169280849Scy } 170280849Scy 171280849Scy return dolfptoa(fpi, fpf, isneg, ndec, TRUE); 172280849Scy} 173280849Scy 174280849Scy 175