#include "gm9lua.h" #include "ui.h" #include "language.h" #ifndef NO_LUA #include "fs.h" #include "ff.h" #include "vff.h" #include "fsutil.h" #include "unittype.h" #include "nand.h" #include "gm9loader.h" #include "gm9os.h" #include "gm9ui.h" #include "gm9title.h" #include "gm9internalfs.h" #include "gm9internalsys.h" #define DEBUGSP(x) ShowPrompt(false, (x)) typedef struct GM9LuaLoadF { int n; // pre-read characters FIL f; FRESULT res; char buff[BUFSIZ]; } GM9LuaLoadF; // similar to "getF" in lauxlib.c static const char* GetF(lua_State* L, void* ud, size_t* size) { GM9LuaLoadF* lf = (GM9LuaLoadF*)ud; UINT br = 0; (void)L; // unused if (lf->n > 0) { // check for pre-read characters *size = lf->n; // return those lf->n = 0; } else { if (fvx_eof(&lf->f)) return NULL; lf->res = fvx_read(&lf->f, lf->buff, BUFSIZ, &br); *size = (size_t)br; if (lf->res != FR_OK) return NULL; } return lf->buff; } // similar to "errfile" in lauxlib.c static int ErrFile(lua_State* L, const char* what, int fnameindex, FRESULT res) { const char* filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s:\nfatfs error %d", what, filename, res); lua_remove(L, fnameindex); return LUA_ERRFILE; } int LoadLuaFile(lua_State* L, const char* filename) { GM9LuaLoadF lf; lf.n = 0; int status; int fnameindex = lua_gettop(L) + 1; // index of filename on the stack lua_pushfstring(L, "@%s", filename); lf.res = fvx_open(&lf.f, filename, FA_READ | FA_OPEN_EXISTING); if (lf.res != FR_OK) return ErrFile(L, "open", fnameindex, lf.res); status = lua_load(L, GetF, &lf, lua_tostring(L, -1), NULL); fvx_close(&lf.f); if (lf.res != FR_OK) { lua_settop(L, fnameindex); return ErrFile(L, "read", fnameindex, lf.res); } lua_remove(L, fnameindex); return status; } u32 GetFlagsFromTable(lua_State* L, int pos, u32 flags_ext_starter, u32 allowed_flags) { char types[FLAGS_COUNT][14] = { FLAGS_STR }; int types_int[FLAGS_COUNT] = { FLAGS_CONSTS }; u32 flags_ext = flags_ext_starter; for (int i = 0; i < FLAGS_COUNT; i++) { if (!(allowed_flags & types_int[i])) continue; lua_getfield(L, pos, types[i]); if (lua_toboolean(L, -1)) flags_ext |= types_int[i]; lua_pop(L, 1); } return flags_ext; } void CheckWritePermissionsLuaError(lua_State* L, const char* path) { if (!CheckWritePermissions(path)) { luaL_error(L, "writing not allowed: %s", path); } } static const luaL_Reg gm9lualibs[] = { // built-ins {LUA_GNAME, luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, // gm9 custom {GM9LUA_OSLIBNAME, gm9lua_open_os}, {GM9LUA_UILIBNAME, gm9lua_open_ui}, {GM9LUA_TITLELIBNAME, gm9lua_open_title}, // gm9 custom internals (usually wrapped by a pure lua module) {GM9LUA_INTERNALFSLIBNAME, gm9lua_open_internalfs}, {GM9LUA_INTERNALSYSLIBNAME, gm9lua_open_internalsys}, {NULL, NULL} }; static void loadlibs(lua_State* L) { const luaL_Reg* lib; for (lib = gm9lualibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); // remove lib from stack } } static bool RunFile(lua_State* L, const char* file) { int result = LoadLuaFile(L, file); if (result != LUA_OK) { char errstr[BUFSIZ] = {0}; strlcpy(errstr, lua_tostring(L, -1), BUFSIZ); WordWrapString(errstr, 0); ShowPrompt(false, "Error during loading:\n%s", errstr); return false; } if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) { char errstr[BUFSIZ] = {0}; strlcpy(errstr, lua_tostring(L, -1), BUFSIZ); WordWrapString(errstr, 0); ShowPrompt(false, "Error during execution:\n%s", errstr); return false; } return true; } // this is also taken from scripting.c static inline bool isntrboot(void) { // taken over from Luma 3DS: // https://github.com/AuroraWright/Luma3DS/blob/bb5518b0f68d89bcd8efaf326355a770d5e57856/source/main.c#L58-L62 const vu8 *bootMediaStatus = (const vu8 *) 0x1FFFE00C; const vu32 *bootPartitionsStatus = (const vu32 *) 0x1FFFE010; // shell closed, no error booting NTRCARD, NAND partitions not even considered return (bootMediaStatus[3] == 2) && !bootMediaStatus[1] && !bootPartitionsStatus[0] && !bootPartitionsStatus[1]; } bool ExecuteLuaScript(const char* path_script) { lua_State* L = luaL_newstate(); loadlibs(L); ResetPackageSearchersAndPath(L); ClearOutputBuffer(); // current path char curr_dir[_VAR_CNT_LEN]; if (path_script) { strncpy(curr_dir, path_script, _VAR_CNT_LEN); curr_dir[_VAR_CNT_LEN-1] = '\0'; char* slash = strrchr(curr_dir, '/'); if (slash) *slash = '\0'; lua_pushstring(L, curr_dir); } else { lua_pushnil(L); } lua_setglobal(L, "CURRDIR"); lua_pushliteral(L, VERSION); lua_setglobal(L, "GM9VER"); lua_pushstring(L, path_script); lua_setglobal(L, "SCRIPT"); lua_pushliteral(L, OUTPUT_PATH); lua_setglobal(L, "GM9OUT"); lua_pushstring(L, IS_UNLOCKED ? (isntrboot() ? "ntrboot" : "sighax") : ""); lua_setglobal(L, "HAX"); lua_pushinteger(L, GetNandSizeSectors(NAND_SYSNAND) * 0x200); lua_setglobal(L, "NANDSIZE"); lua_pushboolean(L, IS_DEVKIT); lua_setglobal(L, "IS_DEVKIT"); lua_pushstring(L, IS_O3DS ? "O3DS" : "N3DS"); lua_setglobal(L, "CONSOLE_TYPE"); bool result = RunFile(L, "V:/preload.lua"); if (!result) { ShowPrompt(false, "A fatal error happened in GodMode9's preload script.\n \nThis is not an error with your code, but with\nGodMode9. Please report it on GitHub."); lua_close(L); return false; } RunFile(L, path_script); lua_close(L); return true; } #else // No-Lua version bool ExecuteLuaScript(const char* path_script) { (void)path_script; // unused ShowPrompt(false, "%s", STR_LUA_NOT_INCLUDED); return false; } #endif