summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/lua_function.cpp39
-rw-r--r--indra/llcommon/lua_function.h10
-rw-r--r--indra/llfilesystem/lldir.cpp5
-rw-r--r--indra/llfilesystem/lldir.h1
-rw-r--r--indra/newview/llluamanager.cpp89
-rw-r--r--indra/newview/llluamanager.h4
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;