sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

_Ldtob.c (8209B)


      1 #include "libultra_internal.h"
      2 #include <macros.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include "printf.h"
      6 
      7 #define BUFF_LEN 0x20
      8 
      9 static s16 _Ldunscale(s16 *, printf_struct *);
     10 static void _Genld(printf_struct *, fmt_type, fmt_type *, s16, s16);
     11 
     12 const double pows[] = { 10e0L, 10e1L, 10e3L, 10e7L, 10e15L, 10e31L, 10e63L, 10e127L, 10e255L };
     13 
     14 /* float properties */
     15 #define _D0 0
     16 #define _DBIAS 0x3ff
     17 #define _DLONG 1
     18 #define _DOFF 4
     19 #define _FBIAS 0x7e
     20 #define _FOFF 7
     21 #define _FRND 1
     22 #define _LBIAS 0x3ffe
     23 #define _LOFF 15
     24 /* integer properties */
     25 #define _C2 1
     26 #define _CSIGN 1
     27 #define _ILONG 0
     28 #define _MBMAX 8
     29 #define NAN 2
     30 #define INF 1
     31 #define FINITE -1
     32 #define _DFRAC ((1 << _DOFF) - 1)
     33 #define _DMASK (0x7fff & ~_DFRAC)
     34 #define _DMAX ((1 << (15 - _DOFF)) - 1)
     35 #define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1))
     36 #define _DSIGN 0x8000
     37 #if _D0 == 3
     38 #define _D1 2 /* little-endian order */
     39 #define _D2 1
     40 #define _D3 0
     41 #else
     42 #define _D1 1 /* big-endian order */
     43 #define _D2 2
     44 #define _D3 3
     45 #endif
     46 
     47 void _Ldtob(printf_struct *args, fmt_type type) {
     48     fmt_type buff[BUFF_LEN];
     49     fmt_type *ptr;
     50     f64 val;
     51     /* maybe struct? */
     52     s16 err;
     53     s16 nsig;
     54     s16 exp;
     55 
     56     s32 i;
     57     s32 n;
     58     f64 factor;
     59     s32 gen;
     60     s32 j;
     61 
     62     ptr = buff;
     63     val = args->value.f64;
     64     if (args->precision < 0) {
     65         args->precision = 6;
     66     } else {
     67         if (args->precision == 0 && (type == 'g' || type == 'G')) {
     68             args->precision = 1;
     69         }
     70     }
     71     err = _Ldunscale(&exp, args);
     72     if (err > 0) {
     73         memcpy(args->buff, err == 2 ? "NaN" : "Inf", args->part2_len = 3);
     74         return;
     75     }
     76     if (err == 0) {
     77         nsig = 0;
     78         exp = 0;
     79     } else {
     80         if (val < 0) {
     81             val = -val;
     82         }
     83         exp = exp * 30103 / 0x000186A0 - 4;
     84         if (exp < 0) {
     85             n = (-exp + 3) & ~3;
     86             exp = -n;
     87             for (i = 0; n > 0; n >>= 1, i++) {
     88                 if ((n & 1) != 0) {
     89                     val *= pows[i];
     90                 }
     91             }
     92         } else {
     93             if (exp > 0) {
     94                 factor = 1;
     95                 exp &= ~3;
     96                 for (n = exp, i = 0; n > 0; n >>= 1, i++) {
     97                     if ((n & 1) != 0) {
     98                         factor *= pows[i];
     99                     }
    100                 }
    101                 val /= factor;
    102             }
    103         }
    104         gen = args->precision + ((type == 'f') ? exp + 10 : 6);
    105         if (gen > 0x13) {
    106             gen = 0x13;
    107         }
    108         *ptr++ = '0';
    109         while (gen > 0 && 0 < val) {
    110             s32 lo = val;
    111             if ((gen -= 8) > 0) {
    112                 val = (val - lo) * 1.0e8;
    113             }
    114             ptr = ptr + 8;
    115             for (j = 8; lo > 0 && --j >= 0;) {
    116                 ldiv_t qr = ldiv(lo, 10);
    117                 *--ptr = qr.rem + '0';
    118                 lo = qr.quot;
    119             }
    120             while (--j >= 0) {
    121                 ptr--;
    122                 *ptr = '0';
    123             }
    124             ptr += 8;
    125         }
    126 
    127         gen = ptr - &buff[1];
    128         for (ptr = &buff[1], exp += 7; *ptr == '0'; ptr++) {
    129             --gen, --exp;
    130         }
    131 
    132         nsig = args->precision + ((type == 'f') ? exp + 1 : ((type == 'e' || type == 'E') ? 1 : 0));
    133         if (gen < nsig) {
    134             nsig = gen;
    135         }
    136         if (nsig > 0) {
    137             fmt_type drop = (nsig < gen && ptr[nsig] > '4') ? '9' : '0';
    138             s32 n2;
    139 
    140             for (n2 = nsig; ptr[--n2] == drop;) {
    141                 nsig--;
    142             }
    143             if (drop == '9') {
    144                 ptr[n2]++;
    145             }
    146             if (n2 < 0) {
    147                 --ptr, ++nsig, ++exp;
    148             }
    149         }
    150     }
    151     _Genld(args, type, ptr, nsig, exp);
    152 }
    153 
    154 static s16 _Ldunscale(s16 *pex, printf_struct *px) {
    155 
    156     unsigned short *ps = (unsigned short *) px;
    157     short xchar = (ps[_D0] & _DMASK) >> _DOFF;
    158     if (xchar == _DMAX) { /* NaN or INF */
    159         *pex = 0;
    160         return (s16)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ? NAN : INF);
    161     } else if (0 < xchar) {
    162         ps[_D0] = (ps[_D0] & ~_DMASK) | (_DBIAS << _DOFF);
    163         *pex = xchar - (_DBIAS - 1);
    164         return (FINITE);
    165     }
    166     if (0 > xchar) {
    167         return NAN;
    168     } else {
    169         *pex = 0;
    170         return (0);
    171     }
    172 }
    173 
    174 static void _Genld(printf_struct *px, fmt_type code, fmt_type *p, s16 nsig, s16 xexp) {
    175     const fmt_type point = '.';
    176     if (nsig <= 0) {
    177         nsig = 1,
    178 
    179         p = (fmt_type *) "0";
    180     }
    181 
    182     if (code == 'f'
    183         || ((code == 'g' || code == 'G') && (-4 <= xexp) && (xexp < px->precision))) { /* 'f' format */
    184         ++xexp;            /* change to leading digit count */
    185         if (code != 'f') { /* fixup for 'g' */
    186             if (!(px->flags & FLAGS_HASH) && nsig < px->precision) {
    187                 px->precision = nsig;
    188             }
    189             if ((px->precision -= xexp) < 0) {
    190                 px->precision = 0;
    191             }
    192         }
    193         if (xexp <= 0) { /* digits only to right of point */
    194             px->buff[px->part2_len++] = '0';
    195             if (0 < px->precision || px->flags & FLAGS_HASH) {
    196                 px->buff[px->part2_len++] = point;
    197             }
    198             if (px->precision < -xexp) {
    199                 xexp = -px->precision;
    200             }
    201             px->num_mid_zeros = -xexp;
    202             px->precision += xexp;
    203             if (px->precision < nsig) {
    204                 nsig = px->precision;
    205             }
    206             memcpy(&px->buff[px->part2_len], p, px->part3_len = nsig);
    207             px->num_trailing_zeros = px->precision - nsig;
    208         } else if (nsig < xexp) { /* zeros before point */
    209             memcpy(&px->buff[px->part2_len], p, nsig);
    210             px->part2_len += nsig;
    211             px->num_mid_zeros = xexp - nsig;
    212             if (0 < px->precision || px->flags & FLAGS_HASH) {
    213                 px->buff[px->part2_len] = point, ++px->part3_len;
    214             }
    215             px->num_trailing_zeros = px->precision;
    216         } else { /* enough digits before point */
    217             memcpy(&px->buff[px->part2_len], p, xexp);
    218             px->part2_len += xexp;
    219             nsig -= xexp;
    220             if (0 < px->precision || px->flags & FLAGS_HASH) {
    221                 px->buff[px->part2_len++] = point;
    222             }
    223             if (px->precision < nsig) {
    224                 nsig = px->precision;
    225             }
    226             memcpy(&px->buff[px->part2_len], p + xexp, nsig);
    227             px->part2_len += nsig;
    228             px->num_mid_zeros = px->precision - nsig;
    229         }
    230     } else {                              /* 'e' format */
    231         if (code == 'g' || code == 'G') { /* fixup for 'g' */
    232             if (nsig < px->precision) {
    233                 px->precision = nsig;
    234             }
    235             if (--px->precision < 0) {
    236                 px->precision = 0;
    237             }
    238             code = code == 'g' ? 'e' : 'E';
    239         }
    240         px->buff[px->part2_len++] = *p++;
    241         if (0 < px->precision || px->flags & FLAGS_HASH) {
    242             px->buff[px->part2_len++] = point;
    243         }
    244         if (0 < px->precision) { /* put fraction digits */
    245             if (px->precision < --nsig) {
    246                 nsig = px->precision;
    247             }
    248             memcpy(&px->buff[px->part2_len], p, nsig);
    249             px->part2_len += nsig;
    250             px->num_mid_zeros = px->precision - nsig;
    251         }
    252         p = (fmt_type *) &px->buff[px->part2_len]; /* put exponent */
    253         *p++ = code;
    254         if (0 <= xexp) {
    255             *p++ = '+';
    256         } else { /* negative exponent */
    257             *p++ = '-';
    258             xexp = -xexp;
    259         }
    260         if (100 <= xexp) { /* put oversize exponent */
    261             if (1000 <= xexp) {
    262                 *p++ = xexp / 1000 + '0', xexp %= 1000;
    263             }
    264             *p++ = xexp / 100 + '0', xexp %= 100;
    265         }
    266         *p++ = xexp / 10 + '0', xexp %= 10;
    267         *p++ = xexp + '0';
    268         px->part3_len = p - (fmt_type *) &px->buff[px->part2_len];
    269     }
    270     if ((px->flags & (FLAGS_ZERO | FLAGS_MINUS)) == FLAGS_ZERO) { /* pad with leading zeros */
    271         int n =
    272             px->part1_len + px->part2_len + px->num_mid_zeros + px->part3_len + px->num_trailing_zeros;
    273 
    274         if (n < px->width) {
    275             px->num_leading_zeros = px->width - n;
    276         }
    277     }
    278 }