Update Lua os.exec, SystemExec API
[ardour.git] / gtk2_ardour / luainstance.cc
index 7f77558f11cde9c0595c3a9e16d83bb211f3c3fd..cfa380e700d13633682042ef0304ddc4d9dda0cd 100644 (file)
@@ -27,6 +27,7 @@
 #include "ardour/plugin_manager.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
+#include "ardour/system_exec.h"
 
 #include "LuaBridge/LuaBridge.h"
 
@@ -367,6 +368,60 @@ namespace LuaMixer {
        }
 
 };
+////////////////////////////////////////////////////////////////////////////////
+
+static PBD::ScopedConnectionList _luaexecs;
+
+static void reaper (ARDOUR::SystemExec* x)
+{
+       delete x;
+}
+
+static int
+lua_forkexec (lua_State *L)
+{
+       int argc = lua_gettop (L);
+       if (argc == 0) {
+               return luaL_argerror (L, 1, "invalid number of arguments, forkexec (command, ...)");
+       }
+       // args are free()ed in ~SystemExec
+       char** args = (char**) malloc ((argc + 1) * sizeof(char*));
+       for (int i = 0; i < argc; ++i) {
+               args[i] = strdup (luaL_checkstring (L, i + 1));
+       }
+       args[argc] = 0;
+
+       ARDOUR::SystemExec* x = new ARDOUR::SystemExec (args[0], args);
+       x->Terminated.connect (_luaexecs, MISSING_INVALIDATOR, boost::bind (&reaper, x), gui_context());
+
+       if (x->start()) {
+               reaper (x);
+               luabridge::Stack<bool>::push (L, false);
+               return -1;
+       } else {
+               luabridge::Stack<bool>::push (L, false);
+       }
+       return 1;
+}
+
+#ifndef PLATFORM_WINDOWS
+static int
+lua_exec (std::string cmd)
+{
+       // args are free()ed in ~SystemExec
+       char** args = (char**) malloc (4 * sizeof(char*));
+       args[0] = strdup ("/bin/sh");
+       args[1] = strdup ("-c");
+       args[2] = strdup (cmd.c_str());
+       args[3] = 0;
+       ARDOUR::SystemExec x ("/bin/sh", args);
+       if (x.start()) {
+               return -1;
+       }
+       x.wait ();
+       return 0;
+}
+#endif
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -376,6 +431,7 @@ namespace LuaMixer {
 using namespace ARDOUR;
 
 PBD::Signal0<void> LuaInstance::LuaTimerDS;
+PBD::Signal0<void> LuaInstance::SetSession;
 
 void
 LuaInstance::register_hooks (lua_State* L)
@@ -397,6 +453,10 @@ LuaInstance::register_hooks (lua_State* L)
                .beginStdBitSet <LuaSignal::LAST_SIGNAL> ("Set")
                .endClass()
                .endNamespace ();
+
+#if 0 // Dump size -> libs/ardour/luabindings.cc
+       printf ("LuaInstance: registered %d signals\n", LuaSignal::LAST_SIGNAL);
+#endif
 }
 
 void
@@ -604,7 +664,6 @@ LuaInstance::register_classes (lua_State* L)
 
        bind_cairo (L);
        bind_dialog (L);
-       register_hooks (L);
 
        luabridge::getGlobalNamespace (L)
                .beginNamespace ("ArdourUI")
@@ -846,6 +905,7 @@ LuaInstance::register_classes (lua_State* L)
 #endif
 
                .addFunction ("access_action", &PublicEditor::access_action)
+               .addFunction ("set_toggleaction", &PublicEditor::set_toggleaction)
                .endClass ()
 
                /* ArdourUI enums */
@@ -870,7 +930,14 @@ LuaInstance::register_classes (lua_State* L)
                .addConst ("Add", Selection::Operation(Selection::Add))
                .endNamespace ()
 
-               .endNamespace (); // end ArdourUI
+               .endNamespace () // end ArdourUI
+
+               .beginNamespace ("os")
+#ifndef PLATFORM_WINDOWS
+               .addFunction ("execute", &lua_exec)
+#endif
+               .addCFunction ("forkexec", &lua_forkexec)
+               .endNamespace ();
 
        // Editing Symbols
 
@@ -907,7 +974,9 @@ using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace std;
 
-static void _lua_print (std::string s) {
+void
+LuaInstance::_lua_print (std::string s)
+{
 #ifndef NDEBUG
        std::cout << "LuaInstance: " << s << "\n";
 #endif
@@ -958,6 +1027,7 @@ LuaInstance::~LuaInstance ()
 void
 LuaInstance::init ()
 {
+       lua.sandbox (false);
        lua.do_command (
                        "function ScriptManager ()"
                        "  local self = { scripts = {}, instances = {}, icons = {} }"
@@ -975,7 +1045,7 @@ LuaInstance::init ()
                        "   assert(type(f) == 'function', 'Factory is a not a function')"
                        "   assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
                        "   self.scripts[i] = { ['n'] = n, ['s'] = s, ['f'] = f, ['a'] = a, ['c'] = c }"
-                       "   local env = _ENV;  env.f = nil env.debug = nil os.exit = nil require = nil dofile = nil loadfile = nil package = nil"
+                       "   local env = _ENV; env.f = nil env.io = nil"
                        "   self.instances[i] = load (string.dump(f, true), nil, nil, env)(a)"
                        "   if type(c) == 'function' then"
                        "     self.icons[i] = load (string.dump(c, true), nil, nil, env)(a)"
@@ -1076,7 +1146,6 @@ LuaInstance::init ()
                        " manager = ScriptManager ()"
                        " ScriptManager = nil"
                        );
-
        lua_State* L = lua.getState();
 
        try {
@@ -1101,6 +1170,7 @@ LuaInstance::init ()
        }
 
        register_classes (L);
+       register_hooks (L);
 
        luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
        lua_setglobal (L, "Editor");
@@ -1120,6 +1190,7 @@ void LuaInstance::set_session (Session* s)
                i->second->set_session (s);
        }
        point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, & LuaInstance::every_point_one_seconds));
+       SetSession (); /* EMIT SIGNAL */
 }
 
 void
@@ -1473,6 +1544,7 @@ LuaInstance::register_lua_slot (const std::string& name, const std::string& scri
        try {
                LuaState l;
                l.Print.connect (&_lua_print);
+               l.sandbox (true);
                lua_State* L = l.getState();
                register_hooks (L);
                l.do_command ("function ardour () end");
@@ -1678,7 +1750,8 @@ LuaCallback::get_state (void)
 void
 LuaCallback::init (void)
 {
-       lua.Print.connect (&_lua_print);
+       lua.Print.connect (&LuaInstance::_lua_print);
+       lua.sandbox (false);
 
        lua.do_command (
                        "function ScriptManager ()"
@@ -1690,7 +1763,7 @@ LuaCallback::init (void)
                        "   assert(type(f) == 'function', 'Factory is a not a function')"
                        "   assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
                        "   self.script = { ['n'] = n, ['s'] = s, ['f'] = f, ['a'] = a }"
-                       "   local env = _ENV;  env.f = nil env.debug = nil os.exit = nil require = nil dofile = nil loadfile = nil package = nil"
+                       "   local env = _ENV; env.f = nil env.io = nil"
                        "   self.instance = load (string.dump(f, true), nil, nil, env)(a)"
                        "  end"
                        ""
@@ -1795,6 +1868,7 @@ LuaCallback::init (void)
        }
 
        LuaInstance::register_classes (L);
+       LuaInstance::register_hooks (L);
 
        luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
        lua_setglobal (L, "Editor");