terom@92: #include "console.h" terom@137: #include "log.h" terom@92: terom@93: #include terom@92: #include terom@92: #include terom@92: #include terom@95: #include terom@137: terom@92: #include terom@92: terom@92: /** The global console state */ terom@92: static struct console _console; terom@92: terom@92: /** terom@92: * Our stdin input handler terom@92: */ terom@92: static void console_input (int fd, short what, void *arg) terom@92: { terom@92: struct console *console = arg; terom@92: terom@92: (void) fd; terom@92: (void) what; terom@92: terom@137: // update state terom@137: console->have_input = true; terom@137: terom@92: // tell readline to process it terom@92: rl_callback_read_char(); terom@92: } terom@92: terom@92: /** terom@92: * Our readline line handler terom@92: */ terom@92: static void console_line (char *line) terom@92: { terom@92: struct console *console = &_console; terom@92: terom@137: // XXX: line == NULL -> EOF? terom@137: terom@137: // update state terom@137: console->have_input = false; terom@93: terom@92: // invoke the console callback terom@93: if (console->callbacks && console->callbacks->on_line) terom@93: console->callbacks->on_line(line, console->cb_arg); terom@95: terom@95: // add to history mechanism terom@95: add_history(line); terom@93: terom@93: // release the line terom@93: free(line); terom@137: terom@137: // update state, as the prompt will be displayed again terom@137: console->have_input = true; terom@92: } terom@92: terom@92: err_t console_init (struct console **console_ptr, struct event_base *ev_base, const struct console_config *config, terom@92: const struct console_callbacks *callbacks, void *cb_arg, struct error_info *err) terom@92: { terom@92: struct console *console = &_console; terom@92: terom@92: // check it's not already initialized terom@92: assert(!console->initialized); terom@92: terom@93: // store callbacks? terom@93: if (callbacks) terom@93: console_set_callbacks(console, callbacks, cb_arg); terom@92: terom@92: // setup the input event terom@92: if ((console->ev = event_new(ev_base, STDIN_FILENO, EV_READ | EV_PERSIST, &console_input, console)) == NULL) terom@92: JUMP_SET_ERROR(err, ERR_EVENT_NEW); terom@92: terom@92: // setup readline terom@92: rl_callback_handler_install(config->prompt, &console_line); terom@92: terom@92: // mark it as initialized terom@92: console->initialized = true; terom@92: terom@92: // enable input terom@92: if (event_add(console->ev, NULL)) terom@92: JUMP_SET_ERROR(err, ERR_EVENT_ADD); terom@92: terom@92: // ok terom@92: *console_ptr = console; terom@92: terom@92: return SUCCESS; terom@92: terom@92: error: terom@92: console_destroy(console); terom@92: terom@92: return ERROR_CODE(err); terom@92: } terom@92: terom@93: void console_set_callbacks (struct console *console, const struct console_callbacks *callbacks, void *cb_arg) terom@93: { terom@93: console->callbacks = callbacks; terom@93: console->cb_arg = cb_arg; terom@93: } terom@93: terom@137: err_t console_print (struct console *console, const char *line) terom@137: { terom@137: if (console->have_input) terom@137: // don't interrupt current input line terom@137: rl_crlf(); terom@137: terom@137: // output the line terom@137: if (printf("%s\n", line) < 0) terom@137: return _ERR_GENERAL; terom@137: terom@137: if (console->have_input) { terom@137: // restore input terom@137: rl_on_new_line(); terom@137: rl_redisplay(); terom@137: } terom@137: terom@137: // ok terom@137: return SUCCESS; terom@137: } terom@137: terom@137: /** terom@137: * Our log_output_func implementation terom@137: */ terom@137: static void console_log_output_func (const char *line, void *_console) terom@137: { terom@137: struct console *console = _console; terom@137: terom@137: console_print(console, line); terom@137: } terom@137: terom@137: void console_set_log_output (struct console *console) terom@137: { terom@137: // replace old one terom@137: log_set_func(console_log_output_func, console); terom@137: terom@137: // mark terom@137: console->log_output = true; terom@137: } terom@137: terom@92: void console_destroy (struct console *console) terom@92: { terom@137: if (console->log_output) terom@137: // unset ourselves as the log handler terom@137: log_set_func(NULL, NULL); terom@137: terom@92: // remove the input event terom@92: if (console->ev) terom@92: event_free(console->ev); terom@92: terom@92: console->ev = NULL; terom@92: terom@92: // de-init rl? terom@92: if (console->initialized) terom@92: rl_callback_handler_remove(); terom@92: terom@92: console->initialized = false; terom@92: terom@92: // remove stored stuff terom@92: console->callbacks = console->cb_arg = NULL; terom@92: } terom@92: