scummvm/engines/grim/lua/lstate.cpp
2022-01-16 22:12:14 +01:00

259 lines
6.3 KiB
C++

/*
** Global State
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
#define FORBIDDEN_SYMBOL_EXCEPTION_stderror
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
#include "common/endian.h"
#include "engines/grim/debug.h"
#include "engines/grim/actor.h"
#include "engines/grim/color.h"
#include "engines/grim/lua/lbuiltin.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lgc.h"
#include "engines/grim/lua/llex.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/lualib.h"
#include "engines/grim/lua/luadebug.h"
namespace Grim {
GCnode rootproto;
GCnode rootcl;
GCnode rootglobal;
GCnode roottable;
struct ref *refArray;
int32 refSize;
int32 GCthreshold;
int32 nblocks;
int32 Mbuffsize;
int32 Mbuffnext;
char *Mbuffbase;
char *Mbuffer;
TObject errorim;
stringtable *string_root;
int32 last_tag;
struct IM *IMtable;
int32 IMtable_size;
LState *lua_state = nullptr;
LState *lua_rootState = nullptr;
int globalTaskSerialId = 0;
void stderrorim();
static luaL_reg stdErrorRimFunc[] = {
{ "stderrorim", stderrorim }
};
static void lua_openthr() {
Mbuffsize = 0;
Mbuffnext = 0;
Mbuffbase = nullptr;
Mbuffer = nullptr;
}
#define STACK_UNIT 256
void lua_stateinit(LState *state) {
state->prev = nullptr;
state->next = nullptr;
state->all_paused = 0;
state->paused = false;
state->preventBreakCounter = 0;
state->callLevelCounter = 0;
state->updated = false;
state->numCblocks = 0;
state->Cstack.base = 0;
state->Cstack.lua2C = 0;
state->Cstack.num = 0;
state->errorJmp = nullptr;
state->id = globalTaskSerialId++;
state->task = nullptr;
state->prevTask = nullptr;
state->taskFunc.ttype = LUA_T_NIL;
state->sleepFor = 0;
state->stack.stack = luaM_newvector(STACK_UNIT, TObject);
state->stack.top = state->stack.stack;
state->stack.last = state->stack.stack + (STACK_UNIT - 1);
}
void lua_statedeinit(LState *state) {
if (state->prev)
state->prev->next = state->next;
if (state->next)
state->next->prev = state->prev;
state->next = nullptr;
state->prev = nullptr;
if (state->task) {
lua_Task *t, *m;
for (t = state->task; t != nullptr;) {
m = t->next;
luaM_free(t);
t = m;
}
}
free(state->stack.stack);
}
void lua_resetglobals() {
lua_openthr();
rootproto.next = nullptr;
rootproto.marked = 0;
rootcl.next = nullptr;
rootcl.marked = 0;
rootglobal.next = nullptr;
rootglobal.marked = 0;
roottable.next = nullptr;
roottable.marked = 0;
refArray = nullptr;
refSize = 0;
GCthreshold = GARBAGE_BLOCK;
nblocks = 0;
luaD_init();
luaS_init();
luaX_init();
}
void callHook(lua_Function func, const char *filename, int32 line) {
const char *name, *type;
FILE *output = stdout;
int i;
for (i = 0; i < lua_state->callLevelCounter; i++) {
fprintf(output, " ");
}
fprintf(output, "id: %d ", lua_state->id);
type = lua_getobjname(func, &name);
if (func == LUA_NOOBJECT) {
fprintf(output, "<< %s\n", filename);
return;
} else {
fprintf(output, ">> %s ", filename);
}
switch (*type) {
case 'g':
fprintf(output, "function: %s(", name);
for (i = 1; ; i++) {
if (lua_getparam(i) == LUA_NOOBJECT)
break;
if (lua_isnil(lua_getparam(i)))
fprintf(output, "nil");
else if (lua_istable(lua_getparam(i)))
fprintf(output, "{...}");
else if (lua_isuserdata(lua_getparam(i))) {
if (lua_tag(lua_getparam(i)) == MKTAG('A','C','T','R')) {
Actor *a = Actor::getPool().getObject(lua_getuserdata(lua_getparam(i)));
fprintf(output, "<actor \"%s\">", a->getName().c_str());
} else if (lua_tag(lua_getparam(i)) == MKTAG('C','O','L','R')) {
Color c(lua_getuserdata(lua_getparam(i)));
fprintf(output, "<color #%02x%02x%02x>", c.getRed(), c.getGreen(), c.getBlue());
} else
fprintf(output, "<userdata %d>", lua_getuserdata(lua_getparam(i)));
} else if (lua_isfunction(lua_getparam(i))) {
lua_getobjname(lua_getparam(i), &name);
fprintf(output, "<function %s>", name);
} else if (lua_isnumber(lua_getparam(i)))
fprintf(output, "%g", lua_getnumber(lua_getparam(i)));
else if (lua_isstring(lua_getparam(i)))
fprintf(output, "\"%s\"", lua_getstring(lua_getparam(i)));
else
fprintf(output, "<unknown>");
if (lua_getparam(i + 1) != LUA_NOOBJECT)
fprintf(output, ", ");
}
fprintf(output, ")");
break;
case 't':
fprintf(output, "`%s' tag method", name);
break;
default:
{
if (line == 0)
fprintf(output, "{START SCRIPT: %s}", filename);
else if (line < 0) {
fprintf(output, "Unknown %s", filename);
} else
fprintf(output, "function (%s:%d)", filename, line);
}
}
fprintf(output, "\n");
}
void lua_open() {
if (lua_state)
return;
lua_rootState = lua_state = luaM_new(LState);
lua_stateinit(lua_state);
lua_resetglobals();
luaT_init();
luaB_predefine();
luaL_addlibtolist(stdErrorRimFunc, (sizeof(stdErrorRimFunc) / sizeof(stdErrorRimFunc[0])));
if (Debug::isChannelEnabled(Debug::Lua))
lua_callhook = callHook;
}
void lua_close() {
TaggedString *alludata = luaS_collectudata();
GCthreshold = MAX_INT; // to avoid GC during GC
luaC_hashcallIM((Hash *)roottable.next); // GC t.methods for tables
luaC_strcallIM(alludata); // GC tag methods for userdata
luaD_gcIM(&luaO_nilobject); // GC tag method for nil (signal end of GC)
luaH_free((Hash *)roottable.next);
luaF_freeproto((TProtoFunc *)rootproto.next);
luaF_freeclosure((Closure *)rootcl.next);
luaS_free(alludata);
luaS_freeall();
luaM_free(IMtable);
luaM_free(refArray);
luaM_free(Mbuffer);
LState *tmpState, *state;
for (state = lua_rootState; state != nullptr;) {
tmpState = state->next;
lua_statedeinit(state);
luaM_free(state);
state = tmpState;
}
Mbuffer = nullptr;
IMtable = nullptr;
refArray = nullptr;
lua_rootState = lua_state = nullptr;
#ifdef LUA_DEBUG
printf("total de blocos: %ld\n", numblocks);
printf("total de memoria: %ld\n", totalmem);
#endif
}
bool lua_isopen() {
return (lua_rootState);
}
} // end of namespace Grim