Browse Source

Initial import of Lua plugin. Currently clish_plugin_lua_la_LDFLAGS and clish_plugin_lua_la_CFLAGS need to be specified manually in plugins/lua/module.am in order to build successfully. Once built - set CLISH_PATH to xml-examples/lua and start klish. You'll have all the commands as in xml-examples/test interpreted by Lua and, in addition, commands test8 (calls a lua function defined in test.lua), eval (can evaluate any string parameter as a Lua chunk) and test9 (an alias for eval)

Stanislav Galabov 11 years ago
parent
commit
3fbc9fdd98

+ 2 - 0
Makefile.am

@@ -23,6 +23,7 @@ EXTRA_DIST = \
 	lub/module.am \
 	tinyrl/module.am \
 	konf/module.am \
+	plugins/module.am \
 	contrib \
 	xml-examples \
 	debian \
@@ -37,3 +38,4 @@ include $(top_srcdir)/tinyrl/module.am
 include $(top_srcdir)/konf/module.am
 include $(top_srcdir)/clish/module.am
 include $(top_srcdir)/bin/module.am
+include $(top_srcdir)/plugins/module.am

BIN
plugins/lua/.module.am.swp


+ 16 - 0
plugins/lua/hook.h

@@ -0,0 +1,16 @@
+#ifndef _HOOK_H_
+#define _HOOK_H_
+
+#include <clish/shell.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#define LUA_UDATA	"lua state"
+
+void l_print_error(lua_State *, const char *, const char *, int);
+
+#include "hook_spec.h"
+
+#endif /* _HOOK_H_ */

+ 29 - 0
plugins/lua/hook_action.c

@@ -0,0 +1,29 @@
+#include <lub/string.h>
+
+#include "hook.h"
+
+CLISH_PLUGIN_SYM(clish_plugin_hook_action)
+{
+	clish_context_t *context = (clish_context_t *) clish_context;
+	lua_State *L = clish_shell__get_udata(context->shell, LUA_UDATA);
+
+	int res = 0, result = -1;
+
+	if (!script) /* Nothing to do */
+		return (0);
+
+	if (out)
+		*out = NULL; /* Does not work for now */
+
+	if ((res = luaL_loadstring(L, script))) {
+		l_print_error(L, __func__, "load", res);
+	} else if ((res = lua_pcall(L, 0, 0, 0))) {
+		l_print_error(L, __func__, "exec", res);
+	} else {
+		result = 0;
+	}
+
+	lua_gc(L, LUA_GCCOLLECT, 0);
+
+	return (result);
+}

+ 13 - 0
plugins/lua/hook_fini.c

@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+#include "hook.h"
+
+CLISH_HOOK_FINI(clish_plugin_hook_fini)
+{
+	clish_context_t *context = (clish_context_t *) clish_context;
+	lua_State *L = clish_shell__del_udata(context->shell, LUA_UDATA);
+
+	lua_close(L);
+
+	return (0);
+}

+ 90 - 0
plugins/lua/hook_init.c

