From 682ad3045c11f6d8961306b1a364289c2aae35ef Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 27 Sep 2008 01:28:56 +0000 Subject: [PATCH] lineedit: fix problems with empty commands in history --- libbb/lineedit.c | 75 +++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index a68e5a3c0..c2c3ea996 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -956,24 +956,33 @@ static void input_tab(smallint *lastWasTab) #if MAX_HISTORY > 0 -/* state->flags is already checked to be nonzero */ -static void get_previous_history(void) +static void save_command_ps_at_cur_history(void) { - if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) { - free(state->history[state->cur_history]); - state->history[state->cur_history] = xstrdup(command_ps); + if (command_ps[0] != '\0') { + int cur = state->cur_history; + free(state->history[cur]); + state->history[cur] = xstrdup(command_ps); } - state->cur_history--; +} + +/* state->flags is already checked to be nonzero */ +static int get_previous_history(void) +{ + if ((state->flags & DO_HISTORY) && state->cur_history) { + save_command_ps_at_cur_history(); + state->cur_history--; + return 1; + } + beep(); + return 0; } static int get_next_history(void) { if (state->flags & DO_HISTORY) { - int ch = state->cur_history; - if (ch < state->cnt_history) { - get_previous_history(); /* save the current history line */ - state->cur_history = ch + 1; - return state->cur_history; + if (state->cur_history < state->cnt_history) { + save_command_ps_at_cur_history(); /* save the current history line */ + return ++state->cur_history; } } beep(); @@ -995,6 +1004,7 @@ static void load_history(const char *fromfile) for (hi = state->cnt_history; hi > 0;) { hi--; free(state->history[hi]); + state->history[hi] = NULL; } for (hi = 0; hi < MAX_HISTORY;) { @@ -1006,14 +1016,14 @@ static void load_history(const char *fromfile) l = strlen(hl); if (l >= MAX_LINELEN) hl[MAX_LINELEN-1] = '\0'; - if (l == 0 || hl[0] == ' ') { + if (l == 0) { free(hl); continue; } state->history[hi++] = hl; } fclose(fp); - state->cur_history = state->cnt_history = hi; + state->cnt_history = hi; } } @@ -1043,19 +1053,27 @@ static void remember_in_history(const char *str) if (!(state->flags & DO_HISTORY)) return; - + if (str[0] == '\0') + return; i = state->cnt_history; - free(state->history[MAX_HISTORY]); - state->history[MAX_HISTORY] = NULL; - /* After max history, remove the oldest command */ + /* Don't save dupes */ + if (i && strcmp(state->history[i-1], str) == 0) + return; + + free(state->history[MAX_HISTORY]); /* redundant, paranoia */ + state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */ + + /* If history[] is full, remove the oldest command */ + /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */ if (i >= MAX_HISTORY) { free(state->history[0]); for (i = 0; i < MAX_HISTORY-1; i++) state->history[i] = state->history[i+1]; + /* i == MAX_HISTORY-1 */ } -// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..." -// (i.e. do not save dups?) + /* i <= MAX_HISTORY-1 */ state->history[i++] = xstrdup(str); + /* i <= MAX_HISTORY */ state->cur_history = i; state->cnt_history = i; #if ENABLE_FEATURE_EDITING_SAVEHISTORY @@ -1397,6 +1415,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li if ((state->flags & SAVE_HISTORY) && state->hist_file) load_history(state->hist_file); #endif + state->cur_history = state->cnt_history; /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ @@ -1432,6 +1451,13 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li } } #endif + +#if 0 + for (ic = 0; ic <= MAX_HISTORY; ic++) + bb_error_msg("history[%d]:'%s'", ic, state->history[ic]); + bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history); +#endif + /* Print out the command prompt */ parse_and_put_prompt(prompt); @@ -1540,11 +1566,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li vi_case(CTRL('P')|vbit:) vi_case('k'|vbit:) /* Control-p -- Get previous command from history */ - if ((state->flags & DO_HISTORY) && state->cur_history > 0) { - get_previous_history(); + if (get_previous_history()) goto rewrite_line; - } - beep(); break; #endif @@ -1733,10 +1756,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #if MAX_HISTORY > 0 case 'A': /* Up Arrow -- Get previous command from history */ - if ((state->flags & DO_HISTORY) && state->cur_history > 0) { - get_previous_history(); + if (get_previous_history()) goto rewrite_line; - } beep(); break; case 'B': @@ -1746,7 +1767,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li rewrite_line: /* Rewrite the line with the selected history item */ /* change command */ - command_len = strlen(strcpy(command, state->history[state->cur_history])); + command_len = strlen(strcpy(command, state->history[state->cur_history] ? : "")); /* redraw and go to eol (bol, in vi */ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); break;