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