From 13ad90627c85c0d744dfa28637fb80e89677a37f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 11 Nov 2009 03:19:30 +0100 Subject: [PATCH] ash: fix bad interaction of "stty -echo" + ASK_TERMINAL function old new delta read_line_input 4820 4886 +66 put_prompt 108 47 -61 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 66/-61) Total: 5 bytes Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 99 +++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index a9972576e..7bb3f2e35 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -372,55 +372,14 @@ static void input_backward(unsigned num) static void put_prompt(void) { + unsigned w; + out1str(cmdedit_prompt); fflush_all(); -#if ENABLE_FEATURE_EDITING_ASK_TERMINAL - { - /* Ask terminal where is the cursor now. - * lineedit_read_key handles response and corrects - * our idea of current cursor position. - * Testcase: run "echo -n long_line_long_line_long_line", - * then type in a long, wrapping command and try to - * delete it using backspace key. - * Note: we print it _after_ prompt, because - * prompt may contain CR. Example: PS1='\[\r\n\]\w ' - */ - /* Problem: if there is buffered input on stdin, - * the response will be delivered later, - * possibly to an unsuspecting application. - * Testcase: "sleep 1; busybox ash" + press and hold [Enter]. - * Result: - * ~/srcdevel/bbox/fix/busybox.t4 # - * ~/srcdevel/bbox/fix/busybox.t4 # - * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage - * ~/srcdevel/bbox/fix/busybox.t4 # - * - * Checking for input with poll only makes the race narrower, - * I still can trigger it. Strace: - * - * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 - * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists - * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! - * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) - * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first - */ - struct pollfd pfd; - - pfd.fd = STDIN_FILENO; - pfd.events = POLLIN; - if (safe_poll(&pfd, 1, 0) == 0) { - S.sent_ESC_br6n = 1; - out1str("\033" "[6n"); - fflush_all(); /* make terminal see it ASAP! */ - } - } -#endif cursor = 0; - { - unsigned w = cmdedit_termw; /* volatile var */ - cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ - cmdedit_x = cmdedit_prmt_len % w; - } + w = cmdedit_termw; /* read volatile var once */ + cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ + cmdedit_x = cmdedit_prmt_len % w; } /* draw prompt, editor line, and clear tail */ @@ -1503,6 +1462,51 @@ static void ctrl_right(void) * read_line_input and its helpers */ +#if ENABLE_FEATURE_EDITING_ASK_TERMINAL +static void ask_terminal(void) +{ + /* Ask terminal where is the cursor now. + * lineedit_read_key handles response and corrects + * our idea of current cursor position. + * Testcase: run "echo -n long_line_long_line_long_line", + * then type in a long, wrapping command and try to + * delete it using backspace key. + * Note: we print it _after_ prompt, because + * prompt may contain CR. Example: PS1='\[\r\n\]\w ' + */ + /* Problem: if there is buffered input on stdin, + * the response will be delivered later, + * possibly to an unsuspecting application. + * Testcase: "sleep 1; busybox ash" + press and hold [Enter]. + * Result: + * ~/srcdevel/bbox/fix/busybox.t4 # + * ~/srcdevel/bbox/fix/busybox.t4 # + * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage + * ~/srcdevel/bbox/fix/busybox.t4 # + * + * Checking for input with poll only makes the race narrower, + * I still can trigger it. Strace: + * + * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 + * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists + * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! + * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) + * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first + */ + struct pollfd pfd; + + pfd.fd = STDIN_FILENO; + pfd.events = POLLIN; + if (safe_poll(&pfd, 1, 0) == 0) { + S.sent_ESC_br6n = 1; + out1str("\033" "[6n"); + fflush_all(); /* make terminal see it ASAP! */ + } +} +#else +#define ask_terminal() ((void)0) +#endif + #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT static void parse_and_put_prompt(const char *prmt_ptr) { @@ -1822,8 +1826,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history); #endif - /* Print out the command prompt */ + /* Print out the command prompt, optionally ask where cursor is */ parse_and_put_prompt(prompt); + ask_terminal(); read_key_buffer[0] = 0; while (1) { -- 2.25.1