From 82a855bda889634ebaa80ae21a1059e006130a91 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 14 Nov 2010 20:59:29 +0200 Subject: [PATCH] Move command line editing routines into src/utils/edit*.[ch] This allows the same routines to be shared with other programs since these are not really specific to wpa_cli. --- src/utils/edit.c | 530 ++++++++++++++++++++++++++++++++++++ src/utils/edit.h | 25 ++ src/utils/edit_simple.c | 90 +++++++ wpa_supplicant/Makefile | 8 +- wpa_supplicant/wpa_cli.c | 568 ++------------------------------------- 5 files changed, 674 insertions(+), 547 deletions(-) create mode 100644 src/utils/edit.c create mode 100644 src/utils/edit.h create mode 100644 src/utils/edit_simple.c diff --git a/src/utils/edit.c b/src/utils/edit.c new file mode 100644 index 000000000..5bda498ee --- /dev/null +++ b/src/utils/edit.c @@ -0,0 +1,530 @@ +/* + * Command line editing and history + * Copyright (c) 2010, Jouni Malinen + * + * 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 + +#include "common.h" +#include "eloop.h" +#include "edit.h" + +#define CMD_BUF_LEN 256 +static char cmdbuf[CMD_BUF_LEN]; +static int cmdbuf_pos = 0; +static int cmdbuf_len = 0; +#define CMD_HISTORY_LEN 20 +static char history_buf[CMD_HISTORY_LEN][CMD_BUF_LEN]; +static int history_pos = 0; +static int history_current = 0; + +static void *edit_cb_ctx; +static void (*edit_cmd_cb)(void *ctx, char *cmd); +static void (*edit_eof_cb)(void *ctx); + +static struct termios prevt, newt; + + +void edit_clear_line(void) +{ + int i; + putchar('\r'); + for (i = 0; i < cmdbuf_len + 2; i++) + putchar(' '); +} + + +static void move_start(void) +{ + cmdbuf_pos = 0; + edit_redraw(); +} + + +static void move_end(void) +{ + cmdbuf_pos = cmdbuf_len; + edit_redraw(); +} + + +static void move_left(void) +{ + if (cmdbuf_pos > 0) { + cmdbuf_pos--; + edit_redraw(); + } +} + + +static void move_right(void) +{ + if (cmdbuf_pos < cmdbuf_len) { + cmdbuf_pos++; + edit_redraw(); + } +} + + +static void move_word_left(void) +{ + while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ') + cmdbuf_pos--; + while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ') + cmdbuf_pos--; + edit_redraw(); +} + + +static void move_word_right(void) +{ + while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ') + cmdbuf_pos++; + while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ') + cmdbuf_pos++; + edit_redraw(); +} + + +static void delete_left(void) +{ + if (cmdbuf_pos == 0) + return; + + edit_clear_line(); + os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos, + cmdbuf_len - cmdbuf_pos); + cmdbuf_pos--; + cmdbuf_len--; + edit_redraw(); +} + + +static void delete_current(void) +{ + if (cmdbuf_pos == cmdbuf_len) + return; + + edit_clear_line(); + os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1, + cmdbuf_len - cmdbuf_pos); + cmdbuf_len--; + edit_redraw(); +} + + +static void delete_word(void) +{ + edit_clear_line(); + while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] == ' ') + cmdbuf_len--; + while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] != ' ') + cmdbuf_len--; + edit_redraw(); +} + + +static void clear_left(void) +{ + if (cmdbuf_pos == 0) + return; + + edit_clear_line(); + os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); + cmdbuf_len -= cmdbuf_pos; + cmdbuf_pos = 0; + edit_redraw(); +} + + +static void clear_right(void) +{ + if (cmdbuf_pos == cmdbuf_len) + return; + + edit_clear_line(); + cmdbuf_len = cmdbuf_pos; + edit_redraw(); +} + + +static void history_add(const char *str) +{ + int prev; + + if (str[0] == '\0') + return; + + if (history_pos == 0) + prev = CMD_HISTORY_LEN - 1; + else + prev = history_pos - 1; + if (os_strcmp(history_buf[prev], str) == 0) + return; + + os_strlcpy(history_buf[history_pos], str, CMD_BUF_LEN); + history_pos++; + if (history_pos == CMD_HISTORY_LEN) + history_pos = 0; + history_current = history_pos; +} + + +static void history_prev(void) +{ + int pos; + + if (history_current == (history_pos + 1) % CMD_HISTORY_LEN) + return; + + pos = history_current; + + if (history_current == history_pos && cmdbuf_len) { + cmdbuf[cmdbuf_len] = '\0'; + history_add(cmdbuf); + } + + if (pos > 0) + pos--; + else + pos = CMD_HISTORY_LEN - 1; + if (history_buf[pos][0] == '\0') + return; + history_current = pos; + + edit_clear_line(); + cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]); + os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len); + edit_redraw(); +} + + +static void history_next(void) +{ + if (history_current == history_pos) + return; + + history_current++; + if (history_current == CMD_HISTORY_LEN) + history_current = 0; + + edit_clear_line(); + cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]); + os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len); + edit_redraw(); +} + + +static void history_debug_dump(void) +{ + int p; + edit_clear_line(); + printf("\r"); + p = (history_pos + 1) % CMD_HISTORY_LEN; + for (;;) { + printf("[%d%s%s] %s\n", + p, p == history_current ? "C" : "", + p == history_pos ? "P" : "", history_buf[p]); + if (p == history_pos) + break; + p++; + if (p == CMD_HISTORY_LEN) + p = 0; + } + edit_redraw(); +} + + +static void insert_char(int c) +{ + if (c < 32 && c > 255) { + printf("[%d]\n", c); + edit_redraw(); + } + + if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1) + return; + if (cmdbuf_len == cmdbuf_pos) { + cmdbuf[cmdbuf_pos++] = c; + cmdbuf_len++; + putchar(c); + fflush(stdout); + } else { + os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos, + cmdbuf_len - cmdbuf_pos); + cmdbuf[cmdbuf_pos++] = c; + cmdbuf_len++; + edit_redraw(); + } +} + + +static void process_cmd(void) +{ + + if (cmdbuf_len == 0) { + printf("\n> "); + fflush(stdout); + return; + } + printf("\n"); + cmdbuf[cmdbuf_len] = '\0'; + history_add(cmdbuf); + cmdbuf_pos = 0; + cmdbuf_len = 0; + edit_cmd_cb(edit_cb_ctx, cmdbuf); + printf("> "); + fflush(stdout); +} + + +static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) +{ + int c; + unsigned char buf[1]; + int res; + static int esc = -1; + static char esc_buf[6]; + + res = read(sock, buf, 1); + if (res < 0) + perror("read"); + if (res <= 0) { + edit_eof_cb(edit_cb_ctx); + return; + } + c = buf[0]; + + if (esc >= 0) { + if (esc == 5) { + printf("{ESC%s}[0]\n", esc_buf); + edit_redraw(); + esc = -1; + } else { + esc_buf[esc++] = c; + esc_buf[esc] = '\0'; + if (esc == 1) + return; + } + } + + if (esc == 2 && esc_buf[0] == '[' && c >= 'A' && c <= 'Z') { + switch (c) { + case 'A': /* up */ + history_prev(); + break; + case 'B': /* down */ + history_next(); + break; + case 'C': /* right */ + move_right(); + break; + case 'D': /* left */ + move_left(); + break; + case 'F': /* end */ + move_end(); + break; + case 'H': /* home */ + move_start(); + break; + default: + printf("{ESC%s}[1]\n", esc_buf); + edit_redraw(); + break; + } + esc = -1; + return; + } + + if (esc > 1 && esc_buf[0] == '[') { + if ((c >= '0' && c <= '9') || c == ';') + return; + + if (esc_buf[1] == '1' && esc_buf[2] == ';' && + esc_buf[3] == '5') { + switch (esc_buf[4]) { + case 'A': /* Ctrl-Up */ + case 'B': /* Ctrl-Down */ + break; + case 'C': /* Ctrl-Right */ + move_word_right(); + break; + case 'D': /* Ctrl-Left */ + move_word_left(); + break; + default: + printf("{ESC%s}[2]\n", esc_buf); + edit_redraw(); + break; + } + esc = -1; + return; + } + + switch (c) { + case '~': + switch (atoi(&esc_buf[1])) { + case 2: /* Insert */ + break; + case 3: /* Delete */ + delete_current(); + break; + case 5: /* Page Up */ + case 6: /* Page Down */ + case 15: /* F5 */ + case 17: /* F6 */ + case 18: /* F7 */ + case 19: /* F8 */ + case 20: /* F9 */ + case 21: /* F10 */ + case 23: /* F11 */ + case 24: /* F12 */ + break; + default: + printf("{ESC%s}[3]\n", esc_buf); + edit_redraw(); + break; + } + break; + default: + printf("{ESC%s}[4]\n", esc_buf); + edit_redraw(); + break; + } + + esc = -1; + return; + } + + if (esc > 1 && esc_buf[0] == 'O') { + switch (esc_buf[1]) { + case 'P': /* F1 */ + history_debug_dump(); + break; + case 'Q': /* F2 */ + case 'R': /* F3 */ + case 'S': /* F4 */ + break; + default: + printf("{ESC%s}[5]\n", esc_buf); + edit_redraw(); + break; + } + esc = -1; + return; + } + + if (esc > 1) { + printf("{ESC%s}[6]\n", esc_buf); + edit_redraw(); + esc = -1; + return; + } + + switch (c) { + case 1: /* ^A */ + move_start(); + break; + case 4: /* ^D */ + if (cmdbuf_len > 0) { + delete_current(); + return; + } + printf("\n"); + edit_eof_cb(edit_cb_ctx); + break; + case 5: /* ^E */ + move_end(); + break; + case 8: /* ^H = BS */ + delete_left(); + break; + case 9: /* ^I = TAB */ + break; + case 10: /* NL */ + case 13: /* CR */ + process_cmd(); + break; + case 11: /* ^K */ + clear_right(); + break; + case 14: /* ^N */ + history_next(); + break; + case 16: /* ^P */ + history_prev(); + break; + case 18: /* ^R */ + /* TODO: search history */ + break; + case 21: /* ^U */ + clear_left(); + break; + case 23: /* ^W */ + delete_word(); + break; + case 27: /* ESC */ + esc = 0; + break; + case 127: /* DEL */ + delete_left(); + break; + default: + insert_char(c); + break; + } +} + + +int edit_init(void (*cmd_cb)(void *ctx, char *cmd), + void (*eof_cb)(void *ctx), + void *ctx) +{ + os_memset(history_buf, 0, sizeof(history_buf)); + + edit_cb_ctx = ctx; + edit_cmd_cb = cmd_cb; + edit_eof_cb = eof_cb; + + tcgetattr(STDIN_FILENO, &prevt); + newt = prevt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); + + return 0; +} + + +void edit_deinit(void) +{ + eloop_unregister_read_sock(STDIN_FILENO); + tcsetattr(STDIN_FILENO, TCSANOW, &prevt); +} + + +void edit_redraw(void) +{ + char tmp; + cmdbuf[cmdbuf_len] = '\0'; + printf("\r> %s", cmdbuf); + if (cmdbuf_pos != cmdbuf_len) { + tmp = cmdbuf[cmdbuf_pos]; + cmdbuf[cmdbuf_pos] = '\0'; + printf("\r> %s", cmdbuf); + cmdbuf[cmdbuf_pos] = tmp; + } + fflush(stdout); +} diff --git a/src/utils/edit.h b/src/utils/edit.h new file mode 100644 index 000000000..7f3efc2bf --- /dev/null +++ b/src/utils/edit.h @@ -0,0 +1,25 @@ +/* + * Command line editing and history + * Copyright (c) 2010, Jouni Malinen + * + * 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. + */ + +#ifndef EDIT_H +#define EDIT_H + +int edit_init(void (*cmd_cb)(void *ctx, char *cmd), + void (*eof_cb)(void *ctx), + void *ctx); +void edit_deinit(void); +void edit_clear_line(void); +void edit_redraw(void); + +#endif /* EDIT_H */ diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c new file mode 100644 index 000000000..ecb4ec98c --- /dev/null +++ b/src/utils/edit_simple.c @@ -0,0 +1,90 @@ +/* + * Minimal command line editing + * Copyright (c) 2010, Jouni Malinen + * + * 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 "common.h" +#include "eloop.h" +#include "edit.h" + + +#define CMD_BUF_LEN 256 +static char cmdbuf[CMD_BUF_LEN]; +static int cmdbuf_pos = 0; + +static void *edit_cb_ctx; +static void (*edit_cmd_cb)(void *ctx, char *cmd); +static void (*edit_eof_cb)(void *ctx); + + +static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) +{ + int c; + unsigned char buf[1]; + int res; + + res = read(sock, buf, 1); + if (res < 0) + perror("read"); + if (res <= 0) { + edit_eof_cb(edit_cb_ctx); + return; + } + c = buf[0]; + + if (c == '\r' || c == '\n') { + cmdbuf[cmdbuf_pos] = '\0'; + cmdbuf_pos = 0; + edit_cmd_cb(edit_cb_ctx, cmdbuf); + printf("> "); + fflush(stdout); + return; + } + + if (c >= 32 && c <= 255) { + if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) { + cmdbuf[cmdbuf_pos++] = c; + } + } +} + + +int edit_init(void (*cmd_cb)(void *ctx, char *cmd), + void (*eof_cb)(void *ctx), + void *ctx) +{ + edit_cb_ctx = ctx; + edit_cmd_cb = cmd_cb; + edit_eof_cb = eof_cb; + eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); + return 0; +} + + +void edit_deinit(void) +{ + eloop_unregister_read_sock(STDIN_FILENO); +} + + +void edit_clear_line(void) +{ +} + + +void edit_redraw(void) +{ + cmdbuf[cmdbuf_pos] = '\0'; + printf("\r> %s", cmdbuf); +} diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 5c7a04473..d7700b45d 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1148,10 +1148,12 @@ LIBS += $(DBUS_LIBS) ifdef CONFIG_READLINE CFLAGS += -DCONFIG_READLINE LIBS_c += -lncurses -lreadline -endif - +else ifdef CONFIG_WPA_CLI_EDIT -CFLAGS += -DCONFIG_WPA_CLI_EDIT +OBJS_c += ../src/utils/edit.o +else +OBJS_c += ../src/utils/edit_simple.o +endif endif ifdef CONFIG_NATIVE_WINDOWS diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index d9cd9c386..c6d7e80f7 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -13,9 +13,6 @@ */ #include "includes.h" -#ifdef CONFIG_WPA_CLI_EDIT -#include -#endif /* CONFIG_WPA_CLI_EDIT */ #ifdef CONFIG_CTRL_IFACE @@ -30,6 +27,7 @@ #include "common/wpa_ctrl.h" #include "utils/common.h" #include "utils/eloop.h" +#include "utils/edit.h" #include "common/version.h" @@ -102,18 +100,6 @@ static const char *pid_file = NULL; static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; -#ifndef CONFIG_READLINE -#define CMD_BUF_LEN 256 -static char cmdbuf[CMD_BUF_LEN]; -static int cmdbuf_pos = 0; -static int cmdbuf_len = 0; -#endif /* CONFIG_READLINE */ -#ifdef CONFIG_WPA_CLI_EDIT -#define CMD_HISTORY_LEN 20 -static char history_buf[CMD_HISTORY_LEN][CMD_BUF_LEN]; -static int history_pos = 0; -static int history_current = 0; -#endif /* CONFIG_WPA_CLI_EDIT */ static void print_help(void); @@ -144,16 +130,7 @@ static void readline_redraw() rl_on_new_line(); rl_redisplay(); #else /* CONFIG_READLINE */ - char tmp; - cmdbuf[cmdbuf_len] = '\0'; - printf("\r> %s", cmdbuf); - if (cmdbuf_pos != cmdbuf_len) { - tmp = cmdbuf[cmdbuf_pos]; - cmdbuf[cmdbuf_pos] = '\0'; - printf("\r> %s", cmdbuf); - cmdbuf[cmdbuf_pos] = tmp; - } - fflush(stdout); + edit_redraw(); #endif /* CONFIG_READLINE */ } @@ -2659,6 +2636,9 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) wpa_cli_action_process(buf); else { if (wpa_cli_show_event(buf)) { +#ifndef CONFIG_READLINE + edit_clear_line(); +#endif /* CONFIG_READLINE */ printf("\r%s\n", buf); readline_redraw(); } @@ -2708,19 +2688,6 @@ static int tokenize_cmd(char *cmd, char *argv[]) } -static void trunc_nl(char *str) -{ - char *pos = str; - while (*pos != '\0') { - if (*pos == '\n') { - *pos = '\0'; - break; - } - pos++; - } -} - - static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { @@ -2832,6 +2799,19 @@ static void wpa_cli_read_char(int sock, void *eloop_ctx, void *sock_ctx) } +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) { int argc; @@ -2922,540 +2902,40 @@ static void wpa_cli_interactive(void) #else /* CONFIG_READLINE */ -#ifdef CONFIG_WPA_CLI_EDIT -static void wpa_cli_clear_line(void) -{ - int i; - putchar('\r'); - for (i = 0; i < cmdbuf_len + 2; i++) - putchar(' '); -} - - -static void move_start(void) -{ - cmdbuf_pos = 0; - readline_redraw(); -} - - -static void move_end(void) -{ - cmdbuf_pos = cmdbuf_len; - readline_redraw(); -} - - -static void move_left(void) -{ - if (cmdbuf_pos > 0) { - cmdbuf_pos--; - readline_redraw(); - } -} - - -static void move_right(void) -{ - if (cmdbuf_pos < cmdbuf_len) { - cmdbuf_pos++; - readline_redraw(); - } -} - - -static void move_word_left(void) -{ - while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ') - cmdbuf_pos--; - while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ') - cmdbuf_pos--; - readline_redraw(); -} - - -static void move_word_right(void) -{ - while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ') - cmdbuf_pos++; - while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ') - cmdbuf_pos++; - readline_redraw(); -} - - -static void delete_left(void) -{ - if (cmdbuf_pos == 0) - return; - - wpa_cli_clear_line(); - os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos, - cmdbuf_len - cmdbuf_pos); - cmdbuf_pos--; - cmdbuf_len--; - readline_redraw(); -} - - -static void delete_current(void) -{ - if (cmdbuf_pos == cmdbuf_len) - return; - - wpa_cli_clear_line(); - os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1, - cmdbuf_len - cmdbuf_pos); - cmdbuf_len--; - readline_redraw(); -} - - -static void delete_word(void) -{ - wpa_cli_clear_line(); - while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] == ' ') - cmdbuf_len--; - while (cmdbuf_len > 0 && cmdbuf[cmdbuf_len - 1] != ' ') - cmdbuf_len--; - readline_redraw(); -} - - -static void clear_left(void) -{ - if (cmdbuf_pos == 0) - return; - - wpa_cli_clear_line(); - os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); - cmdbuf_len -= cmdbuf_pos; - cmdbuf_pos = 0; - readline_redraw(); -} - - -static void clear_right(void) -{ - if (cmdbuf_pos == cmdbuf_len) - return; - - wpa_cli_clear_line(); - cmdbuf_len = cmdbuf_pos; - readline_redraw(); -} - - -static void history_add(const char *str) -{ - int prev; - - if (str[0] == '\0') - return; - - if (history_pos == 0) - prev = CMD_HISTORY_LEN - 1; - else - prev = history_pos - 1; - if (os_strcmp(history_buf[prev], str) == 0) - return; - - os_strlcpy(history_buf[history_pos], str, CMD_BUF_LEN); - history_pos++; - if (history_pos == CMD_HISTORY_LEN) - history_pos = 0; - history_current = history_pos; -} - - -static void history_prev(void) -{ - int pos; - - if (history_current == (history_pos + 1) % CMD_HISTORY_LEN) - return; - - pos = history_current; - - if (history_current == history_pos && cmdbuf_len) { - cmdbuf[cmdbuf_len] = '\0'; - history_add(cmdbuf); - } - - if (pos > 0) - pos--; - else - pos = CMD_HISTORY_LEN - 1; - if (history_buf[pos][0] == '\0') - return; - history_current = pos; - - wpa_cli_clear_line(); - cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]); - os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len); - readline_redraw(); -} - - -static void history_next(void) -{ - if (history_current == history_pos) - return; - - history_current++; - if (history_current == CMD_HISTORY_LEN) - history_current = 0; - - wpa_cli_clear_line(); - cmdbuf_len = cmdbuf_pos = os_strlen(history_buf[history_current]); - os_memcpy(cmdbuf, history_buf[history_current], cmdbuf_len); - readline_redraw(); -} - - -static void history_debug_dump(void) -{ - int p; - wpa_cli_clear_line(); - printf("\r"); - p = (history_pos + 1) % CMD_HISTORY_LEN; - for (;;) { - printf("[%d%s%s] %s\n", - p, p == history_current ? "C" : "", - p == history_pos ? "P" : "", history_buf[p]); - if (p == history_pos) - break; - p++; - if (p == CMD_HISTORY_LEN) - p = 0; - } - readline_redraw(); -} - - -static void insert_char(int c) -{ - if (c < 32 && c > 255) { - printf("[%d]\n", c); - readline_redraw(); - } - - if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1) - return; - if (cmdbuf_len == cmdbuf_pos) { - cmdbuf[cmdbuf_pos++] = c; - cmdbuf_len++; - putchar(c); - fflush(stdout); - } else { - os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos, - cmdbuf_len - cmdbuf_pos); - cmdbuf[cmdbuf_pos++] = c; - cmdbuf_len++; - readline_redraw(); - } -} - - -static void process_cmd(void) +static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd) { char *argv[max_args]; int argc; - - if (cmdbuf_len == 0) { - printf("\n> "); - fflush(stdout); - return; - } - printf("\n"); - cmdbuf[cmdbuf_len] = '\0'; - history_add(cmdbuf); - cmdbuf_pos = 0; - cmdbuf_len = 0; - trunc_nl(cmdbuf); - argc = tokenize_cmd(cmdbuf, argv); + argc = tokenize_cmd(cmd, argv); if (argc) wpa_request(ctrl_conn, argc, argv); - printf("> "); - fflush(stdout); } -static void wpa_cli_read_char(int sock, void *eloop_ctx, void *sock_ctx) +static void wpa_cli_edit_eof_cb(void *ctx) { - int c; - unsigned char buf[1]; - int res; - static int esc = -1; - static char esc_buf[6]; - - res = read(sock, buf, 1); - if (res < 0) - perror("read"); - if (res <= 0) { - eloop_terminate(); - return; - } - c = buf[0]; - - if (esc >= 0) { - if (esc == 5) { - printf("{ESC%s}[0]\n", esc_buf); - readline_redraw(); - esc = -1; - } else { - esc_buf[esc++] = c; - esc_buf[esc] = '\0'; - if (esc == 1) - return; - } - } - - if (esc == 2 && esc_buf[0] == '[' && c >= 'A' && c <= 'Z') { - switch (c) { - case 'A': /* up */ - history_prev(); - break; - case 'B': /* down */ - history_next(); - break; - case 'C': /* right */ - move_right(); - break; - case 'D': /* left */ - move_left(); - break; - case 'F': /* end */ - move_end(); - break; - case 'H': /* home */ - move_start(); - break; - default: - printf("{ESC%s}[1]\n", esc_buf); - readline_redraw(); - break; - } - esc = -1; - return; - } - - if (esc > 1 && esc_buf[0] == '[') { - if ((c >= '0' && c <= '9') || c == ';') - return; - - if (esc_buf[1] == '1' && esc_buf[2] == ';' && - esc_buf[3] == '5') { - switch (esc_buf[4]) { - case 'A': /* Ctrl-Up */ - case 'B': /* Ctrl-Down */ - break; - case 'C': /* Ctrl-Right */ - move_word_right(); - break; - case 'D': /* Ctrl-Left */ - move_word_left(); - break; - default: - printf("{ESC%s}[2]\n", esc_buf); - readline_redraw(); - break; - } - esc = -1; - return; - } - - switch (c) { - case '~': - switch (atoi(&esc_buf[1])) { - case 2: /* Insert */ - break; - case 3: /* Delete */ - delete_current(); - break; - case 5: /* Page Up */ - case 6: /* Page Down */ - case 15: /* F5 */ - case 17: /* F6 */ - case 18: /* F7 */ - case 19: /* F8 */ - case 20: /* F9 */ - case 21: /* F10 */ - case 23: /* F11 */ - case 24: /* F12 */ - break; - default: - printf("{ESC%s}[3]\n", esc_buf); - readline_redraw(); - break; - } - break; - default: - printf("{ESC%s}[4]\n", esc_buf); - readline_redraw(); - break; - } - - esc = -1; - return; - } - - if (esc > 1 && esc_buf[0] == 'O') { - switch (esc_buf[1]) { - case 'P': /* F1 */ - history_debug_dump(); - break; - case 'Q': /* F2 */ - case 'R': /* F3 */ - case 'S': /* F4 */ - break; - default: - printf("{ESC%s}[5]\n", esc_buf); - readline_redraw(); - break; - } - esc = -1; - return; - } - - if (esc > 1) { - printf("{ESC%s}[6]\n", esc_buf); - readline_redraw(); - esc = -1; - return; - } - - switch (c) { - case 1: /* ^A */ - move_start(); - break; - case 4: /* ^D */ - if (cmdbuf_len > 0) { - delete_current(); - return; - } - printf("\n"); - eloop_terminate(); - break; - case 5: /* ^E */ - move_end(); - break; - case 8: /* ^H = BS */ - delete_left(); - break; - case 9: /* ^I = TAB */ - break; - case 10: /* NL */ - case 13: /* CR */ - process_cmd(); - break; - case 11: /* ^K */ - clear_right(); - break; - case 14: /* ^N */ - history_next(); - break; - case 16: /* ^P */ - history_prev(); - break; - case 18: /* ^R */ - /* TODO: search history */ - break; - case 21: /* ^U */ - clear_left(); - break; - case 23: /* ^W */ - delete_word(); - break; - case 27: /* ESC */ - esc = 0; - break; - case 127: /* DEL */ - delete_left(); - break; - default: - insert_char(c); - break; - } + eloop_terminate(); } -#else /* CONFIG_WPA_CLI_EDIT */ - -static void wpa_cli_read_char(int sock, void *eloop_ctx, void *sock_ctx) -{ - char *argv[max_args]; - int argc; - int c; - unsigned char buf[1]; - int res; - - res = read(sock, buf, 1); - if (res < 0) - perror("read"); - if (res <= 0) { - eloop_terminate(); - return; - } - c = buf[0]; - - if (c == '\r' || c == '\n') { - cmdbuf[cmdbuf_pos] = '\0'; - cmdbuf_pos = 0; - trunc_nl(cmdbuf); - argc = tokenize_cmd(cmdbuf, argv); - if (argc) - wpa_request(ctrl_conn, argc, argv); - printf("> "); - fflush(stdout); - return; - } - - if (c >= 32 && c <= 255) { - if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) { - cmdbuf[cmdbuf_pos++] = c; - } - } -} - -#endif /* CONFIG_WPA_CLI_EDIT */ - static void wpa_cli_interactive(void) { -#ifdef CONFIG_WPA_CLI_EDIT - struct termios prevt, newt; -#endif /* CONFIG_WPA_CLI_EDIT */ printf("\nInteractive mode\n\n"); - cmdbuf_pos = 0; - cmdbuf_len = 0; eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL); - eloop_register_read_sock(STDIN_FILENO, wpa_cli_read_char, NULL, NULL); + edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, NULL); eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); -#ifdef CONFIG_WPA_CLI_EDIT - os_memset(history_buf, 0, sizeof(history_buf)); - - tcgetattr(STDIN_FILENO, &prevt); - newt = prevt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); -#endif /* CONFIG_WPA_CLI_EDIT */ - printf("> "); fflush(stdout); eloop_run(); - eloop_unregister_read_sock(STDIN_FILENO); + edit_deinit(); eloop_cancel_timeout(wpa_cli_ping, NULL, NULL); wpa_cli_close_connection(); - -#ifdef CONFIG_WPA_CLI_EDIT - tcsetattr(STDIN_FILENO, TCSANOW, &prevt); -#endif /* CONFIG_WPA_CLI_EDIT */ } #endif /* CONFIG_READLINE */