1 /* $NetBSD: dolfptoa.c,v 1.1.1.1 2009/12/13 16:55:02 kardel Exp $ */ 2 3 /* 4 * dolfptoa - do the grunge work of converting an l_fp number to decimal 5 */ 6 #include <stdio.h> 7 8 #include "ntp_fp.h" 9 #include "lib_strbuf.h" 10 #include "ntp_string.h" 11 #include "ntp_stdlib.h" 12 13 char * 14 dolfptoa( 15 u_long fpi, 16 u_long fpv, 17 int neg, 18 short ndec, 19 int msec 20 ) 21 { 22 register u_char *cp, *cpend; 23 register u_long lwork; 24 register int dec; 25 u_char cbuf[24]; 26 u_char *cpdec; 27 char *buf; 28 char *bp; 29 30 /* 31 * Get a string buffer before starting 32 */ 33 LIB_GETBUF(buf); 34 35 /* 36 * Zero the character buffer 37 */ 38 memset((char *) cbuf, 0, sizeof(cbuf)); 39 40 /* 41 * safeguard against sign extensions and other mishaps on 64 bit platforms 42 * the code following is designed for and only for 32-bit inputs and 43 * only 32-bit worth of input are supplied. 44 */ 45 fpi &= 0xffffffff; 46 fpv &= 0xffffffff; 47 48 /* 49 * Work on the integral part. This is biased by what I know 50 * compiles fairly well for a 68000. 51 */ 52 cp = cpend = &cbuf[10]; 53 lwork = fpi; 54 if (lwork & 0xffff0000) { 55 register u_long lten = 10; 56 register u_long ltmp; 57 58 do { 59 ltmp = lwork; 60 lwork /= lten; 61 ltmp -= (lwork << 3) + (lwork << 1); 62 if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ 63 *--cp = (u_char)ltmp; 64 } while (lwork & 0xffff0000); 65 } 66 if (lwork != 0) { 67 register u_short sten = 10; 68 register u_short stmp; 69 register u_short swork = (u_short)lwork; 70 71 do { 72 stmp = swork; 73 swork = (u_short) (swork/sten); 74 stmp = (u_short)(stmp - ((swork<<3) + (swork<<1))); 75 if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ 76 *--cp = (u_char)stmp; 77 } while (swork != 0); 78 } 79 80 /* 81 * Done that, now deal with the problem of the fraction. First 82 * determine the number of decimal places. 83 */ 84 if (msec) { 85 dec = ndec + 3; 86 if (dec < 3) 87 dec = 3; 88 cpdec = &cbuf[13]; 89 } else { 90 dec = ndec; 91 if (dec < 0) 92 dec = 0; 93 cpdec = &cbuf[10]; 94 } 95 if (dec > 12) 96 dec = 12; 97 98 /* 99 * If there's a fraction to deal with, do so. 100 */ 101 if (fpv != 0) { 102 l_fp work; 103 104 work.l_ui = 0; 105 work.l_uf = fpv; 106 while (dec > 0) { 107 l_fp ftmp; 108 109 dec--; 110 /* 111 * The scheme here is to multiply the 112 * fraction (0.1234...) by ten. This moves 113 * a junk of BCD into the units part. 114 * record that and iterate. 115 */ 116 work.l_ui = 0; 117 L_LSHIFT(&work); 118 ftmp = work; 119 L_LSHIFT(&work); 120 L_LSHIFT(&work); 121 L_ADD(&work, &ftmp); 122 *cpend++ = (u_char)work.l_ui; 123 if (work.l_uf == 0) 124 break; 125 if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */ 126 } 127 128 /* 129 * Rounding is rotten 130 */ 131 if (work.l_uf & 0x80000000) { 132 register u_char *tp = cpend; 133 134 *(--tp) += 1; 135 while (*tp >= 10) { 136 *tp = 0; 137 *(--tp) += 1; 138 }; 139 if (tp < cp) 140 cp = tp; 141 } 142 } 143 cpend += dec; 144 145 146 /* 147 * We've now got the fraction in cbuf[], with cp pointing at 148 * the first character, cpend pointing past the last, and 149 * cpdec pointing at the first character past the decimal. 150 * Remove leading zeros, then format the number into the 151 * buffer. 152 */ 153 while (cp < cpdec) { 154 if (*cp != 0) 155 break; 156 cp++; 157 } 158 if (cp == cpdec) 159 --cp; 160 161 bp = buf; 162 if (neg) 163 *bp++ = '-'; 164 while (cp < cpend) { 165 if (cp == cpdec) 166 *bp++ = '.'; 167 *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */ 168 } 169 *bp = '\0'; 170 171 /* 172 * Done! 173 */ 174 return buf; 175 } 176