diff --git a/Makefile b/Makefile
index d9dd5de..b0cec20 100644
--- a/Makefile
+++ b/Makefile
@@ -58,5 +58,5 @@
@$(MAKE) -j4 --no-print-directory -C arm11 NO_DEBUG=1
firm_builder $(TARGET).firm $(ENTRY9) $(ENTRY11) $(SECTION0_ADR) $(SECTION0_TYPE) \
arm9/$(TARGET).bin $(SECTION1_ADR) $(SECTION1_TYPE) arm11/$(TARGET).bin
- @7z a -mx -m0=ARM -m1=LZMA2 $(TARGET)$(VERS_STRING).7z $(TARGET).firm
- @7z u -mx -m0=LZMA2 fastboot3DS$(VERS_STRING).7z LICENSE.txt README.md
+ @7z a -mx -m0=ARM -m1=LZMA $(TARGET)$(VERS_STRING).7z $(TARGET).firm
+ @7z u -mx -m0=PPMD $(TARGET)$(VERS_STRING).7z LICENSE.txt README.md
diff --git a/include/arm9/console.h b/include/arm9/console.h
index 98399c2..75cf6fc 100644
--- a/include/arm9/console.h
+++ b/include/arm9/console.h
@@ -188,6 +188,8 @@
u16 consoleGetRGB565Color(u8 colorIndex);
+ssize_t con_write(UNUSED struct _reent *r,UNUSED void *fd,const char *ptr, size_t len);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/arm9/fmt.h b/include/arm9/fmt.h
new file mode 100644
index 0000000..d6dc629
--- /dev/null
+++ b/include/arm9/fmt.h
@@ -0,0 +1,39 @@
+#pragma once
+
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2016-2017 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+#include
+#include "types.h"
+
+
+
+u32 ee_vsprintf(char *buf, const char *fmt, va_list args);
+u32 ee_sprintf(char *buf, const char *fmt, ...);
+u32 ee_snprintf(char *const buf, UNUSED u32 size, const char *const fmt, ...);
+u32 ee_vsnprintf(char *const buf, UNUSED u32 size, const char *const fmt, va_list arg);
+u32 ee_printf(const char *const fmt, ...);
+u32 ee_puts(const char *const str);
diff --git a/include/arm9/myassert.h b/include/arm9/myassert.h
new file mode 100644
index 0000000..4029d0e
--- /dev/null
+++ b/include/arm9/myassert.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "types.h"
+
+
+
+noreturn void __myassert(const char *const str, u32 line);
+
+#ifdef NDEBUG
+#define myassert(c) ((void)0)
+#else
+#define myassert(c) ((c) ? ((void)0) : __myassert(#c ", " __FILE__, __LINE__))
+#endif
diff --git a/include/util.h b/include/util.h
index 5bdbdee..91d079a 100644
--- a/include/util.h
+++ b/include/util.h
@@ -18,7 +18,6 @@
* along with this program. If not, see .
*/
-#include
#include "types.h"
#define min(a,b) (u32) a < (u32) b ? (u32) a : (u32) b
@@ -29,6 +28,8 @@
void wait(u32 cycles);
+int mysscanf(const char *s, const char *fmt, ...);
+
// case insensitive string compare function
int strnicmp(const char *str1, const char *str2, u32 len);
diff --git a/source/arm9/config.c b/source/arm9/config.c
index eaee9d7..57dcfe5 100644
--- a/source/arm9/config.c
+++ b/source/arm9/config.c
@@ -23,6 +23,7 @@
#include
#include
#include "types.h"
+#include "arm9/fmt.h"
#include "mem_map.h"
#include "fatfs/ff.h"
#include "arm9/fsutils.h"
@@ -404,7 +405,7 @@
filebuf[curLen++] = 0x0a;
}
- sprintf(&filebuf[curLen], "%s%s%s", keyName, def, textData);
+ ee_sprintf(&filebuf[curLen], "%s%s%s", keyName, def, textData);
return &filebuf[curLen + keyLen + defLen];
}
@@ -492,7 +493,7 @@
return false;
// no non ASCII chars
- if(!isascii(c))
+ if(!((unsigned char)c <= 127))
return false;
}
diff --git a/source/arm9/console.c b/source/arm9/console.c
index 463da54..2bd4a62 100644
--- a/source/arm9/console.c
+++ b/source/arm9/console.c
@@ -4,8 +4,8 @@
#include
#include
-#include
#include "types.h"
+#include "arm9/fmt.h"
#include "gfx.h"
#include "util.h"
#include "arm9/console.h"
@@ -221,7 +221,7 @@
//---------------------------------------
case 'A':
consumed = 0;
- assigned = sscanf(escapeseq,"[%dA%n", ¶meter, &consumed);
+ assigned = mysscanf(escapeseq,"[%dA%n", ¶meter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY - parameter) < 0 ? 0 : currentConsole->cursorY - parameter;
@@ -229,7 +229,7 @@
break;
case 'B':
consumed = 0;
- assigned = sscanf(escapeseq,"[%dB%n", ¶meter, &consumed);
+ assigned = mysscanf(escapeseq,"[%dB%n", ¶meter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + parameter;
@@ -237,7 +237,7 @@
break;
case 'C':
consumed = 0;
- assigned = sscanf(escapeseq,"[%dC%n", ¶meter, &consumed);
+ assigned = mysscanf(escapeseq,"[%dC%n", ¶meter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + parameter;
@@ -245,7 +245,7 @@
break;
case 'D':
consumed = 0;
- assigned = sscanf(escapeseq,"[%dD%n", ¶meter, &consumed);
+ assigned = mysscanf(escapeseq,"[%dD%n", ¶meter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX - parameter) < 0 ? 0 : currentConsole->cursorX - parameter;
@@ -259,7 +259,7 @@
{
int x, y;
char c;
- if(sscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) {
+ if(mysscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
@@ -267,7 +267,7 @@
}
x = y = 1;
- if(sscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) {
+ if(mysscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
@@ -275,7 +275,7 @@
}
x = y = 1;
- if(sscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) {
+ if(mysscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
@@ -283,7 +283,7 @@
}
x = y = 1;
- if(sscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) {
+ if(mysscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
@@ -342,9 +342,9 @@
if (escapelen == 1) {
consumed = 1;
} else if (memchr(escapeseq,';',escapelen)) {
- sscanf(escapeseq,"%d;%n", ¶meter, &consumed);
+ mysscanf(escapeseq,"%d;%n", ¶meter, &consumed);
} else {
- sscanf(escapeseq,"%dm%n", ¶meter, &consumed);
+ mysscanf(escapeseq,"%dm%n", ¶meter, &consumed);
}
escapeseq += consumed;
@@ -464,51 +464,10 @@
return count;
}
-static const devoptab_t dotab_stdout = {
- "con",
- 0,
- NULL,
- NULL,
- con_write,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
//---------------------------------------------------------------------------------
PrintConsole* consoleInit(int screen, PrintConsole* console, bool clear) {
//---------------------------------------------------------------------------------
- static bool firstConsoleInit = true;
-
- if(firstConsoleInit) {
- devoptab_list[STD_OUT] = &dotab_stdout;
- devoptab_list[STD_ERR] = &dotab_stdout;
-
- setvbuf(stdout, NULL , _IONBF, 0);
- setvbuf(stderr, NULL , _IONBF, 0);
-
- firstConsoleInit = false;
- }
-
if(console) {
currentConsole = console;
} else {
@@ -698,6 +657,7 @@
break;
case 10:
newRow();
+ // falls through
case 13:
currentConsole->cursorX = 0;
break;
@@ -711,7 +671,7 @@
//---------------------------------------------------------------------------------
void consoleClear(void) {
//---------------------------------------------------------------------------------
- iprintf("\x1b[2J");
+ ee_printf("\x1b[2J");
}
//---------------------------------------------------------------------------------
diff --git a/source/arm9/crypto.c b/source/arm9/crypto.c
index a7f2979..8a08e23 100644
--- a/source/arm9/crypto.c
+++ b/source/arm9/crypto.c
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-#include
#include
+#include "arm9/myassert.h"
#include "mem_map.h"
#include "types.h"
#include "arm9/crypto.h"
@@ -200,8 +200,8 @@
void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4])
{
- assert(keyslot < 0x40);
- assert(key != NULL);
+ myassert(keyslot < 0x40);
+ myassert(key != NULL);
REG_AESCNT = (u32)orderEndianess<<23;
@@ -237,7 +237,7 @@
void AES_selectKeyslot(u8 keyslot)
{
- assert(keyslot < 0x40);
+ myassert(keyslot < 0x40);
REG_AESKEYSEL = keyslot;
REG_AESCNT |= AES_UPDATE_KEYSLOT;
@@ -245,8 +245,8 @@
void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3])
{
- assert(ctx != NULL);
- assert(nonce != NULL);
+ myassert(ctx != NULL);
+ myassert(nonce != NULL);
ctx->ctrIvNonceParams = (u32)orderEndianess<<23;
@@ -269,8 +269,8 @@
void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4])
{
- assert(ctx != NULL);
- assert(ctrIv != NULL);
+ myassert(ctx != NULL);
+ myassert(ctrIv != NULL);
ctx->ctrIvNonceParams = (u32)orderEndianess<<23;
@@ -296,7 +296,7 @@
// TODO: Handle endianess!
void AES_addCounter(u32 ctr[4], u32 val)
{
- assert(ctr != NULL);
+ myassert(ctr != NULL);
u32 carry, i = 1;
u64 sum;
@@ -318,7 +318,7 @@
void AES_subCounter(u32 ctr[4], u32 val)
{
- assert(ctr != NULL);
+ myassert(ctr != NULL);
u32 carry, i = 1;
u32 sum;
@@ -338,7 +338,7 @@
void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder)
{
- assert(ctx != NULL);
+ myassert(ctx != NULL);
ctx->aesParams = (u32)inEndianessOrder<<23 | (u32)outEndianessOrder<<22;
}
@@ -368,8 +368,8 @@
static void aesProcessBlocksDma(const u32 *in, u32 *out, u32 blocks)
{
// DMA can't reach TCMs
- assert(((u32)in >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)in < DTCM_BASE) || ((u32)in >= DTCM_BASE + DTCM_SIZE)));
- assert(((u32)out >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)out < DTCM_BASE) || ((u32)out >= DTCM_BASE + DTCM_SIZE)));
+ myassert(((u32)in >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)in < DTCM_BASE) || ((u32)in >= DTCM_BASE + DTCM_SIZE)));
+ myassert(((u32)out >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)out < DTCM_BASE) || ((u32)out >= DTCM_BASE + DTCM_SIZE)));
// Check block alignment
@@ -413,9 +413,9 @@
void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma)
{
- assert(ctx != NULL);
- assert(in != NULL);
- assert(out != NULL);
+ myassert(ctx != NULL);
+ myassert(in != NULL);
+ myassert(out != NULL);
const u32 ctrParams = ctx->ctrIvNonceParams;
u32 *const ctr = ctx->ctrIvNonce;
@@ -448,9 +448,9 @@
/*void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma)
{
- assert(ctx != NULL);
- assert(in != NULL);
- assert(out != NULL);
+ myassert(ctx != NULL);
+ myassert(in != NULL);
+ myassert(out != NULL);
const u32 ivParams = ctx->ctrIvNonceParams;
u32 *const iv = ctx->ctrIvNonce;
@@ -519,9 +519,9 @@
void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma)
{
- assert(ctx != NULL);
- assert(in != NULL);
- assert(out != NULL);
+ myassert(ctx != NULL);
+ myassert(in != NULL);
+ myassert(out != NULL);
const u32 aesParams = (enc ? AES_MODE_ECB_ENCRYPT : AES_MODE_ECB_DECRYPT) | ctx->aesParams;
@@ -546,12 +546,12 @@
bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize,
u32 mac[4], u16 blocks, bool enc)
{
- assert(ctx != NULL);
- assert(in != NULL);
- assert(out != NULL);
- assert(macSize != 0);
- assert(mac != NULL);
- assert(blocks != 0);
+ myassert(ctx != NULL);
+ myassert(in != NULL);
+ myassert(out != NULL);
+ myassert(macSize != 0);
+ myassert(mac != NULL);
+ myassert(blocks != 0);
REG_AESCNT = ctx->ctrIvNonceParams;
diff --git a/source/arm9/debug.c b/source/arm9/debug.c
index c45b254..70fa443 100644
--- a/source/arm9/debug.c
+++ b/source/arm9/debug.c
@@ -19,6 +19,7 @@
#include
#include
#include "types.h"
+#include "arm9/fmt.h"
#include "mem_map.h"
#include "pxi.h"
#include "arm9/console.h"
@@ -52,7 +53,7 @@
consoleInit(0, NULL, true);
- printf("\x1b[41m\x1b[0J\x1b[9C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
+ ee_printf("\x1b[41m\x1b[0J\x1b[9C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
fsUnmountAll();
devs_close();
@@ -68,8 +69,8 @@
consoleInit(0, NULL, true);
- printf("\x1b[41m\x1b[0J\x1b[9C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
- printf("\nERROR MESSAGE:\n%s\n", msg);
+ ee_printf("\x1b[41m\x1b[0J\x1b[9C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr);
+ ee_printf("\nERROR MESSAGE:\n%s\n", msg);
fsUnmountAll();
devs_close();
@@ -100,8 +101,8 @@
if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort
else realPc = excStack[15] - instSize; // Other
- printf("\x1b[41m\x1b[0J\x1b[9CGuru Meditation Error!\n\n%s:\n", typeStr[type]);
- printf("CPSR: 0x%08" PRIX32 "\n"
+ ee_printf("\x1b[41m\x1b[0J\x1b[9CGuru Meditation Error!\n\n%s:\n", typeStr[type]);
+ ee_printf("CPSR: 0x%08" PRIX32 "\n"
"r0 = 0x%08" PRIX32 " r8 = 0x%08" PRIX32 "\n"
"r1 = 0x%08" PRIX32 " r9 = 0x%08" PRIX32 "\n"
"r2 = 0x%08" PRIX32 " r10 = 0x%08" PRIX32 "\n"
@@ -120,7 +121,7 @@
excStack[6], excStack[14],
excStack[7], realPc);
- puts("Stack dump:");
+ ee_puts("Stack dump:");
u32 sp = excStack[13];
if(sp >= DTCM_BASE && sp < DTCM_BASE + DTCM_SIZE && !(sp & 3u))
@@ -130,13 +131,13 @@
u32 newlineCounter = 0;
for(u32 i = 0; i < stackWords; i++)
{
- if(newlineCounter == 3) {printf("\n"); newlineCounter = 0;}
- printf("0x%08" PRIX32 " ", ((u32*)sp)[i]);
+ if(newlineCounter == 3) {ee_printf("\n"); newlineCounter = 0;}
+ ee_printf("0x%08" PRIX32 " ", ((u32*)sp)[i]);
newlineCounter++;
}
}
- if(codeChanged) printf("Attention: RO section data changed!!");
+ if(codeChanged) ee_printf("Attention: RO section data changed!!");
// avoid fs corruptions
fsUnmountAll();
diff --git a/source/arm9/dev.c b/source/arm9/dev.c
index 91c3710..b329999 100644
--- a/source/arm9/dev.c
+++ b/source/arm9/dev.c
@@ -19,8 +19,8 @@
#include
#include
#include
-#include
#include "types.h"
+#include "arm9/myassert.h"
#include "mem_map.h"
#include "arm9/main.h"
#include "arm9/ncsd.h"
@@ -171,8 +171,8 @@
{
if(!dev_sd.initialized) return false;
- assert(count != 0);
- assert(buf != NULL);
+ myassert(count != 0);
+ myassert(buf != NULL);
return !sdmmc_sdcard_readsectors(sector, count, buf);
}
@@ -181,8 +181,8 @@
{
if(!dev_sd.initialized) return false;
- assert(count != 0);
- assert(buf != NULL);
+ myassert(count != 0);
+ myassert(buf != NULL);
return !sdmmc_sdcard_writesectors(sector, count, buf);
}
@@ -225,8 +225,8 @@
{
if(!dev_rnand.initialized) return false;
- assert(count != 0);
- assert(buf != NULL);
+ myassert(count != 0);
+ myassert(buf != NULL);
return !sdmmc_nand_readsectors(sector, count, buf);
}
@@ -235,8 +235,8 @@
{
if(!dev_rnand.initialized) return false;
- assert(count != 0);
- assert(buf != NULL);
+ myassert(count != 0);
+ myassert(buf != NULL);
return !sdmmc_nand_writesectors(sector, count, buf);
}
@@ -352,8 +352,8 @@
if(!dev_dnand.dev.initialized) return false;
- assert(count != 0);
- assert(buf != NULL);
+ myassert(count != 0);
+ myassert(buf != NULL);
if(!partitionFind(sector, count, &index)) return false;
@@ -390,7 +390,7 @@
if(!dev_dnand.dev.initialized) return false;
- assert(count != 0);
+ myassert(count != 0);
if(!partitionFind(sector, count, &index)) return false;
diff --git a/source/arm9/firm.c b/source/arm9/firm.c
index d6c503f..91e1eb3 100644
--- a/source/arm9/firm.c
+++ b/source/arm9/firm.c
@@ -268,18 +268,18 @@
noreturn void firm_launch(int argc, const char **argv)
{
- //printf("Sending PXI_CMD_FIRM_LAUNCH\n");
+ //ee_printf("Sending PXI_CMD_FIRM_LAUNCH\n");
PXI_sendWord(PXI_CMD_FIRM_LAUNCH);
- //printf("Waiting for ARM11...\n");
+ //ee_printf("Waiting for ARM11...\n");
while(PXI_recvWord() != PXI_RPL_OK);
deinitCpu();
- //printf("Relocating FIRM launch stub...\n");
+ //ee_printf("Relocating FIRM launch stub...\n");
memcpy((void*)A9_STUB_ENTRY, (const void*)firmLaunchStub, A9_STUB_SIZE);
- //printf("Starting firm launch...\n");
+ //ee_printf("Starting firm launch...\n");
((void (*)(int, const char**))A9_STUB_ENTRY)(argc, argv);
while(1);
}
diff --git a/source/arm9/firmwriter.c b/source/arm9/firmwriter.c
index e89127c..dfcf965 100644
--- a/source/arm9/firmwriter.c
+++ b/source/arm9/firmwriter.c
@@ -113,7 +113,7 @@
if(!firmwriterIsDone())
{
- // printf("firmwriter is not done yet.\n");
+ // ee_printf("firmwriter is not done yet.\n");
return false;
}
diff --git a/source/arm9/fmt.c b/source/arm9/fmt.c
new file mode 100644
index 0000000..532b35b
--- /dev/null
+++ b/source/arm9/fmt.c
@@ -0,0 +1,365 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2016-2017 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+/* File : barebones/ee_printf.c
+ This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
+
+This code is based on a file that contains the following:
+ Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+*/
+
+//TuxSH's changes: add support for 64-bit numbers, remove floating-point code
+
+#include
+#include
+#include "types.h"
+#include "arm9/fmt.h"
+#include "arm9/console.h"
+
+#define ZEROPAD (1<<0) //Pad with zero
+#define SIGN (1<<1) //Unsigned/signed long
+#define PLUS (1<<2) //Show plus
+#define SPACE (1<<3) //Spacer
+#define LEFT (1<<4) //Left justified
+#define HEX_PREP (1<<5) //0x
+#define UPPERCASE (1<<6) //'ABCDEF'
+
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+
+u32 strnlen(const char *string, u32 maxlen)
+{
+ u32 size;
+
+ for(size = 0; size < maxlen && *string; string++, size++);
+
+ return size;
+}
+
+static s32 skipAtoi(const char **s)
+{
+ s32 i = 0;
+
+ while(IS_DIGIT(**s)) i = i * 10 + *((*s)++) - '0';
+
+ return i;
+}
+
+static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precision, u32 type)
+{
+ char sign = 0;
+
+ if(type & SIGN)
+ {
+ if(num < 0)
+ {
+ sign = '-';
+ num = -num;
+ size--;
+ }
+ else if(type & PLUS)
+ {
+ sign = '+';
+ size--;
+ }
+ else if(type & SPACE)
+ {
+ sign = ' ';
+ size--;
+ }
+ }
+
+ static const char *lowerDigits = "0123456789abcdef",
+ *upperDigits = "0123456789ABCDEF";
+
+ s32 i = 0;
+ char tmp[20];
+ const char *dig = (type & UPPERCASE) ? upperDigits : lowerDigits;
+
+ if(num == 0)
+ {
+ if(precision != 0) tmp[i++] = '0';
+ type &= ~HEX_PREP;
+ }
+ else
+ {
+ while(num != 0)
+ {
+ u64 base = isHex ? 16ULL : 10ULL;
+ tmp[i++] = dig[(u64)num % base];
+ num = (s64)((u64)num / base);
+ }
+ }
+
+ if(type & LEFT || precision != -1) type &= ~ZEROPAD;
+ if(type & HEX_PREP && isHex) size -= 2;
+ if(i > precision) precision = i;
+ size -= precision;
+ if(!(type & (ZEROPAD | LEFT))) while(size-- > 0) *str++ = ' ';
+ if(sign) *str++ = sign;
+
+ if(type & HEX_PREP && isHex)
+ {
+ *str++ = '0';
+ *str++ = 'x';
+ }
+
+ if(type & ZEROPAD) while(size-- > 0) *str++ = '0';
+ while(i < precision--) *str++ = '0';
+ while(i-- > 0) *str++ = tmp[i];
+ while(size-- > 0) *str++ = ' ';
+
+ return str;
+}
+
+u32 ee_vsprintf(char *buf, const char *fmt, va_list args)
+{
+ char *str;
+
+ for(str = buf; *fmt; fmt++)
+ {
+ if(*fmt != '%')
+ {
+ *str++ = *fmt;
+ continue;
+ }
+
+ //Process flags
+ u32 flags = 0; //Flags to number()
+ bool loop = true;
+
+ while(loop)
+ {
+ switch(*++fmt)
+ {
+ case '-': flags |= LEFT; break;
+ case '+': flags |= PLUS; break;
+ case ' ': flags |= SPACE; break;
+ case '#': flags |= HEX_PREP; break;
+ case '0': flags |= ZEROPAD; break;
+ default: loop = false; break;
+ }
+ }
+
+ //Get field width
+ s32 fieldWidth = -1; //Width of output field
+ if(IS_DIGIT(*fmt)) fieldWidth = skipAtoi(&fmt);
+ else if(*fmt == '*')
+ {
+ fmt++;
+
+ fieldWidth = va_arg(args, s32);
+
+ if(fieldWidth < 0)
+ {
+ fieldWidth = -fieldWidth;
+ flags |= LEFT;
+ }
+ }
+
+ //Get the precision
+ s32 precision = -1; //Min. # of digits for integers; max number of chars for from string
+ if(*fmt == '.')
+ {
+ fmt++;
+
+ if(IS_DIGIT(*fmt)) precision = skipAtoi(&fmt);
+ else if(*fmt == '*')
+ {
+ fmt++;
+ precision = va_arg(args, s32);
+ }
+
+ if(precision < 0) precision = 0;
+ }
+
+ //Get the conversion qualifier
+ u32 integerType = 0;
+ if(*fmt == 'l')
+ {
+ if(*++fmt == 'l')
+ {
+ fmt++;
+ integerType = 1;
+ }
+
+ }
+ else if(*fmt == 'h')
+ {
+ if(*++fmt == 'h')
+ {
+ fmt++;
+ integerType = 3;
+ }
+ else integerType = 2;
+ }
+
+ bool isHex;
+
+ switch(*fmt)
+ {
+ case 'c':
+ if(!(flags & LEFT)) while(--fieldWidth > 0) *str++ = ' ';
+ *str++ = (u8)va_arg(args, s32);
+ while(--fieldWidth > 0) *str++ = ' ';
+ continue;
+
+ case 's':
+ {
+ char *s = va_arg(args, char *);
+ if(!s) s = "";
+ u32 len = (precision != -1) ? strnlen(s, precision) : strlen(s);
+ if(!(flags & LEFT)) while((s32)len < fieldWidth--) *str++ = ' ';
+ for(u32 i = 0; i < len; i++) *str++ = *s++;
+ while((s32)len < fieldWidth--) *str++ = ' ';
+ continue;
+ }
+
+ case 'p':
+ if(fieldWidth == -1)
+ {
+ fieldWidth = 8;
+ flags |= ZEROPAD;
+ }
+ str = processNumber(str, va_arg(args, u32), true, fieldWidth, precision, flags);
+ continue;
+
+ //Integer number formats - set up the flags and "break"
+ case 'X':
+ flags |= UPPERCASE;
+ //Falls through
+ case 'x':
+ isHex = true;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ //Falls through
+ case 'u':
+ isHex = false;
+ break;
+
+ default:
+ if(*fmt != '%') *str++ = '%';
+ if(*fmt) *str++ = *fmt;
+ else fmt--;
+ continue;
+ }
+
+ s64 num;
+
+ if(flags & SIGN)
+ {
+ if(integerType == 1) num = va_arg(args, s64);
+ else num = va_arg(args, s32);
+
+ if(integerType == 2) num = (s16)num;
+ else if(integerType == 3) num = (s8)num;
+ }
+ else
+ {
+ if(integerType == 1) num = va_arg(args, u64);
+ else num = va_arg(args, u32);
+
+ if(integerType == 2) num = (u16)num;
+ else if(integerType == 3) num = (u8)num;
+ }
+
+ str = processNumber(str, num, isHex, fieldWidth, precision, flags);
+ }
+
+ *str = 0;
+ return str - buf;
+}
+
+u32 ee_sprintf(char *const buf, const char *const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ u32 res = ee_vsprintf(buf, fmt, args);
+ va_end(args);
+
+ return res;
+}
+
+u32 ee_snprintf(char *const buf, UNUSED u32 size, const char *const fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ u32 res = ee_vsprintf(buf, fmt, args);
+ va_end(args);
+
+ return res;
+}
+
+u32 ee_vsnprintf(char *const buf, UNUSED u32 size, const char *const fmt, va_list arg)
+{
+ return ee_vsprintf(buf, fmt, arg);
+}
+
+u32 ee_printf(const char *const fmt, ...)
+{
+ char buf[256];
+ va_list args;
+ va_start(args, fmt);
+ u32 res = ee_vsprintf(buf, fmt, args);
+ va_end(args);
+
+ con_write(NULL, NULL, buf, res);
+
+ return res;
+}
+
+u32 ee_puts(const char *const str)
+{
+ return con_write(NULL, NULL, str, strnlen(str, 256));
+}
diff --git a/source/arm9/main.c b/source/arm9/main.c
index dba6daf..194a37c 100644
--- a/source/arm9/main.c
+++ b/source/arm9/main.c
@@ -19,8 +19,9 @@
#include
#include
#include
-#include "mem_map.h"
#include "types.h"
+#include "arm9/fmt.h"
+#include "mem_map.h"
#include "util.h"
#include "pxi.h"
#include "arm9/hid.h"
@@ -214,7 +215,7 @@
{
bootInfo.unitIsNew3DS = REG_PDN_MPCORE_CFG & 2;
- sprintf(bootInfo.model, "%s 3DS", bootInfo.unitIsNew3DS ? "New" : "Original");
+ ee_sprintf(bootInfo.model, "%s 3DS", bootInfo.unitIsNew3DS ? "New" : "Original");
uiPrintIfVerbose("%s detected!\n", bootInfo.model);
}
@@ -230,7 +231,7 @@
u32 boot_env = CFG_BOOTENV;
if(boot_env > 3) boot_env = 2;
- sprintf(bootInfo.mode, "%s", CFG_UNITINFO != 0 ? "Dev" : "Retail");
+ ee_sprintf(bootInfo.mode, "%s", CFG_UNITINFO != 0 ? "Dev" : "Retail");
strcpy(bootInfo.bootEnv, boot_environment[boot_env]);
}
diff --git a/source/arm9/menu_filebrowse.c b/source/arm9/menu_filebrowse.c
index dc4fdc1..930bd0e 100644
--- a/source/arm9/menu_filebrowse.c
+++ b/source/arm9/menu_filebrowse.c
@@ -20,6 +20,7 @@
#include
#include
#include "types.h"
+#include "arm9/fmt.h"
#include "mem_map.h"
#include "fatfs/ff.h"
#include "arm9/console.h"
@@ -73,7 +74,7 @@
dirEntries[curEntriesCount + i].isDir = (fno.fattrib & AM_DIR) != 0;
if(fno.fattrib & AM_DIR) // directory
- snprintf(dirEntries[curEntriesCount + i].name, FF_MAX_LFN + 1, "/%s", fno.fname);
+ ee_snprintf(dirEntries[curEntriesCount + i].name, FF_MAX_LFN + 1, "/%s", fno.fname);
else // file
strncpy_s(dirEntries[curEntriesCount + i].name, fno.fname, FF_MAX_LFN + 1, FF_MAX_LFN + 2);
}
diff --git a/source/arm9/menu_firmloader.c b/source/arm9/menu_firmloader.c
index c2cdf22..e4e19f7 100644
--- a/source/arm9/menu_firmloader.c
+++ b/source/arm9/menu_firmloader.c
@@ -314,8 +314,8 @@
size_t index;
size_t sector;
size_t firmSize;
-
- sscanf(filePath, "%10s:", partName);
+
+ strncpy_s(partName, filePath, 11, 11);
if(!partitionGetIndex(partName, &index))
return 0;
@@ -347,7 +347,7 @@
if(!statFirmware(filepath))
return false;
- // printf("Loading firmware:\n%s\n\n", filepath);
+ // ee_printf("Loading firmware:\n%s\n\n", filepath);
/* SD card */
if(strncmp(filepath, "sdmc:", 5) == 0)
diff --git a/source/arm9/menu_nand.c b/source/arm9/menu_nand.c
index 3aee283..83ad071 100644
--- a/source/arm9/menu_nand.c
+++ b/source/arm9/menu_nand.c
@@ -137,6 +137,7 @@
case MENU_EVENT_POWER_PRESSED:
f_sync(&file);
f_close(&file);
+ // falls through
case MENU_EVENT_SD_CARD_REMOVED:
menuActState();
goto fail;
@@ -271,6 +272,7 @@
case MENU_EVENT_HOME_PRESSED:
case MENU_EVENT_POWER_PRESSED:
f_close(&file);
+ // falls through
case MENU_EVENT_SD_CARD_REMOVED:
menuActState();
goto fail;
diff --git a/source/arm9/menu_update.c b/source/arm9/menu_update.c
index d086611..8f83fe2 100644
--- a/source/arm9/menu_update.c
+++ b/source/arm9/menu_update.c
@@ -109,7 +109,7 @@
}
partitionGetSectorOffset(index, §or);
- // printf("writing to offset 0x%x aka 0x%x\n", sector, sector<<9);
+ // ee_printf("writing to offset 0x%x aka 0x%x\n", sector, sector<<9);
uiPrintTextAt(0, 9, "Updating...\n");
diff --git a/source/arm9/myassert.c b/source/arm9/myassert.c
new file mode 100644
index 0000000..1ca3cf1
--- /dev/null
+++ b/source/arm9/myassert.c
@@ -0,0 +1,12 @@
+#include "types.h"
+#include "arm9/fmt.h"
+#include "arm9/interrupt.h"
+
+
+
+noreturn void __myassert(const char *const str, u32 line)
+{
+ ee_printf("Assertion failed: %s:%" PRIu32, str, line);
+
+ while(1) waitForInterrupt();
+}
diff --git a/source/arm9/ndma.c b/source/arm9/ndma.c
index e540c97..191170f 100644
--- a/source/arm9/ndma.c
+++ b/source/arm9/ndma.c
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-#include
#include "types.h"
+#include "arm9/myassert.h"
#include "arm9/ndma.h"
#include "arm9/interrupt.h"
@@ -37,8 +37,8 @@
void NDMA_copyAsync(u32 *dest, const u32 *source, u32 size)
{
- assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE)));
- assert(((u32)source >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)source < DTCM_BASE) || ((u32)source >= DTCM_BASE + DTCM_SIZE)));
+ myassert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE)));
+ myassert(((u32)source >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)source < DTCM_BASE) || ((u32)source >= DTCM_BASE + DTCM_SIZE)));
REG_NDMA7_SRC_ADDR = (u32)source;
REG_NDMA7_DST_ADDR = (u32)dest;
@@ -59,7 +59,7 @@
void NDMA_fillAsync(u32 *dest, u32 value, u32 size)
{
- assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE)));
+ myassert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE)));
REG_NDMA7_DST_ADDR = (u32)dest;
REG_NDMA7_LOG_BLK_CNT = size / 4;
diff --git a/source/arm9/partitions.c b/source/arm9/partitions.c
index 110ce69..bc27f93 100644
--- a/source/arm9/partitions.c
+++ b/source/arm9/partitions.c
@@ -36,7 +36,7 @@
for(size_t i=0; i
-#include
#include
+#include
#include
#include "types.h"
+#include "arm9/fmt.h"
#include "util.h"
#include "arm9/hid.h"
#include "pxi.h"
@@ -119,10 +120,10 @@
va_list args;
va_start(args, format);
- vsnprintf(tmp, 256, format, args);
+ ee_vsnprintf(tmp, 256, format, args);
va_end(args);
- snprintf(lastline, 256, "(A): %s (B): %s", textYes, textNo);
+ ee_snprintf(lastline, 256, "(A): %s (B): %s", textYes, textNo);
/* Print dialog */
keys = uiDialog(tmp, lastline, KEY_A | KEY_B, screen, 0, 0, true);
@@ -143,10 +144,10 @@
va_list args;
va_start(args, format);
- vsnprintf(tmp, 256, format, args);
+ ee_vsnprintf(tmp, 256, format, args);
va_end(args);
- printf(tmp);
+ ee_printf(tmp);
}
}
@@ -158,18 +159,18 @@
va_list args;
va_start(args, centered);
- vsnprintf(tmp, 556, format, args);
+ ee_vsnprintf(tmp, 556, format, args);
va_end(args);
if(centered)
{
// Warning. The string must be <= the console width here!
size_t len = strlen(tmp);
- printf("\x1B[%um%*s%s\x1B[0m", color, (width - len) / 2, "", tmp);
+ ee_printf("\x1B[%um%*s%s\x1B[0m", color, (width - len) / 2, "", tmp);
}
else
{
- printf("\x1B[%um%s\x1B[0m", color, tmp);
+ ee_printf("\x1B[%um%s\x1B[0m", color, tmp);
}
}
@@ -180,12 +181,12 @@
va_list args;
va_start(args, format);
- vsnprintf(tmp, width + 1, format, args);
+ ee_vsnprintf(tmp, width + 1, format, args);
va_end(args);
size_t len = strlen(tmp);
- printf("\x1b[%u;%uH", y, 0);
- printf("%*s%s\n", (width - len) / 2, "", tmp);
+ ee_printf("\x1b[%u;%uH", y, 0);
+ ee_printf("%*s%s\n", (width - len) / 2, "", tmp);
}
/* Prints a given text at a certain position in the current window */
@@ -195,10 +196,10 @@
va_list args;
va_start(args, format);
- vsnprintf(tmp, 256, format, args);
+ ee_vsnprintf(tmp, 256, format, args);
va_end(args);
- printf("\x1b[%u;%uH%s", y, x, tmp);
+ ee_printf("\x1b[%u;%uH%s", y, x, tmp);
}
/* Prints a given text surrounded by a graphical window */
@@ -212,7 +213,7 @@
va_list args;
va_start(args, centered);
- vsnprintf(tmp, 256, format, args);
+ ee_vsnprintf(tmp, 256, format, args);
va_end(args);
char *ptr = tmp;
@@ -259,20 +260,20 @@
// TODO: Optimize to only backup what will be overwritten. I'm lazy.
memcpy(fbBackup, fb, screen ? SCREEN_SIZE_TOP : SCREEN_SIZE_SUB);
- printf("\x1B[37m\x1B[40m\x1B[2J\n");
+ ee_printf("\x1B[37m\x1B[40m\x1B[2J\n");
const char *linePtr = tmp;
while(1)
{
unsigned int length = 0;
while(linePtr[length] != '\n' && linePtr[length] != '\0') length++;
- printf(" %.*s\n", length, linePtr);
+ ee_printf(" %.*s\n", length, linePtr);
if(*(linePtr + length) == '\0') break;
linePtr += length + 1;
}
if(lastLine)
- printf("\x1b[%u;%uH%s", lines - 2, (longestLine - strlen(lastLine)) / 2, lastLine);
+ ee_printf("\x1b[%u;%uH%s", lines - 2, (longestLine - strlen(lastLine)) / 2, lastLine);
const u16 color = consoleGetRGB565Color(randomColor);
for(u32 xx = x * 8 + 1; xx < x * 8 + (longestLine * 8) - 1; xx++)
@@ -368,7 +369,7 @@
while(*ptr != 0x0A) ptr++;
ptr++;
- sscanf(ptr, "%i %i", width, height);
+ mysscanf(ptr, "%u %u", width, height);
}
static void uiDrawPPM(unsigned start_x, unsigned start_y, const u8 *data)
diff --git a/source/util.c b/source/util.c
index ba1f5d3..4faa4b7 100644
--- a/source/util.c
+++ b/source/util.c
@@ -16,8 +16,12 @@
* along with this program. If not, see .
*/
-#include "util.h"
+#include
+#include
+#include
#include
+#include "types.h"
+#include "util.h"
void wait(u32 cycles)
{
@@ -29,6 +33,66 @@
}
}
+int mysscanf(const char *s, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+
+ int ret = 0;
+ const char *const oldS = s;
+ while(*fmt && *s)
+ {
+ if(*fmt == '%')
+ {
+ bool longInt = false;
+ bool number = false;
+ if(*++fmt == 'l')
+ {
+ longInt = true;
+ fmt++;
+ }
+
+ switch(*fmt)
+ {
+ case 'd':
+ if(!longInt) *va_arg(args, int*) = atoi(s);
+ else *va_arg(args, long int*) = atol(s);
+ number = true;
+ ret++;
+ break;
+ case 'u':
+ if(!longInt) *va_arg(args, unsigned int*) = (unsigned int)strtoul(s, NULL, 0);
+ else *va_arg(args, unsigned long int*) = strtoul(s, NULL, 0);
+ number = true;
+ ret++;
+ break;
+ case 'c':
+ *va_arg(args, char*) = *s++;
+ ret++;
+ break;
+ case 'n':
+ if(!longInt) *va_arg(args, int*) = (int)(s - oldS);
+ else *va_arg(args, long int*) = (long int)(s - oldS);
+ break;
+ default: ;
+ }
+ if(number) while(*s >= '0' && *s <= '9') s++;
+ fmt++;
+ }
+ else
+ {
+ if(*fmt != *s) break;
+ fmt++;
+ s++;
+ }
+ }
+
+ va_end(args);
+
+ return ret;
+}
+
// case insensitive string compare function
int strnicmp(const char *str1, const char *str2, u32 len)
{
diff --git a/thirdparty/fatfs/diskio.c b/thirdparty/fatfs/diskio.c
index ef6cae2..2bc22ba 100644
--- a/thirdparty/fatfs/diskio.c
+++ b/thirdparty/fatfs/diskio.c
@@ -186,6 +186,7 @@
break;
}
res = RES_NOTRDY;
+ break;
case GET_SECTOR_SIZE:
*(WORD*)buff = 512;
break;