From cfd06ad41ab84dbdc04f422ac46dbf244f8c73d3 Mon Sep 17 00:00:00 2001 From: Nick Marks Date: Tue, 6 Oct 2026 17:15:47 -0500 Subject: [PATCH] Fix bool table value types in luaMacrosFromTable luaMacrosFromTable in luaEpics.cpp tried converting each value in the table to a string, regardless of its actual type and this fails for booleans. This commit fixes this by explicity checking the type and manually converting boolean true to "true" and false to "false". This allows us to pass {async = true} as the options table for luaRunFile as advertised in the documentation. --- luaApp/src/luaEpics.cpp | 17 +++++++++++++++-- luaApp/test/luaShellTest.cpp | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/luaApp/src/luaEpics.cpp b/luaApp/src/luaEpics.cpp index e47f774..17dc018 100644 --- a/luaApp/src/luaEpics.cpp +++ b/luaApp/src/luaEpics.cpp @@ -652,14 +652,27 @@ epicsShareFunc std::string luaMacrosFromTable(lua_State* state, int index) /* Duplicate the value before converting -- lua_tostring on a * non-string value modifies it in-place, which corrupts lua_next */ lua_pushvalue(state, -1); - const char* val = lua_tostring(state, -1); - lua_pop(state, 1); + const char* val = nullptr; + switch (lua_type(state, -1)) + { + case LUA_TBOOLEAN: + val = lua_toboolean(state, -1) ? "true" : "false"; + break; + case LUA_TNUMBER: + case LUA_TSTRING: + val = lua_tostring(state, -1); + break; + default: + break; + } if (val) { if (!result.empty()) { result += ","; } result += std::string(key) + "=" + std::string(val); } + + lua_pop(state, 1); } lua_pop(state, 1); } diff --git a/luaApp/test/luaShellTest.cpp b/luaApp/test/luaShellTest.cpp index 71bcb99..aedeca8 100644 --- a/luaApp/test/luaShellTest.cpp +++ b/luaApp/test/luaShellTest.cpp @@ -999,14 +999,33 @@ static void testLuaCmdTableMacros(void) lua_pushstring(state, "sensor"); lua_setfield(state, -2, "R"); + lua_pushboolean(state, 1); + lua_setfield(state, -2, "enabled"); + lua_pushboolean(state, 0); + lua_setfield(state, -2, "disabled"); + + lua_pushinteger(state, 42); + lua_setfield(state, -2, "ivalue"); + + lua_pushnumber(state, 3.14); + lua_setfield(state, -2, "fvalue"); + std::string macros = luaMacrosFromTable(state, lua_gettop(state)); lua_pop(state, 1); - /* Order of keys in Lua tables is not guaranteed, check both */ + /* Order of keys in Lua tables is not guaranteed */ testOk(macros.find("P=dev1:") != std::string::npos, "macros contains P=dev1: : '%s'", macros.c_str()); testOk(macros.find("R=sensor") != std::string::npos, "macros contains R=sensor : '%s'", macros.c_str()); + testOk(macros.find("enabled=true") != std::string::npos, + "macros contains enabled=true: '%s'", macros.c_str()); + testOk(macros.find("disabled=false") != std::string::npos, + "macros contains disabled=false: '%s'", macros.c_str()); + testOk(macros.find("ivalue=42") != std::string::npos, + "macros contains ivalue=42: '%s'", macros.c_str()); + testOk(macros.find("fvalue=3.14") != std::string::npos, + "macros contains fvalue=3.14: '%s'", macros.c_str()); lua_close(state); }