summaryrefslogtreecommitdiff
path: root/arm9/lib/NitroSDK/src/OS_printf.c
diff options
context:
space:
mode:
authorred031000 <rubenru09@aol.com>2021-07-23 01:11:15 +0100
committerred031000 <rubenru09@aol.com>2021-07-23 01:12:27 +0100
commit5bf13c7f48fe91c7902ce50250bc1a5a2398a2ae (patch)
tree2e91e60bdb7a9174b16d8ca1b532809d4ae2e5b6 /arm9/lib/NitroSDK/src/OS_printf.c
parentc2d91a2d997afd01fa4f40e1e16d5ee85557c9a8 (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.c492
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;
+}