# HG changeset patch # User Tero Marttila # Date 1243460102 -10800 # Node ID 5229a5d098b23dd1164eb9ec220000b4f49b9eeb # Parent 7728d6ec3abfda933fa7304f7e50df4ed68fac5f some of spbot and lib compiles diff -r 7728d6ec3abf -r 5229a5d098b2 src/console.c --- 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 -#include -#include -#include -#include - -#include -#include - -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; -} - diff -r 7728d6ec3abf -r 5229a5d098b2 src/console.h --- 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 -#include - -/** - * 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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/console.c --- /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 +#include +#include +#include +#include + +#include +#include + +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; +} + diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/console.h --- /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 + +/** + * 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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/error.c --- 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 +#include 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(); } diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/error.h --- 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 +#include /** * 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: - ERR_MISC, ///< miscellaneous error: - ERR_CMD_OPT, ///< invalid command line option: - XXX: replace with something getopt - ERR_UNKNOWN, ///< unknown error -}; - -const struct error_list general_errors; +#include "errors.h" #endif /* LIBQMSK_ERROR_H */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/errors.c --- /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" ) +); + diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/errors.h --- /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: + ERR_MISC, ///< miscellaneous error: + ERR_CMD_OPT, ///< invalid command line option: - 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: +}; + +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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/log.c --- 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 #include #include +#include /** * The default log output func diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/str.c --- 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); } } diff -r 7728d6ec3abf -r 5229a5d098b2 src/lib/str.h --- 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_config.c --- 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 - -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); -} - diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_config.h --- 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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_console.c --- 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 - -#include - -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); -} diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_console.h --- 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 - -/** - * 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_thread.c --- 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 -#include - -#include - - -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; -} - diff -r 7728d6ec3abf -r 5229a5d098b2 src/lua_thread.h --- 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 - -/* - * 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/nexus_lua.c --- 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 - -#include -#include - -/** - * 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); - }; -} - diff -r 7728d6ec3abf -r 5229a5d098b2 src/nexus_lua.h --- 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 - -/** - * 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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/config.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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_config.c --- /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 + +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); +} + diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_config.h --- /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 +#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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_console.c --- /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 + +#include + +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); +} diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_console.h --- /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 + +#include + +/** + * 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_thread.c --- /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 + +#include +#include + +#include + + +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; +} + diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/lua_thread.h --- /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 + +/* + * 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/module.c --- 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 #include #include @@ -8,22 +8,24 @@ #include 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 { diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/module.h --- 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/nexus.c --- 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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/nexus_lua.c --- /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 + +#include +#include + +/** + * 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); + }; +} + diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/nexus_lua.h --- /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 + +/** + * 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 */ diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/signals.c --- 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 #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 diff -r 7728d6ec3abf -r 5229a5d098b2 src/spbot/signals.h --- 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.