diff options
author | Ron Yorston <rmy@pobox.com> | 2016-11-29 11:26:45 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-11-29 11:26:45 +0000 |
commit | bb8d79eadbba1942dbdb9f9cee5c47833afe269f (patch) | |
tree | b8c517e9ca895d60d7227aef7177b6291df5e2cd /libbb/lineedit.c | |
parent | 9fa1e4990e655a85025c9d270a1606983e375e47 (diff) | |
parent | 7d877fc9312a742b06125927bb1d34bd35398c6c (diff) | |
download | busybox-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.c | 112 |
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 = ""; | |||
133 | struct lineedit_statics { | 129 | struct 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 | ||
475 | static void put_prompt(void) | 476 | static 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 | ||
2055 | static void cmdedit_setwidth(unsigned w, int redraw_flg) | 2050 | static 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 | ||
2067 | static void win_changed(int nsig) | 2061 | static 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 | ||
2079 | static int lineedit_read_key(char *read_key_buffer, int timeout) | 2075 | static 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 | */ |
2330 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) | 2329 | int 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; |