|
|
|
@ -76,6 +76,27 @@ static void set_dfhack_output(lua_State *L, color_ostream *p)
|
|
|
|
|
lua_rawsetp(L, LUA_REGISTRYINDEX, &DFHACK_OSTREAM_TOKEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Console *get_console(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
color_ostream *pstream = Lua::GetOutput(state);
|
|
|
|
|
|
|
|
|
|
if (!pstream)
|
|
|
|
|
{
|
|
|
|
|
lua_pushnil(state);
|
|
|
|
|
lua_pushstring(state, "no output stream");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pstream->is_console())
|
|
|
|
|
{
|
|
|
|
|
lua_pushnil(state);
|
|
|
|
|
lua_pushstring(state, "not an interactive console");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return static_cast<Console*>(pstream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string lua_print_fmt(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
/* Copied from lua source to fully replicate builtin print */
|
|
|
|
@ -120,37 +141,233 @@ static int lua_dfhack_println(lua_State *S)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_printerr(lua_State *S)
|
|
|
|
|
static void dfhack_printerr(lua_State *S, const std::string &str)
|
|
|
|
|
{
|
|
|
|
|
std::string str = lua_print_fmt(S);
|
|
|
|
|
if (color_ostream *out = Lua::GetOutput(S))
|
|
|
|
|
out->printerr("%s\n", str.c_str());
|
|
|
|
|
else
|
|
|
|
|
Core::printerr("%s\n", str.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_printerr(lua_State *S)
|
|
|
|
|
{
|
|
|
|
|
std::string str = lua_print_fmt(S);
|
|
|
|
|
dfhack_printerr(S, str);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int traceback (lua_State *L) {
|
|
|
|
|
const char *msg = lua_tostring(L, 1);
|
|
|
|
|
if (msg)
|
|
|
|
|
luaL_traceback(L, L, msg, 1);
|
|
|
|
|
else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */
|
|
|
|
|
if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */
|
|
|
|
|
lua_pushliteral(L, "(no error message)");
|
|
|
|
|
}
|
|
|
|
|
static int lua_dfhack_color(lua_State *S)
|
|
|
|
|
{
|
|
|
|
|
int cv = luaL_optint(S, 1, -1);
|
|
|
|
|
|
|
|
|
|
if (cv < -1 || cv > color_ostream::COLOR_MAX)
|
|
|
|
|
luaL_argerror(S, 1, "invalid color value");
|
|
|
|
|
|
|
|
|
|
color_ostream *out = Lua::GetOutput(S);
|
|
|
|
|
if (out)
|
|
|
|
|
out->color(color_ostream::color_value(cv));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_is_interactive(lua_State *S)
|
|
|
|
|
{
|
|
|
|
|
lua_pushboolean(S, get_console(S) != NULL);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void report_error(color_ostream &out, lua_State *L)
|
|
|
|
|
static int lua_dfhack_lineedit(lua_State *S)
|
|
|
|
|
{
|
|
|
|
|
const char *prompt = luaL_optstring(S, 1, ">> ");
|
|
|
|
|
const char *hfile = luaL_optstring(S, 2, NULL);
|
|
|
|
|
|
|
|
|
|
Console *pstream = get_console(S);
|
|
|
|
|
if (!pstream)
|
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
|
|
DFHack::CommandHistory hist;
|
|
|
|
|
if (hfile)
|
|
|
|
|
hist.load(hfile);
|
|
|
|
|
|
|
|
|
|
std::string ret;
|
|
|
|
|
int rv = pstream->lineedit(prompt, ret, hist);
|
|
|
|
|
|
|
|
|
|
if (rv < 0)
|
|
|
|
|
{
|
|
|
|
|
lua_pushnil(S);
|
|
|
|
|
lua_pushstring(S, "input error");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (hfile)
|
|
|
|
|
hist.save(hfile);
|
|
|
|
|
lua_pushlstring(S, ret.data(), ret.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int DFHACK_EXCEPTION_META_TOKEN = 0;
|
|
|
|
|
|
|
|
|
|
static void error_tostring(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
lua_getglobal(L, "tostring");
|
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
|
bool ok = lua_pcall(L, 1, 1, 0) == LUA_OK;
|
|
|
|
|
|
|
|
|
|
const char *msg = lua_tostring(L, -1);
|
|
|
|
|
if (!msg)
|
|
|
|
|
{
|
|
|
|
|
msg = "tostring didn't return a string";
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
|
{
|
|
|
|
|
lua_pushfstring(L, "(invalid error: %s)", msg);
|
|
|
|
|
lua_remove(L, -2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void report_error(lua_State *L, color_ostream *out = NULL)
|
|
|
|
|
{
|
|
|
|
|
lua_dup(L);
|
|
|
|
|
error_tostring(L);
|
|
|
|
|
|
|
|
|
|
const char *msg = lua_tostring(L, -1);
|
|
|
|
|
if (msg)
|
|
|
|
|
out.printerr("%s\n", msg);
|
|
|
|
|
assert(msg);
|
|
|
|
|
|
|
|
|
|
if (out)
|
|
|
|
|
out->printerr("%s\n", msg);
|
|
|
|
|
else
|
|
|
|
|
out.printerr("In Lua::SafeCall: error message is not a string.\n", msg);
|
|
|
|
|
dfhack_printerr(L, msg);
|
|
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool convert_to_exception(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(L);
|
|
|
|
|
|
|
|
|
|
bool force_unknown = false;
|
|
|
|
|
|
|
|
|
|
if (lua_istable(L, base) && lua_getmetatable(L, base))
|
|
|
|
|
{
|
|
|
|
|
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_EXCEPTION_META_TOKEN);
|
|
|
|
|
bool is_exception = lua_rawequal(L, -1, -2);
|
|
|
|
|
lua_settop(L, base);
|
|
|
|
|
|
|
|
|
|
// If it is an exception, return as is
|
|
|
|
|
if (is_exception)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
force_unknown = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!lua_istable(L, base) || force_unknown)
|
|
|
|
|
{
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
lua_swap(L);
|
|
|
|
|
|
|
|
|
|
if (lua_isstring(L, -1))
|
|
|
|
|
lua_setfield(L, base, "message");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
error_tostring(L);
|
|
|
|
|
lua_setfield(L, base, "message");
|
|
|
|
|
lua_setfield(L, base, "object");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lua_getfield(L, base, "message");
|
|
|
|
|
|
|
|
|
|
if (!lua_isstring(L, -1))
|
|
|
|
|
{
|
|
|
|
|
error_tostring(L);
|
|
|
|
|
lua_setfield(L, base, "message");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_settop(L, base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_EXCEPTION_META_TOKEN);
|
|
|
|
|
lua_setmetatable(L, base);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_onerror(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
luaL_checkany(L, 1);
|
|
|
|
|
lua_settop(L, 1);
|
|
|
|
|
|
|
|
|
|
bool changed = convert_to_exception(L);
|
|
|
|
|
if (!changed)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
luaL_traceback(L, L, NULL, 1);
|
|
|
|
|
lua_setfield(L, 1, "stacktrace");
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dfhack_exception_tostring(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
|
|
|
|
|
|
|
|
int base = lua_gettop(L);
|
|
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "message");
|
|
|
|
|
if (!lua_isstring(L, -1))
|
|
|
|
|
{
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
lua_pushstring(L, "(error message is not a string)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_pushstring(L, "\n");
|
|
|
|
|
lua_getfield(L, 1, "stacktrace");
|
|
|
|
|
if (!lua_isstring(L, -1))
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
|
|
lua_concat(L, lua_gettop(L) - base);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int finish_dfhack_safecall (lua_State *L, bool success)
|
|
|
|
|
{
|
|
|
|
|
if (!lua_checkstack(L, 2))
|
|
|
|
|
{
|
|
|
|
|
lua_settop(L, 0); /* create space for return values */
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
lua_pushstring(L, "stack overflow in dfhack.safecall()");
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
|
lua_replace(L, 1); /* put first result in first slot */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
report_error(L);
|
|
|
|
|
|
|
|
|
|
return lua_gettop(L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int safecall_cont (lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
int status = lua_getctx(L, NULL);
|
|
|
|
|
return finish_dfhack_safecall(L, (status == LUA_YIELD));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_safecall (lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
luaL_checkany(L, 1);
|
|
|
|
|
lua_pushcfunction(L, dfhack_onerror);
|
|
|
|
|
lua_insert(L, 1);
|
|
|
|
|
int status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 1, 0, safecall_cont);
|
|
|
|
|
return finish_dfhack_safecall(L, (status == LUA_OK));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DFHack::Lua::SafeCall(color_ostream &out, lua_State *L, int nargs, int nres, bool perr)
|
|
|
|
|
{
|
|
|
|
|
int base = lua_gettop(L) - nargs;
|
|
|
|
@ -158,17 +375,20 @@ bool DFHack::Lua::SafeCall(color_ostream &out, lua_State *L, int nargs, int nres
|
|
|
|
|
color_ostream *cur_out = Lua::GetOutput(L);
|
|
|
|
|
set_dfhack_output(L, &out);
|
|
|
|
|
|
|
|
|
|
lua_pushcfunction(L, traceback);
|
|
|
|
|
lua_pushcfunction(L, dfhack_onerror);
|
|
|
|
|
lua_insert(L, base);
|
|
|
|
|
|
|
|
|
|
bool ok = lua_pcall(L, nargs, nres, base) == LUA_OK;
|
|
|
|
|
|
|
|
|
|
if (!ok && perr)
|
|
|
|
|
{
|
|
|
|
|
report_error(L, &out);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_remove(L, base);
|
|
|
|
|
set_dfhack_output(L, cur_out);
|
|
|
|
|
|
|
|
|
|
if (!ok && perr)
|
|
|
|
|
report_error(out, L);
|
|
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -189,24 +409,51 @@ bool DFHack::Lua::Require(color_ostream &out, lua_State *state,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool load_with_env(color_ostream &out, lua_State *state, const std::string &code, int eidx)
|
|
|
|
|
bool DFHack::Lua::AssignDFObject(color_ostream &out, lua_State *state,
|
|
|
|
|
type_identity *type, void *target, int val_index, bool perr)
|
|
|
|
|
{
|
|
|
|
|
if (luaL_loadbuffer(state, code.data(), code.size(), "=(interactive)") != LUA_OK)
|
|
|
|
|
val_index = lua_absindex(state, val_index);
|
|
|
|
|
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
|
|
|
|
|
PushDFObject(state, type, target);
|
|
|
|
|
lua_pushvalue(state, val_index);
|
|
|
|
|
return Lua::SafeCall(out, state, 2, 0, perr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DFHack::Lua::SafeCallString(color_ostream &out, lua_State *state, const std::string &code,
|
|
|
|
|
int nargs, int nres, bool perr,
|
|
|
|
|
const char *debug_tag, int env_idx)
|
|
|
|
|
{
|
|
|
|
|
if (!debug_tag)
|
|
|
|
|
debug_tag = code.c_str();
|
|
|
|
|
if (env_idx)
|
|
|
|
|
env_idx = lua_absindex(state, env_idx);
|
|
|
|
|
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// Parse the code
|
|
|
|
|
if (luaL_loadbuffer(state, code.data(), code.size(), debug_tag) != LUA_OK)
|
|
|
|
|
{
|
|
|
|
|
report_error(out, state);
|
|
|
|
|
if (perr)
|
|
|
|
|
{
|
|
|
|
|
report_error(state, &out);
|
|
|
|
|
lua_pop(state, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Replace _ENV
|
|
|
|
|
lua_pushvalue(state, eidx);
|
|
|
|
|
|
|
|
|
|
if (!lua_setupvalue(state, -2, 1))
|
|
|
|
|
if (env_idx)
|
|
|
|
|
{
|
|
|
|
|
out.printerr("No _ENV upvalue.\n");
|
|
|
|
|
return false;
|
|
|
|
|
lua_pushvalue(state, env_idx);
|
|
|
|
|
lua_setupvalue(state, -2, 1);
|
|
|
|
|
assert(lua_gettop(state) == base+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
if (nargs > 0)
|
|
|
|
|
lua_insert(state, -1-nargs);
|
|
|
|
|
|
|
|
|
|
return Lua::SafeCall(out, state, nargs, nres, perr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
@ -240,6 +487,8 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
|
|
|
|
|
// Make a proxy global environment.
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
if (env)
|
|
|
|
|
lua_pushvalue(state, env);
|
|
|
|
@ -249,7 +498,6 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
lua_setmetatable(state, -2);
|
|
|
|
|
|
|
|
|
|
// Main interactive loop
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
int vcnt = 1;
|
|
|
|
|
string curline;
|
|
|
|
|
string prompt_str = "[" + string(prompt) + "]# ";
|
|
|
|
@ -272,9 +520,7 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
{
|
|
|
|
|
curline = "return " + curline.substr(1);
|
|
|
|
|
|
|
|
|
|
if (!load_with_env(out, state, curline, base))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SafeCall(out, state, 0, LUA_MULTRET))
|
|
|
|
|
if (!Lua::SafeCallString(out, state, curline, 0, LUA_MULTRET, true, "=(interactive)", base))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int numret = lua_gettop(state) - base;
|
|
|
|
@ -308,9 +554,7 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!load_with_env(out, state, curline, base))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SafeCall(out, state, 0, 0))
|
|
|
|
|
if (!Lua::SafeCallString(out, state, curline, 0, LUA_MULTRET, true, "=(interactive)", base))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -323,9 +567,9 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_interpreter(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
color_ostream *pstream = Lua::GetOutput(state);
|
|
|
|
|
Console *pstream = get_console(state);
|
|
|
|
|
if (!pstream)
|
|
|
|
|
luaL_error(state, "Cannot use dfhack.interpreter() without output.");
|
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
|
|
int argc = lua_gettop(state);
|
|
|
|
|
|
|
|
|
@ -339,8 +583,7 @@ static int lua_dfhack_interpreter(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_with_suspend(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
int ctx;
|
|
|
|
|
int rv = lua_getctx(L, &ctx);
|
|
|
|
|
int rv = lua_getctx(L, NULL);
|
|
|
|
|
|
|
|
|
|
// Non-resume entry point:
|
|
|
|
|
if (rv == LUA_OK)
|
|
|
|
@ -351,7 +594,7 @@ static int lua_dfhack_with_suspend(lua_State *L)
|
|
|
|
|
|
|
|
|
|
Core::getInstance().Suspend();
|
|
|
|
|
|
|
|
|
|
lua_pushcfunction(L, traceback);
|
|
|
|
|
lua_pushcfunction(L, dfhack_onerror);
|
|
|
|
|
lua_insert(L, 1);
|
|
|
|
|
|
|
|
|
|
rv = lua_pcallk(L, nargs-1, LUA_MULTRET, 1, 0, lua_dfhack_with_suspend);
|
|
|
|
@ -372,8 +615,12 @@ static const luaL_Reg dfhack_funcs[] = {
|
|
|
|
|
{ "print", lua_dfhack_print },
|
|
|
|
|
{ "println", lua_dfhack_println },
|
|
|
|
|
{ "printerr", lua_dfhack_printerr },
|
|
|
|
|
{ "traceback", traceback },
|
|
|
|
|
{ "color", lua_dfhack_color },
|
|
|
|
|
{ "is_interactive", lua_dfhack_is_interactive },
|
|
|
|
|
{ "lineedit", lua_dfhack_lineedit },
|
|
|
|
|
{ "interpreter", lua_dfhack_interpreter },
|
|
|
|
|
{ "safecall", lua_dfhack_safecall },
|
|
|
|
|
{ "onerror", dfhack_onerror },
|
|
|
|
|
{ "with_suspend", lua_dfhack_with_suspend },
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
@ -459,6 +706,8 @@ static PersistentDataItem get_persistent(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_get(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
|
|
|
|
|
auto ref = get_persistent(state);
|
|
|
|
|
|
|
|
|
|
return read_persistent(state, ref, !lua_istable(state, 1));
|
|
|
|
@ -466,6 +715,8 @@ static int dfhack_persistent_get(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_delete(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
|
|
|
|
|
auto ref = get_persistent(state);
|
|
|
|
|
|
|
|
|
|
bool ok = Core::getInstance().getWorld()->DeletePersistentData(ref);
|
|
|
|
@ -476,6 +727,8 @@ static int dfhack_persistent_delete(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_get_all(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
|
|
|
|
|
const char *str = luaL_checkstring(state, 1);
|
|
|
|
|
bool prefix = (lua_gettop(state)>=2 ? lua_toboolean(state,2) : false);
|
|
|
|
|
|
|
|
|
@ -501,6 +754,8 @@ static int dfhack_persistent_get_all(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int dfhack_persistent_save(lua_State *state)
|
|
|
|
|
{
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
|
|
|
|
|
lua_settop(state, 2);
|
|
|
|
|
luaL_checktype(state, 1, LUA_TTABLE);
|
|
|
|
|
bool add = lua_toboolean(state, 2);
|
|
|
|
@ -597,8 +852,18 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
|
|
|
|
|
lua_pushcfunction(state, lua_dfhack_println);
|
|
|
|
|
lua_setglobal(state, "print");
|
|
|
|
|
|
|
|
|
|
// Create and initialize the dfhack global
|
|
|
|
|
// Create the dfhack global
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
|
|
|
|
|
// Create the metatable for exceptions
|
|
|
|
|
lua_newtable(state);
|
|
|
|
|
lua_pushcfunction(state, dfhack_exception_tostring);
|
|
|
|
|
lua_setfield(state, -2, "__tostring");
|
|
|
|
|
lua_dup(state);
|
|
|
|
|
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_EXCEPTION_META_TOKEN);
|
|
|
|
|
lua_setfield(state, -2, "exception");
|
|
|
|
|
|
|
|
|
|
// Initialize the dfhack global
|
|
|
|
|
luaL_setfuncs(state, dfhack_funcs, 0);
|
|
|
|
|
|
|
|
|
|
OpenPersistent(state);
|
|
|
|
|