# HG changeset patch # User Tero Marttila # Date 1238517351 -10800 # Node ID 42ade8285570ea32352ac0a59bc4b79a29c21ba9 # Parent 99661e5aac91e11a42a683de48c6bdbe3a010a89 add some rudimentary lua support, by having a simple interactive console, and providing access to irc_client_quit diff -r 99661e5aac91 -r 42ade8285570 cmake/Modules/FindLua51.cmake --- /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) diff -r 99661e5aac91 -r 42ade8285570 src/CMakeLists.txt --- 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") diff -r 99661e5aac91 -r 42ade8285570 src/console.c --- 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 #include #include #include @@ -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 diff -r 99661e5aac91 -r 42ade8285570 src/console.h --- 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); diff -r 99661e5aac91 -r 42ade8285570 src/error.h --- 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, diff -r 99661e5aac91 -r 42ade8285570 src/lua_console.c --- /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 + +#include +#include + +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); +} diff -r 99661e5aac91 -r 42ade8285570 src/lua_console.h --- /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 + +/** + * 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 diff -r 99661e5aac91 -r 42ade8285570 src/lua_objs.c --- /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 +#include +#include + +/** + * 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); +} diff -r 99661e5aac91 -r 42ade8285570 src/lua_objs.h --- /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 + +/** + * 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 */ diff -r 99661e5aac91 -r 42ade8285570 src/nexus.c --- 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); diff -r 99661e5aac91 -r 42ade8285570 src/nexus.h --- 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 #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;