aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-22 15:48:57 +0000
committerRon Yorston <rmy@pobox.com>2012-03-22 15:48:57 +0000
commit9db164d6e39050d09f38288c6045cd2a2cbf6d63 (patch)
treeea5dc2d28d15da0de25c197ed7d059c3656af1a0 /libbb/lineedit.c
parent1118c95535ea51961437089fc3dece5ab4ea7e1b (diff)
parentd84b175cb6948eb17f847313bf912174e2f934e1 (diff)
downloadbusybox-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.c165
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
210static size_t load_string(const char *src, int maxsize) 210static 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 */
322static size_t load_string(const char *src, int maxsize) 325static 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
1962enum {
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 */
1978static 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;