/* * dolfptoa - do the grunge work of converting an l_fp number to decimal */ #include #include "ntp_fp.h" #include "lib_strbuf.h" #include "ntp_string.h" #include "ntp_stdlib.h" char * dolfptoa( u_long fpi, u_long fpv, int neg, short ndec, int msec ) { register u_char *cp, *cpend; register u_long lwork; register int dec; u_char cbuf[24]; u_char *cpdec; char *buf; char *bp; /* * Get a string buffer before starting */ LIB_GETBUF(buf); /* * Zero the character buffer */ memset((char *) cbuf, 0, sizeof(cbuf)); /* * safeguard against sign extensions and other mishaps on 64 bit platforms * the code following is designed for and only for 32-bit inputs and * only 32-bit worth of input are supplied. */ fpi &= 0xffffffff; fpv &= 0xffffffff; /* * Work on the integral part. This is biased by what I know * compiles fairly well for a 68000. */ cp = cpend = &cbuf[10]; lwork = fpi; if (lwork & 0xffff0000) { register u_long lten = 10; register u_long ltmp; do { ltmp = lwork; lwork /= lten; ltmp -= (lwork << 3) + (lwork << 1); if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ *--cp = (u_char)ltmp; } while (lwork & 0xffff0000); } if (lwork != 0) { register u_short sten = 10; register u_short stmp; register u_short swork = (u_short)lwork; do { stmp = swork; swork = (u_short) (swork/sten); stmp = (u_short)(stmp - ((swork<<3) + (swork<<1))); if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ *--cp = (u_char)stmp; } while (swork != 0); } /* * Done that, now deal with the problem of the fraction. First * determine the number of decimal places. */ if (msec) { dec = ndec + 3; if (dec < 3) dec = 3; cpdec = &cbuf[13]; } else { dec = ndec; if (dec < 0) dec = 0; cpdec = &cbuf[10]; } if (dec > 12) dec = 12; /* * If there's a fraction to deal with, do so. */ if (fpv != 0) { l_fp work; work.l_ui = 0; work.l_uf = fpv; while (dec > 0) { l_fp ftmp; dec--; /* * The scheme here is to multiply the * fraction (0.1234...) by ten. This moves * a junk of BCD into the units part. * record that and iterate. */ work.l_ui = 0; L_LSHIFT(&work); ftmp = work; L_LSHIFT(&work); L_LSHIFT(&work); L_ADD(&work, &ftmp); *cpend++ = (u_char)work.l_ui; if (work.l_uf == 0) break; if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */ } /* * Rounding is rotten */ if (work.l_uf & 0x80000000) { register u_char *tp = cpend; *(--tp) += 1; while (*tp >= 10) { *tp = 0; *(--tp) += 1; }; if (tp < cp) cp = tp; } } cpend += dec; /* * We've now got the fraction in cbuf[], with cp pointing at * the first character, cpend pointing past the last, and * cpdec pointing at the first character past the decimal. * Remove leading zeros, then format the number into the * buffer. */ while (cp < cpdec) { if (*cp != 0) break; cp++; } if (cp == cpdec) --cp; bp = buf; if (neg) *bp++ = '-'; while (cp < cpend) { if (cp == cpdec) *bp++ = '.'; *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */ } *bp = '\0'; /* * Done! */ return buf; }