sm64

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

_Printf.c (8649B)


      1 #include "libultra_internal.h"
      2 #include <stdarg.h>
      3 #include <string.h>
      4 #include "printf.h"
      5 
      6 #define ATOI(i, a)                                                                                     \
      7     for (i = 0; *a >= '0' && *a <= '9'; a++)                                                           \
      8         if (i < 999)                                                                                   \
      9             i = i * 10 + *a - '0';
     10 #define _PROUT(dst, fmt, _size)                                                                        \
     11     if (_size > 0) {                                                                                   \
     12         dst = prout(dst, fmt, _size);                                                                  \
     13         if (dst != 0)                                                                                  \
     14             sp78.size += _size;                                                                        \
     15         else                                                                                           \
     16             return sp78.size;                                                                          \
     17     }
     18 #define _PAD(i, m, c, src, extracond)                                                                  \
     19     if (extracond && m > 0)                                                                            \
     20         for (i = m; i > 0; i -= c) {                                                                   \
     21             if ((u32) i > 32)                                                                          \
     22                 c = 32;                                                                                \
     23             else                                                                                       \
     24                 c = i;                                                                                 \
     25             _PROUT(dst, src, c);                                                                       \
     26         }
     27 
     28 char spaces[] = "                                ";
     29 char zeroes[] = "00000000000000000000000000000000";
     30 
     31 static void _Putfld(printf_struct *, va_list *, fmt_type, fmt_type *);
     32 
     33 s32 _Printf(char *(*prout)(char *, const char *, size_t), char *dst, const char *fmt, va_list args) {
     34     static const char flags_str[] = " +-#0";
     35     static const u32 flags_arr[] = { FLAGS_SPACE, FLAGS_PLUS, FLAGS_MINUS, FLAGS_HASH, FLAGS_ZERO, 0 };
     36 
     37     printf_struct sp78;
     38     const fmt_type *fmt_ptr;
     39     fmt_type c;
     40     const char *flag_index;
     41     fmt_type sp4c[0x20]; // probably a buffer?
     42     s32 sp48, sp44, sp40, sp3c, sp38, sp34, sp30, sp2c, sp28, sp24;
     43     sp78.size = 0;
     44     while (TRUE) {
     45         fmt_ptr = (fmt_type *) fmt;
     46 #if defined(VERSION_SH) || defined(VERSION_CN)
     47         // new version: don't point fmt_ptr beyond NUL character
     48         while ((c = *fmt_ptr) != 0 && c != '%') {
     49             fmt_ptr++;
     50         }
     51 #else
     52         while ((c = *fmt_ptr++) > 0) {
     53             if (c == '%') {
     54                 fmt_ptr--;
     55                 break;
     56             }
     57         }
     58 #endif
     59         _PROUT(dst, fmt, fmt_ptr - (fmt_type *) fmt);
     60         if (c == 0) {
     61             return sp78.size;
     62         }
     63         fmt = (char *) ++fmt_ptr;
     64         sp78.flags = 0;
     65         for (; (flag_index = strchr(flags_str, *fmt_ptr)) != NULL; fmt_ptr++) {
     66             sp78.flags |= flags_arr[flag_index - flags_str];
     67         }
     68         if (*fmt_ptr == '*') {
     69             sp78.width = va_arg(args, s32);
     70             if (sp78.width < 0) {
     71                 sp78.width = -sp78.width;
     72                 sp78.flags |= FLAGS_MINUS;
     73             }
     74             fmt_ptr++;
     75         } else {
     76             ATOI(sp78.width, fmt_ptr);
     77         }
     78         if (*fmt_ptr != '.') {
     79             sp78.precision = -1;
     80         } else {
     81             fmt_ptr++;
     82             if (*fmt_ptr == '*') {
     83                 sp78.precision = va_arg(args, s32);
     84                 fmt_ptr++;
     85             } else {
     86                 ATOI(sp78.precision, fmt_ptr);
     87             }
     88         }
     89         sp78.length = strchr("hlL", *fmt_ptr) != NULL ? *fmt_ptr++ : '\0';
     90 
     91         if (sp78.length == 'l' && *fmt_ptr == 'l') {
     92             sp78.length = 'L';
     93             fmt_ptr++;
     94         }
     95         _Putfld(&sp78, &args, *fmt_ptr, sp4c);
     96         sp78.width -= sp78.part1_len + sp78.num_leading_zeros + sp78.part2_len + sp78.num_mid_zeros
     97                       + sp78.part3_len + sp78.num_trailing_zeros;
     98         _PAD(sp44, sp78.width, sp48, spaces, !(sp78.flags & FLAGS_MINUS));
     99         _PROUT(dst, (char *) sp4c, sp78.part1_len);
    100         _PAD(sp3c, sp78.num_leading_zeros, sp40, zeroes, 1);
    101         _PROUT(dst, sp78.buff, sp78.part2_len);
    102         _PAD(sp34, sp78.num_mid_zeros, sp38, zeroes, 1);
    103         _PROUT(dst, (char *) (&sp78.buff[sp78.part2_len]), sp78.part3_len)
    104         _PAD(sp2c, sp78.num_trailing_zeros, sp30, zeroes, 1);
    105         _PAD(sp24, sp78.width, sp28, spaces, sp78.flags & FLAGS_MINUS);
    106         fmt = (char *) fmt_ptr + 1;
    107     }
    108 }
    109 
    110 static void _Putfld(printf_struct *a0, va_list *args, fmt_type type, fmt_type *buff) {
    111     a0->part1_len = a0->num_leading_zeros = a0->part2_len = a0->num_mid_zeros = a0->part3_len =
    112         a0->num_trailing_zeros = 0;
    113 
    114     switch (type) {
    115 
    116         case 'c':
    117             buff[a0->part1_len++] = va_arg(*args, u32);
    118             break;
    119 
    120         case 'd':
    121         case 'i':
    122             if (a0->length == 'l') {
    123                 a0->value.s64 = va_arg(*args, s32);
    124             } else if (a0->length == 'L') {
    125                 a0->value.s64 = va_arg(*args, s64);
    126             } else {
    127                 a0->value.s64 = va_arg(*args, s32);
    128             }
    129 
    130             if (a0->length == 'h') {
    131                 a0->value.s64 = (s16) a0->value.s64;
    132             }
    133 
    134             if (a0->value.s64 < 0) {
    135                 buff[a0->part1_len++] = '-';
    136             } else if (a0->flags & FLAGS_PLUS) {
    137                 buff[a0->part1_len++] = '+';
    138             } else if (a0->flags & FLAGS_SPACE) {
    139                 buff[a0->part1_len++] = ' ';
    140             }
    141 
    142             a0->buff = (char *) &buff[a0->part1_len];
    143 
    144             _Litob(a0, type);
    145             break;
    146 
    147         case 'x':
    148         case 'X':
    149         case 'u':
    150         case 'o':
    151             if (a0->length == 'l') {
    152                 a0->value.s64 = va_arg(*args, s32);
    153             } else if (a0->length == 'L') {
    154                 a0->value.s64 = va_arg(*args, s64);
    155             } else {
    156                 a0->value.s64 = va_arg(*args, s32);
    157             }
    158 
    159             if (a0->length == 'h') {
    160                 a0->value.s64 = (u16) a0->value.s64;
    161             } else if (a0->length == 0) {
    162                 a0->value.s64 = (u32) a0->value.s64;
    163             }
    164 
    165             if (a0->flags & FLAGS_HASH) {
    166                 buff[a0->part1_len++] = '0';
    167                 if (type == 'x' || type == 'X') {
    168 
    169                     buff[a0->part1_len++] = type;
    170                 }
    171             }
    172             a0->buff = (char *) &buff[a0->part1_len];
    173             _Litob(a0, type);
    174             break;
    175 
    176         case 'e':
    177         case 'f':
    178         case 'g':
    179         case 'E':
    180         case 'G':
    181             //... okay?
    182             a0->value.f64 = a0->length == 'L' ? va_arg(*args, f64) : va_arg(*args, f64);
    183 
    184             if (a0->value.u16 & 0x8000) {
    185                 buff[a0->part1_len++] = '-';
    186             } else {
    187                 if (a0->flags & FLAGS_PLUS) {
    188                     buff[a0->part1_len++] = '+';
    189                 } else if (a0->flags & FLAGS_SPACE) {
    190                     buff[a0->part1_len++] = ' ';
    191                 }
    192             }
    193 
    194             a0->buff = (char *) &buff[a0->part1_len];
    195             _Ldtob(a0, type);
    196             break;
    197 
    198         case 'n':
    199             if (a0->length == 'h') {
    200                 *(va_arg(*args, u16 *)) = a0->size;
    201             } else if (a0->length == 'l') {
    202                 *va_arg(*args, u32 *) = a0->size;
    203             } else if (a0->length == 'L') {
    204                 *va_arg(*args, u64 *) = a0->size;
    205             } else {
    206                 *va_arg(*args, u32 *) = a0->size;
    207             }
    208             break;
    209 
    210         case 'p':
    211             a0->value.s64 = (intptr_t) va_arg(*args, void *);
    212             a0->buff = (char *) &buff[a0->part1_len];
    213             _Litob(a0, 'x');
    214             break;
    215 
    216         case 's':
    217             a0->buff = va_arg(*args, char *);
    218             a0->part2_len = strlen(a0->buff);
    219             if (a0->precision >= 0 && a0->part2_len > a0->precision) {
    220                 a0->part2_len = a0->precision;
    221             }
    222             break;
    223 
    224         case '%':
    225             buff[a0->part1_len++] = '%';
    226             break;
    227 
    228         default:
    229             buff[a0->part1_len++] = type;
    230             break;
    231     }
    232 }