]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Move wpa_cli readline integration into src/utils/edit_readline.c
authorJouni Malinen <j@w1.fi>
Sun, 14 Nov 2010 20:37:43 +0000 (22:37 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 14 Nov 2010 20:37:43 +0000 (22:37 +0200)
All three line editing options are now located in src/utils/edit*.c
and provide the same API to allow easy build time selection.

src/utils/edit.c
src/utils/edit.h
src/utils/edit_readline.c [new file with mode: 0644]
src/utils/edit_simple.c
wpa_supplicant/Makefile
wpa_supplicant/wpa_cli.c

index 9737325db6c77b712b8169a00542af80571b0ff3..590e79d37ce4e4d4a44b1eab4e7929d4cb181cb6 100644 (file)
@@ -536,3 +536,13 @@ void edit_redraw(void)
        }
        fflush(stdout);
 }
+
+
+void edit_set_filter_history_cb(int (*cb)(void *ctx, const char *cmd))
+{
+}
+
+
+void edit_set_completion_cb(char ** (*cb)(void *ctx, const char *cmd, int pos))
+{
+}
index 7f3efc2bf17e9c8c3bdf311f80559343476f5439..d674a49d6c0fcc3a7de1986ad188b27073f7d760 100644 (file)
@@ -21,5 +21,8 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
 void edit_deinit(void);
 void edit_clear_line(void);
 void edit_redraw(void);
+void edit_set_filter_history_cb(int (*cb)(void *ctx, const char *cmd));
+void edit_set_completion_cb(char ** (*cb)(void *ctx, const char *cmd,
+                                         int pos));
 
 #endif /* EDIT_H */
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
new file mode 100644 (file)
index 0000000..72d584d
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Command line editing and history wrapper for readline
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * 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.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static int (*edit_filter_history_cb)(void *ctx, const char *cmd) = NULL;
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+       NULL;
+
+static char **pending_completions = NULL;
+
+
+static void readline_free_completions(void)
+{
+       int i;
+       if (pending_completions == NULL)
+               return;
+       for (i = 0; pending_completions[i]; i++)
+               os_free(pending_completions[i]);
+       os_free(pending_completions);
+       pending_completions = NULL;
+}
+
+
+static char * readline_completion_func(const char *text, int state)
+{
+       static int pos = 0;
+       static size_t len = 0;
+
+       if (pending_completions == NULL) {
+               rl_attempted_completion_over = 1;
+               return NULL;
+       }
+
+       if (state == 0) {
+               pos = 0;
+               len = os_strlen(text);
+       }
+       for (; pending_completions[pos]; pos++) {
+               if (strncmp(pending_completions[pos], text, len) == 0)
+                       return strdup(pending_completions[pos++]);
+       }
+
+       rl_attempted_completion_over = 1;
+       return NULL;
+}
+
+
+static char ** readline_completion(const char *text, int start, int end)
+{
+       readline_free_completions();
+       if (edit_completion_cb)
+               pending_completions = edit_completion_cb(edit_cb_ctx,
+                                                        rl_line_buffer, end);
+       return rl_completion_matches(text, readline_completion_func);
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       rl_callback_read_char();
+}
+
+
+static void trunc_nl(char *str)
+{
+       char *pos = str;
+       while (*pos != '\0') {
+               if (*pos == '\n') {
+                       *pos = '\0';
+                       break;
+               }
+               pos++;
+       }
+}
+
+
+static void readline_cmd_handler(char *cmd)
+{
+       if (cmd && *cmd) {
+               HIST_ENTRY *h;
+               while (next_history())
+                       ;
+               h = previous_history();
+               if (h == NULL || os_strcmp(cmd, h->line) != 0)
+                       add_history(cmd);
+               next_history();
+       }
+       if (cmd == NULL) {
+               edit_eof_cb(edit_cb_ctx);
+               return;
+       }
+       trunc_nl(cmd);
+       edit_cmd_cb(edit_cb_ctx, cmd);
+}
+
+
+static char *readline_hfile = NULL;
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+             void (*eof_cb)(void *ctx),
+             void *ctx)
+{
+       char *home;
+
+       edit_cb_ctx = ctx;
+       edit_cmd_cb = cmd_cb;
+       edit_eof_cb = eof_cb;
+
+       rl_attempted_completion_function = readline_completion;
+       home = getenv("HOME");
+       if (home) {
+               const char *fname = ".wpa_cli_history";
+               int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+               readline_hfile = os_malloc(hfile_len);
+               if (readline_hfile) {
+                       int res;
+                       res = os_snprintf(readline_hfile, hfile_len, "%s/%s",
+                                         home, fname);
+                       if (res >= 0 && res < hfile_len) {
+                               readline_hfile[hfile_len - 1] = '\0';
+                               read_history(readline_hfile);
+                               stifle_history(100);
+                       }
+               }
+       }
+
+       eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+       rl_callback_handler_install("> ", readline_cmd_handler);
+
+       return 0;
+}
+
+
+void edit_deinit(void)
+{
+       rl_callback_handler_remove();
+       readline_free_completions();
+
+       eloop_unregister_read_sock(STDIN_FILENO);
+
+       if (readline_hfile) {
+               /* Save command history, excluding lines that may contain
+                * passwords. */
+               HIST_ENTRY *h;
+               history_set_pos(0);
+               while ((h = current_history())) {
+                       char *p = h->line;
+                       while (*p == ' ' || *p == '\t')
+                               p++;
+                       if (edit_filter_history_cb &&
+                           edit_filter_history_cb(edit_cb_ctx, p)) {
+                               h = remove_history(where_history());
+                               if (h) {
+                                       os_free(h->line);
+                                       free(h->data);
+                                       os_free(h);
+                               } else
+                                       next_history();
+                       } else
+                               next_history();
+               }
+               write_history(readline_hfile);
+               os_free(readline_hfile);
+               readline_hfile = NULL;
+       }
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+
+void edit_set_filter_history_cb(int (*cb)(void *ctx, const char *cmd))
+{
+       edit_filter_history_cb = cb;
+}
+
+
+void edit_set_completion_cb(char ** (*cb)(void *ctx, const char *cmd, int pos))
+{
+       edit_completion_cb = cb;
+}
index 305e21e1a7e28217c206df35bfc575f34870802c..c31dc2ea89784eaf470ab40f036bb3a75f1b4643 100644 (file)
@@ -92,3 +92,13 @@ void edit_redraw(void)
        cmdbuf[cmdbuf_pos] = '\0';
        printf("\r> %s", cmdbuf);
 }
