aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2016-11-29 11:26:45 +0000
committerRon Yorston <rmy@pobox.com>2016-11-29 11:26:45 +0000
commitbb8d79eadbba1942dbdb9f9cee5c47833afe269f (patch)
treeb8c517e9ca895d60d7227aef7177b6291df5e2cd /libbb/lineedit.c
parent9fa1e4990e655a85025c9d270a1606983e375e47 (diff)
parent7d877fc9312a742b06125927bb1d34bd35398c6c (diff)
downloadbusybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.tar.gz
busybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.tar.bz2
busybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r--libbb/lineedit.c112
1 files changed, 68 insertions, 44 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 06f708b62..5d9080131 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -13,7 +13,6 @@
13 * 13 *
14 * This code is 'as is' with no warranty. 14 * This code is 'as is' with no warranty.
15 */ 15 */
16
17/* 16/*
18 * Usage and known bugs: 17 * Usage and known bugs:
19 * Terminal key codes are not extensive, more needs to be added. 18 * Terminal key codes are not extensive, more needs to be added.
@@ -23,9 +22,6 @@
23 * Ctrl-E also works as End. 22 * Ctrl-E also works as End.
24 * 23 *
25 * The following readline-like commands are not implemented: 24 * The following readline-like commands are not implemented:
26 * ESC-b -- Move back one word
27 * ESC-f -- Move forward one word
28 * ESC-d -- Delete forward one word
29 * CTL-t -- Transpose two characters 25 * CTL-t -- Transpose two characters
30 * 26 *
31 * lineedit does not know that the terminal escape sequences do not 27 * lineedit does not know that the terminal escape sequences do not
@@ -133,8 +129,7 @@ static const char null_str[] ALIGN1 = "";
133struct lineedit_statics { 129struct lineedit_statics {
134 line_input_t *state; 130 line_input_t *state;
135 131
136 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ 132 unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
137 sighandler_t previous_SIGWINCH_handler;
138 133
139 unsigned cmdedit_x; /* real x (col) terminal position */ 134 unsigned cmdedit_x; /* real x (col) terminal position */
140 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */ 135 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
@@ -159,15 +154,22 @@ struct lineedit_statics {
159 unsigned num_matches; 154 unsigned num_matches;
160#endif 155#endif
161 156
157 unsigned SIGWINCH_saved;
158 volatile unsigned SIGWINCH_count;
159 volatile smallint ok_to_redraw;
160
162#if ENABLE_FEATURE_EDITING_VI 161#if ENABLE_FEATURE_EDITING_VI
163# define DELBUFSIZ 128 162# define DELBUFSIZ 128
164 CHAR_T *delptr;
165 smallint newdelflag; /* whether delbuf should be reused yet */ 163 smallint newdelflag; /* whether delbuf should be reused yet */
164 CHAR_T *delptr;
166 CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */ 165 CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
167#endif 166#endif
168#if ENABLE_FEATURE_EDITING_ASK_TERMINAL 167#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
169 smallint sent_ESC_br6n; 168 smallint sent_ESC_br6n;
170#endif 169#endif
170
171 /* Largish struct, keeping it last results in smaller code */
172 struct sigaction SIGWINCH_handler;
171}; 173};
172 174
173/* See lineedit_ptr_hack.c */ 175/* See lineedit_ptr_hack.c */
@@ -176,7 +178,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
176#define S (*lineedit_ptr_to_statics) 178#define S (*lineedit_ptr_to_statics)
177#define state (S.state ) 179#define state (S.state )
178#define cmdedit_termw (S.cmdedit_termw ) 180#define cmdedit_termw (S.cmdedit_termw )
179#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
180#define cmdedit_x (S.cmdedit_x ) 181#define cmdedit_x (S.cmdedit_x )
181#define cmdedit_y (S.cmdedit_y ) 182#define cmdedit_y (S.cmdedit_y )
182#define cmdedit_prmt_len (S.cmdedit_prmt_len) 183#define cmdedit_prmt_len (S.cmdedit_prmt_len)
@@ -474,14 +475,10 @@ static void beep(void)
474 475
475static void put_prompt(void) 476static void put_prompt(void)
476{ 477{
477 unsigned w;
478
479 fputs(cmdedit_prompt, stdout); 478 fputs(cmdedit_prompt, stdout);
480 fflush_all();
481 cursor = 0; 479 cursor = 0;
482 w = cmdedit_termw; /* read volatile var once */ 480 cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */
483 cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ 481 cmdedit_x = cmdedit_prmt_len % cmdedit_termw;
484 cmdedit_x = cmdedit_prmt_len % w;
485} 482}
486 483
487/* Move back one character */ 484/* Move back one character */
@@ -555,13 +552,11 @@ static void input_backward(unsigned num)
555 put_cur_glyph_and_inc_cursor(); 552 put_cur_glyph_and_inc_cursor();
556 } else { 553 } else {
557 int lines_up; 554 int lines_up;
558 unsigned width;
559 /* num = chars to go back from the beginning of current line: */ 555 /* num = chars to go back from the beginning of current line: */
560 num -= cmdedit_x; 556 num -= cmdedit_x;
561 width = cmdedit_termw; /* read volatile var once */
562 /* num=1...w: one line up, w+1...2w: two, etc: */ 557 /* num=1...w: one line up, w+1...2w: two, etc: */
563 lines_up = 1 + (num - 1) / width; 558 lines_up = 1 + (num - 1) / cmdedit_termw;
564 cmdedit_x = (width * cmdedit_y - num) % width; 559 cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw;
565 cmdedit_y -= lines_up; 560 cmdedit_y -= lines_up;
566 /* go to 1st column; go up */ 561 /* go to 1st column; go up */
567 printf("\r" ESC"[%uA", lines_up); 562 printf("\r" ESC"[%uA", lines_up);
@@ -2052,28 +2047,29 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2052} 2047}
2053#endif 2048#endif
2054 2049
2055static void cmdedit_setwidth(unsigned w, int redraw_flg) 2050static void cmdedit_setwidth(void)
2056{ 2051{
2057 cmdedit_termw = w; 2052 int new_y;
2058 if (redraw_flg) { 2053
2059 /* new y for current cursor */ 2054 cmdedit_termw = get_terminal_width(STDIN_FILENO);
2060 int new_y = (cursor + cmdedit_prmt_len) / w; 2055 /* new y for current cursor */
2061 /* redraw */ 2056 new_y = (cursor + cmdedit_prmt_len) / cmdedit_termw;
2062 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); 2057 /* redraw */
2063 fflush_all(); 2058 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
2064 }
2065} 2059}
2066 2060
2067static void win_changed(int nsig) 2061static void win_changed(int nsig UNUSED_PARAM)
2068{ 2062{
2069 int sv_errno = errno; 2063 if (S.ok_to_redraw) {
2070 unsigned width; 2064 /* We are in read_key(), safe to redraw immediately */
2071 2065 int sv_errno = errno;
2072 get_terminal_width_height(0, &width, NULL); 2066 cmdedit_setwidth();
2073//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!) 2067 fflush_all();
2074 cmdedit_setwidth(width, /*redraw_flg:*/ nsig); 2068 errno = sv_errno;
2075 2069 } else {
2076 errno = sv_errno; 2070 /* Signal main loop that redraw is necessary */
2071 S.SIGWINCH_count++;
2072 }
2077} 2073}
2078 2074
2079static int lineedit_read_key(char *read_key_buffer, int timeout) 2075static int lineedit_read_key(char *read_key_buffer, int timeout)
@@ -2084,6 +2080,7 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2084 int unicode_idx = 0; 2080 int unicode_idx = 0;
2085#endif 2081#endif
2086 2082
2083 fflush_all();
2087 while (1) { 2084 while (1) {
2088 /* Wait for input. TIMEOUT = -1 makes read_key wait even 2085 /* Wait for input. TIMEOUT = -1 makes read_key wait even
2089 * on nonblocking stdin, TIMEOUT = 50 makes sure we won't 2086 * on nonblocking stdin, TIMEOUT = 50 makes sure we won't
@@ -2092,7 +2089,9 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2092 * 2089 *
2093 * Note: read_key sets errno to 0 on success. 2090 * Note: read_key sets errno to 0 on success.
2094 */ 2091 */
2092 S.ok_to_redraw = 1;
2095 ic = read_key(STDIN_FILENO, read_key_buffer, timeout); 2093 ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
2094 S.ok_to_redraw = 0;
2096 if (errno) { 2095 if (errno) {
2097#if ENABLE_UNICODE_SUPPORT 2096#if ENABLE_UNICODE_SUPPORT
2098 if (errno == EAGAIN && unicode_idx != 0) 2097 if (errno == EAGAIN && unicode_idx != 0)
@@ -2223,7 +2222,6 @@ static int32_t reverse_i_search(void)
2223 int h; 2222 int h;
2224 unsigned match_buf_len = strlen(match_buf); 2223 unsigned match_buf_len = strlen(match_buf);
2225 2224
2226 fflush_all();
2227//FIXME: correct timeout? 2225//FIXME: correct timeout?
2228 ic = lineedit_read_key(read_key_buffer, -1); 2226 ic = lineedit_read_key(read_key_buffer, -1);
2229 2227
@@ -2325,6 +2323,7 @@ static int32_t reverse_i_search(void)
2325 * Returns: 2323 * Returns:
2326 * -1 on read errors or EOF, or on bare Ctrl-D, 2324 * -1 on read errors or EOF, or on bare Ctrl-D,
2327 * 0 on ctrl-C (the line entered is still returned in 'command'), 2325 * 0 on ctrl-C (the line entered is still returned in 'command'),
2326 * (in both cases the cursor remains on the input line, '\n' is not printed)
2328 * >0 length of input string, including terminating '\n' 2327 * >0 length of input string, including terminating '\n'
2329 */ 2328 */
2330int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) 2329int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
@@ -2359,7 +2358,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2359 * tty is still in "raw mode"). 2358 * tty is still in "raw mode").
2360 */ 2359 */
2361 parse_and_put_prompt(prompt); 2360 parse_and_put_prompt(prompt);
2362 /* fflush_all(); - done by parse_and_put_prompt */ 2361 fflush_all();
2363 if (fgets(command, maxsize, stdin) == NULL) 2362 if (fgets(command, maxsize, stdin) == NULL)
2364 len = -1; /* EOF or error */ 2363 len = -1; /* EOF or error */
2365 else 2364 else
@@ -2435,9 +2434,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2435 ask_terminal(); 2434 ask_terminal();
2436 2435
2437 /* Install window resize handler (NB: after *all* init is complete) */ 2436 /* Install window resize handler (NB: after *all* init is complete) */
2438//FIXME: save entire sigaction! 2437 S.SIGWINCH_handler.sa_handler = win_changed;
2439 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); 2438 S.SIGWINCH_handler.sa_flags = SA_RESTART;
2440 win_changed(0); /* get initial window size */ 2439 sigaction(SIGWINCH, &S.SIGWINCH_handler, &S.SIGWINCH_handler);
2440
2441 cmdedit_termw = get_terminal_width(STDIN_FILENO);
2441 2442
2442 read_key_buffer[0] = 0; 2443 read_key_buffer[0] = 0;
2443 while (1) { 2444 while (1) {
@@ -2450,8 +2451,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2450 * in one place. 2451 * in one place.
2451 */ 2452 */
2452 int32_t ic, ic_raw; 2453 int32_t ic, ic_raw;
2454 unsigned count;
2455
2456 count = S.SIGWINCH_count;
2457 if (S.SIGWINCH_saved != count) {
2458 S.SIGWINCH_saved = count;
2459 cmdedit_setwidth();
2460 }
2453 2461
2454 fflush_all();
2455 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2462 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2456#if ENABLE_PLATFORM_MINGW32 2463#if ENABLE_PLATFORM_MINGW32
2457 /* scroll to cursor position on any keypress */ 2464 /* scroll to cursor position on any keypress */
@@ -2565,6 +2572,24 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2565 while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) 2572 while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
2566 input_backspace(); 2573 input_backspace();
2567 break; 2574 break;
2575 case KEYCODE_ALT_D: {
2576 /* Delete word forward */
2577 int nc, sc = cursor;
2578 ctrl_right();
2579 nc = cursor - sc;
2580 input_backward(nc);
2581 while (--nc >= 0)
2582 input_delete(1);
2583 break;
2584 }
2585 case KEYCODE_ALT_BACKSPACE: {
2586 /* Delete word backward */
2587 int sc = cursor;
2588 ctrl_left();
2589 while (sc-- > cursor)
2590 input_delete(1);
2591 break;
2592 }
2568#if ENABLE_FEATURE_REVERSE_SEARCH 2593#if ENABLE_FEATURE_REVERSE_SEARCH
2569 case CTRL('R'): 2594 case CTRL('R'):
2570 ic = ic_raw = reverse_i_search(); 2595 ic = ic_raw = reverse_i_search();
@@ -2792,7 +2817,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2792 && ic_raw == initial_settings.c_cc[VINTR] 2817 && ic_raw == initial_settings.c_cc[VINTR]
2793 ) { 2818 ) {
2794 /* Ctrl-C (usually) - stop gathering input */ 2819 /* Ctrl-C (usually) - stop gathering input */
2795 goto_new_line();
2796 command_len = 0; 2820 command_len = 0;
2797 break_out = -1; /* "do not append '\n'" */ 2821 break_out = -1; /* "do not append '\n'" */
2798 break; 2822 break;
@@ -2914,7 +2938,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2914 /* restore initial_settings */ 2938 /* restore initial_settings */
2915 tcsetattr_stdin_TCSANOW(&initial_settings); 2939 tcsetattr_stdin_TCSANOW(&initial_settings);
2916 /* restore SIGWINCH handler */ 2940 /* restore SIGWINCH handler */
2917 signal(SIGWINCH, previous_SIGWINCH_handler); 2941 sigaction_set(SIGWINCH, &S.SIGWINCH_handler);
2918 fflush_all(); 2942 fflush_all();
2919 2943
2920 len = command_len; 2944 len = command_len;