--- a/TODO Sun Apr 12 20:37:57 2009 +0300
+++ b/TODO Sun Apr 12 22:19:54 2009 +0300
@@ -22,6 +22,9 @@
* user-defined types
* return values
+console:
+ * improve console_print further, to act more like rlwrap
+
lua_console:
* some kind of remote console
--- a/src/console.c Sun Apr 12 20:37:57 2009 +0300
+++ b/src/console.c Sun Apr 12 22:19:54 2009 +0300
@@ -1,10 +1,12 @@
#include "console.h"
+#include "log.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
+
#include <assert.h>
/** The global console state */
@@ -17,10 +19,12 @@
{
struct console *console = arg;
- (void) console;
(void) fd;
(void) what;
+ // update state
+ console->have_input = true;
+
// tell readline to process it
rl_callback_read_char();
}
@@ -32,7 +36,10 @@
{
struct console *console = &_console;
- // XXX: EOF?
+ // XXX: line == NULL -> EOF?
+
+ // update state
+ console->have_input = false;
// invoke the console callback
if (console->callbacks && console->callbacks->on_line)
@@ -43,6 +50,9 @@
// release the line
free(line);
+
+ // update state, as the prompt will be displayed again
+ console->have_input = true;
}
err_t console_init (struct console **console_ptr, struct event_base *ev_base, const struct console_config *config,
@@ -88,8 +98,51 @@
console->cb_arg = cb_arg;
}
+err_t console_print (struct console *console, const char *line)
+{
+ if (console->have_input)
+ // don't interrupt current input line
+ rl_crlf();
+
+ // output the line
+ if (printf("%s\n", line) < 0)
+ return _ERR_GENERAL;
+
+ if (console->have_input) {
+ // 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);
--- a/src/console.h Sun Apr 12 20:37:57 2009 +0300
+++ b/src/console.h Sun Apr 12 22:19:54 2009 +0300
@@ -52,6 +52,12 @@
/** Already initialized? */
bool initialized;
+
+ /** Set as log output function? */
+ bool log_output;
+
+ /** In the middle of input? */
+ bool have_input;
};
/**
@@ -73,6 +79,16 @@
void console_set_callbacks (struct console *console, const struct console_callbacks *callbacks, void *cb_arg);
/**
+ * 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);
--- a/src/log.c Sun Apr 12 20:37:57 2009 +0300
+++ b/src/log.c Sun Apr 12 22:19:54 2009 +0300
@@ -1,16 +1,39 @@
#include "log.h"
+#include "str.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
/**
+ * The default log output func
+ */
+void log_default_func (const char *line, void *arg)
+{
+ (void) arg;
+
+ // display
+ printf("%s\n", line);
+}
+
+/**
* The global log level
*/
static enum log_level _log_level = LOG_LEVEL_DEFAULT;
/**
+ * The global log output func
+ */
+static struct log_output_ctx {
+ /** The function itself */
+ log_output_func func;
+
+ /** The arg */
+ void *arg;
+} _log_output_ctx = { log_default_func, NULL };
+
+/**
* List of log level names
*/
const char *log_level_names[] = {
@@ -34,33 +57,7 @@
default: return "???";
}
}
-
-/**
- * Output the "[TYPE] FUNC: " header
- */
-void _log_header (enum log_level level, const char *func)
-{
- printf("[%5s] %20s : ", log_level_name(level), func);
-}
-
-void log_msg (enum log_level level, const char *func, const char *format, ...)
-{
- va_list vargs;
-
- // filter out?
- if (level < _log_level)
- return;
-
- _log_header(level, func);
-
- // formatted output
- va_start(vargs, format);
- vprintf(format, vargs);
- va_end(vargs);
-
- // newline
- printf("\n");
-}
+#undef _LOG_LEVEL_NAME
void set_log_level (enum log_level level)
{
@@ -68,63 +65,82 @@
_log_level = level;
}
-void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
+void log_set_func (log_output_func func, void *arg)
{
- va_list vargs;
+ // replace the current one
+ _log_output_ctx.func = func ? func : log_default_func;
+ _log_output_ctx.arg = arg;
+}
+
+/**
+ * Format the full output line, and pass it to the log_output_func. The line will be of the form:
+ * "[<level>] <func> : <log_fmt> [ <user_fmt> ]"
+ */
+static void log_output (enum log_level level, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
+{
+ char buf[LOG_MSG_MAX], *buf_ptr = buf;
+ size_t buf_size = sizeof(buf);
// filter out?
if (level < _log_level)
return;
-
- // header
- _log_header(level, func);
+
+ // output the header
+ buf_ptr += str_advance(NULL, &buf_size, str_append_fmt(buf_ptr, buf_size, "[%5s] %20s : ", log_level_name(level), func));
- // formatted output
+ // output the user data
+ buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, user_fmt, user_fmtargs));
+
+ // output the suffix
+ if (log_fmt) {
+ va_list vargs;
+
+ va_start(vargs, log_fmt);
+ buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, log_fmt, vargs));
+ va_end(vargs);
+ }
+
+ // send it to the output func
+ _log_output_ctx.func(buf, _log_output_ctx.arg);
+}
+
+void log_msg (enum log_level level, const char *func, const char *format, ...)
+{
+ va_list vargs;
+
+ // formatted output: no suffix
va_start(vargs, format);
- vprintf(format, vargs);
+ log_output(level, func, format, vargs, NULL);
va_end(vargs);
+}
- // err_code and newline
- printf(": %s\n", error_name(err));
+void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
+{
+ va_list vargs;
+
+ // formatted output: suffix error_name()
+ va_start(vargs, format);
+ log_output(level, func, format, vargs, ": %s", error_name(err));
+ va_end(vargs);
}
void _log_err_info (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
{
va_list vargs;
- // filter out?
- if (level < _log_level)
- return;
-
- // header
- _log_header(level, func);
-
- // formatted output
+ // formatted output: suffix error_msg()
va_start(vargs, format);
- vprintf(format, vargs);
+ log_output(level, func, format, vargs, ": %s", error_msg(err));
va_end(vargs);
-
- // err_code and newline
- printf(": %s\n", error_msg(err));
}
void _log_perr (enum log_level level, const char *func, const char *format, ...)
{
va_list vargs;
- // filter out?
- if (level < _log_level)
- return;
-
- // header
- _log_header(level, func);
-
- // formatted output
+ // formatted output: suffix strerror()
va_start(vargs, format);
- vprintf(format, vargs);
+ log_output(level, func, format, vargs, ": %s", strerror(errno));
va_end(vargs);
-
- // err_code and newline
- printf(": %s\n", strerror(errno));
}
--- a/src/log.h Sun Apr 12 20:37:57 2009 +0300
+++ b/src/log.h Sun Apr 12 22:19:54 2009 +0300
@@ -31,10 +31,14 @@
#define LOG_LEVEL_DEFAULT LOG_INFO
/**
- * Log a message with the given level
+ * Maximum length of a log message, including terminating NUL
*/
-void log_msg (enum log_level level, const char *func, const char *format, ...)
- __attribute__ ((format (printf, 3, 4)));
+#define LOG_MSG_MAX 1024
+
+/**
+ * Log output function, for displaying a line of text, without any trailing newline.
+ */
+typedef void (*log_output_func) (const char *line, void *arg);
/**
* Set the current log level to filter out messages below the given level
@@ -42,6 +46,19 @@
void set_log_level (enum log_level level);
/**
+ * Set the current log output function, replacing any default or previous value.
+ *
+ * Pass in func as NULL to revert to the default handler.
+ */
+void log_set_func (log_output_func func, void *arg);
+
+/**
+ * Log a message with the given level
+ */
+void log_msg (enum log_level level, const char *func, const char *format, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+/**
* Shorthand for log_msg
*/
#define log_debug(...) log_msg(LOG_DEBUG, __func__, __VA_ARGS__)
@@ -51,11 +68,14 @@
#define log_fatal(...) log_msg(LOG_FATAL, __func__, __VA_ARGS__)
/**
- * Log a message with LOG_ERROR, appending the formatted error code
+ * Log a message with the given level, appending the formatted error code name
*/
void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
__attribute__ ((format (printf, 4, 5)));
+/**
+ * Log a message with the given level, appending the formatted error message
+ */
void _log_err_info (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
__attribute__ ((format (printf, 4, 5)));
@@ -65,8 +85,12 @@
void _log_perr (enum log_level level, const char *func, const char *format, ...)
__attribute__ ((format (printf, 3, 4)));
+/**
+ * Shorthand for _log_*
+ */
#define log_err(err, ...) _log_err(LOG_ERROR, err, __func__, __VA_ARGS__)
#define log_err_info(err_info, ...) _log_err_info(LOG_ERROR, err_info, __func__, __VA_ARGS__)
+#define log_perr(...) _log_perr(LOG_ERROR, __func__, __VA_ARGS__)
/**
* log_fatal + exit failure
--- a/src/lua_console.c Sun Apr 12 20:37:57 2009 +0300
+++ b/src/lua_console.c Sun Apr 12 22:19:54 2009 +0300
@@ -17,7 +17,7 @@
// eval it
if (nexus_lua_eval(lc->lua, line, &err))
- log_error("%s", error_msg(&err));
+ console_print(lc->console, error_msg(&err));
// XXX: display return value?
--- a/src/nexus.c Sun Apr 12 20:37:57 2009 +0300
+++ b/src/nexus.c Sun Apr 12 22:19:54 2009 +0300
@@ -286,6 +286,9 @@
// init the console
if (console_init(&console, nexus->ev_base, &config, NULL, NULL, err))
return ERROR_CODE(err);
+
+ // set it as the log output handler
+ console_set_log_output(console);
// create the lua console on top of that
if (lua_console_create(&nexus->lua_console, console, nexus->lua, err))