add some rudimentary lua support, by having a simple interactive console, and providing access to irc_client_quit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/FindLua51.cmake Tue Mar 31 19:35:51 2009 +0300
@@ -0,0 +1,23 @@
+# Find lua 5.1
+# Once done, this will define:
+#
+# Lua51_FOUND
+# Lua51_INCLUDE_DIRS
+# Lua51_LIBRARIES
+#
+include (LibFindMacros)
+
+# include dir
+find_path (Lua51_INCLUDE_DIR
+ NAMES "lua5.1/lua.h"
+)
+
+# library
+find_library (Lua51_LIBRARY
+ NAMES "lua5.1"
+)
+
+# set the external vars
+set (Lua51_PROCESS_INCLUDES Lua51_INCLUDE_DIR)
+set (Lua51_PROCESS_LIBS Lua51_LIBRARY)
+libfind_process (Lua51)
--- a/src/CMakeLists.txt Tue Mar 31 15:41:24 2009 +0300
+++ b/src/CMakeLists.txt Tue Mar 31 19:35:51 2009 +0300
@@ -3,22 +3,24 @@
find_package (GnuTLS REQUIRED)
find_package (LibPQ REQUIRED)
find_package (Evsql REQUIRED)
+find_package (Lua51 REQUIRED)
# add our include path
-include_directories (${LibEvent_INCLUDE_DIRS} ${GnuTLS_INCLUDE_DIRS} ${Evsql_INCLUDE_DIRS})
+include_directories (${LibEvent_INCLUDE_DIRS} ${GnuTLS_INCLUDE_DIRS} ${Evsql_INCLUDE_DIRS} ${Lua51_INCLUDE_DIRS})
# define our source code modules
set (CORE_SOURCES error.c log.c)
set (SOCK_SOURCES sock.c sock_tcp.c sock_gnutls.c sock_test.c line_proto.c)
set (IRC_SOURCES irc_line.c irc_conn.c irc_net.c irc_chan.c chain.c irc_cmd.c irc_proto.c irc_client.c irc_user.c irc_queue.c)
+set (CONSOLE_SOURCES console.c lua_console.c lua_objs.c)
-set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} signals.c module.c config.c console.c)
+set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} ${CONSOLE_SOURCES} signals.c module.c config.c)
set (TEST_SOURCES test.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES})
set (IRC_LOG_SOURCES irc_log.c)
# define our libraries
set (MODULE_LIBRARIES "dl")
-set (NEXUS_LIBRARIES ${LibEvent_LIBRARIES} ${GnuTLS_LIBRARIES} ${MODULE_LIBRARIES} "readline")
+set (NEXUS_LIBRARIES ${LibEvent_LIBRARIES} ${GnuTLS_LIBRARIES} ${MODULE_LIBRARIES} "readline" ${Lua51_LIBRARIES})
# compiler flags
set (CFLAGS "-Wall -Wextra -std=gnu99")
--- a/src/console.c Tue Mar 31 15:41:24 2009 +0300
+++ b/src/console.c Tue Mar 31 19:35:51 2009 +0300
@@ -1,5 +1,6 @@
#include "console.h"
+#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <readline/readline.h>
@@ -30,8 +31,14 @@
{
struct console *console = &_console;
+ // XXX: EOF?
+
// invoke the console callback
- console->callbacks->on_line(line, console->cb_arg);
+ if (console->callbacks && console->callbacks->on_line)
+ console->callbacks->on_line(line, console->cb_arg);
+
+ // release the line
+ free(line);
}
err_t console_init (struct console **console_ptr, struct event_base *ev_base, const struct console_config *config,
@@ -42,9 +49,9 @@
// check it's not already initialized
assert(!console->initialized);
- // store
- console->callbacks = callbacks;
- console->cb_arg = cb_arg;
+ // store callbacks?
+ if (callbacks)
+ console_set_callbacks(console, callbacks, cb_arg);
// setup the input event
if ((console->ev = event_new(ev_base, STDIN_FILENO, EV_READ | EV_PERSIST, &console_input, console)) == NULL)
@@ -71,6 +78,12 @@
return ERROR_CODE(err);
}
+void console_set_callbacks (struct console *console, const struct console_callbacks *callbacks, void *cb_arg)
+{
+ console->callbacks = callbacks;
+ console->cb_arg = cb_arg;
+}
+
void console_destroy (struct console *console)
{
// remove the input event
--- a/src/console.h Tue Mar 31 15:41:24 2009 +0300
+++ b/src/console.h Tue Mar 31 19:35:51 2009 +0300
@@ -19,8 +19,12 @@
* Callbacks for event-based actions
*/
struct console_callbacks {
- /** A line was read from the console */
- void (*on_line) (char *line, void *arg);
+ /**
+ * A line was read from the console.
+ *
+ * XXX: currently, line might be NULL on EOF, but this is probably a second callback
+ */
+ void (*on_line) (const char *line, void *arg);
};
/**
@@ -32,7 +36,9 @@
};
/**
- * The console state...
+ * The console state.
+ *
+ * You may replace the callbacks/cb_arg field with a new one at any time, using console_set_callbacks().
*/
struct console {
/** The input event */
@@ -49,12 +55,24 @@
};
/**
- * Initialize the console, setting up the TTY and input handler
+ * Initialize the console, setting up the TTY and input handler.
+ *
+ * @param console_ptr returned new console struct
+ * @param ev_base the libevent base to use
+ * @param config configuration things for the console
+ * @param callbacks optional callbacks, can be updated later
+ * @param cb_arg option callback argument, can be updated later
+ * @param err returned error info
*/
err_t console_init (struct console **console_ptr, struct event_base *ev_base, const struct console_config *config,
const struct console_callbacks *callbacks, void *cb_arg, struct error_info *err);
/**
+ * Replace the current callbacks with the given new ones.
+ */
+void console_set_callbacks (struct console *console, const struct console_callbacks *callbacks, void *cb_arg);
+
+/**
* Deinitialize the console, restoring the TTY and releasing resources
*/
void console_destroy (struct console *console);
--- a/src/error.h Tue Mar 31 15:41:24 2009 +0300
+++ b/src/error.h Tue Mar 31 19:35:51 2009 +0300
@@ -89,6 +89,11 @@
/** config errors */
_ERR_CONFIG = 0x000b00,
ERR_CONFIG_NAME,
+
+ /** lua errors */
+ _ERR_LUA = 0x000c00,
+ ERR_LUA_MEM,
+ ERR_LUA_SYNTAX,
/** General errors */
_ERR_GENERAL = 0xffff00,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lua_console.c Tue Mar 31 19:35:51 2009 +0300
@@ -0,0 +1,112 @@
+#include "lua_console.h"
+#include "lua_objs.h"
+#include "log.h"
+
+#include <stdlib.h>
+
+#include <lua5.1/lualib.h>
+#include <lua5.1/lauxlib.h>
+
+static void lua_console_on_line (const char *line, void *arg)
+{
+ struct lua_console *lc = arg;
+ lua_State *L = lc->st;
+ int ret;
+
+ // ignore empty lines and EOF
+ if (!line || !(*line))
+ return;
+
+ // load the line as a lua function
+ if ((ret = luaL_loadstring(L, line)))
+ goto error;
+
+ // execute it
+ if ((ret = lua_pcall(L, 0, 0, 0)))
+ goto error;
+
+ // XXX: display results?
+
+error:
+ if (ret) {
+ const char *error = lua_tostring(L, -1);
+
+ switch (ret) {
+ case LUA_ERRSYNTAX:
+ log_error("syntax error: %s", error);
+ break;
+
+ case LUA_ERRRUN:
+ log_error("runtime error: %s", error);
+ break;
+
+ case LUA_ERRMEM:
+ log_error("memory allocation error: %s", error);
+ break;
+
+ case LUA_ERRERR:
+ log_error("error handling error: %s", error);
+ break;
+
+ default:
+ log_error("unknown error: %s", error);
+ break;
+ };
+
+ lua_pop(L, 1);
+ }
+}
+
+static struct console_callbacks _console_callbacks = {
+ .on_line = &lua_console_on_line,
+};
+
+err_t lua_console_create (struct lua_console **lc_ptr, struct console *console, struct nexus *nexus, struct error_info *err)
+{
+ struct lua_console *lc;
+
+ // allocate
+ if ((lc = calloc(1, sizeof(*lc))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
+
+ // store
+ lc->console = console;
+
+ // set our console callbacks
+ console_set_callbacks(console, &_console_callbacks, lc);
+
+ // create the lua state
+ if ((lc->st = luaL_newstate()) == NULL)
+ JUMP_SET_ERROR(err, ERR_LUA_MEM);
+
+ // we can then load the core libs
+ // XXX: we don't need all of these
+ // XXX: errors?
+ luaL_openlibs(lc->st);
+
+ // then our own things
+ if ((ERROR_CODE(err) = lua_objs_init(lc->st, nexus)))
+ goto error;
+
+ // ok
+ *lc_ptr = lc;
+
+ return SUCCESS;
+
+error:
+ // destroy
+ lua_console_destroy(lc);
+
+ return ERROR_CODE(err);
+}
+
+void lua_console_destroy (struct lua_console *lc)
+{
+ // close the lua stuff
+ lua_close(lc->st);
+
+ // and the console
+ console_destroy(lc->console);
+
+ free(lc);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lua_console.h Tue Mar 31 19:35:51 2009 +0300
@@ -0,0 +1,37 @@
+#ifndef LUA_CONSOLE_H
+#define LUA_CONSOLE_H
+
+/**
+ * @file
+ *
+ * An interactive lua console
+ */
+#include "nexus.h"
+#include "console.h"
+
+#include <lua5.1/lua.h>
+
+/**
+ * The lua console state
+ */
+struct lua_console {
+ /** The lowlevel line-based console */
+ struct console *console;
+
+ /** Our lua-state */
+ lua_State *st;
+};
+
+/**
+ * Create a new lua console based on the given low-level console, operating on the given nexus
+ *
+ * This overrides the console callbacks.
+ */
+err_t lua_console_create (struct lua_console **lc_ptr, struct console *console, struct nexus *nexus, struct error_info *err);
+
+/**
+ * Destroy the lua console state
+ */
+void lua_console_destroy (struct lua_console *lc);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lua_objs.c Tue Mar 31 19:35:51 2009 +0300
@@ -0,0 +1,83 @@
+#include "lua_objs.h"
+
+#include <lua5.1/lua.h>
+#include <lua5.1/lualib.h>
+#include <lua5.1/lauxlib.h>
+
+/**
+ * Our lua wrapper for irc_net
+ */
+struct lua_irc_net {
+ struct irc_net *net;
+};
+
+/**
+ * Wrapper for irc_client
+ */
+struct lua_client {
+ struct irc_client *client;
+};
+
+static int lua_client_quit (lua_State *L)
+{
+ struct lua_client *lua_client;
+ err_t err;
+
+ // validate the lua_client arg
+ if ((lua_client = luaL_checkudata(L, 1, "evirc.client")) == NULL)
+ return luaL_argerror(L, 1, "`client` expected");
+
+ // the message
+ const char *message = luaL_checkstring(L, 2);
+
+ // execute
+ if ((err = irc_client_quit(lua_client->client, message)))
+ return luaL_error(L, "irc_client_quit: %s", error_name(err));
+
+ // ok
+ return 0;
+}
+
+static const struct luaL_Reg lua_client_lib[] = {
+ { "quit", &lua_client_quit },
+ { NULL, NULL }
+};
+
+/**
+ * Initializes a lua_irc_client wrapper for the given client in the give lua state. This registers a set of globals for
+ * 'client' and 'networks'.
+ */
+static err_t lua_client_init (lua_State *L, struct irc_client *client)
+{
+ // allocate the global "client" object
+ // XXX: mem errors?
+ struct lua_client *lua_client = lua_newuserdata(L, sizeof(*client));
+
+ // push a new metatable to identify the client object
+ luaL_newmetatable(L, "evirc.client");
+
+ // set the metatable __index to itself
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index");
+
+ // register the methods to the metatable
+ luaL_register(L, NULL, lua_client_lib);
+
+ // set the client userdata's metatable
+ lua_setmetatable(L, -2);
+
+ // initialize it
+ lua_client->client = client;
+
+ // store it as a global
+ lua_setglobal(L, "client");
+
+ // ok
+ return SUCCESS;
+}
+
+err_t lua_objs_init (lua_State *L, struct nexus *nexus)
+{
+ // init the various bits
+ return lua_client_init(L, nexus->client);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lua_objs.h Tue Mar 31 19:35:51 2009 +0300
@@ -0,0 +1,18 @@
+#ifndef LUA_OBJS_H
+#define LUA_OBJS_H
+
+/**
+ * @file
+ *
+ * Defines lua functions to access the various objects in a nexus
+ */
+#include "nexus.h"
+
+#include <lua5.1/lua.h>
+
+/**
+ * Registers our lua runtime objects into the given lua state
+ */
+err_t lua_objs_init (lua_State *L, struct nexus *nexus);
+
+#endif /* LUA_OBJS_H */
--- a/src/nexus.c Tue Mar 31 15:41:24 2009 +0300
+++ b/src/nexus.c Tue Mar 31 19:35:51 2009 +0300
@@ -236,33 +236,27 @@
return SUCCESS;
}
-static void on_line (char *line, void *arg)
-{
- struct nexus *nexus = arg;
-
- (void) nexus;
-
- // just dump it
- log_info("read line from console: '%s'", line);
-}
-
-static struct console_callbacks nexus_console_callbacks = {
- .on_line = &on_line,
-};
-
/**
* Open the console
*/
static err_t apply_console (struct nexus *nexus, struct error_info *err)
{
struct console_config config = {
- .prompt = " > ",
+ .prompt = "> ",
};
log_info("initializing the console");
- // just init it
- return console_init(&nexus->console, nexus->ev_base, &config, &nexus_console_callbacks, nexus, err);
+ // init the console
+ if (console_init(&nexus->console, nexus->ev_base, &config, NULL, NULL, err))
+ return ERROR_CODE(err);
+
+ // create the lua console on top of that
+ if (lua_console_create(&nexus->lua_console, nexus->console, nexus, err))
+ return ERROR_CODE(err);
+
+ // ok
+ return SUCCESS;
}
/**
@@ -335,8 +329,8 @@
log_info("Quitting...");
// destroy the console
- if (ctx->console)
- console_destroy(ctx->console);
+ if (ctx->lua_console)
+ lua_console_destroy(ctx->lua_console);
// unload the modules
modules_unload(ctx->modules);
--- a/src/nexus.h Tue Mar 31 15:41:24 2009 +0300
+++ b/src/nexus.h Tue Mar 31 19:35:51 2009 +0300
@@ -11,6 +11,7 @@
#include <event2/event.h>
#include "signals.h"
#include "console.h"
+#include "lua_console.h"
#include "module.h"
#include "irc_client.h"
@@ -27,6 +28,9 @@
/** Our console */
struct console *console;
+ /** Our lua console */
+ struct lua_console *lua_console;
+
/** Our loaded modules */
struct modules *modules;