--- a/src/console.c Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-#include "console.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-
-#include <signal.h>
-#include <assert.h>
-
-struct console {
- /** Configuration */
- struct console_config config;
-
- /** Input event */
- struct event *ev;
-
- /** Callback functions */
- const struct console_callbacks *callbacks;
-
- /** Callback context argument */
- void *cb_arg;
-
- /** Old SIGINT handler */
- struct sigaction old_sigint;
-
- /** Already initialized? */
- bool initialized;
-
- /** Set as log output function? */
- bool log_output;
-
- /** Prompt displayed? */
- bool have_prompt;
-
- /** Waiting for line to be processed */
- bool waiting;
-};
-
-/** The global console state */
-static struct console _console;
-
-/**
- * Our stdin input handler
- */
-static void console_input (int fd, short what, void *arg)
-{
- struct console *console = arg;
-
- (void) fd;
- (void) what;
-
- if (console->waiting)
- // can't feed readline input while it's disabled
- return log_warn("discrding input while waiting");
-
- else
- // tell readline to process it
- rl_callback_read_char();
-}
-
-/**
- * Our readline line handler
- */
-static void console_line (char *line)
-{
- struct console *console = &_console;
- enum console_line_status status = CONSOLE_CONTINUE;
-
- // special-case EOF
- if (!line) {
- // prettify
- rl_crlf();
- rl_on_new_line();
-
- if (console->callbacks->on_eof)
- console->callbacks->on_eof(console->cb_arg);
-
- return;
- }
-
- // update state for console_print during processing
- console->have_prompt = false;
-
- // invoke the console callback
- if (console->callbacks && console->callbacks->on_line)
- status = console->callbacks->on_line(line, console->cb_arg);
-
- // add to history mechanism
- add_history(line);
-
- // release the line
- free(line);
-
- switch (status) {
- case CONSOLE_CONTINUE:
- // the prompt will be displayed again
- console->have_prompt = true;
-
- break;
-
- case CONSOLE_WAIT:
- // deactivate our read event
- if (event_del(console->ev))
- log_warn("unable to deactivate console read event");
-
- // remove the readline stuff to stop it from displaying the prompt
- rl_callback_handler_remove();
-
- // ignore input
- console->waiting = true;
-
- break;
- }
-}
-static void on_sigint (int sig)
-{
- struct console *console = &_console;
-
- (void) sig;
-
- if (console->waiting) {
- // notify user
- if (console->callbacks->on_interrupt)
- console->callbacks->on_interrupt(console->cb_arg);
-
- } else {
- // interrupt the input line
- // XXX: is this the right function to call?
- rl_free_line_state();
-
- // redisplay on new line
- rl_crlf();
- rl_callback_handler_install(console->config.prompt, console_line);
- }
-}
-
-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, error_t *err)
-{
- struct console *console = &_console;
-
- // check it's not already initialized
- assert(!console->initialized);
-
- // store
- console->config = *config;
-
- // 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)
- JUMP_SET_ERROR(err, ERR_EVENT_NEW);
-
- // set our SIGINT handler
- struct sigaction sigact;
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = on_sigint;
- sigaction(SIGINT, &sigact, &console->old_sigint);
-
- // setup state for initial readline prompt
- console->have_prompt = true;
-
- // setup readline
- rl_callback_handler_install(config->prompt, console_line);
-
- // mark it as initialized
- console->initialized = true;
-
- // enable input
- if (event_add(console->ev, NULL))
- JUMP_SET_ERROR(err, ERR_EVENT_ADD);
-
- // ok
- *console_ptr = console;
-
- return SUCCESS;
-
-error:
- console_destroy(console);
-
- 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_continue (struct console *console)
-{
- if (!console->waiting)
- return;
-
- // re-enable input
- console->waiting = false;
-
- if (event_add(console->ev, NULL))
- log_fatal("unable to re-enable console read event");
-
- // the prompt will be displayed again
- console->have_prompt = true;
-
- // re-setup readline with prompt
- rl_callback_handler_install(console->config.prompt, console_line);
-}
-
-err_t console_print (struct console *console, const char *line)
-{
- if (console->have_prompt)
- // don't interrupt current input line
- rl_crlf();
-
- // output the line
- if (printf("%s\n", line) < 0)
- return _ERR_GENERAL;
-
- if (console->have_prompt) {
- // restore input
- rl_on_new_line();
- rl_redisplay();
- }
-
- // ok
- return SUCCESS;
-}
-
-/**
- * Our log_output_func implementation
- */
-static void console_log_output_func (const char *line, void *_console)
-{
- struct console *console = _console;
-
- console_print(console, line);
-}
-
-void console_set_log_output (struct console *console)
-{
- // replace old one
- log_set_func(console_log_output_func, console);
-
- // mark
- console->log_output = true;
-}
-
-void console_destroy (struct console *console)
-{
- if (console->log_output)
- // unset ourselves as the log handler
- log_set_func(NULL, NULL);
-
- // remove the input event
- if (console->ev)
- event_free(console->ev);
-
- console->ev = NULL;
-
- // de-init rl?
- if (console->initialized)
- rl_callback_handler_remove();
-
- console->initialized = false;
-
- // restore signal handler
- sigaction(SIGINT, &console->old_sigint, NULL);
-
- // remove stored stuff
- console->callbacks = console->cb_arg = NULL;
-}
-
--- a/src/console.h Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-#ifndef CONSOLE_H
-#define CONSOLE_H
-
-/**
- * @file
- *
- * An interactive line-based console interface for runtime configuration.
- *
- * This uses the GNU readline library to implement the console, and hence, the console uses global state, and there
- * can only be one console per process - not that it should matter, since the console requires a tty.
- *
- * XXX: the log module interferes with this
- */
-#include "error.h"
-#include <event2/event.h>
-#include <stdbool.h>
-
-/**
- * The console state.
- */
-struct console;
-
-/**
- * Return codes for console_callbacks::on_line
- */
-enum console_line_status {
- /**
- * OK, line was processed, display prompt for next input line
- */
- CONSOLE_CONTINUE,
-
- /**
- * Line is still executing, do not prompt for next line .
- *
- * Call console_continue() once the line was handled.
- */
- CONSOLE_WAIT,
-};
-
-/**
- * Callbacks for event-based actions
- */
-struct console_callbacks {
- /**
- * A line was read from the console.
- *
- * The return code defines how execution continues.
- */
- enum console_line_status (*on_line) (const char *line, void *arg);
-
- /**
- * EOF was read on the console.
- *
- * Note that for interactive consoles, EOF isn't actually EOF - there might be multiple EOFs...
- */
- void (*on_eof) (void *arg);
-
- /**
- * An input interrupt (SIGINT) was recieved while in the wait state. This can be used to abort execution and
- * call console_continue quickly.
- */
- void (*on_interrupt) (void *arg);
-};
-
-/**
- * Configuration info for console operation
- */
-struct console_config {
- /** The prompt to use when displaying lines */
- const char *prompt;
-};
-
-/**
- * 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, error_t *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);
-
-/**
- * Continue reading input after a CONSOLE_WAIT return code from console_callbacks::on_line.
- *
- * This does nothing if the console is not currently in the waiting state (i.e. last console_callbacks::on_line
- * returned CONSOLE_WAIT).
- */
-void console_continue (struct console *console);
-
-/**
- * Output a full line (without included newline) on the console, trying not to interfere with the input too much.
- */
-err_t console_print (struct console *console, const char *line);
-
-/**
- * Install this console as the log output handler
- */
-void console_set_log_output (struct console *console);
-
-/**
- * Deinitialize the console, restoring the TTY and releasing resources
- */
-void console_destroy (struct console *console);
-
-#endif /* CONSOLE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/console.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,277 @@
+#include "console.h"
+#include "log.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include <signal.h>
+#include <assert.h>
+
+struct console {
+ /** Configuration */
+ struct console_config config;
+
+ /** Input event */
+ struct event *ev;
+
+ /** Callback functions */
+ const struct console_callbacks *callbacks;
+
+ /** Callback context argument */
+ void *cb_arg;
+
+ /** Old SIGINT handler */
+ struct sigaction old_sigint;
+
+ /** Already initialized? */
+ bool initialized;
+
+ /** Set as log output function? */
+ bool log_output;
+
+ /** Prompt displayed? */
+ bool have_prompt;
+
+ /** Waiting for line to be processed */
+ bool waiting;
+};
+
+/** The global console state */
+static struct console _console;
+
+/**
+ * Our stdin input handler
+ */
+static void console_input (int fd, short what, void *arg)
+{
+ struct console *console = arg;
+
+ (void) fd;
+ (void) what;
+
+ if (console->waiting)
+ // can't feed readline input while it's disabled
+ return log_warn("discrding input while waiting");
+
+ else
+ // tell readline to process it
+ rl_callback_read_char();
+}
+
+/**
+ * Our readline line handler
+ */
+static void console_line (char *line)
+{
+ struct console *console = &_console;
+ enum console_line_status status = CONSOLE_CONTINUE;
+
+ // special-case EOF
+ if (!line) {
+ // prettify
+ rl_crlf();
+ rl_on_new_line();
+
+ if (console->callbacks->on_eof)
+ console->callbacks->on_eof(console->cb_arg);
+
+ return;
+ }
+
+ // update state for console_print during processing
+ console->have_prompt = false;
+
+ // invoke the console callback
+ if (console->callbacks && console->callbacks->on_line)
+ status = console->callbacks->on_line(line, console->cb_arg);
+
+ // add to history mechanism
+ add_history(line);
+
+ // release the line
+ free(line);
+
+ switch (status) {
+ case CONSOLE_CONTINUE:
+ // the prompt will be displayed again
+ console->have_prompt = true;
+
+ break;
+
+ case CONSOLE_WAIT:
+ // deactivate our read event
+ if (event_del(console->ev))
+ log_warn("unable to deactivate console read event");
+
+ // remove the readline stuff to stop it from displaying the prompt
+ rl_callback_handler_remove();
+
+ // ignore input
+ console->waiting = true;
+
+ break;
+ }
+}
+static void on_sigint (int sig)
+{
+ struct console *console = &_console;
+
+ (void) sig;
+
+ if (console->waiting) {
+ // notify user
+ if (console->callbacks->on_interrupt)
+ console->callbacks->on_interrupt(console->cb_arg);
+
+ } else {
+ // interrupt the input line
+ // XXX: is this the right function to call?
+ rl_free_line_state();
+
+ // redisplay on new line
+ rl_crlf();
+ rl_callback_handler_install(console->config.prompt, console_line);
+ }
+}
+
+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, error_t *err)
+{
+ struct console *console = &_console;
+
+ // check it's not already initialized
+ assert(!console->initialized);
+
+ // store
+ console->config = *config;
+
+ // 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)
+ JUMP_SET_ERROR(err, ERR_EVENT_NEW);
+
+ // set our SIGINT handler
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = on_sigint;
+ sigaction(SIGINT, &sigact, &console->old_sigint);
+
+ // setup state for initial readline prompt
+ console->have_prompt = true;
+
+ // setup readline
+ rl_callback_handler_install(config->prompt, console_line);
+
+ // mark it as initialized
+ console->initialized = true;
+
+ // enable input
+ if (event_add(console->ev, NULL))
+ JUMP_SET_ERROR(err, ERR_EVENT_ADD);
+
+ // ok
+ *console_ptr = console;
+
+ return SUCCESS;
+
+error:
+ console_destroy(console);
+
+ 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_continue (struct console *console)
+{
+ if (!console->waiting)
+ return;
+
+ // re-enable input
+ console->waiting = false;
+
+ if (event_add(console->ev, NULL))
+ log_fatal("unable to re-enable console read event");
+
+ // the prompt will be displayed again
+ console->have_prompt = true;
+
+ // re-setup readline with prompt
+ rl_callback_handler_install(console->config.prompt, console_line);
+}
+
+err_t console_print (struct console *console, const char *line)
+{
+ if (console->have_prompt)
+ // don't interrupt current input line
+ rl_crlf();
+
+ // output the line
+ if (printf("%s\n", line) < 0)
+ return _ERR_GENERAL;
+
+ if (console->have_prompt) {
+ // restore input
+ rl_on_new_line();
+ rl_redisplay();
+ }
+
+ // ok
+ return SUCCESS;
+}
+
+/**
+ * Our log_output_func implementation
+ */
+static void console_log_output_func (const char *line, void *_console)
+{
+ struct console *console = _console;
+
+ console_print(console, line);
+}
+
+void console_set_log_output (struct console *console)
+{
+ // replace old one
+ log_set_func(console_log_output_func, console);
+
+ // mark
+ console->log_output = true;
+}
+
+void console_destroy (struct console *console)
+{
+ if (console->log_output)
+ // unset ourselves as the log handler
+ log_set_func(NULL, NULL);
+
+ // remove the input event
+ if (console->ev)
+ event_free(console->ev);
+
+ console->ev = NULL;
+
+ // de-init rl?
+ if (console->initialized)
+ rl_callback_handler_remove();
+
+ console->initialized = false;
+
+ // restore signal handler
+ sigaction(SIGINT, &console->old_sigint, NULL);
+
+ // remove stored stuff
+ console->callbacks = console->cb_arg = NULL;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/console.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,113 @@
+#ifndef LIBQMSK_CONSOLE_H
+#define LIBQMSK_CONSOLE_H
+
+/**
+ * @file
+ *
+ * An interactive line-based console interface for runtime configuration.
+ *
+ * This uses the GNU readline library to implement the console, and hence, the console uses global state, and there
+ * can only be one console per process - not that it should matter, since the console requires a tty.
+ *
+ * XXX: the log module interferes with this
+ */
+#include "error.h"
+#include <event2/event.h>
+
+/**
+ * The console state.
+ */
+struct console;
+
+/**
+ * Return codes for console_callbacks::on_line
+ */
+enum console_line_status {
+ /**
+ * OK, line was processed, display prompt for next input line
+ */
+ CONSOLE_CONTINUE,
+
+ /**
+ * Line is still executing, do not prompt for next line .
+ *
+ * Call console_continue() once the line was handled.
+ */
+ CONSOLE_WAIT,
+};
+
+/**
+ * Callbacks for event-based actions
+ */
+struct console_callbacks {
+ /**
+ * A line was read from the console.
+ *
+ * The return code defines how execution continues.
+ */
+ enum console_line_status (*on_line) (const char *line, void *arg);
+
+ /**
+ * EOF was read on the console.
+ *
+ * Note that for interactive consoles, EOF isn't actually EOF - there might be multiple EOFs...
+ */
+ void (*on_eof) (void *arg);
+
+ /**
+ * An input interrupt (SIGINT) was recieved while in the wait state. This can be used to abort execution and
+ * call console_continue quickly.
+ */
+ void (*on_interrupt) (void *arg);
+};
+
+/**
+ * Configuration info for console operation
+ */
+struct console_config {
+ /** The prompt to use when displaying lines */
+ const char *prompt;
+};
+
+/**
+ * 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, error_t *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);
+
+/**
+ * Continue reading input after a CONSOLE_WAIT return code from console_callbacks::on_line.
+ *
+ * This does nothing if the console is not currently in the waiting state (i.e. last console_callbacks::on_line
+ * returned CONSOLE_WAIT).
+ */
+void console_continue (struct console *console);
+
+/**
+ * Output a full line (without included newline) on the console, trying not to interfere with the input too much.
+ */
+err_t console_print (struct console *console, const char *line);
+
+/**
+ * Install this console as the log output handler
+ */
+void console_set_log_output (struct console *console);
+
+/**
+ * Deinitialize the console, restoring the TTY and releasing resources
+ */
+void console_destroy (struct console *console);
+
+#endif /* LIBQMSK_CONSOLE_H */
--- a/src/lib/error.c Wed May 27 23:57:48 2009 +0300
+++ b/src/lib/error.c Thu May 28 00:35:02 2009 +0300
@@ -1,13 +1,9 @@
#include "error.h"
#include "log.h"
+#include "str.h"
-const struct error_list general_errors = ERROR_LIST("general",
- ERROR_TYPE( ERR_MEM, "memory allocation error" ),
- ERROR_TYPE_STRING( ERR_NOT_IMPLEMENTED, "function not implmented" ),
- ERROR_TYPE_STRING( ERR_MISC, "miscellaneous error" ),
- ERROR_TYPE_STRING( ERR_CMD_OPT, "invalid command line option" ),
- ERROR_TYPE( ERR_UNKNOWN, "unknown error" )
-);
+#include <string.h>
+#include <stdlib.h>
const struct error_type* error_lookup_code (const struct error_list *list, err_t code)
{
@@ -26,8 +22,9 @@
const struct error_type* error_lookup (const error_t *err)
{
- struct error_item *item;
- struct error_type *type = NULL, *list;
+ const struct error_list *list = NULL;
+ const struct error_item *item;
+ const struct error_type *type;
// traverse stack
for (item = err->cur; item && item >= err->stack; item--) {
@@ -51,9 +48,9 @@
return type;
}
-const char* error_name (const struct error_list *list, err_t code);
+const char* error_name (const struct error_list *list, err_t code)
{
- struct error_type *type;
+ const struct error_type *type;
// just do a lookup
if ((type = error_lookup_code(list, code)))
@@ -71,8 +68,9 @@
char *buf_ptr = buf;
size_t buf_size = sizeof(buf);
- struct error_item *item;
- struct error_type *type;
+ const struct error_list *list = NULL;
+ const struct error_item *item;
+ const struct error_type *type;
// traverse stack
for (item = err->cur; item && item >= err->stack; item--) {
@@ -92,7 +90,7 @@
} else {
// found code's type
// delimit using colons, except at the end
- buf_ptr += str_advance(&buf_size, NULL, str_append(buf_ptr, buf_size, "[%s] %s%s",
+ buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%s] %s%s",
list->name, type->name, item == err->stack ? "" : ": "
));
@@ -106,13 +104,13 @@
// type mismatch
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": [error_extra type mismatch: %s <=> %s",
err->extra_type ? err->extra_type->name : NULL,
- item->extra_type ? item->extra_type->name : NULL
+ type->extra_type ? type->extra_type->name : NULL
));
} else if (err->extra_type) {
// add extra info
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": %s",
- err->extra_type->msg_func(item->extra_type, &item->extra_value)
+ err->extra_type->msg_func(err->extra_type, &err->extra_value)
));
}
@@ -143,7 +141,7 @@
// initial position
return (err->cur = err->stack);
- else if (err->cur < err->stack + ERR_DEPTH_MAX)
+ else if (err->cur < err->stack + ERROR_DEPTH_MAX)
return (err->cur++);
else
@@ -199,7 +197,7 @@
void error_copy (error_t *dst, const error_t *src)
{
- struct error_item *item;
+ const struct error_item *item;
// reset
error_reset(dst);
@@ -228,12 +226,15 @@
va_end(vargs);
}
-void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...)
+void _error_abort (const char *file, int line, const char *func, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
_error_abort_(fmt, vargs, "%s:%d[%s]", file, line, func);
va_end(vargs);
+
+ // then remember to die
+ abort();
}
--- a/src/lib/error.h Wed May 27 23:57:48 2009 +0300
+++ b/src/lib/error.h Thu May 28 00:35:02 2009 +0300
@@ -12,6 +12,7 @@
* then be used to trace the error down.
*/
#include <stdbool.h>
+#include <errno.h>
/**
* The type used to represent a scalar error code, there are only unique per level.
@@ -112,7 +113,7 @@
* Helper macro to define an error_list
*/
#define ERROR_LIST(name, ...) \
- { (name), __VA_ARGS__, ERROR_TYPE_END }
+ { (name), { __VA_ARGS__, ERROR_TYPE_END } }
/**
* Maximum number of nesting levels supported for errors
@@ -185,7 +186,7 @@
/**
* Evaluates to the current top of the error stack,
*/
-static struct error_item* error_top (error_t *err)
+static inline struct error_item* error_top (error_t *err)
{
return err->cur ? err->cur : err->stack;
}
@@ -267,26 +268,17 @@
/**
* Abort execution of process with error message
*/
-void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...);
+void _error_abort (const char *file, int line, const char *func, const char *fmt, ...);
#define error_abort(...) _error_abort(__FILE__, __LINE__, __func__, __VA_ARGS__);
/**
* Used to mark unexpcted conditions for switch-default. The given val must be an integer, as passed to switch
*/
-#define NOT_REACHED(val) error_abort("%s = %#x", #val, (int) (val));
+#define NOT_REACHED(val) error_abort("%s = %d", #val, (int) (val));
-/**
- * General-purpose errors that may be useful and don't belong in any more specific namespace.
+/*
+ * Include some common error codes
*/
-enum general_error_code {
- ERR_GENERAL_NONE,
- ERR_MEM, ///< memory allocation error
- ERR_NOT_IMPLEMENTED, ///< function not implmented: <func>
- ERR_MISC, ///< miscellaneous error: <error>
- ERR_CMD_OPT, ///< invalid command line option: <error> - XXX: replace with something getopt
- ERR_UNKNOWN, ///< unknown error
-};
-
-const struct error_list general_errors;
+#include "errors.h"
#endif /* LIBQMSK_ERROR_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/errors.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,20 @@
+#include "errors.h"
+
+const struct error_list general_errors = ERROR_LIST("general",
+ ERROR_TYPE( ERR_MEM, "memory allocation error" ),
+ ERROR_TYPE_STRING( ERR_NOT_IMPLEMENTED, "function not implmented" ),
+ ERROR_TYPE_STRING( ERR_MISC, "miscellaneous error" ),
+ ERROR_TYPE_STRING( ERR_CMD_OPT, "invalid command line option" ),
+ ERROR_TYPE( ERR_UNKNOWN, "unknown error" )
+);
+
+const struct error_list libc_errors = ERROR_LIST("libc",
+ ERROR_TYPE_ERRNO( ERR_SIGACTION, "sigaction" )
+);
+
+const struct error_list libevent_errors = ERROR_LIST("libevent",
+ ERROR_TYPE( ERR_EVENT_NEW, "event_new" ),
+ ERROR_TYPE( ERR_EVENT_ADD, "event_add" ),
+ ERROR_TYPE( ERR_EVENT_DEL, "event_del" )
+);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/errors.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,52 @@
+#ifndef LIBQMSK_ERRORS_H
+#define LIBQMSK_ERRORS_H
+
+/**
+ * @file
+ *
+ * Defines some errors codes for general-purpose use, or for common libraries.
+ */
+#include "error.h"
+
+/**
+ * General-purpose errors that may be useful and don't belong in any more specific namespace.
+ */
+enum general_error_code {
+ ERR_GENERAL_NONE,
+ ERR_MEM, ///< memory allocation error
+ ERR_NOT_IMPLEMENTED, ///< function not implmented: <func>
+ ERR_MISC, ///< miscellaneous error: <error>
+ ERR_CMD_OPT, ///< invalid command line option: <error> - XXX: replace with something getopt
+ ERR_UNKNOWN, ///< unknown error
+};
+
+const struct error_list general_errors;
+
+/**
+ * Convenience macros
+ */
+#define SET_ERROR_MEM(err_state) \
+ SET_ERROR(err_state, &general_errors, ERR_MEM)
+
+/**
+ * Errors for POSIX libc functions
+ */
+enum libc_error_code {
+ ERR_LIBC_NONE,
+ ERR_SIGACTION, ///< sigaction: <perror>
+};
+
+const struct error_list libc_errors;
+
+/**
+ * Errors for libevent
+ */
+enum libevent_error_code {
+ ERR_EVENT_NEW, ///< event_new
+ ERR_EVENT_ADD, ///< event_add
+ ERR_EVENT_DEL, ///< event_del
+};
+
+const struct error_list libevent_errors;
+
+#endif /* LIBQMSK_ERRORS_H */
--- a/src/lib/log.c Wed May 27 23:57:48 2009 +0300
+++ b/src/lib/log.c Thu May 28 00:35:02 2009 +0300
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
+#include <stdlib.h>
/**
* The default log output func
--- a/src/lib/str.c Wed May 27 23:57:48 2009 +0300
+++ b/src/lib/str.c Thu May 28 00:35:02 2009 +0300
@@ -185,21 +185,20 @@
/**
* Output the data for a single parameter
*/
-static err_t str_format_param (char **buf, size_t *buf_size, const char *name, const char *flags, str_format_cb func, void *arg)
+static err_t str_format_param (char **buf, size_t *buf_size, const char *name, const char *flags, str_format_cb func, void *arg, error_t *err)
{
const char *value;
ssize_t value_len = -1;
char flag;
bool use_quote = false;
- err_t err;
// look it up
- if ((err = func(name, &value, &value_len, arg)))
- return err;
+ if (func(name, &value, &value_len, arg, err))
+ return PUSH_ERROR(err, &str_errors, ERR_STR_FMT_VALUE);
// not found?
if (!value)
- return ERR_STR_FMT_NAME;
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_NAME);
// parse flags
while ((flag = *flags++)) {
@@ -212,7 +211,7 @@
default:
// unknown flag
- return ERR_STR_FMT_FLAG;
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_FLAG);
}
}
--- a/src/lib/str.h Wed May 27 23:57:48 2009 +0300
+++ b/src/lib/str.h Thu May 28 00:35:02 2009 +0300
@@ -20,6 +20,7 @@
ERR_STR_FMT_NAME, ///< invalid/unknown parameter name
ERR_STR_FMT_FLAGS_LEN, ///< invalid paramter flags length
ERR_STR_FMT_FLAG, ///< invalid paramter flag
+ ERR_STR_FMT_VALUE, ///< parameter value
ERR_STR_FMT_BUF_LEN, ///< output buffer ran out
};
@@ -104,9 +105,9 @@
* @param value returned pointer to param value
* @param value_len returned param value length, or -1 for strlen
* @param arg the context arg given to str_format
- * @return the parameter value, or NULL to error out
+ * @param err returned error info
*/
-typedef err_t (*str_format_cb) (const char *name, const char **value, ssize_t *value_len, void *arg);
+typedef err_t (*str_format_cb) (const char *name, const char **value, ssize_t *value_len, void *arg, error_t *err);
/**
* Maximum length of a parameter name
--- a/src/lua_config.c Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-#include "lua_config.h"
-
-#include <lua5.1/lauxlib.h>
-
-err_t lua_config_load (struct nexus_lua *lua, const char *path, error_t *err)
-{
- // just use luaL_loadfile and translate the error code
- if (nexus_lua_error(lua->st, luaL_loadfile(lua->st, path), err))
- // XXX: pollute the stack
- return ERROR_CODE(err);
-
- // execute it
- // XXX; error handler with debug info
- return nexus_lua_error(lua->st, lua_pcall(lua->st, 0, 0, 0), err);
-}
-
--- a/src/lua_config.h Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-#ifndef LUA_CONFIG_H
-#define LUA_CONFIG_H
-
-/**
- * @file
- *
- * Read a lua configuration file into a nexus_lua state
- */
-#include "error.h"
-#include "nexus_lua.h"
-
-/**
- * Load a lua config file at the given path into the nexus's lua state.
- *
- * Path can also be given as NULL to load from stdin.
- */
-err_t lua_config_load (struct nexus_lua *lua, const char *path, error_t *err);
-
-#endif /* LUA_CONFIG_H */
--- a/src/lua_console.c Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-#include "lua_console.h"
-#include "lua_objs.h"
-#include "log.h"
-
-#include <stdlib.h>
-
-#include <lua5.1/lauxlib.h>
-
-struct lua_console {
- /** The lowlevel line-based console */
- struct console *console;
-
- /** Our lua state */
- struct nexus_lua *lua;
-
- /** Coroutine state */
- struct lua_thread thread;
-};
-
-/**
- * Line finished execution
- */
-static void lua_console_on_thread (const error_t *err, void *arg)
-{
- struct lua_console *lc = arg;
-
- if (err)
- // display error message
- console_print(lc->console, error_msg(err));
-
- // XXX: display return value?
-
- // un-wait console
- console_continue(lc->console);
-}
-
-/**
- * Got a line to exec from the console
- */
-static enum console_line_status lua_console_on_line (const char *line, void *arg)
-{
- struct lua_console *lc = arg;
- error_t err;
- int ret;
-
- // ignore empty lines and EOF
- if (!line || !(*line))
- return CONSOLE_CONTINUE;
-
- // exec it in our thread
- if ((ret = lua_thread_start(&lc->thread, line, &err)) < 0) {
- // display error message
- console_print(lc->console, error_msg(&err));
-
- return CONSOLE_CONTINUE;
- }
-
- // waiting?
- if (ret)
- return CONSOLE_WAIT;
-
- else
- return CONSOLE_CONTINUE;
-}
-
-static void lua_console_on_eof (void *arg)
-{
- struct lua_console *lc = arg;
-
- // exit the process
- nexus_shutdown(lc->lua->nexus);
-}
-
-static void lua_console_on_interrupt (void *arg)
-{
- struct lua_console *lc = arg;
-
- // abort thread so we can _start again
- lua_thread_abort(&lc->thread);
-
- // inform user
- console_print(lc->console, "Execution aborted.");
-
- // accept input
- console_continue(lc->console);
-}
-
-static struct console_callbacks _console_callbacks = {
- .on_line = lua_console_on_line,
- .on_eof = lua_console_on_eof,
- .on_interrupt = lua_console_on_interrupt,
-};
-
-err_t lua_console_create (struct lua_console **lc_ptr, struct console *console, struct nexus_lua *lua, error_t *err)
-{
- struct lua_console *lc;
-
- // allocate
- if ((lc = calloc(1, sizeof(*lc))) == NULL)
- return SET_ERROR(err, ERR_CALLOC);
-
- // store
- lc->console = console;
- lc->lua = lua;
-
- // set our console callbacks
- console_set_callbacks(console, &_console_callbacks, lc);
-
- // init thread
- lua_thread_init(&lc->thread, lua, lua_console_on_thread, lc);
-
- // ok
- *lc_ptr = lc;
-
- return SUCCESS;
-}
-
-void lua_console_destroy (struct lua_console *lc)
-{
- // the console
- console_destroy(lc->console);
-
- free(lc);
-}
--- a/src/lua_console.h Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#ifndef LUA_CONSOLE_H
-#define LUA_CONSOLE_H
-
-/**
- * @file
- *
- * An interactive lua console
- */
-#include "lua_thread.h"
-#include "console.h"
-
-#include <lua5.1/lua.h>
-
-/**
- * The lua console state
- */
-struct lua_console;
-
-/**
- * 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_lua *lua, error_t *err);
-
-/**
- * Destroy the lua console state
- */
-void lua_console_destroy (struct lua_console *lc);
-
-#endif
--- a/src/lua_thread.c Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-#include "lua_thread.h"
-#include "log.h"
-
-#include <string.h>
-#include <assert.h>
-
-#include <lua5.1/lauxlib.h>
-
-
-void lua_thread_init (struct lua_thread *thread, struct nexus_lua *lua, lua_thread_cb cb_func, void *cb_arg)
-{
- // zero
- memset(thread, 0, sizeof(*thread));
-
- // store
- thread->lua = lua;
- thread->cb_func = cb_func;
- thread->cb_arg = cb_arg;
-}
-
-/**
- * Thread completed, cleanup and call user callback with given error (NULL for success).
- */
-static void lua_thread_done (struct lua_thread *thread, error_t *err)
-{
- // remove from registry so thread can be GC'd
- // XXX: unsafe
- lua_pushthread(thread->L);
- lua_pushnil(thread->L);
- lua_settable(thread->L, LUA_REGISTRYINDEX);
-
- // drop our ref
- thread->L = NULL;
-
- // call
- thread->cb_func(err, thread->cb_arg);
-}
-
-/**
- * Execute the lua_resume with zero arguments. If the thread finished, this returns zero, if it yielded, >0. For
- * errors, returns -err_t.
- */
-static int lua_thread_resume (lua_State *L, struct lua_thread *thread, error_t *err)
-{
- int ret;
-
- (void) thread;
-
- // invoke it
- switch ((ret = lua_resume(L, 0))) {
- case LUA_YIELD:
- // ok, running, wait
- return 1;
-
- case 0:
- // done
- return 0;
-
- default:
- // let caller handle
- // XXX: backtrace...
- return -nexus_lua_error(L, ret, err);
- }
-}
-
-struct lua_thread_start_ctx {
- struct lua_thread *thread;
- const char *chunk;
-};
-
-/**
- * Create a new thread, set it up, and run the initial resume, returning the boolean result of that
- * (true for yielded, false for done).
- */
-static int _lua_thread_start (lua_State *L)
-{
- struct lua_thread_start_ctx *ctx;
- lua_State *TL;
- error_t err;
- int ret;
-
- // read the ctx argument off the stack
- if ((ctx = lua_touserdata(L, 1)) == NULL)
- return luaL_error(L, "lua_touserdata");
- else
- lua_pop(L, 1);
-
- // check
- assert(!ctx->thread->L);
-
- // create new thread
- TL = lua_newthread(L);
-
- // push the lua_thread as the value
- lua_pushlightuserdata(L, ctx->thread);
-
- // store L -> lua_thread mapping in the registry
- lua_settable(L, LUA_REGISTRYINDEX);
-
- // load the chunk as a lua function into the thread's state
- if (nexus_lua_error(TL, luaL_loadstring(TL, ctx->chunk), &err))
- goto error;
-
- // initial resume on the loaded chunk
- if ((ret = lua_thread_resume(TL, ctx->thread, &err)) < 0)
- goto error;
-
- // yielded?
- if (ret)
- // store
- ctx->thread->L = TL;
-
- // pop thread to release for GC
- lua_pop(L, 1);
-
- return 0;
-
-error:
- // pop thread to release for GC
- lua_pop(L, 1);
-
- // drop ref
- ctx->thread->L = NULL;
-
- // pass on error
- return luaL_error(L, "%s", error_msg(&err));
-}
-
-int lua_thread_start (struct lua_thread *thread, const char *chunk, error_t *err)
-{
- struct lua_thread_start_ctx ctx = { thread, chunk };
-
- // sanity-check
- assert(!thread->L);
-
- // use protected mode to setup
- if (nexus_lua_error(thread->lua->st, lua_cpcall(thread->lua->st, _lua_thread_start, &ctx), err))
- return -ERROR_CODE(err);
-
- // return true if yielded, false if done
- return (thread->L != NULL);
-}
-
-int lua_thread_yield_state (lua_State *L)
-{
- return lua_yield(L, 0);
-}
-
-static int _lua_thread_resume_state (lua_State *L)
-{
- struct lua_thread *thread, **thread_ptr;
-
- // read the ctx argument off the stack
- if ((thread_ptr = lua_touserdata(L, 1)) == NULL)
- return luaL_error(L, "lua_touserdata");
- else
- lua_pop(L, 1);
-
- // lookup the thread's context
- lua_pushthread(L);
- lua_gettable(L, LUA_REGISTRYINDEX);
-
- // not registered?
- if (lua_isnil(L, -1))
- return luaL_error(L, "not a registered lua_thread state");
-
- else if (lua_isboolean(L, -1) && !lua_toboolean(L, -1))
- return luaL_error(L, "lua_thread was aborted");
-
- // get it as a pointer
- if ((thread = lua_touserdata(L, -1)) == NULL)
- return luaL_error(L, "lua_touserdata");
- else
- lua_pop(L, 1);
-
- // store it
- *thread_ptr = thread;
-
- // ok
- return 0;
-}
-
-void lua_thread_resume_state (lua_State *L)
-{
- struct lua_thread *thread = NULL;
- error_t err;
- int ret;
-
- // execute in protected mode
- if (nexus_lua_error(L, lua_cpcall(L, _lua_thread_resume_state, &thread), &err))
- return log_warn_error(&err, "%p", L);
-
- // handle the resume
- if ((ret = lua_thread_resume(L, thread, &err)) < 0)
- // notify user
- lua_thread_done(thread, &err);
-
- // finished?
- else if (ret == 0)
- lua_thread_done(thread, NULL);
-
-}
-
-static int _lua_thread_abort (lua_State *L)
-{
- struct lua_thread *thread;
-
- // get context arg
- if ((thread = lua_touserdata(L, -1)) == NULL)
- luaL_error(L, "lua_thread_resume_state: lua_touserdata");
- else
- lua_pop(L, 1);
-
- // no mechanism to actually abort the underlying wait yet
- (void) thread;
-
- // invalidate in registry for later lua_thread_resume_state
- lua_pushthread(L);
- lua_pushboolean(L, false);
- lua_settable(L, LUA_REGISTRYINDEX);
-
- // not much else we can do
- return 0;
-}
-
-void lua_thread_abort (struct lua_thread *thread)
-{
- error_t err;
-
- if (!thread->L)
- // no thread executing
- return;
-
- // use protected mode
- if (nexus_lua_error(thread->L, lua_cpcall(thread->L, _lua_thread_abort, thread), &err))
- log_warn_error(&err, "_lua_thread_abort");
-
- // unset
- thread->L = NULL;
-}
-
--- a/src/lua_thread.h Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-#ifndef LUA_THREAD_H
-#define LUA_THREAD_H
-
-/**
- * @file
- *
- * Running code as lua coroutines for a nexus_lua
- */
-#include "nexus_lua.h"
-#include <lua5.1/lua.h>
-
-/*
- * Forward-declare
- */
-struct lua_thread;
-
-/**
- * Callback for async execution completion. The thread will be cleaned up for re-use before this is called.
- *
- * Called with err == NULL for success, error code otherwise.
- *
- * XXX: also return execution results (as a lua_State arg)?
- */
-typedef void (*lua_thread_cb) (const error_t *err, void *arg);
-
-/**
- * A thread of execution
- */
-struct lua_thread {
- /** The lua_nexus environment we're running under */
- struct nexus_lua *lua;
-
- /** Callback */
- lua_thread_cb cb_func;
-
- /** Callback context argument */
- void *cb_arg;
-
- /** Real lua thread state */
- lua_State *L;
-};
-
-/**
- * Initialize the given lua_thread state for execution.
- *
- * You only need to call this once for each lua_thread that you use.
- */
-void lua_thread_init (struct lua_thread *thread, struct nexus_lua *lua, lua_thread_cb cb_func, void *cb_arg);
-
-/**
- * Execute the given chunk in a thread context.
- *
- * This should be called from unprotected mode, and the thread must currently not be active.
- *
- * This will load the chunk, create a new lua thread state off the lua_nexus, and then do the initial 'lua_resume' call
- * on the loaded chunk, to execute up to the first yield or final return.
- *
- * If this process raises an error, it will be returned directly. If the called chunk simply returns without yielding,
- * this returns 0, and the callback is *NOT* called. Otherwise, this returns >0 and the thread's callback function will
- * eventually be called once the thread either errors out or finishes execution.
- */
-int lua_thread_start (struct lua_thread *thread, const char *chunk, error_t *err);
-
-/**
- * Protected-mode function to yield execution of the given lua_State, which must be a luaState created with
- * lua_thread_start.
- *
- * This should be called the same way as lua_yield, except no results are supported yet.
- */
-int lua_thread_yield_state (lua_State *L);
-
-/**
- * Resume execution of the given lua_State, which must be a lua_State created with lua_thread_start.
- */
-void lua_thread_resume_state (lua_State *L);
-
-/**
- * Abort execution of the given thread, if it's running.
- *
- * Currently, there is no mechanism to actually abort a running thread, so this will instead release the lua_thread for
- * new use, and then cause the lua_thread_resume to do nothing.
- */
-void lua_thread_abort (struct lua_thread *thread);
-
-#endif
--- a/src/nexus_lua.c Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-#include "nexus_lua.h"
-#include "lua_objs.h"
-#include "lua_irc.h"
-
-#include <stdlib.h>
-
-#include <lua5.1/lualib.h>
-#include <lua5.1/lauxlib.h>
-
-/**
- * Initialize the lua state, in protected mode
- */
-int nexus_lua_init (lua_State *L)
-{
- struct nexus_lua *lua;
-
- // read the nexus_lua off the stack
- if ((lua = lua_touserdata(L, 1)) == NULL)
- luaL_error(L, "lua_touserdata: NULL");
-
- // open the standard libraries
- luaL_openlibs(L);
-
- // open our core lua api
- lua_objs_init(lua);
-
- // and the irc_* stuff
- lua_irc_init(lua);
-
- // ok
- return 0;
-}
-
-err_t nexus_lua_create (struct nexus_lua **lua_ptr, struct nexus *nexus, error_t *err)
-{
- struct nexus_lua *lua;
-
- // alloc
- if ((lua = calloc(1, sizeof(*lua))) == NULL)
- return SET_ERROR(err, ERR_CALLOC);
-
- // store
- lua->nexus = nexus;
-
- // create the lua state
- if ((lua->st = luaL_newstate()) == NULL)
- JUMP_SET_ERROR(err, ERR_LUA_MEM);
-
- // init in protected mode
- if (nexus_lua_error(lua->st, lua_cpcall(lua->st, &nexus_lua_init, lua), err))
- goto error;
-
- // ok
- *lua_ptr = lua;
-
- return SUCCESS;
-
-error:
- nexus_lua_destroy(lua);
-
- return ERROR_CODE(err);
-}
-
-void nexus_lua_destroy (struct nexus_lua *lua)
-{
- // close the lua stuff
- lua_close(lua->st);
-
- free(lua);
-}
-
-err_t nexus_lua_eval (struct nexus_lua *lua, const char *chunk, error_t *err)
-{
- int ret;
- bool loaded = false;
-
- RESET_ERROR(err);
-
- // load the line as a lua function
- if ((ret = luaL_loadstring(lua->st, chunk)))
- goto error;
-
- loaded = true;
-
- // execute it
- if ((ret = lua_pcall(lua->st, 0, 0, 0)))
- goto error;
-
-error:
- if (ret) {
- // build the error_info
- nexus_lua_error(lua->st, ret, err);
-
- // pop the error message
- // XXX: err points at GC:able memory
- lua_pop(lua->st, 1);
- }
-
- return ERROR_CODE(err);
-}
-
-err_t nexus_lua_error (lua_State *L, int ret, error_t *err)
-{
- // XXX: this can raise an erorr itself
- const char *error = lua_tostring(L, -1);
-
- switch (ret) {
- case 0: RETURN_SET_ERROR(err, SUCCESS);
- case LUA_ERRSYNTAX: RETURN_SET_ERROR_STR(err, ERR_LUA_SYNTAX, error);
- case LUA_ERRRUN: RETURN_SET_ERROR_STR(err, ERR_LUA_RUN, error);
- case LUA_ERRMEM: RETURN_SET_ERROR_STR(err, ERR_LUA_MEM, error);
- case LUA_ERRERR: RETURN_SET_ERROR_STR(err, ERR_LUA_ERR, error);
- case LUA_ERRFILE: RETURN_SET_ERROR_STR(err, ERR_LUA_FILE, error);
- default: RETURN_SET_ERROR_EXTRA(err, ERR_UNKNOWN, ret);
- };
-}
-
--- a/src/nexus_lua.h Wed May 27 23:57:48 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#ifndef NEXUS_LUA_H
-#define NEXUS_LUA_H
-
-/**
- * @file
- *
- * Defines the lua environment for use with nexus
- */
-struct nexus_lua;
-
-#include "nexus.h"
-
-#include <lua5.1/lua.h>
-
-/**
- * The global lua state
- */
-struct nexus_lua {
- /** The nexus we are operating on */
- struct nexus *nexus;
-
- /** The main lua state */
- lua_State *st;
-};
-
-/**
- * Create a new lua state for nexus
- */
-err_t nexus_lua_create (struct nexus_lua **lua_ptr, struct nexus *nexus, error_t *err);
-
-/**
- * Destroy the lua state
- */
-void nexus_lua_destroy (struct nexus_lua *lua);
-
-/**
- * Parse and execute the given lua chunk in the nexus's lua context.
- *
- * This operation is equally valid for both textual and binary chunks, but this is intended for textual chunks, and
- * hence accepts a NUL-terminated string.
- *
- * This runs the chunk in the main lua state, so this will fail for any coroutine functions.
- */
-err_t nexus_lua_eval (struct nexus_lua *lua, const char *chunk, error_t *err);
-
-/**
- * Handle a Lua error by converting the given error code into a ERR_LUA_* code, inspecting the error object at
- * the top of the stack.
- *
- * Please note that the resulting error_info points into strings inside the lua stack - once you pop the error, the
- * error_info might not be valid anymore after the next GC cycle.
- */
-err_t nexus_lua_error (lua_State *L, int ret, error_t *err);
-
-#endif /* NEXUS_LUA_H */
--- a/src/spbot/config.h Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/config.h Thu May 28 00:35:02 2009 +0300
@@ -1,5 +1,5 @@
-#ifndef CONFIG_H
-#define CONFIG_H
+#ifndef SPBOT_CONFIG_H
+#define SPBOT_CONFIG_H
/**
* @file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/lua_config.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,16 @@
+#include "lua_config.h"
+
+#include <lua5.1/lauxlib.h>
+
+err_t lua_config_load (struct nexus_lua *lua, const char *path, error_t *err)
+{
+ // just use luaL_loadfile and translate the error code
+ if (nexus_lua_error(lua->st, luaL_loadfile(lua->st, path), err))
+ // XXX: pollute the stack
+ return ERROR_CODE(err);
+
+ // execute it
+ // XXX; error handler with debug info
+ return nexus_lua_error(lua->st, lua_pcall(lua->st, 0, 0, 0), err);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/lua_config.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,19 @@
+#ifndef SPBOT_LUA_CONFIG_H
+#define SPBOT_LUA_CONFIG_H
+
+/**
+ * @file
+ *
+ * Read a lua configuration file into a nexus_lua state
+ */
+#include <lib/error.h>
+#include "nexus_lua.h"
+
+/**
+ * Load a lua config file at the given path into the nexus's lua state.
+ *
+ * Path can also be given as NULL to load from stdin.
+ */
+err_t lua_config_load (struct nexus_lua *lua, const char *path, error_t *err);
+
+#endif /* LUA_CONFIG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/lua_console.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,124 @@
+#include "lua_console.h"
+#include "lua_objs.h"
+#include "log.h"
+
+#include <stdlib.h>
+
+#include <lua5.1/lauxlib.h>
+
+struct lua_console {
+ /** The lowlevel line-based console */
+ struct console *console;
+
+ /** Our lua state */
+ struct nexus_lua *lua;
+
+ /** Coroutine state */
+ struct lua_thread thread;
+};
+
+/**
+ * Line finished execution
+ */
+static void lua_console_on_thread (const error_t *err, void *arg)
+{
+ struct lua_console *lc = arg;
+
+ if (err)
+ // display error message
+ console_print(lc->console, error_msg(err));
+
+ // XXX: display return value?
+
+ // un-wait console
+ console_continue(lc->console);
+}
+
+/**
+ * Got a line to exec from the console
+ */
+static enum console_line_status lua_console_on_line (const char *line, void *arg)
+{
+ struct lua_console *lc = arg;
+ error_t err;
+ int ret;
+
+ // ignore empty lines and EOF
+ if (!line || !(*line))
+ return CONSOLE_CONTINUE;
+
+ // exec it in our thread
+ if ((ret = lua_thread_start(&lc->thread, line, &err)) < 0) {
+ // display error message
+ console_print(lc->console, error_msg(&err));
+
+ return CONSOLE_CONTINUE;
+ }
+
+ // waiting?
+ if (ret)
+ return CONSOLE_WAIT;
+
+ else
+ return CONSOLE_CONTINUE;
+}
+
+static void lua_console_on_eof (void *arg)
+{
+ struct lua_console *lc = arg;
+
+ // exit the process
+ nexus_shutdown(lc->lua->nexus);
+}
+
+static void lua_console_on_interrupt (void *arg)
+{
+ struct lua_console *lc = arg;
+
+ // abort thread so we can _start again
+ lua_thread_abort(&lc->thread);
+
+ // inform user
+ console_print(lc->console, "Execution aborted.");
+
+ // accept input
+ console_continue(lc->console);
+}
+
+static struct console_callbacks _console_callbacks = {
+ .on_line = lua_console_on_line,
+ .on_eof = lua_console_on_eof,
+ .on_interrupt = lua_console_on_interrupt,
+};
+
+err_t lua_console_create (struct lua_console **lc_ptr, struct console *console, struct nexus_lua *lua, error_t *err)
+{
+ struct lua_console *lc;
+
+ // allocate
+ if ((lc = calloc(1, sizeof(*lc))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
+
+ // store
+ lc->console = console;
+ lc->lua = lua;
+
+ // set our console callbacks
+ console_set_callbacks(console, &_console_callbacks, lc);
+
+ // init thread
+ lua_thread_init(&lc->thread, lua, lua_console_on_thread, lc);
+
+ // ok
+ *lc_ptr = lc;
+
+ return SUCCESS;
+}
+
+void lua_console_destroy (struct lua_console *lc)
+{
+ // the console
+ console_destroy(lc->console);
+
+ free(lc);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/lua_console.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,31 @@
+#ifndef SPBOT_LUA_CONSOLE_H
+#define SPBOT_LUA_CONSOLE_H
+
+/**
+ * @file
+ *
+ * An interactive lua console
+ */
+#include "lua_thread.h"
+#include <lib/console.h>
+
+#include <lua5.1/lua.h>
+
+/**
+ * The lua console state
+ */
+struct lua_console;
+
+/**
+ * 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_lua *lua, error_t *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/spbot/lua_thread.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,241 @@
+#include "lua_thread.h"
+#include <lib/log.h>
+
+#include <string.h>
+#include <assert.h>
+
+#include <lua5.1/lauxlib.h>
+
+
+void lua_thread_init (struct lua_thread *thread, struct nexus_lua *lua, lua_thread_cb cb_func, void *cb_arg)
+{
+ // zero
+ memset(thread, 0, sizeof(*thread));
+
+ // store
+ thread->lua = lua;
+ thread->cb_func = cb_func;
+ thread->cb_arg = cb_arg;
+}
+
+/**
+ * Thread completed, cleanup and call user callback with given error (NULL for success).
+ */
+static void lua_thread_done (struct lua_thread *thread, error_t *err)
+{
+ // remove from registry so thread can be GC'd
+ // XXX: unsafe
+ lua_pushthread(thread->L);
+ lua_pushnil(thread->L);
+ lua_settable(thread->L, LUA_REGISTRYINDEX);
+
+ // drop our ref
+ thread->L = NULL;
+
+ // call
+ thread->cb_func(err, thread->cb_arg);
+}
+
+/**
+ * Execute the lua_resume with zero arguments. If the thread finished, this returns zero, if it yielded, >0. For
+ * errors, returns -err_t.
+ */
+static int lua_thread_resume (lua_State *L, struct lua_thread *thread, error_t *err)
+{
+ int ret;
+
+ (void) thread;
+
+ // invoke it
+ switch ((ret = lua_resume(L, 0))) {
+ case LUA_YIELD:
+ // ok, running, wait
+ return 1;
+
+ case 0:
+ // done
+ return 0;
+
+ default:
+ // let caller handle
+ // XXX: backtrace...
+ return -nexus_lua_error(L, ret, err);
+ }
+}
+
+struct lua_thread_start_ctx {
+ struct lua_thread *thread;
+ const char *chunk;
+};
+
+/**
+ * Create a new thread, set it up, and run the initial resume, returning the boolean result of that
+ * (true for yielded, false for done).
+ */
+static int _lua_thread_start (lua_State *L)
+{
+ struct lua_thread_start_ctx *ctx;
+ lua_State *TL;
+ error_t err;
+ int ret;
+
+ // read the ctx argument off the stack
+ if ((ctx = lua_touserdata(L, 1)) == NULL)
+ return luaL_error(L, "lua_touserdata");
+ else
+ lua_pop(L, 1);
+
+ // check
+ assert(!ctx->thread->L);
+
+ // create new thread
+ TL = lua_newthread(L);
+
+ // push the lua_thread as the value
+ lua_pushlightuserdata(L, ctx->thread);
+
+ // store L -> lua_thread mapping in the registry
+ lua_settable(L, LUA_REGISTRYINDEX);
+
+ // load the chunk as a lua function into the thread's state
+ if (nexus_lua_error(TL, luaL_loadstring(TL, ctx->chunk), &err))
+ goto error;
+
+ // initial resume on the loaded chunk
+ if ((ret = lua_thread_resume(TL, ctx->thread, &err)) < 0)
+ goto error;
+
+ // yielded?
+ if (ret)
+ // store
+ ctx->thread->L = TL;
+
+ // pop thread to release for GC
+ lua_pop(L, 1);
+
+ return 0;
+
+error:
+ // pop thread to release for GC
+ lua_pop(L, 1);
+
+ // drop ref
+ ctx->thread->L = NULL;
+
+ // pass on error
+ return luaL_error(L, "%s", error_msg(&err));
+}
+
+int lua_thread_start (struct lua_thread *thread, const char *chunk, error_t *err)
+{
+ struct lua_thread_start_ctx ctx = { thread, chunk };
+
+ // sanity-check
+ assert(!thread->L);
+
+ // use protected mode to setup
+ if (nexus_lua_error(thread->lua->st, lua_cpcall(thread->lua->st, _lua_thread_start, &ctx), err))
+ return -ERROR_CODE(err);
+
+ // return true if yielded, false if done
+ return (thread->L != NULL);
+}
+
+int lua_thread_yield_state (lua_State *L)
+{
+ return lua_yield(L, 0);
+}
+
+static int _lua_thread_resume_state (lua_State *L)
+{
+ struct lua_thread *thread, **thread_ptr;
+
+ // read the ctx argument off the stack
+ if ((thread_ptr = lua_touserdata(L, 1)) == NULL)
+ return luaL_error(L, "lua_touserdata");
+ else
+ lua_pop(L, 1);
+
+ // lookup the thread's context
+ lua_pushthread(L);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+
+ // not registered?
+ if (lua_isnil(L, -1))
+ return luaL_error(L, "not a registered lua_thread state");
+
+ else if (lua_isboolean(L, -1) && !lua_toboolean(L, -1))
+ return luaL_error(L, "lua_thread was aborted");
+
+ // get it as a pointer
+ if ((thread = lua_touserdata(L, -1)) == NULL)
+ return luaL_error(L, "lua_touserdata");
+ else
+ lua_pop(L, 1);
+
+ // store it
+ *thread_ptr = thread;
+
+ // ok
+ return 0;
+}
+
+void lua_thread_resume_state (lua_State *L)
+{
+ struct lua_thread *thread = NULL;
+ error_t err;
+ int ret;
+
+ // execute in protected mode
+ if (nexus_lua_error(L, lua_cpcall(L, _lua_thread_resume_state, &thread), &err))
+ return log_warn_error(&err, "%p", L);
+
+ // handle the resume
+ if ((ret = lua_thread_resume(L, thread, &err)) < 0)
+ // notify user
+ lua_thread_done(thread, &err);
+
+ // finished?
+ else if (ret == 0)
+ lua_thread_done(thread, NULL);
+
+}
+
+static int _lua_thread_abort (lua_State *L)
+{
+ struct lua_thread *thread;
+
+ // get context arg
+ if ((thread = lua_touserdata(L, -1)) == NULL)
+ luaL_error(L, "lua_thread_resume_state: lua_touserdata");
+ else
+ lua_pop(L, 1);
+
+ // no mechanism to actually abort the underlying wait yet
+ (void) thread;
+
+ // invalidate in registry for later lua_thread_resume_state
+ lua_pushthread(L);
+ lua_pushboolean(L, false);
+ lua_settable(L, LUA_REGISTRYINDEX);
+
+ // not much else we can do
+ return 0;
+}
+
+void lua_thread_abort (struct lua_thread *thread)
+{
+ error_t err;
+
+ if (!thread->L)
+ // no thread executing
+ return;
+
+ // use protected mode
+ if (nexus_lua_error(thread->L, lua_cpcall(thread->L, _lua_thread_abort, thread), &err))
+ log_warn_error(&err, "_lua_thread_abort");
+
+ // unset
+ thread->L = NULL;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/lua_thread.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,85 @@
+#ifndef SPBOT_LUA_THREAD_H
+#define SPBOT_LUA_THREAD_H
+
+/**
+ * @file
+ *
+ * Running code as lua coroutines for a nexus_lua
+ */
+#include "nexus_lua.h"
+#include <lua5.1/lua.h>
+
+/*
+ * Forward-declare
+ */
+struct lua_thread;
+
+/**
+ * Callback for async execution completion. The thread will be cleaned up for re-use before this is called.
+ *
+ * Called with err == NULL for success, error code otherwise.
+ *
+ * XXX: also return execution results (as a lua_State arg)?
+ */
+typedef void (*lua_thread_cb) (const error_t *err, void *arg);
+
+/**
+ * A thread of execution
+ */
+struct lua_thread {
+ /** The lua_nexus environment we're running under */
+ struct nexus_lua *lua;
+
+ /** Callback */
+ lua_thread_cb cb_func;
+
+ /** Callback context argument */
+ void *cb_arg;
+
+ /** Real lua thread state */
+ lua_State *L;
+};
+
+/**
+ * Initialize the given lua_thread state for execution.
+ *
+ * You only need to call this once for each lua_thread that you use.
+ */
+void lua_thread_init (struct lua_thread *thread, struct nexus_lua *lua, lua_thread_cb cb_func, void *cb_arg);
+
+/**
+ * Execute the given chunk in a thread context.
+ *
+ * This should be called from unprotected mode, and the thread must currently not be active.
+ *
+ * This will load the chunk, create a new lua thread state off the lua_nexus, and then do the initial 'lua_resume' call
+ * on the loaded chunk, to execute up to the first yield or final return.
+ *
+ * If this process raises an error, it will be returned directly. If the called chunk simply returns without yielding,
+ * this returns 0, and the callback is *NOT* called. Otherwise, this returns >0 and the thread's callback function will
+ * eventually be called once the thread either errors out or finishes execution.
+ */
+int lua_thread_start (struct lua_thread *thread, const char *chunk, error_t *err);
+
+/**
+ * Protected-mode function to yield execution of the given lua_State, which must be a luaState created with
+ * lua_thread_start.
+ *
+ * This should be called the same way as lua_yield, except no results are supported yet.
+ */
+int lua_thread_yield_state (lua_State *L);
+
+/**
+ * Resume execution of the given lua_State, which must be a lua_State created with lua_thread_start.
+ */
+void lua_thread_resume_state (lua_State *L);
+
+/**
+ * Abort execution of the given thread, if it's running.
+ *
+ * Currently, there is no mechanism to actually abort a running thread, so this will instead release the lua_thread for
+ * new use, and then cause the lua_thread_resume to do nothing.
+ */
+void lua_thread_abort (struct lua_thread *thread);
+
+#endif
--- a/src/spbot/module.c Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/module.c Thu May 28 00:35:02 2009 +0300
@@ -1,5 +1,5 @@
#include "module.h"
-#include "log.h"
+#include <lib/log.h>
#include <stdlib.h>
#include <unistd.h>
@@ -8,22 +8,24 @@
#include <assert.h>
const struct error_list module_errors = ERROR_LIST("module",
- ERROR_TYPE_STRING( ERR_MODULE_NAME, "invalid module name" ),
- ERROR_TYPE( ERR_MODULE_DUP, "module already loaded" ),
- ERROR_TYPE_STRING( ERR_MODULE_PATH, "invalid module path" ),
- ERROR_TYPE_STRING( ERR_MODULE_OPEN, "module dlopen() failed" ),
- ERROR_TYPE_STRING( ERR_MODULE_SYM, "module dlsym() failed" ),
- ERROR_TYPE_STRING( ERR_MODULE_INIT_FUNC, "invalid module init func" ),
- ERROR_TYPE_STRING( ERR_MODULE_CONF, "module_conf" )
+ ERROR_TYPE_STRING( ERR_MODULE_NAME, "invalid module name" ),
+ ERROR_TYPE( ERR_MODULE_DUP, "module already loaded" ),
+ ERROR_TYPE_STRING( ERR_MODULE_PATH, "invalid module path" ),
+ ERROR_TYPE_STRING( ERR_MODULE_OPEN, "module dlopen() failed" ),
+ ERROR_TYPE_STRING( ERR_MODULE_SYM, "module dlsym() failed" ),
+ ERROR_TYPE_STRING( ERR_MODULE_INIT_FUNC, "invalid module init func" ),
+ ERROR_TYPE_STRING( ERR_MODULE_CONF, "module_conf" ),
+ ERROR_TYPE( ERR_MODULE_STATE, "module in wrong state for operation" ),
+ ERROR_TYPE( ERR_MODULE_UNLOAD, "unable to unload module" )
);
-err_t modules_create (struct modules **modules_ptr, struct nexus *nexus)
+err_t modules_create (struct modules **modules_ptr, struct nexus *nexus, error_t *err)
{
struct modules *modules;
// alloc
if ((modules = calloc(1, sizeof(*modules))) == NULL)
- return ERR_CALLOC;
+ return SET_ERROR_MEM(err);
// init
TAILQ_INIT(&modules->list);
@@ -85,12 +87,12 @@
err_t modules_unload (struct modules *modules)
{
struct module *module;
- err_t err;
+ error_t err;
// unload each module in turn
while ((module = TAILQ_FIRST(&modules->list))) {
- if ((err = module_unload(module)))
- log_warn("module_unload(%s) failed: %s", module->info.name, error_name(err));
+ if (module_unload(module, &err))
+ log_warn_error(&err, "module_unload(%s) failed", module->info.name);
}
// ok
@@ -208,7 +210,7 @@
// alloc
if ((module = calloc(1, sizeof(*module))) == NULL)
- return SET_ERROR(err, &module_errors, ERR_CALLOC);
+ return SET_ERROR_MEM(err);
// initialize
module->info = *_info;
@@ -240,8 +242,8 @@
JUMP_SET_ERROR_STR(err, &module_errors, ERR_MODULE_OPEN, dlerror());
// load the funcs symbol
- if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module")))
- JUMP_SET_ERROR_STR(err, &module_errors, ERROR_CODE(err), dlerror());
+ if (module_symbol(module, (void **) &module->desc, "module", err))
+ goto error;
// call the init func
if ((module->desc->init(modules->nexus, &module->ctx, err)))
@@ -279,11 +281,11 @@
{
// sanity-check
if (!module->desc->config_options)
- RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options");
+ return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module does not have any config options");
// wrong state
if (module->unloading)
- RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
+ return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
// parse/apply using the module's stuff
// XXX: error namespaces?
@@ -308,20 +310,18 @@
{
// wrong state
if (module->unloading)
- RETURN_SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
+ return SET_ERROR_STR(err, &module_errors, ERR_MODULE_CONF, "module is being unloaded");
// apply with the module's ctx
// XXX: error namespaces?
return config_apply_opt(opt, module->ctx, value, err);
}
-err_t module_unload (struct module *module)
+err_t module_unload (struct module *module, error_t *err)
{
- err_t err;
-
// wrong state
if (module->unloading)
- return ERR_MODULE_STATE;
+ return SET_ERROR(err, &module_errors, ERR_MODULE_STATE);
// remove from modules list
TAILQ_REMOVE(&module->modules->list, module, modules_list);
@@ -332,11 +332,11 @@
if (module->desc->unload) {
// invoke the unload func, passing it our reference
// note that the module might not exist anymore after calling this
- if ((err = module->desc->unload(module->ctx, module))) {
+ if (module->desc->unload(module->ctx, module, err)) {
// mark it as "unloaded"
module_unloaded(module);
-
- return err;
+
+ return PUSH_ERROR(err, &module_errors, ERR_MODULE_UNLOAD);
}
} else {
--- a/src/spbot/module.h Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/module.h Thu May 28 00:35:02 2009 +0300
@@ -1,5 +1,5 @@
-#ifndef MODULE_H
-#define MODULE_H
+#ifndef SPBOT_MODULE_H
+#define SPBOT_MODULE_H
/**
* @file
@@ -47,6 +47,7 @@
ERR_MODULE_INIT_FUNC, ///< invalid module_init_func_t
ERR_MODULE_CONF, ///< value error in configuration data
ERR_MODULE_STATE, ///< module in wrong state for operation
+ ERR_MODULE_UNLOAD, ///< unable to unload module
};
const struct error_list module_errors;
@@ -108,7 +109,7 @@
* @param module the hanging module reference, that must be passed to module_unloaded()
* @return error code
*/
- err_t (*unload) (void *ctx, struct module *module);
+ err_t (*unload) (void *ctx, struct module *module, error_t *err);
/**
* Destroy the module now. No later chances, the module's code will be unloaded directly after this, which means
@@ -187,7 +188,7 @@
/**
* Create a new modules state
*/
-err_t modules_create (struct modules **modules_ptr, struct nexus *nexus);
+err_t modules_create (struct modules **modules_ptr, struct nexus *nexus, error_t *err);
/**
* Set a search path for finding modules by name. The given string won't be copied.
@@ -271,10 +272,10 @@
* \p unload function, passing it the primary reference. The module's unload code will then go about shutting down the
* module, and once that is done, it may module_put() the primary reference, which may then lead to module_destroy().
*
- * This returns ERR_MODULE_STATE if the module is already being unloaded, or other errors from the module's own unload
- * functionality.
+ * This returns ERR_MODULE_STATE if the module is already being unloaded, or ERR_MODULE_UNLOAD if the module's unload
+ * func fails.
*/
-err_t module_unload (struct module *module);
+err_t module_unload (struct module *module, error_t *err);
/**
* Used by a module itself to indicate that an module_desc::unload() operation has completed. This will execute a
--- a/src/spbot/nexus.c Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/nexus.c Thu May 28 00:35:02 2009 +0300
@@ -535,7 +535,7 @@
// initialize signal handlers
- if ((ERROR_CODE(&err) = signals_create(&nexus->signals, nexus->ev_base)))
+ if (signals_create(&nexus->signals, nexus->ev_base, &err))
FATAL("signals_create");
// add our signal handlers
@@ -554,7 +554,7 @@
FATAL_ERROR(&err, "sock_init");
// modules
- if ((ERROR_CODE(&err) = modules_create(&nexus->modules, nexus)))
+ if (modules_create(&nexus->modules, nexus, &err))
FATAL_ERROR(&err, "modules_create");
// the IRC client
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/nexus_lua.c Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,117 @@
+#include "nexus_lua.h"
+#include "../lua_objs.h"
+#include "../lua_irc.h"
+
+#include <stdlib.h>
+
+#include <lua5.1/lualib.h>
+#include <lua5.1/lauxlib.h>
+
+/**
+ * Initialize the lua state, in protected mode
+ */
+int nexus_lua_init (lua_State *L)
+{
+ struct nexus_lua *lua;
+
+ // read the nexus_lua off the stack
+ if ((lua = lua_touserdata(L, 1)) == NULL)
+ luaL_error(L, "lua_touserdata: NULL");
+
+ // open the standard libraries
+ luaL_openlibs(L);
+
+ // open our core lua api
+ lua_objs_init(lua);
+
+ // and the irc_* stuff
+ lua_irc_init(lua);
+
+ // ok
+ return 0;
+}
+
+err_t nexus_lua_create (struct nexus_lua **lua_ptr, struct nexus *nexus, error_t *err)
+{
+ struct nexus_lua *lua;
+
+ // alloc
+ if ((lua = calloc(1, sizeof(*lua))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
+
+ // store
+ lua->nexus = nexus;
+
+ // create the lua state
+ if ((lua->st = luaL_newstate()) == NULL)
+ JUMP_SET_ERROR(err, ERR_LUA_MEM);
+
+ // init in protected mode
+ if (nexus_lua_error(lua->st, lua_cpcall(lua->st, &nexus_lua_init, lua), err))
+ goto error;
+
+ // ok
+ *lua_ptr = lua;
+
+ return SUCCESS;
+
+error:
+ nexus_lua_destroy(lua);
+
+ return ERROR_CODE(err);
+}
+
+void nexus_lua_destroy (struct nexus_lua *lua)
+{
+ // close the lua stuff
+ lua_close(lua->st);
+
+ free(lua);
+}
+
+err_t nexus_lua_eval (struct nexus_lua *lua, const char *chunk, error_t *err)
+{
+ int ret;
+ bool loaded = false;
+
+ RESET_ERROR(err);
+
+ // load the line as a lua function
+ if ((ret = luaL_loadstring(lua->st, chunk)))
+ goto error;
+
+ loaded = true;
+
+ // execute it
+ if ((ret = lua_pcall(lua->st, 0, 0, 0)))
+ goto error;
+
+error:
+ if (ret) {
+ // build the error_info
+ nexus_lua_error(lua->st, ret, err);
+
+ // pop the error message
+ // XXX: err points at GC:able memory
+ lua_pop(lua->st, 1);
+ }
+
+ return ERROR_CODE(err);
+}
+
+err_t nexus_lua_error (lua_State *L, int ret, error_t *err)
+{
+ // XXX: this can raise an erorr itself
+ const char *error = lua_tostring(L, -1);
+
+ switch (ret) {
+ case 0: RETURN_SET_ERROR(err, SUCCESS);
+ case LUA_ERRSYNTAX: RETURN_SET_ERROR_STR(err, ERR_LUA_SYNTAX, error);
+ case LUA_ERRRUN: RETURN_SET_ERROR_STR(err, ERR_LUA_RUN, error);
+ case LUA_ERRMEM: RETURN_SET_ERROR_STR(err, ERR_LUA_MEM, error);
+ case LUA_ERRERR: RETURN_SET_ERROR_STR(err, ERR_LUA_ERR, error);
+ case LUA_ERRFILE: RETURN_SET_ERROR_STR(err, ERR_LUA_FILE, error);
+ default: RETURN_SET_ERROR_EXTRA(err, ERR_UNKNOWN, ret);
+ };
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spbot/nexus_lua.h Thu May 28 00:35:02 2009 +0300
@@ -0,0 +1,55 @@
+#ifndef SPBOT_NEXUS_LUA_H
+#define SPBOT_NEXUS_LUA_H
+
+/**
+ * @file
+ *
+ * Defines the lua environment for use with nexus
+ */
+struct nexus_lua;
+
+#include "nexus.h"
+
+#include <lua5.1/lua.h>
+
+/**
+ * The global lua state
+ */
+struct nexus_lua {
+ /** The nexus we are operating on */
+ struct nexus *nexus;
+
+ /** The main lua state */
+ lua_State *st;
+};
+
+/**
+ * Create a new lua state for nexus
+ */
+err_t nexus_lua_create (struct nexus_lua **lua_ptr, struct nexus *nexus, error_t *err);
+
+/**
+ * Destroy the lua state
+ */
+void nexus_lua_destroy (struct nexus_lua *lua);
+
+/**
+ * Parse and execute the given lua chunk in the nexus's lua context.
+ *
+ * This operation is equally valid for both textual and binary chunks, but this is intended for textual chunks, and
+ * hence accepts a NUL-terminated string.
+ *
+ * This runs the chunk in the main lua state, so this will fail for any coroutine functions.
+ */
+err_t nexus_lua_eval (struct nexus_lua *lua, const char *chunk, error_t *err);
+
+/**
+ * Handle a Lua error by converting the given error code into a ERR_LUA_* code, inspecting the error object at
+ * the top of the stack.
+ *
+ * Please note that the resulting error_info points into strings inside the lua stack - once you pop the error, the
+ * error_info might not be valid anymore after the next GC cycle.
+ */
+err_t nexus_lua_error (lua_State *L, int ret, error_t *err);
+
+#endif /* SPBOT_NEXUS_LUA_H */
--- a/src/spbot/signals.c Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/signals.c Thu May 28 00:35:02 2009 +0300
@@ -1,6 +1,6 @@
#include "signals.h"
-#include "log.h"
+#include <lib/log.h>
#define _GNU_SOURCE
@@ -27,7 +27,8 @@
void signals_loopexit (int signal, short event, void *arg)
{
struct signals *signals = arg;
-
+
+ (void) signal;
(void) event;
log_info("caught %s: exiting", /* strsignal(signal) */ "xxx");
@@ -48,12 +49,12 @@
/* ignore */
}
-err_t signals_create (struct signals **signals_ptr, struct event_base *ev_base)
+err_t signals_create (struct signals **signals_ptr, struct event_base *ev_base, error_t *err)
{
struct signals *signals;
if ((signals = calloc(1, sizeof(*signals))) == NULL)
- return ERR_CALLOC;
+ return SET_ERROR(err, &general_errors, ERR_MEM);
// simple attributes
signals->ev_base = ev_base;
@@ -83,7 +84,7 @@
return SUCCESS;
}
-err_t signal_ignore (int signum, struct error_info *err)
+err_t signal_ignore (int signum, error_t *err)
{
struct sigaction act = {
.sa_handler = SIG_IGN,
@@ -91,7 +92,7 @@
// signall the handler
if (sigaction(signum, &act, NULL))
- RETURN_SET_ERROR_ERRNO(err, ERR_SIGACTION);
+ return SET_ERROR_ERRNO(err, &libc_errors, ERR_SIGACTION);
// ok
return SUCCESS;
@@ -100,10 +101,10 @@
struct signals *signals_default (struct event_base *ev_base)
{
struct signals *signals = NULL;
- struct error_info err;
+ error_t err;
// alloc signals
- if (signals_create(&signals, ev_base))
+ if (signals_create(&signals, ev_base, &err))
return NULL;
// add the set of default signals
--- a/src/spbot/signals.h Wed May 27 23:57:48 2009 +0300
+++ b/src/spbot/signals.h Thu May 28 00:35:02 2009 +0300
@@ -34,7 +34,7 @@
*
* Returns NULL on failure
*/
-err_t signals_create (struct signals **signals_ptr, struct event_base *ev_base);
+err_t signals_create (struct signals **signals_ptr, struct event_base *ev_base, error_t *err);
/**
* Add a signal to be handled by the given signals struct with the given handler.