summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-09-16 13:53:11 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-09-16 13:53:11 -0400
commit1154e02fdded191147284997707a3b18ee3b43fd (patch)
treea7c862ff5d72e452d24a6cb585d1f93421a09665
parentecd5aa227653d9b690a14c1d9c1dd90ea644fec5 (diff)
WIP: edits in support of Lua script args
-rw-r--r--indra/llcommon/lua_function.cpp39
-rw-r--r--indra/llcommon/lua_function.h17
-rw-r--r--indra/newview/llluamanager.cpp79
3 files changed, 106 insertions, 29 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index 2557fd0cc9..014ff3c4c4 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -60,7 +60,8 @@ namespace
namespace lluau
{
-int dostring(lua_State* L, const std::string& desc, const std::string& text)
+int dostring(lua_State* L, const std::string& desc, const std::string& text,
+ const std::vector<std::string>& args)
{
auto r = loadstring(L, desc, text);
if (r != LUA_OK)
@@ -80,12 +81,22 @@ int dostring(lua_State* L, const std::string& desc, const std::string& text)
// stack: compiled chunk, debug.traceback()
lua_insert(L, -2);
// stack: debug.traceback(), compiled chunk
- LuaRemover cleanup(L, -2);
+ // capture absolute index of debug.traceback()
+ int traceback = lua_absindex(L, -2);
+ // remove it from stack on exit
+ LuaRemover cleanup(L, traceback);
+
+ // push any args passed -- all strings -- script must handle any desired
+ // conversions
+ for (const auto& arg : args)
+ {
+ lua_pushstdstring(L, arg);
+ }
// 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
// beyond that number.
- return lua_pcall(L, 0, LUA_MULTRET, -2);
+ return lua_pcall(L, int(args.size()), LUA_MULTRET, traceback);
}
int loadstring(lua_State *L, const std::string &desc, const std::string &text)
@@ -804,7 +815,13 @@ bool LuaState::checkLua(const std::string& desc, int r)
return true;
}
-std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string& text)
+std::pair<int, LLSD> LuaState::expr(const std::string& desc, const ScriptCommand& command)
+{
+ return expr(desc, , command.args);
+}
+
+std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string& text,
+ const std::vector<std::string>& args)
{
/*---------------------------- feature flag ----------------------------*/
if (! mFeature)
@@ -827,7 +844,7 @@ std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string&
};
LL_INFOS("Lua") << desc << " run" << LL_ENDL;
- if (! checkLua(desc, lluau::dostring(mState, desc, text)))
+ if (! checkLua(desc, lluau::dostring(mState, desc, text, args)))
{
LL_WARNS("Lua") << desc << " error: " << mError << LL_ENDL;
return { -1, mError };
@@ -1050,6 +1067,18 @@ std::pair<LuaFunction::Registry&, LuaFunction::Lookup&> LuaFunction::getState()
}
/*****************************************************************************
+* LuaCommand
+*****************************************************************************/
+LuaCommand::LuaCommand(const std::string& command)
+{
+}
+
+bool LuaCommand::found() const
+{
+ return ;
+}
+
+/*****************************************************************************
* source_path()
*****************************************************************************/
lua_function(source_path, "source_path(): return the source path of the running Lua script")
diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h
index 10c201c234..a5022db225 100644
--- a/indra/llcommon/lua_function.h
+++ b/indra/llcommon/lua_function.h
@@ -19,6 +19,7 @@
#include "fsyspath.h"
#include "llerror.h"
#include "llsd.h"
+#include "scriptcommand.h"
#include "stringize.h"
#include <exception> // std::uncaught_exceptions()
#include <memory> // std::shared_ptr
@@ -26,6 +27,7 @@
#include <typeinfo>
#include <unordered_map>
#include <utility> // std::pair
+#include <vector>
class LuaListener;
@@ -55,8 +57,10 @@ namespace lluau
// luau removed lua_dostring(), but since we perform the equivalent luau
// sequence in multiple places, encapsulate it. desc and text are strings
// 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);
+ // terminated char arrays. Any args are pushed to the Lua stack before
+ // calling the Lua chunk in text.
+ int dostring(lua_State* L, const std::string& desc, const std::string& text,
+ const std::vector<std::string>& args={});
int loadstring(lua_State* L, const std::string& desc, const std::string& text);
fsyspath source_path(lua_State* L);
@@ -92,13 +96,20 @@ public:
// expr() is for when we want to capture any results left on the stack
// by a Lua expression, possibly including multiple return values.
+ // Pass:
+ // desc = description used for logging et al.
+ // text = Lua chunk to execute, e.g. contents of a script file
+ // args = arguments, if any, to pass to script file
+ // Returns:
// int < 0 means error, and LLSD::asString() is the error message.
// int == 0 with LLSD::isUndefined() means the Lua expression returned no
// results.
// int == 1 means the Lua expression returned one result.
// int > 1 with LLSD::isArray() means the Lua expression returned
// multiple results, represented as the entries of the array.
- std::pair<int, LLSD> expr(const std::string& desc, const std::string& text);
+ std::pair<int, LLSD> expr(const std::string& desc, const std::string& text,
+ const std::vector<std::string>& args={});
+ std::pair<int, LLSD> expr(const std::string& desc, const ScriptCommand& command);
operator lua_State*() const { return mState; }
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index 0bd21516bc..c4ce07e492 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -192,35 +192,72 @@ void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun,
LLCoros::instance().launch(filename, [filename, autorun, result_cb, finished_cb]()
{
ScriptObserver observer(LLCoros::getName(), filename);
- llifstream in_file;
- in_file.open(filename.c_str());
+ // Use LLStringUtil::getTokens() to parse the script command line
+ auto tokens = LLStringUtil::getTokens(filename,
+ " \t\r\n", // drop_delims
+ "", // no keep_delims
+ "\"'", // either kind of quotes
+ "\\"); // backslash escape
+
+#error Under construction
+ // TODO:
+ // - Move this either/or file existence logic to LuaCommand()
+ // - Accept LuaCommand in all LLLUAmanager::mumbleScriptFile() methods
+ // - Update all existing mumbleScriptFile() callers
+ llifstream in_file;
+ in_file.open(tokens[0]);
if (in_file.is_open())
{
- if (autorun)
- {
- sAutorunScriptCount++;
- }
- sScriptCount++;
-
- // A script_finished_fn is used to initialize the LuaState.
- // It will be called when the LuaState is destroyed.
- LuaState L(finished_cb);
- std::string text{std::istreambuf_iterator<char>(in_file), {}};
- auto [count, result] = L.expr(filename, text);
- if (result_cb)
- {
- result_cb(count, result);
- }
+ // The first token is in fact the script filename. Now that the
+ // script file is open, we've consumed that token. The rest are
+ // command-line arguments.
+ tokens.erase(tokens.begin());
}
else
{
- auto msg{ stringize("unable to open script file '", filename, "'") };
- LL_WARNS("Lua") << msg << LL_ENDL;
- if (result_cb)
+ // Parsing the command line produced a script file path we can't
+ // open. Maybe that's because there are spaces in the original
+ // pathname that were neither quoted nor escaped? See if we can
+ // open the whole original command line string.
+ in_file.open(filename);
+ if (! in_file.is_open())
{
- result_cb(-1, msg);
+ std::ostringstream msgstream;
+ msgstream << "Can't open script file " << std::quoted(tokens[0]);
+ if (filename != tokens[0])
+ {
+ msgstream << " or " << std::quoted(filename);
+ }
+ auto msg = msgstream.str();
+ LL_WARNS("Lua") << msg << LL_ENDL;
+ if (result_cb)
+ {
+ result_cb(-1, msg);
+ }
+ return;
}
+ // Here we do have in_file open, using the whole input command
+ // line as its pathname. Discard any parts of it we mistook for
+ // command-line arguments.
+ tokens.clear();
+ }
+
+ // Here in_file is open.
+ if (autorun)
+ {
+ sAutorunScriptCount++;
+ }
+ sScriptCount++;
+
+ // A script_finished_fn is used to initialize the LuaState.
+ // It will be called when the LuaState is destroyed.
+ LuaState L(finished_cb);
+ std::string text{std::istreambuf_iterator<char>(in_file), {}};
+ auto [count, result] = L.expr(filename, text, tokens);
+ if (result_cb)
+ {
+ result_cb(count, result);
}
});
}