From 877510fe9eef4fabc5d724ab57b192e12afb3a1d Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Wed, 9 Jan 2013 14:52:58 +0000 Subject: [PATCH 1/4] Add history support in command mode. --- commands.c | 113 ++++++++++++++++++++++++++++++++++++++++++-------- commands.h | 5 +++ keybindings.c | 3 ++ keybindings.h | 1 + 4 files changed, 104 insertions(+), 18 deletions(-) diff --git a/commands.c b/commands.c index e310fca..102f948 100644 --- a/commands.c +++ b/commands.c @@ -193,6 +193,33 @@ toggle_get(int registr) } +/**************************************************************************** + * Command mode history functions + ***************************************************************************/ + +char **cmd_mode_hist; +size_t cmd_mode_hist_size; + +void +cmd_mode_hist_add(const char *s) +{ + char **new_ptr; + size_t new_size = sizeof *cmd_mode_hist * (cmd_mode_hist_size + 1); + + if (cmd_mode_hist_size + 1 == 0) + errx(1, "%s: overflow", __FUNCTION__); + if (cmd_mode_hist_size + 1 > SIZE_MAX / sizeof *cmd_mode_hist) + errx(1, "%s: overflow", __FUNCTION__); + if ((new_ptr = realloc(cmd_mode_hist, new_size)) == NULL) + err(1, "%s: realloc(3) failed", __FUNCTION__); + cmd_mode_hist = new_ptr; + + if ((cmd_mode_hist[cmd_mode_hist_size] = strdup(s)) == NULL) + err(1, "%s: strdup(3) failed", __FUNCTION__); + cmd_mode_hist_size++; +} + + /**************************************************************************** * Misc handy functions ***************************************************************************/ @@ -967,8 +994,9 @@ int user_getstr(const char *prompt, char **response) { const int MAX_INPUT_SIZE = 1000; /* TODO remove this limit */ - char *input; - int pos, ch, ret; + char *input, *ptr; + int pos, ch, ret; + size_t hist_index = cmd_mode_hist_size; /* display the prompt */ werase(ui.command); @@ -1007,15 +1035,17 @@ user_getstr(const char *prompt, char **response) if (ch == '\n' || ch == 13) break; - /* handle 'escape' */ - if (ch == 27) { + switch (ch) { + case 27: + /* handle 'escape' */ ret = 1; goto end; - } - - /* handle 'backspace' / left-arrow, etc. */ - if (ch == 127 || ch == KEY_BACKSPACE || ch == KEY_LEFT - || ch == KEY_DC || ch == KEY_SDC) { + case 127: + case KEY_BACKSPACE: + case KEY_LEFT: + case KEY_DC: + case KEY_SDC: + /* handle 'backspace' / left-arrow, etc. */ if (pos == 0) { if (ch == KEY_BACKSPACE) { ret = 1; @@ -1029,17 +1059,65 @@ user_getstr(const char *prompt, char **response) pos--; } continue; + case KEY_UP: + if (cmd_mode_hist == NULL) + continue; + + /* redisplay prompt to clean previous entry */ + werase(ui.command); + mvwprintw(ui.command, 0, 0, "%s", prompt); + + /* stay on the first entry if there are no more elements; just like Vim */ + if (hist_index - 1 < cmd_mode_hist_size) + hist_index--; + + ptr = cmd_mode_hist[hist_index]; + + /* copy it to the input buffer */ + strlcpy(input, ptr, MAX_INPUT_SIZE); + pos = strlen(input); + + mvwaddstr(ui.command, 0, strlen(prompt), ptr); + break; + case KEY_DOWN: + if (cmd_mode_hist == NULL) + continue; + + /* redisplay prompt to clean previous entry */ + werase(ui.command); + mvwprintw(ui.command, 0, 0, "%s", prompt); + + /* show an empty prompt if there are no more elements; just like Vim */ + if (hist_index == SIZE_MAX || hist_index + 1 >= cmd_mode_hist_size) { + hist_index = cmd_mode_hist_size; + pos = 0; + continue; + } + + /* retrieve next entry */ + hist_index++; + ptr = cmd_mode_hist[hist_index]; + + /* copy it to the input buffer */ + strlcpy(input, ptr, MAX_INPUT_SIZE); + pos = strlen(input); + + mvwaddstr(ui.command, 0, strlen(prompt), ptr); + break; + default: + /* got regular input. add to buffer. */ + input[pos] = ch; + mvwaddch(ui.command, 0, strlen(prompt) + pos, ch); + pos++; + + /* see todo above - realloc input buffer here if position reaches max */ + if (pos >= MAX_INPUT_SIZE) + errx(1, "user_getstr: shamefull limit reached"); + + break; } - /* got regular input. add to buffer. */ - input[pos] = ch; - mvwaddch(ui.command, 0, strlen(prompt) + pos, ch); wrefresh(ui.command); - pos++; - - /* see todo above - realloc input buffer here if position reaches max */ - if (pos >= MAX_INPUT_SIZE) - errx(1, "user_getstr: shamefull limit reached"); } /* For lack of input, bail out */ @@ -1085,4 +1163,3 @@ user_get_yesno(const char *msg, int *response) free(answer); return 0; } - diff --git a/commands.h b/commands.h index 521efe7..8925cc6 100644 --- a/commands.h +++ b/commands.h @@ -87,6 +87,11 @@ void toggle_add(toggle_list *t); void toggle_remove(int registr); toggle_list* toggle_get(int registr); +/**************************************************************************** + * Command mode history handling stuff + ***************************************************************************/ + +void cmd_mode_hist_add(const char *s); /**************************************************************************** * Misc. diff --git a/keybindings.c b/keybindings.c index 242e868..7b94a30 100644 --- a/keybindings.c +++ b/keybindings.c @@ -1304,6 +1304,9 @@ kba_command_mode(KbaArgs a UNUSED) return; } + /* add entered command to the history */ + cmd_mode_hist_add(cmd); + /* check for '!' used for executing external commands */ if (cmd[0] == '!') { execute_external_command(cmd + 1); diff --git a/keybindings.h b/keybindings.h index 4ad5ccb..ca32263 100644 --- a/keybindings.h +++ b/keybindings.h @@ -19,6 +19,7 @@ #include "compat.h" +#include "commands.h" #include "debug.h" #include "enums.h" #include "paint.h" From 981f3da2f0a99d6c52f498021d40d31280597e50 Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Wed, 9 Jan 2013 14:53:33 +0000 Subject: [PATCH 2/4] Use strdup(3) when saving the response. --- commands.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/commands.c b/commands.c index 102f948..55f6121 100644 --- a/commands.c +++ b/commands.c @@ -1132,10 +1132,8 @@ user_getstr(const char *prompt, char **response) input[pos] = '\0'; /* trim the fat */ - if ((*response = calloc(strlen(input) + 1, sizeof(char))) == NULL) - err(1, "user_getstr: calloc(3) failed for result"); - - snprintf(*response, strlen(input) + 1, "%s", input); + if ((*response = strdup(input)) == NULL) + err(1, "%s: strdup(3) failed for result", __FUNCTION__); end: free(input); From 6e758d84e124de44210e237cb28362cd4039b652 Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Wed, 9 Jan 2013 14:59:29 +0000 Subject: [PATCH 3/4] Remove size limit on user entered strings. --- commands.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/commands.c b/commands.c index 55f6121..3ec824f 100644 --- a/commands.c +++ b/commands.c @@ -993,10 +993,9 @@ cmd_execute(char *cmd) int user_getstr(const char *prompt, char **response) { - const int MAX_INPUT_SIZE = 1000; /* TODO remove this limit */ - char *input, *ptr; - int pos, ch, ret; - size_t hist_index = cmd_mode_hist_size; + char *input, *new_input, *ptr; + int ch, ret; + size_t len, pos, hist_index = cmd_mode_hist_size; /* display the prompt */ werase(ui.command); @@ -1007,15 +1006,9 @@ user_getstr(const char *prompt, char **response) wmove(ui.command, 0, strlen(prompt)); wrefresh(ui.command); - /* allocate input space and clear */ - if ((input = calloc(MAX_INPUT_SIZE, sizeof(char))) == NULL) - err(1, "user_getstr: calloc(3) failed for input string"); - - bzero(input, MAX_INPUT_SIZE); - /* start getting input */ - ret = 0; - pos = 0; + input = NULL; + len = ret = pos = 0; while ((ch = getch()) && !VSIG_QUIT) { /* @@ -1074,8 +1067,10 @@ user_getstr(const char *prompt, char **response) ptr = cmd_mode_hist[hist_index]; /* copy it to the input buffer */ - strlcpy(input, ptr, MAX_INPUT_SIZE); - pos = strlen(input); + free(input); + if ((input = strdup(ptr)) == NULL) + err(1, "%s: strdup(3) failed", __FUNCTION__); + len = pos = strlen(input); mvwaddstr(ui.command, 0, strlen(prompt), ptr); break; @@ -1099,21 +1094,27 @@ user_getstr(const char *prompt, char **response) ptr = cmd_mode_hist[hist_index]; /* copy it to the input buffer */ - strlcpy(input, ptr, MAX_INPUT_SIZE); - pos = strlen(input); + free(input); + if ((input = strdup(ptr)) == NULL) + err(1, "%s: strdup(3) failed", __FUNCTION__); + len = pos = strlen(input); mvwaddstr(ui.command, 0, strlen(prompt), ptr); break; default: /* got regular input. add to buffer. */ + if (pos >= len) { + if (len == SIZE_MAX) + err(1, "%s: overflow", __FUNCTION__); + if ((new_input = realloc(input, len + 2)) == NULL) + err(1, "%s: realloc(3) failed", __FUNCTION__); + input = new_input; + len++; + } + input[pos] = ch; mvwaddch(ui.command, 0, strlen(prompt) + pos, ch); pos++; - - /* see todo above - realloc input buffer here if position reaches max */ - if (pos >= MAX_INPUT_SIZE) - errx(1, "user_getstr: shamefull limit reached"); - break; } @@ -1128,7 +1129,7 @@ user_getstr(const char *prompt, char **response) /* NULL-terminate and trim off trailing whitespace */ input[pos--] = '\0'; - for (; input[pos] == ' ' && pos >= 0; pos--) + for (; input[pos] == ' '; pos--) input[pos] = '\0'; /* trim the fat */ From eb6298c4720c8b731b5a1d7039f4838c8b473d42 Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Wed, 23 Jan 2013 22:06:25 +0000 Subject: [PATCH 4/4] Add shell commands to the history, as well. --- keybindings.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/keybindings.c b/keybindings.c index 7b94a30..b577808 100644 --- a/keybindings.c +++ b/keybindings.c @@ -1322,7 +1322,7 @@ kba_command_mode(KbaArgs a UNUSED) void kba_shell(KbaArgs a UNUSED) { - char *cmd; + char *cmd, *newcmd; /* get command from user */ if (user_getstr("!", &cmd) != 0) { @@ -1330,6 +1330,12 @@ kba_shell(KbaArgs a UNUSED) return; } + /* prepend the exclamation point before adding it to the history */ + if (asprintf(&newcmd, "!%s", cmd) == -1) + err(1, "%s: asprintf failed", __FUNCTION__); + cmd_mode_hist_add(newcmd); + free(newcmd); + execute_external_command(cmd); free(cmd); }