aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-03-05 12:31:30 +0000
committerRon Yorston <rmy@pobox.com>2023-03-05 12:31:30 +0000
commitf52c2004b818ac739ec886d5ff0a87734b55d293 (patch)
treee68d21ec6e1673e458d1e5b3827c08af146cd14a
parent76d3eafb4c28bc6579baff917ffe7726acf6817a (diff)
downloadbusybox-w32-f52c2004b818ac739ec886d5ff0a87734b55d293.tar.gz
busybox-w32-f52c2004b818ac739ec886d5ff0a87734b55d293.tar.bz2
busybox-w32-f52c2004b818ac739ec886d5ff0a87734b55d293.zip
win32: changes to console mode handling
Add the environment variable BB_TERMINAL_MODE as a more general way of controlling console/terminal mode setting. The default remains unchanged: use virtual terminal mode for output if possible but fall back to the console API with emulated ANSI escape sequences. Currently valid settings are: 0 Force use of console mode 1 Force use of virtual terminal mode for output 5 Prefer virtual terminal mode for output, fall back to console Other values won't do anything useful until code elsewhere has been updated. BB_SKIP_ANSI_EMULATION remains available for backwards compatibility. If both variables are set BB_TERMINAL_MODE takes precedence.
-rw-r--r--Config.in29
-rw-r--r--README.md2
-rw-r--r--configs/make32_defconfig2
-rw-r--r--configs/make64_defconfig2
-rw-r--r--configs/mingw32_defconfig2
-rw-r--r--configs/mingw64_defconfig2
-rw-r--r--include/libbb.h3
-rw-r--r--include/mingw.h5
-rw-r--r--libbb/messages.c4
-rw-r--r--shell/ash.c9
-rw-r--r--win32/winansi.c76
11 files changed, 93 insertions, 43 deletions
diff --git a/Config.in b/Config.in
index 2a2672f29..11990ed41 100644
--- a/Config.in
+++ b/Config.in
@@ -455,22 +455,27 @@ config FEATURE_EURO
455 requires the OEM code page to be 858. If the OEM code page of 455 requires the OEM code page to be 858. If the OEM code page of
456 the console is 850 when BusyBox starts it's changed to 858. 456 the console is 850 when BusyBox starts it's changed to 858.
457 457
458config SKIP_ANSI_EMULATION_DEFAULT 458config TERMINAL_MODE
459 int "Default setting for ANSI escape sequences" 459 int "Default setting for terminal mode"
460 default 2 460 default 5
461 range 0 2 461 range 0 7
462 depends on PLATFORM_MINGW32 462 depends on PLATFORM_MINGW32
463 help 463 help
464 Control how ANSI escape sequences are handled. Possible values 464 Control I/O mode of the Windows console/terminal. Possible
465 are: 465 values are:
466 466
467 0 Always emulate escape sequences. 467 0 Console mode.
468 1 Always emit escape sequences. 468 1 Force terminal mode output.
469 2 Emit escape sequences if the terminal supports them, otherwise 469 2 Force terminal mode input.
470 emulate them. 470 3 Force terminal mode input and output.
471 471
472 Setting the environment variable BB_SKIP_ANSI_EMULATION overrides 472 4 Console mode.
473 this default. 473 5 Prefer terminal mode output, fall back to console mode.
474 6 Prefer terminal mode input, fall back to console mode.
475 7 Prefer terminal mode input and output, fall back to console.
476
477 Setting the environment variable BB_TERMINAL_MODE overrides this
478 default.
474 479
475config FEATURE_IMPROVED_COLOUR_MAPPING 480config FEATURE_IMPROVED_COLOUR_MAPPING
476 bool "More accurate colour mapping for ANSI emulation (0.6 kb)" 481 bool "More accurate colour mapping for ANSI emulation (0.6 kb)"
diff --git a/README.md b/README.md
index 2ea2fe9c0..2857eb51d 100644
--- a/README.md
+++ b/README.md
@@ -31,5 +31,5 @@ Then just `make`.
31 - Handling of users, groups and permissions is totally bogus. The system only admits to knowing about the current user and always returns the same hardcoded uid, gid and permission values. 31 - Handling of users, groups and permissions is totally bogus. The system only admits to knowing about the current user and always returns the same hardcoded uid, gid and permission values.
32 - Some crufty old Windows code (Windows XP, cmd.exe) doesn't like forward slashes in environment variables. The -X shell option (which must be the first argument) prevents busybox-w32 from changing backslashes to forward slashes. If Windows programs don't run from the shell it's worth trying it. 32 - Some crufty old Windows code (Windows XP, cmd.exe) doesn't like forward slashes in environment variables. The -X shell option (which must be the first argument) prevents busybox-w32 from changing backslashes to forward slashes. If Windows programs don't run from the shell it's worth trying it.
33 - If you want to install 32-bit BusyBox in a system directory on a 64-bit version of Windows you should put it in `C:\Windows\SysWOW64`, not `C:\Windows\System32` as you might expect. On 64-bit systems the latter is for 64-bit binaries. 33 - If you want to install 32-bit BusyBox in a system directory on a 64-bit version of Windows you should put it in `C:\Windows\SysWOW64`, not `C:\Windows\System32` as you might expect. On 64-bit systems the latter is for 64-bit binaries.
34 - The system tries to detect the best way to handle ANSI escape sequences for the terminal being used. If this doesn't work you can try setting the environment variable `BB_SKIP_ANSI_EMULATION=1` to force the use of literal ANSI escapes or `BB_SKIP_ANSI_EMULATION=0` to emulate them using the Windows console API. 34 - The system tries to detect the best way to handle the terminal being used. If this doesn't work you can try setting the environment variable `BB_TERMINAL_MODE=1` to force the use of literal ANSI escapes or `BB_TERMINAL_MODE=0` to emulate them using the Windows console API.
35 - It's possible to obtain pseudo-random numbers using `if=/dev/urandom` as the input file to `dd`. The same emulation of `/dev/urandom` is used internally by the `shred` utility and to support https in `wget`. Since the pseudo-random number generator isn't being seeded with sufficient entropy the randomness shouldn't be relied on for any serious use. 35 - It's possible to obtain pseudo-random numbers using `if=/dev/urandom` as the input file to `dd`. The same emulation of `/dev/urandom` is used internally by the `shred` utility and to support https in `wget`. Since the pseudo-random number generator isn't being seeded with sufficient entropy the randomness shouldn't be relied on for any serious use.
diff --git a/configs/make32_defconfig b/configs/make32_defconfig
index 7f7082abc..2c5c15ba9 100644
--- a/configs/make32_defconfig
+++ b/configs/make32_defconfig
@@ -52,7 +52,7 @@ CONFIG_FEATURE_PRNG_SHELL=y
52# CONFIG_FEATURE_ICON_STERM is not set 52# CONFIG_FEATURE_ICON_STERM is not set
53# CONFIG_FEATURE_ICON_ALL is not set 53# CONFIG_FEATURE_ICON_ALL is not set
54# CONFIG_FEATURE_EURO is not set 54# CONFIG_FEATURE_EURO is not set
55CONFIG_SKIP_ANSI_EMULATION_DEFAULT=2 55CONFIG_TERMINAL_MODE=5
56# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set 56# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set
57CONFIG_FEATURE_EXTRA_FILE_DATA=y 57CONFIG_FEATURE_EXTRA_FILE_DATA=y
58 58
diff --git a/configs/make64_defconfig b/configs/make64_defconfig
index 524025f6b..5fa5c4ebc 100644
--- a/configs/make64_defconfig
+++ b/configs/make64_defconfig
@@ -52,7 +52,7 @@ CONFIG_FEATURE_PRNG_SHELL=y
52# CONFIG_FEATURE_ICON_STERM is not set 52# CONFIG_FEATURE_ICON_STERM is not set
53# CONFIG_FEATURE_ICON_ALL is not set 53# CONFIG_FEATURE_ICON_ALL is not set
54# CONFIG_FEATURE_EURO is not set 54# CONFIG_FEATURE_EURO is not set
55CONFIG_SKIP_ANSI_EMULATION_DEFAULT=2 55CONFIG_TERMINAL_MODE=5
56# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set 56# CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING is not set
57CONFIG_FEATURE_EXTRA_FILE_DATA=y 57CONFIG_FEATURE_EXTRA_FILE_DATA=y
58 58
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index 78035dd25..360ea3b50 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -52,7 +52,7 @@ CONFIG_FEATURE_ICON=y
52# CONFIG_FEATURE_ICON_STERM is not set 52# CONFIG_FEATURE_ICON_STERM is not set
53CONFIG_FEATURE_ICON_ALL=y 53CONFIG_FEATURE_ICON_ALL=y
54CONFIG_FEATURE_EURO=y 54CONFIG_FEATURE_EURO=y
55CONFIG_SKIP_ANSI_EMULATION_DEFAULT=2 55CONFIG_TERMINAL_MODE=5
56CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 56CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
57CONFIG_FEATURE_EXTRA_FILE_DATA=y 57CONFIG_FEATURE_EXTRA_FILE_DATA=y
58 58
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index 1ef6024c1..0dc1d0d51 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -52,7 +52,7 @@ CONFIG_FEATURE_ICON=y
52# CONFIG_FEATURE_ICON_STERM is not set 52# CONFIG_FEATURE_ICON_STERM is not set
53CONFIG_FEATURE_ICON_ALL=y 53CONFIG_FEATURE_ICON_ALL=y
54CONFIG_FEATURE_EURO=y 54CONFIG_FEATURE_EURO=y
55CONFIG_SKIP_ANSI_EMULATION_DEFAULT=2 55CONFIG_TERMINAL_MODE=5
56CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 56CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
57CONFIG_FEATURE_EXTRA_FILE_DATA=y 57CONFIG_FEATURE_EXTRA_FILE_DATA=y
58 58
diff --git a/include/libbb.h b/include/libbb.h
index 94f0e40ec..4197a5e83 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -2375,7 +2375,8 @@ extern const char bbvar[] ALIGN1;
2375#define bbafter(p) (p + sizeof(#p)) 2375#define bbafter(p) (p + sizeof(#p))
2376#define BB_OVERRIDE_APPLETS bbvar 2376#define BB_OVERRIDE_APPLETS bbvar
2377#define BB_SKIP_ANSI_EMULATION bbafter(BB_OVERRIDE_APPLETS) 2377#define BB_SKIP_ANSI_EMULATION bbafter(BB_OVERRIDE_APPLETS)
2378#define BB_SYSTEMROOT bbafter(BB_SKIP_ANSI_EMULATION) 2378#define BB_TERMINAL_MODE bbafter(BB_SKIP_ANSI_EMULATION)
2379#define BB_SYSTEMROOT bbafter(BB_TERMINAL_MODE)
2379#endif 2380#endif
2380 2381
2381extern const int const_int_0; 2382extern const int const_int_0;
diff --git a/include/mingw.h b/include/mingw.h
index 6259bc2c6..b5b2fe169 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -545,6 +545,9 @@ char *is_prefixed_with_case(const char *string, const char *key) FAST_FUNC;
545char *is_suffixed_with_case(const char *string, const char *key) FAST_FUNC; 545char *is_suffixed_with_case(const char *string, const char *key) FAST_FUNC;
546void qsort_string_vector_case(char **sv, unsigned count) FAST_FUNC; 546void qsort_string_vector_case(char **sv, unsigned count) FAST_FUNC;
547 547
548#define VT_OUTPUT 1
549#define VT_INPUT 2
550
548/* 551/*
549 * helpers 552 * helpers
550 */ 553 */
@@ -581,7 +584,7 @@ char *xabsolute_path(char *path);
581char *get_drive_cwd(const char *path, char *buffer, int size); 584char *get_drive_cwd(const char *path, char *buffer, int size);
582void fix_path_case(char *path); 585void fix_path_case(char *path);
583void make_sparse(int fd, off_t start, off_t end); 586void make_sparse(int fd, off_t start, off_t end);
584int skip_ansi_emulation(int reset); 587int terminal_mode(int reset);
585int unix_path(const char *path); 588int unix_path(const char *path);
586int has_path(const char *file); 589int has_path(const char *file);
587int is_relative_path(const char *path); 590int is_relative_path(const char *path);
diff --git a/libbb/messages.c b/libbb/messages.c
index e35bf8c6b..3c9d8683a 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -36,10 +36,14 @@ const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
36 * BB_GLOBBING and BB_UMASK are excluded because users shouln't be 36 * BB_GLOBBING and BB_UMASK are excluded because users shouln't be
37 * messing with them; BB_ALT_BUFFER and BB_FIX_BACKSLASH are excluded 37 * messing with them; BB_ALT_BUFFER and BB_FIX_BACKSLASH are excluded
38 * because they only affect particular applets, not the shell itself. 38 * because they only affect particular applets, not the shell itself.
39 *
40 * If you change any of these you should also update the definitions in
41 * include/libbb.h.
39 */ 42 */
40const char bbvar[] ALIGN1 = 43const char bbvar[] ALIGN1 =
41 "BB_OVERRIDE_APPLETS\0" \ 44 "BB_OVERRIDE_APPLETS\0" \
42 "BB_SKIP_ANSI_EMULATION\0" \ 45 "BB_SKIP_ANSI_EMULATION\0" \
46 "BB_TERMINAL_MODE\0" \
43 "BB_SYSTEMROOT\0"; 47 "BB_SYSTEMROOT\0";
44#endif 48#endif
45const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 49const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
diff --git a/shell/ash.c b/shell/ash.c
index 742067216..d78c6e828 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2340,9 +2340,9 @@ static void change_realtime(const char *) FAST_FUNC;
2340 2340
2341#if ENABLE_PLATFORM_MINGW32 2341#if ENABLE_PLATFORM_MINGW32
2342static void FAST_FUNC 2342static void FAST_FUNC
2343change_skip_ansi(const char *newval UNUSED_PARAM) 2343change_terminal_mode(const char *newval UNUSED_PARAM)
2344{ 2344{
2345 skip_ansi_emulation(TRUE); 2345 terminal_mode(TRUE);
2346} 2346}
2347 2347
2348# define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS) 2348# define LINENO_INDEX (5 + 2 * ENABLE_ASH_MAIL + ENABLE_ASH_GETOPTS)
@@ -2387,7 +2387,8 @@ static const struct {
2387 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, 2387 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2388#endif 2388#endif
2389#if ENABLE_PLATFORM_MINGW32 2389#if ENABLE_PLATFORM_MINGW32
2390 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_skip_ansi }, 2390 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_SKIP_ANSI_EMULATION, change_terminal_mode },
2391 { VSTRFIXED|VTEXTFIXED|VUNSET, BB_TERMINAL_MODE, change_terminal_mode },
2391#endif 2392#endif
2392}; 2393};
2393 2394
@@ -14603,7 +14604,7 @@ cmdloop(int top)
14603 inter++; 14604 inter++;
14604 chkmail(); 14605 chkmail();
14605#if ENABLE_PLATFORM_MINGW32 14606#if ENABLE_PLATFORM_MINGW32
14606 skip_ansi_emulation(TRUE); 14607 terminal_mode(TRUE);
14607#endif 14608#endif
14608 } 14609 }
14609 n = parsecmd(inter); 14610 n = parsecmd(inter);
diff --git a/win32/winansi.c b/win32/winansi.c
index ef566684e..11a9327e1 100644
--- a/win32/winansi.c
+++ b/win32/winansi.c
@@ -71,22 +71,38 @@ static int is_wine(void)
71#define DISABLE_NEWLINE_AUTO_RETURN 0x0008 71#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
72#endif 72#endif
73 73
74int skip_ansi_emulation(int reset) 74int terminal_mode(int reset)
75{ 75{
76 static int skip = -1; 76 static int mode = -1;
77 77
78 if (skip < 0 || reset) { 78 if (mode < 0 || reset) {
79 int prefer;
79 HANDLE h; 80 HANDLE h;
80 DWORD oldmode, newmode; 81 DWORD oldmode, newmode;
81 const char *var = getenv(BB_SKIP_ANSI_EMULATION); 82 const char *term = getenv(BB_TERMINAL_MODE);
83 const char *skip = getenv(BB_SKIP_ANSI_EMULATION);
84
85 if (term) {
86 mode = atoi(term);
87 } else if (skip) {
88 mode = atoi(skip);
89 if (mode == 2)
90 mode = 5;
91 else if (mode != 1)
92 mode = 0;
93 } else {
94 mode = (getenv("CONEMUPID") != NULL || is_wine()) ? 0 :
95 CONFIG_TERMINAL_MODE;
96 }
82 97
83 if (var) { 98 if (mode < 0 || mode > 7) {
84 skip = atoi(var); 99 prefer = mode = 0;
85 if (skip < 0 || skip > 2) 100 } else if (mode > 3) {
86 skip = 0; 101 // Try to get requested mode, fall back to console on failure.
102 prefer = mode = mode - 4;
87 } else { 103 } else {
88 skip = (getenv("CONEMUPID") != NULL || is_wine()) ? 0 : 104 // Force the requested mode, even if we can't get it.
89 CONFIG_SKIP_ANSI_EMULATION_DEFAULT; 105 prefer = 0;
90 } 106 }
91 107
92 if (is_console(STDOUT_FILENO)) { 108 if (is_console(STDOUT_FILENO)) {
@@ -94,28 +110,48 @@ int skip_ansi_emulation(int reset)
94 if (GetConsoleMode(h, &oldmode)) { 110 if (GetConsoleMode(h, &oldmode)) {
95 // Try to recover from mode 0 induced by SSH. 111 // Try to recover from mode 0 induced by SSH.
96 newmode = oldmode == 0 ? 3 : oldmode; 112 newmode = oldmode == 0 ? 3 : oldmode;
97 if (skip) 113 if ((mode & VT_OUTPUT))
98 newmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 114 newmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
99 else 115 else
100 newmode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING; 116 newmode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
101 newmode &= ~DISABLE_NEWLINE_AUTO_RETURN; 117 newmode &= ~DISABLE_NEWLINE_AUTO_RETURN;
118
102 if (newmode != oldmode) { 119 if (newmode != oldmode) {
103 if (!SetConsoleMode(h, newmode) && skip == 2) 120 if (!SetConsoleMode(h, newmode)) {
104 skip = 0; 121 if ((prefer & VT_OUTPUT))
122 mode &= ~VT_OUTPUT;
123 newmode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
124 SetConsoleMode(h, newmode);
125 }
105 } 126 }
106 } 127 }
107 } 128 }
108 129
109 // Try to recover from mode 0 induced by SSH. 130 if (is_console_in(STDIN_FILENO)) {
110 if (reset && is_console_in(STDIN_FILENO)) {
111 h = GetStdHandle(STD_INPUT_HANDLE); 131 h = GetStdHandle(STD_INPUT_HANDLE);
112 if (GetConsoleMode(h, &oldmode) && oldmode == 0) { 132 if (GetConsoleMode(h, &oldmode)) {
113 SetConsoleMode(h, 0x1f7); 133 // Try to recover from mode 0 induced by SSH.
134 newmode = oldmode == 0 ? 0x1f7 : oldmode;
135 if ((mode & VT_INPUT))
136 newmode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
137 else
138 newmode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
139
140 if (newmode != oldmode) {
141 if (!SetConsoleMode(h, newmode)) {
142 if ((prefer & VT_INPUT))
143 mode &= ~VT_INPUT;
144 // Failure to set the new mode seems to leave
145 // the flag set. Forcibly unset it.
146 newmode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
147 SetConsoleMode(h, newmode);
148 }
149 }
114 } 150 }
115 } 151 }
116 } 152 }
117 153
118 return skip; 154 return mode;
119} 155}
120 156
121void set_title(const char *str) 157void set_title(const char *str)
@@ -768,7 +804,7 @@ static int ansi_emulate(const char *s, FILE *stream)
768 804
769 while (*pos) { 805 while (*pos) {
770 pos = strchr(str, '\033'); 806 pos = strchr(str, '\033');
771 if (pos && !skip_ansi_emulation(FALSE)) { 807 if (pos && !(terminal_mode(FALSE) & VT_OUTPUT)) {
772 size_t len = pos - str; 808 size_t len = pos - str;
773 809
774 if (len) { 810 if (len) {
@@ -1037,7 +1073,7 @@ static int ansi_emulate_write(int fd, const void *buf, size_t count)
1037 /* we've checked the data doesn't contain any NULs */ 1073 /* we've checked the data doesn't contain any NULs */
1038 while (*pos) { 1074 while (*pos) {
1039 pos = strchr(str, '\033'); 1075 pos = strchr(str, '\033');
1040 if (pos && !skip_ansi_emulation(FALSE)) { 1076 if (pos && !(terminal_mode(FALSE) & VT_OUTPUT)) {
1041 len = pos - str; 1077 len = pos - str;
1042 1078
1043 if (len) { 1079 if (len) {