*
*/
#include <cstring>
+#include <glibmm.h>
#include "pbd/error.h"
#include "pbd/file_utils.h"
#include "pbd/compose.h"
+#include "ardour/directory_names.h"
+#include "ardour/filesystem_paths.h"
#include "ardour/luascripting.h"
+#include "ardour/lua_script_params.h"
#include "ardour/search_paths.h"
#include "lua/luastate.h"
#include "LuaBridge/LuaBridge.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
+#include "sha1.c"
using namespace ARDOUR;
using namespace PBD;
, _sl_session (0)
, _sl_hook (0)
, _sl_action (0)
+ , _sl_snippet (0)
+ , _sl_setup (0)
+ , _sl_tracks (0)
{
;
}
delete _sl_session;
delete _sl_hook;
delete _sl_action;
+ delete _sl_snippet;
+ delete _sl_setup;
+ delete _sl_tracks;
}
}
-void
-LuaScripting::check_scan ()
-{
- if (!_sl_dsp || !_sl_session || !_sl_hook || !_sl_action) {
- scan ();
- }
-}
void
-LuaScripting::refresh ()
+LuaScripting::refresh (bool run_scan)
{
- Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
-
- if (!lm.locked()) {
- return;
- }
+ Glib::Threads::Mutex::Lock lm (_lock);
delete _sl_dsp;
delete _sl_session;
delete _sl_hook;
delete _sl_action;
+ delete _sl_snippet;
+ delete _sl_setup;
+ delete _sl_tracks;
_sl_dsp = 0;
_sl_session = 0;
_sl_hook = 0;
_sl_action = 0;
+ _sl_snippet = 0;
+ _sl_setup = 0;
+ _sl_tracks = 0;
+
+ if (run_scan) {
+ lm.release ();
+ scan ();
+ }
}
struct ScriptSorter {
}
};
+LuaScriptInfoPtr
+LuaScripting::script_info (const std::string &script) {
+ return scan_script ("", script);
+}
+
void
LuaScripting::scan ()
{
- Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
-
- if (!lm.locked()) {
- return;
- }
+ Glib::Threads::Mutex::Lock lm (_lock);
#define CLEAR_OR_NEW(LIST) \
if (LIST) { LIST->clear (); } else { LIST = new LuaScriptList (); }
CLEAR_OR_NEW (_sl_session)
CLEAR_OR_NEW (_sl_hook)
CLEAR_OR_NEW (_sl_action)
+ CLEAR_OR_NEW (_sl_snippet)
+ CLEAR_OR_NEW (_sl_setup)
+ CLEAR_OR_NEW (_sl_tracks)
#undef CLEAR_OR_NEW
case LuaScriptInfo::EditorAction:
_sl_action->push_back(lsi);
break;
+ case LuaScriptInfo::Snippet:
+ _sl_snippet->push_back(lsi);
+ break;
+ case LuaScriptInfo::SessionInit:
+ _sl_setup->push_back(lsi);
+ break;
default:
break;
}
std::sort (_sl_session->begin(), _sl_session->end(), ScriptSorter());
std::sort (_sl_hook->begin(), _sl_hook->end(), ScriptSorter());
std::sort (_sl_action->begin(), _sl_action->end(), ScriptSorter());
+ std::sort (_sl_snippet->begin(), _sl_snippet->end(), ScriptSorter());
+ std::sort (_sl_setup->begin(), _sl_setup->end(), ScriptSorter());
+ std::sort (_sl_tracks->begin(), _sl_tracks->end(), ScriptSorter());
+ scripts_changed (); /* EMIT SIGNAL */
}
void
lua_State* L = lua.getState();
lua.Print.connect (&LuaScripting::lua_print);
-
- lua.do_command ("io = nil;");
+ lua.sandbox (true);
lua.do_command (
"ardourluainfo = {}"
"function ardour (entry)"
" ardourluainfo['type'] = assert(entry['type'])"
" ardourluainfo['name'] = assert(entry['name'])"
+ " ardourluainfo['category'] = entry['category'] or 'Unknown'"
" ardourluainfo['author'] = entry['author'] or 'Unknown'"
" ardourluainfo['license'] = entry['license'] or ''"
" ardourluainfo['description'] = entry['description'] or ''"
err = lua.do_file (fn);
}
if (err) {
+#ifndef NDEBUG
+ cerr << "failed to load lua script\n";
+#endif
return LuaScriptInfoPtr();
}
} catch (...) { // luabridge::LuaException
+#ifndef NDEBUG
+ cerr << "failed to parse lua script\n";
+#endif
return LuaScriptInfoPtr();
}
luabridge::LuaRef nfo = luabridge::getGlobal (L, "ardourluainfo");
if (nfo.type() != LUA_TTABLE) {
+#ifndef NDEBUG
+ cerr << "failed to get ardour{} table from script\n";
+#endif
return LuaScriptInfoPtr();
}
if (nfo["name"].type() != LUA_TSTRING || nfo["type"].type() != LUA_TSTRING) {
+#ifndef NDEBUG
+ cerr << "script-type or script-name is not a string\n";
+#endif
return LuaScriptInfoPtr();
}
LuaScriptInfo::ScriptType type = LuaScriptInfo::str2type (nfo["type"].cast<std::string>());
if (name.empty() || type == LuaScriptInfo::Invalid) {
+#ifndef NDEBUG
+ cerr << "invalid script-type or missing script name\n";
+#endif
return LuaScriptInfoPtr();
}
- LuaScriptInfoPtr lsi (new LuaScriptInfo (type, name, fn));
+ char hash[41];
+ Sha1Digest s;
+ sha1_init (&s);
+
+ if (fn.empty()) {
+ sha1_write (&s, (const uint8_t *) sc.c_str(), sc.size ());
+ } else {
+ try {
+ std::string script = Glib::file_get_contents (fn);
+ sha1_write (&s, (const uint8_t *) script.c_str(), script.size ());
+ } catch (Glib::FileError err) {
+ return LuaScriptInfoPtr();
+ }
+ }
+ sha1_result_hash (&s, hash);
+
+
+ LuaScriptInfoPtr lsi (new LuaScriptInfo (type, name, fn, hash));
for (luabridge::Iterator i(nfo); !i.isNil (); ++i) {
if (!i.key().isString() || !i.value().isString()) {
if (key == "author") { lsi->author = val; }
if (key == "license") { lsi->license = val; }
if (key == "description") { lsi->description = val; }
+ if (key == "category") { lsi->category = val; }
+ }
+
+
+ if (type == LuaScriptInfo::EditorAction) {
+
+ luabridge::LuaRef lua_rs = luabridge::getGlobal (L, "route_setup");
+ if (lua_rs.isFunction ()) {
+ lsi->subtype |= LuaScriptInfo::RouteSetup;
+ }
+
+ luabridge::LuaRef lua_ss = luabridge::getGlobal (L, "session_setup");
+ if (lua_ss.isFunction ()) {
+ try {
+ if (lua_ss () == true) {
+ lsi->subtype |= LuaScriptInfo::SessionSetup;
+ }
+ } catch (...) { }
+ }
+
}
return lsi;
LuaScriptList &
LuaScripting::scripts (LuaScriptInfo::ScriptType type) {
- check_scan();
+
+ if (!_sl_dsp || !_sl_session || !_sl_hook || !_sl_action || !_sl_snippet || ! _sl_setup || ! _sl_tracks) {
+ scan ();
+ }
switch (type) {
case LuaScriptInfo::DSP:
case LuaScriptInfo::EditorAction:
return *_sl_action;
break;
+ case LuaScriptInfo::Snippet:
+ return *_sl_snippet;
+ break;
+ case LuaScriptInfo::SessionInit:
+ return *_sl_setup;
+ break;
default:
- return _empty_script_info;
break;
}
+ return _empty_script_info; // make some compilers happy
}
case LuaScriptInfo::Session: return "Session";
case LuaScriptInfo::EditorHook: return "EditorHook";
case LuaScriptInfo::EditorAction: return "EditorAction";
+ case LuaScriptInfo::Snippet: return "Snippet";
+ case LuaScriptInfo::SessionInit: return "SessionInit";
default: return "Invalid";
}
}
if (!strcasecmp (type, "Session")) {return LuaScriptInfo::Session;}
if (!strcasecmp (type, "EditorHook")) {return LuaScriptInfo::EditorHook;}
if (!strcasecmp (type, "EditorAction")) {return LuaScriptInfo::EditorAction;}
+ if (!strcasecmp (type, "Snippet")) {return LuaScriptInfo::Snippet;}
+ if (!strcasecmp (type, "SessionInit")) {return LuaScriptInfo::SessionInit;}
return LuaScriptInfo::Invalid;
}
LuaScriptParamList
-LuaScripting::script_params (LuaScriptInfoPtr lsi, const std::string &fn)
+LuaScriptParams::script_params (const LuaScriptInfoPtr& lsi, const std::string &pname)
{
- LuaScriptParamList rv;
assert (lsi);
+ return LuaScriptParams::script_params (lsi->path, pname);
+}
+
+LuaScriptParamList
+LuaScriptParams::script_params (const std::string& s, const std::string &pname, bool file)
+{
+ LuaScriptParamList rv;
LuaState lua;
lua_State* L = lua.getState();
- lua.Print.connect (&LuaScripting::lua_print);
- lua.do_command ("io = nil;");
+ lua.sandbox (true);
lua.do_command ("function ardour () end");
try {
- lua.do_file (lsi->path);
- } catch (luabridge::LuaException const& e) {
+ if (file) {
+ lua.do_file (s);
+ } else {
+ lua.do_command (s);
+ }
+ } catch (...) {
return rv;
}
- luabridge::LuaRef lua_params = luabridge::getGlobal (L, fn.c_str());
+ luabridge::LuaRef lua_params = luabridge::getGlobal (L, pname.c_str());
if (lua_params.isFunction ()) {
luabridge::LuaRef params = lua_params ();
if (params.isTable ()) {
return rv;
}
+void
+LuaScriptParams::params_to_ref (luabridge::LuaRef *tbl_args, const LuaScriptParamList& args)
+{
+ assert (tbl_args && (*tbl_args).isTable ());
+ for (LuaScriptParamList::const_iterator i = args.begin(); i != args.end(); ++i) {
+ if ((*i)->optional && !(*i)->is_set) { continue; }
+ (*tbl_args)[(*i)->name] = (*i)->value;
+ }
+}
+
+void
+LuaScriptParams::ref_to_params (LuaScriptParamList& args, luabridge::LuaRef *tbl_ref)
+{
+ assert (tbl_ref && (*tbl_ref).isTable ());
+ for (luabridge::Iterator i (*tbl_ref); !i.isNil (); ++i) {
+ if (!i.key ().isString ()) { assert(0); continue; }
+ std::string name = i.key ().cast<std::string> ();
+ std::string value = i.value ().cast<std::string> ();
+ for (LuaScriptParamList::const_iterator ii = args.begin(); ii != args.end(); ++ii) {
+ if ((*ii)->name == name) {
+ (*ii)->value = value;
+ break;
+ }
+ }
+ }
+}
+
bool
LuaScripting::try_compile (const std::string& script, const LuaScriptParamList& args)
{
return false;
}
LuaState l;
+ l.Print.connect (&LuaScripting::lua_print);
+ l.sandbox (true);
lua_State* L = l.getState();
l.do_command (""
" function checkfactory (b, a)"
" assert(type(b) == 'string', 'ByteCode must be string')"
- " load(b)()"
+ " load(b)()" // assigns f
" assert(type(f) == 'string', 'Assigned ByteCode must be string')"
- " local env = _ENV; env.f = nil env.debug = nil os.exit = nil"
- " load (string.dump(f, true), nil, nil, env)(a)"
+ " local factory = load(f)"
+ " assert(type(factory) == 'function', 'Factory is a not a function')"
+ " local env = _ENV; env.f = nil env.os = nil env.io = nil"
+ " load (string.dump(factory, true), nil, nil, env)(a)"
" end"
);
luabridge::LuaRef lua_test = luabridge::getGlobal (L, "checkfactory");
l.do_command ("checkfactory = nil"); // hide it.
l.do_command ("collectgarbage()");
- lua_test (bytecode);
+
+ luabridge::LuaRef tbl_arg (luabridge::newTable(L));
+ LuaScriptParams::params_to_ref (&tbl_arg, args);
+ lua_test (bytecode, tbl_arg);
return true; // OK
- } catch (luabridge::LuaException const& e) { }
+ } catch (luabridge::LuaException const& e) {
+#ifndef NDEBUG
+ cerr << e.what() << "\n";
+#endif
+ lua_print (e.what());
+ } catch (...) { }
return false;
}
std::string
-LuaScripting::get_factory_bytecode (const std::string& script)
+LuaScripting::get_factory_bytecode (const std::string& script, const std::string& ffn, const std::string& fp)
{
LuaState l;
l.Print.connect (&LuaScripting::lua_print);
+ l.sandbox (true);
lua_State* L = l.getState();
l.do_command (
""
" function dump_function (f)"
" assert(type(f) == 'function', 'Factory is a not a function')"
- " return string.format(\"f = %q\", string.dump(f, true))"
+ " return string.format(\"" + fp + " = %q\", string.dump(f, true))"
" end"
);
luabridge::LuaRef lua_dump = luabridge::getGlobal (L, "dump_function");
l.do_command ("dump_function = nil"); // hide it
l.do_command (script); // register "factory"
- luabridge::LuaRef lua_factory = luabridge::getGlobal (L, "factory");
+ luabridge::LuaRef lua_factory = luabridge::getGlobal (L, ffn.c_str());
if (lua_factory.isFunction()) {
return (lua_dump(lua_factory)).cast<std::string> ();
}
- } catch (luabridge::LuaException const& e) { }
+ } catch (...) { }
return "";
}
+
+std::string
+LuaScripting::user_script_dir ()
+{
+ std::string dir = Glib::build_filename (user_config_directory(), lua_dir_name);
+ g_mkdir_with_parents (dir.c_str(), 0744);
+ return dir;
+}