diff options
author | red031000 <rubenru09@aol.com> | 2021-07-23 01:11:15 +0100 |
---|---|---|
committer | red031000 <rubenru09@aol.com> | 2021-07-23 01:12:27 +0100 |
commit | 5bf13c7f48fe91c7902ce50250bc1a5a2398a2ae (patch) | |
tree | 2e91e60bdb7a9174b16d8ca1b532809d4ae2e5b6 /arm9/lib/NitroSDK/src/OS_printf.c | |
parent | c2d91a2d997afd01fa4f40e1e16d5ee85557c9a8 (diff) |
separate out libs to libc, libnns and NitroSDK
Diffstat (limited to 'arm9/lib/NitroSDK/src/OS_printf.c')
-rw-r--r-- | arm9/lib/NitroSDK/src/OS_printf.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/arm9/lib/NitroSDK/src/OS_printf.c b/arm9/lib/NitroSDK/src/OS_printf.c new file mode 100644 index 00000000..414f0db9 --- /dev/null +++ b/arm9/lib/NitroSDK/src/OS_printf.c @@ -0,0 +1,492 @@ +#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; +} |