Annotation of embedaddon/ntp/libntp/dolfptoa.c, revision 1.1.1.1

1.1       misho       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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>