@@ -0,0 +1,90 @@
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lub/string.h>
+
+#include "hook.h"
+
+static bool_t
+load_scripts(lua_State *L, char *path)
+{
+	struct dirent *entry;
+	DIR *dir = opendir(path);
+	bool_t result = BOOL_FALSE;
+	int res = 0;
+
+	const char *ext_lua = ".lua";
+	const char *ext_bin = ".bin";
+
+	if (!dir) {
+		printf("%s: Failed to open '%s' directory\n", __func__, path);
+		return BOOL_FALSE;
+	}
+
+	for (entry = readdir(dir); entry; entry = readdir(dir)) {
+		const char *extension = strrchr(entry->d_name, '.');
+		/* check the filename */
+		if ((extension) &&
+		    ((!strcmp(ext_lua, extension)) ||
+		     (!strcmp(ext_bin, extension)))) {
+			char *filename = NULL;
+			lub_string_cat(&filename, path);
+			lub_string_cat(&filename, "/");
+			lub_string_cat(&filename, entry->d_name);
+
+			result = BOOL_FALSE;
+			if ((res = luaL_loadfile(L, filename))) {
+				l_print_error(L, __func__, "load", res);
+			} else if ((res = lua_pcall(L, 0, 0, 0))) {
+				l_print_error(L, __func__, "exec", res);
+			} else
+				result = BOOL_TRUE;
+
+			lub_string_free(filename);
+
+			/* Shouldn't happen, but we can't be too sure ;-) */
+			while(lua_gettop(L))
+				lua_pop(L, 1);
+
+			if (!result)
+				break;
+		}
+	}
+
+	closedir(dir);
+
+	return result;
+}
+
+CLISH_HOOK_INIT(clish_plugin_hook_init)
+{
+	clish_context_t *context = (clish_context_t *) clish_context;
+	clish_shell_t *shell = (clish_shell_t *) context->shell;
+	lua_State *L = NULL;
+	char *scripts_path = getenv("CLISH_SCRIPTS_PATH");
+
+	if (!scripts_path)
+		if(!(scripts_path = getenv("CLISH_PATH"))) {
+			printf("%s: Lua scripts dir not specified\n", __func__);
+			return (-1);
+		}
+
+	if (!(L = luaL_newstate())) {
+		printf("%s: Failed to instantiate Lua interpreter\n", __func__);
+		return (-1);
+	}
+
+	luaL_openlibs(L);
+
+	if (!load_scripts(L, scripts_path)) {
+		return (-1);
+	}
+
+	clish_shell__set_udata(shell, LUA_UDATA, L);
+
+	lua_pushlightuserdata(L, shell);
+	lua_setglobal(L, "clish_shell");
+
+	return (0);
+}

+ 8 - 0
plugins/lua/hook_spec.h

@@ -0,0 +1,8 @@
+#ifndef _HOOK_SPEC_H_
+#define _HOOK_SPEC_H
+
+CLISH_HOOK_INIT(clish_plugin_hook_init);
+CLISH_HOOK_FINI(clish_plugin_hook_fini);
+CLISH_PLUGIN_SYM(clish_plugin_hook_action);
+
+#endif /* _HOOK_SPEC_H_ */

+ 28 - 0
plugins/lua/lua_print_error.c

@@ -0,0 +1,28 @@
+#include "hook.h"
+
+void
+l_print_error(lua_State *L, const char *func, const char *when, int res)
+{
+	switch (res) {
+		case LUA_ERRRUN:
+			printf("%s (%s):\n%s\n", func, when,
+					lua_tostring(L, -1));
+			break;
+		case LUA_ERRSYNTAX:
+			printf("%s (%s):\n%s\n", func, when,
+					lua_tostring(L, -1));
+			break;
+		case LUA_ERRMEM:
+			printf("%s (%s):\nmem alloc error\n", func, when);
+			break;
+		case LUA_ERRERR:
+			printf("%s (%s):\nerror handler error\n", func, when);
+			break;
+		case LUA_ERRFILE:
+			printf("%s (%s):\ncouldn't open file\n", func, when);
+			break;
+		default:
+			printf("%s (%s):\nunknown error\n", func, when);
+			break;
+	}
+}

+ 27 - 0
plugins/lua/module.am

@@ -0,0 +1,27 @@
+lib_LTLIBRARIES			+= clish_plugin_lua.la
+clish_plugin_lua_la_SOURCES	 = 
+clish_plugin_lua_la_LIBADD	 =
+clish_plugin_lua_la_LDFLAGS	 = -avoid-version -module -shared
+clish_plugin_lua_la_LDFLAGS	+= -export-symbols-regex '^clish_plugin_.*'
+
+clish_plugin_lua_la_LDFLAGS	+= -L/usr/local/lib -llua-5.1
+clish_plugin_lua_la_CFLAGS	 = -I/usr/local/include/lua51
+
+clish_plugin_lua_la_LIBADD	+= \
+	liblub.la \
+	libclish.la 
+
+clish_plugin_lua_la_DEPENDENCIES = \
+	liblub.la \
+	libclish.la
+
+nobase_include_HEADERS		+= \
+	plugins/lua/hook.h \
+	plugins/lua/hook_spec.h
+
+clish_plugin_lua_la_SOURCES	+= \
+	plugins/lua/plugin_init.c \
+	plugins/lua/hook_init.c \
+	plugins/lua/hook_fini.c \
+	plugins/lua/hook_action.c \
+	plugins/lua/lua_print_error.c

