diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-26 15:23:32 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-26 15:23:32 +0100 |
commit | 727e1b536e5478b8f28c93990a5bf34091144608 (patch) | |
tree | c8993291a1a03a06fcb7a2382e6cc211e6d7861e | |
parent | d31a8793ebedb53b686c9ea01be33d3d564760b9 (diff) | |
download | busybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.tar.gz busybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.tar.bz2 busybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.zip |
read_key,lineeedit: parse position answerback faster; sanitize its use
it's still not reliable, and probably cannot be made so...
added comment with explanation.
function old new delta
put_prompt 52 110 +58
read_key 601 607 +6
lineedit_read_key 201 207 +6
win_changed 108 104 -4
read_line_input 4824 4809 -15
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/2 up/down: 70/-19) Total: 51 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/lineedit.c | 38 | ||||
-rw-r--r-- | libbb/read_key.c | 53 |
2 files changed, 58 insertions, 33 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index bfd0e3346..2e1bc5d2e 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -370,6 +370,7 @@ static void input_backward(unsigned num) | |||
370 | static void put_prompt(void) | 370 | static void put_prompt(void) |
371 | { | 371 | { |
372 | out1str(cmdedit_prompt); | 372 | out1str(cmdedit_prompt); |
373 | fflush(NULL); | ||
373 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL) { | 374 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL) { |
374 | /* Ask terminal where is the cursor now. | 375 | /* Ask terminal where is the cursor now. |
375 | * lineedit_read_key handles response and corrects | 376 | * lineedit_read_key handles response and corrects |
@@ -380,7 +381,33 @@ static void put_prompt(void) | |||
380 | * Note: we print it _after_ prompt, because | 381 | * Note: we print it _after_ prompt, because |
381 | * prompt may contain CR. Example: PS1='\[\r\n\]\w ' | 382 | * prompt may contain CR. Example: PS1='\[\r\n\]\w ' |
382 | */ | 383 | */ |
383 | out1str("\033" "[6n"); | 384 | /* Problem: if there is buffered input on stdin, |
385 | * the response will be delivered later, | ||
386 | * possibly to an unsuspecting application. | ||
387 | * Testcase: "sleep 1; busybox ash" + press and hold [Enter]. | ||
388 | * Result: | ||
389 | * ~/srcdevel/bbox/fix/busybox.t4 # | ||
390 | * ~/srcdevel/bbox/fix/busybox.t4 # | ||
391 | * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage | ||
392 | * ~/srcdevel/bbox/fix/busybox.t4 # | ||
393 | * | ||
394 | * Checking for input with poll only makes the race narrower, | ||
395 | * I still can trigger it. Strace: | ||
396 | * | ||
397 | * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 | ||
398 | * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists | ||
399 | * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! | ||
400 | * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) | ||
401 | * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first | ||
402 | */ | ||
403 | struct pollfd pfd; | ||
404 | |||
405 | pfd.fd = STDIN_FILENO; | ||
406 | pfd.events = POLLIN; | ||
407 | if (safe_poll(&pfd, 1, 0) == 0) { | ||
408 | out1str("\033" "[6n"); | ||
409 | fflush(NULL); /* make terminal see it ASAP! */ | ||
410 | } | ||
384 | } | 411 | } |
385 | cursor = 0; | 412 | cursor = 0; |
386 | { | 413 | { |
@@ -1603,7 +1630,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg) | |||
1603 | int new_y = (cursor + cmdedit_prmt_len) / w; | 1630 | int new_y = (cursor + cmdedit_prmt_len) / w; |
1604 | /* redraw */ | 1631 | /* redraw */ |
1605 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); | 1632 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); |
1606 | fflush(stdout); | 1633 | fflush(NULL); |
1607 | } | 1634 | } |
1608 | } | 1635 | } |
1609 | 1636 | ||
@@ -1640,6 +1667,7 @@ static int lineedit_read_key(char *read_key_buffer) | |||
1640 | ic = read_key(STDIN_FILENO, read_key_buffer); | 1667 | ic = read_key(STDIN_FILENO, read_key_buffer); |
1641 | 1668 | ||
1642 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL | 1669 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL |
1670 | && cursor == 0 /* otherwise it may be bogus */ | ||
1643 | && (int32_t)ic == KEYCODE_CURSOR_POS | 1671 | && (int32_t)ic == KEYCODE_CURSOR_POS |
1644 | ) { | 1672 | ) { |
1645 | int col = ((ic >> 32) & 0x7fff) - 1; | 1673 | int col = ((ic >> 32) & 0x7fff) - 1; |
@@ -1708,7 +1736,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1708 | ) { | 1736 | ) { |
1709 | /* Happens when e.g. stty -echo was run before */ | 1737 | /* Happens when e.g. stty -echo was run before */ |
1710 | parse_and_put_prompt(prompt); | 1738 | parse_and_put_prompt(prompt); |
1711 | fflush(stdout); | 1739 | /* fflush(stdout); - done by parse_and_put_prompt */ |
1712 | if (fgets(command, maxsize, stdin) == NULL) | 1740 | if (fgets(command, maxsize, stdin) == NULL) |
1713 | len = -1; /* EOF or error */ | 1741 | len = -1; /* EOF or error */ |
1714 | else | 1742 | else |
@@ -2190,7 +2218,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2190 | tcsetattr_stdin_TCSANOW(&initial_settings); | 2218 | tcsetattr_stdin_TCSANOW(&initial_settings); |
2191 | /* restore SIGWINCH handler */ | 2219 | /* restore SIGWINCH handler */ |
2192 | signal(SIGWINCH, previous_SIGWINCH_handler); | 2220 | signal(SIGWINCH, previous_SIGWINCH_handler); |
2193 | fflush(stdout); | 2221 | fflush(NULL); |
2194 | 2222 | ||
2195 | len = command_len; | 2223 | len = command_len; |
2196 | DEINIT_S(); | 2224 | DEINIT_S(); |
@@ -2204,7 +2232,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2204 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) | 2232 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) |
2205 | { | 2233 | { |
2206 | fputs(prompt, stdout); | 2234 | fputs(prompt, stdout); |
2207 | fflush(stdout); | 2235 | fflush(NULL); |
2208 | fgets(command, maxsize, stdin); | 2236 | fgets(command, maxsize, stdin); |
2209 | return strlen(command); | 2237 | return strlen(command); |
2210 | } | 2238 | } |
diff --git a/libbb/read_key.c b/libbb/read_key.c index ec1b3a4a8..a2253ce3e 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -202,6 +202,31 @@ int64_t FAST_FUNC read_key(int fd, char *buffer) | |||
202 | break; | 202 | break; |
203 | } | 203 | } |
204 | n++; | 204 | n++; |
205 | /* Try to decipher "ESC [ NNN ; NNN R" sequence */ | ||
206 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL | ||
207 | && n >= 5 | ||
208 | && buffer[0] == '[' | ||
209 | && buffer[n-1] == 'R' | ||
210 | && isdigit(buffer[1]) | ||
211 | ) { | ||
212 | char *end; | ||
213 | unsigned long row, col; | ||
214 | |||
215 | row = strtoul(buffer + 1, &end, 10); | ||
216 | if (*end != ';' || !isdigit(end[1])) | ||
217 | continue; | ||
218 | col = strtoul(end + 1, &end, 10); | ||
219 | if (*end != 'R') | ||
220 | continue; | ||
221 | if (row < 1 || col < 1 || (row | col) > 0x7fff) | ||
222 | continue; | ||
223 | |||
224 | buffer[-1] = 0; | ||
225 | /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */ | ||
226 | col |= (((-1 << 15) | row) << 16); | ||
227 | /* Return it in high-order word */ | ||
228 | return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS; | ||
229 | } | ||
205 | } | 230 | } |
206 | got_all: | 231 | got_all: |
207 | 232 | ||
@@ -213,34 +238,6 @@ int64_t FAST_FUNC read_key(int fd, char *buffer) | |||
213 | return 27; | 238 | return 27; |
214 | } | 239 | } |
215 | 240 | ||
216 | /* Try to decipher "ESC [ NNN ; NNN R" sequence */ | ||
217 | if (ENABLE_FEATURE_EDITING_ASK_TERMINAL | ||
218 | && n >= 5 | ||
219 | && buffer[0] == '[' | ||
220 | && isdigit(buffer[1]) | ||
221 | && buffer[n-1] == 'R' | ||
222 | ) { | ||
223 | char *end; | ||
224 | unsigned long row, col; | ||
225 | |||
226 | row = strtoul(buffer + 1, &end, 10); | ||
227 | if (*end != ';' || !isdigit(end[1])) | ||
228 | goto not_R; | ||
229 | col = strtoul(end + 1, &end, 10); | ||
230 | if (*end != 'R') | ||
231 | goto not_R; | ||
232 | if (row < 1 || col < 1 || (row | col) > 0x7fff) | ||
233 | goto not_R; | ||
234 | |||
235 | buffer[-1] = 0; | ||
236 | |||
237 | /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */ | ||
238 | col |= (((-1 << 15) | row) << 16); | ||
239 | /* Return it in high-order word */ | ||
240 | return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS; | ||
241 | } | ||
242 | not_R: | ||
243 | |||
244 | /* We were doing "buffer[-1] = n; return c;" here, but this results | 241 | /* We were doing "buffer[-1] = n; return c;" here, but this results |
245 | * in unknown key sequences being interpreted as ESC + garbage. | 242 | * in unknown key sequences being interpreted as ESC + garbage. |
246 | * This was not useful. Pretend there was no key pressed, | 243 | * This was not useful. Pretend there was no key pressed, |