/** Execute file on a specific Lua state. * @param L Lua state to execute the file in. * @param filename filet to load and excute. */ void LuaContext::do_file(lua_State *L, const char *filename) { // Load initialization code int err = 0; std::string errmsg; if ( (err = luaL_loadfile(L, filename)) != 0) { errmsg = lua_tostring(L, -1); lua_pop(L, 1); switch (err) { case LUA_ERRSYNTAX: throw SyntaxErrorException("Lua syntax error in file %s: %s", filename, errmsg.c_str()); case LUA_ERRMEM: throw OutOfMemoryException("Could not load Lua file %s", filename); case LUA_ERRFILE: throw CouldNotOpenFileException(filename, errmsg.c_str()); } } int errfunc = __enable_tracebacks ? 1 : 0; if ( (err = lua_pcall(L, 0, LUA_MULTRET, errfunc)) != 0 ) { // There was an error while executing the initialization file errmsg = lua_tostring(L, -1); lua_pop(L, 1); switch (err) { case LUA_ERRRUN: throw LuaRuntimeException("do_file", errmsg.c_str()); case LUA_ERRMEM: throw OutOfMemoryException("Could not execute Lua file %s", filename); case LUA_ERRERR: throw LuaErrorException("do_file", errmsg.c_str()); default: throw LuaErrorException("do_file/unknown error", errmsg.c_str()); } } }
/** Protected call. * Calls the function on top of the stack. Errors are handled gracefully. * @param nargs number of arguments * @param nresults number of results * @param errfunc stack index of an error handling function * @exception Exception thrown for generic runtime error or if the * error function could not be executed. * @exception OutOfMemoryException thrown if not enough memory was available */ void LuaContext::pcall(int nargs, int nresults, int errfunc) { int err = 0; if ( ! errfunc && __enable_tracebacks ) errfunc = 1; if ( (err = lua_pcall(__L, nargs, nresults, errfunc)) != 0 ) { std::string errmsg = lua_tostring(__L, -1); lua_pop(__L, 1); switch (err) { case LUA_ERRRUN: throw LuaRuntimeException("pcall", errmsg.c_str()); case LUA_ERRMEM: throw OutOfMemoryException("Could not execute Lua chunk via pcall"); case LUA_ERRERR: throw LuaErrorException("pcall", errmsg.c_str()); } } }
void LuaError(lua_State * L, const char * format, ...) { SCP_stringstream msgStream; //WMC - if format is set to NULL, assume this is acting as an //error handler for Lua. if (format == NULL) { msgStream << "LUA ERROR: " << lua_tostring(L, -1); lua_pop(L, -1); } else { SCP_string formatText; va_list args; va_start(args, format); vsprintf(formatText, format, args); va_end(args); msgStream << formatText; } msgStream << "\n"; msgStream << "\n"; msgStream << Separator; msgStream << "ADE Debug:"; msgStream << "\n"; msgStream << Separator; LuaDebugPrint(msgStream, Ade_debug_info); msgStream << Separator; msgStream << "\n"; msgStream << "\n"; msgStream << Separator; // Get the stack via the debug.traceback() function lua_getglobal(L, LUA_DBLIBNAME); if (!lua_isnil(L, -1)) { msgStream << "\n"; lua_getfield(L, -1, "traceback"); lua_remove(L, -2); if (lua_pcall(L, 0, 1, 0) != 0) msgStream << "Error while retrieving stack: " << lua_tostring(L, -1); else msgStream << lua_tostring(L, -1); lua_pop(L, 1); } msgStream << "\n"; msgStream << Separator; char stackText[1024]; stackText[0] = '\0'; scripting::ade_stackdump(L, stackText); msgStream << stackText; msgStream << "\n"; msgStream << Separator; mprintf(("Lua Error: %s\n", msgStream.str().c_str())); if (Cmdline_noninteractive) { exit(1); return; } if (running_unittests) { throw LuaErrorException(msgStream.str()); } set_clipboard_text(msgStream.str().c_str()); // truncate text auto truncatedText = truncateLines(msgStream, Messagebox_lines); SCP_stringstream boxTextStream; boxTextStream << truncatedText << "\n"; boxTextStream << "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; auto boxText = boxTextStream.str(); const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 2, "Exit" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "Continue" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 3; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_ERROR; boxData.message = boxText.c_str(); boxData.title = "Error!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed buttonId = 1; // No action } switch (buttonId) { case 2: exit(1); case 0: Int3(); break; default: break; } gr_activate(1); }