summaryrefslogtreecommitdiffstats
path: root/cli/src/cli-rl.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli/src/cli-rl.c')
-rw-r--r--cli/src/cli-rl.c368
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 */