These changes fix two TYPE issues:
- TYPE output should terminate at a Ctrl-Z EOF character, if output is not redirected. - TYPE redirection should function as a rudimentary file copy (bug #56381).
Tests run: TYPE text_file_containing_embedded_ctrl_z.txt (Output terminates at Ctrl-Z character.)
TYPE c:\windows\winhelp.exe >foo (Issue raised in bug #56381. Foo is identical copy of winhelp.exe and not truncated at first NUL character. Test for this case was added to the automated tests.)
CHCP 65001 TYPE text_file_containing_unicode_characters.txt (Unicode characters were output to the console.)
From: Joe Souza jsouza@yahoo.com
--- programs/cmd/builtins.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index b5ad78ab9c7..5efd522259f 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -3417,9 +3417,11 @@ RETURN_CODE WCMD_type(WCHAR *args) while (argN) { WCHAR *thisArg = WCMD_parameter (args, argno++, &argN, FALSE, FALSE);
- HANDLE h; - WCHAR buffer[512]; + HANDLE h, hOut; + char buffer[1024]; DWORD count; + BOOL output_redirected; + char *eof;
if (!argN) break;
@@ -3434,10 +3436,24 @@ RETURN_CODE WCMD_type(WCHAR *args) if (writeHeaders) { WCMD_output_stderr(L"\n%1\n\n\n", thisArg); } - while (WCMD_ReadFile(h, buffer, ARRAY_SIZE(buffer) - 1, &count)) { + + hOut = GetStdHandle(STD_OUTPUT_HANDLE); + output_redirected = (GetFileType(hOut) != FILE_TYPE_CHAR); + + while (ReadFile(h, buffer, ARRAY_SIZE(buffer) - 1, &count, NULL)) { if (count == 0) break; /* ReadFile reports success on EOF! */ buffer[count] = 0; - WCMD_output_asis (buffer); + /* If output is not redirected then TYPE terminates at the EOF character. */ + if (!output_redirected) { + eof = (char *)memchr((void *)buffer, '\x1A', count); + if (eof) { + count = (DWORD)(eof - buffer); + } + } + WriteFile(hOut, buffer, count, &count, NULL); + if (!output_redirected && eof) { + break; + } } CloseHandle (h); }
From: Joe Souza jsouza@yahoo.com
--- programs/cmd/tests/test_builtins.cmd | 22 ++++++++++++++++++++++ programs/cmd/tests/test_builtins.cmd.exp | 2 ++ 2 files changed, 24 insertions(+)
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 9f144bb4e0a..9f41ded4e29 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -1405,6 +1405,10 @@ echo ---6 type foobaw echo ---7 del foobaz foobay foobax foobaw +echo ---8 +type c:\windows\winhelp.exe >foo +call :CompareFileSizes c:\windows\winhelp.exe foo +del foo
echo ------------ Testing NUL ------------ md foobar & cd foobar @@ -3513,6 +3517,24 @@ shift if not "%1"=="" goto :CheckFileSize goto :eof
+:CompareFileSizes +if not exist "%1" ( + echo Failed: File missing in CompareFileSizes [%1] + goto :eof +) +if not exist "%2" ( + echo Failed: File missing in CompareFileSizes [%2] + goto :eof +) +for %%i in (%1) do set WINE_filesize1=%%~zi +for %%j in (%2) do set WINE_filesize2=%%~zj +if "%WINE_filesize1%"=="%WINE_filesize2%" ( + echo Passed: file sizes are equal %1 %2 +) else ( + echo Failed: file sizes are not equal %1 %2 +) +goto :eof + :testcopy
rem ----------------------- diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 6ec30eba3a7..387d3b26c3a 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -994,6 +994,8 @@ foobay
---7 +---8 +Passed: file sizes are equal c:\windows\winhelp.exe foo ------------ Testing NUL ------------ bar bar
eric pouech (@epo) commented about programs/cmd/tests/test_builtins.cmd:
type foobaw echo ---7 del foobaz foobay foobax foobaw +echo ---8 +type c:\windows\winhelp.exe >foo
we'd better create our own test files... see chcp related tests in test_builtin.cmd to insert any hex character
eric pouech (@epo) commented about programs/cmd/tests/test_builtins.cmd:
if not "%1"=="" goto :CheckFileSize goto :eof
+:CompareFileSizes
1) it's overkill to test if files exist 2) why not using only (untested): ``` if "%~z1"=="%~z2" (echo passed) else (echo failed) goto :eof ``` (and there's no need to print the filenames)
from a global view: my first thought was that the behavior should be:
- if output handle has a console code page (GetConsoleOutputCP()), then input file has to be converted to that code page (and it seems also that native cmd.exe supports some BOM from input file, can be done in a later patch). and likely treat input file as text (to handle ctrl-z). And input CP should come from BOM presence or not. - otherwise, a simple binary copy would do
but, things are not that simple :-(
`type foo > con:` does output the whole file (no ctrl-z handling) in binary mode to the console (still using current CP for conversion)
so CP conversion (if any) comes from current output handle CP (GetConsoleOutputCP())
text vs binary mode seems to be driven by redirection or not (best solution is likely to store as global variable the output handle at cmd.exe startup and compare if current stdout handle if the initial one or not)
Did you try to reuse the COPY command helpers (at least for the binary copy)? (note also that `TYPE CON: > foo `works as `COPY CON: foo`)
Would like to have some tests for TYPE in various CP. But couldn't find a simple way to do it as default stdout in tests is not bound to a console, and if we force output to console we'll loose the output) (would require reading back console's screenbuffer)