Skip to content

Commit

Permalink
tool_doswin: Restore original console settings on CTRL signal
Browse files Browse the repository at this point in the history
- Move Windows terminal init code from tool_main to tool_doswin.

- Restore the original console settings on CTRL+C and CTRL+BREAK.

Background: On Windows the curl tool changes the console settings to
enable virtual terminal processing (eg color output) if supported
(ie Win 10). The original settings are restored on exit but prior to
this change were not restored in the case of the CTRL signals.

VT default behavior varies; refer to the discussion in #6226.

Assisted-by: Rich Turner

Closes #xxxx
  • Loading branch information
jay committed Jan 11, 2021
1 parent 4f61fd8 commit 626e49b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 53 deletions.
62 changes: 62 additions & 0 deletions src/tool_doswin.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#endif

#ifdef WIN32
# include <stdlib.h>
# include <tlhelp32.h>
# include "tool_cfgable.h"
# include "tool_libinfo.h"
Expand Down Expand Up @@ -702,6 +703,64 @@ struct curl_slist *GetLoadedModulePaths(void)
return slist;
}

/* The terminal settings to restore on exit */
static struct TerminalSettings {
HANDLE hStdOut;
DWORD dwOutputMode;
LONG valid;
} TerminalSettings;

#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif

static void restore_terminal(void)
{
if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
}

/* This is the console signal handler.
* The system calls it in a separate thread.
*/
static BOOL WINAPI signal_handler(DWORD type)
{
if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
restore_terminal();
return FALSE;
}

static void init_terminal(void)
{
TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
/*
* Enable VT (Virtual Terminal) output.
* Note: VT mode flag can be set on any version of Windows, but VT
* processing only performed on Win10 >= Creators Update)
*/
if((TerminalSettings.hStdOut != INVALID_HANDLE_VALUE) &&
GetConsoleMode(TerminalSettings.hStdOut,
&TerminalSettings.dwOutputMode) &&
!(TerminalSettings.dwOutputMode &
ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
/* The signal handler is set before attempting to change the console mode
because otherwise a signal would not be caught after the change but
before the handler was installed. */
(void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE);
if(SetConsoleCtrlHandler(signal_handler, TRUE)) {
if(SetConsoleMode(TerminalSettings.hStdOut,
(TerminalSettings.dwOutputMode |
ENABLE_VIRTUAL_TERMINAL_PROCESSING))) {
atexit(restore_terminal);
}
else {
SetConsoleCtrlHandler(signal_handler, FALSE);
(void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
}
}
}
}

LARGE_INTEGER tool_freq;
bool tool_isVistaOrGreater;

Expand All @@ -714,6 +773,9 @@ CURLcode win32_init(void)
tool_isVistaOrGreater = false;

QueryPerformanceFrequency(&tool_freq);

init_terminal();

return CURLE_OK;
}

Expand Down
57 changes: 4 additions & 53 deletions src/tool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@

#include <sys/stat.h>

#ifdef WIN32
#include <tchar.h>
#endif

#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
Expand Down Expand Up @@ -225,51 +229,6 @@ static void main_free(struct GlobalConfig *config)
config->last = NULL;
}

#ifdef WIN32
/* TerminalSettings for Windows */
static struct TerminalSettings {
HANDLE hStdOut;
DWORD dwOutputMode;
} TerminalSettings;

static void configure_terminal(void)
{
/*
* If we're running Windows, enable VT output.
* Note: VT mode flag can be set on any version of Windows, but VT
* processing only performed on Win10 >= Creators Update)
*/

/* Define the VT flags in case we're building with an older SDK */
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif

memset(&TerminalSettings, 0, sizeof(TerminalSettings));

/* Enable VT output */
TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if((TerminalSettings.hStdOut != INVALID_HANDLE_VALUE)
&& (GetConsoleMode(TerminalSettings.hStdOut,
&TerminalSettings.dwOutputMode))) {
SetConsoleMode(TerminalSettings.hStdOut,
TerminalSettings.dwOutputMode
| ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}
}
#else
#define configure_terminal()
#endif

static void restore_terminal(void)
{
#ifdef WIN32
/* Restore Console output mode and codepage to whatever they were
* when Curl started */
SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
#endif
}

/*
** curl tool main function.
*/
Expand All @@ -284,7 +243,6 @@ int main(int argc, char *argv[])
memset(&global, 0, sizeof(global));

#ifdef WIN32
#ifdef _tcscmp
/* Undocumented diagnostic option to list the full paths of all loaded
modules. This is purposely pre-init. */
if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) {
Expand All @@ -294,7 +252,6 @@ int main(int argc, char *argv[])
curl_slist_free_all(head);
return head ? 0 : 1;
}
#endif /* _tcscmp */
/* win32_init must be called before other init routines. */
result = win32_init();
if(result) {
Expand All @@ -303,9 +260,6 @@ int main(int argc, char *argv[])
}
#endif

/* Perform any platform-specific terminal configuration */
configure_terminal();

main_checkfds();

#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
Expand All @@ -326,9 +280,6 @@ int main(int argc, char *argv[])
main_free(&global);
}

/* Return the terminal to its original state */
restore_terminal();

#ifdef __NOVELL_LIBC__
if(getenv("_IN_NETWARE_BASH_") == NULL)
tool_pressanykey();
Expand Down

0 comments on commit 626e49b

Please sign in to comment.