Root/package/busybox/patches/911-libbb-lineedit-implement-optional-Ctrl-R-history-sea.patch

1--- a/libbb/lineedit.c
2+++ b/libbb/lineedit.c
3@@ -202,13 +202,23 @@ static void deinit_S(void)
4 
5 
6 #if ENABLE_UNICODE_SUPPORT
7-static size_t load_string(const char *src, int maxsize)
8+static size_t load_string(const char *src)
9 {
10- ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
11- if (len < 0)
12- len = 0;
13- command_ps[len] = BB_NUL;
14- return len;
15+ if (unicode_status == UNICODE_ON) {
16+ ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1);
17+ if (len < 0)
18+ len = 0;
19+ command_ps[len] = BB_NUL;
20+ return len;
21+ } else {
22+ unsigned i = 0;
23+ while (src[i] && i < S.maxsize - 1) {
24+ command_ps[i] = src[i];
25+ i++;
26+ }
27+ command_ps[i] = BB_NUL;
28+ return i;
29+ }
30 }
31 static unsigned save_string(char *dst, unsigned maxsize)
32 {
33@@ -297,9 +307,9 @@ static wchar_t adjust_width_and_validate
34     return wc;
35 }
36 #else /* !UNICODE */
37-static size_t load_string(const char *src, int maxsize)
38+static size_t load_string(const char *src)
39 {
40- safe_strncpy(command_ps, src, maxsize);
41+ safe_strncpy(command_ps, src, S.maxsize);
42     return strlen(command_ps);
43 }
44 # if ENABLE_FEATURE_TAB_COMPLETION
45@@ -1202,10 +1212,10 @@ static NOINLINE void input_tab(smallint
46             strcpy(match_buf, &command[cursor_mb]);
47             /* where do we want to have cursor after all? */
48             strcpy(&command[cursor_mb], chosen_match + match_pfx_len);
49- len = load_string(command, S.maxsize);
50+ len = load_string(command);
51             /* add match and tail */
52             sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf);
53- command_len = load_string(command, S.maxsize);
54+ command_len = load_string(command);
55             /* write out the matched command */
56             /* paranoia: load_string can return 0 on conv error,
57              * prevent passing pos = (0 - 12) to redraw */
58@@ -1911,6 +1921,140 @@ static int isrtl_str(void)
59 #undef CTRL
60 #define CTRL(a) ((a) & ~0x40)
61 
62+enum {
63+ VI_CMDMODE_BIT = 0x40000000,
64+ /* 0x80000000 bit flags KEYCODE_xxx */
65+};
66+
67+#if ENABLE_FEATURE_REVERSE_SEARCH
68+/* Mimic readline Ctrl-R reverse history search.
69+ * When invoked, it shows the following prompt:
70+ * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R]
71+ * and typing results in search being performed:
72+ * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp]
73+ * Search is performed by looking at progressively older lines in history.
74+ * Ctrl-R again searches for the next match in history.
75+ * Backspace deletes last matched char.
76+ * Control keys exit search and return to normal editing (at current history line).
77+ */
78+static int32_t reverse_i_search(void)
79+{
80+ char match_buf[128]; /* for user input */
81+ char read_key_buffer[KEYCODE_BUFFER_SIZE];
82+ const char *matched_history_line;
83+ const char *saved_prompt;
84+ int32_t ic;
85+
86+ matched_history_line = NULL;
87+ read_key_buffer[0] = 0;
88+ match_buf[0] = '\0';
89+
90+ /* Save and replace the prompt */
91+ saved_prompt = cmdedit_prompt;
92+ goto set_prompt;
93+
94+ while (1) {
95+ int h;
96+ unsigned match_buf_len = strlen(match_buf);
97+
98+ fflush_all();
99+//FIXME: correct timeout?
100+ ic = lineedit_read_key(read_key_buffer);
101+
102+ switch (ic) {
103+ case CTRL('R'): /* searching for the next match */
104+ break;
105+
106+ case '\b':
107+ case '\x7f':
108+ /* Backspace */
109+ if (unicode_status == UNICODE_ON) {
110+ while (match_buf_len != 0) {
111+ uint8_t c = match_buf[--match_buf_len];
112+ if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */
113+ break; /* yes */
114+ }
115+ } else {
116+ if (match_buf_len != 0)
117+ match_buf_len--;
118+ }
119+ match_buf[match_buf_len] = '\0';
120+ break;
121+
122+ default:
123+ if (ic < ' '
124+ || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
125+ || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
126+ ) {
127+ goto ret;
128+ }
129+
130+ /* Append this char */
131+#if ENABLE_UNICODE_SUPPORT
132+ if (unicode_status == UNICODE_ON) {
133+ mbstate_t mbstate = { 0 };
134+ char buf[MB_CUR_MAX + 1];
135+ int len = wcrtomb(buf, ic, &mbstate);
136+ if (len > 0) {
137+ buf[len] = '\0';
138+ if (match_buf_len + len < sizeof(match_buf))
139+ strcpy(match_buf + match_buf_len, buf);
140+ }
141+ } else
142+#endif
143+ if (match_buf_len < sizeof(match_buf) - 1) {
144+ match_buf[match_buf_len] = ic;
145+ match_buf[match_buf_len + 1] = '\0';
146+ }
147+ break;
148+ } /* switch (ic) */
149+
150+ /* Search in history for match_buf */
151+ h = state->cur_history;
152+ if (ic == CTRL('R'))
153+ h--;
154+ while (h >= 0) {
155+ if (state->history[h]) {
156+ char *match = strstr(state->history[h], match_buf);
157+ if (match) {
158+ state->cur_history = h;
159+ matched_history_line = state->history[h];
160+ command_len = load_string(matched_history_line);
161+ cursor = match - matched_history_line;
162+//FIXME: cursor position for Unicode case
163+
164+ free((char*)cmdedit_prompt);
165+ set_prompt:
166+ cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
167+ cmdedit_prmt_len = strlen(cmdedit_prompt);
168+ goto do_redraw;
169+ }
170+ }
171+ h--;
172+ }
173+
174+ /* Not found */
175+ match_buf[match_buf_len] = '\0';
176+ beep();
177+ continue;
178+
179+ do_redraw:
180+ redraw(cmdedit_y, command_len - cursor);
181+ } /* while (1) */
182+
183+ ret:
184+ if (matched_history_line)
185+ command_len = load_string(matched_history_line);
186+
187+ free((char*)cmdedit_prompt);
188+ cmdedit_prompt = saved_prompt;
189+ cmdedit_prmt_len = strlen(cmdedit_prompt);
190+ redraw(cmdedit_y, command_len - cursor);
191+
192+ return ic;
193+}
194+#endif
195+
196 /* maxsize must be >= 2.
197  * Returns:
198  * -1 on read errors or EOF, or on bare Ctrl-D,
199@@ -2026,15 +2170,14 @@ int FAST_FUNC read_line_input(const char
200          * clutters the big switch a bit, but keeps all the code
201          * in one place.
202          */
203- enum {
204- VI_CMDMODE_BIT = 0x40000000,
205- /* 0x80000000 bit flags KEYCODE_xxx */
206- };
207         int32_t ic, ic_raw;
208 
209         fflush_all();
210         ic = ic_raw = lineedit_read_key(read_key_buffer);
211 
212+#if ENABLE_FEATURE_REVERSE_SEARCH
213+ again:
214+#endif
215 #if ENABLE_FEATURE_EDITING_VI
216         newdelflag = 1;
217         if (vi_cmdmode) {
218@@ -2138,6 +2281,11 @@ int FAST_FUNC read_line_input(const char
219             while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
220                 input_backspace();
221             break;
222+#if ENABLE_FEATURE_REVERSE_SEARCH
223+ case CTRL('R'):
224+ ic = ic_raw = reverse_i_search();
225+ goto again;
226+#endif
227 
228 #if ENABLE_FEATURE_EDITING_VI
229         case 'i'|VI_CMDMODE_BIT:
230@@ -2291,7 +2439,7 @@ int FAST_FUNC read_line_input(const char
231             /* Rewrite the line with the selected history item */
232             /* change command */
233             command_len = load_string(state->history[state->cur_history] ?
234- state->history[state->cur_history] : "", maxsize);
235+ state->history[state->cur_history] : "");
236             /* redraw and go to eol (bol, in vi) */
237             redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
238             break;
239--- a/libbb/Config.src
240+++ b/libbb/Config.src
241@@ -93,6 +93,14 @@ config FEATURE_EDITING_SAVEHISTORY
242     help
243       Enable history saving in shells.
244 
245+config FEATURE_REVERSE_SEARCH
246+ bool "Reverse history search"
247+ default y
248+ depends on FEATURE_EDITING_SAVEHISTORY
249+ help
250+ Enable readline-like Ctrl-R combination for reverse history search.
251+ Increases code by about 0.5k.
252+
253 config FEATURE_TAB_COMPLETION
254     bool "Tab completion"
255     default y
256

Archive Download this file



interactive