From 8ade494aebe60ea14026d48025a462e6d0b58a7f Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 5 Mar 2023 12:34:31 +0000 Subject: win32: add support for virtual terminal input Alter certain applets to support virtual terminal input, if enabled. In many places this is achieved by building previously excluded upstream terminal-handling code. The busybox-w32 implementation of termios(3) functions does nothing if virtual terminal input is disabled, so it can be invoked regardless. Some applet-specific terminal-handling code is also required. This affects less, more, vi and command line editing in the shell. (The `more` applet isn't enabled in the default configuration.) This series of patches adds about 1.7KB to the binaries. --- editors/vi.c | 7 ------- libbb/lineedit.c | 21 +++++++++------------ miscutils/less.c | 27 ++++++++++++++++++--------- util-linux/more.c | 11 +++++++---- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 13f0ae8ee..74028e2b4 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -456,9 +456,7 @@ struct globals { #if ENABLE_FEATURE_VI_USE_SIGNALS sigjmp_buf restart; // int_handler() jumps to location remembered here #endif -#if !ENABLE_PLATFORM_MINGW32 struct termios term_orig; // remember what the cooked mode was -#endif int cindex; // saved character index for up/down motion smallint keep_index; // retain saved character index #if ENABLE_FEATURE_VI_COLON @@ -700,7 +698,6 @@ static int mysleep(int hund) } //----- Set terminal attributes -------------------------------- -#if !ENABLE_PLATFORM_MINGW32 static void rawmode(void) { // no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals @@ -712,10 +709,6 @@ static void cookmode(void) fflush_all(); tcsetattr_stdin_TCSANOW(&term_orig); } -#else -#define rawmode() ((void)0) -#define cookmode fflush_all -#endif //----- Terminal Drawing --------------------------------------- // The terminal is made up of 'rows' line of 'columns' columns. diff --git a/libbb/lineedit.c b/libbb/lineedit.c index c4f0c65f1..9bf2f89a5 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -726,7 +726,12 @@ static void input_forward(void) #if !ENABLE_PLATFORM_MINGW32 put_cur_glyph_and_inc_cursor(); #else - inc_cursor(); + { + if (terminal_mode(FALSE) & VT_INPUT) + put_cur_glyph_and_inc_cursor(); + else + inc_cursor(); + } #endif } @@ -2579,7 +2584,7 @@ static void sigaction2(int sig, struct sigaction *act) */ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) { - int len IF_NOT_PLATFORM_MINGW32(, n); + int len, n; int timeout; #if ENABLE_FEATURE_TAB_COMPLETION smallint lastWasTab = 0; @@ -2589,9 +2594,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman smallint vi_cmdmode = 0; #endif struct termios initial_settings; -#if !ENABLE_PLATFORM_MINGW32 struct termios new_settings; -#endif char read_key_buffer[KEYCODE_BUFFER_SIZE]; INIT_S(); @@ -2600,15 +2603,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman cmdedit_termw = 80; IF_FEATURE_EDITING_VI(delptr = delbuf;) -#if !ENABLE_PLATFORM_MINGW32 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ ); +#if !ENABLE_PLATFORM_MINGW32 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { #else - initial_settings.c_cc[VINTR] = CTRL('C'); - initial_settings.c_cc[VEOF] = CTRL('D'); - if (!isatty(0) || !isatty(1)) { + if (n != 0 || !isatty(0) || !isatty(1)) { #endif /* Happens when e.g. stty -echo was run before. * But if ICANON is not set, we don't come here. @@ -2661,9 +2662,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman #endif #define command command_must_not_be_used -#if !ENABLE_PLATFORM_MINGW32 tcsetattr_stdin_TCSANOW(&new_settings); -#endif #if 0 for (i = 0; i <= state->max_history; i++) @@ -3150,10 +3149,8 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman free_tab_completion_data(); #endif -#if !ENABLE_PLATFORM_MINGW32 /* restore initial_settings */ tcsetattr_stdin_TCSANOW(&initial_settings); -#endif #if ENABLE_FEATURE_EDITING_WINCH /* restore SIGWINCH handler */ sigaction_set(SIGWINCH, &S.SIGWINCH_handler); diff --git a/miscutils/less.c b/miscutils/less.c index 842031ca3..467c76e2a 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -240,9 +240,7 @@ struct globals { smallint winsize_err; #endif smallint terminated; -#if !ENABLE_PLATFORM_MINGW32 struct termios term_orig, term_less; -#endif char kbd_input[KEYCODE_BUFFER_SIZE]; }; #define G (*ptr_to_globals) @@ -304,9 +302,7 @@ struct globals { static void set_tty_cooked(void) { fflush_all(); -#if !ENABLE_PLATFORM_MINGW32 tcsetattr(kbd_fd, TCSANOW, &term_orig); -#endif } /* Move the cursor to a position (x,y), where (0,0) is the @@ -1132,8 +1128,11 @@ static void reinitialize(void) buffer_fill_and_print(); } -#if !ENABLE_PLATFORM_MINGW32 +#if ENABLE_PLATFORM_MINGW32 +static int64_t unix_getch_nowait(void) +#else static int64_t getch_nowait(void) +#endif { int rd; int64_t key64; @@ -1194,11 +1193,15 @@ static int64_t getch_nowait(void) set_tty_cooked(); return key64; } -#else + +#if ENABLE_PLATFORM_MINGW32 static int64_t getch_nowait(void) { int64_t c; + if (terminal_mode(FALSE) & VT_INPUT) + return unix_getch_nowait(); + retry: c = _getch(); if (c == 0 || c == 0xe0) { @@ -1894,6 +1897,8 @@ int less_main(int argc, char **argv) { #if !ENABLE_PLATFORM_MINGW32 char *tty_name; +#else + HANDLE h; #endif int tty_fd; @@ -1980,12 +1985,16 @@ int less_main(int argc, char **argv) G.kbd_fd_orig_flags = ndelay_on(tty_fd); kbd_fd = tty_fd; /* save in a global */ #else - kbd_fd = tty_fd = 0; + h = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + bb_simple_error_msg_and_die("unable to open console"); + + kbd_fd = tty_fd = _open_osfhandle((intptr_t)h, O_BINARY); #endif -#if !ENABLE_PLATFORM_MINGW32 get_termios_and_make_raw(tty_fd, &term_less, &term_orig, TERMIOS_RAW_CRNL_INPUT); -#endif IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(tty_fd, &width, &max_displayed_line); /* 20: two tabstops + 4 */ diff --git a/util-linux/more.c b/util-linux/more.c index 07275131e..84ce37bc7 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -62,6 +62,7 @@ static void tcsetattr_tty_TCSANOW(struct termios *settings) tcsetattr(G.tty_fileno, TCSANOW, settings); } +#if !ENABLE_PLATFORM_MINGW32 static void gotsig(int sig UNUSED_PARAM) { /* bb_putchar_stderr doesn't use stdio buffering, @@ -70,6 +71,7 @@ static void gotsig(int sig UNUSED_PARAM) tcsetattr_tty_TCSANOW(&G.initial_settings); _exit(EXIT_FAILURE); } +#endif #define CONVERTED_TAB_SIZE 8 @@ -159,12 +161,13 @@ int more_main(int argc UNUSED_PARAM, char **argv) * to get input from the user. */ for (;;) { -#if !ENABLE_PLATFORM_MINGW32 fflush_all(); - input = getc(tty); -#else - input = _getch(); +#if ENABLE_PLATFORM_MINGW32 + if (!(terminal_mode(FALSE) & VT_INPUT)) + input = _getch(); + else #endif + input = getc(tty); input = tolower(input); /* Erase the last message */ printf("\r%*s\r", len, ""); -- cgit v1.2.3-55-g6feb