lineedit: fix problems with empty commands in history
No binary (build failed)
—
(log yok)
| @@ -956,24 +956,33 @@ static void input_tab(smallint *lastWasTab) | |
| #if MAX_HISTORY > 0 | |
| + | static void save_command_ps_at_cur_history(void) |
| + | { |
| + | if (command_ps[0] != '\0') { |
| + | int cur = state->cur_history; |
| + | free(state->history[cur]); |
| + | state->history[cur] = xstrdup(command_ps); |
| + | } |
| + | } |
| + | |
| /* state->flags is already checked to be nonzero */ | |
| - | static void get_previous_history(void) |
| + | static int get_previous_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 ((state->flags & DO_HISTORY) && state->cur_history) { |
| + | save_command_ps_at_cur_history(); |
| + | state->cur_history--; |
| + | return 1; |
| } | |
| - | state->cur_history--; |
| + | 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; | |