initial commit
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
// Loading Lua off the SD card. Lua's stock loaders go through stdio, which cannot see the
|
||||
// mount, so every path into the filesystem goes through FsProvider instead.
|
||||
|
||||
#include <lua/runtime.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lauxlib.h"
|
||||
#include "lua.h"
|
||||
}
|
||||
|
||||
namespace esp32lua {
|
||||
namespace {
|
||||
|
||||
struct ChunkReader {
|
||||
FileReader* file;
|
||||
char buffer[512];
|
||||
};
|
||||
|
||||
const char* readChunk(lua_State*, void* context, size_t* size) {
|
||||
ChunkReader* reader = static_cast<ChunkReader*>(context);
|
||||
const int32_t read = reader->file->read(reader->buffer, sizeof(reader->buffer));
|
||||
*size = read > 0 ? static_cast<size_t>(read) : 0;
|
||||
return read > 0 ? reader->buffer : nullptr;
|
||||
}
|
||||
|
||||
// Loads a path onto the stack as a chunk, or pushes nothing and returns a Lua status.
|
||||
int load(lua_State* state, FsProvider& fs, const std::string& path) {
|
||||
ChunkReader reader;
|
||||
reader.file = fs.openRead(path);
|
||||
if (!reader.file) {
|
||||
lua_pushfstring(state, "cannot open %s", path.c_str());
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
const std::string chunkname = "@" + path;
|
||||
const int status = lua_load(state, readChunk, &reader, chunkname.c_str(), "t");
|
||||
delete reader.file;
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Runtime::loadScript(const std::string& path) {
|
||||
return load(state_, *providers_.fs, path) == LUA_OK;
|
||||
}
|
||||
|
||||
// Resolves a module name against package.path, reporting every path tried the way the stock
|
||||
// searcher does.
|
||||
int Runtime::searchModule(lua_State* state) {
|
||||
Runtime* runtime = Runtime::from(state);
|
||||
std::string name = luaL_checkstring(state, 1);
|
||||
for (size_t at = 0; at < name.size(); at++) {
|
||||
if (name[at] == '.') name[at] = '/';
|
||||
}
|
||||
|
||||
lua_getglobal(state, "package");
|
||||
lua_getfield(state, -1, "path");
|
||||
const std::string templates = luaL_optstring(state, -1, "");
|
||||
lua_pop(state, 2);
|
||||
|
||||
std::string tried;
|
||||
size_t start = 0;
|
||||
while (start <= templates.size()) {
|
||||
const size_t end = templates.find(';', start);
|
||||
std::string candidate = templates.substr(start, end == std::string::npos ? std::string::npos : end - start);
|
||||
start = end == std::string::npos ? templates.size() + 1 : end + 1;
|
||||
if (candidate.empty()) continue;
|
||||
|
||||
const size_t mark = candidate.find('?');
|
||||
if (mark != std::string::npos) candidate.replace(mark, 1, name);
|
||||
if (!runtime->providers_.fs->exists(candidate)) {
|
||||
tried += "\n\tno file '" + candidate + "'";
|
||||
continue;
|
||||
}
|
||||
if (load(state, *runtime->providers_.fs, candidate) != LUA_OK) {
|
||||
return luaL_error(state, "error loading module '%s' from '%s':\n\t%s", luaL_checkstring(state, 1),
|
||||
candidate.c_str(), lua_tostring(state, -1));
|
||||
}
|
||||
lua_pushstring(state, candidate.c_str());
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(state, tried.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Runtime::loadFile(lua_State* state) {
|
||||
Runtime* runtime = Runtime::from(state);
|
||||
if (load(state, *runtime->providers_.fs, luaL_checkstring(state, 1)) == LUA_OK) return 1;
|
||||
lua_pushnil(state);
|
||||
lua_insert(state, -2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
void Runtime::installLoader(const std::string& appDir) {
|
||||
lua_getglobal(state_, "package");
|
||||
|
||||
const std::string path = appDir + "/?.lua;" + paths_.lib + "/?.lua";
|
||||
lua_pushlstring(state_, path.data(), path.size());
|
||||
lua_setfield(state_, -2, "path");
|
||||
|
||||
// Keep the preload searcher, drop the C loaders: they can only report misleading errors
|
||||
// about shared objects that were never there.
|
||||
lua_getfield(state_, -1, "searchers");
|
||||
lua_pushcfunction(state_, searchModule);
|
||||
lua_rawseti(state_, -2, 2);
|
||||
for (int at = 3; at <= 4; at++) {
|
||||
lua_pushnil(state_);
|
||||
lua_rawseti(state_, -2, at);
|
||||
}
|
||||
lua_pop(state_, 2);
|
||||
|
||||
lua_pushcfunction(state_, loadFile);
|
||||
lua_setglobal(state_, "loadfile");
|
||||
}
|
||||
|
||||
} // namespace esp32lua
|
||||
Reference in New Issue
Block a user