From: Eric Pouech epouech@codeweavers.com
Clean-up: - using WCMD_fgets() to get input, - using helper to factorize the two forms of the MORE command.
Enhancements and let behavior be closer to native: - when using 'MORE file1 file2...', stop displaying files at the first non existing one, - can break MORE with ctrl-c, - the information display + wait at the end of each page is only activated when outputting to console, - the bottom information line is overwritten by next line.
Note native MORE outputs to CONOUT$ (not stdout), which makes it hard for adding tests.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/builtins.c | 163 +++++++++++++++++++--------------------- programs/cmd/wcmd.h | 1 + programs/cmd/wcmdmain.c | 13 +++- 3 files changed, 88 insertions(+), 89 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index d777ac197ae..2db7d3d53aa 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -3462,112 +3462,101 @@ RETURN_CODE WCMD_type(WCHAR *args) return errorlevel = return_code; }
-/**************************************************************************** - * WCMD_more - * - * Output either a file or stdin to screen in pages - */ - -RETURN_CODE WCMD_more(WCHAR *args) +static RETURN_CODE page_file(HANDLE h, ULONG64 file_length, BOOL close_previous) { - int argno = 0; - WCHAR *argN = args; - WCHAR moreStr[100]; - WCHAR moreStrPage[100]; - WCHAR buffer[512]; - DWORD count; - RETURN_CODE return_code = NO_ERROR; + WCHAR more_string[100]; + WCHAR page_string[100]; + WCHAR buffer[MAXSTRING]; + RETURN_CODE return_code = NO_ERROR; + DWORD dummy; + BOOL is_output_console = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummy);
- /* Prefix the NLS more with '-- ', then load the text */ - lstrcpyW(moreStr, L"-- "); - LoadStringW(hinst, WCMD_MORESTR, &moreStr[3], ARRAY_SIZE(moreStr)-3); + LoadStringW(hinst, WCMD_MORESTR, more_string, ARRAY_SIZE(more_string));
- if (param1[0] == 0x00) { + wsprintfW(page_string, L"-- %s --", more_string);
- /* Wine implements pipes via temporary files, and hence stdin is - effectively reading from the file. This means the prompts for - more are satisfied by the next line from the input (file). To - avoid this, ensure stdin is to the console */ - HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE); - HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0); - WINE_TRACE("No parms - working probably in pipe mode\n"); - SetStdHandle(STD_INPUT_HANDLE, hConIn); - - /* Warning: No easy way of ending the stream (ctrl+z on windows) so - once you get in this bit unless due to a pipe, it's going to end badly... */ - wsprintfW(moreStrPage, L"%s --\n", moreStr); - - WCMD_enter_paged_mode(moreStrPage); - while (WCMD_ReadFile(hstdin, buffer, ARRAY_SIZE(buffer)-1, &count)) { - if (count == 0) break; /* ReadFile reports success on EOF! */ - buffer[count] = 0; - WCMD_output_asis (buffer); + if (close_previous) + { + if (is_output_console) + { + wsprintfW(page_string, L"-- %s (100%%) --", more_string); + WCMD_output_asis(page_string); + WCMD_output_flush(); + } + WCMD_wait_for_console_input(); + if (is_output_console) + WCMD_output_asis(L"\r"); } - WCMD_leave_paged_mode();
- /* Restore stdin to what it was */ - SetStdHandle(STD_INPUT_HANDLE, hstdin); - CloseHandle(hConIn); - WCMD_output_asis (L"\r\n"); - } else { - BOOL needsPause = FALSE; + WCMD_enter_paged_mode(page_string); + while (return_code == NO_ERROR && WCMD_fgets(buffer, ARRAY_SIZE(buffer), h)) + { + LARGE_INTEGER lizero = {.QuadPart = 0}, lipos;
- /* Loop through all args */ - WINE_TRACE("Parms supplied - working through each file\n"); - WCMD_enter_paged_mode(moreStrPage); + if (file_length && SetFilePointerEx(h, lizero, &lipos, FILE_CURRENT)) + wsprintfW(page_string, L"-- %s (%2.2d%%) --", more_string, + min(99, (int)(lipos.QuadPart * 100) / file_length));
- while (argN) { - WCHAR *thisArg = WCMD_parameter (args, argno++, &argN, FALSE, FALSE); - HANDLE h; + WCMD_output_asis(buffer); + WCMD_output_asis(L"\r\n");
- if (!argN) break; + return_code = WCMD_ctrlc_status(); + } + WCMD_leave_paged_mode();
- if (needsPause) { + return return_code; +}
- /* Wait */ - wsprintfW(moreStrPage, L"%s (%2.2d%%) --\n", moreStr, 100); - WCMD_leave_paged_mode(); - WCMD_output_asis(moreStrPage); - WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), buffer, ARRAY_SIZE(buffer), &count); - WCMD_enter_paged_mode(moreStrPage); - } +/**************************************************************************** + * WCMD_more + * + * Output either a file or stdin to screen in pages + */ +RETURN_CODE WCMD_more(WCHAR *args) +{ + int argno = 0; + WCHAR *argN;
+ if (param1[0] == 0x00) + { + WINE_TRACE("No parms - working probably in pipe mode\n"); + page_file(GetStdHandle(STD_INPUT_HANDLE), 0, FALSE); + WCMD_output_asis(L"\r\n"); + } + else + { + RETURN_CODE return_code = NO_ERROR;
- WINE_TRACE("more: Processing arg '%s'\n", wine_dbgstr_w(thisArg)); - h = CreateFileW(thisArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - WCMD_print_error (); - WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), thisArg); - } else { - ULONG64 curPos = 0; - ULONG64 fileLen = 0; - WIN32_FILE_ATTRIBUTE_DATA fileInfo; + /* Loop through all args */ + WINE_TRACE("Parms supplied - working through each file\n"); + + for (argno = 0; return_code == NO_ERROR; argno++) + { + LARGE_INTEGER lizero = {.QuadPart = 0}, lifilelen; + WCHAR *thisArg = WCMD_parameter(args, argno, &argN, FALSE, FALSE); + HANDLE h; + + if (!argN) break;
- /* Get the file size */ - GetFileAttributesExW(thisArg, GetFileExInfoStandard, (void*)&fileInfo); - fileLen = (((ULONG64)fileInfo.nFileSizeHigh) << 32) + fileInfo.nFileSizeLow; + WINE_TRACE("more: Processing arg '%s'\n", wine_dbgstr_w(thisArg)); + h = CreateFileW(thisArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + { + WCMD_print_error(); + WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), thisArg); + break; + }
- needsPause = TRUE; - while (WCMD_ReadFile(h, buffer, ARRAY_SIZE(buffer)-1, &count)) { - if (count == 0) break; /* ReadFile reports success on EOF! */ - buffer[count] = 0; - curPos += count; + SetFilePointerEx(h, lizero, &lifilelen, FILE_END); + SetFilePointerEx(h, lizero, NULL, FILE_BEGIN);
- /* Update % count (would be used in WCMD_output_asis as prompt) */ - wsprintfW(moreStrPage, L"%s (%2.2d%%) --\n", moreStr, (int) min(99, (curPos * 100)/fileLen)); + return_code = page_file(h, lifilelen.QuadPart, argno != 0);
- WCMD_output_asis (buffer); + CloseHandle(h); } - CloseHandle (h); - } } - - WCMD_leave_paged_mode(); - } - return errorlevel = return_code; + return errorlevel = NO_ERROR; }
/**************************************************************************** diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 4351533042b..ec0a6f2a066 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -219,6 +219,7 @@ WCHAR *WCMD_strip_quotes(WCHAR *cmd); WCHAR *WCMD_LoadMessage(UINT id); WCHAR *WCMD_strsubstW(WCHAR *start, const WCHAR* next, const WCHAR* insert, int len); RETURN_CODE WCMD_wait_for_input(HANDLE hIn); +RETURN_CODE WCMD_wait_for_console_input(void); BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWORD charsRead); BOOL WCMD_read_console(const HANDLE hInput, WCHAR *inputBuffer, const DWORD inputBufferLength, LPDWORD numRead);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index d308cdc9731..e3682e4256d 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -638,6 +638,11 @@ RETURN_CODE WCMD_wait_for_input(HANDLE hIn) return return_code; }
+RETURN_CODE WCMD_wait_for_console_input(void) +{ + return WCMD_wait_for_input(console_input); +} + /*************************************************************************** * WCMD_ReadFile * @@ -674,6 +679,8 @@ RETURN_CODE WCMD_output_asis(const WCHAR *message) RETURN_CODE return_code = NO_ERROR; const WCHAR* ptr; HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dummy; + BOOL is_output_console = GetConsoleMode(handle, &dummy);
if (!message) /* Hack for flushing */ { @@ -692,9 +699,11 @@ RETURN_CODE WCMD_output_asis(const WCHAR *message) if (paged_mode && ++line_count >= max_height - 1) { line_count = 0; - WCMD_output_unbuffered(pagedMessage, -1, handle); + if (is_output_console) + WCMD_output_unbuffered(pagedMessage, -1, handle); return_code = WCMD_wait_for_input(console_input); - WCMD_output_unbuffered(L"\r\n", 2, handle); + if (is_output_console) + WCMD_output_unbuffered(L"\r", 1, handle); } } else