+
+
+void edit_set_filter_history_cb(int (*cb)(void *ctx, const char *cmd))
+{
+}
+
+
+void edit_set_completion_cb(char ** (*cb)(void *ctx, const char *cmd, int pos))
+{
+}
index d7700b45db624504c4724f4fd69f4486f729d70b..ee086e31f4d65df1032855434c0acb93e500f242 100644 (file)
@@ -1146,7 +1146,7 @@ CFLAGS += $(DBUS_CFLAGS)
 LIBS += $(DBUS_LIBS)
 
 ifdef CONFIG_READLINE
-CFLAGS += -DCONFIG_READLINE
+OBJS_c += ../src/utils/edit_readline.o
 LIBS_c += -lncurses -lreadline
 else
 ifdef CONFIG_WPA_CLI_EDIT
index 849c6ffe3287fd79a27ca60a93f1dd81ddbc3df5..0c00acff5e16481137668507c7003f1ac1899682 100644 (file)
 #ifdef CONFIG_CTRL_IFACE_UNIX
 #include <dirent.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_READLINE
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif /* CONFIG_READLINE */
 
 #include "common/wpa_ctrl.h"
 #include "utils/common.h"
@@ -2418,8 +2414,7 @@ static void print_help(void)
 }
 
 
-#ifdef CONFIG_READLINE
-static int cmd_has_sensitive_data(const char *cmd)
+static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
 {
        const char *c, *delim;
        int n;
@@ -2438,7 +2433,65 @@ static int cmd_has_sensitive_data(const char *cmd)
        }
        return 0;
 }
-#endif /* CONFIG_READLINE */
+
+
+static char ** wpa_list_cmd_list(void)
+{
+       char **res;
+       int i, count;
+
+       count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+       res = os_zalloc(count * sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       for (i = 0; wpa_cli_commands[i].cmd; i++) {
+               res[i] = os_strdup(wpa_cli_commands[i].cmd);
+               if (res[i] == NULL)
+                       break;
+       }
+
+       return res;
+}
+
+
+static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
+                                     int pos)
+{
+       int i;
+
+       for (i = 0; wpa_cli_commands[i].cmd; i++) {
+               if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+                       edit_clear_line();
+                       printf("\r%s\n", wpa_cli_commands[i].usage);
+                       edit_redraw();
+                       break;
+               }
+       }
+
+       return NULL;
+}
+
+
+static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos)
+{
+       char **res;
+       const char *end;
+       char *cmd;
+
+       end = os_strchr(str, ' ');
+       if (end == NULL || str + pos < end)
+               return wpa_list_cmd_list();
+
+       cmd = os_malloc(pos + 1);
+       if (cmd == NULL)
+               return NULL;
+       os_memcpy(cmd, str, pos);
+       cmd[end - str] = '\0';
+       res = wpa_cli_cmd_completion(cmd, str, pos);
+       os_free(cmd);
+       return res;
+}
 
 
 static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -2700,215 +2753,6 @@ static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
 }
 
 
