Implement libultra/xprintf.c, libultra/xlitob.c, & libultra/xldtob.c

This commit is contained in:
Cuyler36
2023-02-24 02:43:37 -05:00
parent 3aa0f82a49
commit bde34adfa7
6 changed files with 633 additions and 7 deletions
+14
View File
@@ -6,6 +6,20 @@ libforest/ReconfigBATs.c:
.text: [0x8005adac, 0x8005aed4]
libc64/aprintf.c:
.text: [0x8005cbdc, 0x8005cc14]
libultra/xldtob.c:
.text: [0x8005e918, 0x8005f2a0]
.rodata: [0x800ab110, 0x800ab158]
.sdata: [0x80217df8, 0x80217e08]
sdata2: [0x80219210, 0x80219230]
libultra/xlitob.c:
.text: [0x8005f2a0, 0x8005f4cc]
.data: [0x800ddb60, 0x800ddb88]
libultra/xprintf.c:
.text: [0x8005f4cc, 0x8005ff74]
.rodata: [0x800ab158, 0x800ab170]
.data: [0x800ddb88, 0x800ddd20]
.sdata: [0x80217e08, 0x80217e10]
.sdata2: [0x80219230, 0x80219238]
JSystem/JKernel/JKRHeap.cpp:
.text: [0x80063748, 0x80064028]
.data: [0x800ddf20, 0x800ddf98]
+32 -2
View File
@@ -5,10 +5,40 @@
#include "va_args.h"
#ifdef __cplusplus
extern "C"{
extern "C" {
#endif
extern int _Printf(void* (*prout_func)(void*, const char*, int), void* arg, const char* fmt, va_list ap);
typedef struct {
/* 0x0 */ union {
/* 0x0 */ s64 ll;
/* 0x0 */ f64 ld;
} v;
/* 0x8 */ char* s;
/* 0xC */ s32 n0;
/* 0x10 */ s32 nz0;
/* 0x14 */ s32 n1;
/* 0x18 */ s32 nz1;
/* 0x1C */ s32 n2;
/* 0x20 */ s32 nz2;
/* 0x24 */ s32 prec;
/* 0x28 */ s32 width;
/* 0x2C */ u32 nchar;
/* 0x30 */ u32 flags;
/* 0x34 */ u8 qual;
} _Pft; // size = 0x38
typedef void* (*PrintCallback)(void*, const char*, int);
#define FLAGS_SPACE 1
#define FLAGS_PLUS 2
#define FLAGS_MINUS 4
#define FLAGS_HASH 8
#define FLAGS_ZERO 16
static void _Litob(_Pft* args, u8 type);
static void _Ldtob(_Pft* args, u8 type);
extern int _Printf(void* (*prout_func)(void*, const char*, int), void* arg,
const char* fmt, va_list ap);
#ifdef __cplusplus
}
+288
View File
@@ -0,0 +1,288 @@
#include <stdlib.h> /* ldiv & ldiv_t */
#include <string.h> /* memcpy */
#include "xprintf.h"
#define BUFF_LEN 0x20
s16 _Ldunscale(s16*, _Pft*);
void _Genld(_Pft*, u8, u8*, s16, s16);
const f64 pows[] = {10e0L, 10e1L, 10e3L, 10e7L, 10e15L,
10e31L, 10e63L, 10e127L, 10e255L};
/* float properties */
#define _D0 0
#define _DBIAS 0x3FF
#define _DLONG 1
#define _DOFF 4
#define _FBIAS 0x7E
#define _FOFF 7
#define _FRND 1
#define _LBIAS 0x3FFE
#define _LOFF 15
/* integer properties */
#define _C2 1
#define _CSIGN 1
#define _ILONG 0
#define _MBMAX 8
#define NAN 2
#define INF 1
#define FINITE -1
#define _DFRAC ((1 << _DOFF) - 1)
#define _DMASK (0x7FFF & ~_DFRAC)
#define _DMAX ((1 << (15 - _DOFF)) - 1)
#define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1))
#define _DSIGN 0x8000
#if _D0 == 3
#define _D1 2 /* little-endian order */
#define _D2 1
#define _D3 0
#else
#define _D1 1 /* big-endian order */
#define _D2 2
#define _D3 3
#endif
#pragma optimize_for_size off
void _Ldtob(_Pft* args, u8 type) {
u8 buff[BUFF_LEN];
u8* ptr = buff;
u32 sp70;
f64 val = args->v.ld;
/* maybe struct? */
s16 err;
s16 nsig;
s16 exp;
int i;
int n;
f64 factor;
int gen;
int j;
int lo;
u8 drop;
int n2;
f64* pows_p;
if (args->prec < 0) {
args->prec = 6;
} else if (args->prec == 0 && (type == 'g' || type == 'G')) {
args->prec = 1;
}
err = _Ldunscale(&exp, (_Pft*)args);
if (err > 0) {
memcpy(args->s, err == 2 ? "NaN" : "Inf", args->n1 = 3);
return;
}
if (err == 0) {
nsig = 0;
exp = 0;
} else {
if (val < 0) {
val = -val;
}
if ((exp = (exp * 30103) / 100000 - 4) < 0) {
n = (3 - (int)exp) & ~3;
pows_p = (double*)pows;
exp = -n;
for (; n > 0; n >>= 1, pows_p++) {
if ((n & 1) != 0) {
val *= *pows_p;
}
}
} else if (exp > 0) {
factor = 1;
exp &= ~3;
pows_p = (double*)pows;
for (n = exp; n > 0; n >>= 1, pows_p++) {
if ((n & 1) != 0) {
factor *= *pows_p;
}
}
val /= factor;
}
gen = ((type == 'f') ? exp + 10 : 6) + args->prec;
if (gen > 0x13) {
gen = 0x13;
}
*ptr++ = '0';
while (gen > 0 && 0 < val) {
lo = val;
if ((gen -= 8) > 0) {
val = (val - lo) * 1.0e8;
}
ptr = ptr + 8;
for (j = 8; lo > 0 && --j >= 0;) {
const ldiv_t qr = ldiv(lo, 10);
*--ptr = qr.rem + '0';
lo = qr.quot;
}
while (--j >= 0) {
ptr--;
*ptr = '0';
}
ptr += 8;
}
gen = ptr - &buff[1];
for (ptr = &buff[1], exp += 7; *ptr == '0'; ptr++) {
--gen, --exp;
}
nsig = ((type == 'f') ? exp + 1 : ((type == 'e' || type == 'E') ? 1 : 0)) +
args->prec;
if (gen < nsig) {
nsig = gen;
}
if (nsig > 0) {
char drop = nsig < gen && '5' <= ptr[nsig] ? '9' : '0';
int n;
for (n = nsig; ptr[--n] == drop;) {
--nsig;
}
if (drop == '9') {
++ptr[n];
}
if (n < 0) {
--ptr, ++nsig, ++exp;
}
}
}
_Genld((_Pft*)args, type, ptr, nsig, exp);
}
s16 _Ldunscale(s16* pex, _Pft* px) {
u16* ps = (u16*)px;
s16 xchar = (ps[_D0] & _DMASK) >> _DOFF;
if (xchar == _DMAX) { /* NaN or INF */
*pex = 0;
return (s16)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ? NAN : INF);
} else if (0 < xchar) {
ps[_D0] = (ps[_D0] & ~_DMASK) | (_DBIAS << _DOFF);
*pex = xchar - (_DBIAS - 1);
return FINITE;
}
if (0 > xchar) {
return NAN;
} else {
*pex = 0;
return 0;
}
}
void _Genld(_Pft* px, u8 code, u8* p, s16 nsig, s16 xexp) {
u8 point = '.';
if (nsig <= 0) {
nsig = 1,
p = (u8*)"0";
}
if (code == 'f' || ((code == 'g' || code == 'G') && (-4 <= xexp) &&
(xexp < px->prec))) { /* 'f' format */
int x;
++xexp; /* change to leading digit count */
if (code != 'f') { /* fixup for 'g' */
if (!(px->flags & FLAGS_HASH) && nsig < px->prec) {
px->prec = nsig;
}
if ((px->prec -= xexp) < 0) {
px->prec = 0;
}
}
if (xexp <= 0) { /* digits only to right of point */
px->s[px->n1++] = '0';
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (px->prec < -xexp) {
xexp = -px->prec;
}
px->nz1 = -xexp;
px->prec += xexp;
if (px->prec < nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p, x = px->n2 = nsig);
px->nz2 = px->prec - x;
} else if (nsig < xexp) { /* zeros before point */
memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = xexp - nsig;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1] = point, ++px->n2;
}
px->nz2 = px->prec;
} else { /* enough digits before point */
memcpy(&px->s[px->n1], p, xexp);
px->n1 += xexp;
nsig -= xexp;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (px->prec < nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p + (int)xexp, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
} else { /* 'e' format */
if (code == 'g' || code == 'G') { /* fixup for 'g' */
if (nsig < px->prec) {
px->prec = nsig;
}
if (--px->prec < 0) {
px->prec = 0;
}
code = code == 'g' ? 'e' : 'E';
}
px->s[px->n1++] = *p++;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (0 < px->prec) { /* put fraction digits */
if (px->prec < --nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
p = (u8*)&px->s[px->n1]; /* put exponent */
*p++ = code;
if (0 <= xexp) {
*p++ = '+';
} else { /* negative exponent */
*p++ = '-';
xexp = -xexp;
}
if (100 <= xexp) { /* put oversize exponent */
if (1000 <= xexp) {
*p++ = xexp / 1000 + '0', xexp %= 1000;
}
*p++ = xexp / 100 + '0', xexp %= 100;
}
*p++ = xexp / 10 + '0', xexp %= 10;
*p++ = xexp + '0';
px->n2 = p - (u8*)&px->s[px->n1];
}
if ((px->flags & (FLAGS_ZERO | FLAGS_MINUS)) ==
FLAGS_ZERO) { /* pad with leading zeros */
s32 n = px->n0 + px->n1 + px->nz1 + px->n2 + px->nz2;
if (n < px->width) {
px->nz0 = px->width - n;
}
}
}
#pragma optimize_for_size reset
+59
View File
@@ -0,0 +1,59 @@
#include <stdlib.h> /* lldiv & lldiv_t */
#include <string.h> /* memcpy */
#include "libultra/xprintf.h"
#define BUFF_LEN 0x18
u8 ldigs[] = "0123456789abcdef";
u8 udigs[] = "0123456789ABCDEF";
static void _Litob(_Pft* args, u8 type) {
u8* numMap;
int base;
int idx;
u64 num;
lldiv_t test;
char buff[BUFF_LEN];
if (type == 'X') {
numMap = udigs;
} else {
numMap = ldigs;
}
base = (type == 'o') ? 8 : ((type != 'x' && type != 'X') ? 10 : 16);
idx = BUFF_LEN;
num = args->v.ll;
if ((type == 'd' || type == 'i') && args->v.ll < 0) {
num = -num;
}
if (num != 0 || args->prec != 0) {
buff[--idx] = numMap[num % base];
}
args->v.ll = num / base;
while (args->v.ll > 0 && idx > 0) {
const lldiv_t quotrem = lldiv(args->v.ll, base);
args->v.ll = quotrem.quot;
buff[--idx] = numMap[quotrem.rem];
}
args->n1 = BUFF_LEN - idx;
memcpy(args->s, buff + idx, args->n1);
if (args->n1 < args->prec) {
args->nz0 = args->prec - args->n1;
}
if (args->prec < 0 &&
(args->flags & (FLAGS_ZERO | FLAGS_MINUS)) == FLAGS_ZERO) {
idx = args->width - args->n0 - args->nz0 - args->n1;
if (idx > 0) {
args->nz0 += idx;
}
}
}
-5
View File
@@ -1,5 +0,0 @@
#include "libultra/xprintf.h"
extern int _Printf(void* (*prout_func)(void*, const char*, int), void* arg, const char* fmt, va_list ap) {
}
+240
View File
@@ -0,0 +1,240 @@
#include <string.h> /* strchr */
#include "libultra/xprintf.h"
#define ATOI(i, a) \
for (i = 0; *a >= '0' && *a <= '9'; a++) \
if (i < 999) i = *a + i * 10 - '0';
#define _PROUT(fmt, _size) \
if (_size > 0) { \
arg = pfn(arg, fmt, _size); \
if (arg != NULL) \
x.nchar += _size; \
else \
return x.nchar; \
}
#define _PROUT2(fmt, _size) \
if ((u32)(_size) != 0) { \
arg = pfn(arg, fmt, (u32)(_size)); \
if (arg != NULL) \
x.nchar += _size; \
else \
return x.nchar; \
}
#define _PAD(m, src, extracond) \
if (extracond && m > 0) { \
s32 i; \
s32 j; \
for (j = m; j > 0; j -= i) { \
if (j > 32) \
i = 32; \
else \
i = j; \
_PROUT(src, i); \
} \
}
static const char spaces[] = " ";
static const char zeroes[] = "00000000000000000000000000000000";
void _Putfld(_Pft*, va_list, u8, u8*);
/* These functions seem to have 04,p enabled */
#pragma optimize_for_size off
s32 _Printf(void* (*pfn)(void*, const char*, int), void* arg, const char* fmt,
va_list ap) {
/* Unused static variables to match position of locals */
static int unused0;
static int unused1;
static int unused2;
static char fchar[] = " +-#0";
static u32 fbit[6] = {FLAGS_SPACE, FLAGS_PLUS, FLAGS_MINUS,
FLAGS_HASH, FLAGS_ZERO, 0};
_Pft x;
x.nchar = 0;
while (TRUE) {
u8 qual;
const u8* s = (u8*)fmt;
u8 c;
const char* t;
u8 ac[0x20];
u8* temp;
for (c = *s; c != 0 && c != '%';) {
c = *++s;
}
temp = (u8*)fmt;
_PROUT2(fmt, s - temp);
if (c == 0) {
return x.nchar;
}
fmt = (char*)++s;
x.flags = 0;
for (; (t = strchr(fchar, *s)) != NULL; s++) {
x.flags |= fbit[t - fchar];
}
if (*s == '*') {
x.width = va_arg(ap, s32);
if (x.width < 0) {
x.width = -x.width;
x.flags |= FLAGS_MINUS;
}
s++;
} else {
ATOI(x.width, s);
}
if (*s != '.') {
x.prec = -1;
} else {
s++;
if (*s == '*') {
x.prec = va_arg(ap, s32);
s++;
} else {
ATOI(x.prec, s);
}
}
if (strchr("hlL", *s) != NULL) {
qual = *s++;
} else {
qual = 0;
}
x.qual = qual;
if (qual == 'l' && *s == 'l') {
x.qual = 'L';
s++;
}
_Putfld(&x, ap, *s, ac);
x.width -= x.n0 + x.nz0 + x.n1 + x.nz1 + x.n2 + x.nz2;
_PAD(x.width, spaces, !(x.flags & FLAGS_MINUS));
_PROUT((char*)ac, x.n0);
_PAD(x.nz0, zeroes, 1);
_PROUT(x.s, x.n1);
_PAD(x.nz1, zeroes, 1);
_PROUT((char*)(&x.s[x.n1]), x.n2)
_PAD(x.nz2, zeroes, 1);
_PAD(x.width, spaces, x.flags & FLAGS_MINUS);
fmt = (char*)s + 1;
}
}
void _Putfld(_Pft* px, va_list ap, u8 code, u8* ac) {
px->n0 = px->nz0 = px->n1 = px->nz1 = px->n2 = px->nz2 = 0;
switch ((u8)code) {
case 'c':
ac[px->n0++] = va_arg(ap, u32);
break;
case 'd':
case 'i':
if (px->qual == 'l') {
px->v.ll = va_arg(ap, s32);
} else if (px->qual == 'L') {
px->v.ll = va_arg(ap, s64);
} else {
px->v.ll = va_arg(ap, s32);
}
if (px->qual == 'h') {
px->v.ll = (s16)px->v.ll;
}
if (px->v.ll < 0) {
ac[px->n0++] = '-';
} else if (px->flags & FLAGS_PLUS) {
ac[px->n0++] = '+';
} else if (px->flags & FLAGS_SPACE) {
ac[px->n0++] = ' ';
}
px->s = (char*)&ac[px->n0];
_Litob(px, code);
break;
case 'x':
case 'X':
case 'u':
case 'o':
if (px->qual == 'l') {
px->v.ll = va_arg(ap, s32);
} else if (px->qual == 'L') {
px->v.ll = va_arg(ap, s64);
} else {
px->v.ll = va_arg(ap, s32);
}
if (px->qual == 'h') {
px->v.ll = (u16)px->v.ll;
} else if (px->qual == 0) {
px->v.ll = (u32)px->v.ll;
}
if (px->flags & FLAGS_HASH) {
ac[px->n0++] = '0';
if (code == 'x' || code == 'X') {
ac[px->n0++] = code;
}
}
px->s = (char*)&ac[px->n0];
_Litob(px, code);
break;
case 'e':
case 'f':
case 'g':
case 'E':
case 'G':
px->v.ld = px->qual == 'L' ? va_arg(ap, f64) : va_arg(ap, f64);
if (*(u16*)&px->v.ll & 0x8000) {
ac[px->n0++] = '-';
} else {
if (px->flags & FLAGS_PLUS) {
ac[px->n0++] = '+';
} else if (px->flags & FLAGS_SPACE) {
ac[px->n0++] = ' ';
}
}
px->s = (char*)&ac[px->n0];
_Ldtob(px, code);
break;
case 'n':
if (px->qual == 'h') {
*(va_arg(ap, s16*)) = px->nchar;
} else if (px->qual == 'l') {
*va_arg(ap, s32*) = px->nchar;
} else if (px->qual == 'L') {
*va_arg(ap, s64*) = px->nchar;
} else {
*va_arg(ap, s32*) = px->nchar;
}
break;
case 'p':
px->v.ll = (s32)va_arg(ap, void*);
px->s = (char*)&ac[px->n0];
_Litob(px, 'x');
break;
case 's':
px->s = va_arg(ap, char*);
px->n1 = strlen(px->s);
if (px->prec >= 0 && px->n1 > px->prec) {
px->n1 = px->prec;
}
break;
case '%':
ac[px->n0++] = '%';
break;
default:
ac[px->n0++] = code;
break;
}
}
#pragma optimize_for_size reset