From fac10ea799fe9b6158d74f66d6ad46536d38a545 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 18 Mar 2009 04:55:00 +0100 Subject: Initial commit --- src/cli.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 src/cli.c (limited to 'src/cli.c') diff --git a/src/cli.c b/src/cli.c new file mode 100644 index 00000000..e302dfa8 --- /dev/null +++ b/src/cli.c @@ -0,0 +1,175 @@ +/* + * Asynchronous readline-based interactive interface + * + * Actually not asynchronous so far, but intended to be. + * + * Copyright (c) 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CMDLINE_HISTFILE ".nft.history" + +static const struct input_descriptor indesc_cli = { + .type = INDESC_CLI, +}; + +static struct parser_state *state; +static void *scanner; + +static char histfile[PATH_MAX]; +static char *multiline; +static bool eof; + +static char *cli_append_multiline(char *line) +{ + bool complete = false; + size_t len; + char *s; + + if (line == NULL && multiline == NULL) { + eof = true; + return NULL; + } + + len = strlen(line); + if (line[len - 1] == '\\') { + line[len - 1] = '\0'; + len--; + } else if (multiline == NULL) + return line; + else + complete = 1; + + if (multiline == NULL) { + multiline = line; + rl_save_prompt(); + rl_clear_message(); + } else { + len += strlen(multiline); + s = xmalloc(len + 1); + snprintf(s, len + 1, "%s%s", multiline, line); + xfree(multiline); + multiline = s; + } + line = NULL; + + if (complete) { + line = multiline; + multiline = NULL; + rl_restore_prompt(); + } + return line; +} + +static void cli_complete(char *line) +{ + const HIST_ENTRY *hist; + const char *c; + + line = cli_append_multiline(line); + if (line == NULL) + return; + + for (c = line; *c != '\0'; c++) + if (!isspace(*c)) + break; + if (*c == '\0') + return; + + /* avoid duplicate history entries */ + hist = history_get(history_length); + if (hist == NULL || strcmp(hist->line, line)) + add_history(line); + + scanner_push_buffer(scanner, &indesc_cli, line); + nft_parse(scanner, state); + + erec_print_list(stdout, state->msgs); + xfree(line); +} + +static char **cli_completion(const char *text, int start, int end) +{ + return NULL; +} + +void __fmtstring(1, 0) cli_display(const char *fmt, va_list ap) +{ + int point, end; + char *buf; + + point = rl_point; + end = rl_end; + rl_point = rl_end = 0; + + rl_save_prompt(); + rl_clear_message(); + + if (vasprintf(&buf, fmt, ap) < 0) + fprintf(rl_outstream, "cli_display: out of memory\n"); + else { + fprintf(rl_outstream, "%s\n", buf); + xfree(buf); + } + + rl_restore_prompt(); + + rl_point = point; + rl_end = end; + rl_forced_update_display(); +} + +int cli_init(void *_scanner, struct parser_state *_state) +{ + const char *home; + + rl_readline_name = "nft"; + rl_instream = stdin; + rl_outstream = stdout; + + rl_callback_handler_install("nft> ", cli_complete); + rl_attempted_completion_function = cli_completion; + + home = getenv("HOME"); + if (home == NULL) + home = ""; + snprintf(histfile, sizeof(histfile), "%s/%s", home, CMDLINE_HISTFILE); + + read_history(histfile); + history_set_pos(history_length); + + scanner = _scanner; + state = _state; + + while (!eof) + rl_callback_read_char(); + return 0; +} + +void cli_exit(void) +{ + rl_callback_handler_remove(); + rl_deprep_terminal(); + write_history(histfile); +} -- cgit v1.2.3