I'm working on the mGBA project (https://github.com/mgba-emu/mgba) and I'm trying to fix some problems regarding the scripting API and Lua 5.1.
The project has the following functions:
Load the Lua script:
bool _luaLoad(struct mScriptEngineContext* ctx, const char* filename, struct VFile* vf) {
struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) ctx;
struct mScriptEngineLuaReader data = {
.vf = vf
};
if (luaContext->lastError) {
free(luaContext->lastError);
luaContext->lastError = NULL;
}
char name[PATH_MAX + 1];
char dirname[PATH_MAX];
name[0] = '\0';
dirname[0] = '\0';
if (filename) {
if (*filename == '*') {
snprintf(name, sizeof(name), "=%s", filename + 1);
} else {
const char* lastSlash = strrchr(filename, '/');
const char* lastBackslash = strrchr(filename, '\\');
if (lastSlash && lastBackslash) {
if (lastSlash < lastBackslash) {
lastSlash = lastBackslash;
}
} else if (lastBackslash) {
lastSlash = lastBackslash;
}
if (lastSlash) {
size_t len = lastSlash - filename + 1;
if (sizeof(dirname) < len) {
len = sizeof(dirname);
}
strlcpy(dirname, filename, len);
}
snprintf(name, sizeof(name), "@%s", filename);
}
filename = name;
}
#if LUA_VERSION_NUM >= 502
int ret = lua_load(luaContext->lua, _reader, &data, filename, "t");
#else
int ret = lua_load(luaContext->lua, _reader, &data, filename);
#endif
switch (ret) {
case LUA_OK:
// Create new _ENV
lua_newtable(luaContext->lua);
// Make the old _ENV the __index in the metatable
lua_newtable(luaContext->lua);
lua_pushliteral(luaContext->lua, "__index");
#if LUA_VERSION_NUM >= 502
lua_getupvalue(luaContext->lua, -4, 1);
#else
lua_getfenv(luaContext->lua, -4);
#endif
lua_rawset(luaContext->lua, -3);
lua_pushliteral(luaContext->lua, "__newindex");
#if LUA_VERSION_NUM >= 502
lua_getupvalue(luaContext->lua, -4, 1);
#else
lua_getfenv(luaContext->lua, -4);
#endif
lua_rawset(luaContext->lua, -3);
lua_setmetatable(luaContext->lua, -2);
lua_pushliteral(luaContext->lua, "script");
lua_newtable(luaContext->lua);
if (dirname[0]) {
lua_pushliteral(luaContext->lua, "require");
lua_pushstring(luaContext->lua, dirname);
lua_pushcclosure(luaContext->lua, _luaRequireShim, 1);
lua_rawset(luaContext->lua, -5);
lua_pushliteral(luaContext->lua, "dir");
lua_pushstring(luaContext->lua, dirname);
lua_rawset(luaContext->lua, -3);
}
if (name[0] == '@') {
lua_pushliteral(luaContext->lua, "path");
lua_pushstring(luaContext->lua, &name[1]);
lua_rawset(luaContext->lua, -3);
}
lua_rawset(luaContext->lua, -3);
lua_setupvalue(luaContext->lua, -2, 1);
luaContext->func = luaL_ref(luaContext->lua, LUA_REGISTRYINDEX);
return true;
case LUA_ERRSYNTAX:
luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1));
lua_pop(luaContext->lua, 1);
break;
default:
break;
}
return false;
}
Run the script:
bool _luaRun(struct mScriptEngineContext* context) {
struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) context;
lua_rawgeti(luaContext->lua, LUA_REGISTRYINDEX, luaContext->func);
return _luaInvoke(luaContext, NULL);
}
bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* frame) {
int nargs = 0;
if (frame) {
nargs = mScriptListSize(&frame->arguments);
}
if (luaContext->lastError) {
free(luaContext->lastError);
luaContext->lastError = NULL;
}
if (frame && !_luaPushFrame(luaContext, &frame->arguments)) {
return false;
}
lua_pushliteral(luaContext->lua, "mCtx");
lua_pushlightuserdata(luaContext->lua, luaContext);
lua_rawset(luaContext->lua, LUA_REGISTRYINDEX);
int ret = lua_pcall(luaContext->lua, nargs, LUA_MULTRET, 0);
lua_pushliteral(luaContext->lua, "mCtx");
lua_pushnil(luaContext->lua);
lua_rawset(luaContext->lua, LUA_REGISTRYINDEX);
if (ret == LUA_ERRRUN) {
luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1));
lua_pop(luaContext->lua, 1);
}
if (ret) {
return false;
}
if (frame && !_luaPopFrame(luaContext, &frame->returnValues)) {
mScriptContextDrainPool(luaContext->d.context);
return false;
}
mScriptContextDrainPool(luaContext->d.context);
return true;
}
This works flawlessly with Lua 5.2-5.4, but with Lua 5.1 it gives the following error with every script I've tried, even with a script with only the line print("Hello world"):
"attempt to call a table value"
I think this is related to the environments (in fact, thanks to the first comment here I fixed that) but I'm not sure.
Is there any thing I'm missing here?
Thanks!