diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/lua_function.cpp | 39 | ||||
-rw-r--r-- | indra/llcommon/lua_function.h | 10 | ||||
-rw-r--r-- | indra/llfilesystem/lldir.cpp | 5 | ||||
-rw-r--r-- | indra/llfilesystem/lldir.h | 1 | ||||
-rw-r--r-- | indra/newview/llluamanager.cpp | 89 | ||||
-rw-r--r-- | indra/newview/llluamanager.h | 4 |
6 files changed, 61 insertions, 87 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp index e9b4bf0b89..41bb7bac12 100644 --- a/indra/llcommon/lua_function.cpp +++ b/indra/llcommon/lua_function.cpp @@ -25,18 +25,20 @@ #include "llsdutil.h" #include "lualistener.h" -int lluau::dostring(lua_State* L, const std::string& desc, const std::string& text) +namespace { + // can't specify free function free() as a unique_ptr deleter + struct freer { - size_t bytecodeSize = 0; - // The char* returned by luau_compile() must be freed by calling free(). - // Use unique_ptr so the memory will be freed even if luau_load() throws. - std::unique_ptr<char[], freer> bytecode{ - luau_compile(text.data(), text.length(), nullptr, &bytecodeSize)}; - auto r = luau_load(L, desc.data(), bytecode.get(), bytecodeSize, 0); - if (r != LUA_OK) - return r; - } // free bytecode + void operator()(void* ptr){ free(ptr); } + }; +} // anonymous namespace + +int lluau::dostring(lua_State* L, const std::string& desc, const std::string& text) +{ + auto r = loadstring(L, desc, text); + if (r != LUA_OK) + return r; // It's important to pass LUA_MULTRET as the expected number of return // values: if we pass any fixed number, we discard any returned values @@ -44,6 +46,16 @@ int lluau::dostring(lua_State* L, const std::string& desc, const std::string& te return lua_pcall(L, 0, LUA_MULTRET, 0); } +int lluau::loadstring(lua_State *L, const std::string &desc, const std::string &text) +{ + size_t bytecodeSize = 0; + // The char* returned by luau_compile() must be freed by calling free(). + // Use unique_ptr so the memory will be freed even if luau_load() throws. + std::unique_ptr<char[], freer> bytecode{ + luau_compile(text.data(), text.length(), nullptr, &bytecodeSize)}; + return luau_load(L, desc.data(), bytecode.get(), bytecodeSize, 0); +} + std::string lua_tostdstring(lua_State* L, int index) { size_t len; @@ -406,13 +418,18 @@ void lua_pushllsd(lua_State* L, const LLSD& data) } LuaState::LuaState(script_finished_fn cb): - mCallback(cb) + mCallback(cb), + mState(nullptr) { initLuaState(); } void LuaState::initLuaState() { + if (mState) + { + lua_close(mState); + } mState = luaL_newstate(); luaL_openlibs(mState); LuaFunction::init(mState); diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h index 54db92f73e..0605eb12a6 100644 --- a/indra/llcommon/lua_function.h +++ b/indra/llcommon/lua_function.h @@ -22,15 +22,6 @@ #define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) #define lua_rawlen lua_objlen -namespace -{ - // can't specify free function free() as a unique_ptr deleter - struct freer - { - void operator()(void *ptr) { free(ptr); } - }; -} - namespace lluau { // luau defines luaL_error() as void, but we want to use the Lua idiom of @@ -56,6 +47,7 @@ namespace lluau // rather than string_views because dostring() needs pointers to nul- // terminated char arrays. int dostring(lua_State* L, const std::string& desc, const std::string& text); + int loadstring(lua_State* L, const std::string& desc, const std::string& text); } // namespace lluau std::string lua_tostdstring(lua_State* L, int index); diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 69b23f9cf8..e3769c6afb 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -469,6 +469,7 @@ static std::string ELLPathToString(ELLPath location) ENT(LL_PATH_DEFAULT_SKIN) ENT(LL_PATH_FONTS) ENT(LL_PATH_LAST) + ENT(LL_PATH_SCRIPTS) ; #undef ENT @@ -588,6 +589,10 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd case LL_PATH_FONTS: prefix = add(getAppRODataDir(), "fonts"); break; + + case LL_PATH_SCRIPTS: + prefix = add(getAppRODataDir(), "scripts"); + break; default: llassert(0); diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index b9a046ba33..7d418159d1 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -49,6 +49,7 @@ typedef enum ELLPath LL_PATH_DEFAULT_SKIN = 17, LL_PATH_FONTS = 18, LL_PATH_DUMP = 19, + LL_PATH_SCRIPTS = 20, LL_PATH_LAST } ELLPath; diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 164738bc3b..671410d420 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -46,6 +46,7 @@ extern LLUIListener sUIListener; #endif // ! LL_TEST #include <boost/algorithm/string/replace.hpp> +#include <filesystem> #include "luau/luacode.h" #include "luau/lua.h" @@ -307,8 +308,7 @@ void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, scrip if (in_file.is_open()) { - std::string text{std::istreambuf_iterator<char>(in_file), - std::istreambuf_iterator<char>()}; + std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); if (cb) { @@ -402,28 +402,6 @@ void LLLUAmanager::runScriptOnLogin() #endif // ! LL_TEST } - -bool is_absolute_path(std::string_view path) -{ -#ifdef LL_WINDOWS - // Must either begin with "X:/", "X:\", "/", or "\", where X is a drive letter - return (path.size() >= 3 && isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) || - (path.size() >= 1 && (path[0] == '/' || path[0] == '\\')); -#else - // Must begin with '/' - return path.size() >= 1 && path[0] == '/'; -#endif -} - -std::string join_paths(const std::string &lhs, const std::string &rhs) -{ - std::string result = lhs; - if (!result.empty() && result.back() != '/' && result.back() != '\\') - result += '/'; - result += rhs; - return result; -} - std::string read_file(const std::string &name) { llifstream in_file; @@ -431,20 +409,22 @@ std::string read_file(const std::string &name) if (in_file.is_open()) { - std::string text {std::istreambuf_iterator<char>(in_file), std::istreambuf_iterator<char>()}; + std::string text {std::istreambuf_iterator<char>(in_file), {}}; return text; } return std::string(); } -LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToResolve(std::move(path)), L(L) +LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) : mPathToResolve(path), L(L) { lua_Debug ar; lua_getinfo(L, 1, "s", &ar); mSourceChunkname = ar.source; - if (is_absolute_path(mPathToResolve)) + mPathToResolve = std::filesystem::path(mPathToResolve).lexically_normal().string(); + + if (std::filesystem::path(mPathToResolve).is_absolute()) luaL_argerrorL(L, 1, "cannot require a full path"); std::replace(mPathToResolve.begin(), mPathToResolve.end(), '\\', '/'); @@ -457,7 +437,7 @@ LLRequireResolver::LLRequireResolver(lua_State *L, std::string path) : mPathToRe if (status != ModuleStatus::FileRead) return ResolvedRequire {status}; else - return ResolvedRequire {status, std::move(resolver.mChunkname), std::move(resolver.mAbsolutePath), std::move(resolver.mSourceCode)}; + return ResolvedRequire {status, resolver.mAbsolutePath, resolver.mSourceCode}; } LLRequireResolver::ModuleStatus LLRequireResolver::findModule() @@ -467,26 +447,24 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModule() // Put _MODULES table on stack for checking and saving to the cache luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1); + // Check if the module is already in _MODULES table, read from file otherwise LLRequireResolver::ModuleStatus moduleStatus = findModuleImpl(); if (moduleStatus != LLRequireResolver::ModuleStatus::NotFound) return moduleStatus; - if (is_absolute_path(mPathToResolve)) + if (std::filesystem::path(mPathToResolve).is_absolute()) return moduleStatus; - std::vector<std::string> lib_paths; - - lib_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + std::vector<std::string> lib_paths {gDirUtilp->getExpandedFilename(LL_PATH_SCRIPTS, "lua")}; - for (size_t i = 0; i < lib_paths.size(); ++i) + for (const auto& path : lib_paths) { - std::string absolutePathOpt = join_paths(lib_paths[i], mPathToResolve); + std::string absolutePathOpt = (std::filesystem::path(path) / mPathToResolve).u8string(); if (absolutePathOpt.empty()) luaL_errorL(L, "error requiring module"); - mChunkname = absolutePathOpt; mAbsolutePath = absolutePathOpt; moduleStatus = findModuleImpl(); @@ -500,16 +478,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModule() LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() { - std::string possibleSuffixes[] = {".luau", ".lua"}; - - size_t unsuffixedAbsolutePathSize = mAbsolutePath.size(); + std::string possibleSuffixedPaths[] = {mAbsolutePath + ".luau", mAbsolutePath + ".lua"}; - for (auto possibleSuffix : possibleSuffixes) + for (auto suffixedPath : possibleSuffixedPaths) { - mAbsolutePath += possibleSuffix; - - // Check cache for module - lua_getfield(L, -1, mAbsolutePath.c_str()); + // Check _MODULES cache for module + lua_getfield(L, -1, suffixedPath.c_str()); if (!lua_isnil(L, -1)) { return ModuleStatus::Cached; @@ -517,15 +491,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() lua_pop(L, 1); // Try to read the matching file - std::string source = read_file(mAbsolutePath); + std::string source = read_file(suffixedPath); if (!source.empty()) { - mChunkname = "=" + mChunkname + possibleSuffix; mSourceCode = source; return ModuleStatus::FileRead; } - - mAbsolutePath.resize(unsuffixedAbsolutePathSize); // truncate to remove suffix } return ModuleStatus::NotFound; @@ -533,17 +504,12 @@ LLRequireResolver::ModuleStatus LLRequireResolver::findModuleImpl() void LLRequireResolver::resolveAndStoreDefaultPaths() { - if (!is_absolute_path(mPathToResolve)) + if (!std::filesystem::path(mPathToResolve).is_absolute()) { - std::string path = gDirUtilp->getDirName(mSourceChunkname); - std::replace(path.begin(), path.end(), '\\', '/'); - path = join_paths(path, mPathToResolve); - mAbsolutePath = path; - mChunkname = path; + mAbsolutePath = (std::filesystem::path((mSourceChunkname)).parent_path() / mPathToResolve).u8string();; } else { - mChunkname = mPathToResolve; mAbsolutePath = mPathToResolve; } } @@ -558,9 +524,9 @@ static int finishrequire(lua_State *L) lua_function(require, "require(module_name) : module_name can be fullpath or just the name, in both cases without .lua") { - std::string name = luaL_checkstring(L, 1); + std::string name = lua_tostdstring(L, 1); - LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, std::move(name)); + LLRequireResolver::ResolvedRequire resolvedRequire = LLRequireResolver::resolveRequire(L, name); if (resolvedRequire.status == LLRequireResolver::ModuleStatus::Cached) return finishrequire(L); @@ -577,18 +543,13 @@ lua_function(require, "require(module_name) : module_name can be fullpath or jus luaL_sandboxthread(ML); { - // now we can compile & run module on the new thread - size_t bytecodeSize = 0; - std::unique_ptr<char[], freer> bytecode { - luau_compile(resolvedRequire.sourceCode.c_str(), resolvedRequire.sourceCode.length(), nullptr, &bytecodeSize)}; - - if (luau_load(ML, resolvedRequire.chunkName.c_str(), bytecode.get(), bytecodeSize, 0) == 0) + if (lluau::loadstring(ML, resolvedRequire.absolutePath.c_str(), resolvedRequire.sourceCode.c_str()) == LUA_OK) { int status = lua_resume(ML, L, 0); - if (status == 0) + if (status == LUA_OK) { - if (lua_gettop(ML) == 0) + if (lua_gettop(ML) == LUA_OK) lua_pushstring(ML, "module must return a value"); else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) lua_pushstring(ML, "module must return a table or function"); diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index c382de3c62..43950ccee4 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -97,14 +97,12 @@ class LLRequireResolver struct ResolvedRequire { ModuleStatus status; - std::string chunkName; std::string absolutePath; std::string sourceCode; }; [[nodiscard]] ResolvedRequire static resolveRequire(lua_State *L, std::string path); - std::string mChunkname; std::string mAbsolutePath; std::string mSourceCode; @@ -112,7 +110,7 @@ class LLRequireResolver std::string mPathToResolve; std::string mSourceChunkname; - LLRequireResolver(lua_State *L, std::string path); + LLRequireResolver(lua_State *L, const std::string& path); ModuleStatus findModule(); lua_State *L; |