diff options
-rw-r--r-- | indra/newview/llluamanager.cpp | 103 |
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 ¬ification, 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; } } |