diff options
author | Amar Tumballi <amar@gluster.com> | 2010-07-08 08:16:13 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-07-08 23:28:08 -0700 |
commit | 915adb9c1291d140e57765b7fad0c5bb0e7d5ed5 (patch) | |
tree | 0330fa8796e18601ef7ef1441b6d4eb0df8cb9b6 /cli/src/cli-rl.c | |
parent | 7e489f3cc7f3eb738d2698dcf588bad0bdc12a8b (diff) |
gluster-CLI-and-mgmt-glusterd-added-to-codebase
Signed-off-by: Vijay Bellur <vijay@gluster.com>
Signed-off-by: Amar Tumballi <amar@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 971 (dynamic volume management)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=971
Diffstat (limited to 'cli/src/cli-rl.c')
-rw-r--r-- | cli/src/cli-rl.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/cli/src/cli-rl.c b/cli/src/cli-rl.c new file mode 100644 index 00000000000..bc2e80eba04 --- /dev/null +++ b/cli/src/cli-rl.c @@ -0,0 +1,368 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" + +#include "event.h" + +#include <fnmatch.h> + +#ifdef HAVE_READLINE + +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> + + +int +cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) +{ + int tmp_rl_point = rl_point; + int n = rl_end; + int i = 0; + int ret = 0; + + if (rl_end >= 0 ) { + rl_kill_text (0, rl_end); + rl_redisplay (); + } + + printf ("\r"); + + for (i = 0; i <= strlen (state->prompt); i++) + printf (" "); + + printf ("\r"); + + ret = vprintf (fmt, ap); + + printf ("\n"); + fflush(stdout); + + if (n) { + rl_do_undo (); + rl_point = tmp_rl_point; + rl_reset_line_state (); + } + + return ret; +} + + +void +cli_rl_process_line (char *line) +{ + struct cli_state *state = NULL; + int ret = 0; + + state = global_state; + + state->rl_processing = 1; + { + ret = cli_cmd_process_line (state, line); + add_history (line); + } + state->rl_processing = 0; +} + + +int +cli_rl_stdin (int fd, int idx, void *data, + int poll_out, int poll_in, int poll_err) +{ + rl_callback_read_char (); + + return 0; +} + + +char * +cli_rl_autocomplete_entry (const char *text, int times) +{ + struct cli_state *state = NULL; + char *retp = NULL; + + state = global_state; + + if (!state->matchesp) + return NULL; + + retp = *state->matchesp; + + state->matchesp++; + + return retp ? strdup (retp) : NULL; +} + + +int +cli_rl_token_count (const char *text) +{ + int count = 0; + const char *trav = NULL; + int is_spc = 1; + + for (trav = text; *trav; trav++) { + if (*trav == ' ') { + is_spc = 1; + } else { + if (is_spc) { + count++; + is_spc = 0; + } + } + } + + if (is_spc) + /* what needs to be autocompleted is a full + new word, and not extend the last word + */ + count++; + + return count; +} + + +char ** +cli_rl_tokenize (const char *text) +{ + int count = 0; + char **tokens = NULL; + char **tokenp = NULL; + char *token = NULL; + char *copy = NULL; + char *saveptr = NULL; + int i = 0; + + count = cli_rl_token_count (text); + + tokens = calloc (count + 1, sizeof (*tokens)); + if (!tokens) + return NULL; + + copy = strdup (text); + if (!copy) + goto out; + + tokenp = tokens; + + for (token = strtok_r (copy, " \t\r\n", &saveptr); token; + token = strtok_r (NULL, " \t\r\n", &saveptr)) { + *tokenp = strdup (token); + + if (!*tokenp) + goto out; + tokenp++; + i++; + + } + + if (i < count) { + /* symoblize that what needs to be autocompleted is + the full set of possible nextwords, and not extend + the last word + */ + *tokenp = strdup (""); + if (!*tokenp) + goto out; + tokenp++; + i++; + } + +out: + if (copy) + free (copy); + + if (i < count) { + cli_cmd_tokens_destroy (tokens); + tokens = NULL; + } + + return tokens; +} + + +char ** +cli_rl_get_matches (struct cli_state *state, struct cli_cmd_word *word, + const char *text) +{ + char **matches = NULL; + char **matchesp = NULL; + struct cli_cmd_word **next = NULL; + int count = 0; + int len = 0; + + len = strlen (text); + + if (!word->nextwords) + return NULL; + + for (next = word->nextwords; *next; next++) + count++; + + matches = calloc (count + 1, sizeof (*matches)); + matchesp = matches; + + for (next = word->nextwords; *next; next++) { + if ((*next)->match) { + continue; + } + + if (strncmp ((*next)->word, text, len) == 0) { + *matchesp = strdup ((*next)->word); + matchesp++; + } + } + + return matches; +} + + +int +cli_rl_autocomplete_prepare (struct cli_state *state, const char *text) +{ + struct cli_cmd_word *word = NULL; + struct cli_cmd_word *next = NULL; + char **tokens = NULL; + char **tokenp = NULL; + char *token = NULL; + char **matches = NULL; + + tokens = cli_rl_tokenize (text); + if (!tokens) + return 0; + + word = &state->tree.root; + + for (tokenp = tokens; (token = *tokenp); tokenp++) { + if (!*(tokenp+1)) { + /* last word */ + break; + } + + next = cli_cmd_nextword (word, token); + word = next; + if (!word) + break; + } + + if (!word) + goto out; + + matches = cli_rl_get_matches (state, word, token); + + state->matches = matches; + state->matchesp = matches; + +out: + cli_cmd_tokens_destroy (tokens); + return 0; +} + + +int +cli_rl_autocomplete_cleanup (struct cli_state *state) +{ + if (state->matches) + cli_cmd_tokens_destroy (state->matches); + + state->matches = NULL; + state->matchesp = NULL; + + return 0; +} + + +char ** +cli_rl_autocomplete (const char *text, int start, int end) +{ + struct cli_state *state = NULL; + char **matches = NULL; + char save = 0; + + state = global_state; + + /* hack to make the autocompletion code neater */ + /* fake it as though the cursor is at the end of line */ + + save = rl_line_buffer[rl_point]; + rl_line_buffer[rl_point] = 0; + + cli_rl_autocomplete_prepare (state, rl_line_buffer); + + matches = rl_completion_matches (text, cli_rl_autocomplete_entry); + + cli_rl_autocomplete_cleanup (state); + + rl_line_buffer[rl_point] = save; + + return matches; +} + + +static char * +complete_none (const char *txt, int times) +{ + return NULL; +} + + +int +cli_rl_enable (struct cli_state *state) +{ + int ret = 0; + + rl_pre_input_hook = NULL; + rl_attempted_completion_function = cli_rl_autocomplete; + rl_completion_entry_function = complete_none; + + ret = event_register (state->ctx->event_pool, 0, cli_rl_stdin, state, + 1, 0); + if (ret == -1) + goto out; + + state->rl_enabled = 1; + rl_callback_handler_install (state->prompt, cli_rl_process_line); + +out: + return state->rl_enabled; +} + +#else /* HAVE_READLINE */ + +int +cli_rl_enable (struct cli_state *state) +{ + return 0; +} + +#endif /* HAVE_READLINE */ |