lua-bindings: added support for evaluating Lua from the console.
authorKrisztian Litkey <kli@iki.fi>
Tue, 6 Nov 2012 20:32:07 +0000 (22:32 +0200)
committerKrisztian Litkey <kli@iki.fi>
Tue, 6 Nov 2012 20:46:49 +0000 (22:46 +0200)
You can now evaluate Lua code snippets or Lua files from the console.
Please note that currently you need to fully quote Lua code you enter
via the console to protect it from the console input tokenizer. This
limitation will be lifted once we have implemented support for non-
pre-tokenized console commands.

Also note that all output produced by Lua code is currently going to
the standard output of the murphy daemon and not to the console where
you entered the Lua snippet. Consider this a bug which should be fixed.
Fixing this is a bit harder that it was with the old ohm-time console
implementation. In all its crudeness (whenever 'grabbed') the old ohm
console was simply dup2ing stdout to the socket fd of the console
connection during the execution of console commands. With our current
console things this is not so easy: we have mrp_console_printf to print
to the console which is not fd-based but is using glibc's custom stream
handler support...

src/Makefile.am
src/core/lua-bindings/lua-console.c [new file with mode: 0644]

index 0b157e5..ddb3629 100644 (file)
@@ -109,7 +109,8 @@ pkgconfig_DATA  += core/murphy-core.pc
 LUA_BINDINGS_SOURCES =                                 \
                core/lua-bindings/lua-murphy.c  \
                core/lua-bindings/lua-plugin.c  \
-               core/lua-bindings/lua-log.c
+               core/lua-bindings/lua-log.c     \
+               core/lua-bindings/lua-console.c
 
 LUA_BINDINGS_HDRS = core/lua-bindings/murphy.h
 
diff --git a/src/core/lua-bindings/lua-console.c b/src/core/lua-bindings/lua-console.c
new file mode 100644 (file)
index 0000000..ec0babe
--- /dev/null
@@ -0,0 +1,125 @@
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <alloca.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <murphy/core/console.h>
+#include <murphy/core/lua-bindings/murphy.h>
+
+static void eval_cb(mrp_console_t *c, void *user_data, int argc, char **argv)
+{
+    lua_State *L;
+    char       code[1024], *p;
+    int        i, n, l, len;
+
+    MRP_UNUSED(user_data);
+
+    L = mrp_lua_get_lua_state();
+
+    if (L == NULL) {
+        mrp_console_printf(c, "Lua runtime not available or initialized.");
+        return;
+    }
+
+    p   = code;
+    l   = sizeof(code);
+    len = 0;
+    for (i = 2; i < argc; i++) {
+        n = snprintf(p, l, "%s", argv[i]);
+
+        if (n >= l)
+            return;
+
+        l   -= n;
+        p   += n;
+        len += n;
+    }
+
+    if (luaL_loadbuffer(L, code, len, "<console>") || lua_pcall(L, 0, 0, 0))
+        mrp_console_printf(c, "Lua error: %s\n", lua_tostring(L, -1));
+
+    lua_settop(L, 0);
+}
+
+
+static void source_cb(mrp_console_t *c, void *user_data, int argc, char **argv)
+{
+    lua_State   *L;
+    struct stat  st;
+    char        *path, *code;
+    size_t       size;
+    ssize_t      len;
+    int          fd;
+
+    MRP_UNUSED(user_data);
+
+    if (argc != 3) {
+        mrp_console_printf(c, "Invalid arguments, expecting a single path.");
+        return;
+    }
+    else
+        path = argv[2];
+
+    L = mrp_lua_get_lua_state();
+
+    if (L == NULL) {
+        mrp_console_printf(c, "Lua runtime not available or initialized.");
+        return;
+    }
+
+    if (path && *path) {
+        if (stat(path, &st) == 0) {
+            fd = open(path, O_RDONLY);
+
+            if (fd >= 0) {
+                size = st.st_size;
+                code = alloca(size);
+                len  = read(fd, code, size);
+                close(fd);
+
+                if (len > 0) {
+                    if (luaL_loadbuffer(L, code, len, path) != 0 ||
+                        lua_pcall(L, 0, 0, 0) != 0)
+                        mrp_console_printf(c, "Lua error: %s\n",
+                                           lua_tostring(L, -1));
+
+                    lua_settop(L, 0);
+                }
+            }
+            else
+                mrp_console_printf(c, "Failed to open %s (%d: %s).", path,
+                                   errno, strerror(errno));
+        }
+        else
+            mrp_console_printf(c, "Failed to open %s (%d: %s).", path,
+                               errno, strerror(errno));
+    }
+}
+
+
+#define LUA_GROUP_DESCRIPTION                                    \
+    "Lua commands allows one to evaluate Lua code either from\n" \
+    "the console command line itself, or from sourced files.\n"
+
+#define EVAL_SYNTAX      "eval <lua-code>"
+#define EVAL_SUMMARY     "evaluate the given snippet of Lua code"
+#define EVAL_DESCRIPTION                                               \
+    "Evaluate the given snippet of Lua code. Currently you have to\n"  \
+    "fully quote the Lua code you are trying to evaluate to protect\n" \
+    "it from the tokenizer of the console input parser. This is the\n" \
+    "easiest to accomplish by surrounding your Lua code snippet in\n"  \
+    "single or double quotes unconditionally.\n"
+
+#define SOURCE_SYNTAX      "source <lua-file>"
+#define SOURCE_SUMMARY     "evaluate the Lua script from the given <lua-file>"
+#define SOURCE_DESCRIPTION "Read and evaluate the contents of <lua-file>.\n"
+
+MRP_CORE_CONSOLE_GROUP(lua_group, "lua", LUA_GROUP_DESCRIPTION, NULL, {
+        MRP_TOKENIZED_CMD("eval", eval_cb, TRUE,
+                          EVAL_SYNTAX, EVAL_SUMMARY, EVAL_DESCRIPTION),
+        MRP_TOKENIZED_CMD("source", source_cb, FALSE,
+                          SOURCE_SYNTAX, SOURCE_SUMMARY, SOURCE_DESCRIPTION),
+    });