_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 }