mirror of
https://github.com/pret/pokediamond.git
synced 2026-10-05 00:47:32 -04:00
493 lines
14 KiB
C
493 lines
14 KiB
C
#include "global.h"
|
|
#include "OS_printf.h"
|
|
|
|
typedef struct printfStr
|
|
{
|
|
s32 spaceLeft;
|
|
s8 *stringEnd;
|
|
s8 *stringStart;
|
|
} printfStr;
|
|
|
|
void string_put_char(struct printfStr *dest, s8 value);
|
|
void string_fill_char(struct printfStr *dest, s8 value, s32 count);
|
|
void string_put_string(struct printfStr *dest, const s8 *src, s32 count);
|
|
|
|
ARM_FUNC void string_put_char(struct printfStr *dest, s8 value)
|
|
{
|
|
if (dest->spaceLeft != 0)
|
|
{
|
|
dest->stringEnd[0] = value;
|
|
dest->spaceLeft--;
|
|
}
|
|
dest->stringEnd++;
|
|
}
|
|
|
|
ARM_FUNC void string_fill_char(struct printfStr *dest, s8 value, s32 count)
|
|
{
|
|
if (count <= 0)
|
|
return;
|
|
|
|
u32 written = 0;
|
|
u32 spaceLeft = (u32)dest->spaceLeft;
|
|
u32 toWrite = spaceLeft > (u32)count ? count : spaceLeft;
|
|
|
|
while (written < toWrite)
|
|
{
|
|
dest->stringEnd[written] = value;
|
|
written++;
|
|
}
|
|
|
|
dest->spaceLeft -= toWrite;
|
|
dest->stringEnd += count; // this is wrong but matching...
|
|
}
|
|
|
|
ARM_FUNC void string_put_string(struct printfStr *dest, const s8 *src, s32 count)
|
|
{
|
|
if (count <= 0)
|
|
return;
|
|
|
|
u32 written = 0;
|
|
u32 spaceLeft = (u32)dest->spaceLeft;
|
|
u32 toWrite = spaceLeft > (u32)count ? count : spaceLeft;
|
|
|
|
while (written < toWrite)
|
|
{
|
|
dest->stringEnd[written] = src[written];
|
|
written++;
|
|
}
|
|
|
|
dest->spaceLeft -= toWrite;
|
|
dest->stringEnd += count; // this is wrong but matching...
|
|
}
|
|
|
|
ARM_FUNC s32 OS_SPrintf(s8 *buffer, const s8 *format, ...)
|
|
{
|
|
void *args = (void *)((u32 *)((u32)&format & ~0x3) + 1); // hack since mwccarm doesn't have <stdarg.h> apparently
|
|
return OS_VSPrintf(buffer, format, args);
|
|
}
|
|
|
|
ARM_FUNC s32 OS_VSPrintf(s8 *buffer, const s8 *format, void *args)
|
|
{
|
|
return OS_VSNPrintf(buffer, 0x7FFFFFFF, format, args);
|
|
}
|
|
|
|
ARM_FUNC s32 OS_SNPrintf(s8 *buffer, s32 bufsz, const s8 *format, ...)
|
|
{
|
|
void *args = (void *)((u32 *)((u32)&format & ~0x3) + 1); // hack since mwccarm doesn't have <stdarg.h> apparently
|
|
return OS_VSNPrintf(buffer, bufsz, format, args);
|
|
}
|
|
|
|
#define va_arg(list, ty) *(ty *)((u32 *)(list = (void *)((u32 *)(list) + 1)) - 1)
|
|
#define va_arg_64(list, sgn) *((sgn##64 *)(list = (void *)((sgn##64 *)(list) + 1)) - 1)
|
|
|
|
ARM_FUNC s32 OS_VSNPrintf(s8 *buffer, s32 bufsz, const s8 *format, void *args)
|
|
{
|
|
s8 buf[24];
|
|
s32 n_buf;
|
|
s8 prefix[2];
|
|
s32 n_prefix;
|
|
|
|
const s8 *s = format;
|
|
|
|
printfStr str;
|
|
str.spaceLeft = bufsz;
|
|
str.stringStart = buffer;
|
|
str.stringEnd = buffer;
|
|
|
|
while (*s)
|
|
{
|
|
// matches:
|
|
// binary range (hex range) [dec range]
|
|
// 1000 0001-1001 1111 (0x81-0x9F) [129-159]
|
|
// 1110 0000-1111 1100 (0xE0-0xFC) [224-252]
|
|
if ((u32)(((u8)*s ^ 0x20) - 0xa1) < 0x3c)
|
|
{
|
|
string_put_char(&str, *s++);
|
|
if (*s)
|
|
{
|
|
string_put_char(&str, *s++);
|
|
}
|
|
}
|
|
else if (*s != '%')
|
|
{
|
|
string_put_char(&str, *s++);
|
|
}
|
|
else
|
|
{
|
|
enum {
|
|
blank = 000001,
|
|
plus = 000002,
|
|
sharp = 000004,
|
|
minus = 000010,
|
|
zero = 000020,
|
|
l1 = 000040,
|
|
h1 = 000100,
|
|
l2 = 000200,
|
|
h2 = 000400,
|
|
usigned = 010000,
|
|
end
|
|
};
|
|
s32 flag = 0, width = 0, precision = -1, radix = 10;
|
|
s8 hex = 'a' - 10;
|
|
const s8 *p_start = s;
|
|
for (;;)
|
|
{
|
|
switch (*++s)
|
|
{
|
|
case '+':
|
|
if (s[-1] != ' ')
|
|
break;
|
|
flag |= plus;
|
|
continue;
|
|
case ' ':
|
|
flag |= blank;
|
|
continue;
|
|
case '-':
|
|
flag |= minus;
|
|
continue;
|
|
case '0':
|
|
flag |= zero;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (*s == '*')
|
|
{
|
|
++s, width = va_arg(args, s32);
|
|
if (width < 0)
|
|
{
|
|
width = -width, flag |= minus;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((*s >= '0') && (*s <= '9'))
|
|
{
|
|
width = (width * 10) + *s++ - '0';
|
|
}
|
|
}
|
|
|
|
if (*s == '.')
|
|
{
|
|
++s, precision = 0;
|
|
if (*s == '*')
|
|
{
|
|
++s, precision = va_arg(args, s32);
|
|
if (precision < 0)
|
|
{
|
|
precision = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((*s >= '0') && (*s <= '9'))
|
|
{
|
|
precision = (precision * 10) + *s++ - '0';
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (*s)
|
|
{
|
|
case 'h':
|
|
if (*++s != 'h') {
|
|
flag |= h1;
|
|
}
|
|
else {
|
|
++s, flag |= h2;
|
|
}
|
|
break;
|
|
case 'l':
|
|
if (*++s != 'l') {
|
|
flag |= l1;
|
|
}
|
|
else {
|
|
++s, flag |= l2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (*s)
|
|
{
|
|
case 'd':
|
|
case 'i':
|
|
goto put_int;
|
|
case 'o':
|
|
radix = 8;
|
|
flag |= usigned;
|
|
goto put_int;
|
|
case 'u':
|
|
flag |= usigned;
|
|
goto put_int;
|
|
case 'X':
|
|
hex = 'A' - 10;
|
|
goto put_hex;
|
|
case 'x':
|
|
goto put_hex;
|
|
case 'p':
|
|
flag |= sharp;
|
|
precision = 8;
|
|
goto put_hex;
|
|
case 'c':
|
|
if (precision >= 0)
|
|
goto put_invalid;
|
|
{
|
|
s32 v = va_arg(args, s32);
|
|
width -= 1;
|
|
if (flag & minus)
|
|
{
|
|
string_put_char(&str, (s8)v);
|
|
string_fill_char(&str, ' ', width);
|
|
}
|
|
else
|
|
{
|
|
s8 pad = (s8)((flag & zero) ? '0' : ' ');
|
|
string_fill_char(&str, pad, width);
|
|
string_put_char(&str, (s8)v);
|
|
}
|
|
++s;
|
|
}
|
|
break;
|
|
case 's':
|
|
{
|
|
s32 n_bufs = 0;
|
|
const s8 *p_bufs = va_arg(args, const s8 *);
|
|
if (precision < 0)
|
|
{
|
|
while (p_bufs[n_bufs])
|
|
{
|
|
++n_bufs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (n_bufs < precision && p_bufs[n_bufs])
|
|
{
|
|
++n_bufs;
|
|
}
|
|
}
|
|
width -= n_bufs;
|
|
if (flag & minus)
|
|
{
|
|
string_put_string(&str, p_bufs, n_bufs);
|
|
string_fill_char(&str, ' ', width);
|
|
}
|
|
else
|
|
{
|
|
s8 pad = (s8)((flag & zero) ? '0' : ' ');
|
|
string_fill_char(&str, pad, width);
|
|
string_put_string(&str, p_bufs, n_bufs);
|
|
}
|
|
++s;
|
|
}
|
|
break;
|
|
case 'n':
|
|
{
|
|
s32 count = str.stringEnd - str.stringStart;
|
|
if (!(flag & h2))
|
|
{
|
|
if (flag & h1)
|
|
{
|
|
*va_arg(args, s16 *) = (s16)count;
|
|
}
|
|
else if (flag & l2)
|
|
{
|
|
*va_arg(args, u64 *) = (u64)count;
|
|
}
|
|
else
|
|
{
|
|
*va_arg(args, s32 *) = count;
|
|
}
|
|
}
|
|
}
|
|
++s;
|
|
break;
|
|
case '%':
|
|
if (p_start + 1 != s)
|
|
goto put_invalid;
|
|
string_put_char(&str, *s++);
|
|
break;
|
|
|
|
default:
|
|
goto put_invalid;
|
|
|
|
put_invalid:
|
|
string_put_string(&str, p_start, s - p_start);
|
|
break;
|
|
|
|
put_hex:
|
|
radix = 16;
|
|
flag |= usigned;
|
|
put_int:
|
|
{
|
|
u64 value = 0;
|
|
n_prefix = 0;
|
|
if (flag & minus)
|
|
{
|
|
flag &= ~zero;
|
|
}
|
|
if (precision < 0)
|
|
{
|
|
precision = 1;
|
|
}
|
|
else
|
|
{
|
|
flag &= ~zero;
|
|
}
|
|
if (flag & usigned)
|
|
{
|
|
if (flag & h2)
|
|
{
|
|
value = va_arg(args, u8);
|
|
}
|
|
else if (flag & h1)
|
|
{
|
|
value = va_arg(args, u16);
|
|
}
|
|
else if (flag & l2)
|
|
{
|
|
value = va_arg_64(args, u);
|
|
}
|
|
else
|
|
{
|
|
value = va_arg(args, u32);
|
|
}
|
|
flag &= ~(plus | blank);
|
|
if (flag & sharp)
|
|
{
|
|
if (radix == 16)
|
|
{
|
|
if (value != 0)
|
|
{
|
|
prefix[0] = (s8)(hex + (10 + 'x' - 'a'));
|
|
prefix[1] = '0';
|
|
n_prefix = 2;
|
|
}
|
|
}
|
|
else if (radix == 8)
|
|
{
|
|
prefix[0] = '0';
|
|
n_prefix = 1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (flag & h2) {
|
|
value = va_arg(args, s8);
|
|
} else if (flag & h1) {
|
|
value = va_arg(args, s16);
|
|
} else if (flag & l2) {
|
|
value = va_arg_64(args, u);
|
|
} else {
|
|
value = va_arg(args, s32);
|
|
}
|
|
|
|
if ((value >> 32) & 0x80000000) {
|
|
value = ~value + 1;
|
|
prefix[0] = '-';
|
|
n_prefix = 1;
|
|
} else {
|
|
if (value || precision) {
|
|
if (flag & plus) {
|
|
prefix[0] = '+';
|
|
n_prefix = 1;
|
|
} else if (flag & blank) {
|
|
prefix[0] = ' ';
|
|
n_prefix = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
n_buf = 0;
|
|
switch (radix) {
|
|
case 8:
|
|
while (value != 0) {
|
|
s32 octDig = (s32) (value & 0x7);
|
|
value >>= 3;
|
|
buf[n_buf++] = (s8) (octDig + '0');
|
|
}
|
|
break;
|
|
case 10:
|
|
if ((value >> 32) == 0) {
|
|
u32 v = (u32) value;
|
|
while (v) {
|
|
u32 div10 = v / 10;
|
|
s32 dig = (s32) (v - (div10 * 10));
|
|
v = div10;
|
|
buf[n_buf++] = (s8) (dig + '0');
|
|
}
|
|
} else {
|
|
while (value) {
|
|
u64 div10 = value / 10;
|
|
s32 dig = (s32) (value - (div10 * 10));
|
|
value = div10;
|
|
buf[n_buf++] = (s8) (dig + '0');
|
|
}
|
|
}
|
|
break;
|
|
case 16:
|
|
while (value != 0) {
|
|
s32 hexDig = (s32) (value & 0xf);
|
|
value >>= 4;
|
|
buf[n_buf++] = (s8) ((hexDig < 10) ? (hexDig + '0') : (hexDig + hex));
|
|
}
|
|
break;
|
|
}
|
|
if (n_prefix > 0 && prefix[0] == '0') {
|
|
n_prefix = 0;
|
|
buf[n_buf++] = '0';
|
|
}
|
|
}
|
|
goto put_to_stream;
|
|
|
|
put_to_stream:
|
|
{
|
|
s32 n_pad = (s32)(precision - n_buf);
|
|
if (flag & zero)
|
|
{
|
|
if (n_pad < width - n_buf - n_prefix)
|
|
{
|
|
n_pad = (s32)(width - n_buf - n_prefix);
|
|
}
|
|
}
|
|
if (n_pad > 0)
|
|
{
|
|
width -= n_pad;
|
|
}
|
|
|
|
width -= n_prefix + n_buf;
|
|
if (!(flag & minus))
|
|
{
|
|
string_fill_char(&str, ' ', width);
|
|
}
|
|
while (n_prefix > 0)
|
|
{
|
|
string_put_char(&str, prefix[--n_prefix]);
|
|
}
|
|
string_fill_char(&str, '0', n_pad);
|
|
while (n_buf > 0)
|
|
{
|
|
string_put_char(&str, buf[--n_buf]);
|
|
}
|
|
if (flag & minus)
|
|
{
|
|
string_fill_char(&str, ' ', width);
|
|
}
|
|
++s;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (str.spaceLeft != 0)
|
|
{
|
|
*str.stringEnd = '\0';
|
|
}
|
|
else if (bufsz != 0)
|
|
{
|
|
str.stringStart[bufsz - 1] = '\0';
|
|
}
|
|
return str.stringEnd - str.stringStart;
|
|
}
|