Like BUG-57912 and BUG-57913, this was encountered in https://www.smwcentral.net/?p=section&a=details&id=33546 (.resources/Lunar Magic/scripts/insert_all_patches.bat).
Unfortunately, I was unable to write a passing test; winetest redirects the child's stdout to a file, so GetConsoleScreenBufferInfo fails. And some of those numbers will vary between machines. Should I just drop the test?
From: Alfred Agrell floating@muncher.se
--- programs/cmd/builtins.c | 39 +++++++++++++++++++++++++++++++++++++++ programs/cmd/cmd.rc | 3 +++ programs/cmd/wcmd.h | 36 +++++++++++++++++++----------------- programs/cmd/wcmdmain.c | 3 +++ 4 files changed, 64 insertions(+), 17 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index d7c5090d17f..0e2499f2507 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -72,6 +72,7 @@ const WCHAR inbuilt[][10] = { L"START", L"TIME", L"TITLE", + L"MODE", L"TYPE", L"VERIFY", L"VER", @@ -3417,6 +3418,44 @@ RETURN_CODE WCMD_title(const WCHAR *args) return NO_ERROR; }
+/**************************************************************************** + * WCMD_mode + * + * Get the console size + */ +RETURN_CODE WCMD_mode(void) +{ + CONSOLE_SCREEN_BUFFER_INFO inf; + UINT keybd_speed, keybd_delay; + WCHAR buf[1024]; + WCHAR* buf_ptr; + + buf_ptr = buf; + errorlevel = NO_ERROR; + SystemParametersInfoA(SPI_GETKEYBOARDSPEED, 0, &keybd_speed, 0); + SystemParametersInfoA(SPI_GETKEYBOARDDELAY, 0, &keybd_delay, 0); + + buf_ptr += wsprintfW(buf_ptr, + L"\r\n" + L"Status for device CON:\r\n" + L"----------------------\r\n"); + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &inf)) { + buf_ptr += wsprintfW(buf_ptr, + L" Lines: %u\r\n" + L" Columns: %u\r\n" + L" Keyboard rate: %u\r\n" + L" Keyboard delay: %u\r\n" + L" Code page: %u\r\n", + inf.dwSize.Y, inf.dwSize.X, keybd_speed, keybd_delay, GetConsoleCP()); + } else { + errorlevel = GetLastError(); + buf_ptr += wsprintfW(buf_ptr, L" Not found\r\n"); + } + buf_ptr += wsprintfW(buf_ptr, L"\r\n"); + WCMD_output_asis(buf); + return errorlevel; +} + /**************************************************************************** * WCMD_type * diff --git a/programs/cmd/cmd.rc b/programs/cmd/cmd.rc index 90091090e11..83598bdc4d7 100644 --- a/programs/cmd/cmd.rc +++ b/programs/cmd/cmd.rc @@ -235,6 +235,9 @@ called from the command line.\n" WCMD_TITLE, "TITLE <string> sets the window title for the cmd window.\n"
+ WCMD_MODE, +"MODE tells the cmd window size.\n" + WCMD_TYPE, "TYPE <filename> copies <filename> to the console device (or elsewhere if\n\ redirected). No check is made that the file is readable text.\n" diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 225ebd44310..7331578ccbf 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -192,6 +192,7 @@ RETURN_CODE WCMD_setshow_time(void); RETURN_CODE WCMD_shift(const WCHAR *args); RETURN_CODE WCMD_start(WCHAR *args); RETURN_CODE WCMD_title(const WCHAR *); +RETURN_CODE WCMD_mode(void); RETURN_CODE WCMD_type(WCHAR *); RETURN_CODE WCMD_verify(void); RETURN_CODE WCMD_version(void); @@ -378,25 +379,26 @@ static inline BOOL WCMD_is_in_context(const WCHAR *ext) #define WCMD_START 29 #define WCMD_TIME 30 #define WCMD_TITLE 31 -#define WCMD_TYPE 32 -#define WCMD_VERIFY 33 -#define WCMD_VER 34 -#define WCMD_VOL 35 - -#define WCMD_ENDLOCAL 36 -#define WCMD_SETLOCAL 37 -#define WCMD_PUSHD 38 -#define WCMD_POPD 39 -#define WCMD_ASSOC 40 -#define WCMD_COLOR 41 -#define WCMD_FTYPE 42 -#define WCMD_MORE 43 -#define WCMD_CHOICE 44 -#define WCMD_MKLINK 45 -#define WCMD_CHGDRIVE 46 +#define WCMD_MODE 32 +#define WCMD_TYPE 33 +#define WCMD_VERIFY 34 +#define WCMD_VER 35 +#define WCMD_VOL 36 + +#define WCMD_ENDLOCAL 37 +#define WCMD_SETLOCAL 38 +#define WCMD_PUSHD 39 +#define WCMD_POPD 40 +#define WCMD_ASSOC 41 +#define WCMD_COLOR 42 +#define WCMD_FTYPE 43 +#define WCMD_MORE 44 +#define WCMD_CHOICE 45 +#define WCMD_MKLINK 46 +#define WCMD_CHGDRIVE 47
/* Must be last in list */ -#define WCMD_EXIT 47 +#define WCMD_EXIT 48
/* Some standard messages */ extern WCHAR anykey[]; diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 77f1112be23..12afd5ad7f5 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -1789,6 +1789,9 @@ RETURN_CODE WCMD_run_builtin_command(int cmd_index, WCHAR *cmd) case WCMD_TIME: return_code = WCMD_setshow_time(); break; + case WCMD_MODE: + return_code = WCMD_mode(); + break; case WCMD_TITLE: return_code = WCMD_title(parms_start); break;
From: Alfred Agrell floating@muncher.se
--- programs/cmd/tests/test_builtins.cmd | 7 +++++-- programs/cmd/tests/test_builtins.cmd.exp | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 1253e5fc2a5..a9ec590e286 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -3173,7 +3173,7 @@ regedit /s regCleanup.reg set WINE_FOO= endlocal cd .. & rd /s/q foobar -goto ContinueCall +goto ExitFtype :SkipFType echo --- setting association echo --- @@ -3190,8 +3190,11 @@ echo Skipped as not enough permissions echo Skipped as not enough permissions echo --- resetting association echo original value +:ExitFtype + +echo ------------ Testing mode ------------ +call :setError 666 & (mode CON &&echo SUCCESS %errorlevel%||echo FAILURE %errorlevel%)
-:ContinueCall echo ------------ Testing CALL ------------ mkdir foobar & cd foobar echo --- external script diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 6137c594359..457bdab8eb9 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -1861,6 +1861,17 @@ footype=cmd.exe /c "echo '%*'" foobar@or_broken@Skipped as not enough permissions --- resetting association original value@or_broken@buggyXP@or_broken@!WINE_FOO! +------------ Testing mode ------------ + +Status for device CON: +---------------------- +@todo_wine@ Lines: 9001 +@todo_wine@ Columns: 120 +@todo_wine@ Keyboard rate: 31 +@todo_wine@ Keyboard delay: 1 +@todo_wine@ Code page: 932 +@todo_wine@ +@todo_wine@SUCCESS 2 ------------ Testing CALL ------------ --- external script foo@space@
you likely need to reopen console (CONOUT$) attached to cmd.exe not the current output handle
as the MODE command deals with device, this command likely starts by opening the corresponding device (console, lpt serial line...)
for the tests, beware that cmd.exe output are localized so comparing command's output will not work
but you could (as tests):
* add a test for a non existent device * add a test for a non conforming CON configuration * try changing lines & columns and check in 'MODE CON:' output that the numerical values are present in output (findstr)
and put the tests dealing with errorlevel and return code in the relevant part of both test_builtins.cmd and test_builtins.bat
(more functional testing, like actually changing the screen buffer size, could go elsewhere only in the .cmd tests file)
in the code, from the behavior of lots of other builtin commands, it's very unlikely that the errorlevel is set with GetLastError()
On Mon Mar 10 14:42:07 2025 +0000, eric pouech wrote:
you likely need to reopen console (CONOUT$) attached to cmd.exe not the current output handle as the MODE command deals with device, this command likely starts by opening the corresponding device (console, lpt serial line...) for the tests, beware that cmd.exe output are localized so comparing command's output will not work but you could (as tests):
- add a test for a non existent device
- add a test for a non conforming CON configuration
- try changing lines & columns and check in 'MODE CON:' output that the
numerical values are present in output (findstr) and put the tests dealing with errorlevel and return code in the relevant part of both test_builtins.cmd and test_builtins.bat (more functional testing, like actually changing the screen buffer size, could go elsewhere only in the .cmd tests file) in the code, from the behavior of lots of other builtin commands, it's very unlikely that the errorlevel is set with GetLastError()
CONOUT$ is a good idea, yes. CON doesn't work (neither wine nor windows), but the MODE command seems to do string comparison on the device name, so hardcoding CONOUT$ instead is fine.
You're right about errorlevel, it's just 0 or -1. Fixed.
Setting console size feels a bit like scope creep, but if it's the only way to test the thing, then so be it.