aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2024-04-13 18:40:20 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2024-04-13 18:40:20 +0200
commitfd47f056765aed515f4c71118813f07be1402bee (patch)
tree5e2d6f5c01003989629aa898344b278d0cd3c6ec /libbb
parent681e4f5d922b9f0ea968238750d5c5d748eac809 (diff)
downloadbusybox-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.c62
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... */
349static void BB_PUTCHAR(wchar_t c) 349static 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: */
409int adjust_width_and_validate_wc(unsigned *width_adj, int wc); 409int 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
495static void beep(void) 495static 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 */
503static void put_prompt_custom(bool is_full) 503static 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)
600static void draw_custom(int y, int back_cursor, bool is_full) 603static 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
3028int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) 3031int 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;