This is part XXXV of cmd engine rewrite.
It : - fixes a regression introduced by previous serie, - fixed a couple of erroneous settings of some env variables (likely corner cases)
But mostly, it's the start of implementing a pipe (between commands) as a pipe (IPC).
Currently, cmd runs lhs of pipe, stores output into a file, then runs rhs with that file as input.
However, this will expose a bunch of issues to be fixed before thinking implementing the IPC part.
This serie covers the output part: - don't filter the stderr output in the paging (MORE) output, - send all stdout output to the paging (MORE), - use a line-buffered output for stdout, - adding some explicit flush before expecting input.
It also fixes an issue triggered down the road.
Next series (likely two) will cover the input part.
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 161952a40a1..7ad835ed25d 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -4307,10 +4307,12 @@ static void set_console_default_color(unsigned color) query_default_color_key(HKEY_LOCAL_MACHINE, &value)) color = value; } - if (color >= 0x100 || ((color >> 4) == (color & 0xf))) - color = 7; - swprintf(param1, ARRAY_SIZE(param1), L"%x", color); - WCMD_color(); + if (color < 0x100 && ((color >> 4) != (color & 0xf))) + { + swprintf(param1, ARRAY_SIZE(param1), L"%x", color); + WCMD_color(); + } + else color = 7; }
struct cmd_parameters
From: Eric Pouech epouech@codeweavers.com
+ COMSPEC should be set to the path of running cmd.exe instance if not present, + PROMPT must be set to $P$G if not already defined.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 7ad835ed25d..1b6a3ea6f2f 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -4461,11 +4461,11 @@ static void WCMD_setup(void) /* initialize some env variables */ if (!GetEnvironmentVariableW(L"COMSPEC", string, ARRAY_SIZE(string))) { - GetSystemDirectoryW(string, ARRAY_SIZE(string) - ARRAY_SIZE(L"\cmd.exe")); - lstrcatW(string, L"\cmd.exe"); + GetModuleFileNameW(NULL, string, ARRAY_SIZE(string)); SetEnvironmentVariableW(L"COMSPEC", string); } - SetEnvironmentVariableW(L"PROMPT", L"$P$G"); + if (!GetEnvironmentVariableW(L"PROMPT", string, ARRAY_SIZE(string))) + SetEnvironmentVariableW(L"PROMPT", L"$P$G");
/* Save cwd into appropriate env var (Must be before the /c processing */ GetCurrentDirectoryW(ARRAY_SIZE(string), string);
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/batch.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 42cb4c47b99..38a1e8c2826 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -676,7 +676,7 @@ RETURN_CODE WCMD_call(WCHAR *command) return_code = errorlevel; } } - else if (context) + else if (WCMD_is_in_context(NULL)) { WCHAR gotoLabel[MAX_PATH];
@@ -699,11 +699,13 @@ RETURN_CODE WCMD_call(WCHAR *command)
/* Restore the for loop context */ WCMD_restore_for_loop_context(); - } else { - WCMD_output_asis_stderr(WCMD_LoadMessage(WCMD_CALLINSCRIPT)); - return_code = ERROR_INVALID_FUNCTION; - } - return return_code; + } + else + { + WCMD_output_asis_stderr(WCMD_LoadMessage(WCMD_CALLINSCRIPT)); + return_code = ERROR_INVALID_FUNCTION; + } + return return_code; }
void WCMD_set_label_end(WCHAR *string)
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmd.h | 10 +-- programs/cmd/wcmdmain.c | 138 +++++++++++++++++----------------------- 2 files changed, 65 insertions(+), 83 deletions(-)
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index ae4dc038e34..8d908accc2e 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -178,11 +178,11 @@ RETURN_CODE WCMD_label(void); void WCMD_leave_paged_mode(void); RETURN_CODE WCMD_more(WCHAR *); RETURN_CODE WCMD_move (void); -WCHAR* WINAPIV WCMD_format_string (const WCHAR *format, ...); -void WINAPIV WCMD_output (const WCHAR *format, ...); -void WINAPIV WCMD_output_stderr (const WCHAR *format, ...); -RETURN_CODE WCMD_output_asis (const WCHAR *message); -RETURN_CODE WCMD_output_asis_stderr (const WCHAR *message); +WCHAR* WINAPIV WCMD_format_string(const WCHAR *format, ...); +void WINAPIV WCMD_output(const WCHAR *format, ...); +void WINAPIV WCMD_output_stderr(const WCHAR *format, ...); +RETURN_CODE WCMD_output_asis(const WCHAR *message); +RETURN_CODE WCMD_output_asis_stderr(const WCHAR *message); RETURN_CODE WCMD_pause(void); RETURN_CODE WCMD_popd(void); void WCMD_print_error (void); diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 1b6a3ea6f2f..9f31a84ad5e 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -477,54 +477,35 @@ static char *get_file_buffer(void) }
/******************************************************************* - * WCMD_output_asis_len - send output to current standard output + * WCMD_output_unbuffered - send output to a given handle * - * Output a formatted unicode string. Ideally this will go to the console - * and hence required WriteConsoleW to output it, however if file i/o is - * redirected, it needs to be WriteFile'd using OEM (not ANSI) format */ -static void WCMD_output_asis_len(const WCHAR *message, DWORD len, HANDLE device) +static void WCMD_output_unbuffered(const WCHAR *message, DWORD len, HANDLE handle) { - DWORD nOut= 0; - DWORD res = 0; + BOOL usedDefaultChar = FALSE; + DWORD convertedChars; + char *buffer; + DWORD nOut;
/* If nothing to write, return (MORE does this sometimes) */ + if ((int)len == -1) len = wcslen(message); if (!len) return;
/* Try to write as unicode assuming it is to a console */ - res = WriteConsoleW(device, message, len, &nOut, NULL); - - /* If writing to console fails, assume it's file - i/o so convert to OEM codepage and output */ - if (!res) { - BOOL usedDefaultChar = FALSE; - DWORD convertedChars; - char *buffer; - - if (!unicodeOutput) { - UINT code_page; - + if (WriteConsoleW(handle, message, len, &nOut, NULL)) return; + if (!unicodeOutput) + { if (!(buffer = get_file_buffer())) return;
- /* On Wine, GetConsoleOutputCP function fails - if Shell-no-window console is used */ - code_page = GetConsoleOutputCP(); - if (!code_page) - code_page = GetOEMCP(); - /* Convert to OEM, then output */ - convertedChars = WideCharToMultiByte(code_page, 0, message, - len, buffer, MAX_WRITECONSOLE_SIZE, - "?", &usedDefaultChar); - WriteFile(device, buffer, convertedChars, - &nOut, FALSE); - } else { - WriteFile(device, message, len*sizeof(WCHAR), - &nOut, FALSE); - } + convertedChars = WideCharToMultiByte(GetOEMCP(), 0, message, + len, buffer, MAX_WRITECONSOLE_SIZE, + "?", &usedDefaultChar); + WriteFile(handle, buffer, convertedChars, &nOut, FALSE); } - return; + else + WriteFile(handle, message, len * sizeof(WCHAR), &nOut, FALSE); }
/******************************************************************* @@ -547,7 +528,7 @@ void WINAPIV WCMD_output (const WCHAR *format, ...) { WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(format)); else { - WCMD_output_asis_len(string, len, GetStdHandle(STD_OUTPUT_HANDLE)); + WCMD_output_unbuffered(string, len, GetStdHandle(STD_OUTPUT_HANDLE)); LocalFree(string); } } @@ -557,24 +538,24 @@ void WINAPIV WCMD_output (const WCHAR *format, ...) { * */
-void WINAPIV WCMD_output_stderr (const WCHAR *format, ...) { - - va_list ap; - WCHAR* string; - DWORD len; +void WINAPIV WCMD_output_stderr(const WCHAR *format, ...) +{ + va_list ap; + WCHAR* string; + DWORD len;
- va_start(ap,format); - string = NULL; - len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, - format, 0, 0, (LPWSTR)&string, 0, &ap); - va_end(ap); - if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE) - WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(format)); - else - { - WCMD_output_asis_len(string, len, GetStdHandle(STD_ERROR_HANDLE)); - LocalFree(string); - } + va_start(ap,format); + string = NULL; + len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, + format, 0, 0, (LPWSTR)&string, 0, &ap); + va_end(ap); + if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE) + WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(format)); + else + { + WCMD_output_unbuffered(string, len, GetStdHandle(STD_ERROR_HANDLE)); + LocalFree(string); + } }
/******************************************************************* @@ -726,17 +707,17 @@ static RETURN_CODE WCMD_output_asis_handle(DWORD std_handle, const WCHAR *messag { for (ptr = message; *ptr && *ptr != L'\n'; ptr++) {} if (*ptr == L'\n') ptr++; - WCMD_output_asis_len(message, ptr - message, handle); + WCMD_output_unbuffered(message, ptr - message, handle); if (++line_count >= max_height - 1) { line_count = 0; - WCMD_output_asis_len(pagedMessage, lstrlenW(pagedMessage), handle); + WCMD_output_unbuffered(pagedMessage, -1, handle); return_code = WCMD_wait_for_input(GetStdHandle(STD_INPUT_HANDLE)); - WCMD_output_asis_len(L"\r\n", 2, handle); + WCMD_output_unbuffered(L"\r\n", 2, handle); } } while (*(message = ptr) && !return_code); } else - WCMD_output_asis_len(message, lstrlenW(message), handle); + WCMD_output_unbuffered(message, -1, handle);
return return_code; } @@ -757,8 +738,10 @@ RETURN_CODE WCMD_output_asis (const WCHAR *message) { * Send output to current standard error device, without formatting * e.g. when message contains '%' */ -RETURN_CODE WCMD_output_asis_stderr (const WCHAR *message) { - return WCMD_output_asis_handle(STD_ERROR_HANDLE, message); +RETURN_CODE WCMD_output_asis_stderr(const WCHAR *message) +{ + WCMD_output_unbuffered(message, -1, GetStdHandle(STD_ERROR_HANDLE)); + return NO_ERROR; }
/**************************************************************************** @@ -766,26 +749,25 @@ RETURN_CODE WCMD_output_asis_stderr (const WCHAR *message) { * * Print the message for GetLastError */ +void WCMD_print_error(void) +{ + LPVOID lpMsgBuf; + DWORD error_code; + int status; + + error_code = GetLastError(); + status = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error_code, 0, (LPWSTR) &lpMsgBuf, 0, NULL); + if (!status) + { + WINE_FIXME("Cannot display message for error %ld, status %ld\n", + error_code, GetLastError()); + return; + }
-void WCMD_print_error (void) { - LPVOID lpMsgBuf; - DWORD error_code; - int status; - - error_code = GetLastError (); - status = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error_code, 0, (LPWSTR) &lpMsgBuf, 0, NULL); - if (!status) { - WINE_FIXME ("Cannot display message for error %ld, status %ld\n", - error_code, GetLastError()); - return; - } - - WCMD_output_asis_len(lpMsgBuf, lstrlenW(lpMsgBuf), - GetStdHandle(STD_ERROR_HANDLE)); - LocalFree (lpMsgBuf); - WCMD_output_asis_len(L"\r\n", lstrlenW(L"\r\n"), GetStdHandle(STD_ERROR_HANDLE)); - return; + WCMD_output_unbuffered(lpMsgBuf, -1, GetStdHandle(STD_ERROR_HANDLE)); + LocalFree(lpMsgBuf); + WCMD_output_unbuffered(L"\r\n", 2, GetStdHandle(STD_ERROR_HANDLE)); }
/******************************************************************************
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 52 +++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 9f31a84ad5e..0d8bb52504c 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2073,13 +2073,32 @@ static RETURN_CODE search_command(WCHAR *command, struct search_command *sc, BOO return RETURN_CODE_CANT_LAUNCH; }
-static BOOL set_std_redirections(CMD_REDIRECTION *redir) +static DWORD std_index[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; + +static void pop_std_redirections(HANDLE saved[3]) +{ + unsigned int i; + + /* Restore old handles */ + for (i = 0; i < 3; i++) + { + if (saved[i] != GetStdHandle(std_index[i])) + { + CloseHandle(GetStdHandle(std_index[i])); + SetStdHandle(std_index[i], saved[i]); + } + } +} + +static BOOL push_std_redirections(CMD_REDIRECTION *redir, HANDLE saved[3]) { - static DWORD std_index[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; static SECURITY_ATTRIBUTES sa = {.nLength = sizeof(sa), .lpSecurityDescriptor = NULL, .bInheritHandle = TRUE}; WCHAR expanded_filename[MAXSTRING]; HANDLE h; + unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(std_index); i++) + saved[i] = GetStdHandle(std_index[i]); for (; redir; redir = redir->next) { CMD_REDIRECTION *next; @@ -4101,16 +4120,12 @@ static RETURN_CODE for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *node
RETURN_CODE node_execute(CMD_NODE *node) { - HANDLE old_stdhandles[3] = {GetStdHandle (STD_INPUT_HANDLE), - GetStdHandle (STD_OUTPUT_HANDLE), - GetStdHandle (STD_ERROR_HANDLE)}; - static DWORD idx_stdhandles[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; - + HANDLE saved[3]; RETURN_CODE return_code; - int i, test; + int test;
if (!node) return NO_ERROR; - if (!set_std_redirections(node->redirects)) + if (!push_std_redirections(node->redirects, saved)) { WCMD_print_error(); return_code = ERROR_INVALID_FUNCTION; @@ -4147,7 +4162,7 @@ RETURN_CODE node_execute(CMD_NODE *node) WCHAR temp_path[MAX_PATH]; WCHAR filename[MAX_PATH]; CMD_REDIRECTION *output; - HANDLE saved_output; + HANDLE saved[3]; struct batch_context *saved_context = context;
/* pipe LHS & RHS are run outside of any batch context */ @@ -4165,14 +4180,12 @@ RETURN_CODE node_execute(CMD_NODE *node) GetTempFileNameW(temp_path, L"CMD", 0, filename); TRACE("Using temporary file of %ls\n", filename);
- saved_output = GetStdHandle(STD_OUTPUT_HANDLE); /* set output for left hand side command */ output = redirection_create_file(REDIR_WRITE_TO, 1, filename); - if (set_std_redirections(output)) + if (push_std_redirections(output, saved)) { RETURN_CODE return_code_left = node_execute(node->left); - CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE)); - SetStdHandle(STD_OUTPUT_HANDLE, saved_output); + pop_std_redirections(saved);
if (errorlevel == RETURN_CODE_CANT_LAUNCH && saved_context) ExitProcess(255); @@ -4211,15 +4224,8 @@ RETURN_CODE node_execute(CMD_NODE *node) FIXME("Unexpected operator %u\n", node->op); return_code = ERROR_INVALID_FUNCTION; } - /* Restore old handles */ - for (i = 0; i < 3; i++) - { - if (old_stdhandles[i] != GetStdHandle(idx_stdhandles[i])) - { - CloseHandle(GetStdHandle(idx_stdhandles[i])); - SetStdHandle(idx_stdhandles[i], old_stdhandles[i]); - } - } + pop_std_redirections(saved); + return return_code; }
From: Eric Pouech epouech@codeweavers.com
This allows: - to also page formatted output (no reason it isn't), - implement line buffering for STD_OUTPUT.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/builtins.c | 7 ++- programs/cmd/wcmd.h | 1 + programs/cmd/wcmdmain.c | 106 +++++++++++++++++++++++----------------- 3 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index dd9808aa9f2..41ed7fb8a71 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -227,6 +227,7 @@ static BOOL WCMD_ask_confirm (const WCHAR *message, BOOL showSureText, if (showSureText) WCMD_output_asis (confirm); WCMD_output_asis (options); + WCMD_output_flush(); if (!WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, ARRAY_SIZE(answer), &count) || !count) return FALSE; answer[0] = towupper(answer[0]); @@ -398,6 +399,7 @@ RETURN_CODE WCMD_choice(WCHAR *args) WCMD_output_asis(L"]?"); }
+ WCMD_output_flush(); while (return_code == NO_ERROR) { if (opt_timeout == 0) @@ -1940,6 +1942,7 @@ RETURN_CODE WCMD_pause(void) { RETURN_CODE return_code = NO_ERROR; WCMD_output_asis(anykey); + WCMD_output_flush(); return_code = WCMD_wait_for_input(GetStdHandle(STD_INPUT_HANDLE)); WCMD_output_asis(L"\r\n");
@@ -2399,7 +2402,8 @@ RETURN_CODE WCMD_setshow_date(void) if (GetDateFormatW(LOCALE_USER_DEFAULT, 0, NULL, NULL, curdate, ARRAY_SIZE(curdate))) { WCMD_output (WCMD_LoadMessage(WCMD_CURRENTDATE), curdate); if (wcsstr(quals, L"/T") == NULL) { - WCMD_output (WCMD_LoadMessage(WCMD_NEWDATE)); + WCMD_output(WCMD_LoadMessage(WCMD_NEWDATE)); + WCMD_output_flush(); if (WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), buffer, ARRAY_SIZE(buffer), &count) && count > 2) { WCMD_output_stderr (WCMD_LoadMessage(WCMD_NYI)); @@ -3203,6 +3207,7 @@ RETURN_CODE WCMD_setshow_time(void) WCMD_output (WCMD_LoadMessage(WCMD_CURRENTTIME), curtime); if (wcsstr(quals, L"/T") == NULL) { WCMD_output (WCMD_LoadMessage(WCMD_NEWTIME)); + WCMD_output_flush(); if (WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), buffer, ARRAY_SIZE(buffer), &count) && count > 2) { WCMD_output_stderr (WCMD_LoadMessage(WCMD_NYI)); diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 8d908accc2e..4351533042b 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -182,6 +182,7 @@ WCHAR* WINAPIV WCMD_format_string(const WCHAR *format, ...); void WINAPIV WCMD_output(const WCHAR *format, ...); void WINAPIV WCMD_output_stderr(const WCHAR *format, ...); RETURN_CODE WCMD_output_asis(const WCHAR *message); +RETURN_CODE WCMD_output_flush(void); RETURN_CODE WCMD_output_asis_stderr(const WCHAR *message); RETURN_CODE WCMD_pause(void); RETURN_CODE WCMD_popd(void); diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 0d8bb52504c..1e9142ad805 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -508,31 +508,6 @@ static void WCMD_output_unbuffered(const WCHAR *message, DWORD len, HANDLE handl WriteFile(handle, message, len * sizeof(WCHAR), &nOut, FALSE); }
-/******************************************************************* - * WCMD_output - send output to current standard output device. - * - */ - -void WINAPIV WCMD_output (const WCHAR *format, ...) { - - va_list ap; - WCHAR* string; - DWORD len; - - va_start(ap,format); - string = NULL; - len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, - format, 0, 0, (LPWSTR)&string, 0, &ap); - va_end(ap); - if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE) - WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(format)); - else - { - WCMD_output_unbuffered(string, len, GetStdHandle(STD_OUTPUT_HANDLE)); - LocalFree(string); - } -} - /******************************************************************* * WCMD_output_stderr - send output to current standard error device. * @@ -691,45 +666,54 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWO }
/******************************************************************* - * WCMD_output_asis_handle + * WCMD_output_asis * - * Send output to specified handle without formatting e.g. when message contains '%' + * Send output to OUTPUT, buffering the content. */ -static RETURN_CODE WCMD_output_asis_handle(DWORD std_handle, const WCHAR *message) +RETURN_CODE WCMD_output_asis(const WCHAR *message) { + static WCHAR out_buffer[MAXSTRING]; RETURN_CODE return_code = NO_ERROR; const WCHAR* ptr; - HANDLE handle = GetStdHandle(std_handle); + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
- if (paged_mode) + if (!message) /* Hack for flushing */ { - do + WCMD_output_unbuffered(out_buffer, -1, handle); + out_buffer[0] = L'\0'; + } + for (ptr = message; ptr && return_code == NO_ERROR; ) + { + WCHAR *next = wcschr(ptr, L'\n'); + if (next) { - for (ptr = message; *ptr && *ptr != L'\n'; ptr++) {} - if (*ptr == L'\n') ptr++; - WCMD_output_unbuffered(message, ptr - message, handle); - if (++line_count >= max_height - 1) + next++; + WCMD_output_unbuffered(out_buffer, -1, handle); + out_buffer[0] = L'\0'; + WCMD_output_unbuffered(ptr, next - ptr, handle); + if (paged_mode && ++line_count >= max_height - 1) { line_count = 0; WCMD_output_unbuffered(pagedMessage, -1, handle); return_code = WCMD_wait_for_input(GetStdHandle(STD_INPUT_HANDLE)); WCMD_output_unbuffered(L"\r\n", 2, handle); } - } while (*(message = ptr) && !return_code); - } else - WCMD_output_unbuffered(message, -1, handle); + } + else + { + size_t fblen = wcslen(out_buffer), len = wcslen(ptr); + if (len && (fblen + len + 1) < ARRAY_SIZE(out_buffer)) + memcpy(out_buffer + fblen, ptr, (len + 1) * sizeof(WCHAR)); + } + ptr = next; + }
return return_code; }
-/******************************************************************* - * WCMD_output_asis - * - * Send output to current standard output device, without formatting - * e.g. when message contains '%' - */ -RETURN_CODE WCMD_output_asis (const WCHAR *message) { - return WCMD_output_asis_handle(STD_OUTPUT_HANDLE, message); +RETURN_CODE WCMD_output_flush(void) +{ + return WCMD_output_asis(NULL); }
/******************************************************************* @@ -744,6 +728,30 @@ RETURN_CODE WCMD_output_asis_stderr(const WCHAR *message) return NO_ERROR; }
+/******************************************************************* + * WCMD_output - send formated output to current standard output device. + * + */ +void WINAPIV WCMD_output(const WCHAR *format, ...) +{ + va_list ap; + WCHAR* string; + DWORD len; + + va_start(ap,format); + string = NULL; + len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, + format, 0, 0, (LPWSTR)&string, 0, &ap); + va_end(ap); + if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE) + WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(format)); + else + { + WCMD_output_asis(string); + LocalFree(string); + } +} + /**************************************************************************** * WCMD_print_error * @@ -872,6 +880,7 @@ static void WCMD_show_prompt(void) } } WCMD_output_asis (out_string); + WCMD_output_flush(); }
void *xrealloc(void *ptr, size_t size) @@ -2084,6 +2093,8 @@ static void pop_std_redirections(HANDLE saved[3]) { if (saved[i] != GetStdHandle(std_index[i])) { + if (std_index[i] == STD_OUTPUT_HANDLE) + WCMD_output_flush(); CloseHandle(GetStdHandle(std_index[i])); SetStdHandle(std_index[i], saved[i]); } @@ -2159,7 +2170,10 @@ static BOOL push_std_redirections(CMD_REDIRECTION *redir, HANDLE saved[3]) if (redir->fd > 2) CloseHandle(h); else + { + if (std_index[redir->fd] == STD_OUTPUT_HANDLE) WCMD_output_flush(); SetStdHandle(std_index[redir->fd], h); + } } return TRUE; }