diff options
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 000000000..bc2e80eba --- /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 */  | 
