diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2024-04-13 18:40:20 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2024-04-13 18:40:20 +0200 |
| commit | fd47f056765aed515f4c71118813f07be1402bee (patch) | |
| tree | 5e2d6f5c01003989629aa898344b278d0cd3c6ec /libbb | |
| parent | 681e4f5d922b9f0ea968238750d5c5d748eac809 (diff) | |
| download | busybox-w32-fd47f056765aed515f4c71118813f07be1402bee.tar.gz busybox-w32-fd47f056765aed515f4c71118813f07be1402bee.tar.bz2 busybox-w32-fd47f056765aed515f4c71118813f07be1402bee.zip | |
lineedit: print prompt and editing operations to stderr
For shells, this is mandated by standards
function old new delta
input_backward 215 231 +16
read_line_input 3015 3028 +13
draw_custom 66 78 +12
put_cur_glyph_and_inc_cursor 149 159 +10
put_prompt_custom 47 56 +9
show_history 40 46 +6
input_tab 927 933 +6
input_delete 136 142 +6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 8/0 up/down: 78/0) Total: 78 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/lineedit.c | 62 |
1 files changed, 34 insertions, 28 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index bdae10914..543a3f11c 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
| @@ -345,7 +345,7 @@ static unsigned save_string(char *dst, unsigned maxsize) | |||
| 345 | return i; | 345 | return i; |
| 346 | } | 346 | } |
| 347 | } | 347 | } |
| 348 | /* I thought just fputwc(c, stdout) would work. But no... */ | 348 | /* I thought just fputwc(c, stderr) would work. But no... */ |
| 349 | static void BB_PUTCHAR(wchar_t c) | 349 | static void BB_PUTCHAR(wchar_t c) |
| 350 | { | 350 | { |
| 351 | if (unicode_status == UNICODE_ON) { | 351 | if (unicode_status == UNICODE_ON) { |
| @@ -354,11 +354,11 @@ static void BB_PUTCHAR(wchar_t c) | |||
| 354 | ssize_t len = wcrtomb(buf, c, &mbst); | 354 | ssize_t len = wcrtomb(buf, c, &mbst); |
| 355 | if (len > 0) { | 355 | if (len > 0) { |
| 356 | buf[len] = '\0'; | 356 | buf[len] = '\0'; |
| 357 | fputs_stdout(buf); | 357 | fputs(buf, stderr); |
| 358 | } | 358 | } |
| 359 | } else { | 359 | } else { |
| 360 | /* In this case, c is always one byte */ | 360 | /* In this case, c is always one byte */ |
| 361 | putchar(c); | 361 | bb_putchar_stderr(c); |
| 362 | } | 362 | } |
| 363 | } | 363 | } |
| 364 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS | 364 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS |
| @@ -404,7 +404,7 @@ static void save_string(char *dst, unsigned maxsize) | |||
| 404 | safe_strncpy(dst, command_ps, maxsize); | 404 | safe_strncpy(dst, command_ps, maxsize); |
| 405 | } | 405 | } |
| 406 | # endif | 406 | # endif |
| 407 | # define BB_PUTCHAR(c) bb_putchar(c) | 407 | # define BB_PUTCHAR(c) bb_putchar_stderr(c) |
| 408 | /* Should never be called: */ | 408 | /* Should never be called: */ |
| 409 | int adjust_width_and_validate_wc(unsigned *width_adj, int wc); | 409 | int adjust_width_and_validate_wc(unsigned *width_adj, int wc); |
| 410 | #endif | 410 | #endif |
| @@ -463,7 +463,7 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
| 463 | if (c == BB_NUL) | 463 | if (c == BB_NUL) |
| 464 | c = ' '; | 464 | c = ' '; |
| 465 | BB_PUTCHAR(c); | 465 | BB_PUTCHAR(c); |
| 466 | bb_putchar('\b'); | 466 | bb_putchar_stderr('\b'); |
| 467 | #endif | 467 | #endif |
| 468 | cmdedit_y++; | 468 | cmdedit_y++; |
| 469 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { | 469 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { |
| @@ -489,12 +489,12 @@ static void goto_new_line(void) | |||
| 489 | put_till_end_and_adv_cursor(); | 489 | put_till_end_and_adv_cursor(); |
| 490 | /* "cursor == 0" is only if prompt is "" and user input is empty */ | 490 | /* "cursor == 0" is only if prompt is "" and user input is empty */ |
| 491 | if (cursor == 0 || cmdedit_x != 0) | 491 | if (cursor == 0 || cmdedit_x != 0) |
| 492 | bb_putchar('\n'); | 492 | bb_putchar_stderr('\n'); |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | static void beep(void) | 495 | static void beep(void) |
| 496 | { | 496 | { |
| 497 | bb_putchar('\007'); | 497 | bb_putchar_stderr('\007'); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | /* Full or last/sole prompt line, reset edit cursor, calculate terminal cursor. | 500 | /* Full or last/sole prompt line, reset edit cursor, calculate terminal cursor. |
| @@ -502,7 +502,10 @@ static void beep(void) | |||
| 502 | */ | 502 | */ |
| 503 | static void put_prompt_custom(bool is_full) | 503 | static void put_prompt_custom(bool is_full) |
| 504 | { | 504 | { |
| 505 | fputs_stdout((is_full ? cmdedit_prompt : prompt_last_line)); | 505 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
| 506 | * says that shells must write $PSn to stderr, not stdout. | ||
| 507 | */ | ||
| 508 | fputs((is_full ? cmdedit_prompt : prompt_last_line), stderr); | ||
| 506 | cursor = 0; | 509 | cursor = 0; |
| 507 | cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */ | 510 | cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */ |
| 508 | cmdedit_x = cmdedit_prmt_len % cmdedit_termw; | 511 | cmdedit_x = cmdedit_prmt_len % cmdedit_termw; |
| @@ -539,15 +542,15 @@ static void input_backward(unsigned num) | |||
| 539 | /* This is longer by 5 bytes on x86. | 542 | /* This is longer by 5 bytes on x86. |
| 540 | * Also gets miscompiled for ARM users | 543 | * Also gets miscompiled for ARM users |
| 541 | * (busybox.net/bugs/view.php?id=2274). | 544 | * (busybox.net/bugs/view.php?id=2274). |
| 542 | * printf(("\b\b\b\b" + 4) - num); | 545 | * fprintf(("\b\b\b\b" + 4) - num, stderr); |
| 543 | * return; | 546 | * return; |
| 544 | */ | 547 | */ |
| 545 | do { | 548 | do { |
| 546 | bb_putchar('\b'); | 549 | bb_putchar_stderr('\b'); |
| 547 | } while (--num); | 550 | } while (--num); |
| 548 | return; | 551 | return; |
| 549 | } | 552 | } |
| 550 | printf(ESC"[%uD", num); | 553 | fprintf(stderr, ESC"[%uD", num); |
| 551 | return; | 554 | return; |
| 552 | } | 555 | } |
| 553 | 556 | ||
| @@ -572,7 +575,7 @@ static void input_backward(unsigned num) | |||
| 572 | */ | 575 | */ |
| 573 | unsigned sv_cursor; | 576 | unsigned sv_cursor; |
| 574 | /* go to 1st column; go up to first line */ | 577 | /* go to 1st column; go up to first line */ |
| 575 | printf("\r" ESC"[%uA", cmdedit_y); | 578 | fprintf(stderr, "\r" ESC"[%uA", cmdedit_y); |
| 576 | cmdedit_y = 0; | 579 | cmdedit_y = 0; |
| 577 | sv_cursor = cursor; | 580 | sv_cursor = cursor; |
| 578 | put_prompt_last_line(); /* sets cursor to 0 */ | 581 | put_prompt_last_line(); /* sets cursor to 0 */ |
| @@ -587,12 +590,12 @@ static void input_backward(unsigned num) | |||
| 587 | cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw; | 590 | cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw; |
| 588 | cmdedit_y -= lines_up; | 591 | cmdedit_y -= lines_up; |
| 589 | /* go to 1st column; go up */ | 592 | /* go to 1st column; go up */ |
| 590 | printf("\r" ESC"[%uA", lines_up); | 593 | fprintf(stderr, "\r" ESC"[%uA", lines_up); |
| 591 | /* go to correct column. | 594 | /* go to correct column. |
| 592 | * xterm, konsole, Linux VT interpret 0 as 1 below! wow. | 595 | * xterm, konsole, Linux VT interpret 0 as 1 below! wow. |
| 593 | * need to *make sure* we skip it if cmdedit_x == 0 */ | 596 | * need to *make sure* we skip it if cmdedit_x == 0 */ |
| 594 | if (cmdedit_x) | 597 | if (cmdedit_x) |
| 595 | printf(ESC"[%uC", cmdedit_x); | 598 | fprintf(stderr, ESC"[%uC", cmdedit_x); |
| 596 | } | 599 | } |
| 597 | } | 600 | } |
| 598 | 601 | ||
| @@ -600,11 +603,11 @@ static void input_backward(unsigned num) | |||
| 600 | static void draw_custom(int y, int back_cursor, bool is_full) | 603 | static void draw_custom(int y, int back_cursor, bool is_full) |
| 601 | { | 604 | { |
| 602 | if (y > 0) /* up y lines */ | 605 | if (y > 0) /* up y lines */ |
| 603 | printf(ESC"[%uA", y); | 606 | fprintf(stderr, ESC"[%uA", y); |
| 604 | bb_putchar('\r'); | 607 | bb_putchar_stderr('\r'); |
| 605 | put_prompt_custom(is_full); | 608 | put_prompt_custom(is_full); |
| 606 | put_till_end_and_adv_cursor(); | 609 | put_till_end_and_adv_cursor(); |
| 607 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 610 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
| 608 | input_backward(back_cursor); | 611 | input_backward(back_cursor); |
| 609 | } | 612 | } |
| 610 | 613 | ||
| @@ -649,7 +652,7 @@ static void input_delete(int save) | |||
| 649 | command_len--; | 652 | command_len--; |
| 650 | put_till_end_and_adv_cursor(); | 653 | put_till_end_and_adv_cursor(); |
| 651 | /* Last char is still visible, erase it (and more) */ | 654 | /* Last char is still visible, erase it (and more) */ |
| 652 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 655 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
| 653 | input_backward(cursor - j); /* back to old pos cursor */ | 656 | input_backward(cursor - j); /* back to old pos cursor */ |
| 654 | } | 657 | } |
| 655 | 658 | ||
| @@ -984,8 +987,8 @@ static void remove_chunk(int16_t *int_buf, int beg, int end) | |||
| 984 | if (dbg_bmp) { | 987 | if (dbg_bmp) { |
| 985 | int i; | 988 | int i; |
| 986 | for (i = 0; int_buf[i]; i++) | 989 | for (i = 0; int_buf[i]; i++) |
| 987 | bb_putchar((unsigned char)int_buf[i]); | 990 | bb_putchar_stderr((unsigned char)int_buf[i]); |
| 988 | bb_putchar('\n'); | 991 | bb_putchar_stderr('\n'); |
| 989 | } | 992 | } |
| 990 | } | 993 | } |
| 991 | /* Caller ensures that match_buf points to a malloced buffer | 994 | /* Caller ensures that match_buf points to a malloced buffer |
| @@ -1162,7 +1165,7 @@ static void showfiles(void) | |||
| 1162 | int nc; | 1165 | int nc; |
| 1163 | 1166 | ||
| 1164 | for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { | 1167 | for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { |
| 1165 | printf("%s%-*s", matches[n], | 1168 | fprintf(stderr, "%s%-*s", matches[n], |
| 1166 | (int)(column_width - unicode_strwidth(matches[n])), "" | 1169 | (int)(column_width - unicode_strwidth(matches[n])), "" |
| 1167 | ); | 1170 | ); |
| 1168 | } | 1171 | } |
| @@ -1460,7 +1463,7 @@ void FAST_FUNC show_history(const line_input_t *st) | |||
| 1460 | if (!st) | 1463 | if (!st) |
| 1461 | return; | 1464 | return; |
| 1462 | for (i = 0; i < st->cnt_history; i++) | 1465 | for (i = 0; i < st->cnt_history; i++) |
| 1463 | printf("%4d %s\n", i, st->history[i]); | 1466 | fprintf(stderr, "%4d %s\n", i, st->history[i]); |
| 1464 | } | 1467 | } |
| 1465 | 1468 | ||
| 1466 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1469 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
| @@ -1900,7 +1903,7 @@ static void ask_terminal(void) | |||
| 1900 | pfd.events = POLLIN; | 1903 | pfd.events = POLLIN; |
| 1901 | if (safe_poll(&pfd, 1, 0) == 0) { | 1904 | if (safe_poll(&pfd, 1, 0) == 0) { |
| 1902 | S.sent_ESC_br6n = 1; | 1905 | S.sent_ESC_br6n = 1; |
| 1903 | fputs_stdout(ESC"[6n"); | 1906 | fputs(ESC"[6n", stderr); |
| 1904 | fflush_all(); /* make terminal see it ASAP! */ | 1907 | fflush_all(); /* make terminal see it ASAP! */ |
| 1905 | } | 1908 | } |
| 1906 | } | 1909 | } |
| @@ -2639,13 +2642,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2639 | /* Control-k -- clear to end of line */ | 2642 | /* Control-k -- clear to end of line */ |
| 2640 | command_ps[cursor] = BB_NUL; | 2643 | command_ps[cursor] = BB_NUL; |
| 2641 | command_len = cursor; | 2644 | command_len = cursor; |
| 2642 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 2645 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
| 2643 | break; | 2646 | break; |
| 2644 | case CTRL('L'): | 2647 | case CTRL('L'): |
| 2645 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) | 2648 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) |
| 2646 | /* Control-l -- clear screen */ | 2649 | /* Control-l -- clear screen */ |
| 2647 | /* cursor to top,left; clear to the end of screen */ | 2650 | /* cursor to top,left; clear to the end of screen */ |
| 2648 | printf(ESC"[H" ESC"[J"); | 2651 | fputs(ESC"[H" ESC"[J", stderr); |
| 2649 | draw_full(command_len - cursor); | 2652 | draw_full(command_len - cursor); |
| 2650 | break; | 2653 | break; |
| 2651 | #if MAX_HISTORY > 0 | 2654 | #if MAX_HISTORY > 0 |
| @@ -2832,8 +2835,8 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 2832 | beep(); | 2835 | beep(); |
| 2833 | } else { | 2836 | } else { |
| 2834 | command_ps[cursor] = ic; | 2837 | command_ps[cursor] = ic; |
| 2835 | bb_putchar(ic); | 2838 | bb_putchar_stderr(ic); |
| 2836 | bb_putchar('\b'); | 2839 | bb_putchar_stderr('\b'); |
| 2837 | } | 2840 | } |
| 2838 | break; | 2841 | break; |
| 2839 | case '\x1b': /* ESC */ | 2842 | case '\x1b': /* ESC */ |
| @@ -3027,7 +3030,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
| 3027 | #undef read_line_input | 3030 | #undef read_line_input |
| 3028 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) | 3031 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) |
| 3029 | { | 3032 | { |
| 3030 | fputs_stdout(prompt); | 3033 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
| 3034 | * says that shells must write $PSn to stderr, not stdout. | ||
| 3035 | */ | ||
| 3036 | fputs(prompt, stderr); | ||
| 3031 | fflush_all(); | 3037 | fflush_all(); |
| 3032 | if (!fgets(command, maxsize, stdin)) | 3038 | if (!fgets(command, maxsize, stdin)) |
| 3033 | return -1; | 3039 | return -1; |