+ 13 - 0
plugins/lua/plugin_init.c

@@ -0,0 +1,13 @@
+#include "hook.h"
+
+CLISH_PLUGIN_INIT
+{
+	clish_plugin_add_phook(plugin, clish_plugin_hook_init, "hook_init",
+			CLISH_SYM_TYPE_INIT);
+	clish_plugin_add_phook(plugin, clish_plugin_hook_fini, "hook_fini",
+			CLISH_SYM_TYPE_FINI);
+	clish_plugin_add_phook(plugin, clish_plugin_hook_action, "hook_action",
+			CLISH_SYM_TYPE_ACTION);
+
+	return 0;
+}

+ 4 - 0
plugins/module.am

@@ -0,0 +1,4 @@
+EXTRA_DIST += \
+	plugins/lua/module.am
+
+include $(top_srcdir)/plugins/lua/module.am

+ 18 - 0
xml-examples/lua/startup.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CLISH_MODULE xmlns="http://clish.sourceforge.net/XMLSchema" 
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+ xsi:schemaLocation="http://clish.sourceforge.net/XMLSchema
+                     http://clish.sourceforge.net/XMLSchema/clish.xsd">
+
+	<PLUGIN name="lua_hooks" file="clish_plugin_lua.so"/>
+
+	<HOOK name="init" builtin="hook_init@lua_hooks"/>
+	<HOOK name="fini" builtin="hook_fini@lua_hooks"/>
+
+	<!--
+	<STARTUP view="test-view"/>
+	-->
+	<STARTUP view="test-view" default_builtin="hook_action@lua_hooks"/>
+
+</CLISH_MODULE>
+

+ 7 - 0
xml-examples/lua/test.lua

@@ -0,0 +1,7 @@
+echo = print
+
+shell = os.execute
+
+function hello_world()
+	print("Hello world from Lua!")
+end

+ 98 - 0
xml-examples/lua/test.xml

@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CLISH_MODULE xmlns="http://clish.sourceforge.net/XMLSchema" 
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+ xsi:schemaLocation="http://clish.sourceforge.net/XMLSchema
+                     http://clish.sourceforge.net/XMLSchema/clish.xsd">
+	<!--=======================================================-->
+
+<PTYPE name="STRING" pattern=".+" help="String"/>
+
+<VIEW name="test-view"
+	prompt="${SYSTEM_NAME}# ">
+
+	<COMMAND name="exit" help="Exit from the CLI" lock="false">
+		<ACTION builtin="clish_close"/>
+	</COMMAND>
+
+	<COMMAND name="test1" help="" lock="false">
+		<ACTION> echo "Empty attribute" </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test2" help='Single quotes' lock="false">
+		<ACTION> echo "Single quotes" </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test3" help='"Single quotes with nested common quotes"' lock="false">
+		<ACTION> echo "Single quotes with nested common quotes" </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test4" help="'Common quotes with nested single quotes'" lock="false">
+		<ACTION> echo "Common quotes with nested single quotes" </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test5" help="Broken comment. Problem with libroxml.">
+<!-- - '
+-->
+		<PARAM name="test5.param2" help="Help test5.param2" ptype="STRING" optional="true" order="true"/>
+		<ACTION> echo "Broken comment. Problem with libroxml." </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test6" help="Long ACTION. libexpat hangs">
+		<ACTION>
+			shell [[
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+			]]
+		</ACTION>
+	</COMMAND>
+
+	<COMMAND help="The > within attribute value" name="test7" lock="false">
+		<ACTION> echo "The > within attribute value" </ACTION>
+	</COMMAND>
+
+	<COMMAND name="test8" help="Call a Lua function">
+		<ACTION builtin="hook_action@lua_hooks">hello_world()</ACTION>
+	</COMMAND>
+
+	<COMMAND name="eval" help="Evaluate a string as Lua chunk">
+		<PARAM name="str" help="String to evaluate" ptype="STRING"/>
+		<ACTION builtin="hook_action@lua_hooks">
+			loadstring("${str}")()
+		</ACTION>
+	</COMMAND>
+
+	<COMMAND name="test9" ref="eval" help="Alias for the eval command"/>
+
+</VIEW>
+
+</CLISH_MODULE>