src/console.c
author Tero Marttila <terom@fixme.fi>
Thu, 02 Apr 2009 02:55:32 +0300
changeset 111 5a1ebffca81a
parent 95 6bb8ef294689
child 137 c607c357c486
permissions -rw-r--r--
fix refcount semantics for module_load and have module_unload call module_unloaded on module_desc::unload errors
#include "console.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 */
static struct console _console;

/**
 * Our stdin input handler
 */
static void console_input (int fd, short what, void *arg)
{
    struct console *console = arg;

    (void) console;
    (void) fd;
    (void) what;

    // tell readline to process it
    rl_callback_read_char();
}

/**
 * Our readline line handler
 */
static void console_line (char *line)
{
    struct console *console = &_console;

    // XXX: EOF?

    // invoke the console callback
    if (console->callbacks && console->callbacks->on_line)
        console->callbacks->on_line(line, console->cb_arg);
    
    // add to history mechanism
    add_history(line);

    // release the line
    free(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, struct error_info *err)
{
    struct console *console = &_console;

    // check it's not already initialized
    assert(!console->initialized);

    // 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);

    // 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_destroy (struct console *console)
{
    // 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;

    // remove stored stuff
    console->callbacks = console->cb_arg = NULL;
}