diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:48:57 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:48:57 +0000 |
commit | 9db164d6e39050d09f38288c6045cd2a2cbf6d63 (patch) | |
tree | ea5dc2d28d15da0de25c197ed7d059c3656af1a0 /libbb/lineedit.c | |
parent | 1118c95535ea51961437089fc3dece5ab4ea7e1b (diff) | |
parent | d84b175cb6948eb17f847313bf912174e2f934e1 (diff) | |
download | busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.tar.gz busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.tar.bz2 busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.zip |
Merge commit 'd84b175cb6948eb17f847313bf912174e2f934e1' into merge
Conflicts:
include/platform.h
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 165 |
1 files changed, 153 insertions, 12 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index e443c7a3e..1b97e8609 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -207,18 +207,21 @@ static void deinit_S(void) | |||
207 | 207 | ||
208 | 208 | ||
209 | #if ENABLE_UNICODE_SUPPORT | 209 | #if ENABLE_UNICODE_SUPPORT |
210 | static size_t load_string(const char *src, int maxsize) | 210 | static size_t load_string(const char *src) |
211 | { | 211 | { |
212 | if (unicode_status == UNICODE_ON) { | 212 | if (unicode_status == UNICODE_ON) { |
213 | ssize_t len = mbstowcs(command_ps, src, maxsize - 1); | 213 | ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1); |
214 | if (len < 0) | 214 | if (len < 0) |
215 | len = 0; | 215 | len = 0; |
216 | command_ps[len] = BB_NUL; | 216 | command_ps[len] = BB_NUL; |
217 | return len; | 217 | return len; |
218 | } else { | 218 | } else { |
219 | unsigned i = 0; | 219 | unsigned i = 0; |
220 | while ((command_ps[i] = src[i]) != 0) | 220 | while (src[i] && i < S.maxsize - 1) { |
221 | command_ps[i] = src[i]; | ||
221 | i++; | 222 | i++; |
223 | } | ||
224 | command_ps[i] = BB_NUL; | ||
222 | return i; | 225 | return i; |
223 | } | 226 | } |
224 | } | 227 | } |
@@ -319,9 +322,9 @@ static wchar_t adjust_width_and_validate_wc(wchar_t wc) | |||
319 | return wc; | 322 | return wc; |
320 | } | 323 | } |
321 | #else /* !UNICODE */ | 324 | #else /* !UNICODE */ |
322 | static size_t load_string(const char *src, int maxsize) | 325 | static size_t load_string(const char *src) |
323 | { | 326 | { |
324 | safe_strncpy(command_ps, src, maxsize); | 327 | safe_strncpy(command_ps, src, S.maxsize); |
325 | return strlen(command_ps); | 328 | return strlen(command_ps); |
326 | } | 329 | } |
327 | # if ENABLE_FEATURE_TAB_COMPLETION | 330 | # if ENABLE_FEATURE_TAB_COMPLETION |
@@ -1232,10 +1235,10 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1232 | strcpy(match_buf, &command[cursor_mb]); | 1235 | strcpy(match_buf, &command[cursor_mb]); |
1233 | /* where do we want to have cursor after all? */ | 1236 | /* where do we want to have cursor after all? */ |
1234 | strcpy(&command[cursor_mb], chosen_match + match_pfx_len); | 1237 | strcpy(&command[cursor_mb], chosen_match + match_pfx_len); |
1235 | len = load_string(command, S.maxsize); | 1238 | len = load_string(command); |
1236 | /* add match and tail */ | 1239 | /* add match and tail */ |
1237 | sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); | 1240 | sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); |
1238 | command_len = load_string(command, S.maxsize); | 1241 | command_len = load_string(command); |
1239 | /* write out the matched command */ | 1242 | /* write out the matched command */ |
1240 | /* paranoia: load_string can return 0 on conv error, | 1243 | /* paranoia: load_string can return 0 on conv error, |
1241 | * prevent passing pos = (0 - 12) to redraw */ | 1244 | * prevent passing pos = (0 - 12) to redraw */ |
@@ -1956,6 +1959,140 @@ static int isrtl_str(void) | |||
1956 | #undef CTRL | 1959 | #undef CTRL |
1957 | #define CTRL(a) ((a) & ~0x40) | 1960 | #define CTRL(a) ((a) & ~0x40) |
1958 | 1961 | ||
1962 | enum { | ||
1963 | VI_CMDMODE_BIT = 0x40000000, | ||
1964 | /* 0x80000000 bit flags KEYCODE_xxx */ | ||
1965 | }; | ||
1966 | |||
1967 | #if ENABLE_FEATURE_REVERSE_SEARCH | ||
1968 | /* Mimic readline Ctrl-R reverse history search. | ||
1969 | * When invoked, it shows the following prompt: | ||
1970 | * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R] | ||
1971 | * and typing results in search being performed: | ||
1972 | * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp] | ||
1973 | * Search is performed by looking at progressively older lines in history. | ||
1974 | * Ctrl-R again searches for the next match in history. | ||
1975 | * Backspace deletes last matched char. | ||
1976 | * Control keys exit search and return to normal editing (at current history line). | ||
1977 | */ | ||
1978 | static int32_t reverse_i_search(void) | ||
1979 | { | ||
1980 | char match_buf[128]; /* for user input */ | ||
1981 | char read_key_buffer[KEYCODE_BUFFER_SIZE]; | ||
1982 | const char *matched_history_line; | ||
1983 | const char *saved_prompt; | ||
1984 | int32_t ic; | ||
1985 | |||
1986 | matched_history_line = NULL; | ||
1987 | read_key_buffer[0] = 0; | ||
1988 | match_buf[0] = '\0'; | ||
1989 | |||
1990 | /* Save and replace the prompt */ | ||
1991 | saved_prompt = cmdedit_prompt; | ||
1992 | goto set_prompt; | ||
1993 | |||
1994 | while (1) { | ||
1995 | int h; | ||
1996 | unsigned match_buf_len = strlen(match_buf); | ||
1997 | |||
1998 | fflush_all(); | ||
1999 | //FIXME: correct timeout? | ||
2000 | ic = lineedit_read_key(read_key_buffer, -1); | ||
2001 | |||
2002 | switch (ic) { | ||
2003 | case CTRL('R'): /* searching for the next match */ | ||
2004 | break; | ||
2005 | |||
2006 | case '\b': | ||
2007 | case '\x7f': | ||
2008 | /* Backspace */ | ||
2009 | if (unicode_status == UNICODE_ON) { | ||
2010 | while (match_buf_len != 0) { | ||
2011 | uint8_t c = match_buf[--match_buf_len]; | ||
2012 | if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */ | ||
2013 | break; /* yes */ | ||
2014 | } | ||
2015 | } else { | ||
2016 | if (match_buf_len != 0) | ||
2017 | match_buf_len--; | ||
2018 | } | ||
2019 | match_buf[match_buf_len] = '\0'; | ||
2020 | break; | ||
2021 | |||
2022 | default: | ||
2023 | if (ic < ' ' | ||
2024 | || (!ENABLE_UNICODE_SUPPORT && ic >= 256) | ||
2025 | || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT) | ||
2026 | ) { | ||
2027 | goto ret; | ||
2028 | } | ||
2029 | |||
2030 | /* Append this char */ | ||
2031 | #if ENABLE_UNICODE_SUPPORT | ||
2032 | if (unicode_status == UNICODE_ON) { | ||
2033 | mbstate_t mbstate = { 0 }; | ||
2034 | char buf[MB_CUR_MAX + 1]; | ||
2035 | int len = wcrtomb(buf, ic, &mbstate); | ||
2036 | if (len > 0) { | ||
2037 | buf[len] = '\0'; | ||
2038 | if (match_buf_len + len < sizeof(match_buf)) | ||
2039 | strcpy(match_buf + match_buf_len, buf); | ||
2040 | } | ||
2041 | } else | ||
2042 | #endif | ||
2043 | if (match_buf_len < sizeof(match_buf) - 1) { | ||
2044 | match_buf[match_buf_len] = ic; | ||
2045 | match_buf[match_buf_len + 1] = '\0'; | ||
2046 | } | ||
2047 | break; | ||
2048 | } /* switch (ic) */ | ||
2049 | |||
2050 | /* Search in history for match_buf */ | ||
2051 | h = state->cur_history; | ||
2052 | if (ic == CTRL('R')) | ||
2053 | h--; | ||
2054 | while (h >= 0) { | ||
2055 | if (state->history[h]) { | ||
2056 | char *match = strstr(state->history[h], match_buf); | ||
2057 | if (match) { | ||
2058 | state->cur_history = h; | ||
2059 | matched_history_line = state->history[h]; | ||
2060 | command_len = load_string(matched_history_line); | ||
2061 | cursor = match - matched_history_line; | ||
2062 | //FIXME: cursor position for Unicode case | ||
2063 | |||
2064 | free((char*)cmdedit_prompt); | ||
2065 | set_prompt: | ||
2066 | cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf); | ||
2067 | cmdedit_prmt_len = strlen(cmdedit_prompt); | ||
2068 | goto do_redraw; | ||
2069 | } | ||
2070 | } | ||
2071 | h--; | ||
2072 | } | ||
2073 | |||
2074 | /* Not found */ | ||
2075 | match_buf[match_buf_len] = '\0'; | ||
2076 | beep(); | ||
2077 | continue; | ||
2078 | |||
2079 | do_redraw: | ||
2080 | redraw(cmdedit_y, command_len - cursor); | ||
2081 | } /* while (1) */ | ||
2082 | |||
2083 | ret: | ||
2084 | if (matched_history_line) | ||
2085 | command_len = load_string(matched_history_line); | ||
2086 | |||
2087 | free((char*)cmdedit_prompt); | ||
2088 | cmdedit_prompt = saved_prompt; | ||
2089 | cmdedit_prmt_len = strlen(cmdedit_prompt); | ||
2090 | redraw(cmdedit_y, command_len - cursor); | ||
2091 | |||
2092 | return ic; | ||
2093 | } | ||
2094 | #endif | ||
2095 | |||
1959 | /* maxsize must be >= 2. | 2096 | /* maxsize must be >= 2. |
1960 | * Returns: | 2097 | * Returns: |
1961 | * -1 on read errors or EOF, or on bare Ctrl-D, | 2098 | * -1 on read errors or EOF, or on bare Ctrl-D, |
@@ -2077,15 +2214,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2077 | * clutters the big switch a bit, but keeps all the code | 2214 | * clutters the big switch a bit, but keeps all the code |
2078 | * in one place. | 2215 | * in one place. |
2079 | */ | 2216 | */ |
2080 | enum { | ||
2081 | VI_CMDMODE_BIT = 0x40000000, | ||
2082 | /* 0x80000000 bit flags KEYCODE_xxx */ | ||
2083 | }; | ||
2084 | int32_t ic, ic_raw; | 2217 | int32_t ic, ic_raw; |
2085 | 2218 | ||
2086 | fflush_all(); | 2219 | fflush_all(); |
2087 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); | 2220 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); |
2088 | 2221 | ||
2222 | #if ENABLE_FEATURE_REVERSE_SEARCH | ||
2223 | again: | ||
2224 | #endif | ||
2089 | #if ENABLE_FEATURE_EDITING_VI | 2225 | #if ENABLE_FEATURE_EDITING_VI |
2090 | newdelflag = 1; | 2226 | newdelflag = 1; |
2091 | if (vi_cmdmode) { | 2227 | if (vi_cmdmode) { |
@@ -2189,6 +2325,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2189 | while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) | 2325 | while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) |
2190 | input_backspace(); | 2326 | input_backspace(); |
2191 | break; | 2327 | break; |
2328 | #if ENABLE_FEATURE_REVERSE_SEARCH | ||
2329 | case CTRL('R'): | ||
2330 | ic = ic_raw = reverse_i_search(); | ||
2331 | goto again; | ||
2332 | #endif | ||
2192 | 2333 | ||
2193 | #if ENABLE_FEATURE_EDITING_VI | 2334 | #if ENABLE_FEATURE_EDITING_VI |
2194 | case 'i'|VI_CMDMODE_BIT: | 2335 | case 'i'|VI_CMDMODE_BIT: |
@@ -2342,7 +2483,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2342 | /* Rewrite the line with the selected history item */ | 2483 | /* Rewrite the line with the selected history item */ |
2343 | /* change command */ | 2484 | /* change command */ |
2344 | command_len = load_string(state->history[state->cur_history] ? | 2485 | command_len = load_string(state->history[state->cur_history] ? |
2345 | state->history[state->cur_history] : "", maxsize); | 2486 | state->history[state->cur_history] : ""); |
2346 | /* redraw and go to eol (bol, in vi) */ | 2487 | /* redraw and go to eol (bol, in vi) */ |
2347 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); | 2488 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); |
2348 | break; | 2489 | break; |