summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llluamanager.cpp103
1 files changed, 76 insertions, 27 deletions
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index bdf8fc0278..a105eebf67 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -32,6 +32,7 @@
#include "llappearancemgr.h"
#include "llcallbacklist.h"
#include "llerror.h"
+#include "lleventcoro.h"
#include "llevents.h"
#include "llfloaterreg.h"
#include "llfloaterimnearbychat.h"
@@ -141,6 +142,12 @@ private:
static bool call_lua(lua_State* L, const std::string& pump, const LLSD& data)
{
+ if (! lua_checkstack(L, 3))
+ {
+ LL_WARNS("Lua") << "Cannot extend Lua stack to call listen_events() callback"
+ << LL_ENDL;
+ return false;
+ }
// push the registered Lua callback function stored in our registry as
// "event.function"
lua_getfield(L, LUA_REGISTRYINDEX, "event.function");
@@ -227,6 +234,15 @@ public:
}
}
+ static lua_CFunction get(const std::string& key)
+ {
+ // use find() instead of subscripting to avoid creating an entry for
+ // unknown key
+ const auto& registry{ getRegistry() };
+ auto found{ registry.find(key) };
+ return (found == registry.end())? nullptr : found->second;
+ }
+
private:
using Registry = std::map<std::string, lua_CFunction>;
static Registry& getRegistry()
@@ -266,6 +282,7 @@ lua_function(print_debug)
return 0;
}
+// also used for print(); see LuaState constructor
lua_function(print_info)
{
luaL_where(L, 1);
@@ -402,12 +419,14 @@ lua_function(set_debug_setting_bool)
lua_function(get_avatar_name)
{
std::string name = gAgentAvatarp->getFullname();
+ luaL_checkstack(L, 1, nullptr);
lua_pushstring(L, name.c_str());
return 1;
}
lua_function(is_avatar_flying)
{
+ luaL_checkstack(L, 1, nullptr);
lua_pushboolean(L, gAgent.getFlying());
return 1;
}
@@ -461,6 +480,7 @@ void handle_notification_dialog(const LLSD &notification, const LLSD &response,
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ luaL_checkstack(L, 1, nullptr);
lua_pushinteger(L, option);
lua_setglobal(L, response_cb.c_str());
}
@@ -619,10 +639,10 @@ lua_function(run_ui_command)
return 0;
}
-lua_function(post_on_pump)
+lua_function(post_on)
{
- std::string pumpname{ lua_tostring(L, -2) };
- LLSD data{ lua_tollsd(L, -1) };
+ std::string pumpname{ lua_tostring(L, 1) };
+ LLSD data{ lua_tollsd(L, 2) };
lua_pop(L, 2);
LLEventPumps::instance().obtain(pumpname).post(data);
return 0;
@@ -634,6 +654,7 @@ lua_function(listen_events)
{
return luaL_typeerror(L, 1, "function");
}
+ luaL_checkstack(L, 2, nullptr);
// Get the lua_State* for the main thread of this state, in case we were
// called from a coroutine thread. We're going to make callbacks into Lua
@@ -649,6 +670,7 @@ lua_function(listen_events)
// pop the main thread
lua_pop(L, 1);
+ luaL_checkstack(mainthread, 1, nullptr);
LuaListener::ptr_t listener;
// Does the main thread already have a LuaListener stored in the registry?
// That is, has this Lua chunk already called listen_events()?
@@ -691,9 +713,27 @@ lua_function(listen_events)
return 2;
}
-void initLUA(lua_State *L)
+lua_function(await_event)
{
- LuaFunction::init(L);
+ // await_event(pumpname [, timeout [, value to return if timeout (default nil)]])
+ auto pumpname{ lua_tostdstring(L, 1) };
+ LLSD result;
+ if (lua_gettop(L) > 1)
+ {
+ auto timeout{ lua_tonumber(L, 2) };
+ // with no 3rd argument, should be LLSD()
+ auto dftval{ lua_tollsd(L, 3) };
+ lua_pop(L, lua_gettop(L));
+ result = llcoro::suspendUntilEventOnWithTimeout(pumpname, timeout, dftval);
+ }
+ else
+ {
+ // no timeout
+ lua_pop(L, 1);
+ result = llcoro::suspendUntilEventOn(pumpname);
+ }
+ lua_pushllsd(L, result);
+ return 1;
}
/**
@@ -708,7 +748,9 @@ public:
mState(luaL_newstate())
{
luaL_openlibs(mState);
- initLUA(mState);
+ LuaFunction::init(mState);
+ // Try to make print() write to our log.
+ lua_register(mState, "print", LuaFunction::get("print_info"));
}
LuaState(const LuaState&) = delete;
@@ -770,9 +812,10 @@ private:
void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb)
{
- LLCoros::instance().launch("LUAScriptFileCoro", [filename, cb]()
+ std::string desc{ stringize("runScriptFile('", filename, "')") };
+ LLCoros::instance().launch(desc, [desc, filename, cb]()
{
- LuaState L(stringize("runScriptFile('", filename, "')"), cb);
+ LuaState L(desc, cb);
auto LUA_sleep_func = [](lua_State *L)
{
@@ -799,18 +842,19 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn
void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb)
{
- LLCoros::instance().launch("LUAScriptFileCoro", [cmd, cb]()
+ // find a suitable abbreviation for the cmd string
+ std::string_view shortcmd{ cmd };
+ const size_t shortlen = 40;
+ std::string::size_type eol = shortcmd.find_first_of("\r\n");
+ if (eol != std::string::npos)
+ shortcmd = shortcmd.substr(0, eol);
+ if (shortcmd.length() > shortlen)
+ shortcmd = stringize(shortcmd.substr(0, shortlen), "...");
+
+ std::string desc{ stringize("runScriptLine('", shortcmd, "')") };
+ LLCoros::instance().launch(desc, [desc, cmd, cb]()
{
- // find a suitable abbreviation for the cmd string
- std::string_view shortcmd{ cmd };
- const size_t shortlen = 40;
- std::string::size_type eol = shortcmd.find_first_of("\r\n");
- if (eol != std::string::npos)
- shortcmd = shortcmd.substr(0, eol);
- if (shortcmd.length() > shortlen)
- shortcmd = stringize(shortcmd.substr(0, shortlen), "...");
-
- LuaState L(stringize("runScriptLine('", shortcmd, "')"), cb);
+ LuaState L(desc, cb);
L.checkLua(luaL_dostring(L, cmd.c_str()));
});
}
@@ -843,6 +887,7 @@ std::string lua_tostdstring(lua_State* L, int index)
void lua_pushstdstring(lua_State* L, const std::string& str)
{
+ luaL_checkstack(L, 1, nullptr);
lua_pushlstring(L, str.c_str(), str.length());
}
@@ -934,6 +979,11 @@ LLSD lua_tollsd(lua_State* L, int index)
// - LLSD::Real with integer value returns as LLSD::Integer.
// - LLSD::UUID, LLSD::Date and LLSD::URI all convert to Lua string,
// and so return as LLSD::String.
+
+ // This is the most important of the luaL_checkstack() calls because a
+ // deeply nested Lua structure will enter this case at each level, and
+ // we'll need another 2 stack slots to traverse each nested table.
+ luaL_checkstack(L, 2, nullptr);
lua_pushnil(L); // first key
if (! lua_next(L, index))
{
@@ -1082,6 +1132,8 @@ LLSD lua_tollsd(lua_State* L, int index)
// stack a Lua object corresponding to the passed LLSD object.
void lua_pushllsd(lua_State* L, const LLSD& data)
{
+ // might need 2 slots for array or map
+ luaL_checkstack(L, 2, nullptr);
switch (data.type())
{
case LLSD::TypeUndefined:
@@ -1126,15 +1178,13 @@ void lua_pushllsd(lua_State* L, const LLSD& data)
{
// push a new table with space for array entries
lua_createtable(L, data.size(), 0);
- lua_Integer index{ 0 };
+ lua_Integer key{ 0 };
for (const auto& item: llsd::inArray(data))
{
- // push new index value: table at -2, index at -1
- lua_pushinteger(L, ++index);
- // push new array value: table at -3, index at -2, value at -1
+ // push new array value: table at -2, value at -1
lua_pushllsd(L, item);
- // pop key and value, assign table[key] = value
- lua_settable(L, -3);
+ // pop value, assign table[key] = value
+ lua_seti(L, -2, ++key);
}
break;
}
@@ -1145,8 +1195,7 @@ void lua_pushllsd(lua_State* L, const LLSD& data)
case LLSD::TypeURI:
default:
{
- auto strdata{ data.asString() };
- lua_pushlstring(L, strdata.c_str(), strdata.length());
+ lua_pushstdstring(data.asString());
break;
}
}