diff options
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 73 |
1 files changed, 47 insertions, 26 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) | |||
956 | 956 | ||
957 | #if MAX_HISTORY > 0 | 957 | #if MAX_HISTORY > 0 |
958 | 958 | ||
959 | static void save_command_ps_at_cur_history(void) | ||
960 | { | ||
961 | if (command_ps[0] != '\0') { | ||
962 | int cur = state->cur_history; | ||
963 | free(state->history[cur]); | ||
964 | state->history[cur] = xstrdup(command_ps); | ||
965 | } | ||
966 | } | ||
967 | |||
959 | /* state->flags is already checked to be nonzero */ | 968 | /* state->flags is already checked to be nonzero */ |
960 | static void get_previous_history(void) | 969 | static int get_previous_history(void) |
961 | { | 970 | { |
962 | if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) { | 971 | if ((state->flags & DO_HISTORY) && state->cur_history) { |
963 | free(state->history[state->cur_history]); | 972 | save_command_ps_at_cur_history(); |
964 | state->history[state->cur_history] = xstrdup(command_ps); | 973 | state->cur_history--; |
974 | return 1; | ||
965 | } | 975 | } |
966 | state->cur_history--; | 976 | beep(); |
977 | return 0; | ||
967 | } | 978 | } |
968 | 979 | ||
969 | static int get_next_history(void) | 980 | static int get_next_history(void) |
970 | { | 981 | { |
971 | if (state->flags & DO_HISTORY) { | 982 | if (state->flags & DO_HISTORY) { |
972 | int ch = state->cur_history; | 983 | if (state->cur_history < state->cnt_history) { |
973 | if (ch < state->cnt_history) { | 984 | save_command_ps_at_cur_history(); /* save the current history line */ |
974 | get_previous_history(); /* save the current history line */ | 985 | return ++state->cur_history; |
975 | state->cur_history = ch + 1; | ||
976 | return state->cur_history; | ||
977 | } | 986 | } |
978 | } | 987 | } |
979 | beep(); | 988 | beep(); |
@@ -995,6 +1004,7 @@ static void load_history(const char *fromfile) | |||
995 | for (hi = state->cnt_history; hi > 0;) { | 1004 | for (hi = state->cnt_history; hi > 0;) { |
996 | hi--; | 1005 | hi--; |
997 | free(state->history[hi]); | 1006 | free(state->history[hi]); |
1007 | state->history[hi] = NULL; | ||
998 | } | 1008 | } |
999 | 1009 | ||
1000 | for (hi = 0; hi < MAX_HISTORY;) { | 1010 | for (hi = 0; hi < MAX_HISTORY;) { |
@@ -1006,14 +1016,14 @@ static void load_history(const char *fromfile) | |||
1006 | l = strlen(hl); | 1016 | l = strlen(hl); |
1007 | if (l >= MAX_LINELEN) | 1017 | if (l >= MAX_LINELEN) |
1008 | hl[MAX_LINELEN-1] = '\0'; | 1018 | hl[MAX_LINELEN-1] = '\0'; |
1009 | if (l == 0 || hl[0] == ' ') { | 1019 | if (l == 0) { |
1010 | free(hl); | 1020 | free(hl); |
1011 | continue; | 1021 | continue; |
1012 | } | 1022 | } |
1013 | state->history[hi++] = hl; | 1023 | state->history[hi++] = hl; |
1014 | } | 1024 | } |
1015 | fclose(fp); | 1025 | fclose(fp); |
1016 | state->cur_history = state->cnt_history = hi; | 1026 | state->cnt_history = hi; |
1017 | } | 1027 | } |
1018 | } | 1028 | } |
1019 | 1029 | ||
@@ -1043,19 +1053,27 @@ static void remember_in_history(const char *str) | |||
1043 | 1053 | ||
1044 | if (!(state->flags & DO_HISTORY)) | 1054 | if (!(state->flags & DO_HISTORY)) |
1045 | return; | 1055 | return; |
1046 | 1056 | if (str[0] == '\0') | |
1057 | return; | ||
1047 | i = state->cnt_history; | 1058 | i = state->cnt_history; |
1048 | free(state->history[MAX_HISTORY]); | 1059 | /* Don't save dupes */ |
1049 | state->history[MAX_HISTORY] = NULL; | 1060 | if (i && strcmp(state->history[i-1], str) == 0) |
1050 | /* After max history, remove the oldest command */ | 1061 | return; |
1062 | |||
1063 | free(state->history[MAX_HISTORY]); /* redundant, paranoia */ | ||
1064 | state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */ | ||
1065 | |||
1066 | /* If history[] is full, remove the oldest command */ | ||
1067 | /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */ | ||
1051 | if (i >= MAX_HISTORY) { | 1068 | if (i >= MAX_HISTORY) { |
1052 | free(state->history[0]); | 1069 | free(state->history[0]); |
1053 | for (i = 0; i < MAX_HISTORY-1; i++) | 1070 | for (i = 0; i < MAX_HISTORY-1; i++) |
1054 | state->history[i] = state->history[i+1]; | 1071 | state->history[i] = state->history[i+1]; |
1072 | /* i == MAX_HISTORY-1 */ | ||
1055 | } | 1073 | } |
1056 | // Maybe "if (!i || strcmp(history[i-1], command) != 0) ..." | 1074 | /* i <= MAX_HISTORY-1 */ |
1057 | // (i.e. do not save dups?) | ||
1058 | state->history[i++] = xstrdup(str); | 1075 | state->history[i++] = xstrdup(str); |
1076 | /* i <= MAX_HISTORY */ | ||
1059 | state->cur_history = i; | 1077 | state->cur_history = i; |
1060 | state->cnt_history = i; | 1078 | state->cnt_history = i; |
1061 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1079 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -1397,6 +1415,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1397 | if ((state->flags & SAVE_HISTORY) && state->hist_file) | 1415 | if ((state->flags & SAVE_HISTORY) && state->hist_file) |
1398 | load_history(state->hist_file); | 1416 | load_history(state->hist_file); |
1399 | #endif | 1417 | #endif |
1418 | state->cur_history = state->cnt_history; | ||
1400 | 1419 | ||
1401 | /* prepare before init handlers */ | 1420 | /* prepare before init handlers */ |
1402 | cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ | 1421 | 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 | |||
1432 | } | 1451 | } |
1433 | } | 1452 | } |
1434 | #endif | 1453 | #endif |
1454 | |||
1455 | #if 0 | ||
1456 | for (ic = 0; ic <= MAX_HISTORY; ic++) | ||
1457 | bb_error_msg("history[%d]:'%s'", ic, state->history[ic]); | ||
1458 | bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history); | ||
1459 | #endif | ||
1460 | |||
1435 | /* Print out the command prompt */ | 1461 | /* Print out the command prompt */ |
1436 | parse_and_put_prompt(prompt); | 1462 | parse_and_put_prompt(prompt); |
1437 | 1463 | ||
@@ -1540,11 +1566,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1540 | vi_case(CTRL('P')|vbit:) | 1566 | vi_case(CTRL('P')|vbit:) |
1541 | vi_case('k'|vbit:) | 1567 | vi_case('k'|vbit:) |
1542 | /* Control-p -- Get previous command from history */ | 1568 | /* Control-p -- Get previous command from history */ |
1543 | if ((state->flags & DO_HISTORY) && state->cur_history > 0) { | 1569 | if (get_previous_history()) |
1544 | get_previous_history(); | ||
1545 | goto rewrite_line; | 1570 | goto rewrite_line; |
1546 | } | ||
1547 | beep(); | ||
1548 | break; | 1571 | break; |
1549 | #endif | 1572 | #endif |
1550 | 1573 | ||
@@ -1733,10 +1756,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1733 | #if MAX_HISTORY > 0 | 1756 | #if MAX_HISTORY > 0 |
1734 | case 'A': | 1757 | case 'A': |
1735 | /* Up Arrow -- Get previous command from history */ | 1758 | /* Up Arrow -- Get previous command from history */ |
1736 | if ((state->flags & DO_HISTORY) && state->cur_history > 0) { | 1759 | if (get_previous_history()) |
1737 | get_previous_history(); | ||
1738 | goto rewrite_line; | 1760 | goto rewrite_line; |
1739 | } | ||
1740 | beep(); | 1761 | beep(); |
1741 | break; | 1762 | break; |
1742 | case 'B': | 1763 | case 'B': |
@@ -1746,7 +1767,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1746 | rewrite_line: | 1767 | rewrite_line: |
1747 | /* Rewrite the line with the selected history item */ | 1768 | /* Rewrite the line with the selected history item */ |
1748 | /* change command */ | 1769 | /* change command */ |
1749 | command_len = strlen(strcpy(command, state->history[state->cur_history])); | 1770 | command_len = strlen(strcpy(command, state->history[state->cur_history] ? : "")); |
1750 | /* redraw and go to eol (bol, in vi */ | 1771 | /* redraw and go to eol (bol, in vi */ |
1751 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); | 1772 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); |
1752 | break; | 1773 | break; |