-#ifdef CONFIG_READLINE
-
-static void *edit_cb_ctx;
-static void (*edit_cmd_cb)(void *ctx, char *cmd);
-static void (*edit_eof_cb)(void *ctx);
-
-
-static char * wpa_cli_cmd_gen(const char *text, int state)
-{
-       static int i, len;
-       const char *cmd;
-
-       if (state == 0) {
-               i = 0;
-               len = os_strlen(text);
-       }
-
-       while ((cmd = wpa_cli_commands[i].cmd)) {
-               i++;
-               if (os_strncasecmp(cmd, text, len) == 0)
-                       return strdup(cmd);
-       }
-
-       return NULL;
-}
-
-
-static char * wpa_cli_dummy_gen(const char *text, int state)
-{
-       int i;
-
-       for (i = 0; wpa_cli_commands[i].cmd; i++) {
-               const char *cmd = wpa_cli_commands[i].cmd;
-               size_t len = os_strlen(cmd);
-               if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
-                   rl_line_buffer[len] == ' ') {
-                       printf("\n%s\n", wpa_cli_commands[i].usage);
-                       edit_redraw();
-                       break;
-               }
-       }
-
-       rl_attempted_completion_over = 1;
-       return NULL;
-}
-
-
-static char * wpa_cli_status_gen(const char *text, int state)
-{
-       static int i, len;
-       char *options[] = {
-               "verbose", NULL
-       };
-       char *t;
-
-       if (state == 0) {
-               i = 0;
-               len = os_strlen(text);
-       }
-
-       while ((t = options[i])) {
-               i++;
-               if (os_strncasecmp(t, text, len) == 0)
-                       return strdup(t);
-       }
-
-       rl_attempted_completion_over = 1;
-       return NULL;
-}
-
-
-static char ** wpa_cli_completion(const char *text, int start, int end)
-{
-       char * (*func)(const char *text, int state);
-
-       if (start == 0)
-               func = wpa_cli_cmd_gen;
-       else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
-               func = wpa_cli_status_gen;
-       else
-               func = wpa_cli_dummy_gen;
-       return rl_completion_matches(text, func);
-}
-
-
-static void wpa_cli_read_char(int sock, void *eloop_ctx, void *sock_ctx)
-{
-       rl_callback_read_char();
-}
-
-
-static void trunc_nl(char *str)
-{
-       char *pos = str;
-       while (*pos != '\0') {
-               if (*pos == '\n') {
-                       *pos = '\0';
-                       break;
-               }
-               pos++;
-       }
-}
-
-
-static void readline_cmd_handler(char *cmd)
-{
-       if (cmd && *cmd) {
-               HIST_ENTRY *h;
-               while (next_history())
-                       ;
-               h = previous_history();
-               if (h == NULL || os_strcmp(cmd, h->line) != 0)
-                       add_history(cmd);
-               next_history();
-       }
-       if (cmd == NULL) {
-               edit_eof_cb(edit_cb_ctx);
-               return;
-       }
-       trunc_nl(cmd);
-       edit_cmd_cb(edit_cb_ctx, cmd);
-}
-
-
-static char *readline_hfile = NULL;
-
-int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
-             void (*eof_cb)(void *ctx),
-             void *ctx)
-{
-       char *home;
-
-       edit_cb_ctx = ctx;
-       edit_cmd_cb = cmd_cb;
-       edit_eof_cb = eof_cb;
-
-       rl_attempted_completion_function = wpa_cli_completion;
-       home = getenv("HOME");
-       if (home) {
-               const char *fname = ".wpa_cli_history";
-               int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
-               readline_hfile = os_malloc(hfile_len);
-               if (readline_hfile) {
-                       int res;
-                       res = os_snprintf(readline_hfile, hfile_len, "%s/%s",
-                                         home, fname);
-                       if (res >= 0 && res < hfile_len) {
-                               readline_hfile[hfile_len - 1] = '\0';
-                               read_history(readline_hfile);
-                               stifle_history(100);
-                       }
-               }
-       }
-
-       eloop_register_read_sock(STDIN_FILENO, wpa_cli_read_char, NULL, NULL);
-
-       rl_callback_handler_install("> ", readline_cmd_handler);
-
-       return 0;
-}
-
-
-void edit_deinit(void)
-{
-       rl_callback_handler_remove();
-
-       eloop_unregister_read_sock(STDIN_FILENO);
-
-       if (readline_hfile) {
-               /* Save command history, excluding lines that may contain
-                * passwords. */
-               HIST_ENTRY *h;
-               history_set_pos(0);
-               while ((h = current_history())) {
-                       char *p = h->line;
-                       while (*p == ' ' || *p == '\t')
-                               p++;
-                       if (cmd_has_sensitive_data(p)) {
-                               h = remove_history(where_history());
-                               if (h) {
-                                       os_free(h->line);
-                                       free(h->data);
-                                       os_free(h);
-                               } else
-                                       next_history();
-                       } else
-                               next_history();
-               }
-               write_history(readline_hfile);
-               os_free(readline_hfile);
-               readline_hfile = NULL;
-       }
-}
-
-
-void edit_clear_line(void)
-{
-}
-
-
-void edit_redraw(void)
-{
-       rl_on_new_line();
-       rl_redisplay();
-}
-
-#endif /* CONFIG_READLINE */
-
-
 static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
 {
        char *argv[max_args];
@@ -2932,6 +2776,8 @@ static void wpa_cli_interactive(void)
 
        eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL);
        edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, NULL);
+       edit_set_filter_history_cb(wpa_cli_edit_filter_history_cb);
+       edit_set_completion_cb(wpa_cli_edit_completion_cb);
        eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
 
        eloop_run();