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;