aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/winpty')
-rw-r--r--src/libs/3rdparty/winpty/.gitattributes19
-rw-r--r--src/libs/3rdparty/winpty/.gitignore16
-rw-r--r--src/libs/3rdparty/winpty/CMakeLists.txt1
-rw-r--r--src/libs/3rdparty/winpty/LICENSE21
-rw-r--r--src/libs/3rdparty/winpty/README.md151
-rw-r--r--src/libs/3rdparty/winpty/RELEASES.md280
-rw-r--r--src/libs/3rdparty/winpty/VERSION.txt1
-rw-r--r--src/libs/3rdparty/winpty/appveyor.yml16
-rw-r--r--src/libs/3rdparty/winpty/configure167
-rw-r--r--src/libs/3rdparty/winpty/misc/.gitignore2
-rw-r--r--src/libs/3rdparty/winpty/misc/BufferResizeTests.cc90
-rw-r--r--src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc53
-rw-r--r--src/libs/3rdparty/winpty/misc/ClearConsole.cc72
-rw-r--r--src/libs/3rdparty/winpty/misc/ConinMode.cc117
-rw-r--r--src/libs/3rdparty/winpty/misc/ConinMode.ps1116
-rw-r--r--src/libs/3rdparty/winpty/misc/ConoutMode.cc113
-rw-r--r--src/libs/3rdparty/winpty/misc/DebugClient.py42
-rw-r--r--src/libs/3rdparty/winpty/misc/DebugServer.py63
-rw-r--r--src/libs/3rdparty/winpty/misc/DumpLines.py5
-rw-r--r--src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt46
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt528
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt633
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt630
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt630
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt630
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt630
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt16
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt4
-rw-r--r--src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt144
-rw-r--r--src/libs/3rdparty/winpty/misc/FontSurvey.cc100
-rw-r--r--src/libs/3rdparty/winpty/misc/FormatChar.h21
-rw-r--r--src/libs/3rdparty/winpty/misc/FreezePerfTest.cc62
-rw-r--r--src/libs/3rdparty/winpty/misc/GetCh.cc20
-rw-r--r--src/libs/3rdparty/winpty/misc/GetConsolePos.cc41
-rw-r--r--src/libs/3rdparty/winpty/misc/GetFont.cc261
-rw-r--r--src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps151
-rw-r--r--src/libs/3rdparty/winpty/misc/IsNewConsole.cc87
-rw-r--r--src/libs/3rdparty/winpty/misc/MouseInputNotes.txt90
-rw-r--r--src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc34
-rw-r--r--src/libs/3rdparty/winpty/misc/Notes.txt219
-rw-r--r--src/libs/3rdparty/winpty/misc/OSVersion.cc27
-rw-r--r--src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc101
-rw-r--r--src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc671
-rw-r--r--src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc151
-rw-r--r--src/libs/3rdparty/winpty/misc/SelectAllTest.cc45
-rw-r--r--src/libs/3rdparty/winpty/misc/SetBufInfo.cc90
-rw-r--r--src/libs/3rdparty/winpty/misc/SetBufferSize.cc32
-rw-r--r--src/libs/3rdparty/winpty/misc/SetCursorPos.cc10
-rw-r--r--src/libs/3rdparty/winpty/misc/SetFont.cc145
-rw-r--r--src/libs/3rdparty/winpty/misc/SetWindowRect.cc36
-rw-r--r--src/libs/3rdparty/winpty/misc/ShowArgv.cc12
-rw-r--r--src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc40
-rw-r--r--src/libs/3rdparty/winpty/misc/Spew.py5
-rw-r--r--src/libs/3rdparty/winpty/misc/TestUtil.cc172
-rw-r--r--src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc102
-rw-r--r--src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc246
-rw-r--r--src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc130
-rw-r--r--src/libs/3rdparty/winpty/misc/UnixEcho.cc89
-rw-r--r--src/libs/3rdparty/winpty/misc/Utf16Echo.cc46
-rw-r--r--src/libs/3rdparty/winpty/misc/VeryLargeRead.cc122
-rw-r--r--src/libs/3rdparty/winpty/misc/VkEscapeTest.cc56
-rw-r--r--src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc52
-rw-r--r--src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc57
-rw-r--r--src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc30
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Echo1.cc26
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Echo2.cc19
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Test1.cc46
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Test2.cc70
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Test3.cc78
-rw-r--r--src/libs/3rdparty/winpty/misc/Win32Write1.cc44
-rw-r--r--src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc27
-rw-r--r--src/libs/3rdparty/winpty/misc/WriteConsole.cc106
-rw-r--r--src/libs/3rdparty/winpty/misc/build32.sh9
-rw-r--r--src/libs/3rdparty/winpty/misc/build64.sh9
-rw-r--r--src/libs/3rdparty/winpty/misc/color-test.sh212
-rw-r--r--src/libs/3rdparty/winpty/misc/font-notes.txt300
-rw-r--r--src/libs/3rdparty/winpty/misc/winbug-15048.cc201
-rw-r--r--src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat36
-rw-r--r--src/libs/3rdparty/winpty/ship/common_ship.py89
-rw-r--r--src/libs/3rdparty/winpty/ship/make_msvc_package.py163
-rw-r--r--src/libs/3rdparty/winpty/ship/ship.py104
-rw-r--r--src/libs/3rdparty/winpty/src/CMakeLists.txt111
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Agent.cc612
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Agent.h103
-rw-r--r--src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc84
-rw-r--r--src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h28
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc698
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleFont.h28
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc852
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleInput.h109
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc121
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h36
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc152
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleLine.h41
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Coord.h87
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc239
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DebugShowInput.h32
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc422
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h28
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DsrSender.h30
-rw-r--r--src/libs/3rdparty/winpty/src/agent/EventLoop.cc99
-rw-r--r--src/libs/3rdparty/winpty/src/agent/EventLoop.h47
-rw-r--r--src/libs/3rdparty/winpty/src/agent/InputMap.cc246
-rw-r--r--src/libs/3rdparty/winpty/src/agent/InputMap.h114
-rw-r--r--src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc71
-rw-r--r--src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h68
-rw-r--r--src/libs/3rdparty/winpty/src/agent/NamedPipe.cc378
-rw-r--r--src/libs/3rdparty/winpty/src/agent/NamedPipe.h125
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Scraper.cc699
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Scraper.h103
-rw-r--r--src/libs/3rdparty/winpty/src/agent/SimplePool.h75
-rw-r--r--src/libs/3rdparty/winpty/src/agent/SmallRect.h143
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Terminal.cc535
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Terminal.h69
-rw-r--r--src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h157
-rw-r--r--src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc189
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Win32Console.cc107
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Win32Console.h67
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc193
-rw-r--r--src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h99
-rw-r--r--src/libs/3rdparty/winpty/src/agent/main.cc120
-rw-r--r--src/libs/3rdparty/winpty/src/agent/subdir.mk61
-rw-r--r--src/libs/3rdparty/winpty/src/configurations.gypi60
-rw-r--r--src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc117
-rw-r--r--src/libs/3rdparty/winpty/src/debugserver/subdir.mk41
-rw-r--r--src/libs/3rdparty/winpty/src/include/winpty.h242
-rw-r--r--src/libs/3rdparty/winpty/src/include/winpty_constants.h131
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc75
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h28
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h54
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h72
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/subdir.mk46
-rw-r--r--src/libs/3rdparty/winpty/src/libwinpty/winpty.cc970
-rw-r--r--src/libs/3rdparty/winpty/src/shared/AgentMsg.h38
-rw-r--r--src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc122
-rw-r--r--src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h73
-rw-r--r--src/libs/3rdparty/winpty/src/shared/Buffer.cc103
-rw-r--r--src/libs/3rdparty/winpty/src/shared/Buffer.h102
-rw-r--r--src/libs/3rdparty/winpty/src/shared/DebugClient.cc187
-rw-r--r--src/libs/3rdparty/winpty/src/shared/DebugClient.h38
-rw-r--r--src/libs/3rdparty/winpty/src/shared/GenRandom.cc138
-rw-r--r--src/libs/3rdparty/winpty/src/shared/GenRandom.h55
-rw-r--r--src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat13
-rw-r--r--src/libs/3rdparty/winpty/src/shared/Mutex.h54
-rw-r--r--src/libs/3rdparty/winpty/src/shared/OsModule.h63
-rw-r--r--src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc36
-rw-r--r--src/libs/3rdparty/winpty/src/shared/OwnedHandle.h45
-rw-r--r--src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h43
-rw-r--r--src/libs/3rdparty/winpty/src/shared/StringBuilder.h227
-rw-r--r--src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc114
-rw-r--r--src/libs/3rdparty/winpty/src/shared/StringUtil.cc55
-rw-r--r--src/libs/3rdparty/winpty/src/shared/StringUtil.h80
-rw-r--r--src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h63
-rw-r--r--src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h45
-rw-r--r--src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat20
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc460
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h104
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc252
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WindowsVersion.h29
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc55
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyAssert.h64
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyException.cc57
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyException.h43
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc42
-rw-r--r--src/libs/3rdparty/winpty/src/shared/WinptyVersion.h27
-rw-r--r--src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h99
-rw-r--r--src/libs/3rdparty/winpty/src/subdir.mk5
-rw-r--r--src/libs/3rdparty/winpty/src/tests/subdir.mk28
-rw-r--r--src/libs/3rdparty/winpty/src/tests/trivial_test.cc158
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc114
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h56
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc80
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h53
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/Util.cc86
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/Util.h31
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc70
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h42
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/main.cc729
-rw-r--r--src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk41
-rw-r--r--src/libs/3rdparty/winpty/src/winpty.gyp206
-rw-r--r--src/libs/3rdparty/winpty/vcbuild.bat83
-rw-r--r--src/libs/3rdparty/winpty/winpty.qbs205
182 files changed, 24575 insertions, 0 deletions
diff --git a/src/libs/3rdparty/winpty/.gitattributes b/src/libs/3rdparty/winpty/.gitattributes
new file mode 100644
index 0000000000..36d4c60f1a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/.gitattributes
@@ -0,0 +1,19 @@
+* text=auto
+*.bat text eol=crlf
+*.c text
+*.cc text
+*.gyp text
+*.gypi text
+*.h text
+*.ps1 text eol=crlf
+*.rst text
+*.sh text
+*.txt text
+.gitignore text
+.gitattributes text
+Makefile text
+configure text
+
+*.sh eol=lf
+configure eol=lf
+VERSION.txt eol=lf
diff --git a/src/libs/3rdparty/winpty/.gitignore b/src/libs/3rdparty/winpty/.gitignore
new file mode 100644
index 0000000000..68c6b47fb3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/.gitignore
@@ -0,0 +1,16 @@
+*.sln
+*.suo
+*.vcxproj
+*.vcxproj.filters
+*.pyc
+winpty.sdf
+winpty.opensdf
+/config.mk
+/build
+/build-gyp
+/build-libpty
+/ship/packages
+/ship/tmp
+/src/Default
+/src/Release
+/src/gen
diff --git a/src/libs/3rdparty/winpty/CMakeLists.txt b/src/libs/3rdparty/winpty/CMakeLists.txt
new file mode 100644
index 0000000000..febd4f0ab6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(src)
diff --git a/src/libs/3rdparty/winpty/LICENSE b/src/libs/3rdparty/winpty/LICENSE
new file mode 100644
index 0000000000..246fbe0113
--- /dev/null
+++ b/src/libs/3rdparty/winpty/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2016 Ryan Prichard
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/src/libs/3rdparty/winpty/README.md b/src/libs/3rdparty/winpty/README.md
new file mode 100644
index 0000000000..bc8e7d6e5f
--- /dev/null
+++ b/src/libs/3rdparty/winpty/README.md
@@ -0,0 +1,151 @@
+# winpty
+
+[![Build Status](https://ci.appveyor.com/api/projects/status/69tb9gylsph1ee1x/branch/master?svg=true)](https://ci.appveyor.com/project/rprichard/winpty/branch/master)
+
+winpty is a Windows software package providing an interface similar to a Unix
+pty-master for communicating with Windows console programs. The package
+consists of a library (libwinpty) and a tool for Cygwin and MSYS for running
+Windows console programs in a Cygwin/MSYS pty.
+
+The software works by starting the `winpty-agent.exe` process with a new,
+hidden console window, which bridges between the console API and terminal
+input/output escape codes. It polls the hidden console's screen buffer for
+changes and generates a corresponding stream of output.
+
+The Unix adapter allows running Windows console programs (e.g. CMD, PowerShell,
+IronPython, etc.) under `mintty` or Cygwin's `sshd` with
+properly-functioning input (e.g. arrow and function keys) and output (e.g. line
+buffering). The library could be also useful for writing a non-Cygwin SSH
+server.
+
+## Supported Windows versions
+
+winpty runs on Windows XP through Windows 10, including server versions. It
+can be compiled into either 32-bit or 64-bit binaries.
+
+## Cygwin/MSYS adapter (`winpty.exe`)
+
+### Prerequisites
+
+You need the following to build winpty:
+
+* A Cygwin or MSYS installation
+* GNU make
+* A MinGW g++ toolchain capable of compiling C++11 code to build `winpty.dll`
+ and `winpty-agent.exe`
+* A g++ toolchain targeting Cygwin or MSYS to build `winpty.exe`
+
+Winpty requires two g++ toolchains as it is split into two parts. The
+`winpty.dll` and `winpty-agent.exe` binaries interface with the native
+Windows command prompt window so they are compiled with the native MinGW
+toolchain. The `winpty.exe` binary interfaces with the MSYS/Cygwin terminal so
+it is compiled with the MSYS/Cygwin toolchain.
+
+MinGW appears to be split into two distributions -- MinGW (creates 32-bit
+binaries) and MinGW-w64 (creates both 32-bit and 64-bit binaries). Either
+one is generally acceptable.
+
+#### Cygwin packages
+
+The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also
+packages MinGW-w64 compilers. As of this writing, the necessary packages are:
+
+* Either `mingw64-i686-gcc-g++` or `mingw64-x86_64-gcc-g++`. Select the
+ appropriate compiler for your CPU architecture.
+* `gcc-g++`
+* `make`
+
+As of this writing (2016-01-23), only the MinGW-w64 compiler is acceptable.
+The MinGW compiler (e.g. from the `mingw-gcc-g++` package) is no longer
+maintained and is too buggy.
+
+#### MSYS packages
+
+For the original MSYS, use the `mingw-get` tool (MinGW Installation Manager),
+and select at least these components:
+
+* `mingw-developer-toolkit`
+* `mingw32-base`
+* `mingw32-gcc-g++`
+* `msys-base`
+* `msys-system-builder`
+
+When running `./configure`, make sure that `mingw32-g++` is in your
+`PATH`. It will be in the `C:\MinGW\bin` directory.
+
+#### MSYS2 packages
+
+For MSYS2, use `pacman` and install at least these packages:
+
+* `msys/gcc`
+* `mingw32/mingw-w64-i686-gcc` or `mingw64/mingw-w64-x86_64-gcc`. Select
+ the appropriate compiler for your CPU architecture.
+* `make`
+
+MSYS2 provides three start menu shortcuts for starting MSYS2:
+
+* MinGW-w64 Win32 Shell
+* MinGW-w64 Win64 Shell
+* MSYS2 Shell
+
+To build winpty, use the MinGW-w64 {Win32,Win64} shortcut of the architecture
+matching MSYS2. These shortcuts will put the g++ compiler from the
+`{mingw32,mingw64}/mingw-w64-{i686,x86_64}-gcc` packages into the `PATH`.
+
+Alternatively, instead of installing `mingw32/mingw-w64-i686-gcc` or
+`mingw64/mingw-w64-x86_64-gcc`, install the `mingw-w64-cross-gcc` and
+`mingw-w64-cross-crt-git` packages. These packages install cross-compilers
+into `/opt/bin`, and then any of the three shortcuts will work.
+
+### Building the Unix adapter
+
+In the project directory, run `./configure`, then `make`, then `make install`.
+By default, winpty is installed into `/usr/local`. Pass `PREFIX=<path>` to
+`make install` to override this default.
+
+### Using the Unix adapter
+
+To run a Windows console program in `mintty` or Cygwin `sshd`, prepend
+`winpty` to the command-line:
+
+ $ winpty powershell
+ Windows PowerShell
+ Copyright (C) 2009 Microsoft Corporation. All rights reserved.
+
+ PS C:\rprichard\proj\winpty> 10 + 20
+ 30
+ PS C:\rprichard\proj\winpty> exit
+
+## Embedding winpty / MSVC compilation
+
+See `src/include/winpty.h` for the prototypes of functions exported by
+`winpty.dll`.
+
+Only the `winpty.exe` binary uses Cygwin; all the other binaries work without
+it and can be compiled with either MinGW or MSVC. To compile using MSVC,
+download gyp and run `gyp -I configurations.gypi` in the `src` subdirectory.
+This will generate a `winpty.sln` and associated project files. See the
+`src/winpty.gyp` and `src/configurations.gypi` files for notes on dealing with
+MSVC versions and different architectures.
+
+Compiling winpty with MSVC currently requires MSVC 2013 or newer.
+
+## Debugging winpty
+
+winpty comes with a tool for collecting timestamped debugging output. To use
+it:
+
+1. Run `winpty-debugserver.exe` on the same computer as winpty.
+2. Set the `WINPTY_DEBUG` environment variable to `trace` for the
+ `winpty.exe` process and/or the process using `libwinpty.dll`.
+
+winpty also recognizes a `WINPTY_SHOW_CONSOLE` environment variable. Set it
+to 1 to prevent winpty from hiding the console window.
+
+## Copyright
+
+This project is distributed under the MIT license (see the `LICENSE` file in
+the project root).
+
+By submitting a pull request for this project, you agree to license your
+contribution under the MIT license to this project.
diff --git a/src/libs/3rdparty/winpty/RELEASES.md b/src/libs/3rdparty/winpty/RELEASES.md
new file mode 100644
index 0000000000..768cdf90e3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/RELEASES.md
@@ -0,0 +1,280 @@
+# Next Version
+
+Input handling changes:
+
+ * Improve Ctrl-C handling with programs that use unprocessed input. (e.g.
+ Ctrl-C now cancels input with PowerShell on Windows 10.)
+ [#116](https://github.com/rprichard/winpty/issues/116)
+ * Fix a theoretical issue with input event ordering.
+ [#117](https://github.com/rprichard/winpty/issues/117)
+ * Ctrl/Shift+{Arrow,Home,End} keys now work with IntelliJ.
+ [#118](https://github.com/rprichard/winpty/issues/118)
+
+# Version 0.4.3 (2017-05-17)
+
+Input handling changes:
+
+ * winpty sets `ENHANCED_KEY` for arrow and navigation keys. This fixes an
+ issue with the Ruby REPL.
+ [#99](https://github.com/rprichard/winpty/issues/99)
+ * AltGr keys are handled better now.
+ [#109](https://github.com/rprichard/winpty/issues/109)
+ * In `ENABLE_VIRTUAL_TERMINAL_INPUT` mode, when typing Home/End with a
+ modifier (e.g. Ctrl), winpty now generates an H/F escape sequence like
+ `^[[1;5F` rather than a 1/4 escape like `^[[4;5~`.
+ [#114](https://github.com/rprichard/winpty/issues/114)
+
+Resizing and scraping fixes:
+
+ * winpty now synthesizes a `WINDOW_BUFFER_SIZE_EVENT` event after resizing
+ the console to better propagate window size changes to console programs.
+ In particular, this affects WSL and Cygwin.
+ [#110](https://github.com/rprichard/winpty/issues/110)
+ * Better handling of resizing for certain full-screen programs, like
+ WSL less.
+ [#112](https://github.com/rprichard/winpty/issues/112)
+ * Hide the cursor if it's currently outside the console window. This change
+ fixes an issue with Far Manager.
+ [#113](https://github.com/rprichard/winpty/issues/113)
+ * winpty now avoids using console fonts smaller than 5px high to improve
+ half-vs-full-width character handling. See
+ https://github.com/Microsoft/vscode/issues/19665.
+ [b4db322010](https://github.com/rprichard/winpty/commit/b4db322010d2d897e6c496fefc4f0ecc9b84c2f3)
+
+Cygwin/MSYS adapter fix:
+
+ * The way the `winpty` Cygwin/MSYS2 adapter searches for the program to
+ launch changed. It now resolves symlinks and searches the PATH explicitly.
+ [#81](https://github.com/rprichard/winpty/issues/81)
+ [#98](https://github.com/rprichard/winpty/issues/98)
+
+This release does not include binaries for the old MSYS1 project anymore.
+MSYS2 will continue to be supported. See
+https://github.com/rprichard/winpty/issues/97.
+
+# Version 0.4.2 (2017-01-18)
+
+This release improves WSL support (i.e. Bash-on-Windows):
+
+ * winpty generates more correct input escape sequences for WSL programs that
+ enable an alternate input mode using DECCKM. This bug affected arrow keys
+ and Home/End in WSL programs such as `vim`, `mc`, and `less`.
+ [#90](https://github.com/rprichard/winpty/issues/90)
+ * winpty now recognizes the `COMMON_LVB_REVERSE_VIDEO` and
+ `COMMON_LVB_UNDERSCORE` text attributes. The Windows console uses these
+ attributes to implement the SGR.4(Underline) and SGR.7(Negative) modes in
+ its VT handling. This change affects WSL pager status bars, man pages, etc.
+
+The build system no longer has a "version suffix" mechanism, so passing
+`VERSION_SUFFIX=<suffix>` to make or `-D VERSION_SUFFIX=<suffix>` to gyp now
+has no effect. AFAIK, the mechanism was never used publicly.
+[67a34b6c03](https://github.com/rprichard/winpty/commit/67a34b6c03557a5c2e0a2bdd502c2210921d8f3e)
+
+# Version 0.4.1 (2017-01-03)
+
+Bug fixes:
+
+ * This version fixes a bug where the `winpty-agent.exe` process could read
+ past the end of a buffer.
+ [#94](https://github.com/rprichard/winpty/issues/94)
+
+# Version 0.4.0 (2016-06-28)
+
+The winpty library has a new API that should be easier for embedding.
+[880c00c69e](https://github.com/rprichard/winpty/commit/880c00c69eeca73643ddb576f02c5badbec81f56)
+
+User-visible changes:
+
+ * winpty now automatically puts the terminal into mouse mode when it detects
+ that the console has left QuickEdit mode. The `--mouse` option still forces
+ the terminal into mouse mode. In principle, an option could be added to
+ suppress terminal mode, but hopefully it won't be necessary. There is a
+ script in the `misc` subdirectory, `misc/ConinMode.ps1`, that can change
+ the QuickEdit mode from the command-line.
+ * winpty now passes keyboard escapes to `bash.exe` in the Windows Subsystem
+ for Linux.
+ [#82](https://github.com/rprichard/winpty/issues/82)
+
+Bug fixes:
+
+ * By default, `winpty.dll` avoids calling `SetProcessWindowStation` within
+ the calling process.
+ [#58](https://github.com/rprichard/winpty/issues/58)
+ * Fixed an uninitialized memory bug that could have crashed winpty.
+ [#80](https://github.com/rprichard/winpty/issues/80)
+ * winpty now works better with very large and very small terminal windows.
+ It resizes the console font according to the number of columns.
+ [#61](https://github.com/rprichard/winpty/issues/61)
+ * winpty no longer uses Mark to freeze the console on Windows 10. The Mark
+ command could interfere with the cursor position, corrupting the data in
+ the screen buffer.
+ [#79](https://github.com/rprichard/winpty/issues/79)
+
+# Version 0.3.0 (2016-05-20)
+
+User-visible changes:
+
+ * The UNIX adapter is renamed from `console.exe` to `winpty.exe` to be
+ consistent with MSYS2. The name `winpty.exe` is less likely to conflict
+ with another program and is easier to search for online (e.g. for someone
+ unfamiliar with winpty).
+ * The UNIX adapter now clears the `TERM` variable.
+ [#43](https://github.com/rprichard/winpty/issues/43)
+ * An escape character appearing in a console screen buffer cell is converted
+ to a '?'.
+ [#47](https://github.com/rprichard/winpty/issues/47)
+
+Bug fixes:
+
+ * A major bug affecting XP users was fixed.
+ [#67](https://github.com/rprichard/winpty/issues/67)
+ * Fixed an incompatibility with ConEmu where winpty hung if ConEmu's
+ "Process 'start'" feature was enabled.
+ [#70](https://github.com/rprichard/winpty/issues/70)
+ * Fixed a bug where `cmd.exe` sometimes printed the message,
+ `Not enough storage is available to process this command.`.
+ [#74](https://github.com/rprichard/winpty/issues/74)
+
+Many changes internally:
+
+ * The codebase is switched from C++03 to C++11 and uses exceptions internally.
+ No exceptions are thrown across the C APIs defined in `winpty.h`.
+ * This version drops support for the original MinGW compiler packaged with
+ Cygwin (`i686-pc-mingw32-g++`). The MinGW-w64 compiler is still supported,
+ as is the MinGW distributed at mingw.org. Compiling with MSVC now requires
+ MSVC 2013 or newer. Windows XP is still supported.
+ [ec3eae8df5](https://github.com/rprichard/winpty/commit/ec3eae8df5bbbb36d7628d168b0815638d122f37)
+ * Pipe security is improved. winpty works harder to produce unique pipe names
+ and includes a random component in the name. winpty secures pipes with a
+ DACL that prevents arbitrary users from connecting to its pipes. winpty now
+ passes `PIPE_REJECT_REMOTE_CLIENTS` on Vista and up, and it verifies that
+ the pipe client PID is correct, again on Vista and up. When connecting to a
+ named pipe, winpty uses the `SECURITY_IDENTIFICATION` flag to restrict
+ impersonation. Previous versions *should* still be secure.
+ * `winpty-debugserver.exe` now has an `--everyone` flag that allows capturing
+ debug output from other users.
+ * The code now compiles cleanly with MSVC's "Security Development Lifecycle"
+ (`/SDL`) checks enabled.
+
+# Version 0.2.2 (2016-02-25)
+
+Minor bug fixes and enhancements:
+
+ * Fix a bug that generated spurious mouse input records when an incomplete
+ mouse escape sequence was seen.
+ * Fix a buffer overflow bug in `winpty-debugserver.exe` affecting messages of
+ exactly 4096 bytes.
+ * For MSVC builds, add a `src/configurations.gypi` file that can be included
+ on the gyp command-line to enable 32-bit and 64-bit builds.
+ * `winpty-agent --show-input` mode: Flush stdout after each line.
+ * Makefile builds: generate a `build/winpty.lib` import library to accompany
+ `build/winpty.dll`.
+
+# Version 0.2.1 (2015-12-19)
+
+ * The main project source was moved into a `src` directory for better code
+ organization and to fix
+ [#51](https://github.com/rprichard/winpty/issues/51).
+ * winpty recognizes many more escape sequences, including:
+ * putty/rxvt's F1-F4 keys
+ [#40](https://github.com/rprichard/winpty/issues/40)
+ * the Linux virtual console's F1-F5 keys
+ * the "application numpad" keys (e.g. enabled with DECPAM)
+ * Fixed handling of Shift-Alt-O and Alt-[.
+ * Added support for mouse input. The UNIX adapter has a `--mouse` argument
+ that puts the terminal into mouse mode, but the agent recognizes mouse
+ input even without the argument. The agent recognizes double-clicks using
+ Windows' double-click interval setting (i.e. GetDoubleClickTime).
+ [#57](https://github.com/rprichard/winpty/issues/57)
+
+Changes to debugging interfaces:
+
+ * The `WINPTY_DEBUG` variable is now a comma-separated list. The old
+ behavior (i.e. tracing) is enabled with `WINPTY_DEBUG=trace`.
+ * The UNIX adapter program now has a `--showkey` argument that dumps input
+ bytes.
+ * The `winpty-agent.exe` program has a `--show-input` argument that dumps
+ `INPUT_RECORD` records. (It omits mouse events unless `--with-mouse` is
+ also specified.) The agent also responds to `WINPTY_DEBUG=trace,input`,
+ which logs input bytes and synthesized console events, and it responds to
+ `WINPTY_DEBUG=trace,dump_input_map`, which dumps the internal table of
+ escape sequences.
+
+# Version 0.2.0 (2015-11-13)
+
+No changes to the API, but many small changes to the implementation. The big
+changes include:
+
+ * Support for 64-bit Cygwin and MSYS2
+ * Support for Windows 10
+ * Better Unicode support (especially East Asian languages)
+
+Details:
+
+ * The `configure` script recognizes 64-bit Cygwin and MSYS2 environments and
+ selects the appropriate compiler.
+ * winpty works much better with the upgraded console in Windows 10. The
+ `conhost.exe` hang can still occur, but only with certain programs, and
+ is much less likely to occur. With the new console, use Mark instead of
+ SelectAll, for better performance.
+ [#31](https://github.com/rprichard/winpty/issues/31)
+ [#30](https://github.com/rprichard/winpty/issues/30)
+ [#53](https://github.com/rprichard/winpty/issues/53)
+ * The UNIX adapter now calls `setlocale(LC_ALL, "")` to set the locale.
+ * Improved Unicode support. When a console is started with an East Asian code
+ page, winpty now chooses an East Asian font rather than Consolas / Lucida
+ Console. Selecting the right font helps synchronize character widths
+ between the console and terminal. (It's not perfect, though.)
+ [#41](https://github.com/rprichard/winpty/issues/41)
+ * winpty now more-or-less works with programs that change the screen buffer
+ or resize the original screen buffer. If the screen buffer height changes,
+ winpty switches to a "direct mode", where it makes no effort to track
+ scrolling. In direct mode, it merely syncs snapshots of the console to the
+ terminal. Caveats:
+ * Changing the screen buffer (i.e. `SetConsoleActiveScreenBuffer`)
+ breaks winpty on Windows 7. This problem can eventually be mitigated,
+ but never completely fixed, due to Windows 7 bugginess.
+ * Resizing the original screen buffer can hang `conhost.exe` on Windows 10.
+ Enabling the legacy console is a workaround.
+ * If a program changes the screen buffer and then exits, relying on the OS
+ to restore the original screen buffer, that restoration probably will not
+ happen with winpty. winpty's behavior can probably be improved here.
+ * Improved color handling:
+ * DkGray-on-Black text was previously hiddenly completely. Now it is
+ output as DkGray, with a fallback to LtGray on terminals that don't
+ recognize the intense colors.
+ [#39](https://github.com/rprichard/winpty/issues/39).
+ * The console is always initialized to LtGray-on-Black, regardless of the
+ user setting, which matches the console color heuristic, which translates
+ LtGray-on-Black to "reset SGR parameters."
+ * Shift-Tab is recognized correctly now.
+ [#19](https://github.com/rprichard/winpty/issues/19)
+ * Add a `--version` argument to `winpty-agent.exe` and the UNIX adapter. The
+ argument reports the nominal version (i.e. the `VERSION.txt`) file, with a
+ "VERSION_SUFFIX" appended (defaulted to `-dev`), and a git commit hash, if
+ the `git` command successfully reports a hash during the build. The `git`
+ command is invoked by either `make` or `gyp`.
+ * The agent now combines `ReadConsoleOutputW` calls when it polls the console
+ buffer for changes, which may slightly reduce its CPU overhead.
+ [#44](https://github.com/rprichard/winpty/issues/44).
+ * A `gyp` file is added to help compile with MSVC.
+ * The code can now be compiled as C++11 code, though it isn't by default.
+ [bde8922e08](https://github.com/rprichard/winpty/commit/bde8922e08c3638e01ecc7b581b676c314163e3c)
+ * If winpty can't create a new window station, it charges ahead rather than
+ aborting. This situation might happen if winpty were started from an SSH
+ session.
+ * Debugging improvements:
+ * `WINPTYDBG` is renamed to `WINPTY_DEBUG`, and a new `WINPTY_SHOW_CONSOLE`
+ variable keeps the underlying console visible.
+ * A `winpty-debugserver.exe` program is built and shipped by default. It
+ collects the trace output enabled with `WINPTY_DEBUG`.
+ * The `Makefile` build of winpty now compiles `winpty-agent.exe` and
+ `winpty.dll` with -O2.
+
+# Version 0.1.1 (2012-07-28)
+
+Minor bugfix release.
+
+# Version 0.1 (2012-04-17)
+
+Initial release.
diff --git a/src/libs/3rdparty/winpty/VERSION.txt b/src/libs/3rdparty/winpty/VERSION.txt
new file mode 100644
index 0000000000..5d47ff8c45
--- /dev/null
+++ b/src/libs/3rdparty/winpty/VERSION.txt
@@ -0,0 +1 @@
+0.4.4-dev
diff --git a/src/libs/3rdparty/winpty/appveyor.yml b/src/libs/3rdparty/winpty/appveyor.yml
new file mode 100644
index 0000000000..a9e8726fc1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/appveyor.yml
@@ -0,0 +1,16 @@
+image: Visual Studio 2015
+
+init:
+ - C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain"
+ - C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
+ - C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
+
+build_script:
+ - C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64
+ - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin
+ - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64
+ - C:\Python27-x64\python.exe ship\make_msvc_package.py
+
+artifacts:
+ - path: ship\packages\*.tar.gz
+ - path: ship\packages\*.zip
diff --git a/src/libs/3rdparty/winpty/configure b/src/libs/3rdparty/winpty/configure
new file mode 100644
index 0000000000..6d37d65b09
--- /dev/null
+++ b/src/libs/3rdparty/winpty/configure
@@ -0,0 +1,167 @@
+#!/bin/bash
+#
+# Copyright (c) 2011-2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+#
+# findTool(desc, commandList)
+#
+# Searches commandLine for the first command in the PATH and returns it.
+# Prints an error and aborts the script if no match is found.
+#
+FINDTOOL_OUT=""
+function findTool {
+ DESC=$1
+ OPTIONS=$2
+ for CMD in ${OPTIONS}; do
+ if (which $CMD &>/dev/null) then
+ echo "Found $DESC: $CMD"
+ FINDTOOL_OUT="$CMD"
+ return
+ fi
+ done
+ echo "Error: could not find $DESC. One of these should be in your PATH:"
+ for CMD in ${OPTIONS}; do
+ echo " * $CMD"
+ done
+ exit 1
+}
+
+IS_CYGWIN=0
+IS_MSYS1=0
+IS_MSYS2=0
+
+# Link parts of the Cygwin binary statically to aid in redistribution? The
+# binary still links dynamically against the main DLL. The MinGW binaries are
+# also statically linked and therefore depend only on Windows DLLs. I started
+# linking the Cygwin/MSYS binary statically, because G++ 4.7 changed the
+# Windows C++ ABI.
+UNIX_LDFLAGS_STATIC='-static -static-libgcc -static-libstdc++'
+
+# Detect the environment -- Cygwin or MSYS.
+case $(uname -s) in
+ CYGWIN*)
+ echo 'uname -s identifies a Cygwin environment.'
+ IS_CYGWIN=1
+ case $(uname -m) in
+ i686)
+ echo 'uname -m identifies an i686 environment.'
+ UNIX_CXX=i686-pc-cygwin-g++
+ MINGW_CXX=i686-w64-mingw32-g++
+ ;;
+ x86_64)
+ echo 'uname -m identifies an x86_64 environment.'
+ UNIX_CXX=x86_64-pc-cygwin-g++
+ MINGW_CXX=x86_64-w64-mingw32-g++
+ ;;
+ *)
+ echo 'Error: uname -m did not match either i686 or x86_64.'
+ exit 1
+ ;;
+ esac
+ ;;
+ MSYS*|MINGW*)
+ # MSYS2 notes:
+ # - MSYS2 offers two shortcuts to open an environment:
+ # - MinGW-w64 Win32 Shell. This env reports a `uname -s` of
+ # MINGW32_NT-6.1 on 32-bit Win7. The MinGW-w64 compiler
+ # (i686-w64-mingw32-g++.exe) is in the PATH.
+ # - MSYS2 Shell. `uname -s` instead reports MSYS_NT-6.1.
+ # The i686-w64-mingw32-g++ compiler is not in the PATH.
+ # - MSYS2 appears to use MinGW-w64, not the older mingw.org.
+ # MSYS notes:
+ # - `uname -s` is always MINGW32_NT-6.1 on Win7.
+ echo 'uname -s identifies an MSYS/MSYS2 environment.'
+ case $(uname -m) in
+ i686)
+ echo 'uname -m identifies an i686 environment.'
+ UNIX_CXX=i686-pc-msys-g++
+ if echo "$(uname -r)" | grep '^1[.]' > /dev/null; then
+ # The MSYS-targeting compiler for the original 32-bit-only
+ # MSYS does not recognize the -static-libstdc++ flag, and
+ # it does not work with -static, because it tries to link
+ # statically with the core MSYS library and fails.
+ #
+ # Distinguish between the two using the major version
+ # number of `uname -r`:
+ #
+ # MSYS uname -r: 1.0.18(0.48/3/2)
+ # MSYS2 uname -r: 2.0.0(0.284/5/3)
+ #
+ # This is suboptimal because MSYS2 is not actually the
+ # second version of MSYS--it's a brand-new fork of Cygwin.
+ #
+ IS_MSYS1=1
+ UNIX_LDFLAGS_STATIC=
+ MINGW_CXX=mingw32-g++
+ else
+ IS_MSYS2=1
+ MINGW_CXX=i686-w64-mingw32-g++.exe
+ fi
+ ;;
+ x86_64)
+ echo 'uname -m identifies an x86_64 environment.'
+ IS_MSYS2=1
+ UNIX_CXX=x86_64-pc-msys-g++
+ MINGW_CXX=x86_64-w64-mingw32-g++
+ ;;
+ *)
+ echo 'Error: uname -m did not match either i686 or x86_64.'
+ exit 1
+ ;;
+ esac
+ ;;
+ *)
+ echo 'Error: uname -s did not match either CYGWIN* or MINGW*.'
+ exit 1
+ ;;
+esac
+
+# Search the PATH and pick the first match.
+findTool "Cygwin/MSYS G++ compiler" "$UNIX_CXX"
+UNIX_CXX=$FINDTOOL_OUT
+findTool "MinGW G++ compiler" "$MINGW_CXX"
+MINGW_CXX=$FINDTOOL_OUT
+
+# Write config files.
+echo Writing config.mk
+echo UNIX_CXX=$UNIX_CXX > config.mk
+echo UNIX_LDFLAGS_STATIC=$UNIX_LDFLAGS_STATIC >> config.mk
+echo MINGW_CXX=$MINGW_CXX >> config.mk
+
+if test $IS_MSYS1 = 1; then
+ echo UNIX_CXXFLAGS += -DWINPTY_TARGET_MSYS1 >> config.mk
+ # The MSYS1 MinGW compiler has a bug that prevents inclusion of algorithm
+ # and math.h in normal C++11 mode. The workaround is to enable the gnu++11
+ # mode instead. The bug was fixed on 2015-07-31, but as of 2016-02-26, the
+ # fix apparently hasn't been released. See
+ # http://ehc.ac/p/mingw/bugs/2250/.
+ echo MINGW_ENABLE_CXX11_FLAG := -std=gnu++11 >> config.mk
+fi
+
+if test -d .git -a -f .git/HEAD -a -f .git/index && git rev-parse HEAD >&/dev/null; then
+ echo "Commit info: git"
+ echo 'COMMIT_HASH = $(shell git rev-parse HEAD)' >> config.mk
+ echo 'COMMIT_HASH_DEP := config.mk .git/HEAD .git/index' >> config.mk
+else
+ echo "Commit info: none"
+ echo 'COMMIT_HASH := none' >> config.mk
+ echo 'COMMIT_HASH_DEP := config.mk' >> config.mk
+fi
diff --git a/src/libs/3rdparty/winpty/misc/.gitignore b/src/libs/3rdparty/winpty/misc/.gitignore
new file mode 100644
index 0000000000..23751645fa
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/.gitignore
@@ -0,0 +1,2 @@
+*.exe
+UnixEcho \ No newline at end of file
diff --git a/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc b/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc
new file mode 100644
index 0000000000..a5bb074826
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc
@@ -0,0 +1,90 @@
+#include <windows.h>
+#include <cassert>
+
+#include "TestUtil.cc"
+
+void dumpInfoToTrace() {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info));
+ trace("win=(%d,%d,%d,%d)",
+ (int)info.srWindow.Left,
+ (int)info.srWindow.Top,
+ (int)info.srWindow.Right,
+ (int)info.srWindow.Bottom);
+ trace("buf=(%d,%d)",
+ (int)info.dwSize.X,
+ (int)info.dwSize.Y);
+ trace("cur=(%d,%d)",
+ (int)info.dwCursorPosition.X,
+ (int)info.dwCursorPosition.Y);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ setWindowPos(0, 0, 1, 1);
+
+ if (false) {
+ // Reducing the buffer height can move the window up.
+ setBufferSize(80, 25);
+ setWindowPos(0, 20, 80, 5);
+ Sleep(2000);
+ setBufferSize(80, 10);
+ }
+
+ if (false) {
+ // Reducing the buffer height moves the window up and the buffer
+ // contents up too.
+ setBufferSize(80, 25);
+ setWindowPos(0, 20, 80, 5);
+ setCursorPos(0, 20);
+ printf("TEST1\nTEST2\nTEST3\nTEST4\n");
+ fflush(stdout);
+ Sleep(2000);
+ setBufferSize(80, 10);
+ }
+
+ if (false) {
+ // Reducing the buffer width can move the window left.
+ setBufferSize(80, 25);
+ setWindowPos(40, 0, 40, 25);
+ Sleep(2000);
+ setBufferSize(60, 25);
+ }
+
+ if (false) {
+ // Sometimes the buffer contents are shifted up; sometimes they're
+ // shifted down. It seems to depend on the cursor position?
+
+ // setBufferSize(80, 25);
+ // setWindowPos(0, 20, 80, 5);
+ // setCursorPos(0, 20);
+ // printf("TESTa\nTESTb\nTESTc\nTESTd\nTESTe");
+ // fflush(stdout);
+ // setCursorPos(0, 0);
+ // printf("TEST1\nTEST2\nTEST3\nTEST4\nTEST5");
+ // fflush(stdout);
+ // setCursorPos(0, 24);
+ // Sleep(5000);
+ // setBufferSize(80, 24);
+
+ setBufferSize(80, 20);
+ setWindowPos(0, 10, 80, 10);
+ setCursorPos(0, 18);
+
+ printf("TEST1\nTEST2");
+ fflush(stdout);
+ setCursorPos(0, 18);
+
+ Sleep(2000);
+ setBufferSize(80, 18);
+ }
+
+ dumpInfoToTrace();
+ Sleep(30000);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc b/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc
new file mode 100644
index 0000000000..701a2cb4a3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc
@@ -0,0 +1,53 @@
+// A test program for CreateConsoleScreenBuffer / SetConsoleActiveScreenBuffer
+//
+
+#include <windows.h>
+#include <stdio.h>
+#include <conio.h>
+#include <io.h>
+#include <cassert>
+
+#include "TestUtil.cc"
+
+int main()
+{
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE childBuffer = CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
+
+ SetConsoleActiveScreenBuffer(childBuffer);
+
+ while (true) {
+ char buf[1024];
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ assert(GetConsoleScreenBufferInfo(origBuffer, &info));
+ trace("child.size=(%d,%d)", (int)info.dwSize.X, (int)info.dwSize.Y);
+ trace("child.cursor=(%d,%d)", (int)info.dwCursorPosition.X, (int)info.dwCursorPosition.Y);
+ trace("child.window=(%d,%d,%d,%d)",
+ (int)info.srWindow.Left, (int)info.srWindow.Top,
+ (int)info.srWindow.Right, (int)info.srWindow.Bottom);
+ trace("child.maxSize=(%d,%d)", (int)info.dwMaximumWindowSize.X, (int)info.dwMaximumWindowSize.Y);
+
+ int ch = getch();
+ sprintf(buf, "%02x\n", ch);
+ DWORD actual = 0;
+ WriteFile(childBuffer, buf, strlen(buf), &actual, NULL);
+ if (ch == 0x1b/*ESC*/ || ch == 0x03/*CTRL-C*/)
+ break;
+
+ if (ch == 'b') {
+ setBufferSize(origBuffer, 40, 25);
+ } else if (ch == 'w') {
+ setWindowPos(origBuffer, 1, 1, 38, 23);
+ } else if (ch == 'c') {
+ setCursorPos(origBuffer, 10, 10);
+ }
+ }
+
+ SetConsoleActiveScreenBuffer(origBuffer);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ClearConsole.cc b/src/libs/3rdparty/winpty/misc/ClearConsole.cc
new file mode 100644
index 0000000000..f95f8c84ca
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ClearConsole.cc
@@ -0,0 +1,72 @@
+/*
+ * Demonstrates that console clearing sets each cell's character to SP, not
+ * NUL, and it sets the attribute of each cell to the current text attribute.
+ *
+ * This confirms the MSDN instruction in the "Clearing the Screen" article.
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx
+ * It advises using GetConsoleScreenBufferInfo to get the current text
+ * attribute, then FillConsoleOutputCharacter and FillConsoleOutputAttribute to
+ * write to the console buffer.
+ */
+
+#include <windows.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ SetConsoleTextAttribute(conout, 0x24);
+ system("cls");
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(80, 25);
+ setWindowPos(0, 0, 80, 25);
+
+ CHAR_INFO buf;
+ COORD bufSize = { 1, 1 };
+ COORD bufCoord = { 0, 0 };
+ SMALL_RECT rect = { 5, 5, 5, 5 };
+ BOOL ret;
+ DWORD actual;
+ COORD writeCoord = { 5, 5 };
+
+ // After cls, each cell's character is a space, and its attributes are the
+ // default text attributes.
+ ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
+ assert(ret && buf.Char.UnicodeChar == L' ' && buf.Attributes == 0x24);
+
+ // Nevertheless, it is possible to change a cell to NUL.
+ ret = FillConsoleOutputCharacterW(conout, L'\0', 1, writeCoord, &actual);
+ assert(ret && actual == 1);
+ ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
+ assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0x24);
+
+ // As well as a 0 attribute. (As one would expect, the cell is
+ // black-on-black.)
+ ret = FillConsoleOutputAttribute(conout, 0, 1, writeCoord, &actual);
+ assert(ret && actual == 1);
+ ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
+ assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0);
+ ret = FillConsoleOutputCharacterW(conout, L'X', 1, writeCoord, &actual);
+ assert(ret && actual == 1);
+ ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
+ assert(ret && buf.Char.UnicodeChar == L'X' && buf.Attributes == 0);
+
+ // The 'X' is invisible.
+ countDown(3);
+
+ ret = FillConsoleOutputAttribute(conout, 0x42, 1, writeCoord, &actual);
+ assert(ret && actual == 1);
+
+ countDown(5);
+}
diff --git a/src/libs/3rdparty/winpty/misc/ConinMode.cc b/src/libs/3rdparty/winpty/misc/ConinMode.cc
new file mode 100644
index 0000000000..1e1428d8b0
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ConinMode.cc
@@ -0,0 +1,117 @@
+#include <windows.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+static HANDLE getConin() {
+ HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
+ if (conin == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "error: cannot get stdin\n");
+ exit(1);
+ }
+ return conin;
+}
+
+static DWORD getConsoleMode() {
+ DWORD mode = 0;
+ if (!GetConsoleMode(getConin(), &mode)) {
+ fprintf(stderr, "error: GetConsoleMode failed (is stdin a console?)\n");
+ exit(1);
+ }
+ return mode;
+}
+
+static void setConsoleMode(DWORD mode) {
+ if (!SetConsoleMode(getConin(), mode)) {
+ fprintf(stderr, "error: SetConsoleMode failed (is stdin a console?)\n");
+ exit(1);
+ }
+}
+
+static long parseInt(const std::string &s) {
+ errno = 0;
+ char *endptr = nullptr;
+ long result = strtol(s.c_str(), &endptr, 0);
+ if (errno != 0 || !endptr || *endptr != '\0') {
+ fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
+ exit(1);
+ }
+ return result;
+}
+
+static void usage() {
+ printf("Usage: ConinMode [verb] [options]\n");
+ printf("Verbs:\n");
+ printf(" [info] Dumps info about mode flags.\n");
+ printf(" get Prints the mode DWORD.\n");
+ printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
+ printf(" set VALUE MASK\n");
+ printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
+ exit(1);
+}
+
+struct {
+ const char *name;
+ DWORD value;
+} kInputFlags[] = {
+ "ENABLE_PROCESSED_INPUT", ENABLE_PROCESSED_INPUT, // 0x0001
+ "ENABLE_LINE_INPUT", ENABLE_LINE_INPUT, // 0x0002
+ "ENABLE_ECHO_INPUT", ENABLE_ECHO_INPUT, // 0x0004
+ "ENABLE_WINDOW_INPUT", ENABLE_WINDOW_INPUT, // 0x0008
+ "ENABLE_MOUSE_INPUT", ENABLE_MOUSE_INPUT, // 0x0010
+ "ENABLE_INSERT_MODE", ENABLE_INSERT_MODE, // 0x0020
+ "ENABLE_QUICK_EDIT_MODE", ENABLE_QUICK_EDIT_MODE, // 0x0040
+ "ENABLE_EXTENDED_FLAGS", ENABLE_EXTENDED_FLAGS, // 0x0080
+ "ENABLE_VIRTUAL_TERMINAL_INPUT", 0x0200/*ENABLE_VIRTUAL_TERMINAL_INPUT*/, // 0x0200
+};
+
+int main(int argc, char *argv[]) {
+ std::vector<std::string> args;
+ for (size_t i = 1; i < argc; ++i) {
+ args.push_back(argv[i]);
+ }
+
+ if (args.empty() || args.size() == 1 && args[0] == "info") {
+ DWORD mode = getConsoleMode();
+ printf("mode: 0x%lx\n", mode);
+ for (const auto &flag : kInputFlags) {
+ printf("%-29s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
+ mode &= ~flag.value;
+ }
+ for (int i = 0; i < 32; ++i) {
+ if (mode & (1u << i)) {
+ printf("Unrecognized flag: %04x\n", (1u << i));
+ }
+ }
+ return 0;
+ }
+
+ const auto verb = args[0];
+
+ if (verb == "set") {
+ if (args.size() == 2) {
+ const DWORD newMode = parseInt(args[1]);
+ setConsoleMode(newMode);
+ } else if (args.size() == 3) {
+ const DWORD mode = parseInt(args[1]);
+ const DWORD mask = parseInt(args[2]);
+ const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
+ setConsoleMode(newMode);
+ } else {
+ usage();
+ }
+ } else if (verb == "get") {
+ if (args.size() != 1) {
+ usage();
+ }
+ printf("0x%lx\n", getConsoleMode());
+ } else {
+ usage();
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ConinMode.ps1 b/src/libs/3rdparty/winpty/misc/ConinMode.ps1
new file mode 100644
index 0000000000..ecfe8f039e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ConinMode.ps1
@@ -0,0 +1,116 @@
+#
+# PowerShell script for controlling the console QuickEdit and InsertMode flags.
+#
+# Turn QuickEdit off to interact with mouse-driven console programs.
+#
+# Usage:
+#
+# powershell .\ConinMode.ps1 [Options]
+#
+# Options:
+# -QuickEdit [on/off]
+# -InsertMode [on/off]
+# -Mode [integer]
+#
+
+param (
+ [ValidateSet("on", "off")][string] $QuickEdit,
+ [ValidateSet("on", "off")][string] $InsertMode,
+ [int] $Mode
+)
+
+$signature = @'
+[DllImport("kernel32.dll", SetLastError = true)]
+public static extern IntPtr GetStdHandle(int nStdHandle);
+
+[DllImport("kernel32.dll", SetLastError = true)]
+public static extern uint GetConsoleMode(
+ IntPtr hConsoleHandle,
+ out uint lpMode);
+
+[DllImport("kernel32.dll", SetLastError = true)]
+public static extern uint SetConsoleMode(
+ IntPtr hConsoleHandle,
+ uint dwMode);
+
+public const int STD_INPUT_HANDLE = -10;
+public const int ENABLE_INSERT_MODE = 0x0020;
+public const int ENABLE_QUICK_EDIT_MODE = 0x0040;
+public const int ENABLE_EXTENDED_FLAGS = 0x0080;
+'@
+
+$WinAPI = Add-Type -MemberDefinition $signature `
+ -Name WinAPI -Namespace ConinModeScript `
+ -PassThru
+
+function GetConIn {
+ $ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE)
+ if ($ret -eq -1) {
+ throw "error: cannot get stdin"
+ }
+ return $ret
+}
+
+function GetConsoleMode {
+ $conin = GetConIn
+ $mode = 0
+ $ret = $WinAPI::GetConsoleMode($conin, [ref]$mode)
+ if ($ret -eq 0) {
+ throw "GetConsoleMode failed (is stdin a console?)"
+ }
+ return $mode
+}
+
+function SetConsoleMode($mode) {
+ $conin = GetConIn
+ $ret = $WinAPI::SetConsoleMode($conin, $mode)
+ if ($ret -eq 0) {
+ throw "SetConsoleMode failed (is stdin a console?)"
+ }
+}
+
+$oldMode = GetConsoleMode
+$newMode = $oldMode
+$doingSomething = $false
+
+if ($PSBoundParameters.ContainsKey("Mode")) {
+ $newMode = $Mode
+ $doingSomething = $true
+}
+
+if ($QuickEdit + $InsertMode -ne "") {
+ if (!($newMode -band $WinAPI::ENABLE_EXTENDED_FLAGS)) {
+ # We can't enable an extended flag without overwriting the existing
+ # QuickEdit/InsertMode flags. AFAICT, there is no way to query their
+ # existing values, so at least we can choose sensible defaults.
+ $newMode = $newMode -bor $WinAPI::ENABLE_EXTENDED_FLAGS
+ $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
+ $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
+ $doingSomething = $true
+ }
+}
+
+if ($QuickEdit -eq "on") {
+ $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
+ $doingSomething = $true
+} elseif ($QuickEdit -eq "off") {
+ $newMode = $newMode -band (-bnot $WinAPI::ENABLE_QUICK_EDIT_MODE)
+ $doingSomething = $true
+}
+
+if ($InsertMode -eq "on") {
+ $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
+ $doingSomething = $true
+} elseif ($InsertMode -eq "off") {
+ $newMode = $newMode -band (-bnot $WinAPI::ENABLE_INSERT_MODE)
+ $doingSomething = $true
+}
+
+if ($doingSomething) {
+ echo "old mode: $oldMode"
+ SetConsoleMode $newMode
+ $newMode = GetConsoleMode
+ echo "new mode: $newMode"
+} else {
+ echo "mode: $oldMode"
+}
diff --git a/src/libs/3rdparty/winpty/misc/ConoutMode.cc b/src/libs/3rdparty/winpty/misc/ConoutMode.cc
new file mode 100644
index 0000000000..100e0c7bea
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ConoutMode.cc
@@ -0,0 +1,113 @@
+#include <windows.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+static HANDLE getConout() {
+ HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (conout == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "error: cannot get stdout\n");
+ exit(1);
+ }
+ return conout;
+}
+
+static DWORD getConsoleMode() {
+ DWORD mode = 0;
+ if (!GetConsoleMode(getConout(), &mode)) {
+ fprintf(stderr, "error: GetConsoleMode failed (is stdout a console?)\n");
+ exit(1);
+ }
+ return mode;
+}
+
+static void setConsoleMode(DWORD mode) {
+ if (!SetConsoleMode(getConout(), mode)) {
+ fprintf(stderr, "error: SetConsoleMode failed (is stdout a console?)\n");
+ exit(1);
+ }
+}
+
+static long parseInt(const std::string &s) {
+ errno = 0;
+ char *endptr = nullptr;
+ long result = strtol(s.c_str(), &endptr, 0);
+ if (errno != 0 || !endptr || *endptr != '\0') {
+ fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
+ exit(1);
+ }
+ return result;
+}
+
+static void usage() {
+ printf("Usage: ConoutMode [verb] [options]\n");
+ printf("Verbs:\n");
+ printf(" [info] Dumps info about mode flags.\n");
+ printf(" get Prints the mode DWORD.\n");
+ printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
+ printf(" set VALUE MASK\n");
+ printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
+ exit(1);
+}
+
+struct {
+ const char *name;
+ DWORD value;
+} kOutputFlags[] = {
+ "ENABLE_PROCESSED_OUTPUT", ENABLE_PROCESSED_OUTPUT, // 0x0001
+ "ENABLE_WRAP_AT_EOL_OUTPUT", ENABLE_WRAP_AT_EOL_OUTPUT, // 0x0002
+ "ENABLE_VIRTUAL_TERMINAL_PROCESSING", 0x0004/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/, // 0x0004
+ "DISABLE_NEWLINE_AUTO_RETURN", 0x0008/*DISABLE_NEWLINE_AUTO_RETURN*/, // 0x0008
+ "ENABLE_LVB_GRID_WORLDWIDE", 0x0010/*ENABLE_LVB_GRID_WORLDWIDE*/, //0x0010
+};
+
+int main(int argc, char *argv[]) {
+ std::vector<std::string> args;
+ for (size_t i = 1; i < argc; ++i) {
+ args.push_back(argv[i]);
+ }
+
+ if (args.empty() || args.size() == 1 && args[0] == "info") {
+ DWORD mode = getConsoleMode();
+ printf("mode: 0x%lx\n", mode);
+ for (const auto &flag : kOutputFlags) {
+ printf("%-34s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
+ mode &= ~flag.value;
+ }
+ for (int i = 0; i < 32; ++i) {
+ if (mode & (1u << i)) {
+ printf("Unrecognized flag: %04x\n", (1u << i));
+ }
+ }
+ return 0;
+ }
+
+ const auto verb = args[0];
+
+ if (verb == "set") {
+ if (args.size() == 2) {
+ const DWORD newMode = parseInt(args[1]);
+ setConsoleMode(newMode);
+ } else if (args.size() == 3) {
+ const DWORD mode = parseInt(args[1]);
+ const DWORD mask = parseInt(args[2]);
+ const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
+ setConsoleMode(newMode);
+ } else {
+ usage();
+ }
+ } else if (verb == "get") {
+ if (args.size() != 1) {
+ usage();
+ }
+ printf("0x%lx\n", getConsoleMode());
+ } else {
+ usage();
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/DebugClient.py b/src/libs/3rdparty/winpty/misc/DebugClient.py
new file mode 100644
index 0000000000..cd12df8924
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/DebugClient.py
@@ -0,0 +1,42 @@
+#!python
+# Run with native CPython. Needs pywin32 extensions.
+
+# Copyright (c) 2011-2012 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import winerror
+import win32pipe
+import win32file
+import win32api
+import sys
+import pywintypes
+import time
+
+if len(sys.argv) != 2:
+ print("Usage: %s message" % sys.argv[0])
+ sys.exit(1)
+
+message = "[%05.3f %s]: %s" % (time.time() % 100000, sys.argv[0], sys.argv[1])
+
+win32pipe.CallNamedPipe(
+ "\\\\.\\pipe\\DebugServer",
+ message.encode(),
+ 16,
+ win32pipe.NMPWAIT_WAIT_FOREVER)
diff --git a/src/libs/3rdparty/winpty/misc/DebugServer.py b/src/libs/3rdparty/winpty/misc/DebugServer.py
new file mode 100644
index 0000000000..3fc068bae7
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/DebugServer.py
@@ -0,0 +1,63 @@
+#!python
+#
+# Run with native CPython. Needs pywin32 extensions.
+
+# Copyright (c) 2011-2012 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import win32pipe
+import win32api
+import win32file
+import time
+import threading
+import sys
+
+# A message may not be larger than this size.
+MSG_SIZE=4096
+
+serverPipe = win32pipe.CreateNamedPipe(
+ "\\\\.\\pipe\\DebugServer",
+ win32pipe.PIPE_ACCESS_DUPLEX,
+ win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE,
+ win32pipe.PIPE_UNLIMITED_INSTANCES,
+ MSG_SIZE,
+ MSG_SIZE,
+ 10 * 1000,
+ None)
+while True:
+ win32pipe.ConnectNamedPipe(serverPipe, None)
+ (ret, data) = win32file.ReadFile(serverPipe, MSG_SIZE)
+ print(data.decode())
+ sys.stdout.flush()
+
+ # The client uses CallNamedPipe to send its message. CallNamedPipe waits
+ # for a reply message. If I send a reply, however, using WriteFile, then
+ # sometimes WriteFile fails with:
+ # pywintypes.error: (232, 'WriteFile', 'The pipe is being closed.')
+ # I can't figure out how to write a strictly correct pipe server, but if
+ # I comment out the WriteFile line, then everything seems to work. I
+ # think the DisconnectNamedPipe call aborts the client's CallNamedPipe
+ # call normally.
+
+ try:
+ win32file.WriteFile(serverPipe, b'OK')
+ except:
+ pass
+ win32pipe.DisconnectNamedPipe(serverPipe)
diff --git a/src/libs/3rdparty/winpty/misc/DumpLines.py b/src/libs/3rdparty/winpty/misc/DumpLines.py
new file mode 100644
index 0000000000..40049961b5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/DumpLines.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+import sys
+
+for i in range(1, int(sys.argv[1]) + 1):
+ print i, "X" * 78
diff --git a/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt b/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt
new file mode 100644
index 0000000000..37914dac26
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt
@@ -0,0 +1,46 @@
+Note regarding ENABLE_EXTENDED_FLAGS (2016-05-30)
+
+There is a complicated interaction between the ENABLE_EXTENDED_FLAGS flag
+and the ENABLE_QUICK_EDIT_MODE and ENABLE_INSERT_MODE flags (presumably for
+backwards compatibility?). I studied the behavior on Windows 7 and Windows
+10, with both the old and new consoles, and I didn't see any differences
+between versions. Here's what I seemed to observe:
+
+ - The console has three flags internally:
+ - QuickEdit
+ - InsertMode
+ - ExtendedFlags
+
+ - SetConsoleMode psuedocode:
+ void SetConsoleMode(..., DWORD mode) {
+ ExtendedFlags = (mode & (ENABLE_EXTENDED_FLAGS
+ | ENABLE_QUICK_EDIT_MODE
+ | ENABLE_INSERT_MODE )) != 0;
+ if (ExtendedFlags) {
+ QuickEdit = (mode & ENABLE_QUICK_EDIT_MODE) != 0;
+ InsertMode = (mode & ENABLE_INSERT_MODE) != 0;
+ }
+ }
+
+ - Setting QuickEdit or InsertMode from the properties dialog GUI does not
+ affect the ExtendedFlags setting -- it simply toggles the one flag.
+
+ - GetConsoleMode psuedocode:
+ GetConsoleMode(..., DWORD *result) {
+ if (ExtendedFlags) {
+ *result |= ENABLE_EXTENDED_FLAGS;
+ if (QuickEdit) { *result |= ENABLE_QUICK_EDIT_MODE; }
+ if (InsertMode) { *result |= ENABLE_INSERT_MODE; }
+ }
+ }
+
+Effectively, the ExtendedFlags flags controls whether the other two flags
+are visible/controlled by the user application. If they aren't visible,
+though, there is no way for the user application to make them visible,
+except by overwriting their values! Calling SetConsoleMode with just
+ENABLE_EXTENDED_FLAGS would clear the extended flags we want to read.
+
+Consequently, if a program temporarily alters the QuickEdit flag (e.g. to
+enable mouse input), it cannot restore the original values of the QuickEdit
+and InsertMode flags, UNLESS every other console program cooperates by
+keeping the ExtendedFlags flag set.
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt
new file mode 100644
index 0000000000..067bd3824a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt
@@ -0,0 +1,528 @@
+==================================
+Code Page 437, Consolas font
+==================================
+
+Options: -face "Consolas" -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+FontSurvey "-face \"Consolas\" -family 0x36"
+
+Windows 7
+---------
+
+Size 1: 1,3 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 1,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 2,5 BAD (HHHHHH)
+Size 6: 3,6 BAD (HHHHHH)
+Size 7: 3,6 BAD (HHHHHH)
+Size 8: 4,8 BAD (HHHHHH)
+Size 9: 4,9 BAD (HHHHHH)
+Size 10: 5,10 BAD (HHHHHH)
+Size 11: 5,11 BAD (HHHHHH)
+Size 12: 6,12 BAD (HHHHHH)
+Size 13: 6,13 BAD (HHHHHH)
+Size 14: 7,14 BAD (HHHHHH)
+Size 15: 7,15 BAD (HHHHHH)
+Size 16: 8,16 BAD (HHHHHH)
+Size 17: 8,17 BAD (HHHHHH)
+Size 18: 8,18 BAD (HHHHHH)
+Size 19: 9,19 BAD (HHHHHH)
+Size 20: 9,20 BAD (HHHHHH)
+Size 21: 10,22 BAD (HHHHHH)
+Size 22: 10,22 BAD (HHHHHH)
+Size 23: 11,23 BAD (HHHHHH)
+Size 24: 11,24 BAD (HHHHHH)
+Size 25: 12,25 BAD (HHHHHH)
+Size 26: 12,26 BAD (HHHHHH)
+Size 27: 13,27 BAD (HHHHHH)
+Size 28: 13,28 BAD (HHHHHH)
+Size 29: 14,29 BAD (HHHHHH)
+Size 30: 14,30 BAD (HHHHHH)
+Size 31: 15,31 BAD (HHHHHH)
+Size 32: 15,32 BAD (HHHHHH)
+Size 33: 15,33 BAD (HHHHHH)
+Size 34: 16,34 BAD (HHHHHH)
+Size 35: 16,36 BAD (HHHHHH)
+Size 36: 17,36 BAD (HHHHHH)
+Size 37: 17,37 BAD (HHHHHH)
+Size 38: 18,38 BAD (HHHHHH)
+Size 39: 18,39 BAD (HHHHHH)
+Size 40: 19,40 BAD (HHHHHH)
+Size 41: 19,41 BAD (HHHHHH)
+Size 42: 20,42 BAD (HHHHHH)
+Size 43: 20,43 BAD (HHHHHH)
+Size 44: 21,44 BAD (HHHHHH)
+Size 45: 21,45 BAD (HHHHHH)
+Size 46: 22,46 BAD (HHHHHH)
+Size 47: 22,47 BAD (HHHHHH)
+Size 48: 23,48 BAD (HHHHHH)
+Size 49: 23,49 BAD (HHHHHH)
+Size 50: 23,50 BAD (HHHHHH)
+Size 51: 24,51 BAD (HHHHHH)
+Size 52: 24,52 BAD (HHHHHH)
+Size 53: 25,53 BAD (HHHHHH)
+Size 54: 25,54 BAD (HHHHHH)
+Size 55: 26,55 BAD (HHHHHH)
+Size 56: 26,56 BAD (HHHHHH)
+Size 57: 27,57 BAD (HHHHHH)
+Size 58: 27,58 BAD (HHHHHH)
+Size 59: 28,59 BAD (HHHHHH)
+Size 60: 28,60 BAD (HHHHHH)
+Size 61: 29,61 BAD (HHHHHH)
+Size 62: 29,62 BAD (HHHHHH)
+Size 63: 30,64 BAD (HHHHHH)
+Size 64: 30,64 BAD (HHHHHH)
+Size 65: 31,65 BAD (HHHHHH)
+Size 66: 31,66 BAD (HHHHHH)
+Size 67: 31,67 BAD (HHHHHH)
+Size 68: 32,68 BAD (HHHHHH)
+Size 69: 32,69 BAD (HHHHHH)
+Size 70: 33,70 BAD (HHHHHH)
+Size 71: 33,71 BAD (HHHHHH)
+Size 72: 34,72 BAD (HHHHHH)
+Size 73: 34,73 BAD (HHHHHH)
+Size 74: 35,74 BAD (HHHHHH)
+Size 75: 35,75 BAD (HHHHHH)
+Size 76: 36,76 BAD (HHHHHH)
+Size 77: 36,77 BAD (HHHHHH)
+Size 78: 37,78 BAD (HHHHHH)
+Size 79: 37,79 BAD (HHHHHH)
+Size 80: 38,80 BAD (HHHHHH)
+Size 81: 38,81 BAD (HHHHHH)
+Size 82: 39,82 BAD (HHHHHH)
+Size 83: 39,83 BAD (HHHHHH)
+Size 84: 39,84 BAD (HHHHHH)
+Size 85: 40,85 BAD (HHHHHH)
+Size 86: 40,86 BAD (HHHHHH)
+Size 87: 41,87 BAD (HHHHHH)
+Size 88: 41,88 BAD (HHHHHH)
+Size 89: 42,89 BAD (HHHHHH)
+Size 90: 42,90 BAD (HHHHHH)
+Size 91: 43,91 BAD (HHHHHH)
+Size 92: 43,92 BAD (HHHHHH)
+Size 93: 44,93 BAD (HHHHHH)
+Size 94: 44,94 BAD (HHHHHH)
+Size 95: 45,95 BAD (HHHHHH)
+Size 96: 45,96 BAD (HHHHHH)
+Size 97: 46,97 BAD (HHHHHH)
+Size 98: 46,98 BAD (HHHHHH)
+Size 99: 46,99 BAD (HHHHHH)
+Size 100: 47,100 BAD (HHHHHH)
+
+Windows 8
+---------
+
+Size 1: 1,3 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 1,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 2,5 BAD (HHHHHH)
+Size 6: 3,6 BAD (HHHHHH)
+Size 7: 3,6 BAD (HHHHHH)
+Size 8: 4,8 BAD (HHHHHH)
+Size 9: 4,9 BAD (HHHHHH)
+Size 10: 5,10 BAD (HHHHHH)
+Size 11: 5,11 BAD (HHHHHH)
+Size 12: 6,12 BAD (HHHHHH)
+Size 13: 6,13 BAD (HHHHHH)
+Size 14: 7,14 BAD (HHHHHH)
+Size 15: 7,15 BAD (HHHHHH)
+Size 16: 8,16 BAD (HHHHHH)
+Size 17: 8,17 BAD (HHHHHH)
+Size 18: 8,18 BAD (HHHHHH)
+Size 19: 9,19 BAD (HHHHHH)
+Size 20: 9,20 BAD (HHHHHH)
+Size 21: 10,22 BAD (HHHHHH)
+Size 22: 10,22 BAD (HHHHHH)
+Size 23: 11,23 BAD (HHHHHH)
+Size 24: 11,24 BAD (HHHHHH)
+Size 25: 12,25 BAD (HHHHHH)
+Size 26: 12,26 BAD (HHHHHH)
+Size 27: 13,27 BAD (HHHHHH)
+Size 28: 13,28 BAD (HHHHHH)
+Size 29: 14,29 BAD (HHHHHH)
+Size 30: 14,30 BAD (HHHHHH)
+Size 31: 15,31 BAD (HHHHHH)
+Size 32: 15,32 BAD (HHHHHH)
+Size 33: 15,33 BAD (HHHHHH)
+Size 34: 16,34 BAD (HHHHHH)
+Size 35: 16,36 BAD (HHHHHH)
+Size 36: 17,36 BAD (HHHHHH)
+Size 37: 17,37 BAD (HHHHHH)
+Size 38: 18,38 BAD (HHHHHH)
+Size 39: 18,39 BAD (HHHHHH)
+Size 40: 19,40 BAD (HHHHHH)
+Size 41: 19,41 BAD (HHHHHH)
+Size 42: 20,42 BAD (HHHHHH)
+Size 43: 20,43 BAD (HHHHHH)
+Size 44: 21,44 BAD (HHHHHH)
+Size 45: 21,45 BAD (HHHHHH)
+Size 46: 22,46 BAD (HHHHHH)
+Size 47: 22,47 BAD (HHHHHH)
+Size 48: 23,48 BAD (HHHHHH)
+Size 49: 23,49 BAD (HHHHHH)
+Size 50: 23,50 BAD (HHHHHH)
+Size 51: 24,51 BAD (HHHHHH)
+Size 52: 24,52 BAD (HHHHHH)
+Size 53: 25,53 BAD (HHHHHH)
+Size 54: 25,54 BAD (HHHHHH)
+Size 55: 26,55 BAD (HHHHHH)
+Size 56: 26,56 BAD (HHHHHH)
+Size 57: 27,57 BAD (HHHHHH)
+Size 58: 27,58 BAD (HHHHHH)
+Size 59: 28,59 BAD (HHHHHH)
+Size 60: 28,60 BAD (HHHHHH)
+Size 61: 29,61 BAD (HHHHHH)
+Size 62: 29,62 BAD (HHHHHH)
+Size 63: 30,64 BAD (HHHHHH)
+Size 64: 30,64 BAD (HHHHHH)
+Size 65: 31,65 BAD (HHHHHH)
+Size 66: 31,66 BAD (HHHHHH)
+Size 67: 31,67 BAD (HHHHHH)
+Size 68: 32,68 BAD (HHHHHH)
+Size 69: 32,69 BAD (HHHHHH)
+Size 70: 33,70 BAD (HHHHHH)
+Size 71: 33,71 BAD (HHHHHH)
+Size 72: 34,72 BAD (HHHHHH)
+Size 73: 34,73 BAD (HHHHHH)
+Size 74: 35,74 BAD (HHHHHH)
+Size 75: 35,75 BAD (HHHHHH)
+Size 76: 36,76 BAD (HHHHHH)
+Size 77: 36,77 BAD (HHHHHH)
+Size 78: 37,78 BAD (HHHHHH)
+Size 79: 37,79 BAD (HHHHHH)
+Size 80: 38,80 BAD (HHHHHH)
+Size 81: 38,81 BAD (HHHHHH)
+Size 82: 39,82 BAD (HHHHHH)
+Size 83: 39,83 BAD (HHHHHH)
+Size 84: 39,84 BAD (HHHHHH)
+Size 85: 40,85 BAD (HHHHHH)
+Size 86: 40,86 BAD (HHHHHH)
+Size 87: 41,87 BAD (HHHHHH)
+Size 88: 41,88 BAD (HHHHHH)
+Size 89: 42,89 BAD (HHHHHH)
+Size 90: 42,90 BAD (HHHHHH)
+Size 91: 43,91 BAD (HHHHHH)
+Size 92: 43,92 BAD (HHHHHH)
+Size 93: 44,93 BAD (HHHHHH)
+Size 94: 44,94 BAD (HHHHHH)
+Size 95: 45,95 BAD (HHHHHH)
+Size 96: 45,96 BAD (HHHHHH)
+Size 97: 46,97 BAD (HHHHHH)
+Size 98: 46,98 BAD (HHHHHH)
+Size 99: 46,99 BAD (HHHHHH)
+Size 100: 47,100 BAD (HHHHHH)
+
+Windows 8.1
+-----------
+
+Size 1: 1,3 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 1,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 2,5 BAD (HHHHHH)
+Size 6: 3,6 BAD (HHHHHH)
+Size 7: 3,6 BAD (HHHHHH)
+Size 8: 4,8 BAD (HHHHHH)
+Size 9: 4,9 BAD (HHHHHH)
+Size 10: 5,10 BAD (HHHHHH)
+Size 11: 5,11 BAD (HHHHHH)
+Size 12: 6,12 BAD (HHHHHH)
+Size 13: 6,13 BAD (HHHHHH)
+Size 14: 7,14 BAD (HHHHHH)
+Size 15: 7,15 BAD (HHHHHH)
+Size 16: 8,16 BAD (HHHHHH)
+Size 17: 8,17 BAD (HHHHHH)
+Size 18: 8,18 BAD (HHHHHH)
+Size 19: 9,19 BAD (HHHHHH)
+Size 20: 9,20 BAD (HHHHHH)
+Size 21: 10,22 BAD (HHHHHH)
+Size 22: 10,22 BAD (HHHHHH)
+Size 23: 11,23 BAD (HHHHHH)
+Size 24: 11,24 BAD (HHHHHH)
+Size 25: 12,25 BAD (HHHHHH)
+Size 26: 12,26 BAD (HHHHHH)
+Size 27: 13,27 BAD (HHHHHH)
+Size 28: 13,28 BAD (HHHHHH)
+Size 29: 14,29 BAD (HHHHHH)
+Size 30: 14,30 BAD (HHHHHH)
+Size 31: 15,31 BAD (HHHHHH)
+Size 32: 15,32 BAD (HHHHHH)
+Size 33: 15,33 BAD (HHHHHH)
+Size 34: 16,34 BAD (HHHHHH)
+Size 35: 16,36 BAD (HHHHHH)
+Size 36: 17,36 BAD (HHHHHH)
+Size 37: 17,37 BAD (HHHHHH)
+Size 38: 18,38 BAD (HHHHHH)
+Size 39: 18,39 BAD (HHHHHH)
+Size 40: 19,40 BAD (HHHHHH)
+Size 41: 19,41 BAD (HHHHHH)
+Size 42: 20,42 BAD (HHHHHH)
+Size 43: 20,43 BAD (HHHHHH)
+Size 44: 21,44 BAD (HHHHHH)
+Size 45: 21,45 BAD (HHHHHH)
+Size 46: 22,46 BAD (HHHHHH)
+Size 47: 22,47 BAD (HHHHHH)
+Size 48: 23,48 BAD (HHHHHH)
+Size 49: 23,49 BAD (HHHHHH)
+Size 50: 23,50 BAD (HHHHHH)
+Size 51: 24,51 BAD (HHHHHH)
+Size 52: 24,52 BAD (HHHHHH)
+Size 53: 25,53 BAD (HHHHHH)
+Size 54: 25,54 BAD (HHHHHH)
+Size 55: 26,55 BAD (HHHHHH)
+Size 56: 26,56 BAD (HHHHHH)
+Size 57: 27,57 BAD (HHHHHH)
+Size 58: 27,58 BAD (HHHHHH)
+Size 59: 28,59 BAD (HHHHHH)
+Size 60: 28,60 BAD (HHHHHH)
+Size 61: 29,61 BAD (HHHHHH)
+Size 62: 29,62 BAD (HHHHHH)
+Size 63: 30,64 BAD (HHHHHH)
+Size 64: 30,64 BAD (HHHHHH)
+Size 65: 31,65 BAD (HHHHHH)
+Size 66: 31,66 BAD (HHHHHH)
+Size 67: 31,67 BAD (HHHHHH)
+Size 68: 32,68 BAD (HHHHHH)
+Size 69: 32,69 BAD (HHHHHH)
+Size 70: 33,70 BAD (HHHHHH)
+Size 71: 33,71 BAD (HHHHHH)
+Size 72: 34,72 BAD (HHHHHH)
+Size 73: 34,73 BAD (HHHHHH)
+Size 74: 35,74 BAD (HHHHHH)
+Size 75: 35,75 BAD (HHHHHH)
+Size 76: 36,76 BAD (HHHHHH)
+Size 77: 36,77 BAD (HHHHHH)
+Size 78: 37,78 BAD (HHHHHH)
+Size 79: 37,79 BAD (HHHHHH)
+Size 80: 38,80 BAD (HHHHHH)
+Size 81: 38,81 BAD (HHHHHH)
+Size 82: 39,82 BAD (HHHHHH)
+Size 83: 39,83 BAD (HHHHHH)
+Size 84: 39,84 BAD (HHHHHH)
+Size 85: 40,85 BAD (HHHHHH)
+Size 86: 40,86 BAD (HHHHHH)
+Size 87: 41,87 BAD (HHHHHH)
+Size 88: 41,88 BAD (HHHHHH)
+Size 89: 42,89 BAD (HHHHHH)
+Size 90: 42,90 BAD (HHHHHH)
+Size 91: 43,91 BAD (HHHHHH)
+Size 92: 43,92 BAD (HHHHHH)
+Size 93: 44,93 BAD (HHHHHH)
+Size 94: 44,94 BAD (HHHHHH)
+Size 95: 45,95 BAD (HHHHHH)
+Size 96: 45,96 BAD (HHHHHH)
+Size 97: 46,97 BAD (HHHHHH)
+Size 98: 46,98 BAD (HHHHHH)
+Size 99: 46,99 BAD (HHHHHH)
+Size 100: 47,100 BAD (HHHHHH)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,3 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 1,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 2,5 BAD (HHHHHH)
+Size 6: 3,6 BAD (HHHHHH)
+Size 7: 3,6 BAD (HHHHHH)
+Size 8: 4,8 BAD (HHHHHH)
+Size 9: 4,9 BAD (HHHHHH)
+Size 10: 5,10 BAD (HHHHHH)
+Size 11: 5,11 BAD (HHHHHH)
+Size 12: 6,12 BAD (HHHHHH)
+Size 13: 6,13 BAD (HHHHHH)
+Size 14: 7,14 BAD (HHHHHH)
+Size 15: 7,15 BAD (HHHHHH)
+Size 16: 8,16 BAD (HHHHHH)
+Size 17: 8,17 BAD (HHHHHH)
+Size 18: 8,18 BAD (HHHHHH)
+Size 19: 9,19 BAD (HHHHHH)
+Size 20: 9,20 BAD (HHHHHH)
+Size 21: 10,22 BAD (HHHHHH)
+Size 22: 10,22 BAD (HHHHHH)
+Size 23: 11,23 BAD (HHHHHH)
+Size 24: 11,24 BAD (HHHHHH)
+Size 25: 12,25 BAD (HHHHHH)
+Size 26: 12,26 BAD (HHHHHH)
+Size 27: 13,27 BAD (HHHHHH)
+Size 28: 13,28 BAD (HHHHHH)
+Size 29: 14,29 BAD (HHHHHH)
+Size 30: 14,30 BAD (HHHHHH)
+Size 31: 15,31 BAD (HHHHHH)
+Size 32: 15,32 BAD (HHHHHH)
+Size 33: 15,33 BAD (HHHHHH)
+Size 34: 16,34 BAD (HHHHHH)
+Size 35: 16,36 BAD (HHHHHH)
+Size 36: 17,36 BAD (HHHHHH)
+Size 37: 17,37 BAD (HHHHHH)
+Size 38: 18,38 BAD (HHHHHH)
+Size 39: 18,39 BAD (HHHHHH)
+Size 40: 19,40 BAD (HHHHHH)
+Size 41: 19,41 BAD (HHHHHH)
+Size 42: 20,42 BAD (HHHHHH)
+Size 43: 20,43 BAD (HHHHHH)
+Size 44: 21,44 BAD (HHHHHH)
+Size 45: 21,45 BAD (HHHHHH)
+Size 46: 22,46 BAD (HHHHHH)
+Size 47: 22,47 BAD (HHHHHH)
+Size 48: 23,48 BAD (HHHHHH)
+Size 49: 23,49 BAD (HHHHHH)
+Size 50: 23,50 BAD (HHHHHH)
+Size 51: 24,51 BAD (HHHHHH)
+Size 52: 24,52 BAD (HHHHHH)
+Size 53: 25,53 BAD (HHHHHH)
+Size 54: 25,54 BAD (HHHHHH)
+Size 55: 26,55 BAD (HHHHHH)
+Size 56: 26,56 BAD (HHHHHH)
+Size 57: 27,57 BAD (HHHHHH)
+Size 58: 27,58 BAD (HHHHHH)
+Size 59: 28,59 BAD (HHHHHH)
+Size 60: 28,60 BAD (HHHHHH)
+Size 61: 29,61 BAD (HHHHHH)
+Size 62: 29,62 BAD (HHHHHH)
+Size 63: 30,64 BAD (HHHHHH)
+Size 64: 30,64 BAD (HHHHHH)
+Size 65: 31,65 BAD (HHHHHH)
+Size 66: 31,66 BAD (HHHHHH)
+Size 67: 31,67 BAD (HHHHHH)
+Size 68: 32,68 BAD (HHHHHH)
+Size 69: 32,69 BAD (HHHHHH)
+Size 70: 33,70 BAD (HHHHHH)
+Size 71: 33,71 BAD (HHHHHH)
+Size 72: 34,72 BAD (HHHHHH)
+Size 73: 34,73 BAD (HHHHHH)
+Size 74: 35,74 BAD (HHHHHH)
+Size 75: 35,75 BAD (HHHHHH)
+Size 76: 36,76 BAD (HHHHHH)
+Size 77: 36,77 BAD (HHHHHH)
+Size 78: 37,78 BAD (HHHHHH)
+Size 79: 37,79 BAD (HHHHHH)
+Size 80: 38,80 BAD (HHHHHH)
+Size 81: 38,81 BAD (HHHHHH)
+Size 82: 39,82 BAD (HHHHHH)
+Size 83: 39,83 BAD (HHHHHH)
+Size 84: 39,84 BAD (HHHHHH)
+Size 85: 40,85 BAD (HHHHHH)
+Size 86: 40,86 BAD (HHHHHH)
+Size 87: 41,87 BAD (HHHHHH)
+Size 88: 41,88 BAD (HHHHHH)
+Size 89: 42,89 BAD (HHHHHH)
+Size 90: 42,90 BAD (HHHHHH)
+Size 91: 43,91 BAD (HHHHHH)
+Size 92: 43,92 BAD (HHHHHH)
+Size 93: 44,93 BAD (HHHHHH)
+Size 94: 44,94 BAD (HHHHHH)
+Size 95: 45,95 BAD (HHHHHH)
+Size 96: 45,96 BAD (HHHHHH)
+Size 97: 46,97 BAD (HHHHHH)
+Size 98: 46,98 BAD (HHHHHH)
+Size 99: 46,99 BAD (HHHHHH)
+Size 100: 47,100 BAD (HHHHHH)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 1,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 2,5 BAD (HHHHHH)
+Size 6: 3,6 BAD (HHHHHH)
+Size 7: 3,7 BAD (HHHHHH)
+Size 8: 4,8 BAD (HHHHHH)
+Size 9: 4,9 BAD (HHHHHH)
+Size 10: 5,10 BAD (HHHHHH)
+Size 11: 5,11 BAD (HHHHHH)
+Size 12: 6,12 BAD (HHHHHH)
+Size 13: 6,13 BAD (HHHHHH)
+Size 14: 7,14 BAD (HHHHHH)
+Size 15: 7,15 BAD (HHHHHH)
+Size 16: 8,16 BAD (HHHHHH)
+Size 17: 8,17 BAD (HHHHHH)
+Size 18: 8,18 BAD (HHHHHH)
+Size 19: 9,19 BAD (HHHHHH)
+Size 20: 9,20 BAD (HHHHHH)
+Size 21: 10,21 BAD (HHHHHH)
+Size 22: 10,22 BAD (HHHHHH)
+Size 23: 11,23 BAD (HHHHHH)
+Size 24: 11,24 BAD (HHHHHH)
+Size 25: 12,25 BAD (HHHHHH)
+Size 26: 12,26 BAD (HHHHHH)
+Size 27: 13,27 BAD (HHHHHH)
+Size 28: 13,28 BAD (HHHHHH)
+Size 29: 14,29 BAD (HHHHHH)
+Size 30: 14,30 BAD (HHHHHH)
+Size 31: 15,31 BAD (HHHHHH)
+Size 32: 15,32 BAD (HHHHHH)
+Size 33: 15,33 BAD (HHHHHH)
+Size 34: 16,34 BAD (HHHHHH)
+Size 35: 16,35 BAD (HHHHHH)
+Size 36: 17,36 BAD (HHHHHH)
+Size 37: 17,37 BAD (HHHHHH)
+Size 38: 18,38 BAD (HHHHHH)
+Size 39: 18,39 BAD (HHHHHH)
+Size 40: 19,40 BAD (HHHHHH)
+Size 41: 19,41 BAD (HHHHHH)
+Size 42: 20,42 BAD (HHHHHH)
+Size 43: 20,43 BAD (HHHHHH)
+Size 44: 21,44 BAD (HHHHHH)
+Size 45: 21,45 BAD (HHHHHH)
+Size 46: 22,46 BAD (HHHHHH)
+Size 47: 22,47 BAD (HHHHHH)
+Size 48: 23,48 BAD (HHHHHH)
+Size 49: 23,49 BAD (HHHHHH)
+Size 50: 23,50 BAD (HHHHHH)
+Size 51: 24,51 BAD (HHHHHH)
+Size 52: 24,52 BAD (HHHHHH)
+Size 53: 25,53 BAD (HHHHHH)
+Size 54: 25,54 BAD (HHHHHH)
+Size 55: 26,55 BAD (HHHHHH)
+Size 56: 26,56 BAD (HHHHHH)
+Size 57: 27,57 BAD (HHHHHH)
+Size 58: 27,58 BAD (HHHHHH)
+Size 59: 28,59 BAD (HHHHHH)
+Size 60: 28,60 BAD (HHHHHH)
+Size 61: 29,61 BAD (HHHHHH)
+Size 62: 29,62 BAD (HHHHHH)
+Size 63: 30,63 BAD (HHHHHH)
+Size 64: 30,64 BAD (HHHHHH)
+Size 65: 31,65 BAD (HHHHHH)
+Size 66: 31,66 BAD (HHHHHH)
+Size 67: 31,67 BAD (HHHHHH)
+Size 68: 32,68 BAD (HHHHHH)
+Size 69: 32,69 BAD (HHHHHH)
+Size 70: 33,70 BAD (HHHHHH)
+Size 71: 33,71 BAD (HHHHHH)
+Size 72: 34,72 BAD (HHHHHH)
+Size 73: 34,73 BAD (HHHHHH)
+Size 74: 35,74 BAD (HHHHHH)
+Size 75: 35,75 BAD (HHHHHH)
+Size 76: 36,76 BAD (HHHHHH)
+Size 77: 36,77 BAD (HHHHHH)
+Size 78: 37,78 BAD (HHHHHH)
+Size 79: 37,79 BAD (HHHHHH)
+Size 80: 38,80 BAD (HHHHHH)
+Size 81: 38,81 BAD (HHHHHH)
+Size 82: 39,82 BAD (HHHHHH)
+Size 83: 39,83 BAD (HHHHHH)
+Size 84: 39,84 BAD (HHHHHH)
+Size 85: 40,85 BAD (HHHHHH)
+Size 86: 40,86 BAD (HHHHHH)
+Size 87: 41,87 BAD (HHHHHH)
+Size 88: 41,88 BAD (HHHHHH)
+Size 89: 42,89 BAD (HHHHHH)
+Size 90: 42,90 BAD (HHHHHH)
+Size 91: 43,91 BAD (HHHHHH)
+Size 92: 43,92 BAD (HHHHHH)
+Size 93: 44,93 BAD (HHHHHH)
+Size 94: 44,94 BAD (HHHHHH)
+Size 95: 45,95 BAD (HHHHHH)
+Size 96: 45,96 BAD (HHHHHH)
+Size 97: 46,97 BAD (HHHHHH)
+Size 98: 46,98 BAD (HHHHHH)
+Size 99: 46,99 BAD (HHHHHH)
+Size 100: 47,100 BAD (HHHHHH)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt
new file mode 100644
index 0000000000..0eed93ad98
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt
@@ -0,0 +1,633 @@
+==================================
+Code Page 437, Lucida Console font
+==================================
+
+Options: -face "Lucida Console" -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+FontSurvey "-face \"Lucida Console\" -family 0x36"
+
+Vista
+-----
+
+Size 1: 1,2 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,65 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
+
+
+Windows 7
+---------
+
+Size 1: 1,2 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,65 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
+
+Windows 8
+---------
+
+Size 1: 1,2 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,65 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
+
+Windows 8.1
+-----------
+
+Size 1: 1,2 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,65 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,2 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,65 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 BAD (HHHHHH)
+Size 2: 1,2 BAD (HHHHHH)
+Size 3: 2,3 BAD (HHHHHH)
+Size 4: 2,4 BAD (HHHHHH)
+Size 5: 3,5 BAD (HHHHHH)
+Size 6: 4,6 BAD (HHHHHH)
+Size 7: 4,7 BAD (HHHHHH)
+Size 8: 5,8 BAD (HHHHHH)
+Size 9: 5,9 BAD (HHHHHH)
+Size 10: 6,10 BAD (HHHHHH)
+Size 11: 7,11 BAD (HHHHHH)
+Size 12: 7,12 BAD (HHHHHH)
+Size 13: 8,13 BAD (HHHHHH)
+Size 14: 8,14 BAD (HHHHHH)
+Size 15: 9,15 BAD (HHHHHH)
+Size 16: 10,16 BAD (HHHHHH)
+Size 17: 10,17 BAD (HHHHHH)
+Size 18: 11,18 BAD (HHHHHH)
+Size 19: 11,19 BAD (HHHHHH)
+Size 20: 12,20 BAD (HHHHHH)
+Size 21: 13,21 BAD (HHHHHH)
+Size 22: 13,22 BAD (HHHHHH)
+Size 23: 14,23 BAD (HHHHHH)
+Size 24: 14,24 BAD (HHHHHH)
+Size 25: 15,25 BAD (HHHHHH)
+Size 26: 16,26 BAD (HHHHHH)
+Size 27: 16,27 BAD (HHHHHH)
+Size 28: 17,28 BAD (HHHHHH)
+Size 29: 17,29 BAD (HHHHHH)
+Size 30: 18,30 BAD (HHHHHH)
+Size 31: 19,31 BAD (HHHHHH)
+Size 32: 19,32 BAD (HHHHHH)
+Size 33: 20,33 BAD (HHHHHH)
+Size 34: 20,34 BAD (HHHHHH)
+Size 35: 21,35 BAD (HHHHHH)
+Size 36: 22,36 BAD (HHHHHH)
+Size 37: 22,37 BAD (HHHHHH)
+Size 38: 23,38 BAD (HHHHHH)
+Size 39: 23,39 BAD (HHHHHH)
+Size 40: 24,40 BAD (HHHHHH)
+Size 41: 25,41 BAD (HHHHHH)
+Size 42: 25,42 BAD (HHHHHH)
+Size 43: 26,43 BAD (HHHHHH)
+Size 44: 27,44 BAD (HHHHHH)
+Size 45: 27,45 BAD (HHHHHH)
+Size 46: 28,46 BAD (HHHHHH)
+Size 47: 28,47 BAD (HHHHHH)
+Size 48: 29,48 BAD (HHHHHH)
+Size 49: 30,49 BAD (HHHHHH)
+Size 50: 30,50 BAD (HHHHHH)
+Size 51: 31,51 BAD (HHHHHH)
+Size 52: 31,52 BAD (HHHHHH)
+Size 53: 32,53 BAD (HHHHHH)
+Size 54: 33,54 BAD (HHHHHH)
+Size 55: 33,55 BAD (HHHHHH)
+Size 56: 34,56 BAD (HHHHHH)
+Size 57: 34,57 BAD (HHHHHH)
+Size 58: 35,58 BAD (HHHHHH)
+Size 59: 36,59 BAD (HHHHHH)
+Size 60: 36,60 BAD (HHHHHH)
+Size 61: 37,61 BAD (HHHHHH)
+Size 62: 37,62 BAD (HHHHHH)
+Size 63: 38,63 BAD (HHHHHH)
+Size 64: 39,64 BAD (HHHHHH)
+Size 65: 39,65 BAD (HHHHHH)
+Size 66: 40,66 BAD (HHHHHH)
+Size 67: 40,67 BAD (HHHHHH)
+Size 68: 41,68 BAD (HHHHHH)
+Size 69: 42,69 BAD (HHHHHH)
+Size 70: 42,70 BAD (HHHHHH)
+Size 71: 43,71 BAD (HHHHHH)
+Size 72: 43,72 BAD (HHHHHH)
+Size 73: 44,73 BAD (HHHHHH)
+Size 74: 45,74 BAD (HHHHHH)
+Size 75: 45,75 BAD (HHHHHH)
+Size 76: 46,76 BAD (HHHHHH)
+Size 77: 46,77 BAD (HHHHHH)
+Size 78: 47,78 BAD (HHHHHH)
+Size 79: 48,79 BAD (HHHHHH)
+Size 80: 48,80 BAD (HHHHHH)
+Size 81: 49,81 BAD (HHHHHH)
+Size 82: 49,82 BAD (HHHHHH)
+Size 83: 50,83 BAD (HHHHHH)
+Size 84: 51,84 BAD (HHHHHH)
+Size 85: 51,85 BAD (HHHHHH)
+Size 86: 52,86 BAD (HHHHHH)
+Size 87: 52,87 BAD (HHHHHH)
+Size 88: 53,88 BAD (HHHHHH)
+Size 89: 54,89 BAD (HHHHHH)
+Size 90: 54,90 BAD (HHHHHH)
+Size 91: 55,91 BAD (HHHHHH)
+Size 92: 55,92 BAD (HHHHHH)
+Size 93: 56,93 BAD (HHHHHH)
+Size 94: 57,94 BAD (HHHHHH)
+Size 95: 57,95 BAD (HHHHHH)
+Size 96: 58,96 BAD (HHHHHH)
+Size 97: 58,97 BAD (HHHHHH)
+Size 98: 59,98 BAD (HHHHHH)
+Size 99: 60,99 BAD (HHHHHH)
+Size 100: 60,100 BAD (HHHHHH)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt
new file mode 100644
index 0000000000..ed3637eac1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt
@@ -0,0 +1,630 @@
+=======================================
+Code Page 932, Japanese, MS Gothic font
+=======================================
+
+Options: -face-gothic -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+Vista
+-----
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,4 OK (HHHFFF)
+Size 5: 3,5 OK (HHHFFF)
+Size 6: 3,6 OK (HHHFFF)
+Size 7: 4,7 OK (HHHFFF)
+Size 8: 4,8 OK (HHHFFF)
+Size 9: 5,9 OK (HHHFFF)
+Size 10: 5,10 OK (HHHFFF)
+Size 11: 6,11 OK (HHHFFF)
+Size 12: 6,12 OK (HHHFFF)
+Size 13: 7,13 OK (HHHFFF)
+Size 14: 7,14 BAD (HHHFHH)
+Size 15: 8,15 OK (HHHFFF)
+Size 16: 8,16 BAD (HHHFHH)
+Size 17: 9,17 OK (HHHFFF)
+Size 18: 9,18 BAD (HHHFHH)
+Size 19: 10,19 OK (HHHFFF)
+Size 20: 10,20 BAD (HHHFHH)
+Size 21: 11,21 OK (HHHFFF)
+Size 22: 11,22 BAD (HHHFHH)
+Size 23: 12,23 BAD (HHHFHH)
+Size 24: 12,24 BAD (HHHFHH)
+Size 25: 13,25 BAD (HHHFHH)
+Size 26: 13,26 BAD (HHHFHH)
+Size 27: 14,27 BAD (HHHFHH)
+Size 28: 14,28 BAD (HHHFHH)
+Size 29: 15,29 BAD (HHHFHH)
+Size 30: 15,30 BAD (HHHFHH)
+Size 31: 16,31 BAD (HHHFHH)
+Size 32: 16,33 BAD (HHHFHH)
+Size 33: 17,33 BAD (HHHFHH)
+Size 34: 17,34 BAD (HHHFHH)
+Size 35: 18,35 BAD (HHHFHH)
+Size 36: 18,36 BAD (HHHFHH)
+Size 37: 19,37 BAD (HHHFHH)
+Size 38: 19,38 BAD (HHHFHH)
+Size 39: 20,39 BAD (HHHFHH)
+Size 40: 20,40 BAD (HHHFHH)
+Size 41: 21,41 BAD (HHHFHH)
+Size 42: 21,42 BAD (HHHFHH)
+Size 43: 22,43 BAD (HHHFHH)
+Size 44: 22,44 BAD (HHHFHH)
+Size 45: 23,45 BAD (HHHFHH)
+Size 46: 23,46 BAD (HHHFHH)
+Size 47: 24,47 BAD (HHHFHH)
+Size 48: 24,48 BAD (HHHFHH)
+Size 49: 25,49 BAD (HHHFHH)
+Size 50: 25,50 BAD (HHHFHH)
+Size 51: 26,51 BAD (HHHFHH)
+Size 52: 26,52 BAD (HHHFHH)
+Size 53: 27,53 BAD (HHHFHH)
+Size 54: 27,54 BAD (HHHFHH)
+Size 55: 28,55 BAD (HHHFHH)
+Size 56: 28,56 BAD (HHHFHH)
+Size 57: 29,57 BAD (HHHFHH)
+Size 58: 29,58 BAD (HHHFHH)
+Size 59: 30,59 BAD (HHHFHH)
+Size 60: 30,60 BAD (HHHFHH)
+Size 61: 31,61 BAD (HHHFHH)
+Size 62: 31,62 BAD (HHHFHH)
+Size 63: 32,63 BAD (HHHFHH)
+Size 64: 32,64 BAD (HHHFHH)
+Size 65: 33,65 BAD (HHHFHH)
+Size 66: 33,66 BAD (HHHFHH)
+Size 67: 34,67 BAD (HHHFHH)
+Size 68: 34,68 BAD (HHHFHH)
+Size 69: 35,69 BAD (HHHFHH)
+Size 70: 35,70 BAD (HHHFHH)
+Size 71: 36,71 BAD (HHHFHH)
+Size 72: 36,72 BAD (HHHFHH)
+Size 73: 37,73 BAD (HHHFHH)
+Size 74: 37,74 BAD (HHHFHH)
+Size 75: 38,75 BAD (HHHFHH)
+Size 76: 38,76 BAD (HHHFHH)
+Size 77: 39,77 BAD (HHHFHH)
+Size 78: 39,78 BAD (HHHFHH)
+Size 79: 40,79 BAD (HHHFHH)
+Size 80: 40,80 BAD (HHHFHH)
+Size 81: 41,81 BAD (HHHFHH)
+Size 82: 41,82 BAD (HHHFHH)
+Size 83: 42,83 BAD (HHHFHH)
+Size 84: 42,84 BAD (HHHFHH)
+Size 85: 43,85 BAD (HHHFHH)
+Size 86: 43,86 BAD (HHHFHH)
+Size 87: 44,87 BAD (HHHFHH)
+Size 88: 44,88 BAD (HHHFHH)
+Size 89: 45,89 BAD (HHHFHH)
+Size 90: 45,90 BAD (HHHFHH)
+Size 91: 46,91 BAD (HHHFHH)
+Size 92: 46,92 BAD (HHHFHH)
+Size 93: 47,93 BAD (HHHFHH)
+Size 94: 47,94 BAD (HHHFHH)
+Size 95: 48,95 BAD (HHHFHH)
+Size 96: 48,97 BAD (HHHFHH)
+Size 97: 49,97 BAD (HHHFHH)
+Size 98: 49,98 BAD (HHHFHH)
+Size 99: 50,99 BAD (HHHFHH)
+Size 100: 50,100 BAD (HHHFHH)
+
+Windows 7
+---------
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,4 OK (HHHFFF)
+Size 5: 3,5 OK (HHHFFF)
+Size 6: 3,6 OK (HHHFFF)
+Size 7: 4,7 OK (HHHFFF)
+Size 8: 4,8 OK (HHHFFF)
+Size 9: 5,9 OK (HHHFFF)
+Size 10: 5,10 OK (HHHFFF)
+Size 11: 6,11 OK (HHHFFF)
+Size 12: 6,12 OK (HHHFFF)
+Size 13: 7,13 OK (HHHFFF)
+Size 14: 7,14 BAD (FFFFFF)
+Size 15: 8,15 OK (HHHFFF)
+Size 16: 8,16 BAD (FFFFFF)
+Size 17: 9,17 OK (HHHFFF)
+Size 18: 9,18 BAD (FFFFFF)
+Size 19: 10,19 OK (HHHFFF)
+Size 20: 10,20 BAD (FFFFFF)
+Size 21: 11,21 OK (HHHFFF)
+Size 22: 11,22 BAD (FFFFFF)
+Size 23: 12,23 BAD (FFFFFF)
+Size 24: 12,24 BAD (FFFFFF)
+Size 25: 13,25 BAD (FFFFFF)
+Size 26: 13,26 BAD (FFFFFF)
+Size 27: 14,27 BAD (FFFFFF)
+Size 28: 14,28 BAD (FFFFFF)
+Size 29: 15,29 BAD (FFFFFF)
+Size 30: 15,30 BAD (FFFFFF)
+Size 31: 16,31 BAD (FFFFFF)
+Size 32: 16,33 BAD (FFFFFF)
+Size 33: 17,33 BAD (FFFFFF)
+Size 34: 17,34 BAD (FFFFFF)
+Size 35: 18,35 BAD (FFFFFF)
+Size 36: 18,36 BAD (FFFFFF)
+Size 37: 19,37 BAD (FFFFFF)
+Size 38: 19,38 BAD (FFFFFF)
+Size 39: 20,39 BAD (FFFFFF)
+Size 40: 20,40 BAD (FFFFFF)
+Size 41: 21,41 BAD (FFFFFF)
+Size 42: 21,42 BAD (FFFFFF)
+Size 43: 22,43 BAD (FFFFFF)
+Size 44: 22,44 BAD (FFFFFF)
+Size 45: 23,45 BAD (FFFFFF)
+Size 46: 23,46 BAD (FFFFFF)
+Size 47: 24,47 BAD (FFFFFF)
+Size 48: 24,48 BAD (FFFFFF)
+Size 49: 25,49 BAD (FFFFFF)
+Size 50: 25,50 BAD (FFFFFF)
+Size 51: 26,51 BAD (FFFFFF)
+Size 52: 26,52 BAD (FFFFFF)
+Size 53: 27,53 BAD (FFFFFF)
+Size 54: 27,54 BAD (FFFFFF)
+Size 55: 28,55 BAD (FFFFFF)
+Size 56: 28,56 BAD (FFFFFF)
+Size 57: 29,57 BAD (FFFFFF)
+Size 58: 29,58 BAD (FFFFFF)
+Size 59: 30,59 BAD (FFFFFF)
+Size 60: 30,60 BAD (FFFFFF)
+Size 61: 31,61 BAD (FFFFFF)
+Size 62: 31,62 BAD (FFFFFF)
+Size 63: 32,63 BAD (FFFFFF)
+Size 64: 32,64 BAD (FFFFFF)
+Size 65: 33,65 BAD (FFFFFF)
+Size 66: 33,66 BAD (FFFFFF)
+Size 67: 34,67 BAD (FFFFFF)
+Size 68: 34,68 BAD (FFFFFF)
+Size 69: 35,69 BAD (FFFFFF)
+Size 70: 35,70 BAD (FFFFFF)
+Size 71: 36,71 BAD (FFFFFF)
+Size 72: 36,72 BAD (FFFFFF)
+Size 73: 37,73 BAD (FFFFFF)
+Size 74: 37,74 BAD (FFFFFF)
+Size 75: 38,75 BAD (FFFFFF)
+Size 76: 38,76 BAD (FFFFFF)
+Size 77: 39,77 BAD (FFFFFF)
+Size 78: 39,78 BAD (FFFFFF)
+Size 79: 40,79 BAD (FFFFFF)
+Size 80: 40,80 BAD (FFFFFF)
+Size 81: 41,81 BAD (FFFFFF)
+Size 82: 41,82 BAD (FFFFFF)
+Size 83: 42,83 BAD (FFFFFF)
+Size 84: 42,84 BAD (FFFFFF)
+Size 85: 43,85 BAD (FFFFFF)
+Size 86: 43,86 BAD (FFFFFF)
+Size 87: 44,87 BAD (FFFFFF)
+Size 88: 44,88 BAD (FFFFFF)
+Size 89: 45,89 BAD (FFFFFF)
+Size 90: 45,90 BAD (FFFFFF)
+Size 91: 46,91 BAD (FFFFFF)
+Size 92: 46,92 BAD (FFFFFF)
+Size 93: 47,93 BAD (FFFFFF)
+Size 94: 47,94 BAD (FFFFFF)
+Size 95: 48,95 BAD (FFFFFF)
+Size 96: 48,97 BAD (FFFFFF)
+Size 97: 49,97 BAD (FFFFFF)
+Size 98: 49,98 BAD (FFFFFF)
+Size 99: 50,99 BAD (FFFFFF)
+Size 100: 50,100 BAD (FFFFFF)
+
+Windows 8
+---------
+
+Size 1: 1,2 BAD (FFFFHH)
+Size 2: 1,2 BAD (FFFFHH)
+Size 3: 2,3 BAD (FFFFFF)
+Size 4: 2,4 BAD (FFFFHH)
+Size 5: 3,5 BAD (FFFFFF)
+Size 6: 3,6 BAD (FFFFHH)
+Size 7: 4,7 BAD (FFFFFF)
+Size 8: 4,8 BAD (FFFFHH)
+Size 9: 5,9 BAD (FFFFFF)
+Size 10: 5,10 BAD (FFFFHH)
+Size 11: 6,11 BAD (FFFFFF)
+Size 12: 6,12 BAD (FFFFHH)
+Size 13: 7,13 BAD (FFFFFF)
+Size 14: 7,14 BAD (FFFFHH)
+Size 15: 8,15 BAD (FFFFFF)
+Size 16: 8,16 BAD (FFFFHH)
+Size 17: 9,17 BAD (FFFFFF)
+Size 18: 9,18 BAD (FFFFHH)
+Size 19: 10,19 BAD (FFFFFF)
+Size 20: 10,20 BAD (FFFFFF)
+Size 21: 11,21 BAD (FFFFFF)
+Size 22: 11,22 BAD (FFFFFF)
+Size 23: 12,23 BAD (FFFFFF)
+Size 24: 12,24 BAD (FFFFFF)
+Size 25: 13,25 BAD (FFFFFF)
+Size 26: 13,26 BAD (FFFFFF)
+Size 27: 14,27 BAD (FFFFFF)
+Size 28: 14,28 BAD (FFFFFF)
+Size 29: 15,29 BAD (FFFFFF)
+Size 30: 15,30 BAD (FFFFFF)
+Size 31: 16,31 BAD (FFFFFF)
+Size 32: 16,33 BAD (FFFFFF)
+Size 33: 17,33 BAD (FFFFFF)
+Size 34: 17,34 BAD (FFFFFF)
+Size 35: 18,35 BAD (FFFFFF)
+Size 36: 18,36 BAD (FFFFFF)
+Size 37: 19,37 BAD (FFFFFF)
+Size 38: 19,38 BAD (FFFFFF)
+Size 39: 20,39 BAD (FFFFFF)
+Size 40: 20,40 BAD (FFFFFF)
+Size 41: 21,41 BAD (FFFFFF)
+Size 42: 21,42 BAD (FFFFFF)
+Size 43: 22,43 BAD (FFFFFF)
+Size 44: 22,44 BAD (FFFFFF)
+Size 45: 23,45 BAD (FFFFFF)
+Size 46: 23,46 BAD (FFFFFF)
+Size 47: 24,47 BAD (FFFFFF)
+Size 48: 24,48 BAD (FFFFFF)
+Size 49: 25,49 BAD (FFFFFF)
+Size 50: 25,50 BAD (FFFFFF)
+Size 51: 26,51 BAD (FFFFFF)
+Size 52: 26,52 BAD (FFFFFF)
+Size 53: 27,53 BAD (FFFFFF)
+Size 54: 27,54 BAD (FFFFFF)
+Size 55: 28,55 BAD (FFFFFF)
+Size 56: 28,56 BAD (FFFFFF)
+Size 57: 29,57 BAD (FFFFFF)
+Size 58: 29,58 BAD (FFFFFF)
+Size 59: 30,59 BAD (FFFFFF)
+Size 60: 30,60 BAD (FFFFFF)
+Size 61: 31,61 BAD (FFFFFF)
+Size 62: 31,62 BAD (FFFFFF)
+Size 63: 32,63 BAD (FFFFFF)
+Size 64: 32,64 BAD (FFFFFF)
+Size 65: 33,65 BAD (FFFFFF)
+Size 66: 33,66 BAD (FFFFFF)
+Size 67: 34,67 BAD (FFFFFF)
+Size 68: 34,68 BAD (FFFFFF)
+Size 69: 35,69 BAD (FFFFFF)
+Size 70: 35,70 BAD (FFFFFF)
+Size 71: 36,71 BAD (FFFFFF)
+Size 72: 36,72 BAD (FFFFFF)
+Size 73: 37,73 BAD (FFFFFF)
+Size 74: 37,74 BAD (FFFFFF)
+Size 75: 38,75 BAD (FFFFFF)
+Size 76: 38,76 BAD (FFFFFF)
+Size 77: 39,77 BAD (FFFFFF)
+Size 78: 39,78 BAD (FFFFFF)
+Size 79: 40,79 BAD (FFFFFF)
+Size 80: 40,80 BAD (FFFFFF)
+Size 81: 41,81 BAD (FFFFFF)
+Size 82: 41,82 BAD (FFFFFF)
+Size 83: 42,83 BAD (FFFFFF)
+Size 84: 42,84 BAD (FFFFFF)
+Size 85: 43,85 BAD (FFFFFF)
+Size 86: 43,86 BAD (FFFFFF)
+Size 87: 44,87 BAD (FFFFFF)
+Size 88: 44,88 BAD (FFFFFF)
+Size 89: 45,89 BAD (FFFFFF)
+Size 90: 45,90 BAD (FFFFFF)
+Size 91: 46,91 BAD (FFFFFF)
+Size 92: 46,92 BAD (FFFFFF)
+Size 93: 47,93 BAD (FFFFFF)
+Size 94: 47,94 BAD (FFFFFF)
+Size 95: 48,95 BAD (FFFFFF)
+Size 96: 48,97 BAD (FFFFFF)
+Size 97: 49,97 BAD (FFFFFF)
+Size 98: 49,98 BAD (FFFFFF)
+Size 99: 50,99 BAD (FFFFFF)
+Size 100: 50,100 BAD (FFFFFF)
+
+Windows 8.1
+-----------
+
+Size 1: 1,2 BAD (FFFFHH)
+Size 2: 1,2 BAD (FFFFHH)
+Size 3: 2,3 BAD (FFFFFF)
+Size 4: 2,4 BAD (FFFFHH)
+Size 5: 3,5 BAD (FFFFFF)
+Size 6: 3,6 BAD (FFFFHH)
+Size 7: 4,7 BAD (FFFFFF)
+Size 8: 4,8 BAD (FFFFHH)
+Size 9: 5,9 BAD (FFFFFF)
+Size 10: 5,10 BAD (FFFFHH)
+Size 11: 6,11 BAD (FFFFFF)
+Size 12: 6,12 BAD (FFFFHH)
+Size 13: 7,13 BAD (FFFFFF)
+Size 14: 7,14 BAD (FFFFHH)
+Size 15: 8,15 BAD (FFFFFF)
+Size 16: 8,16 BAD (FFFFHH)
+Size 17: 9,17 BAD (FFFFFF)
+Size 18: 9,18 BAD (FFFFHH)
+Size 19: 10,19 BAD (FFFFFF)
+Size 20: 10,20 BAD (FFFFFF)
+Size 21: 11,21 BAD (FFFFFF)
+Size 22: 11,22 BAD (FFFFFF)
+Size 23: 12,23 BAD (FFFFFF)
+Size 24: 12,24 BAD (FFFFFF)
+Size 25: 13,25 BAD (FFFFFF)
+Size 26: 13,26 BAD (FFFFFF)
+Size 27: 14,27 BAD (FFFFFF)
+Size 28: 14,28 BAD (FFFFFF)
+Size 29: 15,29 BAD (FFFFFF)
+Size 30: 15,30 BAD (FFFFFF)
+Size 31: 16,31 BAD (FFFFFF)
+Size 32: 16,33 BAD (FFFFFF)
+Size 33: 17,33 BAD (FFFFFF)
+Size 34: 17,34 BAD (FFFFFF)
+Size 35: 18,35 BAD (FFFFFF)
+Size 36: 18,36 BAD (FFFFFF)
+Size 37: 19,37 BAD (FFFFFF)
+Size 38: 19,38 BAD (FFFFFF)
+Size 39: 20,39 BAD (FFFFFF)
+Size 40: 20,40 BAD (FFFFFF)
+Size 41: 21,41 BAD (FFFFFF)
+Size 42: 21,42 BAD (FFFFFF)
+Size 43: 22,43 BAD (FFFFFF)
+Size 44: 22,44 BAD (FFFFFF)
+Size 45: 23,45 BAD (FFFFFF)
+Size 46: 23,46 BAD (FFFFFF)
+Size 47: 24,47 BAD (FFFFFF)
+Size 48: 24,48 BAD (FFFFFF)
+Size 49: 25,49 BAD (FFFFFF)
+Size 50: 25,50 BAD (FFFFFF)
+Size 51: 26,51 BAD (FFFFFF)
+Size 52: 26,52 BAD (FFFFFF)
+Size 53: 27,53 BAD (FFFFFF)
+Size 54: 27,54 BAD (FFFFFF)
+Size 55: 28,55 BAD (FFFFFF)
+Size 56: 28,56 BAD (FFFFFF)
+Size 57: 29,57 BAD (FFFFFF)
+Size 58: 29,58 BAD (FFFFFF)
+Size 59: 30,59 BAD (FFFFFF)
+Size 60: 30,60 BAD (FFFFFF)
+Size 61: 31,61 BAD (FFFFFF)
+Size 62: 31,62 BAD (FFFFFF)
+Size 63: 32,63 BAD (FFFFFF)
+Size 64: 32,64 BAD (FFFFFF)
+Size 65: 33,65 BAD (FFFFFF)
+Size 66: 33,66 BAD (FFFFFF)
+Size 67: 34,67 BAD (FFFFFF)
+Size 68: 34,68 BAD (FFFFFF)
+Size 69: 35,69 BAD (FFFFFF)
+Size 70: 35,70 BAD (FFFFFF)
+Size 71: 36,71 BAD (FFFFFF)
+Size 72: 36,72 BAD (FFFFFF)
+Size 73: 37,73 BAD (FFFFFF)
+Size 74: 37,74 BAD (FFFFFF)
+Size 75: 38,75 BAD (FFFFFF)
+Size 76: 38,76 BAD (FFFFFF)
+Size 77: 39,77 BAD (FFFFFF)
+Size 78: 39,78 BAD (FFFFFF)
+Size 79: 40,79 BAD (FFFFFF)
+Size 80: 40,80 BAD (FFFFFF)
+Size 81: 41,81 BAD (FFFFFF)
+Size 82: 41,82 BAD (FFFFFF)
+Size 83: 42,83 BAD (FFFFFF)
+Size 84: 42,84 BAD (FFFFFF)
+Size 85: 43,85 BAD (FFFFFF)
+Size 86: 43,86 BAD (FFFFFF)
+Size 87: 44,87 BAD (FFFFFF)
+Size 88: 44,88 BAD (FFFFFF)
+Size 89: 45,89 BAD (FFFFFF)
+Size 90: 45,90 BAD (FFFFFF)
+Size 91: 46,91 BAD (FFFFFF)
+Size 92: 46,92 BAD (FFFFFF)
+Size 93: 47,93 BAD (FFFFFF)
+Size 94: 47,94 BAD (FFFFFF)
+Size 95: 48,95 BAD (FFFFFF)
+Size 96: 48,97 BAD (FFFFFF)
+Size 97: 49,97 BAD (FFFFFF)
+Size 98: 49,98 BAD (FFFFFF)
+Size 99: 50,99 BAD (FFFFFF)
+Size 100: 50,100 BAD (FFFFFF)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,2 BAD (FFFFHH)
+Size 2: 1,2 BAD (FFFFHH)
+Size 3: 2,3 BAD (FFFFFF)
+Size 4: 2,4 BAD (FFFFHH)
+Size 5: 3,5 BAD (FFFFFF)
+Size 6: 3,6 BAD (FFFFHH)
+Size 7: 4,7 BAD (FFFFFF)
+Size 8: 4,8 BAD (FFFFHH)
+Size 9: 5,9 BAD (FFFFFF)
+Size 10: 5,10 BAD (FFFFHH)
+Size 11: 6,11 BAD (FFFFFF)
+Size 12: 6,12 BAD (FFFFHH)
+Size 13: 7,13 BAD (FFFFFF)
+Size 14: 7,14 BAD (FFFFHH)
+Size 15: 8,15 BAD (FFFFFF)
+Size 16: 8,16 BAD (FFFFHH)
+Size 17: 9,17 BAD (FFFFFF)
+Size 18: 9,18 BAD (FFFFHH)
+Size 19: 10,19 BAD (FFFFFF)
+Size 20: 10,20 BAD (FFFFFF)
+Size 21: 11,21 BAD (FFFFFF)
+Size 22: 11,22 BAD (FFFFFF)
+Size 23: 12,23 BAD (FFFFFF)
+Size 24: 12,24 BAD (FFFFFF)
+Size 25: 13,25 BAD (FFFFFF)
+Size 26: 13,26 BAD (FFFFFF)
+Size 27: 14,27 BAD (FFFFFF)
+Size 28: 14,28 BAD (FFFFFF)
+Size 29: 15,29 BAD (FFFFFF)
+Size 30: 15,30 BAD (FFFFFF)
+Size 31: 16,31 BAD (FFFFFF)
+Size 32: 16,33 BAD (FFFFFF)
+Size 33: 17,33 BAD (FFFFFF)
+Size 34: 17,34 BAD (FFFFFF)
+Size 35: 18,35 BAD (FFFFFF)
+Size 36: 18,36 BAD (FFFFFF)
+Size 37: 19,37 BAD (FFFFFF)
+Size 38: 19,38 BAD (FFFFFF)
+Size 39: 20,39 BAD (FFFFFF)
+Size 40: 20,40 BAD (FFFFFF)
+Size 41: 21,41 BAD (FFFFFF)
+Size 42: 21,42 BAD (FFFFFF)
+Size 43: 22,43 BAD (FFFFFF)
+Size 44: 22,44 BAD (FFFFFF)
+Size 45: 23,45 BAD (FFFFFF)
+Size 46: 23,46 BAD (FFFFFF)
+Size 47: 24,47 BAD (FFFFFF)
+Size 48: 24,48 BAD (FFFFFF)
+Size 49: 25,49 BAD (FFFFFF)
+Size 50: 25,50 BAD (FFFFFF)
+Size 51: 26,51 BAD (FFFFFF)
+Size 52: 26,52 BAD (FFFFFF)
+Size 53: 27,53 BAD (FFFFFF)
+Size 54: 27,54 BAD (FFFFFF)
+Size 55: 28,55 BAD (FFFFFF)
+Size 56: 28,56 BAD (FFFFFF)
+Size 57: 29,57 BAD (FFFFFF)
+Size 58: 29,58 BAD (FFFFFF)
+Size 59: 30,59 BAD (FFFFFF)
+Size 60: 30,60 BAD (FFFFFF)
+Size 61: 31,61 BAD (FFFFFF)
+Size 62: 31,62 BAD (FFFFFF)
+Size 63: 32,63 BAD (FFFFFF)
+Size 64: 32,64 BAD (FFFFFF)
+Size 65: 33,65 BAD (FFFFFF)
+Size 66: 33,66 BAD (FFFFFF)
+Size 67: 34,67 BAD (FFFFFF)
+Size 68: 34,68 BAD (FFFFFF)
+Size 69: 35,69 BAD (FFFFFF)
+Size 70: 35,70 BAD (FFFFFF)
+Size 71: 36,71 BAD (FFFFFF)
+Size 72: 36,72 BAD (FFFFFF)
+Size 73: 37,73 BAD (FFFFFF)
+Size 74: 37,74 BAD (FFFFFF)
+Size 75: 38,75 BAD (FFFFFF)
+Size 76: 38,76 BAD (FFFFFF)
+Size 77: 39,77 BAD (FFFFFF)
+Size 78: 39,78 BAD (FFFFFF)
+Size 79: 40,79 BAD (FFFFFF)
+Size 80: 40,80 BAD (FFFFFF)
+Size 81: 41,81 BAD (FFFFFF)
+Size 82: 41,82 BAD (FFFFFF)
+Size 83: 42,83 BAD (FFFFFF)
+Size 84: 42,84 BAD (FFFFFF)
+Size 85: 43,85 BAD (FFFFFF)
+Size 86: 43,86 BAD (FFFFFF)
+Size 87: 44,87 BAD (FFFFFF)
+Size 88: 44,88 BAD (FFFFFF)
+Size 89: 45,89 BAD (FFFFFF)
+Size 90: 45,90 BAD (FFFFFF)
+Size 91: 46,91 BAD (FFFFFF)
+Size 92: 46,92 BAD (FFFFFF)
+Size 93: 47,93 BAD (FFFFFF)
+Size 94: 47,94 BAD (FFFFFF)
+Size 95: 48,95 BAD (FFFFFF)
+Size 96: 48,97 BAD (FFFFFF)
+Size 97: 49,97 BAD (FFFFFF)
+Size 98: 49,98 BAD (FFFFFF)
+Size 99: 50,99 BAD (FFFFFF)
+Size 100: 50,100 BAD (FFFFFF)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 OK (HHHFFF)
+Size 4: 2,4 OK (HHHFFF)
+Size 5: 3,5 OK (HHHFFF)
+Size 6: 3,6 OK (HHHFFF)
+Size 7: 4,7 OK (HHHFFF)
+Size 8: 4,8 OK (HHHFFF)
+Size 9: 5,9 OK (HHHFFF)
+Size 10: 5,10 OK (HHHFFF)
+Size 11: 6,11 OK (HHHFFF)
+Size 12: 6,12 OK (HHHFFF)
+Size 13: 7,13 OK (HHHFFF)
+Size 14: 7,14 OK (HHHFFF)
+Size 15: 8,15 OK (HHHFFF)
+Size 16: 8,16 OK (HHHFFF)
+Size 17: 9,17 OK (HHHFFF)
+Size 18: 9,18 OK (HHHFFF)
+Size 19: 10,19 OK (HHHFFF)
+Size 20: 10,20 OK (HHHFFF)
+Size 21: 11,21 OK (HHHFFF)
+Size 22: 11,22 OK (HHHFFF)
+Size 23: 12,23 OK (HHHFFF)
+Size 24: 12,24 OK (HHHFFF)
+Size 25: 13,25 OK (HHHFFF)
+Size 26: 13,26 OK (HHHFFF)
+Size 27: 14,27 OK (HHHFFF)
+Size 28: 14,28 OK (HHHFFF)
+Size 29: 15,29 OK (HHHFFF)
+Size 30: 15,30 OK (HHHFFF)
+Size 31: 16,31 OK (HHHFFF)
+Size 32: 16,32 OK (HHHFFF)
+Size 33: 17,33 OK (HHHFFF)
+Size 34: 17,34 OK (HHHFFF)
+Size 35: 18,35 OK (HHHFFF)
+Size 36: 18,36 OK (HHHFFF)
+Size 37: 19,37 OK (HHHFFF)
+Size 38: 19,38 OK (HHHFFF)
+Size 39: 20,39 OK (HHHFFF)
+Size 40: 20,40 OK (HHHFFF)
+Size 41: 21,41 OK (HHHFFF)
+Size 42: 21,42 OK (HHHFFF)
+Size 43: 22,43 OK (HHHFFF)
+Size 44: 22,44 OK (HHHFFF)
+Size 45: 23,45 OK (HHHFFF)
+Size 46: 23,46 OK (HHHFFF)
+Size 47: 24,47 OK (HHHFFF)
+Size 48: 24,48 OK (HHHFFF)
+Size 49: 25,49 OK (HHHFFF)
+Size 50: 25,50 OK (HHHFFF)
+Size 51: 26,51 OK (HHHFFF)
+Size 52: 26,52 OK (HHHFFF)
+Size 53: 27,53 OK (HHHFFF)
+Size 54: 27,54 OK (HHHFFF)
+Size 55: 28,55 OK (HHHFFF)
+Size 56: 28,56 OK (HHHFFF)
+Size 57: 29,57 OK (HHHFFF)
+Size 58: 29,58 OK (HHHFFF)
+Size 59: 30,59 OK (HHHFFF)
+Size 60: 30,60 OK (HHHFFF)
+Size 61: 31,61 OK (HHHFFF)
+Size 62: 31,62 OK (HHHFFF)
+Size 63: 32,63 OK (HHHFFF)
+Size 64: 32,64 OK (HHHFFF)
+Size 65: 33,65 OK (HHHFFF)
+Size 66: 33,66 OK (HHHFFF)
+Size 67: 34,67 OK (HHHFFF)
+Size 68: 34,68 OK (HHHFFF)
+Size 69: 35,69 OK (HHHFFF)
+Size 70: 35,70 OK (HHHFFF)
+Size 71: 36,71 OK (HHHFFF)
+Size 72: 36,72 OK (HHHFFF)
+Size 73: 37,73 OK (HHHFFF)
+Size 74: 37,74 OK (HHHFFF)
+Size 75: 38,75 OK (HHHFFF)
+Size 76: 38,76 OK (HHHFFF)
+Size 77: 39,77 OK (HHHFFF)
+Size 78: 39,78 OK (HHHFFF)
+Size 79: 40,79 OK (HHHFFF)
+Size 80: 40,80 OK (HHHFFF)
+Size 81: 41,81 OK (HHHFFF)
+Size 82: 41,82 OK (HHHFFF)
+Size 83: 42,83 OK (HHHFFF)
+Size 84: 42,84 OK (HHHFFF)
+Size 85: 43,85 OK (HHHFFF)
+Size 86: 43,86 OK (HHHFFF)
+Size 87: 44,87 OK (HHHFFF)
+Size 88: 44,88 OK (HHHFFF)
+Size 89: 45,89 OK (HHHFFF)
+Size 90: 45,90 OK (HHHFFF)
+Size 91: 46,91 OK (HHHFFF)
+Size 92: 46,92 OK (HHHFFF)
+Size 93: 47,93 OK (HHHFFF)
+Size 94: 47,94 OK (HHHFFF)
+Size 95: 48,95 OK (HHHFFF)
+Size 96: 48,96 OK (HHHFFF)
+Size 97: 49,97 OK (HHHFFF)
+Size 98: 49,98 OK (HHHFFF)
+Size 99: 50,99 OK (HHHFFF)
+Size 100: 50,100 OK (HHHFFF)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt
new file mode 100644
index 0000000000..43210dac51
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt
@@ -0,0 +1,630 @@
+==========================================================
+Code Page 936, Chinese Simplified (China/PRC), SimSun font
+==========================================================
+
+Options: -face-simsun -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+Vista
+-----
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (HHHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (HHHFHH)
+Size 8: 4,9 GOOD (HHFFFF)
+Size 9: 5,10 BAD (HHHFHH)
+Size 10: 5,11 GOOD (HHFFFF)
+Size 11: 6,13 BAD (HHHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,15 BAD (HHHFHH)
+Size 14: 7,16 GOOD (HHFFFF)
+Size 15: 8,17 BAD (HHHFHH)
+Size 16: 8,18 GOOD (HHFFFF)
+Size 17: 9,19 BAD (HHHFHH)
+Size 18: 9,21 GOOD (HHFFFF)
+Size 19: 10,22 BAD (HHHFHH)
+Size 20: 10,23 GOOD (HHFFFF)
+Size 21: 11,24 BAD (HHHFHH)
+Size 22: 11,25 GOOD (HHFFFF)
+Size 23: 12,26 BAD (HHHFHH)
+Size 24: 12,27 GOOD (HHFFFF)
+Size 25: 13,29 BAD (HHHFHH)
+Size 26: 13,30 GOOD (HHFFFF)
+Size 27: 14,31 BAD (HHHFHH)
+Size 28: 14,32 GOOD (HHFFFF)
+Size 29: 15,33 BAD (HHHFHH)
+Size 30: 15,34 GOOD (HHFFFF)
+Size 31: 16,35 BAD (HHHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,38 BAD (HHHFHH)
+Size 34: 17,39 GOOD (HHFFFF)
+Size 35: 18,40 BAD (HHHFHH)
+Size 36: 18,41 GOOD (HHFFFF)
+Size 37: 19,42 BAD (HHHFHH)
+Size 38: 19,43 GOOD (HHFFFF)
+Size 39: 20,44 BAD (HHHFHH)
+Size 40: 20,46 GOOD (HHFFFF)
+Size 41: 21,47 BAD (HHHFHH)
+Size 42: 21,48 GOOD (HHFFFF)
+Size 43: 22,49 BAD (HHHFHH)
+Size 44: 22,50 GOOD (HHFFFF)
+Size 45: 23,51 BAD (HHHFHH)
+Size 46: 23,52 GOOD (HHFFFF)
+Size 47: 24,54 BAD (HHHFHH)
+Size 48: 24,55 GOOD (HHFFFF)
+Size 49: 25,56 BAD (HHHFHH)
+Size 50: 25,57 GOOD (HHFFFF)
+Size 51: 26,58 BAD (HHHFHH)
+Size 52: 26,59 GOOD (HHFFFF)
+Size 53: 27,60 BAD (HHHFHH)
+Size 54: 27,62 GOOD (HHFFFF)
+Size 55: 28,63 BAD (HHHFHH)
+Size 56: 28,64 GOOD (HHFFFF)
+Size 57: 29,65 BAD (HHHFHH)
+Size 58: 29,66 GOOD (HHFFFF)
+Size 59: 30,67 BAD (HHHFHH)
+Size 60: 30,68 GOOD (HHFFFF)
+Size 61: 31,70 BAD (HHHFHH)
+Size 62: 31,71 GOOD (HHFFFF)
+Size 63: 32,72 BAD (HHHFHH)
+Size 64: 32,73 GOOD (HHFFFF)
+Size 65: 33,74 GOOD (HHFFFF)
+Size 66: 33,75 GOOD (HHFFFF)
+Size 67: 34,76 GOOD (HHFFFF)
+Size 68: 34,78 GOOD (HHFFFF)
+Size 69: 35,79 GOOD (HHFFFF)
+Size 70: 35,80 GOOD (HHFFFF)
+Size 71: 36,81 GOOD (HHFFFF)
+Size 72: 36,82 GOOD (HHFFFF)
+Size 73: 37,83 GOOD (HHFFFF)
+Size 74: 37,84 GOOD (HHFFFF)
+Size 75: 38,86 GOOD (HHFFFF)
+Size 76: 38,87 GOOD (HHFFFF)
+Size 77: 39,88 GOOD (HHFFFF)
+Size 78: 39,89 GOOD (HHFFFF)
+Size 79: 40,90 GOOD (HHFFFF)
+Size 80: 40,91 GOOD (HHFFFF)
+Size 81: 41,92 GOOD (HHFFFF)
+Size 82: 41,94 GOOD (HHFFFF)
+Size 83: 42,95 GOOD (HHFFFF)
+Size 84: 42,96 GOOD (HHFFFF)
+Size 85: 43,97 GOOD (HHFFFF)
+Size 86: 43,98 GOOD (HHFFFF)
+Size 87: 44,99 GOOD (HHFFFF)
+Size 88: 44,100 GOOD (HHFFFF)
+Size 89: 45,102 GOOD (HHFFFF)
+Size 90: 45,103 GOOD (HHFFFF)
+Size 91: 46,104 GOOD (HHFFFF)
+Size 92: 46,105 GOOD (HHFFFF)
+Size 93: 47,106 GOOD (HHFFFF)
+Size 94: 47,107 GOOD (HHFFFF)
+Size 95: 48,108 GOOD (HHFFFF)
+Size 96: 48,111 GOOD (HHFFFF)
+Size 97: 49,111 GOOD (HHFFFF)
+Size 98: 49,112 GOOD (HHFFFF)
+Size 99: 50,113 GOOD (HHFFFF)
+Size 100: 50,114 GOOD (HHFFFF)
+
+Windows 7
+---------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,9 GOOD (HHFFFF)
+Size 9: 5,10 BAD (FFHFHH)
+Size 10: 5,11 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,15 BAD (FFHFHH)
+Size 14: 7,16 GOOD (HHFFFF)
+Size 15: 8,17 BAD (FFHFHH)
+Size 16: 8,18 GOOD (HHFFFF)
+Size 17: 9,19 BAD (FFHFHH)
+Size 18: 9,21 GOOD (HHFFFF)
+Size 19: 10,22 BAD (FFHFHH)
+Size 20: 10,23 GOOD (HHFFFF)
+Size 21: 11,24 BAD (FFHFHH)
+Size 22: 11,25 GOOD (HHFFFF)
+Size 23: 12,26 BAD (FFHFHH)
+Size 24: 12,27 GOOD (HHFFFF)
+Size 25: 13,29 BAD (FFHFHH)
+Size 26: 13,30 GOOD (HHFFFF)
+Size 27: 14,31 BAD (FFHFHH)
+Size 28: 14,32 GOOD (HHFFFF)
+Size 29: 15,33 BAD (FFHFHH)
+Size 30: 15,34 GOOD (HHFFFF)
+Size 31: 16,35 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,38 BAD (FFHFHH)
+Size 34: 17,39 GOOD (HHFFFF)
+Size 35: 18,40 BAD (FFHFHH)
+Size 36: 18,41 GOOD (HHFFFF)
+Size 37: 19,42 BAD (FFHFHH)
+Size 38: 19,43 GOOD (HHFFFF)
+Size 39: 20,44 BAD (FFHFHH)
+Size 40: 20,46 GOOD (HHFFFF)
+Size 41: 21,47 BAD (FFHFHH)
+Size 42: 21,48 GOOD (HHFFFF)
+Size 43: 22,49 BAD (FFHFHH)
+Size 44: 22,50 GOOD (HHFFFF)
+Size 45: 23,51 BAD (FFHFHH)
+Size 46: 23,52 GOOD (HHFFFF)
+Size 47: 24,54 BAD (FFHFHH)
+Size 48: 24,55 GOOD (HHFFFF)
+Size 49: 25,56 BAD (FFHFHH)
+Size 50: 25,57 GOOD (HHFFFF)
+Size 51: 26,58 BAD (FFHFHH)
+Size 52: 26,59 GOOD (HHFFFF)
+Size 53: 27,60 BAD (FFHFHH)
+Size 54: 27,62 GOOD (HHFFFF)
+Size 55: 28,63 BAD (FFHFHH)
+Size 56: 28,64 GOOD (HHFFFF)
+Size 57: 29,65 BAD (FFHFHH)
+Size 58: 29,66 GOOD (HHFFFF)
+Size 59: 30,67 BAD (FFHFHH)
+Size 60: 30,68 GOOD (HHFFFF)
+Size 61: 31,70 BAD (FFHFHH)
+Size 62: 31,71 GOOD (HHFFFF)
+Size 63: 32,72 BAD (FFHFHH)
+Size 64: 32,73 GOOD (HHFFFF)
+Size 65: 33,74 GOOD (HHFFFF)
+Size 66: 33,75 GOOD (HHFFFF)
+Size 67: 34,76 GOOD (HHFFFF)
+Size 68: 34,78 GOOD (HHFFFF)
+Size 69: 35,79 GOOD (HHFFFF)
+Size 70: 35,80 GOOD (HHFFFF)
+Size 71: 36,81 GOOD (HHFFFF)
+Size 72: 36,82 GOOD (HHFFFF)
+Size 73: 37,83 GOOD (HHFFFF)
+Size 74: 37,84 GOOD (HHFFFF)
+Size 75: 38,86 GOOD (HHFFFF)
+Size 76: 38,87 GOOD (HHFFFF)
+Size 77: 39,88 GOOD (HHFFFF)
+Size 78: 39,89 GOOD (HHFFFF)
+Size 79: 40,90 GOOD (HHFFFF)
+Size 80: 40,91 GOOD (HHFFFF)
+Size 81: 41,92 GOOD (HHFFFF)
+Size 82: 41,94 GOOD (HHFFFF)
+Size 83: 42,95 GOOD (HHFFFF)
+Size 84: 42,96 GOOD (HHFFFF)
+Size 85: 43,97 GOOD (HHFFFF)
+Size 86: 43,98 GOOD (HHFFFF)
+Size 87: 44,99 GOOD (HHFFFF)
+Size 88: 44,100 GOOD (HHFFFF)
+Size 89: 45,102 GOOD (HHFFFF)
+Size 90: 45,103 GOOD (HHFFFF)
+Size 91: 46,104 GOOD (HHFFFF)
+Size 92: 46,105 GOOD (HHFFFF)
+Size 93: 47,106 GOOD (HHFFFF)
+Size 94: 47,107 GOOD (HHFFFF)
+Size 95: 48,108 GOOD (HHFFFF)
+Size 96: 48,111 GOOD (HHFFFF)
+Size 97: 49,111 GOOD (HHFFFF)
+Size 98: 49,112 GOOD (HHFFFF)
+Size 99: 50,113 GOOD (HHFFFF)
+Size 100: 50,114 GOOD (HHFFFF)
+
+Windows 8
+---------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,9 GOOD (HHFFFF)
+Size 9: 5,10 BAD (FFHFHH)
+Size 10: 5,11 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,15 BAD (FFHFHH)
+Size 14: 7,16 GOOD (HHFFFF)
+Size 15: 8,17 BAD (FFHFHH)
+Size 16: 8,18 GOOD (HHFFFF)
+Size 17: 9,19 BAD (FFHFHH)
+Size 18: 9,21 GOOD (HHFFFF)
+Size 19: 10,22 BAD (FFHFHH)
+Size 20: 10,23 GOOD (HHFFFF)
+Size 21: 11,24 BAD (FFHFHH)
+Size 22: 11,25 GOOD (HHFFFF)
+Size 23: 12,26 BAD (FFHFHH)
+Size 24: 12,27 GOOD (HHFFFF)
+Size 25: 13,29 BAD (FFHFHH)
+Size 26: 13,30 GOOD (HHFFFF)
+Size 27: 14,31 BAD (FFHFHH)
+Size 28: 14,32 GOOD (HHFFFF)
+Size 29: 15,33 BAD (FFHFHH)
+Size 30: 15,34 GOOD (HHFFFF)
+Size 31: 16,35 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,38 BAD (FFHFHH)
+Size 34: 17,39 GOOD (HHFFFF)
+Size 35: 18,40 BAD (FFHFHH)
+Size 36: 18,41 GOOD (HHFFFF)
+Size 37: 19,42 BAD (FFHFHH)
+Size 38: 19,43 GOOD (HHFFFF)
+Size 39: 20,44 BAD (FFHFHH)
+Size 40: 20,46 GOOD (HHFFFF)
+Size 41: 21,47 BAD (FFHFHH)
+Size 42: 21,48 GOOD (HHFFFF)
+Size 43: 22,49 BAD (FFHFHH)
+Size 44: 22,50 GOOD (HHFFFF)
+Size 45: 23,51 BAD (FFHFHH)
+Size 46: 23,52 GOOD (HHFFFF)
+Size 47: 24,54 BAD (FFHFHH)
+Size 48: 24,55 GOOD (HHFFFF)
+Size 49: 25,56 BAD (FFHFHH)
+Size 50: 25,57 GOOD (HHFFFF)
+Size 51: 26,58 BAD (FFHFHH)
+Size 52: 26,59 GOOD (HHFFFF)
+Size 53: 27,60 BAD (FFHFHH)
+Size 54: 27,62 GOOD (HHFFFF)
+Size 55: 28,63 BAD (FFHFHH)
+Size 56: 28,64 GOOD (HHFFFF)
+Size 57: 29,65 BAD (FFHFHH)
+Size 58: 29,66 GOOD (HHFFFF)
+Size 59: 30,67 BAD (FFHFHH)
+Size 60: 30,68 GOOD (HHFFFF)
+Size 61: 31,70 BAD (FFHFHH)
+Size 62: 31,71 GOOD (HHFFFF)
+Size 63: 32,72 BAD (FFHFHH)
+Size 64: 32,73 GOOD (HHFFFF)
+Size 65: 33,74 GOOD (HHFFFF)
+Size 66: 33,75 GOOD (HHFFFF)
+Size 67: 34,76 GOOD (HHFFFF)
+Size 68: 34,78 GOOD (HHFFFF)
+Size 69: 35,79 GOOD (HHFFFF)
+Size 70: 35,80 GOOD (HHFFFF)
+Size 71: 36,81 GOOD (HHFFFF)
+Size 72: 36,82 GOOD (HHFFFF)
+Size 73: 37,83 GOOD (HHFFFF)
+Size 74: 37,84 GOOD (HHFFFF)
+Size 75: 38,86 GOOD (HHFFFF)
+Size 76: 38,87 GOOD (HHFFFF)
+Size 77: 39,88 GOOD (HHFFFF)
+Size 78: 39,89 GOOD (HHFFFF)
+Size 79: 40,90 GOOD (HHFFFF)
+Size 80: 40,91 GOOD (HHFFFF)
+Size 81: 41,92 GOOD (HHFFFF)
+Size 82: 41,94 GOOD (HHFFFF)
+Size 83: 42,95 GOOD (HHFFFF)
+Size 84: 42,96 GOOD (HHFFFF)
+Size 85: 43,97 GOOD (HHFFFF)
+Size 86: 43,98 GOOD (HHFFFF)
+Size 87: 44,99 GOOD (HHFFFF)
+Size 88: 44,100 GOOD (HHFFFF)
+Size 89: 45,102 GOOD (HHFFFF)
+Size 90: 45,103 GOOD (HHFFFF)
+Size 91: 46,104 GOOD (HHFFFF)
+Size 92: 46,105 GOOD (HHFFFF)
+Size 93: 47,106 GOOD (HHFFFF)
+Size 94: 47,107 GOOD (HHFFFF)
+Size 95: 48,108 GOOD (HHFFFF)
+Size 96: 48,111 GOOD (HHFFFF)
+Size 97: 49,111 GOOD (HHFFFF)
+Size 98: 49,112 GOOD (HHFFFF)
+Size 99: 50,113 GOOD (HHFFFF)
+Size 100: 50,114 GOOD (HHFFFF)
+
+Windows 8.1
+-----------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,9 GOOD (HHFFFF)
+Size 9: 5,10 BAD (FFHFHH)
+Size 10: 5,11 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,15 BAD (FFHFHH)
+Size 14: 7,16 GOOD (HHFFFF)
+Size 15: 8,17 BAD (FFHFHH)
+Size 16: 8,18 GOOD (HHFFFF)
+Size 17: 9,19 BAD (FFHFHH)
+Size 18: 9,21 GOOD (HHFFFF)
+Size 19: 10,22 BAD (FFHFHH)
+Size 20: 10,23 GOOD (HHFFFF)
+Size 21: 11,24 BAD (FFHFHH)
+Size 22: 11,25 GOOD (HHFFFF)
+Size 23: 12,26 BAD (FFHFHH)
+Size 24: 12,27 GOOD (HHFFFF)
+Size 25: 13,29 BAD (FFHFHH)
+Size 26: 13,30 GOOD (HHFFFF)
+Size 27: 14,31 BAD (FFHFHH)
+Size 28: 14,32 GOOD (HHFFFF)
+Size 29: 15,33 BAD (FFHFHH)
+Size 30: 15,34 GOOD (HHFFFF)
+Size 31: 16,35 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,38 BAD (FFHFHH)
+Size 34: 17,39 GOOD (HHFFFF)
+Size 35: 18,40 BAD (FFHFHH)
+Size 36: 18,41 GOOD (HHFFFF)
+Size 37: 19,42 BAD (FFHFHH)
+Size 38: 19,43 GOOD (HHFFFF)
+Size 39: 20,44 BAD (FFHFHH)
+Size 40: 20,46 GOOD (HHFFFF)
+Size 41: 21,47 BAD (FFHFHH)
+Size 42: 21,48 GOOD (HHFFFF)
+Size 43: 22,49 BAD (FFHFHH)
+Size 44: 22,50 GOOD (HHFFFF)
+Size 45: 23,51 BAD (FFHFHH)
+Size 46: 23,52 GOOD (HHFFFF)
+Size 47: 24,54 BAD (FFHFHH)
+Size 48: 24,55 GOOD (HHFFFF)
+Size 49: 25,56 BAD (FFHFHH)
+Size 50: 25,57 GOOD (HHFFFF)
+Size 51: 26,58 BAD (FFHFHH)
+Size 52: 26,59 GOOD (HHFFFF)
+Size 53: 27,60 BAD (FFHFHH)
+Size 54: 27,62 GOOD (HHFFFF)
+Size 55: 28,63 BAD (FFHFHH)
+Size 56: 28,64 GOOD (HHFFFF)
+Size 57: 29,65 BAD (FFHFHH)
+Size 58: 29,66 GOOD (HHFFFF)
+Size 59: 30,67 BAD (FFHFHH)
+Size 60: 30,68 GOOD (HHFFFF)
+Size 61: 31,70 BAD (FFHFHH)
+Size 62: 31,71 GOOD (HHFFFF)
+Size 63: 32,72 BAD (FFHFHH)
+Size 64: 32,73 GOOD (HHFFFF)
+Size 65: 33,74 GOOD (HHFFFF)
+Size 66: 33,75 GOOD (HHFFFF)
+Size 67: 34,76 GOOD (HHFFFF)
+Size 68: 34,78 GOOD (HHFFFF)
+Size 69: 35,79 GOOD (HHFFFF)
+Size 70: 35,80 GOOD (HHFFFF)
+Size 71: 36,81 GOOD (HHFFFF)
+Size 72: 36,82 GOOD (HHFFFF)
+Size 73: 37,83 GOOD (HHFFFF)
+Size 74: 37,84 GOOD (HHFFFF)
+Size 75: 38,86 GOOD (HHFFFF)
+Size 76: 38,87 GOOD (HHFFFF)
+Size 77: 39,88 GOOD (HHFFFF)
+Size 78: 39,89 GOOD (HHFFFF)
+Size 79: 40,90 GOOD (HHFFFF)
+Size 80: 40,91 GOOD (HHFFFF)
+Size 81: 41,92 GOOD (HHFFFF)
+Size 82: 41,94 GOOD (HHFFFF)
+Size 83: 42,95 GOOD (HHFFFF)
+Size 84: 42,96 GOOD (HHFFFF)
+Size 85: 43,97 GOOD (HHFFFF)
+Size 86: 43,98 GOOD (HHFFFF)
+Size 87: 44,99 GOOD (HHFFFF)
+Size 88: 44,100 GOOD (HHFFFF)
+Size 89: 45,102 GOOD (HHFFFF)
+Size 90: 45,103 GOOD (HHFFFF)
+Size 91: 46,104 GOOD (HHFFFF)
+Size 92: 46,105 GOOD (HHFFFF)
+Size 93: 47,106 GOOD (HHFFFF)
+Size 94: 47,107 GOOD (HHFFFF)
+Size 95: 48,108 GOOD (HHFFFF)
+Size 96: 48,111 GOOD (HHFFFF)
+Size 97: 49,111 GOOD (HHFFFF)
+Size 98: 49,112 GOOD (HHFFFF)
+Size 99: 50,113 GOOD (HHFFFF)
+Size 100: 50,114 GOOD (HHFFFF)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,9 GOOD (HHFFFF)
+Size 9: 5,10 BAD (FFHFHH)
+Size 10: 5,11 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,15 BAD (FFHFHH)
+Size 14: 7,16 GOOD (HHFFFF)
+Size 15: 8,17 BAD (FFHFHH)
+Size 16: 8,18 GOOD (HHFFFF)
+Size 17: 9,19 BAD (FFHFHH)
+Size 18: 9,21 GOOD (HHFFFF)
+Size 19: 10,22 BAD (FFHFHH)
+Size 20: 10,23 GOOD (HHFFFF)
+Size 21: 11,24 BAD (FFHFHH)
+Size 22: 11,25 GOOD (HHFFFF)
+Size 23: 12,26 BAD (FFHFHH)
+Size 24: 12,27 GOOD (HHFFFF)
+Size 25: 13,29 BAD (FFHFHH)
+Size 26: 13,30 GOOD (HHFFFF)
+Size 27: 14,31 BAD (FFHFHH)
+Size 28: 14,32 GOOD (HHFFFF)
+Size 29: 15,33 BAD (FFHFHH)
+Size 30: 15,34 GOOD (HHFFFF)
+Size 31: 16,35 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,38 BAD (FFHFHH)
+Size 34: 17,39 GOOD (HHFFFF)
+Size 35: 18,40 BAD (FFHFHH)
+Size 36: 18,41 GOOD (HHFFFF)
+Size 37: 19,42 BAD (FFHFHH)
+Size 38: 19,43 GOOD (HHFFFF)
+Size 39: 20,44 BAD (FFHFHH)
+Size 40: 20,46 GOOD (HHFFFF)
+Size 41: 21,47 BAD (FFHFHH)
+Size 42: 21,48 GOOD (HHFFFF)
+Size 43: 22,49 BAD (FFHFHH)
+Size 44: 22,50 GOOD (HHFFFF)
+Size 45: 23,51 BAD (FFHFHH)
+Size 46: 23,52 GOOD (HHFFFF)
+Size 47: 24,54 BAD (FFHFHH)
+Size 48: 24,55 GOOD (HHFFFF)
+Size 49: 25,56 BAD (FFHFHH)
+Size 50: 25,57 GOOD (HHFFFF)
+Size 51: 26,58 BAD (FFHFHH)
+Size 52: 26,59 GOOD (HHFFFF)
+Size 53: 27,60 BAD (FFHFHH)
+Size 54: 27,62 GOOD (HHFFFF)
+Size 55: 28,63 BAD (FFHFHH)
+Size 56: 28,64 GOOD (HHFFFF)
+Size 57: 29,65 BAD (FFHFHH)
+Size 58: 29,66 GOOD (HHFFFF)
+Size 59: 30,67 BAD (FFHFHH)
+Size 60: 30,68 GOOD (HHFFFF)
+Size 61: 31,70 BAD (FFHFHH)
+Size 62: 31,71 GOOD (HHFFFF)
+Size 63: 32,72 BAD (FFHFHH)
+Size 64: 32,73 GOOD (HHFFFF)
+Size 65: 33,74 GOOD (HHFFFF)
+Size 66: 33,75 GOOD (HHFFFF)
+Size 67: 34,76 GOOD (HHFFFF)
+Size 68: 34,78 GOOD (HHFFFF)
+Size 69: 35,79 GOOD (HHFFFF)
+Size 70: 35,80 GOOD (HHFFFF)
+Size 71: 36,81 GOOD (HHFFFF)
+Size 72: 36,82 GOOD (HHFFFF)
+Size 73: 37,83 GOOD (HHFFFF)
+Size 74: 37,84 GOOD (HHFFFF)
+Size 75: 38,86 GOOD (HHFFFF)
+Size 76: 38,87 GOOD (HHFFFF)
+Size 77: 39,88 GOOD (HHFFFF)
+Size 78: 39,89 GOOD (HHFFFF)
+Size 79: 40,90 GOOD (HHFFFF)
+Size 80: 40,91 GOOD (HHFFFF)
+Size 81: 41,92 GOOD (HHFFFF)
+Size 82: 41,94 GOOD (HHFFFF)
+Size 83: 42,95 GOOD (HHFFFF)
+Size 84: 42,96 GOOD (HHFFFF)
+Size 85: 43,97 GOOD (HHFFFF)
+Size 86: 43,98 GOOD (HHFFFF)
+Size 87: 44,99 GOOD (HHFFFF)
+Size 88: 44,100 GOOD (HHFFFF)
+Size 89: 45,102 GOOD (HHFFFF)
+Size 90: 45,103 GOOD (HHFFFF)
+Size 91: 46,104 GOOD (HHFFFF)
+Size 92: 46,105 GOOD (HHFFFF)
+Size 93: 47,106 GOOD (HHFFFF)
+Size 94: 47,107 GOOD (HHFFFF)
+Size 95: 48,108 GOOD (HHFFFF)
+Size 96: 48,111 GOOD (HHFFFF)
+Size 97: 49,111 GOOD (HHFFFF)
+Size 98: 49,112 GOOD (HHFFFF)
+Size 99: 50,113 GOOD (HHFFFF)
+Size 100: 50,114 GOOD (HHFFFF)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 GOOD (HHFFFF)
+Size 4: 2,4 GOOD (HHFFFF)
+Size 5: 3,5 GOOD (HHFFFF)
+Size 6: 3,6 GOOD (HHFFFF)
+Size 7: 4,7 GOOD (HHFFFF)
+Size 8: 4,8 GOOD (HHFFFF)
+Size 9: 5,9 GOOD (HHFFFF)
+Size 10: 5,10 GOOD (HHFFFF)
+Size 11: 6,11 GOOD (HHFFFF)
+Size 12: 6,12 GOOD (HHFFFF)
+Size 13: 7,13 GOOD (HHFFFF)
+Size 14: 7,14 GOOD (HHFFFF)
+Size 15: 8,15 GOOD (HHFFFF)
+Size 16: 8,16 GOOD (HHFFFF)
+Size 17: 9,17 GOOD (HHFFFF)
+Size 18: 9,18 GOOD (HHFFFF)
+Size 19: 10,19 GOOD (HHFFFF)
+Size 20: 10,20 GOOD (HHFFFF)
+Size 21: 11,21 GOOD (HHFFFF)
+Size 22: 11,22 GOOD (HHFFFF)
+Size 23: 12,23 GOOD (HHFFFF)
+Size 24: 12,24 GOOD (HHFFFF)
+Size 25: 13,25 GOOD (HHFFFF)
+Size 26: 13,26 GOOD (HHFFFF)
+Size 27: 14,27 GOOD (HHFFFF)
+Size 28: 14,28 GOOD (HHFFFF)
+Size 29: 15,29 GOOD (HHFFFF)
+Size 30: 15,30 GOOD (HHFFFF)
+Size 31: 16,31 GOOD (HHFFFF)
+Size 32: 16,32 GOOD (HHFFFF)
+Size 33: 17,33 GOOD (HHFFFF)
+Size 34: 17,34 GOOD (HHFFFF)
+Size 35: 18,35 GOOD (HHFFFF)
+Size 36: 18,36 GOOD (HHFFFF)
+Size 37: 19,37 GOOD (HHFFFF)
+Size 38: 19,38 GOOD (HHFFFF)
+Size 39: 20,39 GOOD (HHFFFF)
+Size 40: 20,40 GOOD (HHFFFF)
+Size 41: 21,41 GOOD (HHFFFF)
+Size 42: 21,42 GOOD (HHFFFF)
+Size 43: 22,43 GOOD (HHFFFF)
+Size 44: 22,44 GOOD (HHFFFF)
+Size 45: 23,45 GOOD (HHFFFF)
+Size 46: 23,46 GOOD (HHFFFF)
+Size 47: 24,47 GOOD (HHFFFF)
+Size 48: 24,48 GOOD (HHFFFF)
+Size 49: 25,49 GOOD (HHFFFF)
+Size 50: 25,50 GOOD (HHFFFF)
+Size 51: 26,51 GOOD (HHFFFF)
+Size 52: 26,52 GOOD (HHFFFF)
+Size 53: 27,53 GOOD (HHFFFF)
+Size 54: 27,54 GOOD (HHFFFF)
+Size 55: 28,55 GOOD (HHFFFF)
+Size 56: 28,56 GOOD (HHFFFF)
+Size 57: 29,57 GOOD (HHFFFF)
+Size 58: 29,58 GOOD (HHFFFF)
+Size 59: 30,59 GOOD (HHFFFF)
+Size 60: 30,60 GOOD (HHFFFF)
+Size 61: 31,61 GOOD (HHFFFF)
+Size 62: 31,62 GOOD (HHFFFF)
+Size 63: 32,63 GOOD (HHFFFF)
+Size 64: 32,64 GOOD (HHFFFF)
+Size 65: 33,65 GOOD (HHFFFF)
+Size 66: 33,66 GOOD (HHFFFF)
+Size 67: 34,67 GOOD (HHFFFF)
+Size 68: 34,68 GOOD (HHFFFF)
+Size 69: 35,69 GOOD (HHFFFF)
+Size 70: 35,70 GOOD (HHFFFF)
+Size 71: 36,71 GOOD (HHFFFF)
+Size 72: 36,72 GOOD (HHFFFF)
+Size 73: 37,73 GOOD (HHFFFF)
+Size 74: 37,74 GOOD (HHFFFF)
+Size 75: 38,75 GOOD (HHFFFF)
+Size 76: 38,76 GOOD (HHFFFF)
+Size 77: 39,77 GOOD (HHFFFF)
+Size 78: 39,78 GOOD (HHFFFF)
+Size 79: 40,79 GOOD (HHFFFF)
+Size 80: 40,80 GOOD (HHFFFF)
+Size 81: 41,81 GOOD (HHFFFF)
+Size 82: 41,82 GOOD (HHFFFF)
+Size 83: 42,83 GOOD (HHFFFF)
+Size 84: 42,84 GOOD (HHFFFF)
+Size 85: 43,85 GOOD (HHFFFF)
+Size 86: 43,86 GOOD (HHFFFF)
+Size 87: 44,87 GOOD (HHFFFF)
+Size 88: 44,88 GOOD (HHFFFF)
+Size 89: 45,89 GOOD (HHFFFF)
+Size 90: 45,90 GOOD (HHFFFF)
+Size 91: 46,91 GOOD (HHFFFF)
+Size 92: 46,92 GOOD (HHFFFF)
+Size 93: 47,93 GOOD (HHFFFF)
+Size 94: 47,94 GOOD (HHFFFF)
+Size 95: 48,95 GOOD (HHFFFF)
+Size 96: 48,96 GOOD (HHFFFF)
+Size 97: 49,97 GOOD (HHFFFF)
+Size 98: 49,98 GOOD (HHFFFF)
+Size 99: 50,99 GOOD (HHFFFF)
+Size 100: 50,100 GOOD (HHFFFF)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt
new file mode 100644
index 0000000000..2f0ea1e7c2
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt
@@ -0,0 +1,630 @@
+=====================================
+Code Page 949, Korean, GulimChe font
+=====================================
+
+Options: -face-gulimche -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+Vista
+-----
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,5 OK (HHHFFF)
+Size 5: 3,6 BAD (HHHFHH)
+Size 6: 3,7 OK (HHHFFF)
+Size 7: 4,8 BAD (HHHFHH)
+Size 8: 4,9 OK (HHHFFF)
+Size 9: 5,10 BAD (HHHFHH)
+Size 10: 5,11 OK (HHHFFF)
+Size 11: 6,13 BAD (HHHFHH)
+Size 12: 6,14 OK (HHHFFF)
+Size 13: 7,15 BAD (HHHFHH)
+Size 14: 7,16 OK (HHHFFF)
+Size 15: 8,17 BAD (HHHFHH)
+Size 16: 8,18 OK (HHHFFF)
+Size 17: 9,20 BAD (HHHFHH)
+Size 18: 9,21 OK (HHHFFF)
+Size 19: 10,22 BAD (HHHFHH)
+Size 20: 10,23 OK (HHHFFF)
+Size 21: 11,24 BAD (HHHFHH)
+Size 22: 11,25 OK (HHHFFF)
+Size 23: 12,26 BAD (HHHFHH)
+Size 24: 12,28 OK (HHHFFF)
+Size 25: 13,29 BAD (HHHFHH)
+Size 26: 13,30 OK (HHHFFF)
+Size 27: 14,31 BAD (HHHFHH)
+Size 28: 14,32 OK (HHHFFF)
+Size 29: 15,33 BAD (HHHFHH)
+Size 30: 15,34 OK (HHHFFF)
+Size 31: 16,36 BAD (HHHFHH)
+Size 32: 16,37 OK (HHHFFF)
+Size 33: 17,38 BAD (HHHFHH)
+Size 34: 17,39 OK (HHHFFF)
+Size 35: 18,40 BAD (HHHFHH)
+Size 36: 18,41 OK (HHHFFF)
+Size 37: 19,42 BAD (HHHFHH)
+Size 38: 19,44 OK (HHHFFF)
+Size 39: 20,45 BAD (HHHFHH)
+Size 40: 20,46 OK (HHHFFF)
+Size 41: 21,47 BAD (HHHFHH)
+Size 42: 21,48 OK (HHHFFF)
+Size 43: 22,49 BAD (HHHFHH)
+Size 44: 22,51 OK (HHHFFF)
+Size 45: 23,52 BAD (HHHFHH)
+Size 46: 23,53 OK (HHHFFF)
+Size 47: 24,54 BAD (HHHFHH)
+Size 48: 24,55 OK (HHHFFF)
+Size 49: 25,56 BAD (HHHFHH)
+Size 50: 25,57 OK (HHHFFF)
+Size 51: 26,59 BAD (HHHFHH)
+Size 52: 26,60 OK (HHHFFF)
+Size 53: 27,61 BAD (HHHFHH)
+Size 54: 27,62 OK (HHHFFF)
+Size 55: 28,63 BAD (HHHFHH)
+Size 56: 28,64 OK (HHHFFF)
+Size 57: 29,65 BAD (HHHFHH)
+Size 58: 29,67 OK (HHHFFF)
+Size 59: 30,68 BAD (HHHFHH)
+Size 60: 30,69 OK (HHHFFF)
+Size 61: 31,70 BAD (HHHFHH)
+Size 62: 31,71 OK (HHHFFF)
+Size 63: 32,72 BAD (HHHFHH)
+Size 64: 32,74 OK (HHHFFF)
+Size 65: 33,75 BAD (HHHFHH)
+Size 66: 33,76 OK (HHHFFF)
+Size 67: 34,77 BAD (HHHFHH)
+Size 68: 34,78 OK (HHHFFF)
+Size 69: 35,79 BAD (HHHFHH)
+Size 70: 35,80 OK (HHHFFF)
+Size 71: 36,82 BAD (HHHFHH)
+Size 72: 36,83 OK (HHHFFF)
+Size 73: 37,84 BAD (HHHFHH)
+Size 74: 37,85 OK (HHHFFF)
+Size 75: 38,86 BAD (HHHFHH)
+Size 76: 38,87 OK (HHHFFF)
+Size 77: 39,88 BAD (HHHFHH)
+Size 78: 39,90 OK (HHHFFF)
+Size 79: 40,91 BAD (HHHFHH)
+Size 80: 40,92 OK (HHHFFF)
+Size 81: 41,93 BAD (HHHFHH)
+Size 82: 41,94 OK (HHHFFF)
+Size 83: 42,95 BAD (HHHFHH)
+Size 84: 42,96 OK (HHHFFF)
+Size 85: 43,98 BAD (HHHFHH)
+Size 86: 43,99 OK (HHHFFF)
+Size 87: 44,100 BAD (HHHFHH)
+Size 88: 44,101 OK (HHHFFF)
+Size 89: 45,102 BAD (HHHFHH)
+Size 90: 45,103 OK (HHHFFF)
+Size 91: 46,105 BAD (HHHFHH)
+Size 92: 46,106 OK (HHHFFF)
+Size 93: 47,107 BAD (HHHFHH)
+Size 94: 47,108 OK (HHHFFF)
+Size 95: 48,109 BAD (HHHFHH)
+Size 96: 48,110 OK (HHHFFF)
+Size 97: 49,111 BAD (HHHFHH)
+Size 98: 49,113 OK (HHHFFF)
+Size 99: 50,114 BAD (HHHFHH)
+Size 100: 50,115 OK (HHHFFF)
+
+Windows 7
+---------
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,5 OK (HHHFFF)
+Size 5: 3,6 BAD (FFFFHH)
+Size 6: 3,7 OK (HHHFFF)
+Size 7: 4,8 BAD (FFFFHH)
+Size 8: 4,9 OK (HHHFFF)
+Size 9: 5,10 BAD (FFFFHH)
+Size 10: 5,11 OK (HHHFFF)
+Size 11: 6,13 BAD (FFFFHH)
+Size 12: 6,14 OK (HHHFFF)
+Size 13: 7,15 BAD (FFFFHH)
+Size 14: 7,16 OK (HHHFFF)
+Size 15: 8,17 BAD (FFFFHH)
+Size 16: 8,18 OK (HHHFFF)
+Size 17: 9,20 BAD (FFFFHH)
+Size 18: 9,21 OK (HHHFFF)
+Size 19: 10,22 BAD (FFFFHH)
+Size 20: 10,23 OK (HHHFFF)
+Size 21: 11,24 BAD (FFFFHH)
+Size 22: 11,25 OK (HHHFFF)
+Size 23: 12,26 BAD (FFFFHH)
+Size 24: 12,28 OK (HHHFFF)
+Size 25: 13,29 BAD (FFFFHH)
+Size 26: 13,30 OK (HHHFFF)
+Size 27: 14,31 BAD (FFFFHH)
+Size 28: 14,32 OK (HHHFFF)
+Size 29: 15,33 BAD (FFFFHH)
+Size 30: 15,34 OK (HHHFFF)
+Size 31: 16,36 BAD (FFFFHH)
+Size 32: 16,37 OK (HHHFFF)
+Size 33: 17,38 BAD (FFFFHH)
+Size 34: 17,39 OK (HHHFFF)
+Size 35: 18,40 BAD (FFFFHH)
+Size 36: 18,41 OK (HHHFFF)
+Size 37: 19,42 BAD (FFFFHH)
+Size 38: 19,44 OK (HHHFFF)
+Size 39: 20,45 BAD (FFFFHH)
+Size 40: 20,46 OK (HHHFFF)
+Size 41: 21,47 BAD (FFFFHH)
+Size 42: 21,48 OK (HHHFFF)
+Size 43: 22,49 BAD (FFFFHH)
+Size 44: 22,51 OK (HHHFFF)
+Size 45: 23,52 BAD (FFFFHH)
+Size 46: 23,53 OK (HHHFFF)
+Size 47: 24,54 BAD (FFFFHH)
+Size 48: 24,55 OK (HHHFFF)
+Size 49: 25,56 BAD (FFFFHH)
+Size 50: 25,57 OK (HHHFFF)
+Size 51: 26,59 BAD (FFFFHH)
+Size 52: 26,60 OK (HHHFFF)
+Size 53: 27,61 BAD (FFFFHH)
+Size 54: 27,62 OK (HHHFFF)
+Size 55: 28,63 BAD (FFFFHH)
+Size 56: 28,64 OK (HHHFFF)
+Size 57: 29,65 BAD (FFFFHH)
+Size 58: 29,67 OK (HHHFFF)
+Size 59: 30,68 BAD (FFFFHH)
+Size 60: 30,69 OK (HHHFFF)
+Size 61: 31,70 BAD (FFFFHH)
+Size 62: 31,71 OK (HHHFFF)
+Size 63: 32,72 BAD (FFFFHH)
+Size 64: 32,74 OK (HHHFFF)
+Size 65: 33,75 BAD (FFFFHH)
+Size 66: 33,76 OK (HHHFFF)
+Size 67: 34,77 BAD (FFFFHH)
+Size 68: 34,78 OK (HHHFFF)
+Size 69: 35,79 BAD (FFFFHH)
+Size 70: 35,80 OK (HHHFFF)
+Size 71: 36,82 BAD (FFFFHH)
+Size 72: 36,83 OK (HHHFFF)
+Size 73: 37,84 BAD (FFFFHH)
+Size 74: 37,85 OK (HHHFFF)
+Size 75: 38,86 BAD (FFFFHH)
+Size 76: 38,87 OK (HHHFFF)
+Size 77: 39,88 BAD (FFFFHH)
+Size 78: 39,90 OK (HHHFFF)
+Size 79: 40,91 BAD (FFFFHH)
+Size 80: 40,92 OK (HHHFFF)
+Size 81: 41,93 BAD (FFFFHH)
+Size 82: 41,94 OK (HHHFFF)
+Size 83: 42,95 BAD (FFFFHH)
+Size 84: 42,96 OK (HHHFFF)
+Size 85: 43,98 BAD (FFFFHH)
+Size 86: 43,99 OK (HHHFFF)
+Size 87: 44,100 BAD (FFFFHH)
+Size 88: 44,101 OK (HHHFFF)
+Size 89: 45,102 BAD (FFFFHH)
+Size 90: 45,103 OK (HHHFFF)
+Size 91: 46,105 BAD (FFFFHH)
+Size 92: 46,106 OK (HHHFFF)
+Size 93: 47,107 BAD (FFFFHH)
+Size 94: 47,108 OK (HHHFFF)
+Size 95: 48,109 BAD (FFFFHH)
+Size 96: 48,110 OK (HHHFFF)
+Size 97: 49,111 BAD (FFFFHH)
+Size 98: 49,113 OK (HHHFFF)
+Size 99: 50,114 BAD (FFFFHH)
+Size 100: 50,115 OK (HHHFFF)
+
+Windows 8
+---------
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,5 OK (HHHFFF)
+Size 5: 3,6 BAD (FFFFHH)
+Size 6: 3,7 OK (HHHFFF)
+Size 7: 4,8 BAD (FFFFHH)
+Size 8: 4,9 OK (HHHFFF)
+Size 9: 5,10 BAD (FFFFHH)
+Size 10: 5,11 OK (HHHFFF)
+Size 11: 6,13 BAD (FFFFHH)
+Size 12: 6,14 OK (HHHFFF)
+Size 13: 7,15 BAD (FFFFHH)
+Size 14: 7,16 OK (HHHFFF)
+Size 15: 8,17 BAD (FFFFHH)
+Size 16: 8,18 OK (HHHFFF)
+Size 17: 9,20 BAD (FFFFHH)
+Size 18: 9,21 OK (HHHFFF)
+Size 19: 10,22 BAD (FFFFHH)
+Size 20: 10,23 OK (HHHFFF)
+Size 21: 11,24 BAD (FFFFHH)
+Size 22: 11,25 OK (HHHFFF)
+Size 23: 12,26 BAD (FFFFHH)
+Size 24: 12,28 OK (HHHFFF)
+Size 25: 13,29 BAD (FFFFHH)
+Size 26: 13,30 OK (HHHFFF)
+Size 27: 14,31 BAD (FFFFHH)
+Size 28: 14,32 OK (HHHFFF)
+Size 29: 15,33 BAD (FFFFHH)
+Size 30: 15,34 OK (HHHFFF)
+Size 31: 16,36 BAD (FFFFHH)
+Size 32: 16,37 OK (HHHFFF)
+Size 33: 17,38 BAD (FFFFHH)
+Size 34: 17,39 OK (HHHFFF)
+Size 35: 18,40 BAD (FFFFHH)
+Size 36: 18,41 OK (HHHFFF)
+Size 37: 19,42 BAD (FFFFHH)
+Size 38: 19,44 OK (HHHFFF)
+Size 39: 20,45 BAD (FFFFHH)
+Size 40: 20,46 OK (HHHFFF)
+Size 41: 21,47 BAD (FFFFHH)
+Size 42: 21,48 OK (HHHFFF)
+Size 43: 22,49 BAD (FFFFHH)
+Size 44: 22,51 OK (HHHFFF)
+Size 45: 23,52 BAD (FFFFHH)
+Size 46: 23,53 OK (HHHFFF)
+Size 47: 24,54 BAD (FFFFHH)
+Size 48: 24,55 OK (HHHFFF)
+Size 49: 25,56 BAD (FFFFHH)
+Size 50: 25,57 OK (HHHFFF)
+Size 51: 26,59 BAD (FFFFHH)
+Size 52: 26,60 OK (HHHFFF)
+Size 53: 27,61 BAD (FFFFHH)
+Size 54: 27,62 OK (HHHFFF)
+Size 55: 28,63 BAD (FFFFHH)
+Size 56: 28,64 OK (HHHFFF)
+Size 57: 29,65 BAD (FFFFHH)
+Size 58: 29,67 OK (HHHFFF)
+Size 59: 30,68 BAD (FFFFHH)
+Size 60: 30,69 OK (HHHFFF)
+Size 61: 31,70 BAD (FFFFHH)
+Size 62: 31,71 OK (HHHFFF)
+Size 63: 32,72 BAD (FFFFHH)
+Size 64: 32,74 OK (HHHFFF)
+Size 65: 33,75 BAD (FFFFHH)
+Size 66: 33,76 OK (HHHFFF)
+Size 67: 34,77 BAD (FFFFHH)
+Size 68: 34,78 OK (HHHFFF)
+Size 69: 35,79 BAD (FFFFHH)
+Size 70: 35,80 OK (HHHFFF)
+Size 71: 36,82 BAD (FFFFHH)
+Size 72: 36,83 OK (HHHFFF)
+Size 73: 37,84 BAD (FFFFHH)
+Size 74: 37,85 OK (HHHFFF)
+Size 75: 38,86 BAD (FFFFHH)
+Size 76: 38,87 OK (HHHFFF)
+Size 77: 39,88 BAD (FFFFHH)
+Size 78: 39,90 OK (HHHFFF)
+Size 79: 40,91 BAD (FFFFHH)
+Size 80: 40,92 OK (HHHFFF)
+Size 81: 41,93 BAD (FFFFHH)
+Size 82: 41,94 OK (HHHFFF)
+Size 83: 42,95 BAD (FFFFHH)
+Size 84: 42,96 OK (HHHFFF)
+Size 85: 43,98 BAD (FFFFHH)
+Size 86: 43,99 OK (HHHFFF)
+Size 87: 44,100 BAD (FFFFHH)
+Size 88: 44,101 OK (HHHFFF)
+Size 89: 45,102 BAD (FFFFHH)
+Size 90: 45,103 OK (HHHFFF)
+Size 91: 46,105 BAD (FFFFHH)
+Size 92: 46,106 OK (HHHFFF)
+Size 93: 47,107 BAD (FFFFHH)
+Size 94: 47,108 OK (HHHFFF)
+Size 95: 48,109 BAD (FFFFHH)
+Size 96: 48,110 OK (HHHFFF)
+Size 97: 49,111 BAD (FFFFHH)
+Size 98: 49,113 OK (HHHFFF)
+Size 99: 50,114 BAD (FFFFHH)
+Size 100: 50,115 OK (HHHFFF)
+
+Windows 8.1
+-----------
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,5 OK (HHHFFF)
+Size 5: 3,6 BAD (FFFFHH)
+Size 6: 3,7 OK (HHHFFF)
+Size 7: 4,8 BAD (FFFFHH)
+Size 8: 4,9 OK (HHHFFF)
+Size 9: 5,10 BAD (FFFFHH)
+Size 10: 5,11 OK (HHHFFF)
+Size 11: 6,13 BAD (FFFFHH)
+Size 12: 6,14 OK (HHHFFF)
+Size 13: 7,15 BAD (FFFFHH)
+Size 14: 7,16 OK (HHHFFF)
+Size 15: 8,17 BAD (FFFFHH)
+Size 16: 8,18 OK (HHHFFF)
+Size 17: 9,20 BAD (FFFFHH)
+Size 18: 9,21 OK (HHHFFF)
+Size 19: 10,22 BAD (FFFFHH)
+Size 20: 10,23 OK (HHHFFF)
+Size 21: 11,24 BAD (FFFFHH)
+Size 22: 11,25 OK (HHHFFF)
+Size 23: 12,26 BAD (FFFFHH)
+Size 24: 12,28 OK (HHHFFF)
+Size 25: 13,29 BAD (FFFFHH)
+Size 26: 13,30 OK (HHHFFF)
+Size 27: 14,31 BAD (FFFFHH)
+Size 28: 14,32 OK (HHHFFF)
+Size 29: 15,33 BAD (FFFFHH)
+Size 30: 15,34 OK (HHHFFF)
+Size 31: 16,36 BAD (FFFFHH)
+Size 32: 16,37 OK (HHHFFF)
+Size 33: 17,38 BAD (FFFFHH)
+Size 34: 17,39 OK (HHHFFF)
+Size 35: 18,40 BAD (FFFFHH)
+Size 36: 18,41 OK (HHHFFF)
+Size 37: 19,42 BAD (FFFFHH)
+Size 38: 19,44 OK (HHHFFF)
+Size 39: 20,45 BAD (FFFFHH)
+Size 40: 20,46 OK (HHHFFF)
+Size 41: 21,47 BAD (FFFFHH)
+Size 42: 21,48 OK (HHHFFF)
+Size 43: 22,49 BAD (FFFFHH)
+Size 44: 22,51 OK (HHHFFF)
+Size 45: 23,52 BAD (FFFFHH)
+Size 46: 23,53 OK (HHHFFF)
+Size 47: 24,54 BAD (FFFFHH)
+Size 48: 24,55 OK (HHHFFF)
+Size 49: 25,56 BAD (FFFFHH)
+Size 50: 25,57 OK (HHHFFF)
+Size 51: 26,59 BAD (FFFFHH)
+Size 52: 26,60 OK (HHHFFF)
+Size 53: 27,61 BAD (FFFFHH)
+Size 54: 27,62 OK (HHHFFF)
+Size 55: 28,63 BAD (FFFFHH)
+Size 56: 28,64 OK (HHHFFF)
+Size 57: 29,65 BAD (FFFFHH)
+Size 58: 29,67 OK (HHHFFF)
+Size 59: 30,68 BAD (FFFFHH)
+Size 60: 30,69 OK (HHHFFF)
+Size 61: 31,70 BAD (FFFFHH)
+Size 62: 31,71 OK (HHHFFF)
+Size 63: 32,72 BAD (FFFFHH)
+Size 64: 32,74 OK (HHHFFF)
+Size 65: 33,75 BAD (FFFFHH)
+Size 66: 33,76 OK (HHHFFF)
+Size 67: 34,77 BAD (FFFFHH)
+Size 68: 34,78 OK (HHHFFF)
+Size 69: 35,79 BAD (FFFFHH)
+Size 70: 35,80 OK (HHHFFF)
+Size 71: 36,82 BAD (FFFFHH)
+Size 72: 36,83 OK (HHHFFF)
+Size 73: 37,84 BAD (FFFFHH)
+Size 74: 37,85 OK (HHHFFF)
+Size 75: 38,86 BAD (FFFFHH)
+Size 76: 38,87 OK (HHHFFF)
+Size 77: 39,88 BAD (FFFFHH)
+Size 78: 39,90 OK (HHHFFF)
+Size 79: 40,91 BAD (FFFFHH)
+Size 80: 40,92 OK (HHHFFF)
+Size 81: 41,93 BAD (FFFFHH)
+Size 82: 41,94 OK (HHHFFF)
+Size 83: 42,95 BAD (FFFFHH)
+Size 84: 42,96 OK (HHHFFF)
+Size 85: 43,98 BAD (FFFFHH)
+Size 86: 43,99 OK (HHHFFF)
+Size 87: 44,100 BAD (FFFFHH)
+Size 88: 44,101 OK (HHHFFF)
+Size 89: 45,102 BAD (FFFFHH)
+Size 90: 45,103 OK (HHHFFF)
+Size 91: 46,105 BAD (FFFFHH)
+Size 92: 46,106 OK (HHHFFF)
+Size 93: 47,107 BAD (FFFFHH)
+Size 94: 47,108 OK (HHHFFF)
+Size 95: 48,109 BAD (FFFFHH)
+Size 96: 48,110 OK (HHHFFF)
+Size 97: 49,111 BAD (FFFFHH)
+Size 98: 49,113 OK (HHHFFF)
+Size 99: 50,114 BAD (FFFFHH)
+Size 100: 50,115 OK (HHHFFF)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,2 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 BAD (FFFFHH)
+Size 4: 2,5 OK (HHHFFF)
+Size 5: 3,6 BAD (FFFFHH)
+Size 6: 3,7 OK (HHHFFF)
+Size 7: 4,8 BAD (FFFFHH)
+Size 8: 4,9 OK (HHHFFF)
+Size 9: 5,10 BAD (FFFFHH)
+Size 10: 5,11 OK (HHHFFF)
+Size 11: 6,13 BAD (FFFFHH)
+Size 12: 6,14 OK (HHHFFF)
+Size 13: 7,15 BAD (FFFFHH)
+Size 14: 7,16 OK (HHHFFF)
+Size 15: 8,17 BAD (FFFFHH)
+Size 16: 8,18 OK (HHHFFF)
+Size 17: 9,20 BAD (FFFFHH)
+Size 18: 9,21 OK (HHHFFF)
+Size 19: 10,22 BAD (FFFFHH)
+Size 20: 10,23 OK (HHHFFF)
+Size 21: 11,24 BAD (FFFFHH)
+Size 22: 11,25 OK (HHHFFF)
+Size 23: 12,26 BAD (FFFFHH)
+Size 24: 12,28 OK (HHHFFF)
+Size 25: 13,29 BAD (FFFFHH)
+Size 26: 13,30 OK (HHHFFF)
+Size 27: 14,31 BAD (FFFFHH)
+Size 28: 14,32 OK (HHHFFF)
+Size 29: 15,33 BAD (FFFFHH)
+Size 30: 15,34 OK (HHHFFF)
+Size 31: 16,36 BAD (FFFFHH)
+Size 32: 16,37 OK (HHHFFF)
+Size 33: 17,38 BAD (FFFFHH)
+Size 34: 17,39 OK (HHHFFF)
+Size 35: 18,40 BAD (FFFFHH)
+Size 36: 18,41 OK (HHHFFF)
+Size 37: 19,42 BAD (FFFFHH)
+Size 38: 19,44 OK (HHHFFF)
+Size 39: 20,45 BAD (FFFFHH)
+Size 40: 20,46 OK (HHHFFF)
+Size 41: 21,47 BAD (FFFFHH)
+Size 42: 21,48 OK (HHHFFF)
+Size 43: 22,49 BAD (FFFFHH)
+Size 44: 22,51 OK (HHHFFF)
+Size 45: 23,52 BAD (FFFFHH)
+Size 46: 23,53 OK (HHHFFF)
+Size 47: 24,54 BAD (FFFFHH)
+Size 48: 24,55 OK (HHHFFF)
+Size 49: 25,56 BAD (FFFFHH)
+Size 50: 25,57 OK (HHHFFF)
+Size 51: 26,59 BAD (FFFFHH)
+Size 52: 26,60 OK (HHHFFF)
+Size 53: 27,61 BAD (FFFFHH)
+Size 54: 27,62 OK (HHHFFF)
+Size 55: 28,63 BAD (FFFFHH)
+Size 56: 28,64 OK (HHHFFF)
+Size 57: 29,65 BAD (FFFFHH)
+Size 58: 29,67 OK (HHHFFF)
+Size 59: 30,68 BAD (FFFFHH)
+Size 60: 30,69 OK (HHHFFF)
+Size 61: 31,70 BAD (FFFFHH)
+Size 62: 31,71 OK (HHHFFF)
+Size 63: 32,72 BAD (FFFFHH)
+Size 64: 32,74 OK (HHHFFF)
+Size 65: 33,75 BAD (FFFFHH)
+Size 66: 33,76 OK (HHHFFF)
+Size 67: 34,77 BAD (FFFFHH)
+Size 68: 34,78 OK (HHHFFF)
+Size 69: 35,79 BAD (FFFFHH)
+Size 70: 35,80 OK (HHHFFF)
+Size 71: 36,82 BAD (FFFFHH)
+Size 72: 36,83 OK (HHHFFF)
+Size 73: 37,84 BAD (FFFFHH)
+Size 74: 37,85 OK (HHHFFF)
+Size 75: 38,86 BAD (FFFFHH)
+Size 76: 38,87 OK (HHHFFF)
+Size 77: 39,88 BAD (FFFFHH)
+Size 78: 39,90 OK (HHHFFF)
+Size 79: 40,91 BAD (FFFFHH)
+Size 80: 40,92 OK (HHHFFF)
+Size 81: 41,93 BAD (FFFFHH)
+Size 82: 41,94 OK (HHHFFF)
+Size 83: 42,95 BAD (FFFFHH)
+Size 84: 42,96 OK (HHHFFF)
+Size 85: 43,98 BAD (FFFFHH)
+Size 86: 43,99 OK (HHHFFF)
+Size 87: 44,100 BAD (FFFFHH)
+Size 88: 44,101 OK (HHHFFF)
+Size 89: 45,102 BAD (FFFFHH)
+Size 90: 45,103 OK (HHHFFF)
+Size 91: 46,105 BAD (FFFFHH)
+Size 92: 46,106 OK (HHHFFF)
+Size 93: 47,107 BAD (FFFFHH)
+Size 94: 47,108 OK (HHHFFF)
+Size 95: 48,109 BAD (FFFFHH)
+Size 96: 48,110 OK (HHHFFF)
+Size 97: 49,111 BAD (FFFFHH)
+Size 98: 49,113 OK (HHHFFF)
+Size 99: 50,114 BAD (FFFFHH)
+Size 100: 50,115 OK (HHHFFF)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 OK (HHHFFF)
+Size 2: 1,2 OK (HHHFFF)
+Size 3: 2,3 OK (HHHFFF)
+Size 4: 2,4 OK (HHHFFF)
+Size 5: 3,5 OK (HHHFFF)
+Size 6: 3,6 OK (HHHFFF)
+Size 7: 4,7 OK (HHHFFF)
+Size 8: 4,8 OK (HHHFFF)
+Size 9: 5,9 OK (HHHFFF)
+Size 10: 5,10 OK (HHHFFF)
+Size 11: 6,11 OK (HHHFFF)
+Size 12: 6,12 OK (HHHFFF)
+Size 13: 7,13 OK (HHHFFF)
+Size 14: 7,14 OK (HHHFFF)
+Size 15: 8,15 OK (HHHFFF)
+Size 16: 8,16 OK (HHHFFF)
+Size 17: 9,17 OK (HHHFFF)
+Size 18: 9,18 OK (HHHFFF)
+Size 19: 10,19 OK (HHHFFF)
+Size 20: 10,20 OK (HHHFFF)
+Size 21: 11,21 OK (HHHFFF)
+Size 22: 11,22 OK (HHHFFF)
+Size 23: 12,23 OK (HHHFFF)
+Size 24: 12,24 OK (HHHFFF)
+Size 25: 13,25 OK (HHHFFF)
+Size 26: 13,26 OK (HHHFFF)
+Size 27: 14,27 OK (HHHFFF)
+Size 28: 14,28 OK (HHHFFF)
+Size 29: 15,29 OK (HHHFFF)
+Size 30: 15,30 OK (HHHFFF)
+Size 31: 16,31 OK (HHHFFF)
+Size 32: 16,32 OK (HHHFFF)
+Size 33: 17,33 OK (HHHFFF)
+Size 34: 17,34 OK (HHHFFF)
+Size 35: 18,35 OK (HHHFFF)
+Size 36: 18,36 OK (HHHFFF)
+Size 37: 19,37 OK (HHHFFF)
+Size 38: 19,38 OK (HHHFFF)
+Size 39: 20,39 OK (HHHFFF)
+Size 40: 20,40 OK (HHHFFF)
+Size 41: 21,41 OK (HHHFFF)
+Size 42: 21,42 OK (HHHFFF)
+Size 43: 22,43 OK (HHHFFF)
+Size 44: 22,44 OK (HHHFFF)
+Size 45: 23,45 OK (HHHFFF)
+Size 46: 23,46 OK (HHHFFF)
+Size 47: 24,47 OK (HHHFFF)
+Size 48: 24,48 OK (HHHFFF)
+Size 49: 25,49 OK (HHHFFF)
+Size 50: 25,50 OK (HHHFFF)
+Size 51: 26,51 OK (HHHFFF)
+Size 52: 26,52 OK (HHHFFF)
+Size 53: 27,53 OK (HHHFFF)
+Size 54: 27,54 OK (HHHFFF)
+Size 55: 28,55 OK (HHHFFF)
+Size 56: 28,56 OK (HHHFFF)
+Size 57: 29,57 OK (HHHFFF)
+Size 58: 29,58 OK (HHHFFF)
+Size 59: 30,59 OK (HHHFFF)
+Size 60: 30,60 OK (HHHFFF)
+Size 61: 31,61 OK (HHHFFF)
+Size 62: 31,62 OK (HHHFFF)
+Size 63: 32,63 OK (HHHFFF)
+Size 64: 32,64 OK (HHHFFF)
+Size 65: 33,65 OK (HHHFFF)
+Size 66: 33,66 OK (HHHFFF)
+Size 67: 34,67 OK (HHHFFF)
+Size 68: 34,68 OK (HHHFFF)
+Size 69: 35,69 OK (HHHFFF)
+Size 70: 35,70 OK (HHHFFF)
+Size 71: 36,71 OK (HHHFFF)
+Size 72: 36,72 OK (HHHFFF)
+Size 73: 37,73 OK (HHHFFF)
+Size 74: 37,74 OK (HHHFFF)
+Size 75: 38,75 OK (HHHFFF)
+Size 76: 38,76 OK (HHHFFF)
+Size 77: 39,77 OK (HHHFFF)
+Size 78: 39,78 OK (HHHFFF)
+Size 79: 40,79 OK (HHHFFF)
+Size 80: 40,80 OK (HHHFFF)
+Size 81: 41,81 OK (HHHFFF)
+Size 82: 41,82 OK (HHHFFF)
+Size 83: 42,83 OK (HHHFFF)
+Size 84: 42,84 OK (HHHFFF)
+Size 85: 43,85 OK (HHHFFF)
+Size 86: 43,86 OK (HHHFFF)
+Size 87: 44,87 OK (HHHFFF)
+Size 88: 44,88 OK (HHHFFF)
+Size 89: 45,89 OK (HHHFFF)
+Size 90: 45,90 OK (HHHFFF)
+Size 91: 46,91 OK (HHHFFF)
+Size 92: 46,92 OK (HHHFFF)
+Size 93: 47,93 OK (HHHFFF)
+Size 94: 47,94 OK (HHHFFF)
+Size 95: 48,95 OK (HHHFFF)
+Size 96: 48,96 OK (HHHFFF)
+Size 97: 49,97 OK (HHHFFF)
+Size 98: 49,98 OK (HHHFFF)
+Size 99: 50,99 OK (HHHFFF)
+Size 100: 50,100 OK (HHHFFF)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt
new file mode 100644
index 0000000000..0dbade504d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt
@@ -0,0 +1,630 @@
+===========================================================
+Code Page 950, Chinese Traditional (Taiwan), MingLight font
+===========================================================
+
+Options: -face-minglight -family 0x36
+Chars: A2 A3 2014 3044 30FC 4000
+
+Vista
+-----
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,4 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (HHHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (HHHFHH)
+Size 8: 4,10 GOOD (HHFFFF)
+Size 9: 5,11 BAD (HHHFHH)
+Size 10: 5,12 GOOD (HHFFFF)
+Size 11: 6,13 BAD (HHHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,16 BAD (HHHFHH)
+Size 14: 7,17 GOOD (HHFFFF)
+Size 15: 8,18 BAD (HHHFHH)
+Size 16: 8,19 GOOD (HHFFFF)
+Size 17: 9,20 BAD (HHHFHH)
+Size 18: 9,22 GOOD (HHFFFF)
+Size 19: 10,23 BAD (HHHFHH)
+Size 20: 10,24 GOOD (HHFFFF)
+Size 21: 11,25 BAD (HHHFHH)
+Size 22: 11,26 GOOD (HHFFFF)
+Size 23: 12,28 BAD (HHHFHH)
+Size 24: 12,29 GOOD (HHFFFF)
+Size 25: 13,30 BAD (HHHFHH)
+Size 26: 13,31 GOOD (HHFFFF)
+Size 27: 14,32 BAD (HHHFHH)
+Size 28: 14,34 GOOD (HHFFFF)
+Size 29: 15,35 BAD (HHHFHH)
+Size 30: 15,36 GOOD (HHFFFF)
+Size 31: 16,37 BAD (HHHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,40 BAD (HHHFHH)
+Size 34: 17,41 GOOD (HHFFFF)
+Size 35: 18,42 BAD (HHHFHH)
+Size 36: 18,43 GOOD (HHFFFF)
+Size 37: 19,44 BAD (HHHFHH)
+Size 38: 19,46 GOOD (HHFFFF)
+Size 39: 20,47 BAD (HHHFHH)
+Size 40: 20,48 GOOD (HHFFFF)
+Size 41: 21,49 BAD (HHHFHH)
+Size 42: 21,50 GOOD (HHFFFF)
+Size 43: 22,52 BAD (HHHFHH)
+Size 44: 22,53 GOOD (HHFFFF)
+Size 45: 23,54 BAD (HHHFHH)
+Size 46: 23,55 GOOD (HHFFFF)
+Size 47: 24,56 BAD (HHHFHH)
+Size 48: 24,58 GOOD (HHFFFF)
+Size 49: 25,59 BAD (HHHFHH)
+Size 50: 25,60 GOOD (HHFFFF)
+Size 51: 26,61 BAD (HHHFHH)
+Size 52: 26,62 GOOD (HHFFFF)
+Size 53: 27,64 BAD (HHHFHH)
+Size 54: 27,65 GOOD (HHFFFF)
+Size 55: 28,66 BAD (HHHFHH)
+Size 56: 28,67 GOOD (HHFFFF)
+Size 57: 29,68 BAD (HHHFHH)
+Size 58: 29,70 GOOD (HHFFFF)
+Size 59: 30,71 BAD (HHHFHH)
+Size 60: 30,72 GOOD (HHFFFF)
+Size 61: 31,73 BAD (HHHFHH)
+Size 62: 31,74 GOOD (HHFFFF)
+Size 63: 32,76 BAD (HHHFHH)
+Size 64: 32,77 GOOD (HHFFFF)
+Size 65: 33,78 BAD (HHHFHH)
+Size 66: 33,79 GOOD (HHFFFF)
+Size 67: 34,80 BAD (HHHFHH)
+Size 68: 34,82 GOOD (HHFFFF)
+Size 69: 35,83 BAD (HHHFHH)
+Size 70: 35,84 GOOD (HHFFFF)
+Size 71: 36,85 BAD (HHHFHH)
+Size 72: 36,86 GOOD (HHFFFF)
+Size 73: 37,88 BAD (HHHFHH)
+Size 74: 37,89 GOOD (HHFFFF)
+Size 75: 38,90 BAD (HHHFHH)
+Size 76: 38,91 GOOD (HHFFFF)
+Size 77: 39,92 BAD (HHHFHH)
+Size 78: 39,94 GOOD (HHFFFF)
+Size 79: 40,95 BAD (HHHFHH)
+Size 80: 40,96 GOOD (HHFFFF)
+Size 81: 41,97 BAD (HHHFHH)
+Size 82: 41,98 GOOD (HHFFFF)
+Size 83: 42,100 BAD (HHHFHH)
+Size 84: 42,101 GOOD (HHFFFF)
+Size 85: 43,102 BAD (HHHFHH)
+Size 86: 43,103 GOOD (HHFFFF)
+Size 87: 44,104 BAD (HHHFHH)
+Size 88: 44,106 GOOD (HHFFFF)
+Size 89: 45,107 BAD (HHHFHH)
+Size 90: 45,108 GOOD (HHFFFF)
+Size 91: 46,109 BAD (HHHFHH)
+Size 92: 46,110 GOOD (HHFFFF)
+Size 93: 47,112 BAD (HHHFHH)
+Size 94: 47,113 GOOD (HHFFFF)
+Size 95: 48,114 BAD (HHHFHH)
+Size 96: 48,115 GOOD (HHFFFF)
+Size 97: 49,116 BAD (HHHFHH)
+Size 98: 49,118 GOOD (HHFFFF)
+Size 99: 50,119 BAD (HHHFHH)
+Size 100: 50,120 GOOD (HHFFFF)
+
+Windows 7
+---------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,4 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,10 GOOD (HHFFFF)
+Size 9: 5,11 BAD (FFHFHH)
+Size 10: 5,12 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,16 BAD (FFHFHH)
+Size 14: 7,17 GOOD (HHFFFF)
+Size 15: 8,18 BAD (FFHFHH)
+Size 16: 8,19 GOOD (HHFFFF)
+Size 17: 9,20 BAD (FFHFHH)
+Size 18: 9,22 GOOD (HHFFFF)
+Size 19: 10,23 BAD (FFHFHH)
+Size 20: 10,24 GOOD (HHFFFF)
+Size 21: 11,25 BAD (FFHFHH)
+Size 22: 11,26 GOOD (HHFFFF)
+Size 23: 12,28 BAD (FFHFHH)
+Size 24: 12,29 GOOD (HHFFFF)
+Size 25: 13,30 BAD (FFHFHH)
+Size 26: 13,31 GOOD (HHFFFF)
+Size 27: 14,32 BAD (FFHFHH)
+Size 28: 14,34 GOOD (HHFFFF)
+Size 29: 15,35 BAD (FFHFHH)
+Size 30: 15,36 GOOD (HHFFFF)
+Size 31: 16,37 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,40 BAD (FFHFHH)
+Size 34: 17,41 GOOD (HHFFFF)
+Size 35: 18,42 BAD (FFHFHH)
+Size 36: 18,43 GOOD (HHFFFF)
+Size 37: 19,44 BAD (FFHFHH)
+Size 38: 19,46 GOOD (HHFFFF)
+Size 39: 20,47 BAD (FFHFHH)
+Size 40: 20,48 GOOD (HHFFFF)
+Size 41: 21,49 BAD (FFHFHH)
+Size 42: 21,50 GOOD (HHFFFF)
+Size 43: 22,52 BAD (FFHFHH)
+Size 44: 22,53 GOOD (HHFFFF)
+Size 45: 23,54 BAD (FFHFHH)
+Size 46: 23,55 GOOD (HHFFFF)
+Size 47: 24,56 BAD (FFHFHH)
+Size 48: 24,58 GOOD (HHFFFF)
+Size 49: 25,59 BAD (FFHFHH)
+Size 50: 25,60 GOOD (HHFFFF)
+Size 51: 26,61 BAD (FFHFHH)
+Size 52: 26,62 GOOD (HHFFFF)
+Size 53: 27,64 BAD (FFHFHH)
+Size 54: 27,65 GOOD (HHFFFF)
+Size 55: 28,66 BAD (FFHFHH)
+Size 56: 28,67 GOOD (HHFFFF)
+Size 57: 29,68 BAD (FFHFHH)
+Size 58: 29,70 GOOD (HHFFFF)
+Size 59: 30,71 BAD (FFHFHH)
+Size 60: 30,72 GOOD (HHFFFF)
+Size 61: 31,73 BAD (FFHFHH)
+Size 62: 31,74 GOOD (HHFFFF)
+Size 63: 32,76 BAD (FFHFHH)
+Size 64: 32,77 GOOD (HHFFFF)
+Size 65: 33,78 BAD (FFHFHH)
+Size 66: 33,79 GOOD (HHFFFF)
+Size 67: 34,80 BAD (FFHFHH)
+Size 68: 34,82 GOOD (HHFFFF)
+Size 69: 35,83 BAD (FFHFHH)
+Size 70: 35,84 GOOD (HHFFFF)
+Size 71: 36,85 BAD (FFHFHH)
+Size 72: 36,86 GOOD (HHFFFF)
+Size 73: 37,88 BAD (FFHFHH)
+Size 74: 37,89 GOOD (HHFFFF)
+Size 75: 38,90 BAD (FFHFHH)
+Size 76: 38,91 GOOD (HHFFFF)
+Size 77: 39,92 BAD (FFHFHH)
+Size 78: 39,94 GOOD (HHFFFF)
+Size 79: 40,95 BAD (FFHFHH)
+Size 80: 40,96 GOOD (HHFFFF)
+Size 81: 41,97 BAD (FFHFHH)
+Size 82: 41,98 GOOD (HHFFFF)
+Size 83: 42,100 BAD (FFHFHH)
+Size 84: 42,101 GOOD (HHFFFF)
+Size 85: 43,102 BAD (FFHFHH)
+Size 86: 43,103 GOOD (HHFFFF)
+Size 87: 44,104 BAD (FFHFHH)
+Size 88: 44,106 GOOD (HHFFFF)
+Size 89: 45,107 BAD (FFHFHH)
+Size 90: 45,108 GOOD (HHFFFF)
+Size 91: 46,109 BAD (FFHFHH)
+Size 92: 46,110 GOOD (HHFFFF)
+Size 93: 47,112 BAD (FFHFHH)
+Size 94: 47,113 GOOD (HHFFFF)
+Size 95: 48,114 BAD (FFHFHH)
+Size 96: 48,115 GOOD (HHFFFF)
+Size 97: 49,116 BAD (FFHFHH)
+Size 98: 49,118 GOOD (HHFFFF)
+Size 99: 50,119 BAD (FFHFHH)
+Size 100: 50,120 GOOD (HHFFFF)
+
+Windows 8
+---------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,4 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,10 GOOD (HHFFFF)
+Size 9: 5,11 BAD (FFHFHH)
+Size 10: 5,12 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,16 BAD (FFHFHH)
+Size 14: 7,17 GOOD (HHFFFF)
+Size 15: 8,18 BAD (FFHFHH)
+Size 16: 8,19 GOOD (HHFFFF)
+Size 17: 9,20 BAD (FFHFHH)
+Size 18: 9,22 GOOD (HHFFFF)
+Size 19: 10,23 BAD (FFHFHH)
+Size 20: 10,24 GOOD (HHFFFF)
+Size 21: 11,25 BAD (FFHFHH)
+Size 22: 11,26 GOOD (HHFFFF)
+Size 23: 12,28 BAD (FFHFHH)
+Size 24: 12,29 GOOD (HHFFFF)
+Size 25: 13,30 BAD (FFHFHH)
+Size 26: 13,31 GOOD (HHFFFF)
+Size 27: 14,32 BAD (FFHFHH)
+Size 28: 14,34 GOOD (HHFFFF)
+Size 29: 15,35 BAD (FFHFHH)
+Size 30: 15,36 GOOD (HHFFFF)
+Size 31: 16,37 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,40 BAD (FFHFHH)
+Size 34: 17,41 GOOD (HHFFFF)
+Size 35: 18,42 BAD (FFHFHH)
+Size 36: 18,43 GOOD (HHFFFF)
+Size 37: 19,44 BAD (FFHFHH)
+Size 38: 19,46 GOOD (HHFFFF)
+Size 39: 20,47 BAD (FFHFHH)
+Size 40: 20,48 GOOD (HHFFFF)
+Size 41: 21,49 BAD (FFHFHH)
+Size 42: 21,50 GOOD (HHFFFF)
+Size 43: 22,52 BAD (FFHFHH)
+Size 44: 22,53 GOOD (HHFFFF)
+Size 45: 23,54 BAD (FFHFHH)
+Size 46: 23,55 GOOD (HHFFFF)
+Size 47: 24,56 BAD (FFHFHH)
+Size 48: 24,58 GOOD (HHFFFF)
+Size 49: 25,59 BAD (FFHFHH)
+Size 50: 25,60 GOOD (HHFFFF)
+Size 51: 26,61 BAD (FFHFHH)
+Size 52: 26,62 GOOD (HHFFFF)
+Size 53: 27,64 BAD (FFHFHH)
+Size 54: 27,65 GOOD (HHFFFF)
+Size 55: 28,66 BAD (FFHFHH)
+Size 56: 28,67 GOOD (HHFFFF)
+Size 57: 29,68 BAD (FFHFHH)
+Size 58: 29,70 GOOD (HHFFFF)
+Size 59: 30,71 BAD (FFHFHH)
+Size 60: 30,72 GOOD (HHFFFF)
+Size 61: 31,73 BAD (FFHFHH)
+Size 62: 31,74 GOOD (HHFFFF)
+Size 63: 32,76 BAD (FFHFHH)
+Size 64: 32,77 GOOD (HHFFFF)
+Size 65: 33,78 BAD (FFHFHH)
+Size 66: 33,79 GOOD (HHFFFF)
+Size 67: 34,80 BAD (FFHFHH)
+Size 68: 34,82 GOOD (HHFFFF)
+Size 69: 35,83 BAD (FFHFHH)
+Size 70: 35,84 GOOD (HHFFFF)
+Size 71: 36,85 BAD (FFHFHH)
+Size 72: 36,86 GOOD (HHFFFF)
+Size 73: 37,88 BAD (FFHFHH)
+Size 74: 37,89 GOOD (HHFFFF)
+Size 75: 38,90 BAD (FFHFHH)
+Size 76: 38,91 GOOD (HHFFFF)
+Size 77: 39,92 BAD (FFHFHH)
+Size 78: 39,94 GOOD (HHFFFF)
+Size 79: 40,95 BAD (FFHFHH)
+Size 80: 40,96 GOOD (HHFFFF)
+Size 81: 41,97 BAD (FFHFHH)
+Size 82: 41,98 GOOD (HHFFFF)
+Size 83: 42,100 BAD (FFHFHH)
+Size 84: 42,101 GOOD (HHFFFF)
+Size 85: 43,102 BAD (FFHFHH)
+Size 86: 43,103 GOOD (HHFFFF)
+Size 87: 44,104 BAD (FFHFHH)
+Size 88: 44,106 GOOD (HHFFFF)
+Size 89: 45,107 BAD (FFHFHH)
+Size 90: 45,108 GOOD (HHFFFF)
+Size 91: 46,109 BAD (FFHFHH)
+Size 92: 46,110 GOOD (HHFFFF)
+Size 93: 47,112 BAD (FFHFHH)
+Size 94: 47,113 GOOD (HHFFFF)
+Size 95: 48,114 BAD (FFHFHH)
+Size 96: 48,115 GOOD (HHFFFF)
+Size 97: 49,116 BAD (FFHFHH)
+Size 98: 49,118 GOOD (HHFFFF)
+Size 99: 50,119 BAD (FFHFHH)
+Size 100: 50,120 GOOD (HHFFFF)
+
+Windows 8.1
+-----------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,4 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,10 GOOD (HHFFFF)
+Size 9: 5,11 BAD (FFHFHH)
+Size 10: 5,12 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,16 BAD (FFHFHH)
+Size 14: 7,17 GOOD (HHFFFF)
+Size 15: 8,18 BAD (FFHFHH)
+Size 16: 8,19 GOOD (HHFFFF)
+Size 17: 9,20 BAD (FFHFHH)
+Size 18: 9,22 GOOD (HHFFFF)
+Size 19: 10,23 BAD (FFHFHH)
+Size 20: 10,24 GOOD (HHFFFF)
+Size 21: 11,25 BAD (FFHFHH)
+Size 22: 11,26 GOOD (HHFFFF)
+Size 23: 12,28 BAD (FFHFHH)
+Size 24: 12,29 GOOD (HHFFFF)
+Size 25: 13,30 BAD (FFHFHH)
+Size 26: 13,31 GOOD (HHFFFF)
+Size 27: 14,32 BAD (FFHFHH)
+Size 28: 14,34 GOOD (HHFFFF)
+Size 29: 15,35 BAD (FFHFHH)
+Size 30: 15,36 GOOD (HHFFFF)
+Size 31: 16,37 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,40 BAD (FFHFHH)
+Size 34: 17,41 GOOD (HHFFFF)
+Size 35: 18,42 BAD (FFHFHH)
+Size 36: 18,43 GOOD (HHFFFF)
+Size 37: 19,44 BAD (FFHFHH)
+Size 38: 19,46 GOOD (HHFFFF)
+Size 39: 20,47 BAD (FFHFHH)
+Size 40: 20,48 GOOD (HHFFFF)
+Size 41: 21,49 BAD (FFHFHH)
+Size 42: 21,50 GOOD (HHFFFF)
+Size 43: 22,52 BAD (FFHFHH)
+Size 44: 22,53 GOOD (HHFFFF)
+Size 45: 23,54 BAD (FFHFHH)
+Size 46: 23,55 GOOD (HHFFFF)
+Size 47: 24,56 BAD (FFHFHH)
+Size 48: 24,58 GOOD (HHFFFF)
+Size 49: 25,59 BAD (FFHFHH)
+Size 50: 25,60 GOOD (HHFFFF)
+Size 51: 26,61 BAD (FFHFHH)
+Size 52: 26,62 GOOD (HHFFFF)
+Size 53: 27,64 BAD (FFHFHH)
+Size 54: 27,65 GOOD (HHFFFF)
+Size 55: 28,66 BAD (FFHFHH)
+Size 56: 28,67 GOOD (HHFFFF)
+Size 57: 29,68 BAD (FFHFHH)
+Size 58: 29,70 GOOD (HHFFFF)
+Size 59: 30,71 BAD (FFHFHH)
+Size 60: 30,72 GOOD (HHFFFF)
+Size 61: 31,73 BAD (FFHFHH)
+Size 62: 31,74 GOOD (HHFFFF)
+Size 63: 32,76 BAD (FFHFHH)
+Size 64: 32,77 GOOD (HHFFFF)
+Size 65: 33,78 BAD (FFHFHH)
+Size 66: 33,79 GOOD (HHFFFF)
+Size 67: 34,80 BAD (FFHFHH)
+Size 68: 34,82 GOOD (HHFFFF)
+Size 69: 35,83 BAD (FFHFHH)
+Size 70: 35,84 GOOD (HHFFFF)
+Size 71: 36,85 BAD (FFHFHH)
+Size 72: 36,86 GOOD (HHFFFF)
+Size 73: 37,88 BAD (FFHFHH)
+Size 74: 37,89 GOOD (HHFFFF)
+Size 75: 38,90 BAD (FFHFHH)
+Size 76: 38,91 GOOD (HHFFFF)
+Size 77: 39,92 BAD (FFHFHH)
+Size 78: 39,94 GOOD (HHFFFF)
+Size 79: 40,95 BAD (FFHFHH)
+Size 80: 40,96 GOOD (HHFFFF)
+Size 81: 41,97 BAD (FFHFHH)
+Size 82: 41,98 GOOD (HHFFFF)
+Size 83: 42,100 BAD (FFHFHH)
+Size 84: 42,101 GOOD (HHFFFF)
+Size 85: 43,102 BAD (FFHFHH)
+Size 86: 43,103 GOOD (HHFFFF)
+Size 87: 44,104 BAD (FFHFHH)
+Size 88: 44,106 GOOD (HHFFFF)
+Size 89: 45,107 BAD (FFHFHH)
+Size 90: 45,108 GOOD (HHFFFF)
+Size 91: 46,109 BAD (FFHFHH)
+Size 92: 46,110 GOOD (HHFFFF)
+Size 93: 47,112 BAD (FFHFHH)
+Size 94: 47,113 GOOD (HHFFFF)
+Size 95: 48,114 BAD (FFHFHH)
+Size 96: 48,115 GOOD (HHFFFF)
+Size 97: 49,116 BAD (FFHFHH)
+Size 98: 49,118 GOOD (HHFFFF)
+Size 99: 50,119 BAD (FFHFHH)
+Size 100: 50,120 GOOD (HHFFFF)
+
+Windows 10 14342 Old Console
+----------------------------
+
+Size 1: 1,2 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,4 BAD (FFHFHH)
+Size 4: 2,5 GOOD (HHFFFF)
+Size 5: 3,6 BAD (FFHFHH)
+Size 6: 3,7 GOOD (HHFFFF)
+Size 7: 4,8 BAD (FFHFHH)
+Size 8: 4,10 GOOD (HHFFFF)
+Size 9: 5,11 BAD (FFHFHH)
+Size 10: 5,12 GOOD (HHFFFF)
+Size 11: 6,13 BAD (FFHFHH)
+Size 12: 6,14 GOOD (HHFFFF)
+Size 13: 7,16 BAD (FFHFHH)
+Size 14: 7,17 GOOD (HHFFFF)
+Size 15: 8,18 BAD (FFHFHH)
+Size 16: 8,19 GOOD (HHFFFF)
+Size 17: 9,20 BAD (FFHFHH)
+Size 18: 9,22 GOOD (HHFFFF)
+Size 19: 10,23 BAD (FFHFHH)
+Size 20: 10,24 GOOD (HHFFFF)
+Size 21: 11,25 BAD (FFHFHH)
+Size 22: 11,26 GOOD (HHFFFF)
+Size 23: 12,28 BAD (FFHFHH)
+Size 24: 12,29 GOOD (HHFFFF)
+Size 25: 13,30 BAD (FFHFHH)
+Size 26: 13,31 GOOD (HHFFFF)
+Size 27: 14,32 BAD (FFHFHH)
+Size 28: 14,34 GOOD (HHFFFF)
+Size 29: 15,35 BAD (FFHFHH)
+Size 30: 15,36 GOOD (HHFFFF)
+Size 31: 16,37 BAD (FFHFHH)
+Size 32: 16,38 GOOD (HHFFFF)
+Size 33: 17,40 BAD (FFHFHH)
+Size 34: 17,41 GOOD (HHFFFF)
+Size 35: 18,42 BAD (FFHFHH)
+Size 36: 18,43 GOOD (HHFFFF)
+Size 37: 19,44 BAD (FFHFHH)
+Size 38: 19,46 GOOD (HHFFFF)
+Size 39: 20,47 BAD (FFHFHH)
+Size 40: 20,48 GOOD (HHFFFF)
+Size 41: 21,49 BAD (FFHFHH)
+Size 42: 21,50 GOOD (HHFFFF)
+Size 43: 22,52 BAD (FFHFHH)
+Size 44: 22,53 GOOD (HHFFFF)
+Size 45: 23,54 BAD (FFHFHH)
+Size 46: 23,55 GOOD (HHFFFF)
+Size 47: 24,56 BAD (FFHFHH)
+Size 48: 24,58 GOOD (HHFFFF)
+Size 49: 25,59 BAD (FFHFHH)
+Size 50: 25,60 GOOD (HHFFFF)
+Size 51: 26,61 BAD (FFHFHH)
+Size 52: 26,62 GOOD (HHFFFF)
+Size 53: 27,64 BAD (FFHFHH)
+Size 54: 27,65 GOOD (HHFFFF)
+Size 55: 28,66 BAD (FFHFHH)
+Size 56: 28,67 GOOD (HHFFFF)
+Size 57: 29,68 BAD (FFHFHH)
+Size 58: 29,70 GOOD (HHFFFF)
+Size 59: 30,71 BAD (FFHFHH)
+Size 60: 30,72 GOOD (HHFFFF)
+Size 61: 31,73 BAD (FFHFHH)
+Size 62: 31,74 GOOD (HHFFFF)
+Size 63: 32,76 BAD (FFHFHH)
+Size 64: 32,77 GOOD (HHFFFF)
+Size 65: 33,78 BAD (FFHFHH)
+Size 66: 33,79 GOOD (HHFFFF)
+Size 67: 34,80 BAD (FFHFHH)
+Size 68: 34,82 GOOD (HHFFFF)
+Size 69: 35,83 BAD (FFHFHH)
+Size 70: 35,84 GOOD (HHFFFF)
+Size 71: 36,85 BAD (FFHFHH)
+Size 72: 36,86 GOOD (HHFFFF)
+Size 73: 37,88 BAD (FFHFHH)
+Size 74: 37,89 GOOD (HHFFFF)
+Size 75: 38,90 BAD (FFHFHH)
+Size 76: 38,91 GOOD (HHFFFF)
+Size 77: 39,92 BAD (FFHFHH)
+Size 78: 39,94 GOOD (HHFFFF)
+Size 79: 40,95 BAD (FFHFHH)
+Size 80: 40,96 GOOD (HHFFFF)
+Size 81: 41,97 BAD (FFHFHH)
+Size 82: 41,98 GOOD (HHFFFF)
+Size 83: 42,100 BAD (FFHFHH)
+Size 84: 42,101 GOOD (HHFFFF)
+Size 85: 43,102 BAD (FFHFHH)
+Size 86: 43,103 GOOD (HHFFFF)
+Size 87: 44,104 BAD (FFHFHH)
+Size 88: 44,106 GOOD (HHFFFF)
+Size 89: 45,107 BAD (FFHFHH)
+Size 90: 45,108 GOOD (HHFFFF)
+Size 91: 46,109 BAD (FFHFHH)
+Size 92: 46,110 GOOD (HHFFFF)
+Size 93: 47,112 BAD (FFHFHH)
+Size 94: 47,113 GOOD (HHFFFF)
+Size 95: 48,114 BAD (FFHFHH)
+Size 96: 48,115 GOOD (HHFFFF)
+Size 97: 49,116 BAD (FFHFHH)
+Size 98: 49,118 GOOD (HHFFFF)
+Size 99: 50,119 BAD (FFHFHH)
+Size 100: 50,120 GOOD (HHFFFF)
+
+Windows 10 14342 New Console
+----------------------------
+
+Size 1: 1,1 GOOD (HHFFFF)
+Size 2: 1,2 GOOD (HHFFFF)
+Size 3: 2,3 GOOD (HHFFFF)
+Size 4: 2,4 GOOD (HHFFFF)
+Size 5: 3,5 GOOD (HHFFFF)
+Size 6: 3,6 GOOD (HHFFFF)
+Size 7: 4,7 GOOD (HHFFFF)
+Size 8: 4,8 GOOD (HHFFFF)
+Size 9: 5,9 GOOD (HHFFFF)
+Size 10: 5,10 GOOD (HHFFFF)
+Size 11: 6,11 GOOD (HHFFFF)
+Size 12: 6,12 GOOD (HHFFFF)
+Size 13: 7,13 GOOD (HHFFFF)
+Size 14: 7,14 GOOD (HHFFFF)
+Size 15: 8,15 GOOD (HHFFFF)
+Size 16: 8,16 GOOD (HHFFFF)
+Size 17: 9,17 GOOD (HHFFFF)
+Size 18: 9,18 GOOD (HHFFFF)
+Size 19: 10,19 GOOD (HHFFFF)
+Size 20: 10,20 GOOD (HHFFFF)
+Size 21: 11,21 GOOD (HHFFFF)
+Size 22: 11,22 GOOD (HHFFFF)
+Size 23: 12,23 GOOD (HHFFFF)
+Size 24: 12,24 GOOD (HHFFFF)
+Size 25: 13,25 GOOD (HHFFFF)
+Size 26: 13,26 GOOD (HHFFFF)
+Size 27: 14,27 GOOD (HHFFFF)
+Size 28: 14,28 GOOD (HHFFFF)
+Size 29: 15,29 GOOD (HHFFFF)
+Size 30: 15,30 GOOD (HHFFFF)
+Size 31: 16,31 GOOD (HHFFFF)
+Size 32: 16,32 GOOD (HHFFFF)
+Size 33: 17,33 GOOD (HHFFFF)
+Size 34: 17,34 GOOD (HHFFFF)
+Size 35: 18,35 GOOD (HHFFFF)
+Size 36: 18,36 GOOD (HHFFFF)
+Size 37: 19,37 GOOD (HHFFFF)
+Size 38: 19,38 GOOD (HHFFFF)
+Size 39: 20,39 GOOD (HHFFFF)
+Size 40: 20,40 GOOD (HHFFFF)
+Size 41: 21,41 GOOD (HHFFFF)
+Size 42: 21,42 GOOD (HHFFFF)
+Size 43: 22,43 GOOD (HHFFFF)
+Size 44: 22,44 GOOD (HHFFFF)
+Size 45: 23,45 GOOD (HHFFFF)
+Size 46: 23,46 GOOD (HHFFFF)
+Size 47: 24,47 GOOD (HHFFFF)
+Size 48: 24,48 GOOD (HHFFFF)
+Size 49: 25,49 GOOD (HHFFFF)
+Size 50: 25,50 GOOD (HHFFFF)
+Size 51: 26,51 GOOD (HHFFFF)
+Size 52: 26,52 GOOD (HHFFFF)
+Size 53: 27,53 GOOD (HHFFFF)
+Size 54: 27,54 GOOD (HHFFFF)
+Size 55: 28,55 GOOD (HHFFFF)
+Size 56: 28,56 GOOD (HHFFFF)
+Size 57: 29,57 GOOD (HHFFFF)
+Size 58: 29,58 GOOD (HHFFFF)
+Size 59: 30,59 GOOD (HHFFFF)
+Size 60: 30,60 GOOD (HHFFFF)
+Size 61: 31,61 GOOD (HHFFFF)
+Size 62: 31,62 GOOD (HHFFFF)
+Size 63: 32,63 GOOD (HHFFFF)
+Size 64: 32,64 GOOD (HHFFFF)
+Size 65: 33,65 GOOD (HHFFFF)
+Size 66: 33,66 GOOD (HHFFFF)
+Size 67: 34,67 GOOD (HHFFFF)
+Size 68: 34,68 GOOD (HHFFFF)
+Size 69: 35,69 GOOD (HHFFFF)
+Size 70: 35,70 GOOD (HHFFFF)
+Size 71: 36,71 GOOD (HHFFFF)
+Size 72: 36,72 GOOD (HHFFFF)
+Size 73: 37,73 GOOD (HHFFFF)
+Size 74: 37,74 GOOD (HHFFFF)
+Size 75: 38,75 GOOD (HHFFFF)
+Size 76: 38,76 GOOD (HHFFFF)
+Size 77: 39,77 GOOD (HHFFFF)
+Size 78: 39,78 GOOD (HHFFFF)
+Size 79: 40,79 GOOD (HHFFFF)
+Size 80: 40,80 GOOD (HHFFFF)
+Size 81: 41,81 GOOD (HHFFFF)
+Size 82: 41,82 GOOD (HHFFFF)
+Size 83: 42,83 GOOD (HHFFFF)
+Size 84: 42,84 GOOD (HHFFFF)
+Size 85: 43,85 GOOD (HHFFFF)
+Size 86: 43,86 GOOD (HHFFFF)
+Size 87: 44,87 GOOD (HHFFFF)
+Size 88: 44,88 GOOD (HHFFFF)
+Size 89: 45,89 GOOD (HHFFFF)
+Size 90: 45,90 GOOD (HHFFFF)
+Size 91: 46,91 GOOD (HHFFFF)
+Size 92: 46,92 GOOD (HHFFFF)
+Size 93: 47,93 GOOD (HHFFFF)
+Size 94: 47,94 GOOD (HHFFFF)
+Size 95: 48,95 GOOD (HHFFFF)
+Size 96: 48,96 GOOD (HHFFFF)
+Size 97: 49,97 GOOD (HHFFFF)
+Size 98: 49,98 GOOD (HHFFFF)
+Size 99: 50,99 GOOD (HHFFFF)
+Size 100: 50,100 GOOD (HHFFFF)
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt
new file mode 100644
index 0000000000..d5261d8db3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt
@@ -0,0 +1,16 @@
+The narrowest allowed console window, in pixels, on a conventional (~96dpi)
+monitor:
+
+(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 1 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
+
+(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 16 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
+
+ sz1:px sz1:col sz16:px sz16:col
+Vista: 124 104 137 10
+Windows 7: 132 112 147 11
+Windows 8: 140 120 147 11
+Windows 8.1: 140 120 147 11
+Windows 10 OLD: 136 116 147 11
+Windows 10 NEW: 136 103 136 10
+
+I used build 14342 to test Windows 10.
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt
new file mode 100644
index 0000000000..15a825cb51
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt
@@ -0,0 +1,4 @@
+As before, avoid odd sizes in favor of even sizes.
+
+It's curious that the Japanese font is handled so poorly, especially with
+Windows 8 and later.
diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt
new file mode 100644
index 0000000000..fef397a1e3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt
@@ -0,0 +1,144 @@
+Issues:
+
+ - Starting with the 14342 build, changing the font using
+ SetCurrentConsoleFontEx does not affect the window size. e.g. The content
+ itself will resize/redraw, but the window neither shrinks nor expands.
+ Presumably this is an oversight? It's almost a convenience; if a program
+ is going to resize the window anyway, then it's nice that the window size
+ contraints don't get in the way. Ordinarily, changing the font doesn't just
+ change the window size in pixels--it can also change the size as measured in
+ rows and columns.
+
+ - (Aside: in the 14342 build, there is also a bug with wmic.exe. Open a console
+ with more than 300 lines of screen buffer, then fill those lines with, e.g.,
+ dir /s. Then run wmic.exe. You won't be able to see the wmic.exe prompt.
+ If you query the screen buffer info somehow, you'll notice that the srWindow
+ is not contained within the dwSize. This breaks winpty's scraping, because
+ it's invalid.)
+
+ - In build 14316, with the Japanese locale, with the 437 code page, attempting
+ to set the Consolas font instead sets the Terminal (raster) font. It seems
+ to pick an appropriate vertical size.
+
+ - It seems necessary to specify "-family 0x36" for maximum reliability.
+ Setting the family to 0 almost always works, and specifying just -tt rarely
+ works.
+
+Win7
+ English locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 932 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt unreliable
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+
+Win10 Build 10586
+ New console
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+
+Win10 Build 14316
+ Old console
+ English locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 932 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selected very small Consolas font
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ New console
+ English locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt works
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 932 code page:
+ SetFont.exe -face Consolas -h 16 selects gothic instead
+ SetFont.exe -face Consolas -h 16 -tt selects gothic instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36(*) selects Terminal font instead
+
+Win10 Build 14342
+ Old Console
+ English locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 932 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ New console
+ English locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 works
+ SetFont.exe -face Consolas -h 16 -tt works
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+ Japanese locale / 932 code page:
+ SetFont.exe -face Consolas -h 16 selects gothic instead
+ SetFont.exe -face Consolas -h 16 -tt selects gothic instead
+ SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
+ Japanese locale / 437 code page:
+ SetFont.exe -face Consolas -h 16 selects Terminal font instead
+ SetFont.exe -face Consolas -h 16 -tt works
+ SetFont.exe -face Consolas -h 16 -family 0x36 works
+
+(*) I was trying to figure out whether the inconsistency was at when I stumbled
+onto this completely unexpected bug. Here's more detail:
+
+ F:\>SetFont.exe -face Consolas -h 16 -family 0x36 -weight normal -w 8
+ Setting to: nFont=0 dwFontSize=(8,16) FontFamily=0x36 FontWeight=400 FaceName="Consolas"
+ SetCurrentConsoleFontEx returned 1
+
+ F:\>GetFont.exe
+ largestConsoleWindowSize=(96,50)
+ maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ 00-00: 12x16
+ GetNumberOfConsoleFonts returned 0
+ CP=437 OutputCP=437
+
+ F:\>SetFont.exe -face "Lucida Console" -h 16 -family 0x36 -weight normal
+ Setting to: nFont=0 dwFontSize=(0,16) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
+ SetCurrentConsoleFontEx returned 1
+
+ F:\>GetFont.exe
+ largestConsoleWindowSize=(96,50)
+ maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ 00-00: 12x16
+ GetNumberOfConsoleFonts returned 0
+ CP=437 OutputCP=437
+
+ F:\>SetFont.exe -face "Lucida Console" -h 12 -family 0x36 -weight normal
+ Setting to: nFont=0 dwFontSize=(0,12) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
+ SetCurrentConsoleFontEx returned 1
+
+ F:\>GetFont.exe
+ largestConsoleWindowSize=(230,66)
+ maxWnd=0: nFont=0 dwFontSize=(5,12) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ maxWnd=1: nFont=0 dwFontSize=(116,36) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
+ 00-00: 5x12
+ GetNumberOfConsoleFonts returned 0
+ CP=437 OutputCP=437
+
+Even attempting to set to a Lucida Console / Consolas font from the Console
+properties dialog fails.
diff --git a/src/libs/3rdparty/winpty/misc/FontSurvey.cc b/src/libs/3rdparty/winpty/misc/FontSurvey.cc
new file mode 100644
index 0000000000..254bcc81a6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/FontSurvey.cc
@@ -0,0 +1,100 @@
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+
+#include "TestUtil.cc"
+
+#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
+
+// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
+const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
+const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
+const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
+const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
+
+std::vector<bool> condense(const std::vector<CHAR_INFO> &buf) {
+ std::vector<bool> ret;
+ size_t i = 0;
+ while (i < buf.size()) {
+ if (buf[i].Char.UnicodeChar == L' ' &&
+ ((buf[i].Attributes & 0x300) == 0)) {
+ // end of line
+ break;
+ } else if (i + 1 < buf.size() &&
+ ((buf[i].Attributes & 0x300) == 0x100) &&
+ ((buf[i + 1].Attributes & 0x300) == 0x200) &&
+ buf[i].Char.UnicodeChar != L' ' &&
+ buf[i].Char.UnicodeChar == buf[i + 1].Char.UnicodeChar) {
+ // double-width
+ ret.push_back(true);
+ i += 2;
+ } else if ((buf[i].Attributes & 0x300) == 0) {
+ // single-width
+ ret.push_back(false);
+ i++;
+ } else {
+ ASSERT(false && "unexpected output");
+ }
+ }
+ return ret;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ printf("Usage: %s \"arguments for SetFont.exe\"\n", argv[0]);
+ return 1;
+ }
+
+ const char *setFontArgs = argv[1];
+
+ const wchar_t testLine[] = { 0xA2, 0xA3, 0x2014, 0x3044, 0x30FC, 0x4000, 0 };
+ const HANDLE conout = openConout();
+
+ char setFontCmd[1024];
+ for (int h = 1; h <= 100; ++h) {
+ sprintf(setFontCmd, ".\\SetFont.exe %s -h %d && cls", setFontArgs, h);
+ system(setFontCmd);
+
+ CONSOLE_FONT_INFOEX infoex = {};
+ infoex.cbSize = sizeof(infoex);
+ BOOL success = GetCurrentConsoleFontEx(conout, FALSE, &infoex);
+ ASSERT(success && "GetCurrentConsoleFontEx failed");
+
+ DWORD actual = 0;
+ success = WriteConsoleW(conout, testLine, wcslen(testLine), &actual, nullptr);
+ ASSERT(success && actual == wcslen(testLine));
+
+ std::vector<CHAR_INFO> readBuf(14);
+ const SMALL_RECT readRegion = {0, 0, static_cast<short>(readBuf.size() - 1), 0};
+ SMALL_RECT readRegion2 = readRegion;
+ success = ReadConsoleOutputW(
+ conout, readBuf.data(),
+ {static_cast<short>(readBuf.size()), 1},
+ {0, 0},
+ &readRegion2);
+ ASSERT(success && !memcmp(&readRegion, &readRegion2, sizeof(readRegion)));
+
+ const auto widths = condense(readBuf);
+ std::string widthsStr;
+ for (bool width : widths) {
+ widthsStr.append(width ? "F" : "H");
+ }
+ char size[16];
+ sprintf(size, "%d,%d", infoex.dwFontSize.X, infoex.dwFontSize.Y);
+ const char *status = "";
+ if (widthsStr == "HHFFFF") {
+ status = "GOOD";
+ } else if (widthsStr == "HHHFFF") {
+ status = "OK";
+ } else {
+ status = "BAD";
+ }
+ trace("Size %3d: %-7s %-4s (%s)", h, size, status, widthsStr.c_str());
+ }
+ sprintf(setFontCmd, ".\\SetFont.exe %s -h 14", setFontArgs);
+ system(setFontCmd);
+}
diff --git a/src/libs/3rdparty/winpty/misc/FormatChar.h b/src/libs/3rdparty/winpty/misc/FormatChar.h
new file mode 100644
index 0000000000..aade488f9e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/FormatChar.h
@@ -0,0 +1,21 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+static inline void formatChar(char *str, char ch)
+{
+ // Print some common control codes.
+ switch (ch) {
+ case '\r': strcpy(str, "CR "); break;
+ case '\n': strcpy(str, "LF "); break;
+ case ' ': strcpy(str, "SP "); break;
+ case 27: strcpy(str, "^[ "); break;
+ case 3: strcpy(str, "^C "); break;
+ default:
+ if (isgraph(ch))
+ sprintf(str, "%c ", ch);
+ else
+ sprintf(str, "%02x ", ch);
+ break;
+ }
+}
diff --git a/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc b/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc
new file mode 100644
index 0000000000..2c0b0086a1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc
@@ -0,0 +1,62 @@
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+
+int main(int argc, char *argv[0]) {
+
+ if (argc != 2) {
+ printf("Usage: %s (mark|selectall|read)\n", argv[0]);
+ return 1;
+ }
+
+ enum class Test { Mark, SelectAll, Read } test;
+ if (!strcmp(argv[1], "mark")) {
+ test = Test::Mark;
+ } else if (!strcmp(argv[1], "selectall")) {
+ test = Test::SelectAll;
+ } else if (!strcmp(argv[1], "read")) {
+ test = Test::Read;
+ } else {
+ printf("Invalid test: %s\n", argv[1]);
+ return 1;
+ }
+
+ HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ TimeMeasurement tm;
+ HWND hwnd = GetConsoleWindow();
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(100, 3000);
+ system("cls");
+ setWindowPos(0, 2975, 100, 25);
+ setCursorPos(0, 2999);
+
+ ShowWindow(hwnd, SW_HIDE);
+
+ for (int i = 0; i < 1000; ++i) {
+ // CONSOLE_SCREEN_BUFFER_INFO info = {};
+ // GetConsoleScreenBufferInfo(conout, &info);
+
+ if (test == Test::Mark) {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
+ SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
+ } else if (test == Test::SelectAll) {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
+ SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
+ } else if (test == Test::Read) {
+ static CHAR_INFO buffer[100 * 3000];
+ const SMALL_RECT readRegion = {0, 0, 99, 2999};
+ SMALL_RECT tmp = readRegion;
+ BOOL ret = ReadConsoleOutput(conout, buffer, {100, 3000}, {0, 0}, &tmp);
+ ASSERT(ret && !memcmp(&tmp, &readRegion, sizeof(tmp)));
+ }
+ }
+
+ ShowWindow(hwnd, SW_SHOW);
+
+ printf("elapsed: %f\n", tm.elapsed());
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/GetCh.cc b/src/libs/3rdparty/winpty/misc/GetCh.cc
new file mode 100644
index 0000000000..cd6ed1943a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/GetCh.cc
@@ -0,0 +1,20 @@
+#include <conio.h>
+#include <ctype.h>
+#include <stdio.h>
+
+int main() {
+ printf("\nPress any keys -- Ctrl-D exits\n\n");
+
+ while (true) {
+ const int ch = getch();
+ printf("0x%x", ch);
+ if (isgraph(ch)) {
+ printf(" '%c'", ch);
+ }
+ printf("\n");
+ if (ch == 0x4) { // Ctrl-D
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/GetConsolePos.cc b/src/libs/3rdparty/winpty/misc/GetConsolePos.cc
new file mode 100644
index 0000000000..1f3cc5316f
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/GetConsolePos.cc
@@ -0,0 +1,41 @@
+#include <windows.h>
+
+#include <stdio.h>
+
+#include "TestUtil.cc"
+
+int main() {
+ const HANDLE conout = openConout();
+
+ CONSOLE_SCREEN_BUFFER_INFO info = {};
+ BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
+ ASSERT(ret && "GetConsoleScreenBufferInfo failed");
+
+ trace("cursor=%d,%d", info.dwCursorPosition.X, info.dwCursorPosition.Y);
+ printf("cursor=%d,%d\n", info.dwCursorPosition.X, info.dwCursorPosition.Y);
+
+ trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
+ printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
+
+ trace("dwSize=%d,%d", info.dwSize.X, info.dwSize.Y);
+ printf("dwSize=%d,%d\n", info.dwSize.X, info.dwSize.Y);
+
+ const HWND hwnd = GetConsoleWindow();
+ if (hwnd != NULL) {
+ RECT r = {};
+ if (GetWindowRect(hwnd, &r)) {
+ const int w = r.right - r.left;
+ const int h = r.bottom - r.top;
+ trace("hwnd: pos=(%d,%d) size=(%d,%d)", r.left, r.top, w, h);
+ printf("hwnd: pos=(%d,%d) size=(%d,%d)\n", r.left, r.top, w, h);
+ } else {
+ trace("GetWindowRect failed");
+ printf("GetWindowRect failed\n");
+ }
+ } else {
+ trace("GetConsoleWindow returned NULL");
+ printf("GetConsoleWindow returned NULL\n");
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/GetFont.cc b/src/libs/3rdparty/winpty/misc/GetFont.cc
new file mode 100644
index 0000000000..38625317ab
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/GetFont.cc
@@ -0,0 +1,261 @@
+#include <windows.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+#include "../src/shared/OsModule.h"
+#include "../src/shared/StringUtil.h"
+
+#include "TestUtil.cc"
+#include "../src/shared/StringUtil.cc"
+
+#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
+
+// Some of these types and functions are missing from the MinGW headers.
+// Others are undocumented.
+
+struct AGENT_CONSOLE_FONT_INFO {
+ DWORD nFont;
+ COORD dwFontSize;
+};
+
+struct AGENT_CONSOLE_FONT_INFOEX {
+ ULONG cbSize;
+ DWORD nFont;
+ COORD dwFontSize;
+ UINT FontFamily;
+ UINT FontWeight;
+ WCHAR FaceName[LF_FACESIZE];
+};
+
+// undocumented XP API
+typedef BOOL WINAPI SetConsoleFont_t(
+ HANDLE hOutput,
+ DWORD dwFontIndex);
+
+// undocumented XP API
+typedef DWORD WINAPI GetNumberOfConsoleFonts_t();
+
+// XP and up
+typedef BOOL WINAPI GetCurrentConsoleFont_t(
+ HANDLE hOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont);
+
+// XP and up
+typedef COORD WINAPI GetConsoleFontSize_t(
+ HANDLE hConsoleOutput,
+ DWORD nFont);
+
+// Vista and up
+typedef BOOL WINAPI GetCurrentConsoleFontEx_t(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
+
+// Vista and up
+typedef BOOL WINAPI SetCurrentConsoleFontEx_t(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
+
+#define GET_MODULE_PROC(mod, funcName) \
+ m_##funcName = reinterpret_cast<funcName##_t*>((mod).proc(#funcName)); \
+
+#define DEFINE_ACCESSOR(funcName) \
+ funcName##_t &funcName() const { \
+ ASSERT(valid()); \
+ return *m_##funcName; \
+ }
+
+class XPFontAPI {
+public:
+ XPFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont);
+ GET_MODULE_PROC(m_kernel32, GetConsoleFontSize);
+ }
+
+ bool valid() const {
+ return m_GetCurrentConsoleFont != NULL &&
+ m_GetConsoleFontSize != NULL;
+ }
+
+ DEFINE_ACCESSOR(GetCurrentConsoleFont)
+ DEFINE_ACCESSOR(GetConsoleFontSize)
+
+private:
+ OsModule m_kernel32;
+ GetCurrentConsoleFont_t *m_GetCurrentConsoleFont;
+ GetConsoleFontSize_t *m_GetConsoleFontSize;
+};
+
+class UndocumentedXPFontAPI : public XPFontAPI {
+public:
+ UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, SetConsoleFont);
+ GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts);
+ }
+
+ bool valid() const {
+ return this->XPFontAPI::valid() &&
+ m_SetConsoleFont != NULL &&
+ m_GetNumberOfConsoleFonts != NULL;
+ }
+
+ DEFINE_ACCESSOR(SetConsoleFont)
+ DEFINE_ACCESSOR(GetNumberOfConsoleFonts)
+
+private:
+ OsModule m_kernel32;
+ SetConsoleFont_t *m_SetConsoleFont;
+ GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts;
+};
+
+class VistaFontAPI : public XPFontAPI {
+public:
+ VistaFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx);
+ GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx);
+ }
+
+ bool valid() const {
+ return this->XPFontAPI::valid() &&
+ m_GetCurrentConsoleFontEx != NULL &&
+ m_SetCurrentConsoleFontEx != NULL;
+ }
+
+ DEFINE_ACCESSOR(GetCurrentConsoleFontEx)
+ DEFINE_ACCESSOR(SetCurrentConsoleFontEx)
+
+private:
+ OsModule m_kernel32;
+ GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx;
+ SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx;
+};
+
+static std::vector<std::pair<DWORD, COORD> > readFontTable(
+ XPFontAPI &api, HANDLE conout, DWORD maxCount) {
+ std::vector<std::pair<DWORD, COORD> > ret;
+ for (DWORD i = 0; i < maxCount; ++i) {
+ COORD size = api.GetConsoleFontSize()(conout, i);
+ if (size.X == 0 && size.Y == 0) {
+ break;
+ }
+ ret.push_back(std::make_pair(i, size));
+ }
+ return ret;
+}
+
+static void dumpFontTable(HANDLE conout) {
+ const int kMaxCount = 1000;
+ XPFontAPI api;
+ if (!api.valid()) {
+ printf("dumpFontTable: cannot dump font table -- missing APIs\n");
+ return;
+ }
+ std::vector<std::pair<DWORD, COORD> > table =
+ readFontTable(api, conout, kMaxCount);
+ std::string line;
+ char tmp[128];
+ size_t first = 0;
+ while (first < table.size()) {
+ size_t last = std::min(table.size() - 1, first + 10 - 1);
+ winpty_snprintf(tmp, "%02u-%02u:",
+ static_cast<unsigned>(first), static_cast<unsigned>(last));
+ line = tmp;
+ for (size_t i = first; i <= last; ++i) {
+ if (i % 10 == 5) {
+ line += " - ";
+ }
+ winpty_snprintf(tmp, " %2dx%-2d",
+ table[i].second.X, table[i].second.Y);
+ line += tmp;
+ }
+ printf("%s\n", line.c_str());
+ first = last + 1;
+ }
+ if (table.size() == kMaxCount) {
+ printf("... stopped reading at %d fonts ...\n", kMaxCount);
+ }
+}
+
+static std::string stringToCodePoints(const std::wstring &str) {
+ std::string ret = "(";
+ for (size_t i = 0; i < str.size(); ++i) {
+ char tmp[32];
+ winpty_snprintf(tmp, "%X", str[i]);
+ if (ret.size() > 1) {
+ ret.push_back(' ');
+ }
+ ret += tmp;
+ }
+ ret.push_back(')');
+ return ret;
+}
+
+static void dumpFontInfoEx(
+ const AGENT_CONSOLE_FONT_INFOEX &infoex) {
+ std::wstring faceName(infoex.FaceName,
+ winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName)));
+ cprintf(L"nFont=%u dwFontSize=(%d,%d) "
+ "FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n",
+ static_cast<unsigned>(infoex.nFont),
+ infoex.dwFontSize.X, infoex.dwFontSize.Y,
+ infoex.FontFamily, infoex.FontWeight, faceName.c_str(),
+ stringToCodePoints(faceName).c_str());
+}
+
+static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) {
+ AGENT_CONSOLE_FONT_INFOEX infoex = {0};
+ infoex.cbSize = sizeof(infoex);
+ if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) {
+ printf("GetCurrentConsoleFontEx call failed\n");
+ return;
+ }
+ dumpFontInfoEx(infoex);
+}
+
+static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) {
+ AGENT_CONSOLE_FONT_INFO info = {0};
+ if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) {
+ printf("GetCurrentConsoleFont call failed\n");
+ return;
+ }
+ printf("nFont=%u dwFontSize=(%d,%d)\n",
+ static_cast<unsigned>(info.nFont),
+ info.dwFontSize.X, info.dwFontSize.Y);
+}
+
+static void dumpFontAndTable(HANDLE conout) {
+ VistaFontAPI vista;
+ if (vista.valid()) {
+ printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE);
+ printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE);
+ dumpFontTable(conout);
+ return;
+ }
+ UndocumentedXPFontAPI xp;
+ if (xp.valid()) {
+ printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE);
+ printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE);
+ dumpFontTable(conout);
+ return;
+ }
+ printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n");
+ dumpFontTable(conout);
+}
+
+int main() {
+ const HANDLE conout = openConout();
+ const COORD largest = GetLargestConsoleWindowSize(conout);
+ printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y);
+ dumpFontAndTable(conout);
+ UndocumentedXPFontAPI xp;
+ if (xp.valid()) {
+ printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()());
+ } else {
+ printf("The GetNumberOfConsoleFonts API was missing\n");
+ }
+ printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP());
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1 b/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1
new file mode 100644
index 0000000000..0c488597bd
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1
@@ -0,0 +1,51 @@
+#
+# Usage: powershell <path>\IdentifyConsoleWindow.ps1
+#
+# This script determines whether the process has a console attached, whether
+# that console has a non-NULL window (e.g. HWND), and whether the window is on
+# the current window station.
+#
+
+$signature = @'
+[DllImport("kernel32.dll", SetLastError=true)]
+public static extern IntPtr GetConsoleWindow();
+
+[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
+public static extern bool SetConsoleTitle(String title);
+
+[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
+public static extern int GetWindowText(IntPtr hWnd,
+ System.Text.StringBuilder lpString,
+ int nMaxCount);
+'@
+
+$WinAPI = Add-Type -MemberDefinition $signature `
+ -Name WinAPI -Namespace IdentifyConsoleWindow -PassThru
+
+if (!$WinAPI::SetConsoleTitle("ConsoleWindowScript")) {
+ echo "error: could not change console title -- is a console attached?"
+ exit 1
+} else {
+ echo "note: successfully set console title to ""ConsoleWindowScript""."
+}
+
+$hwnd = $WinAPI::GetConsoleWindow()
+if ($hwnd -eq 0) {
+ echo "note: GetConsoleWindow returned NULL."
+} else {
+ echo "note: GetConsoleWindow returned 0x$($hwnd.ToString("X"))."
+ $sb = New-Object System.Text.StringBuilder -ArgumentList 4096
+ if ($WinAPI::GetWindowText($hwnd, $sb, $sb.Capacity)) {
+ $title = $sb.ToString()
+ echo "note: GetWindowText returned ""${title}""."
+ if ($title -eq "ConsoleWindowScript") {
+ echo "success!"
+ } else {
+ echo "error: expected to see ""ConsoleWindowScript""."
+ echo " (Perhaps the console window is on a different window station?)"
+ }
+ } else {
+ echo "error: GetWindowText could not read the window title."
+ echo " (Perhaps the console window is on a different window station?)"
+ }
+}
diff --git a/src/libs/3rdparty/winpty/misc/IsNewConsole.cc b/src/libs/3rdparty/winpty/misc/IsNewConsole.cc
new file mode 100644
index 0000000000..2b554c72c9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/IsNewConsole.cc
@@ -0,0 +1,87 @@
+// Determines whether this is a new console by testing whether MARK moves the
+// cursor.
+//
+// WARNING: This test program may behave erratically if run under winpty.
+//
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "TestUtil.cc"
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+
+static COORD getWindowPos(HANDLE conout) {
+ CONSOLE_SCREEN_BUFFER_INFO info = {};
+ BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
+ ASSERT(ret && "GetConsoleScreenBufferInfo failed");
+ return { info.srWindow.Left, info.srWindow.Top };
+}
+
+static COORD getWindowSize(HANDLE conout) {
+ CONSOLE_SCREEN_BUFFER_INFO info = {};
+ BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
+ ASSERT(ret && "GetConsoleScreenBufferInfo failed");
+ return {
+ static_cast<short>(info.srWindow.Right - info.srWindow.Left + 1),
+ static_cast<short>(info.srWindow.Bottom - info.srWindow.Top + 1)
+ };
+}
+
+static COORD getCursorPos(HANDLE conout) {
+ CONSOLE_SCREEN_BUFFER_INFO info = {};
+ BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
+ ASSERT(ret && "GetConsoleScreenBufferInfo failed");
+ return info.dwCursorPosition;
+}
+
+static void setCursorPos(HANDLE conout, COORD pos) {
+ BOOL ret = SetConsoleCursorPosition(conout, pos);
+ ASSERT(ret && "SetConsoleCursorPosition failed");
+}
+
+int main() {
+ const HANDLE conout = openConout();
+ const HWND hwnd = GetConsoleWindow();
+ ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL");
+
+ // With the legacy console, the Mark command moves the the cursor to the
+ // top-left cell of the visible console window. Determine whether this
+ // is the new console by seeing if the cursor moves.
+
+ const auto windowSize = getWindowSize(conout);
+ if (windowSize.X <= 1) {
+ printf("Error: console window must be at least 2 columns wide\n");
+ trace("Error: console window must be at least 2 columns wide");
+ return 1;
+ }
+
+ bool cursorMoved = false;
+ const auto initialPos = getCursorPos(conout);
+
+ const auto windowPos = getWindowPos(conout);
+ setCursorPos(conout, { static_cast<short>(windowPos.X + 1), windowPos.Y });
+
+ {
+ const auto posA = getCursorPos(conout);
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
+ const auto posB = getCursorPos(conout);
+ cursorMoved = memcmp(&posA, &posB, sizeof(posA)) != 0;
+ SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE
+ }
+
+ setCursorPos(conout, initialPos);
+
+ if (cursorMoved) {
+ printf("Legacy console (i.e. MARK moved cursor)\n");
+ trace("Legacy console (i.e. MARK moved cursor)");
+ } else {
+ printf("Windows 10 new console (i.e MARK did not move cursor)\n");
+ trace("Windows 10 new console (i.e MARK did not move cursor)");
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt b/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt
new file mode 100644
index 0000000000..18460c6861
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt
@@ -0,0 +1,90 @@
+Introduction
+============
+
+The only specification I could find describing mouse input escape sequences
+was the /usr/share/doc/xterm/ctlseqs.txt.gz file installed on my Ubuntu
+machine.
+
+Here are the relevant escape sequences:
+
+ * [ON] CSI '?' M 'h' Enable mouse input mode M
+ * [OFF] CSI '?' M 'l' Disable mouse input mode M
+ * [EVT] CSI 'M' F X Y Mouse event (default or mode 1005)
+ * [EVT6] CSI '<' F ';' X ';' Y 'M' Mouse event with mode 1006
+ * [EVT6] CSI '<' F ';' X ';' Y 'm' Mouse event with mode 1006 (up)
+ * [EVT15] CSI F ';' X ';' Y 'M' Mouse event with mode 1015
+
+The first batch of modes affect what events are reported:
+
+ * 9: Presses only (not as well-supported as the other modes)
+ * 1000: Presses and releases
+ * 1002: Presses, releases, and moves-while-pressed
+ * 1003: Presses, releases, and all moves
+
+The next batch of modes affect the encoding of the mouse events:
+
+ * 1005: The X and Y coordinates are UTF-8 codepoints rather than bytes.
+ * 1006: Use the EVT6 sequences instead of EVT
+ * 1015: Use the EVT15 sequence instead of EVT (aka URVXT-mode)
+
+Support for modes in existing terminals
+=======================================
+
+ | 9 1000 1002 1003 | 1004 | overflow | defhi | 1005 1006 1015
+---------------------------------+---------------------+------+--------------+-------+----------------
+Eclipse TM Terminal (Neon) | _ _ _ _ | _ | n/a | n/a | _ _ _
+gnome-terminal 3.6.2 | X X X X | _ | suppressed*b | 0x07 | _ X X
+iTerm2 2.1.4 | _ X X X | OI | wrap*z | n/a | X X X
+jediterm/IntelliJ | _ X X X | _ | ch='?' | 0xff | X X X
+Konsole 2.13.2 | _ X X *a | _ | suppressed | 0xff | X X X
+mintty 2.2.2 | X X X X | OI | ch='\0' | 0xff | X X X
+putty 0.66 | _ X X _ | _ | suppressed | 0xff | _ X X
+rxvt 2.7.10 | X X _ _ | _ | wrap*z | n/a | _ _ _
+screen(under xterm) | X X X X | _ | suppressed | 0xff | _ _ _
+urxvt 9.21 | X X X X | _ | wrap*z | n/a | X _ X
+xfce4-terminal 0.6.3 (GTK2 VTE) | X X X X | _ | wrap | n/a | _ _ _
+xterm | X X X X | OI | ch='\0' | 0xff | X X X
+
+*a: Mode 1003 is handled the same way as 1002.
+*b: The coordinate wraps from 0xff to 0x00, then maxs out at 0x07. I'm
+ guessing this behavior is a bug? I'm using the Xubuntu 14.04
+ gnome-terminal.
+*z: These terminals have a bug where column 224 (and row 224, presumably)
+ yields a truncated escape sequence. 224 + 32 is 0, so it would normally
+ yield `CSI 'M' F '\0' Y`, but the '\0' is interpreted as a NUL-terminator.
+
+Problem 1: How do these flags work?
+===================================
+
+Terminals accept the OFF sequence with any of the input modes. This makes
+little sense--there are two multi-value settings, not seven independent flags!
+
+All the terminals handle Granularity the same way. ON-Granularity sets
+Granularity to the specified value, and OFF-Granularity sets Granularity to
+OFF.
+
+Terminals vary in how they handle the Encoding modes. For example:
+
+ * xterm. ON-Encoding sets Encoding. OFF-Encoding with a non-active Encoding
+ has no effect. OFF-Encoding otherwise resets Encoding to Default.
+
+ * mintty (tested 2.2.2), iTerm2 2.1.4, and jediterm. ON-Encoding sets
+ Encoding. OFF-Encoding resets Encoding to Default.
+
+ * Konsole (tested 2.13.2) seems to configure each encoding method
+ independently. The effective Encoding is the first enabled encoding in this
+ list:
+ - Mode 1006
+ - Mode 1015
+ - Mode 1005
+ - Default
+
+ * gnome-terminal (tested 3.6.2) also configures each encoding method
+ independently. The effective Encoding is the first enabled encoding in
+ this list:
+ - Mode 1006
+ - Mode 1015
+ - Default
+ Mode 1005 is not supported.
+
+ * xfce4 terminal 0.6.3 (GTK2 VTE) always outputs the default encoding method.
diff --git a/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc b/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc
new file mode 100644
index 0000000000..7d9684fe94
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc
@@ -0,0 +1,34 @@
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc != 3 && argc != 5) {
+ printf("Usage: %s x y\n", argv[0]);
+ printf("Usage: %s x y width height\n", argv[0]);
+ return 1;
+ }
+
+ HWND hwnd = GetConsoleWindow();
+
+ const int x = atoi(argv[1]);
+ const int y = atoi(argv[2]);
+
+ int w = 0, h = 0;
+ if (argc == 3) {
+ RECT r = {};
+ BOOL ret = GetWindowRect(hwnd, &r);
+ ASSERT(ret && "GetWindowRect failed on console window");
+ w = r.right - r.left;
+ h = r.bottom - r.top;
+ } else {
+ w = atoi(argv[3]);
+ h = atoi(argv[4]);
+ }
+
+ BOOL ret = MoveWindow(hwnd, x, y, w, h, TRUE);
+ trace("MoveWindow: ret=%d", ret);
+ printf("MoveWindow: ret=%d\n", ret);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Notes.txt b/src/libs/3rdparty/winpty/misc/Notes.txt
new file mode 100644
index 0000000000..410e184198
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Notes.txt
@@ -0,0 +1,219 @@
+Test programs
+-------------
+
+Cygwin
+ emacs
+ vim
+ mc (Midnight Commander)
+ lynx
+ links
+ less
+ more
+ wget
+
+Capturing the console output
+----------------------------
+
+Initial idea:
+
+In the agent, keep track of the remote terminal state for N lines of
+(window+history). Also keep track of the terminal size. Regularly poll for
+changes to the console screen buffer, then use some number of edits to bring
+the remote terminal into sync with the console.
+
+This idea seems to have trouble when a Unix terminal is resized. When the
+server receives a resize notification, it can have a hard time figuring out
+what the terminal did. Race conditions might also be a problem.
+
+The behavior of the terminal can be tricky:
+
+ - When the window is expanded by one line, does the terminal add a blank line
+ to the bottom or move a line from the history into the top?
+
+ - When the window is shrunk by one line, does the terminal delete the topmost
+ or the bottommost line? Can it delete the line with the cursor?
+
+Some popular behaviors for expanding:
+ - [all] If there are no history lines, then add a line at the bottom.
+ - [konsole] Always add a line at the bottom.
+ - [putty,xterm,rxvt] Pull in a history line from the top.
+ - [g-t] I can't tell. It seems to add a blank line, until the program writes
+ to stdout or until I click the scroll bar, then the output "snaps" back down,
+ pulling lines out of the history. I thought I saw different behavior
+ between Ubuntu 10.10 and 11.10, so maybe GNOME 3 changed something. Avoid
+ using "bash" to test this behavior because "bash" apparently always writes
+ the prompt after terminal resize.
+
+Some popular behaviors for shrinking:
+ - [konsole,putty,xterm,rxvt] If the line at the bottom is blank, then delete
+ it. Otherwise, move the topmost line into history.
+ - [g-t] If the line at the bottom has not been touched, then delete it.
+ Otherwise, move the topmost line into history.
+
+(TODO: I need to test my theories about the terminal behavior better still.
+It's interesting to see how g-t handles clear differently than every other
+terminal.)
+
+There is an ANSI escape sequence (DSR) that sends the current cursor location
+to the terminal's input. One idea I had was to use this code to figure out how
+the terminal had handled a resize. I currently think this idea won't work due
+to race conditions.
+
+Newer idea:
+
+Keep track of the last N lines that have been sent to the remote terminal.
+Poll for changes to console output. When the output changes, send just the
+changed content to the terminal. In particular:
+ - Don't send a cursor position (CUP) code. Instead, if the line that's 3
+ steps up from the latest line changes, send a relative cursor up (CUU)
+ code. It's OK to send an absolute column number code (CHA).
+ - At least in general, don't try to send complete screenshots of the current
+ console window.
+
+The idea is that sending just the changes should have good behavior for streams
+of output, even when those streams modify the output (e.g. an archiver, or
+maybe a downloader/packager/wget). I need to think about whether this works
+for full-screen programs (e.g. emacs, less, lynx, the above list of programs).
+
+I noticed that console programs don't typically modify the window or buffer
+coordinates. edit.com is an exception.
+
+I tested the pager in native Python (more?), and I verified that ENTER and SPACE
+both paid no attention to the location of the console window within the screen
+buffer. This makes sense -- why would they care? The Cygwin less, on the other
+hand, does care. If I scroll the window up, then Cygwin less will write to a
+position within the window. I didn't really expect this behavior, but it
+doesn't seem to be a problem.
+
+Setting up a TestNetServer service
+----------------------------------
+
+First run the deploy.sh script to copy files into deploy. Make sure
+TestNetServer.exe will run in a bare environment (no MinGW or Qt in the path).
+
+Install the Windows Server 2003 Resource Kit. It will have two programs in it,
+instsrv and srvany.
+
+Run:
+
+ InstSrv TestNetServer <path-to-srvany>\srvany.exe
+
+This creates a service named "TestNetServer" that uses the Microsoft service
+wrapper. To configure the new service to run TestNetServer, set a registry
+value:
+
+ [HKLM\SYSTEM\CurrentControlSet\Services\TestNetServer\Parameters]
+ Application=<full-path>\TestNetServer.exe
+
+Also see http://www.iopus.com/guides/srvany.htm.
+
+To remove the service, run:
+
+ InstSrv TestNetServer REMOVE
+
+TODO
+----
+
+Agent: When resizing the console, consider whether to add lines to the top
+or bottom. I remember thinking the current behavior was wrong for some
+application, but I forgot which one.
+
+Make the font as small as possible. The console window dimensions are limited by
+the screen size, so making the font small reduces an unnecessary limitation on the
+PseudoConsole size. There's a documented Vista/Win7 API for this
+(SetCurrentConsoleFontEx), and apparently WinXP has an undocumented API
+(SetConsoleFont):
+ http://blogs.microsoft.co.il/blogs/pavely/archive/2009/07/23/changing-console-fonts.aspx
+
+Make the agent work with DOS programs like edit and qbasic.
+ - Detect that the terminal program has resized the window/buffer and enter a
+ simple just-scrape-and-dont-resize mode. Track the client window size and
+ send the intersection of the console and the agent's client.
+ - I also need to generate keyboard scan codes.
+ - Solve the NTVDM.EXE console shutdown problem, probably by ignoring NTVDM.EXE
+ when it appears on the GetConsoleProcessList list.
+
+Rename the agent? Is the term "proxy" more accurate?
+
+Optimize the polling. e.g. Use a longer poll interval when the console is idle.
+Do a minimal poll that checks whether the sync marker or window has moved.
+
+Increase the console buffer size to ~9000 lines. Beware making it so big that
+reading the sync column exhausts the 32KB conhost<->agent heap.
+
+Reduce the memory overhead of the agent. The agent's m_bufferData array can
+be small (a few hundred lines?) relative to the console buffer size.
+
+Try to handle console background color better.
+ Unix terminal emulators have a user-configurable foreground and background
+color, and for best results, the agent really needs to avoid changing the colors,
+especially the background color. It's undesirable/ugly to SSH into a machine
+and see the command prompt change the colors. It's especially ugly that the
+terminal retains its original colors and only drawn cells get the new colors.
+(e.g. Resizing the window to the right uses the local terminal colors rather
+than the remote colors.) It's especially ugly in gnome-terminal, which draws
+user-configurable black as black, but VT100 black as dark-gray.
+ If there were a way to query the terminal emulator's colors, then I could
+match the console's colors to the terminal and everything would just work. As
+far as I know, that's not possible.
+ I thought of a kludge that might work. Instead of translating console white
+and black to VT/100 white and black, I would translate them to "reset" and
+"invert". I'd translate other colors normally. This approach should produce
+ideal results for command-line work and tolerable results for full-screen
+programs without configuration. Configuring the agent for black-on-white or
+white-on-black would produce ideal results in all situations.
+ This kludge only really applies to the SSH application. For a Win32 Konsole
+application, it should be easy to get the colors right all the time.
+
+Try using the screen reader API:
+ - To eliminate polling.
+ - To detect when a line wraps. When a line wraps, it'd be nice not to send a
+ CRLF to the terminal emulator so copy-and-paste works better.
+ - To detect hard tabs with Cygwin.
+
+Implement VT100/ANSI escape sequence recognition for input. Decide where this
+functionality belongs. PseudoConsole.dll? Disambiguating ESC from an escape
+sequence might be tricky. For the SSH server, I was thinking that when a small
+SSH payload ended with an ESC character, I could assume the character was really
+an ESC keypress, on the assumption that if it were an escape sequence, the
+payload would probably contain the whole sequence. I'm not sure this works,
+especially if there's a lot of other traffic multiplexed on the SSH socket.
+
+Support Unicode.
+ - Some DOS programs draw using line/box characters. Can these characters be
+ translated to the Unicode equivalents?
+
+Create automated tests.
+
+Experiment with the Terminator emulator, an emulator that doesn't wrap lines.
+How many columns does it report having? What column does it report the cursor
+in as it's writing past the right end of the window? Will Terminator be a
+problem if I implement line wrapping detection in the agent?
+
+BUG: After the unix-adapter/pconsole.exe program exits, the blinking cursor is
+replaced with a hidden cursor.
+
+Fix assert() in the agent. If it fails, the failure message needs to be
+reported somewhere. Pop up a dialog box? Maybe switch the active desktop,
+then show a dialog box?
+
+TODO: There's already a pconsole project on GitHub. Maybe rename this project
+to something else? winpty?
+
+TODO: Can the DebugServer system be replaced with OutputDebugString? How
+do we decide whose processes' output to collect?
+
+TODO: Three executables:
+ build/winpty-agent.exe
+ build/winpty.dll
+ build/console.exe
+
+BUG: Run the pconsole.exe inside another console. As I type dir, I see this:
+ D:\rprichard\pconsole>
+ D:\rprichard\pconsole>d
+ D:\rprichard\pconsole>di
+ D:\rprichard\pconsole>dir
+ In the output of "dir", every other line is blank.
+ There was a bug in Terminal::sendLine that was causing this to happen
+ frequently. Now that I fixed it, this bug should only manifest on lines
+ whose last column is not a space (i.e. a full line).
diff --git a/src/libs/3rdparty/winpty/misc/OSVersion.cc b/src/libs/3rdparty/winpty/misc/OSVersion.cc
new file mode 100644
index 0000000000..456708f05b
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/OSVersion.cc
@@ -0,0 +1,27 @@
+#include <windows.h>
+
+#include <assert.h>
+#include <locale.h>
+#include <stdio.h>
+
+#include <iostream>
+
+int main() {
+ setlocale(LC_ALL, "");
+
+ OSVERSIONINFOEXW info = {0};
+ info.dwOSVersionInfoSize = sizeof(info);
+ assert(GetVersionExW((OSVERSIONINFOW*)&info));
+
+ printf("dwMajorVersion = %d\n", (int)info.dwMajorVersion);
+ printf("dwMinorVersion = %d\n", (int)info.dwMinorVersion);
+ printf("dwBuildNumber = %d\n", (int)info.dwBuildNumber);
+ printf("dwPlatformId = %d\n", (int)info.dwPlatformId);
+ printf("szCSDVersion = %ls\n", info.szCSDVersion);
+ printf("wServicePackMajor = %d\n", info.wServicePackMajor);
+ printf("wServicePackMinor = %d\n", info.wServicePackMinor);
+ printf("wSuiteMask = 0x%x\n", (unsigned int)info.wSuiteMask);
+ printf("wProductType = 0x%x\n", (unsigned int)info.wProductType);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc
new file mode 100644
index 0000000000..656d4f126d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc
@@ -0,0 +1,101 @@
+//
+// Verify that console selection blocks writes to an inactive console screen
+// buffer. Writes TEST PASSED or TEST FAILED to the popup console window.
+//
+
+#include <windows.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "TestUtil.cc"
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+
+bool g_useMark = false;
+
+CALLBACK DWORD pausingThread(LPVOID dummy)
+{
+ HWND hwnd = GetConsoleWindow();
+ trace("Sending selection to freeze");
+ SendMessage(hwnd, WM_SYSCOMMAND,
+ g_useMark ? SC_CONSOLE_MARK :
+ SC_CONSOLE_SELECT_ALL,
+ 0);
+ Sleep(1000);
+ trace("Sending escape WM_CHAR to unfreeze");
+ SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
+ Sleep(1000);
+}
+
+static HANDLE createBuffer() {
+ HANDLE buf = CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL);
+ ASSERT(buf != INVALID_HANDLE_VALUE);
+ return buf;
+}
+
+static void runTest(bool useMark, bool createEarly) {
+ trace("=======================================");
+ trace("useMark=%d createEarly=%d", useMark, createEarly);
+ g_useMark = useMark;
+ HANDLE buf = INVALID_HANDLE_VALUE;
+
+ if (createEarly) {
+ buf = createBuffer();
+ }
+
+ CreateThread(NULL, 0,
+ pausingThread, NULL,
+ 0, NULL);
+ Sleep(500);
+
+ if (!createEarly) {
+ trace("Creating buffer");
+ TimeMeasurement tm1;
+ buf = createBuffer();
+ const double elapsed1 = tm1.elapsed();
+ if (elapsed1 >= 0.250) {
+ printf("!!! TEST FAILED !!!\n");
+ Sleep(2000);
+ return;
+ }
+ }
+
+ trace("Writing to aux buffer");
+ TimeMeasurement tm2;
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleW(buf, L"HI", 2, &actual, NULL);
+ const double elapsed2 = tm2.elapsed();
+ trace("Writing to aux buffer: finished: ret=%d actual=%d (elapsed=%1.3f)", ret, actual, elapsed2);
+ if (elapsed2 < 0.250) {
+ printf("!!! TEST FAILED !!!\n");
+ } else {
+ printf("TEST PASSED\n");
+ }
+ Sleep(2000);
+}
+
+int main(int argc, char **argv) {
+ if (argc == 1) {
+ startChildProcess(L"child");
+ return 0;
+ }
+
+ std::string arg = argv[1];
+ if (arg == "child") {
+ for (int useMark = 0; useMark <= 1; useMark++) {
+ for (int createEarly = 0; createEarly <= 1; createEarly++) {
+ runTest(useMark, createEarly);
+ }
+ }
+ printf("done...\n");
+ Sleep(1000);
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc
new file mode 100644
index 0000000000..fa584b9fae
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc
@@ -0,0 +1,671 @@
+//
+// Windows versions tested
+//
+// Vista Enterprise SP2 32-bit
+// - ver reports [Version 6.0.6002]
+// - kernel32.dll product/file versions are 6.0.6002.19381
+//
+// Windows 7 Ultimate SP1 32-bit
+// - ver reports [Version 6.1.7601]
+// - conhost.exe product/file versions are 6.1.7601.18847
+// - kernel32.dll product/file versions are 6.1.7601.18847
+//
+// Windows Server 2008 R2 Datacenter SP1 64-bit
+// - ver reports [Version 6.1.7601]
+// - conhost.exe product/file versions are 6.1.7601.23153
+// - kernel32.dll product/file versions are 6.1.7601.23153
+//
+// Windows 8 Enterprise 32-bit
+// - ver reports [Version 6.2.9200]
+// - conhost.exe product/file versions are 6.2.9200.16578
+// - kernel32.dll product/file versions are 6.2.9200.16859
+//
+
+//
+// Specific version details on working Server 2008 R2:
+//
+// dwMajorVersion = 6
+// dwMinorVersion = 1
+// dwBuildNumber = 7601
+// dwPlatformId = 2
+// szCSDVersion = Service Pack 1
+// wServicePackMajor = 1
+// wServicePackMinor = 0
+// wSuiteMask = 0x190
+// wProductType = 0x3
+//
+// Specific version details on broken Win7:
+//
+// dwMajorVersion = 6
+// dwMinorVersion = 1
+// dwBuildNumber = 7601
+// dwPlatformId = 2
+// szCSDVersion = Service Pack 1
+// wServicePackMajor = 1
+// wServicePackMinor = 0
+// wSuiteMask = 0x100
+// wProductType = 0x1
+//
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "TestUtil.cc"
+
+const char *g_prefix = "";
+
+static void dumpHandles() {
+ trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x",
+ g_prefix,
+ (long long)GetStdHandle(STD_INPUT_HANDLE),
+ (long long)GetStdHandle(STD_OUTPUT_HANDLE),
+ (long long)GetStdHandle(STD_ERROR_HANDLE));
+}
+
+static const char *successOrFail(BOOL ret) {
+ return ret ? "ok" : "FAILED";
+}
+
+static void startChildInSameConsole(const wchar_t *args, BOOL
+ bInheritHandles=FALSE) {
+ wchar_t program[1024];
+ wchar_t cmdline[1024];
+ GetModuleFileNameW(NULL, program, 1024);
+ swprintf(cmdline, L"\"%ls\" %ls", program, args);
+
+ STARTUPINFOW sui;
+ PROCESS_INFORMATION pi;
+ memset(&sui, 0, sizeof(sui));
+ memset(&pi, 0, sizeof(pi));
+ sui.cb = sizeof(sui);
+
+ CreateProcessW(program, cmdline,
+ NULL, NULL,
+ /*bInheritHandles=*/bInheritHandles,
+ /*dwCreationFlags=*/0,
+ NULL, NULL,
+ &sui, &pi);
+}
+
+static void closeHandle(HANDLE h) {
+ trace("%sClosing handle 0x%I64x...", g_prefix, (long long)h);
+ trace("%sClosing handle 0x%I64x... %s", g_prefix, (long long)h, successOrFail(CloseHandle(h)));
+}
+
+static HANDLE createBuffer() {
+
+ // If sa isn't provided, the handle defaults to not-inheritable.
+ SECURITY_ATTRIBUTES sa = {0};
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+
+ trace("%sCreating a new buffer...", g_prefix);
+ HANDLE conout = CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ CONSOLE_TEXTMODE_BUFFER, NULL);
+
+ trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout);
+ return conout;
+}
+
+static HANDLE openConout() {
+
+ // If sa isn't provided, the handle defaults to not-inheritable.
+ SECURITY_ATTRIBUTES sa = {0};
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+
+ trace("%sOpening CONOUT...", g_prefix);
+ HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING, 0, NULL);
+ trace("%sOpening CONOUT... 0x%I64x", g_prefix, (long long)conout);
+ return conout;
+}
+
+static void setConsoleActiveScreenBuffer(HANDLE conout) {
+ trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...",
+ g_prefix, (long long)conout);
+ trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s",
+ g_prefix, (long long)conout,
+ successOrFail(SetConsoleActiveScreenBuffer(conout)));
+}
+
+static void writeTest(HANDLE conout, const char *msg) {
+ char writeData[256];
+ sprintf(writeData, "%s%s\n", g_prefix, msg);
+
+ trace("%sWriting to 0x%I64x: '%s'...",
+ g_prefix, (long long)conout, msg);
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
+ trace("%sWriting to 0x%I64x: '%s'... %s",
+ g_prefix, (long long)conout, msg,
+ successOrFail(ret && actual == strlen(writeData)));
+}
+
+static void writeTest(const char *msg) {
+ writeTest(GetStdHandle(STD_OUTPUT_HANDLE), msg);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST 1 -- create new buffer, activate it, and close the handle. The console
+// automatically switches the screen buffer back to the original.
+//
+// This test passes everywhere.
+//
+
+static void test1(int argc, char *argv[]) {
+ if (!strcmp(argv[1], "1")) {
+ startChildProcess(L"1:child");
+ return;
+ }
+
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+ writeTest(origBuffer, "<-- origBuffer -->");
+
+ HANDLE newBuffer = createBuffer();
+ writeTest(newBuffer, "<-- newBuffer -->");
+ setConsoleActiveScreenBuffer(newBuffer);
+ Sleep(2000);
+
+ writeTest(origBuffer, "TEST PASSED!");
+
+ // Closing the handle w/o switching the active screen buffer automatically
+ // switches the console back to the original buffer.
+ closeHandle(newBuffer);
+
+ while (true) {
+ Sleep(1000);
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST 2 -- Test program that creates and activates newBuffer, starts a child
+// process, then closes its newBuffer handle. newBuffer remains activated,
+// because the child keeps it active. (Also see TEST D.)
+//
+
+static void test2(int argc, char *argv[]) {
+ if (!strcmp(argv[1], "2")) {
+ startChildProcess(L"2:parent");
+ return;
+ }
+
+ if (!strcmp(argv[1], "2:parent")) {
+ g_prefix = "parent: ";
+ dumpHandles();
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+ writeTest(origBuffer, "<-- origBuffer -->");
+
+ HANDLE newBuffer = createBuffer();
+ writeTest(newBuffer, "<-- newBuffer -->");
+ setConsoleActiveScreenBuffer(newBuffer);
+
+ Sleep(1000);
+ writeTest(newBuffer, "bInheritHandles=FALSE:");
+ startChildInSameConsole(L"2:child", FALSE);
+ Sleep(1000);
+ writeTest(newBuffer, "bInheritHandles=TRUE:");
+ startChildInSameConsole(L"2:child", TRUE);
+
+ Sleep(1000);
+ trace("parent:----");
+
+ // Close the new buffer. The active screen buffer doesn't automatically
+ // switch back to origBuffer, because the child process has a handle open
+ // to the original buffer.
+ closeHandle(newBuffer);
+
+ Sleep(600 * 1000);
+ return;
+ }
+
+ if (!strcmp(argv[1], "2:child")) {
+ g_prefix = "child: ";
+ dumpHandles();
+ // The child's output isn't visible, because it's still writing to
+ // origBuffer.
+ trace("child:----");
+ writeTest("writing to STDOUT");
+
+ // Handle inheritability is curious. The console handles this program
+ // creates are inheritable, but CreateProcess is called with both
+ // bInheritHandles=TRUE and bInheritHandles=FALSE.
+ //
+ // Vista and Windows 7: bInheritHandles has no effect. The child and
+ // parent processes have the same STDIN/STDOUT/STDERR handles:
+ // 0x3, 0x7, and 0xB. The parent has a 0xF handle for newBuffer.
+ // The child can only write to 0x7, 0xB, and 0xF. Only the writes to
+ // 0xF are visible (i.e. they touch newBuffer).
+ //
+ // Windows 8 or Windows 10 (legacy or non-legacy): the lowest 2 bits of
+ // the HANDLE to WriteConsole seem to be ignored. The new process'
+ // console handles always refer to the buffer that was active when they
+ // started, but the values of the handles depend upon bInheritHandles.
+ // With bInheritHandles=TRUE, the child has the same
+ // STDIN/STDOUT/STDERR/newBuffer handles as the parent, and the three
+ // output handles all work, though their output is all visible. With
+ // bInheritHandles=FALSE, the child has different STDIN/STDOUT/STDERR
+ // handles, and only the new STDOUT/STDERR handles work.
+ //
+ for (unsigned int i = 0x1; i <= 0xB0; ++i) {
+ char msg[256];
+ sprintf(msg, "Write to handle 0x%x", i);
+ HANDLE h = reinterpret_cast<HANDLE>(i);
+ writeTest(h, msg);
+ }
+
+ Sleep(600 * 1000);
+ return;
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST A -- demonstrate an apparent Windows bug with screen buffers
+//
+// Steps:
+// - The parent starts a child process.
+// - The child process creates and activates newBuffer
+// - The parent opens CONOUT$ and writes to it.
+// - The parent closes CONOUT$.
+// - At this point, broken Windows reactivates origBuffer.
+// - The child writes to newBuffer again.
+// - The child activates origBuffer again, then closes newBuffer.
+//
+// Test passes if the message "TEST PASSED!" is visible.
+// Test commonly fails if conhost.exe crashes.
+//
+// Results:
+// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
+// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
+// - Windows 8 Enterprise 32-bit: PASS
+// - Windows 10 64-bit (legacy and non-legacy): PASS
+//
+
+static void testA_parentWork() {
+ // Open an extra CONOUT$ handle so that the HANDLE values in parent and
+ // child don't collide. I think it's OK if they collide, but since we're
+ // trying to track down a Windows bug, it's best to avoid unnecessary
+ // complication.
+ HANDLE dummy = openConout();
+
+ Sleep(3000);
+
+ // Step 2: Open CONOUT$ in the parent. This opens the active buffer, which
+ // was just created in the child. It's handle 0x13. Write to it.
+
+ HANDLE newBuffer = openConout();
+ writeTest(newBuffer, "step2: writing to newBuffer");
+
+ Sleep(3000);
+
+ // Step 3: Close handle 0x13. With Windows 7, the console switches back to
+ // origBuffer, and (unless I'm missing something) it shouldn't.
+
+ closeHandle(newBuffer);
+}
+
+static void testA_childWork() {
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ //
+ // Step 1: Create the new screen buffer in the child process and make it
+ // active. (Typically, it's handle 0x0F.)
+ //
+
+ HANDLE newBuffer = createBuffer();
+
+ setConsoleActiveScreenBuffer(newBuffer);
+ writeTest(newBuffer, "<-- newBuffer -->");
+
+ Sleep(9000);
+ trace("child:----");
+
+ // Step 4: write to the newBuffer again.
+ writeTest(newBuffer, "TEST PASSED!");
+
+ //
+ // Step 5: Switch back to the original screen buffer and close the new
+ // buffer. The switch call succeeds, but the CloseHandle call freezes for
+ // several seconds, because conhost.exe crashes.
+ //
+ Sleep(3000);
+
+ setConsoleActiveScreenBuffer(origBuffer);
+ writeTest(origBuffer, "writing to origBuffer");
+
+ closeHandle(newBuffer);
+
+ // The console HWND is NULL.
+ trace("child: console HWND=0x%I64x", (long long)GetConsoleWindow());
+
+ // At this point, the console window has closed, but the parent/child
+ // processes are still running. Calling AllocConsole would fail, but
+ // calling FreeConsole followed by AllocConsole would both succeed, and a
+ // new console would appear.
+}
+
+static void testA(int argc, char *argv[]) {
+
+ if (!strcmp(argv[1], "A")) {
+ startChildProcess(L"A:parent");
+ return;
+ }
+
+ if (!strcmp(argv[1], "A:parent")) {
+ g_prefix = "parent: ";
+ trace("parent:----");
+ dumpHandles();
+ writeTest("<-- origBuffer -->");
+ startChildInSameConsole(L"A:child");
+ testA_parentWork();
+ Sleep(120000);
+ return;
+ }
+
+ if (!strcmp(argv[1], "A:child")) {
+ g_prefix = "child: ";
+ dumpHandles();
+ testA_childWork();
+ Sleep(120000);
+ return;
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST B -- invert TEST A -- also crashes conhost on Windows 7
+//
+// Test passes if the message "TEST PASSED!" is visible.
+// Test commonly fails if conhost.exe crashes.
+//
+// Results:
+// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
+// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
+// - Windows 8 Enterprise 32-bit: PASS
+// - Windows 10 64-bit (legacy and non-legacy): PASS
+//
+
+static void testB(int argc, char *argv[]) {
+ if (!strcmp(argv[1], "B")) {
+ startChildProcess(L"B:parent");
+ return;
+ }
+
+ if (!strcmp(argv[1], "B:parent")) {
+ g_prefix = "parent: ";
+ startChildInSameConsole(L"B:child");
+ writeTest("<-- origBuffer -->");
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ //
+ // Step 1: Create the new buffer and make it active.
+ //
+ trace("%s----", g_prefix);
+ HANDLE newBuffer = createBuffer();
+ setConsoleActiveScreenBuffer(newBuffer);
+ writeTest(newBuffer, "<-- newBuffer -->");
+
+ //
+ // Step 4: Attempt to write again to the new buffer.
+ //
+ Sleep(9000);
+ trace("%s----", g_prefix);
+ writeTest(newBuffer, "TEST PASSED!");
+
+ //
+ // Step 5: Switch back to the original buffer.
+ //
+ Sleep(3000);
+ trace("%s----", g_prefix);
+ setConsoleActiveScreenBuffer(origBuffer);
+ closeHandle(newBuffer);
+ writeTest(origBuffer, "writing to the initial buffer");
+
+ Sleep(60000);
+ return;
+ }
+
+ if (!strcmp(argv[1], "B:child")) {
+ g_prefix = "child: ";
+ Sleep(3000);
+ trace("%s----", g_prefix);
+
+ //
+ // Step 2: Open the newly active buffer and write to it.
+ //
+ HANDLE newBuffer = openConout();
+ writeTest(newBuffer, "writing to newBuffer");
+
+ //
+ // Step 3: Close the newly active buffer.
+ //
+ Sleep(3000);
+ closeHandle(newBuffer);
+
+ Sleep(60000);
+ return;
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST C -- Interleaving open/close of console handles also seems to break on
+// Windows 7.
+//
+// Test:
+// - child creates and activates newBuf1
+// - parent opens newBuf1
+// - child creates and activates newBuf2
+// - parent opens newBuf2, then closes newBuf1
+// - child switches back to newBuf1
+// * At this point, the console starts malfunctioning.
+// - parent and child close newBuf2
+// - child closes newBuf1
+//
+// Test passes if the message "TEST PASSED!" is visible.
+// Test commonly fails if conhost.exe crashes.
+//
+// Results:
+// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
+// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
+// - Windows 8 Enterprise 32-bit: PASS
+// - Windows 10 64-bit (legacy and non-legacy): PASS
+//
+
+static void testC(int argc, char *argv[]) {
+ if (!strcmp(argv[1], "C")) {
+ startChildProcess(L"C:parent");
+ return;
+ }
+
+ if (!strcmp(argv[1], "C:parent")) {
+ startChildInSameConsole(L"C:child");
+ writeTest("<-- origBuffer -->");
+ g_prefix = "parent: ";
+
+ // At time=4, open newBuffer1.
+ Sleep(4000);
+ trace("%s---- t=4", g_prefix);
+ const HANDLE newBuffer1 = openConout();
+
+ // At time=8, open newBuffer2, and close newBuffer1.
+ Sleep(4000);
+ trace("%s---- t=8", g_prefix);
+ const HANDLE newBuffer2 = openConout();
+ closeHandle(newBuffer1);
+
+ // At time=25, cleanup of newBuffer2.
+ Sleep(17000);
+ trace("%s---- t=25", g_prefix);
+ closeHandle(newBuffer2);
+
+ Sleep(240000);
+ return;
+ }
+
+ if (!strcmp(argv[1], "C:child")) {
+ g_prefix = "child: ";
+
+ // At time=2, create newBuffer1 and activate it.
+ Sleep(2000);
+ trace("%s---- t=2", g_prefix);
+ const HANDLE newBuffer1 = createBuffer();
+ setConsoleActiveScreenBuffer(newBuffer1);
+ writeTest(newBuffer1, "<-- newBuffer1 -->");
+
+ // At time=6, create newBuffer2 and activate it.
+ Sleep(4000);
+ trace("%s---- t=6", g_prefix);
+ const HANDLE newBuffer2 = createBuffer();
+ setConsoleActiveScreenBuffer(newBuffer2);
+ writeTest(newBuffer2, "<-- newBuffer2 -->");
+
+ // At time=10, attempt to switch back to newBuffer1. The parent process
+ // has opened and closed its handle to newBuffer1, so does it still exist?
+ Sleep(4000);
+ trace("%s---- t=10", g_prefix);
+ setConsoleActiveScreenBuffer(newBuffer1);
+ writeTest(newBuffer1, "write to newBuffer1: TEST PASSED!");
+
+ // At time=25, cleanup of newBuffer2.
+ Sleep(15000);
+ trace("%s---- t=25", g_prefix);
+ closeHandle(newBuffer2);
+
+ // At time=35, cleanup of newBuffer1. The console should switch to the
+ // initial buffer again.
+ Sleep(10000);
+ trace("%s---- t=35", g_prefix);
+ closeHandle(newBuffer1);
+
+ Sleep(240000);
+ return;
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TEST D -- parent creates a new buffer, child launches, writes,
+// closes it output handle, then parent writes again. (Also see TEST 2.)
+//
+// On success, this will appear:
+//
+// parent: <-- newBuffer -->
+// child: writing to newBuffer
+// parent: TEST PASSED!
+//
+// If this appears, it indicates that the child's closing its output handle did
+// not destroy newBuffer.
+//
+// Results:
+// - Windows 7 Ultimate SP1 32-bit: PASS
+// - Windows 8 Enterprise 32-bit: PASS
+// - Windows 10 64-bit (legacy and non-legacy): PASS
+//
+
+static void testD(int argc, char *argv[]) {
+ if (!strcmp(argv[1], "D")) {
+ startChildProcess(L"D:parent");
+ return;
+ }
+
+ if (!strcmp(argv[1], "D:parent")) {
+ g_prefix = "parent: ";
+ HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
+ writeTest(origBuffer, "<-- origBuffer -->");
+
+ HANDLE newBuffer = createBuffer();
+ writeTest(newBuffer, "<-- newBuffer -->");
+ setConsoleActiveScreenBuffer(newBuffer);
+
+ // At t=2, start a child process, explicitly forcing it to use
+ // newBuffer for its standard handles. These calls are apparently
+ // redundant on Windows 8 and up.
+ Sleep(2000);
+ trace("parent:----");
+ trace("parent: starting child process");
+ SetStdHandle(STD_OUTPUT_HANDLE, newBuffer);
+ SetStdHandle(STD_ERROR_HANDLE, newBuffer);
+ startChildInSameConsole(L"D:child");
+ SetStdHandle(STD_OUTPUT_HANDLE, origBuffer);
+ SetStdHandle(STD_ERROR_HANDLE, origBuffer);
+
+ // At t=6, write again to newBuffer.
+ Sleep(4000);
+ trace("parent:----");
+ writeTest(newBuffer, "TEST PASSED!");
+
+ // At t=8, close the newBuffer. In earlier versions of windows
+ // (including Server 2008 R2), the console then switches back to
+ // origBuffer. As of Windows 8, it doesn't, because somehow the child
+ // process is keeping the console on newBuffer, even though the child
+ // process closed its STDIN/STDOUT/STDERR handles. Killing the child
+ // process by hand after the test finishes *does* force the console
+ // back to origBuffer.
+ Sleep(2000);
+ closeHandle(newBuffer);
+
+ Sleep(120000);
+ return;
+ }
+
+ if (!strcmp(argv[1], "D:child")) {
+ g_prefix = "child: ";
+ // At t=2, the child starts.
+ trace("child:----");
+ dumpHandles();
+ writeTest("writing to newBuffer");
+
+ // At t=4, the child explicitly closes its handle.
+ Sleep(2000);
+ trace("child:----");
+ if (GetStdHandle(STD_ERROR_HANDLE) != GetStdHandle(STD_OUTPUT_HANDLE)) {
+ closeHandle(GetStdHandle(STD_ERROR_HANDLE));
+ }
+ closeHandle(GetStdHandle(STD_OUTPUT_HANDLE));
+ closeHandle(GetStdHandle(STD_INPUT_HANDLE));
+
+ Sleep(120000);
+ return;
+ }
+}
+
+
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ printf("USAGE: %s testnum\n", argv[0]);
+ return 0;
+ }
+
+ if (argv[1][0] == '1') {
+ test1(argc, argv);
+ } else if (argv[1][0] == '2') {
+ test2(argc, argv);
+ } else if (argv[1][0] == 'A') {
+ testA(argc, argv);
+ } else if (argv[1][0] == 'B') {
+ testB(argc, argv);
+ } else if (argv[1][0] == 'C') {
+ testC(argc, argv);
+ } else if (argv[1][0] == 'D') {
+ testD(argc, argv);
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc
new file mode 100644
index 0000000000..2b648c9409
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc
@@ -0,0 +1,151 @@
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+const char *g_prefix = "";
+
+static void dumpHandles() {
+ trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x",
+ g_prefix,
+ (long long)GetStdHandle(STD_INPUT_HANDLE),
+ (long long)GetStdHandle(STD_OUTPUT_HANDLE),
+ (long long)GetStdHandle(STD_ERROR_HANDLE));
+}
+
+static HANDLE createBuffer() {
+
+ // If sa isn't provided, the handle defaults to not-inheritable.
+ SECURITY_ATTRIBUTES sa = {0};
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+
+ trace("%sCreating a new buffer...", g_prefix);
+ HANDLE conout = CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ CONSOLE_TEXTMODE_BUFFER, NULL);
+
+ trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout);
+ return conout;
+}
+
+static const char *successOrFail(BOOL ret) {
+ return ret ? "ok" : "FAILED";
+}
+
+static void setConsoleActiveScreenBuffer(HANDLE conout) {
+ trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...",
+ g_prefix, (long long)conout);
+ trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s",
+ g_prefix, (long long)conout,
+ successOrFail(SetConsoleActiveScreenBuffer(conout)));
+}
+
+static void writeTest(HANDLE conout, const char *msg) {
+ char writeData[256];
+ sprintf(writeData, "%s%s\n", g_prefix, msg);
+
+ trace("%sWriting to 0x%I64x: '%s'...",
+ g_prefix, (long long)conout, msg);
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
+ trace("%sWriting to 0x%I64x: '%s'... %s",
+ g_prefix, (long long)conout, msg,
+ successOrFail(ret && actual == strlen(writeData)));
+}
+
+static HANDLE startChildInSameConsole(const wchar_t *args, BOOL
+ bInheritHandles=FALSE) {
+ wchar_t program[1024];
+ wchar_t cmdline[1024];
+ GetModuleFileNameW(NULL, program, 1024);
+ swprintf(cmdline, L"\"%ls\" %ls", program, args);
+
+ STARTUPINFOW sui;
+ PROCESS_INFORMATION pi;
+ memset(&sui, 0, sizeof(sui));
+ memset(&pi, 0, sizeof(pi));
+ sui.cb = sizeof(sui);
+
+ CreateProcessW(program, cmdline,
+ NULL, NULL,
+ /*bInheritHandles=*/bInheritHandles,
+ /*dwCreationFlags=*/0,
+ NULL, NULL,
+ &sui, &pi);
+
+ return pi.hProcess;
+}
+
+static HANDLE dup(HANDLE h, HANDLE targetProcess) {
+ HANDLE h2 = INVALID_HANDLE_VALUE;
+ BOOL ret = DuplicateHandle(
+ GetCurrentProcess(), h,
+ targetProcess, &h2,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ trace("dup(0x%I64x) to process 0x%I64x... %s, 0x%I64x",
+ (long long)h,
+ (long long)targetProcess,
+ successOrFail(ret),
+ (long long)h2);
+ return h2;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"parent");
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "parent")) {
+ g_prefix = "parent: ";
+ dumpHandles();
+ HANDLE hChild = startChildInSameConsole(L"child");
+
+ // Windows 10.
+ HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE new1 = createBuffer();
+
+ Sleep(2000);
+ setConsoleActiveScreenBuffer(new1);
+
+ // Handle duplication results to child process in same console:
+ // - Windows XP: fails
+ // - Windows 7 Ultimate SP1 32-bit: fails
+ // - Windows Server 2008 R2 Datacenter SP1 64-bit: fails
+ // - Windows 8 Enterprise 32-bit: succeeds
+ // - Windows 10: succeeds
+ HANDLE orig2 = dup(orig1, GetCurrentProcess());
+ HANDLE new2 = dup(new1, GetCurrentProcess());
+
+ dup(orig1, hChild);
+ dup(new1, hChild);
+
+ // The writes to orig1/orig2 are invisible. The writes to new1/new2
+ // are visible.
+ writeTest(orig1, "write to orig1");
+ writeTest(orig2, "write to orig2");
+ writeTest(new1, "write to new1");
+ writeTest(new2, "write to new2");
+
+ Sleep(120000);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "child")) {
+ g_prefix = "child: ";
+ dumpHandles();
+ Sleep(4000);
+ for (unsigned int i = 0x1; i <= 0xB0; ++i) {
+ char msg[256];
+ sprintf(msg, "Write to handle 0x%x", i);
+ HANDLE h = reinterpret_cast<HANDLE>(i);
+ writeTest(h, msg);
+ }
+ Sleep(120000);
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SelectAllTest.cc b/src/libs/3rdparty/winpty/misc/SelectAllTest.cc
new file mode 100644
index 0000000000..a6c27739d8
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SelectAllTest.cc
@@ -0,0 +1,45 @@
+#define _WIN32_WINNT 0x0501
+#include <stdio.h>
+#include <windows.h>
+
+#include "../src/shared/DebugClient.cc"
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+
+CALLBACK DWORD pausingThread(LPVOID dummy)
+{
+ HWND hwnd = GetConsoleWindow();
+ while (true) {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
+ Sleep(1000);
+ SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
+ Sleep(1000);
+ }
+}
+
+int main()
+{
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ GetConsoleScreenBufferInfo(out, &info);
+ COORD initial = info.dwCursorPosition;
+
+ CreateThread(NULL, 0,
+ pausingThread, NULL,
+ 0, NULL);
+
+ for (int i = 0; i < 30; ++i) {
+ Sleep(100);
+ GetConsoleScreenBufferInfo(out, &info);
+ if (memcmp(&info.dwCursorPosition, &initial, sizeof(COORD)) != 0) {
+ trace("cursor moved to [%d,%d]",
+ info.dwCursorPosition.X,
+ info.dwCursorPosition.Y);
+ } else {
+ trace("cursor in expected position");
+ }
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SetBufInfo.cc b/src/libs/3rdparty/winpty/misc/SetBufInfo.cc
new file mode 100644
index 0000000000..f37c31bdf7
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SetBufInfo.cc
@@ -0,0 +1,90 @@
+#include <windows.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "TestUtil.cc"
+
+static void usage() {
+ printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n");
+}
+
+int main(int argc, char *argv[]) {
+ const HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+
+ bool change = false;
+ BOOL success;
+ CONSOLE_SCREEN_BUFFER_INFOEX info = {};
+ info.cbSize = sizeof(info);
+
+ success = GetConsoleScreenBufferInfoEx(conout, &info);
+ ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
+
+ for (int i = 1; i < argc; ) {
+ std::string arg = argv[i];
+ if (arg == "-buf" && (i + 2) < argc) {
+ info.dwSize.X = atoi(argv[i + 1]);
+ info.dwSize.Y = atoi(argv[i + 2]);
+ i += 3;
+ change = true;
+ } else if (arg == "-pos" && (i + 2) < argc) {
+ int dx = info.srWindow.Right - info.srWindow.Left;
+ int dy = info.srWindow.Bottom - info.srWindow.Top;
+ info.srWindow.Left = atoi(argv[i + 1]);
+ info.srWindow.Top = atoi(argv[i + 2]);
+ i += 3;
+ info.srWindow.Right = info.srWindow.Left + dx;
+ info.srWindow.Bottom = info.srWindow.Top + dy;
+ change = true;
+ } else if (arg == "-win" && (i + 2) < argc) {
+ info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1;
+ info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1;
+ i += 3;
+ change = true;
+ } else if (arg == "-set") {
+ change = true;
+ ++i;
+ } else if (arg == "--help" || arg == "-help") {
+ usage();
+ exit(0);
+ } else {
+ fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str());
+ usage();
+ exit(1);
+ }
+ }
+
+ if (change) {
+ success = SetConsoleScreenBufferInfoEx(conout, &info);
+ if (success) {
+ printf("success\n");
+ } else {
+ printf("SetConsoleScreenBufferInfoEx call failed\n");
+ }
+ success = GetConsoleScreenBufferInfoEx(conout, &info);
+ ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
+ }
+
+ auto dump = [](const char *fmt, ...) {
+ char msg[256];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(msg, fmt, ap);
+ va_end(ap);
+ trace("%s", msg);
+ printf("%s\n", msg);
+ };
+
+ dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y);
+ dump("window-size: %d x %d",
+ info.srWindow.Right - info.srWindow.Left + 1,
+ info.srWindow.Bottom - info.srWindow.Top + 1);
+ dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SetBufferSize.cc b/src/libs/3rdparty/winpty/misc/SetBufferSize.cc
new file mode 100644
index 0000000000..b50a1f8dc3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SetBufferSize.cc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc != 3) {
+ printf("Usage: %s x y width height\n", argv[0]);
+ return 1;
+ }
+
+ const HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+
+ COORD size = {
+ (short)atoi(argv[1]),
+ (short)atoi(argv[2]),
+ };
+
+ BOOL ret = SetConsoleScreenBufferSize(conout, size);
+ const unsigned lastError = GetLastError();
+ const char *const retStr = ret ? "OK" : "failed";
+ trace("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)", retStr, lastError);
+ printf("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)\n", retStr, lastError);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SetCursorPos.cc b/src/libs/3rdparty/winpty/misc/SetCursorPos.cc
new file mode 100644
index 0000000000..d20fdbdfc0
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SetCursorPos.cc
@@ -0,0 +1,10 @@
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ int col = atoi(argv[1]);
+ int row = atoi(argv[2]);
+ setCursorPos(col, row);
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SetFont.cc b/src/libs/3rdparty/winpty/misc/SetFont.cc
new file mode 100644
index 0000000000..9bcd4b4cc9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SetFont.cc
@@ -0,0 +1,145 @@
+#include <windows.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+#include "TestUtil.cc"
+
+#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
+
+// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
+const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
+const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
+const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
+const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
+
+int main() {
+ setlocale(LC_ALL, "");
+ wchar_t *cmdline = GetCommandLineW();
+ int argc = 0;
+ wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
+ const HANDLE conout = openConout();
+
+ if (argc == 1) {
+ cprintf(L"Usage:\n");
+ cprintf(L" SetFont <index>\n");
+ cprintf(L" SetFont options\n");
+ cprintf(L"\n");
+ cprintf(L"Options for SetCurrentConsoleFontEx:\n");
+ cprintf(L" -idx INDEX\n");
+ cprintf(L" -w WIDTH\n");
+ cprintf(L" -h HEIGHT\n");
+ cprintf(L" -family (0xNN|NN)\n");
+ cprintf(L" -weight (normal|bold|NNN)\n");
+ cprintf(L" -face FACENAME\n");
+ cprintf(L" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n");
+ cprintf(L" -tt\n");
+ cprintf(L" -vec\n");
+ cprintf(L" -vp\n");
+ cprintf(L" -dev\n");
+ cprintf(L" -roman\n");
+ cprintf(L" -swiss\n");
+ cprintf(L" -modern\n");
+ cprintf(L" -script\n");
+ cprintf(L" -decorative\n");
+ return 0;
+ }
+
+ if (isdigit(argv[1][0])) {
+ int index = _wtoi(argv[1]);
+ HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
+ FARPROC proc = GetProcAddress(kernel32, "SetConsoleFont");
+ if (proc == NULL) {
+ cprintf(L"Couldn't get address of SetConsoleFont\n");
+ } else {
+ BOOL ret = reinterpret_cast<BOOL WINAPI(*)(HANDLE, DWORD)>(proc)(
+ conout, index);
+ cprintf(L"SetFont returned %d\n", ret);
+ }
+ return 0;
+ }
+
+ CONSOLE_FONT_INFOEX fontex = {0};
+ fontex.cbSize = sizeof(fontex);
+
+ for (int i = 1; i < argc; ++i) {
+ std::wstring arg = argv[i];
+ if (i + 1 < argc) {
+ std::wstring next = argv[i + 1];
+ if (arg == L"-idx") {
+ fontex.nFont = _wtoi(next.c_str());
+ ++i; continue;
+ } else if (arg == L"-w") {
+ fontex.dwFontSize.X = _wtoi(next.c_str());
+ ++i; continue;
+ } else if (arg == L"-h") {
+ fontex.dwFontSize.Y = _wtoi(next.c_str());
+ ++i; continue;
+ } else if (arg == L"-weight") {
+ if (next == L"normal") {
+ fontex.FontWeight = 400;
+ } else if (next == L"bold") {
+ fontex.FontWeight = 700;
+ } else {
+ fontex.FontWeight = _wtoi(next.c_str());
+ }
+ ++i; continue;
+ } else if (arg == L"-face") {
+ wcsncpy(fontex.FaceName, next.c_str(), COUNT_OF(fontex.FaceName));
+ ++i; continue;
+ } else if (arg == L"-family") {
+ fontex.FontFamily = strtol(narrowString(next).c_str(), nullptr, 0);
+ ++i; continue;
+ }
+ }
+ if (arg == L"-tt") {
+ fontex.FontFamily |= TMPF_TRUETYPE;
+ } else if (arg == L"-vec") {
+ fontex.FontFamily |= TMPF_VECTOR;
+ } else if (arg == L"-vp") {
+ // Setting the TMPF_FIXED_PITCH bit actually indicates variable
+ // pitch.
+ fontex.FontFamily |= TMPF_FIXED_PITCH;
+ } else if (arg == L"-dev") {
+ fontex.FontFamily |= TMPF_DEVICE;
+ } else if (arg == L"-roman") {
+ fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_ROMAN;
+ } else if (arg == L"-swiss") {
+ fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SWISS;
+ } else if (arg == L"-modern") {
+ fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_MODERN;
+ } else if (arg == L"-script") {
+ fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SCRIPT;
+ } else if (arg == L"-decorative") {
+ fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_DECORATIVE;
+ } else if (arg == L"-face-gothic") {
+ wcsncpy(fontex.FaceName, kMSGothic, COUNT_OF(fontex.FaceName));
+ } else if (arg == L"-face-simsun") {
+ wcsncpy(fontex.FaceName, kNSimSun, COUNT_OF(fontex.FaceName));
+ } else if (arg == L"-face-minglight") {
+ wcsncpy(fontex.FaceName, kMingLight, COUNT_OF(fontex.FaceName));
+ } else if (arg == L"-face-gulimche") {
+ wcsncpy(fontex.FaceName, kGulimChe, COUNT_OF(fontex.FaceName));
+ } else {
+ cprintf(L"Unrecognized argument: %ls\n", arg.c_str());
+ exit(1);
+ }
+ }
+
+ cprintf(L"Setting to: nFont=%u dwFontSize=(%d,%d) "
+ L"FontFamily=0x%x FontWeight=%u "
+ L"FaceName=\"%ls\"\n",
+ static_cast<unsigned>(fontex.nFont),
+ fontex.dwFontSize.X, fontex.dwFontSize.Y,
+ fontex.FontFamily, fontex.FontWeight,
+ fontex.FaceName);
+
+ BOOL ret = SetCurrentConsoleFontEx(
+ conout,
+ FALSE,
+ &fontex);
+ cprintf(L"SetCurrentConsoleFontEx returned %d\n", ret);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/SetWindowRect.cc b/src/libs/3rdparty/winpty/misc/SetWindowRect.cc
new file mode 100644
index 0000000000..6291dd6745
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/SetWindowRect.cc
@@ -0,0 +1,36 @@
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc != 5) {
+ printf("Usage: %s x y width height\n", argv[0]);
+ return 1;
+ }
+
+ const HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+
+ SMALL_RECT sr = {
+ (short)atoi(argv[1]),
+ (short)atoi(argv[2]),
+ (short)(atoi(argv[1]) + atoi(argv[3]) - 1),
+ (short)(atoi(argv[2]) + atoi(argv[4]) - 1),
+ };
+
+ trace("Calling SetConsoleWindowInfo with {L=%d,T=%d,R=%d,B=%d}",
+ sr.Left, sr.Top, sr.Right, sr.Bottom);
+ BOOL ret = SetConsoleWindowInfo(conout, TRUE, &sr);
+ const unsigned lastError = GetLastError();
+ const char *const retStr = ret ? "OK" : "failed";
+ trace("SetConsoleWindowInfo ret: %s (LastError=0x%x)", retStr, lastError);
+ printf("SetConsoleWindowInfo ret: %s (LastError=0x%x)\n", retStr, lastError);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ShowArgv.cc b/src/libs/3rdparty/winpty/misc/ShowArgv.cc
new file mode 100644
index 0000000000..29a0f09131
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ShowArgv.cc
@@ -0,0 +1,12 @@
+// This test program is useful for studying commandline<->argv conversion.
+
+#include <stdio.h>
+#include <windows.h>
+
+int main(int argc, char **argv)
+{
+ printf("cmdline = [%s]\n", GetCommandLine());
+ for (int i = 0; i < argc; ++i)
+ printf("[%s]\n", argv[i]);
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc b/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc
new file mode 100644
index 0000000000..75fbfb81f1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc
@@ -0,0 +1,40 @@
+#include <windows.h>
+#include <stdio.h>
+#include <ctype.h>
+
+int main(int argc, char *argv[])
+{
+ static int escCount = 0;
+
+ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
+ while (true) {
+ DWORD count;
+ INPUT_RECORD ir;
+ if (!ReadConsoleInput(hStdin, &ir, 1, &count)) {
+ printf("ReadConsoleInput failed\n");
+ return 1;
+ }
+
+ if (true) {
+ DWORD mode;
+ GetConsoleMode(hStdin, &mode);
+ SetConsoleMode(hStdin, mode & ~ENABLE_PROCESSED_INPUT);
+ }
+
+ if (ir.EventType == KEY_EVENT) {
+ const KEY_EVENT_RECORD &ker = ir.Event.KeyEvent;
+ printf("%s", ker.bKeyDown ? "dn" : "up");
+ printf(" ch=");
+ if (isprint(ker.uChar.AsciiChar))
+ printf("'%c'", ker.uChar.AsciiChar);
+ printf("%d", ker.uChar.AsciiChar);
+ printf(" vk=%#x", ker.wVirtualKeyCode);
+ printf(" scan=%#x", ker.wVirtualScanCode);
+ printf(" state=%#x", (int)ker.dwControlKeyState);
+ printf(" repeat=%d", ker.wRepeatCount);
+ printf("\n");
+ if (ker.uChar.AsciiChar == 27 && ++escCount == 6)
+ break;
+ }
+ }
+}
diff --git a/src/libs/3rdparty/winpty/misc/Spew.py b/src/libs/3rdparty/winpty/misc/Spew.py
new file mode 100644
index 0000000000..9d1796af37
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Spew.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+i = 0;
+while True:
+ i += 1
+ print(i)
diff --git a/src/libs/3rdparty/winpty/misc/TestUtil.cc b/src/libs/3rdparty/winpty/misc/TestUtil.cc
new file mode 100644
index 0000000000..c832a12b85
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/TestUtil.cc
@@ -0,0 +1,172 @@
+// This file is included into test programs using #include
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <vector>
+#include <string>
+
+#include "../src/shared/DebugClient.h"
+#include "../src/shared/TimeMeasurement.h"
+
+#include "../src/shared/DebugClient.cc"
+#include "../src/shared/WinptyAssert.cc"
+#include "../src/shared/WinptyException.cc"
+
+// Launch this test program again, in a new console that we will destroy.
+static void startChildProcess(const wchar_t *args) {
+ wchar_t program[1024];
+ wchar_t cmdline[1024];
+ GetModuleFileNameW(NULL, program, 1024);
+ swprintf(cmdline, L"\"%ls\" %ls", program, args);
+
+ STARTUPINFOW sui;
+ PROCESS_INFORMATION pi;
+ memset(&sui, 0, sizeof(sui));
+ memset(&pi, 0, sizeof(pi));
+ sui.cb = sizeof(sui);
+
+ CreateProcessW(program, cmdline,
+ NULL, NULL,
+ /*bInheritHandles=*/FALSE,
+ /*dwCreationFlags=*/CREATE_NEW_CONSOLE,
+ NULL, NULL,
+ &sui, &pi);
+}
+
+static void setBufferSize(HANDLE conout, int x, int y) {
+ COORD size = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
+ BOOL success = SetConsoleScreenBufferSize(conout, size);
+ trace("setBufferSize: (%d,%d), result=%d", x, y, success);
+}
+
+static void setWindowPos(HANDLE conout, int x, int y, int w, int h) {
+ SMALL_RECT r = {
+ static_cast<SHORT>(x), static_cast<SHORT>(y),
+ static_cast<SHORT>(x + w - 1),
+ static_cast<SHORT>(y + h - 1)
+ };
+ BOOL success = SetConsoleWindowInfo(conout, /*bAbsolute=*/TRUE, &r);
+ trace("setWindowPos: (%d,%d,%d,%d), result=%d", x, y, w, h, success);
+}
+
+static void setCursorPos(HANDLE conout, int x, int y) {
+ COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
+ SetConsoleCursorPosition(conout, coord);
+}
+
+static void setBufferSize(int x, int y) {
+ setBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
+}
+
+static void setWindowPos(int x, int y, int w, int h) {
+ setWindowPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y, w, h);
+}
+
+static void setCursorPos(int x, int y) {
+ setCursorPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
+}
+
+static void countDown(int sec) {
+ for (int i = sec; i > 0; --i) {
+ printf("%d.. ", i);
+ fflush(stdout);
+ Sleep(1000);
+ }
+ printf("\n");
+}
+
+static void writeBox(int x, int y, int w, int h, char ch, int attributes=7) {
+ CHAR_INFO info = { 0 };
+ info.Char.AsciiChar = ch;
+ info.Attributes = attributes;
+ std::vector<CHAR_INFO> buf(w * h, info);
+ HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ COORD bufSize = { static_cast<SHORT>(w), static_cast<SHORT>(h) };
+ COORD bufCoord = { 0, 0 };
+ SMALL_RECT writeRegion = {
+ static_cast<SHORT>(x),
+ static_cast<SHORT>(y),
+ static_cast<SHORT>(x + w - 1),
+ static_cast<SHORT>(y + h - 1)
+ };
+ WriteConsoleOutputA(conout, buf.data(), bufSize, bufCoord, &writeRegion);
+}
+
+static void setChar(int x, int y, char ch, int attributes=7) {
+ writeBox(x, y, 1, 1, ch, attributes);
+}
+
+static void fillChar(int x, int y, int repeat, char ch) {
+ COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
+ DWORD actual = 0;
+ FillConsoleOutputCharacterA(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ ch, repeat, coord, &actual);
+}
+
+static void repeatChar(int count, char ch) {
+ for (int i = 0; i < count; ++i) {
+ putchar(ch);
+ }
+ fflush(stdout);
+}
+
+// I don't know why, but wprintf fails to print this face name,
+// "MS ゴシック" (aka MS Gothic). It helps to use wprintf instead of printf, and
+// it helps to call `setlocale(LC_ALL, "")`, but the Japanese symbols are
+// ultimately converted to `?` symbols, even though MS Gothic is able to
+// display its own name, and the current code page is 932 (Shift-JIS).
+static void cvfprintf(HANDLE conout, const wchar_t *fmt, va_list ap) {
+ wchar_t buffer[256];
+ vswprintf(buffer, 256 - 1, fmt, ap);
+ buffer[255] = L'\0';
+ DWORD actual = 0;
+ if (!WriteConsoleW(conout, buffer, wcslen(buffer), &actual, NULL)) {
+ wprintf(L"WriteConsoleW call failed!\n");
+ }
+}
+
+static void cfprintf(HANDLE conout, const wchar_t *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ cvfprintf(conout, fmt, ap);
+ va_end(ap);
+}
+
+static void cprintf(const wchar_t *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ cvfprintf(GetStdHandle(STD_OUTPUT_HANDLE), fmt, ap);
+ va_end(ap);
+}
+
+static std::string narrowString(const std::wstring &input)
+{
+ int mblen = WideCharToMultiByte(
+ CP_UTF8, 0,
+ input.data(), input.size(),
+ NULL, 0, NULL, NULL);
+ if (mblen <= 0) {
+ return std::string();
+ }
+ std::vector<char> tmp(mblen);
+ int mblen2 = WideCharToMultiByte(
+ CP_UTF8, 0,
+ input.data(), input.size(),
+ tmp.data(), tmp.size(),
+ NULL, NULL);
+ assert(mblen2 == mblen);
+ return std::string(tmp.data(), tmp.size());
+}
+
+HANDLE openConout() {
+ const HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+ return conout;
+}
diff --git a/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc b/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc
new file mode 100644
index 0000000000..7210d41032
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc
@@ -0,0 +1,102 @@
+// Demonstrates how U+30FC is sometimes handled as a single-width character
+// when it should be handled as a double-width character.
+//
+// It only runs on computers where 932 is a valid code page. Set the system
+// local to "Japanese (Japan)" to ensure this.
+//
+// The problem seems to happen when U+30FC is printed in a console using the
+// Lucida Console font, and only when that font is at certain sizes.
+//
+
+#include <windows.h>
+#include <assert.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "TestUtil.cc"
+
+#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
+
+static void setFont(const wchar_t *faceName, int pxSize) {
+ CONSOLE_FONT_INFOEX infoex = {0};
+ infoex.cbSize = sizeof(infoex);
+ infoex.dwFontSize.Y = pxSize;
+ wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName));
+ BOOL ret = SetCurrentConsoleFontEx(
+ GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex);
+ assert(ret);
+}
+
+static bool performTest(const wchar_t testChar) {
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ SetConsoleTextAttribute(conout, 7);
+
+ system("cls");
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL);
+ assert(ret && actual == 1);
+
+ CHAR_INFO verify[2];
+ COORD bufSize = {2, 1};
+ COORD bufCoord = {0, 0};
+ const SMALL_RECT readRegion = {0, 0, 1, 0};
+ SMALL_RECT actualRegion = readRegion;
+ ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion);
+ assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion)));
+ assert(verify[0].Char.UnicodeChar == testChar);
+
+ if (verify[1].Char.UnicodeChar == testChar) {
+ // Typical double-width behavior with a TrueType font. Pass.
+ assert(verify[0].Attributes == 0x107);
+ assert(verify[1].Attributes == 0x207);
+ return true;
+ } else if (verify[1].Char.UnicodeChar == 0) {
+ // Typical double-width behavior with a Raster Font. Pass.
+ assert(verify[0].Attributes == 7);
+ assert(verify[1].Attributes == 0);
+ return true;
+ } else if (verify[1].Char.UnicodeChar == L' ') {
+ // Single-width behavior. Fail.
+ assert(verify[0].Attributes == 7);
+ assert(verify[1].Attributes == 7);
+ return false;
+ } else {
+ // Unexpected output.
+ assert(false);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ setlocale(LC_ALL, "");
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ assert(SetConsoleCP(932));
+ assert(SetConsoleOutputCP(932));
+
+ const wchar_t testChar = 0x30FC;
+ const wchar_t *const faceNames[] = {
+ L"Lucida Console",
+ L"Consolas",
+ L"MS ゴシック",
+ };
+
+ trace("Test started");
+
+ for (auto faceName : faceNames) {
+ for (int px = 1; px <= 50; ++px) {
+ setFont(faceName, px);
+ if (!performTest(testChar)) {
+ trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px);
+ }
+ }
+ }
+
+ trace("Test complete");
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc b/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc
new file mode 100644
index 0000000000..a8d798e70d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc
@@ -0,0 +1,246 @@
+#include <windows.h>
+
+#include <assert.h>
+#include <vector>
+
+#include "TestUtil.cc"
+
+#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
+
+
+CHAR_INFO ci(wchar_t ch, WORD attributes) {
+ CHAR_INFO ret;
+ ret.Char.UnicodeChar = ch;
+ ret.Attributes = attributes;
+ return ret;
+}
+
+CHAR_INFO ci(wchar_t ch) {
+ return ci(ch, 7);
+}
+
+CHAR_INFO ci() {
+ return ci(L' ');
+}
+
+bool operator==(SMALL_RECT x, SMALL_RECT y) {
+ return !memcmp(&x, &y, sizeof(x));
+}
+
+SMALL_RECT sr(COORD pt, COORD size) {
+ return {
+ pt.X, pt.Y,
+ static_cast<SHORT>(pt.X + size.X - 1),
+ static_cast<SHORT>(pt.Y + size.Y - 1)
+ };
+}
+
+static void set(
+ const COORD pt,
+ const COORD size,
+ const std::vector<CHAR_INFO> &data) {
+ assert(data.size() == size.X * size.Y);
+ SMALL_RECT writeRegion = sr(pt, size);
+ BOOL ret = WriteConsoleOutputW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), size, {0, 0}, &writeRegion);
+ assert(ret && writeRegion == sr(pt, size));
+}
+
+static void set(
+ const COORD pt,
+ const std::vector<CHAR_INFO> &data) {
+ set(pt, {static_cast<SHORT>(data.size()), 1}, data);
+}
+
+static void writeAttrsAt(
+ const COORD pt,
+ const std::vector<WORD> &data) {
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleOutputAttribute(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), data.size(), pt, &actual);
+ assert(ret && actual == data.size());
+}
+
+static void writeCharsAt(
+ const COORD pt,
+ const std::vector<wchar_t> &data) {
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleOutputCharacterW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), data.size(), pt, &actual);
+ assert(ret && actual == data.size());
+}
+
+static void writeChars(
+ const std::vector<wchar_t> &data) {
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), data.size(), &actual, NULL);
+ assert(ret && actual == data.size());
+}
+
+std::vector<CHAR_INFO> get(
+ const COORD pt,
+ const COORD size) {
+ std::vector<CHAR_INFO> data(size.X * size.Y);
+ SMALL_RECT readRegion = sr(pt, size);
+ BOOL ret = ReadConsoleOutputW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), size, {0, 0}, &readRegion);
+ assert(ret && readRegion == sr(pt, size));
+ return data;
+}
+
+std::vector<wchar_t> readCharsAt(
+ const COORD pt,
+ int size) {
+ std::vector<wchar_t> data(size);
+ DWORD actual = 0;
+ BOOL ret = ReadConsoleOutputCharacterW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ data.data(), data.size(), pt, &actual);
+ assert(ret);
+ data.resize(actual); // With double-width chars, we can read fewer than `size`.
+ return data;
+}
+
+static void dump(const COORD pt, const COORD size) {
+ for (CHAR_INFO ci : get(pt, size)) {
+ printf("%04X %04X\n", ci.Char.UnicodeChar, ci.Attributes);
+ }
+}
+
+static void dumpCharsAt(const COORD pt, int size) {
+ for (wchar_t ch : readCharsAt(pt, size)) {
+ printf("%04X\n", ch);
+ }
+}
+
+static COORD getCursorPos() {
+ CONSOLE_SCREEN_BUFFER_INFO info = { sizeof(info) };
+ assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info));
+ return info.dwCursorPosition;
+}
+
+static void test1() {
+ // We write "䀀䀀", then write "䀁" in the middle of the two. The second
+ // write turns the first and last cells into spaces. The LEADING/TRAILING
+ // flags retain consistency.
+ printf("test1 - overlap full-width char with full-width char\n");
+ writeCharsAt({1,0}, {0x4000, 0x4000});
+ dump({0,0}, {6,1});
+ printf("\n");
+ writeCharsAt({2,0}, {0x4001});
+ dump({0,0}, {6,1});
+ printf("\n");
+}
+
+static void test2() {
+ // Like `test1`, but use a lower-level API to do the write. Consistency is
+ // preserved here too -- the first and last cells are replaced with spaces.
+ printf("test2 - overlap full-width char with full-width char (lowlevel)\n");
+ writeCharsAt({1,0}, {0x4000, 0x4000});
+ dump({0,0}, {6,1});
+ printf("\n");
+ set({2,0}, {ci(0x4001,0x107), ci(0x4001,0x207)});
+ dump({0,0}, {6,1});
+ printf("\n");
+}
+
+static void test3() {
+ // However, the lower-level API can break the LEADING/TRAILING invariant
+ // explicitly:
+ printf("test3 - explicitly violate LEADING/TRAILING using lowlevel API\n");
+ set({1,0}, {
+ ci(0x4000, 0x207),
+ ci(0x4001, 0x107),
+ ci(0x3044, 7),
+ ci(L'X', 0x107),
+ ci(L'X', 0x207),
+ });
+ dump({0,0}, {7,1});
+}
+
+static void test4() {
+ // It is possible for the two cells of a double-width character to have two
+ // colors.
+ printf("test4 - use lowlevel to assign two colors to one full-width char\n");
+ set({0,0}, {
+ ci(0x4000, 0x142),
+ ci(0x4000, 0x224),
+ });
+ dump({0,0}, {2,1});
+}
+
+static void test5() {
+ // WriteConsoleOutputAttribute doesn't seem to affect the LEADING/TRAILING
+ // flags.
+ printf("test5 - WriteConsoleOutputAttribute cannot affect LEADING/TRAILING\n");
+
+ // Trying to clear the flags doesn't work...
+ writeCharsAt({0,0}, {0x4000});
+ dump({0,0}, {2,1});
+ writeAttrsAt({0,0}, {0x42, 0x24});
+ printf("\n");
+ dump({0,0}, {2,1});
+
+ // ... and trying to add them also doesn't work.
+ writeCharsAt({0,1}, {'A', ' '});
+ writeAttrsAt({0,1}, {0x107, 0x207});
+ printf("\n");
+ dump({0,1}, {2,1});
+}
+
+static void test6() {
+ // The cursor position may be on either cell of a double-width character.
+ // Visually, the cursor appears under both cells, regardless of which
+ // specific one has the cursor.
+ printf("test6 - cursor can be either left or right cell of full-width char\n");
+
+ writeCharsAt({2,1}, {0x4000});
+
+ setCursorPos(2, 1);
+ auto pos1 = getCursorPos();
+ Sleep(1000);
+
+ setCursorPos(3, 1);
+ auto pos2 = getCursorPos();
+ Sleep(1000);
+
+ setCursorPos(0, 15);
+ printf("%d,%d\n", pos1.X, pos1.Y);
+ printf("%d,%d\n", pos2.X, pos2.Y);
+}
+
+static void runTest(void (&test)()) {
+ system("cls");
+ setCursorPos(0, 14);
+ test();
+ system("pause");
+}
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(80, 40);
+ setWindowPos(0, 0, 80, 40);
+
+ auto cp = GetConsoleOutputCP();
+ assert(cp == 932 || cp == 936 || cp == 949 || cp == 950);
+
+ runTest(test1);
+ runTest(test2);
+ runTest(test3);
+ runTest(test4);
+ runTest(test5);
+ runTest(test6);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc b/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc
new file mode 100644
index 0000000000..05f80f70bd
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc
@@ -0,0 +1,130 @@
+//
+// Test half-width vs full-width characters.
+//
+
+#include <windows.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "TestUtil.cc"
+
+static void writeChars(const wchar_t *text) {
+ wcslen(text);
+ const int len = wcslen(text);
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ text, len, &actual, NULL);
+ trace("writeChars: ret=%d, actual=%lld", ret, (long long)actual);
+}
+
+static void dumpChars(int x, int y, int w, int h) {
+ BOOL ret;
+ const COORD bufSize = {w, h};
+ const COORD bufCoord = {0, 0};
+ const SMALL_RECT topLeft = {x, y, x + w - 1, y + h - 1};
+ CHAR_INFO mbcsData[w * h];
+ CHAR_INFO unicodeData[w * h];
+ SMALL_RECT readRegion;
+ readRegion = topLeft;
+ ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData,
+ bufSize, bufCoord, &readRegion);
+ assert(ret);
+ readRegion = topLeft;
+ ret = ReadConsoleOutputA(GetStdHandle(STD_OUTPUT_HANDLE), mbcsData,
+ bufSize, bufCoord, &readRegion);
+ assert(ret);
+
+ printf("\n");
+ for (int i = 0; i < w * h; ++i) {
+ printf("(%02d,%02d) CHAR: %04x %4x -- %02x %4x\n",
+ x + i % w, y + i / w,
+ (unsigned short)unicodeData[i].Char.UnicodeChar,
+ (unsigned short)unicodeData[i].Attributes,
+ (unsigned char)mbcsData[i].Char.AsciiChar,
+ (unsigned short)mbcsData[i].Attributes);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ system("cls");
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(80, 38);
+ setWindowPos(0, 0, 80, 38);
+
+ // Write text.
+ const wchar_t text1[] = {
+ 0x3044, // U+3044 (HIRAGANA LETTER I)
+ 0x2014, // U+2014 (EM DASH)
+ 0x3044, // U+3044 (HIRAGANA LETTER I)
+ 0xFF2D, // U+FF2D (FULLWIDTH LATIN CAPITAL LETTER M)
+ 0x30FC, // U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK)
+ 0x0031, // U+3031 (DIGIT ONE)
+ 0x2014, // U+2014 (EM DASH)
+ 0x0032, // U+0032 (DIGIT TWO)
+ 0x005C, // U+005C (REVERSE SOLIDUS)
+ 0x3044, // U+3044 (HIRAGANA LETTER I)
+ 0
+ };
+ setCursorPos(0, 0);
+ writeChars(text1);
+
+ setCursorPos(78, 1);
+ writeChars(L"<>");
+
+ const wchar_t text2[] = {
+ 0x0032, // U+3032 (DIGIT TWO)
+ 0x3044, // U+3044 (HIRAGANA LETTER I)
+ 0,
+ };
+ setCursorPos(78, 1);
+ writeChars(text2);
+
+ system("pause");
+
+ dumpChars(0, 0, 17, 1);
+ dumpChars(2, 0, 2, 1);
+ dumpChars(2, 0, 1, 1);
+ dumpChars(3, 0, 1, 1);
+ dumpChars(78, 1, 2, 1);
+ dumpChars(0, 2, 2, 1);
+
+ system("pause");
+ system("cls");
+
+ const wchar_t text3[] = {
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 1
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 2
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 3
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 4
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 5
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 6
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 7
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 8
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 9
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 10
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 11
+ 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 12
+ L'\r', '\n',
+ L'\r', '\n',
+ 0
+ };
+ writeChars(text3);
+ system("pause");
+ {
+ const COORD bufSize = {80, 2};
+ const COORD bufCoord = {0, 0};
+ SMALL_RECT readRegion = {0, 0, 79, 1};
+ CHAR_INFO unicodeData[160];
+ BOOL ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData,
+ bufSize, bufCoord, &readRegion);
+ assert(ret);
+ for (int i = 0; i < 96; ++i) {
+ printf("%04x ", unicodeData[i].Char.UnicodeChar);
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/UnixEcho.cc b/src/libs/3rdparty/winpty/misc/UnixEcho.cc
new file mode 100644
index 0000000000..372e045157
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/UnixEcho.cc
@@ -0,0 +1,89 @@
+/*
+ * Unix test code that puts the terminal into raw mode, then echos typed
+ * characters to stdout. Derived from sample code in the Stevens book, posted
+ * online at http://www.lafn.org/~dave/linux/terminalIO.html.
+ */
+
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "FormatChar.h"
+
+static struct termios save_termios;
+static int term_saved;
+
+/* RAW! mode */
+int tty_raw(int fd)
+{
+ struct termios buf;
+
+ if (tcgetattr(fd, &save_termios) < 0) /* get the original state */
+ return -1;
+
+ buf = save_termios;
+
+ /* echo off, canonical mode off, extended input
+ processing off, signal chars off */
+ buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+
+ /* no SIGINT on BREAK, CR-to-NL off, input parity
+ check off, don't strip the 8th bit on input,
+ ouput flow control off */
+ buf.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON);
+
+ /* clear size bits, parity checking off */
+ buf.c_cflag &= ~(CSIZE | PARENB);
+
+ /* set 8 bits/char */
+ buf.c_cflag |= CS8;
+
+ /* output processing off */
+ buf.c_oflag &= ~(OPOST);
+
+ buf.c_cc[VMIN] = 1; /* 1 byte at a time */
+ buf.c_cc[VTIME] = 0; /* no timer on input */
+
+ if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
+ return -1;
+
+ term_saved = 1;
+
+ return 0;
+}
+
+
+/* set it to normal! */
+int tty_reset(int fd)
+{
+ if (term_saved)
+ if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+int main()
+{
+ tty_raw(0);
+
+ int count = 0;
+ while (true) {
+ char ch;
+ char buf[16];
+ int actual = read(0, &ch, 1);
+ if (actual != 1) {
+ perror("read error");
+ break;
+ }
+ formatChar(buf, ch);
+ fputs(buf, stdout);
+ fflush(stdout);
+ if (ch == 3) // Ctrl-C
+ break;
+ }
+
+ tty_reset(0);
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Utf16Echo.cc b/src/libs/3rdparty/winpty/misc/Utf16Echo.cc
new file mode 100644
index 0000000000..ef5f302de4
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Utf16Echo.cc
@@ -0,0 +1,46 @@
+#include <windows.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <vector>
+#include <string>
+
+int main(int argc, char *argv[]) {
+ system("cls");
+
+ if (argc == 1) {
+ printf("Usage: %s hhhh\n", argv[0]);
+ return 0;
+ }
+
+ std::wstring dataToWrite;
+ for (int i = 1; i < argc; ++i) {
+ wchar_t ch = strtol(argv[i], NULL, 16);
+ dataToWrite.push_back(ch);
+ }
+
+ DWORD actual = 0;
+ BOOL ret = WriteConsoleW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ dataToWrite.data(), dataToWrite.size(), &actual, NULL);
+ assert(ret && actual == dataToWrite.size());
+
+ // Read it back.
+ std::vector<CHAR_INFO> readBuffer(dataToWrite.size() * 2);
+ COORD bufSize = {static_cast<short>(readBuffer.size()), 1};
+ COORD bufCoord = {0, 0};
+ SMALL_RECT topLeft = {0, 0, static_cast<short>(readBuffer.size() - 1), 0};
+ ret = ReadConsoleOutputW(
+ GetStdHandle(STD_OUTPUT_HANDLE), readBuffer.data(),
+ bufSize, bufCoord, &topLeft);
+ assert(ret);
+
+ printf("\n");
+ for (int i = 0; i < readBuffer.size(); ++i) {
+ printf("CHAR: %04x %04x\n",
+ readBuffer[i].Char.UnicodeChar,
+ readBuffer[i].Attributes);
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc b/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc
new file mode 100644
index 0000000000..58f0897022
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc
@@ -0,0 +1,122 @@
+//
+// 2015-09-25
+// I measured these limits on the size of a single ReadConsoleOutputW call.
+// The limit seems to more-or-less disppear with Windows 8, which is the first
+// OS to stop using ALPCs for console I/O. My guess is that the new I/O
+// method does not use the 64KiB shared memory buffer that the ALPC method
+// uses.
+//
+// I'm guessing the remaining difference between Windows 8/8.1 and Windows 10
+// might be related to the 32-vs-64-bitness.
+//
+// Client OSs
+//
+// Windows XP 32-bit VM ==> up to 13304 characters
+// - 13304x1 works, but 13305x1 fails instantly
+// Windows 7 32-bit VM ==> between 16-17 thousand characters
+// - 16000x1 works, 17000x1 fails instantly
+// - 163x100 *crashes* conhost.exe but leaves VeryLargeRead.exe running
+// Windows 8 32-bit VM ==> between 240-250 million characters
+// - 10000x24000 works, but 10000x25000 does not
+// Windows 8.1 32-bit VM ==> between 240-250 million characters
+// - 10000x24000 works, but 10000x25000 does not
+// Windows 10 64-bit VM ==> no limit (tested to 576 million characters)
+// - 24000x24000 works
+// - `ver` reports [Version 10.0.10240], conhost.exe and ConhostV1.dll are
+// 10.0.10240.16384 for file and product version. ConhostV2.dll is
+// 10.0.10240.16391 for file and product version.
+//
+// Server OSs
+//
+// Windows Server 2008 64-bit VM ==> 14300-14400 characters
+// - 14300x1 works, 14400x1 fails instantly
+// - This OS does not have conhost.exe.
+// - `ver` reports [Version 6.0.6002]
+// Windows Server 2008 R2 64-bit VM ==> 15600-15700 characters
+// - 15600x1 works, 15700x1 fails instantly
+// - This OS has conhost.exe, and procexp.exe reveals console ALPC ports in
+// use in conhost.exe.
+// - `ver` reports [Version 6.1.7601], conhost.exe is 6.1.7601.23153 for file
+// and product version.
+// Windows Server 2012 64-bit VM ==> at least 100 million characters
+// - 10000x10000 works (VM had only 1GiB of RAM, so I skipped larger tests)
+// - This OS has Windows 8's task manager and procexp.exe reveals the same
+// lack of ALPC ports and the same \Device\ConDrv\* files as Windows 8.
+// - `ver` reports [Version 6.2.9200], conhost.exe is 6.2.9200.16579 for file
+// and product version.
+//
+// To summarize:
+//
+// client-OS server-OS notes
+// ---------------------------------------------------------------------------
+// XP Server 2008 CSRSS, small reads
+// 7 Server 2008 R2 ALPC-to-conhost, small reads
+// 8, 8.1 Server 2012 new I/O interface, large reads allowed
+// 10 <no server OS yet> enhanced console w/rewrapping
+//
+// (Presumably, Win2K, Vista, and Win2K3 behave the same as XP. conhost.exe
+// was announced as a Win7 feature.)
+//
+
+#include <windows.h>
+#include <assert.h>
+#include <vector>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ long long width = 9000;
+ long long height = 9000;
+
+ assert(argc >= 1);
+ if (argc == 4) {
+ width = atoi(argv[2]);
+ height = atoi(argv[3]);
+ } else {
+ if (argc == 3) {
+ width = atoi(argv[1]);
+ height = atoi(argv[2]);
+ }
+ wchar_t args[1024];
+ swprintf(args, 1024, L"CHILD %lld %lld", width, height);
+ startChildProcess(args);
+ return 0;
+ }
+
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(width, height);
+ setWindowPos(0, 0, std::min(80LL, width), std::min(50LL, height));
+
+ setCursorPos(0, 0);
+ printf("A");
+ fflush(stdout);
+ setCursorPos(width - 2, height - 1);
+ printf("B");
+ fflush(stdout);
+
+ trace("sizeof(CHAR_INFO) = %d", (int)sizeof(CHAR_INFO));
+
+ trace("Allocating buffer...");
+ CHAR_INFO *buffer = new CHAR_INFO[width * height];
+ assert(buffer != NULL);
+ memset(&buffer[0], 0, sizeof(CHAR_INFO));
+ memset(&buffer[width * height - 2], 0, sizeof(CHAR_INFO));
+
+ COORD bufSize = { width, height };
+ COORD bufCoord = { 0, 0 };
+ SMALL_RECT readRegion = { 0, 0, width - 1, height - 1 };
+ trace("ReadConsoleOutputW: calling...");
+ BOOL success = ReadConsoleOutputW(conout, buffer, bufSize, bufCoord, &readRegion);
+ trace("ReadConsoleOutputW: success=%d", success);
+
+ assert(buffer[0].Char.UnicodeChar == L'A');
+ assert(buffer[width * height - 2].Char.UnicodeChar == L'B');
+ trace("Top-left and bottom-right characters read successfully!");
+
+ Sleep(30000);
+
+ delete [] buffer;
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc b/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc
new file mode 100644
index 0000000000..97bf59f998
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc
@@ -0,0 +1,56 @@
+/*
+ * Sending VK_PAUSE to the console window almost works as a mechanism for
+ * pausing it, but it doesn't because the console could turn off the
+ * ENABLE_LINE_INPUT console mode flag.
+ */
+
+#define _WIN32_WINNT 0x0501
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+
+CALLBACK DWORD pausingThread(LPVOID dummy)
+{
+ if (1) {
+ Sleep(1000);
+ HWND hwnd = GetConsoleWindow();
+ SendMessage(hwnd, WM_KEYDOWN, VK_PAUSE, 1);
+ Sleep(1000);
+ SendMessage(hwnd, WM_KEYDOWN, VK_ESCAPE, 1);
+ }
+
+ if (0) {
+ INPUT_RECORD ir;
+ memset(&ir, 0, sizeof(ir));
+ ir.EventType = KEY_EVENT;
+ ir.Event.KeyEvent.bKeyDown = TRUE;
+ ir.Event.KeyEvent.wVirtualKeyCode = VK_PAUSE;
+ ir.Event.KeyEvent.wRepeatCount = 1;
+ }
+
+ return 0;
+}
+
+int main()
+{
+ HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ COORD c = { 0, 0 };
+
+ DWORD mode;
+ GetConsoleMode(hin, &mode);
+ SetConsoleMode(hin, mode &
+ ~(ENABLE_LINE_INPUT));
+
+ CreateThread(NULL, 0,
+ pausingThread, NULL,
+ 0, NULL);
+
+ int i = 0;
+ while (true) {
+ Sleep(100);
+ printf("%d\n", ++i);
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc b/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc
new file mode 100644
index 0000000000..82feaf3c50
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc
@@ -0,0 +1,52 @@
+/*
+ * Demonstrates a conhost hang that occurs when widening the console buffer
+ * while selection is in progress. The problem affects the new Windows 10
+ * console, not the "legacy" console mode that Windows 10 also includes.
+ *
+ * First tested with:
+ * - Windows 10.0.10240
+ * - conhost.exe version 10.0.10240.16384
+ * - ConhostV1.dll version 10.0.10240.16384
+ * - ConhostV2.dll version 10.0.10240.16391
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include "TestUtil.cc"
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(80, 25);
+ setWindowPos(0, 0, 80, 25);
+
+ countDown(5);
+
+ SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
+ Sleep(2000);
+
+ // This API call does not return. In the console window, the "Select All"
+ // operation appears to end. The console window becomes non-responsive,
+ // and the conhost.exe process must be killed from the Task Manager.
+ // (Killing this test program or closing the console window is not
+ // sufficient.)
+ //
+ // The same hang occurs whether line resizing is off or on. It happens
+ // with both "Mark" and "Select All". Calling setBufferSize with the
+ // existing buffer size does not hang, but calling it with only a changed
+ // buffer height *does* hang. Calling setWindowPos does not hang.
+ setBufferSize(120, 25);
+
+ printf("Done...\n");
+ Sleep(2000);
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc b/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc
new file mode 100644
index 0000000000..645fa95d54
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc
@@ -0,0 +1,57 @@
+/*
+ * Demonstrates some wrapping behaviors of the new Windows 10 console.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(40, 20);
+ setWindowPos(0, 0, 40, 20);
+
+ system("cls");
+
+ repeatChar(39, 'A'); repeatChar(1, ' ');
+ repeatChar(39, 'B'); repeatChar(1, ' ');
+ printf("\n");
+
+ repeatChar(39, 'C'); repeatChar(1, ' ');
+ repeatChar(39, 'D'); repeatChar(1, ' ');
+ printf("\n");
+
+ repeatChar(40, 'E');
+ repeatChar(40, 'F');
+ printf("\n");
+
+ repeatChar(39, 'G'); repeatChar(1, ' ');
+ repeatChar(39, 'H'); repeatChar(1, ' ');
+ printf("\n");
+
+ Sleep(2000);
+
+ setChar(39, 0, '*', 0x24);
+ setChar(39, 1, '*', 0x24);
+
+ setChar(39, 3, ' ', 0x24);
+ setChar(39, 4, ' ', 0x24);
+
+ setChar(38, 6, ' ', 0x24);
+ setChar(38, 7, ' ', 0x24);
+
+ Sleep(2000);
+ setWindowPos(0, 0, 35, 20);
+ setBufferSize(35, 20);
+ trace("DONE");
+
+ printf("Sleeping forever...\n");
+ while(true) { Sleep(1000); }
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc b/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc
new file mode 100644
index 0000000000..50615fc8c7
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc
@@ -0,0 +1,30 @@
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ startChildProcess(L"CHILD");
+ return 0;
+ }
+
+ const int WIDTH = 25;
+
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(WIDTH, 40);
+ setWindowPos(0, 0, WIDTH, 20);
+
+ system("cls");
+
+ for (int i = 0; i < 100; ++i) {
+ printf("FOO(%d)\n", i);
+ }
+
+ repeatChar(5, '\n');
+ repeatChar(WIDTH * 5, '.');
+ repeatChar(10, '\n');
+ setWindowPos(0, 20, WIDTH, 20);
+ writeBox(0, 5, 1, 10, '|');
+
+ Sleep(120000);
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Echo1.cc b/src/libs/3rdparty/winpty/misc/Win32Echo1.cc
new file mode 100644
index 0000000000..06fc79f794
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Echo1.cc
@@ -0,0 +1,26 @@
+/*
+ * A Win32 program that reads raw console input with ReadFile and echos
+ * it to stdout.
+ */
+
+#include <stdio.h>
+#include <conio.h>
+#include <windows.h>
+
+int main()
+{
+ int count = 0;
+ HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleMode(hStdIn, 0);
+
+ while (true) {
+ DWORD actual;
+ char ch;
+ ReadFile(hStdIn, &ch, 1, &actual, NULL);
+ printf("%02x ", ch);
+ if (++count == 50)
+ break;
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Echo2.cc b/src/libs/3rdparty/winpty/misc/Win32Echo2.cc
new file mode 100644
index 0000000000..b2ea2ad1c5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Echo2.cc
@@ -0,0 +1,19 @@
+/*
+ * A Win32 program that reads raw console input with getch and echos
+ * it to stdout.
+ */
+
+#include <stdio.h>
+#include <conio.h>
+
+int main()
+{
+ int count = 0;
+ while (true) {
+ int ch = getch();
+ printf("%02x ", ch);
+ if (++count == 50)
+ break;
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Test1.cc b/src/libs/3rdparty/winpty/misc/Win32Test1.cc
new file mode 100644
index 0000000000..a40d318a98
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Test1.cc
@@ -0,0 +1,46 @@
+#define _WIN32_WINNT 0x0501
+#include "../src/shared/DebugClient.cc"
+#include <windows.h>
+#include <stdio.h>
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+
+CALLBACK DWORD writerThread(void*)
+{
+ while (true) {
+ Sleep(1000);
+ trace("writing");
+ printf("X\n");
+ trace("written");
+ }
+}
+
+int main()
+{
+ CreateThread(NULL, 0, writerThread, NULL, 0, NULL);
+ trace("marking console");
+ HWND hwnd = GetConsoleWindow();
+ PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
+
+ Sleep(2000);
+
+ trace("reading output");
+ CHAR_INFO buf[1];
+ COORD bufSize = { 1, 1 };
+ COORD zeroCoord = { 0, 0 };
+ SMALL_RECT readRect = { 0, 0, 0, 0 };
+ ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE),
+ buf,
+ bufSize,
+ zeroCoord,
+ &readRect);
+ trace("done reading output");
+
+ Sleep(2000);
+
+ PostMessage(hwnd, WM_CHAR, 27, 0x00010001);
+
+ Sleep(1100);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Test2.cc b/src/libs/3rdparty/winpty/misc/Win32Test2.cc
new file mode 100644
index 0000000000..2777bad456
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Test2.cc
@@ -0,0 +1,70 @@
+/*
+ * This test demonstrates that putting a console into selection mode does not
+ * block the low-level console APIs, even though it blocks WriteFile.
+ */
+
+#define _WIN32_WINNT 0x0501
+#include "../src/shared/DebugClient.cc"
+#include <windows.h>
+#include <stdio.h>
+
+const int SC_CONSOLE_MARK = 0xFFF2;
+
+CALLBACK DWORD writerThread(void*)
+{
+ CHAR_INFO xChar, fillChar;
+ memset(&xChar, 0, sizeof(xChar));
+ xChar.Char.AsciiChar = 'X';
+ xChar.Attributes = 7;
+ memset(&fillChar, 0, sizeof(fillChar));
+ fillChar.Char.AsciiChar = ' ';
+ fillChar.Attributes = 7;
+ COORD oneCoord = { 1, 1 };
+ COORD zeroCoord = { 0, 0 };
+
+ while (true) {
+ SMALL_RECT writeRegion = { 5, 5, 5, 5 };
+ WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE),
+ &xChar, oneCoord,
+ zeroCoord,
+ &writeRegion);
+ Sleep(500);
+ SMALL_RECT scrollRect = { 1, 1, 20, 20 };
+ COORD destCoord = { 0, 0 };
+ ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE),
+ &scrollRect,
+ NULL,
+ destCoord,
+ &fillChar);
+ }
+}
+
+int main()
+{
+ CreateThread(NULL, 0, writerThread, NULL, 0, NULL);
+ trace("marking console");
+ HWND hwnd = GetConsoleWindow();
+ PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
+
+ Sleep(2000);
+
+ trace("reading output");
+ CHAR_INFO buf[1];
+ COORD bufSize = { 1, 1 };
+ COORD zeroCoord = { 0, 0 };
+ SMALL_RECT readRect = { 0, 0, 0, 0 };
+ ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE),
+ buf,
+ bufSize,
+ zeroCoord,
+ &readRect);
+ trace("done reading output");
+
+ Sleep(2000);
+
+ PostMessage(hwnd, WM_CHAR, 27, 0x00010001);
+
+ Sleep(1100);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Test3.cc b/src/libs/3rdparty/winpty/misc/Win32Test3.cc
new file mode 100644
index 0000000000..1fb92aff3d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Test3.cc
@@ -0,0 +1,78 @@
+/*
+ * Creates a window station and starts a process under it. The new process
+ * also gets a new console.
+ */
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+int main()
+{
+ BOOL success;
+
+ SECURITY_ATTRIBUTES sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.bInheritHandle = TRUE;
+
+ HWINSTA originalStation = GetProcessWindowStation();
+ printf("originalStation == 0x%x\n", originalStation);
+ HWINSTA station = CreateWindowStation(NULL,
+ 0,
+ WINSTA_ALL_ACCESS,
+ &sa);
+ printf("station == 0x%x\n", station);
+ if (!SetProcessWindowStation(station))
+ printf("SetWindowStation failed!\n");
+ HDESK desktop = CreateDesktop("Default", NULL, NULL,
+ /*dwFlags=*/0, GENERIC_ALL,
+ &sa);
+ printf("desktop = 0x%x\n", desktop);
+
+ char stationName[256];
+ stationName[0] = '\0';
+ success = GetUserObjectInformation(station, UOI_NAME,
+ stationName, sizeof(stationName),
+ NULL);
+ printf("stationName = [%s]\n", stationName);
+
+ char startupDesktop[256];
+ sprintf(startupDesktop, "%s\\Default", stationName);
+
+ STARTUPINFO sui;
+ PROCESS_INFORMATION pi;
+ memset(&sui, 0, sizeof(sui));
+ memset(&pi, 0, sizeof(pi));
+ sui.cb = sizeof(STARTUPINFO);
+ sui.lpDesktop = startupDesktop;
+
+ // Start a cmd subprocess, and have it start its own cmd subprocess.
+ // Both subprocesses will connect to the same non-interactive window
+ // station.
+
+ const char program[] = "c:\\windows\\system32\\cmd.exe";
+ char cmdline[256];
+ sprintf(cmdline, "%s /c cmd", program);
+ success = CreateProcess(program,
+ cmdline,
+ NULL,
+ NULL,
+ /*bInheritHandles=*/FALSE,
+ /*dwCreationFlags=*/CREATE_NEW_CONSOLE,
+ NULL, NULL,
+ &sui,
+ &pi);
+
+ printf("pid == %d\n", pi.dwProcessId);
+
+ // This sleep is necessary. We must give the child enough time to
+ // connect to the specified window station.
+ Sleep(5000);
+
+ SetProcessWindowStation(originalStation);
+ CloseWindowStation(station);
+ CloseDesktop(desktop);
+ Sleep(5000);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/Win32Write1.cc b/src/libs/3rdparty/winpty/misc/Win32Write1.cc
new file mode 100644
index 0000000000..6e5bf96682
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/Win32Write1.cc
@@ -0,0 +1,44 @@
+/*
+ * A Win32 program that scrolls and writes to the console using the ioctl-like
+ * interface.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+int main()
+{
+ HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ for (int i = 0; i < 80; ++i) {
+
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo(conout, &info);
+
+ SMALL_RECT src = { 0, 1, info.dwSize.X - 1, info.dwSize.Y - 1 };
+ COORD destOrigin = { 0, 0 };
+ CHAR_INFO fillCharInfo = { 0 };
+ fillCharInfo.Char.AsciiChar = ' ';
+ fillCharInfo.Attributes = 7;
+ ScrollConsoleScreenBuffer(conout,
+ &src,
+ NULL,
+ destOrigin,
+ &fillCharInfo);
+
+ CHAR_INFO buffer = { 0 };
+ buffer.Char.AsciiChar = 'X';
+ buffer.Attributes = 7;
+ COORD bufferSize = { 1, 1 };
+ COORD bufferCoord = { 0, 0 };
+ SMALL_RECT writeRegion = { 0, 0, 0, 0 };
+ writeRegion.Left = writeRegion.Right = i;
+ writeRegion.Top = writeRegion.Bottom = 5;
+ WriteConsoleOutput(conout,
+ &buffer, bufferSize, bufferCoord,
+ &writeRegion);
+
+ Sleep(250);
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc b/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc
new file mode 100644
index 0000000000..e6d9558df6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc
@@ -0,0 +1,27 @@
+// I noticed this on the ConEmu web site:
+//
+// https://social.msdn.microsoft.com/Forums/en-US/40c8e395-cca9-45c8-b9b8-2fbe6782ac2b/readconsoleoutput-cause-access-violation-writing-location-exception
+// https://conemu.github.io/en/MicrosoftBugs.html
+//
+// In Windows 7, 8, and 8.1, a ReadConsoleOutputW with an out-of-bounds read
+// region crashes the application. I have reproduced the problem on Windows 8
+// and 8.1, but not on Windows 7.
+//
+
+#include <windows.h>
+
+#include "TestUtil.cc"
+
+int main() {
+ setWindowPos(0, 0, 1, 1);
+ setBufferSize(80, 25);
+ setWindowPos(0, 0, 80, 25);
+
+ const HANDLE conout = openConout();
+ static CHAR_INFO lineBuf[80];
+ SMALL_RECT readRegion = { 0, 999, 79, 999 };
+ const BOOL ret = ReadConsoleOutputW(conout, lineBuf, {80, 1}, {0, 0}, &readRegion);
+ ASSERT(!ret && "ReadConsoleOutputW should have failed");
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/WriteConsole.cc b/src/libs/3rdparty/winpty/misc/WriteConsole.cc
new file mode 100644
index 0000000000..a03670ca92
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/WriteConsole.cc
@@ -0,0 +1,106 @@
+#include <windows.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+static std::wstring mbsToWcs(const std::string &s) {
+ const size_t len = mbstowcs(nullptr, s.c_str(), 0);
+ if (len == static_cast<size_t>(-1)) {
+ assert(false && "mbsToWcs: invalid string");
+ }
+ std::wstring ret;
+ ret.resize(len);
+ const size_t len2 = mbstowcs(&ret[0], s.c_str(), len);
+ assert(len == len2);
+ return ret;
+}
+
+uint32_t parseHex(wchar_t ch, bool &invalid) {
+ if (ch >= L'0' && ch <= L'9') {
+ return ch - L'0';
+ } else if (ch >= L'a' && ch <= L'f') {
+ return ch - L'a' + 10;
+ } else if (ch >= L'A' && ch <= L'F') {
+ return ch - L'A' + 10;
+ } else {
+ invalid = true;
+ return 0;
+ }
+}
+
+int main(int argc, char *argv[]) {
+ std::vector<std::wstring> args;
+ for (int i = 1; i < argc; ++i) {
+ args.push_back(mbsToWcs(argv[i]));
+ }
+
+ std::wstring out;
+ for (const auto &arg : args) {
+ if (!out.empty()) {
+ out.push_back(L' ');
+ }
+ for (size_t i = 0; i < arg.size(); ++i) {
+ wchar_t ch = arg[i];
+ wchar_t nch = i + 1 < arg.size() ? arg[i + 1] : L'\0';
+ if (ch == L'\\') {
+ switch (nch) {
+ case L'a': ch = L'\a'; ++i; break;
+ case L'b': ch = L'\b'; ++i; break;
+ case L'e': ch = L'\x1b'; ++i; break;
+ case L'f': ch = L'\f'; ++i; break;
+ case L'n': ch = L'\n'; ++i; break;
+ case L'r': ch = L'\r'; ++i; break;
+ case L't': ch = L'\t'; ++i; break;
+ case L'v': ch = L'\v'; ++i; break;
+ case L'\\': ch = L'\\'; ++i; break;
+ case L'\'': ch = L'\''; ++i; break;
+ case L'\"': ch = L'\"'; ++i; break;
+ case L'\?': ch = L'\?'; ++i; break;
+ case L'x':
+ if (i + 3 < arg.size()) {
+ bool invalid = false;
+ uint32_t d1 = parseHex(arg[i + 2], invalid);
+ uint32_t d2 = parseHex(arg[i + 3], invalid);
+ if (!invalid) {
+ i += 3;
+ ch = (d1 << 4) | d2;
+ }
+ }
+ break;
+ case L'u':
+ if (i + 5 < arg.size()) {
+ bool invalid = false;
+ uint32_t d1 = parseHex(arg[i + 2], invalid);
+ uint32_t d2 = parseHex(arg[i + 3], invalid);
+ uint32_t d3 = parseHex(arg[i + 4], invalid);
+ uint32_t d4 = parseHex(arg[i + 5], invalid);
+ if (!invalid) {
+ i += 5;
+ ch = (d1 << 24) | (d2 << 16) | (d3 << 8) | d4;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ out.push_back(ch);
+ }
+ }
+
+ DWORD actual = 0;
+ if (!WriteConsoleW(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ out.c_str(),
+ out.size(),
+ &actual,
+ nullptr)) {
+ fprintf(stderr, "WriteConsole failed (is stdout a console?)\n");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/misc/build32.sh b/src/libs/3rdparty/winpty/misc/build32.sh
new file mode 100644
index 0000000000..162993ce33
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/build32.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+name=$1
+name=${name%.}
+name=${name%.cc}
+name=${name%.exe}
+echo Compiling $name.cc to $name.exe
+i686-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe
+i686-w64-mingw32-strip $name.exe
diff --git a/src/libs/3rdparty/winpty/misc/build64.sh b/src/libs/3rdparty/winpty/misc/build64.sh
new file mode 100644
index 0000000000..6757967684
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/build64.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+name=$1
+name=${name%.}
+name=${name%.cc}
+name=${name%.exe}
+echo Compiling $name.cc to $name.exe
+x86_64-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe
+x86_64-w64-mingw32-strip $name.exe
diff --git a/src/libs/3rdparty/winpty/misc/color-test.sh b/src/libs/3rdparty/winpty/misc/color-test.sh
new file mode 100644
index 0000000000..065c8094e2
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/color-test.sh
@@ -0,0 +1,212 @@
+#!/bin/bash
+
+FORE=$1
+BACK=$2
+FILL=$3
+
+if [ "$FORE" = "" ]; then
+ FORE=DefaultFore
+fi
+if [ "$BACK" = "" ]; then
+ BACK=DefaultBack
+fi
+
+# To detect color changes, we want a character that fills the whole cell
+# if possible. U+2588 is perfect, except that it becomes invisible in the
+# original xterm, when bolded. For that terminal, use something else, like
+# "#" or "@".
+if [ "$FILL" = "" ]; then
+ FILL="█"
+fi
+
+# SGR (Select Graphic Rendition)
+s() {
+ printf '\033[0m'
+ while [ "$1" != "" ]; do
+ printf '\033['"$1"'m'
+ shift
+ done
+}
+
+# Print
+p() {
+ echo -n "$@"
+}
+
+# Print with newline
+pn() {
+ echo "$@"
+}
+
+# For practical reasons, sandwich black and white in-between the other colors.
+FORE_COLORS="31 30 37 32 33 34 35 36"
+BACK_COLORS="41 40 47 42 43 44 45 46"
+
+
+
+### Test order of Invert(7) -- it does not matter what order it appears in.
+
+# The Red color setting here (31) is shadowed by the green setting (32). The
+# Reverse flag does not cause (32) to alter the background color immediately;
+# instead, the Reverse flag is applied once to determine the final effective
+# Fore/Back colors.
+s 7 31 32; p " -- Should be: $BACK-on-green -- "; s; pn
+s 31 7 32; p " -- Should be: $BACK-on-green -- "; s; pn
+s 31 32 7; p " -- Should be: $BACK-on-green -- "; s; pn
+
+# As above, but for the background color.
+s 7 41 42; p " -- Should be: green-on-$FORE -- "; s; pn
+s 41 7 42; p " -- Should be: green-on-$FORE -- "; s; pn
+s 41 42 7; p " -- Should be: green-on-$FORE -- "; s; pn
+
+# One last, related test
+s 7; p "Invert text"; s 7 1; p " with some words bold"; s; pn;
+s 0; p "Normal text"; s 0 1; p " with some words bold"; s; pn;
+
+pn
+
+
+
+### Test effect of Bold(1) on color, with and without Invert(7).
+
+# The Bold flag does not affect the background color when Reverse is missing.
+# There should always be 8 colored boxes.
+p " "
+for x in $BACK_COLORS; do
+ s $x; p "-"; s $x 1; p "-"
+done
+s; pn " Bold should not affect background"
+
+# On some terminals, Bold affects color, and on some it doesn't. If there
+# are only 8 colored boxes, then the next two tests will also show 8 colored
+# boxes. If there are 16 boxes, then exactly one of the next two tests will
+# also have 16 boxes.
+p " "
+for x in $FORE_COLORS; do
+ s $x; p "$FILL"; s $x 1; p "$FILL"
+done
+s; pn " Does bold affect foreground color?"
+
+# On some terminals, Bold+Invert highlights the final Background color.
+p " "
+for x in $FORE_COLORS; do
+ s $x 7; p "-"; s $x 7 1; p "-"
+done
+s; pn " Test if Bold+Invert affects background color"
+
+# On some terminals, Bold+Invert highlights the final Foreground color.
+p " "
+for x in $BACK_COLORS; do
+ s $x 7; p "$FILL"; s $x 7 1; p "$FILL"
+done
+s; pn " Test if Bold+Invert affects foreground color"
+
+pn
+
+
+
+### Test for support of ForeHi and BackHi properties.
+
+# ForeHi
+p " "
+for x in $FORE_COLORS; do
+ hi=$(( $x + 60 ))
+ s $x; p "$FILL"; s $hi; p "$FILL"
+done
+s; pn " Test for support of ForeHi colors"
+p " "
+for x in $FORE_COLORS; do
+ hi=$(( $x + 60 ))
+ s $x; p "$FILL"; s $x $hi; p "$FILL"
+done
+s; pn " Test for support of ForeHi colors (w/compat)"
+
+# BackHi
+p " "
+for x in $BACK_COLORS; do
+ hi=$(( $x + 60 ))
+ s $x; p "-"; s $hi; p "-"
+done
+s; pn " Test for support of BackHi colors"
+p " "
+for x in $BACK_COLORS; do
+ hi=$(( $x + 60 ))
+ s $x; p "-"; s $x $hi; p "-"
+done
+s; pn " Test for support of BackHi colors (w/compat)"
+
+pn
+
+
+
+### Identify the default fore and back colors.
+
+pn "Match default fore and back colors against 16-color palette"
+pn " ==fore== ==back=="
+for fore in $FORE_COLORS; do
+ forehi=$(( $fore + 60 ))
+ back=$(( $fore + 10 ))
+ backhi=$(( $back + 60 ))
+ p " "
+ s $fore; p "$FILL"; s; p "$FILL"; s $fore; p "$FILL"; s; p " "
+ s $forehi; p "$FILL"; s; p "$FILL"; s $forehi; p "$FILL"; s; p " "
+ s $back; p "-"; s; p "-"; s $back; p "-"; s; p " "
+ s $backhi; p "-"; s; p "-"; s $backhi; p "-"; s; p " "
+ pn " $fore $forehi $back $backhi"
+done
+
+pn
+
+
+
+### Test coloring of rest-of-line.
+
+#
+# When a new line is scrolled in, every cell in the line receives the
+# current background color, which can be the default/transparent color.
+#
+
+p "Newline with red background: usually no red -->"; s 41; pn
+s; pn "This text is plain, but rest is red if scrolled -->"
+s; p " "; s 41; printf '\033[1K'; s; printf '\033[1C'; pn "<-- red Erase-in-Line to beginning"
+s; p "red Erase-in-Line to end -->"; s 41; printf '\033[0K'; s; pn
+pn
+
+
+
+### Moving the cursor around does not change colors of anything.
+
+pn "Test modifying uncolored lines with a colored SGR:"
+pn "aaaa"
+pn
+pn "____e"
+s 31 42; printf '\033[4C\033[3A'; pn "bb"
+pn "cccc"
+pn "dddd"
+s; pn
+
+pn "Test modifying colored+inverted+bold line with plain text:"
+s 42 31 7 1; printf 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r';
+s; pn "This text is plain and followed by green-on-red -->"
+pn
+
+
+
+### Full-width character overwriting
+
+pn 'Overwrite part of a full-width char with a half-width char'
+p 'initial U+4000 ideographs -->'; s 31 42; p '䀀䀀'; s; pn
+p 'write X to index #1 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[24G'; p X; s; pn
+p 'write X to index #2 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[25G'; p X; s; pn
+p 'write X to index #3 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[26G'; p X; s; pn
+p 'write X to index #4 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[27G'; p X; s; pn
+pn
+
+pn 'Verify that Erase-in-Line can "fix" last char in line'
+p 'original -->'; s 31 42; p '䀀䀀'; s; pn
+p 'overwrite -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; pn
+p 'overwrite + Erase-in-Line -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; printf '\033[0K'; pn
+p 'original -->'; s 31 42; p 'X䀀䀀'; s; pn
+p 'overwrite -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; pn
+p 'overwrite + Erase-in-Line -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; printf '\033[0K'; pn
+pn
diff --git a/src/libs/3rdparty/winpty/misc/font-notes.txt b/src/libs/3rdparty/winpty/misc/font-notes.txt
new file mode 100644
index 0000000000..d4e36d8e25
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/font-notes.txt
@@ -0,0 +1,300 @@
+==================================================================
+Notes regarding fonts, code pages, and East Asian character widths
+==================================================================
+
+
+Registry settings
+=================
+
+ * There are console registry settings in `HKCU\Console`. That key has many
+ default settings (e.g. the default font settings) and also per-app subkeys
+ for app-specific overrides.
+
+ * It is possible to override the code page with an app-specific setting.
+
+ * There are registry settings in
+ `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console`. In particular,
+ the `TrueTypeFont` subkey has a list of suitable font names associated with
+ various CJK code pages, as well as default font names.
+
+ * There are two values in `HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage`
+ that specify the current code pages -- `OEMCP` and `ACP`. Setting the
+ system locale via the Control Panel's "Region" or "Language" dialogs seems
+ to change these code page values.
+
+
+Console fonts
+=============
+
+ * The `FontFamily` field of `CONSOLE_FONT_INFOEX` has two parts:
+ - The high four bits can be exactly one of the `FF_xxxx` font families:
+ FF_DONTCARE(0x00)
+ FF_ROMAN(0x10)
+ FF_SWISS(0x20)
+ FF_MODERN(0x30)
+ FF_SCRIPT(0x40)
+ FF_DECORATIVE(0x50)
+ - The low four bits are a bitmask:
+ TMPF_FIXED_PITCH(1) -- actually means variable pitch
+ TMPF_VECTOR(2)
+ TMPF_TRUETYPE(4)
+ TMPF_DEVICE(8)
+
+ * Each console has its own independent console font table. The current font
+ is identified with an index into this table. The size of the table is
+ returned by the undocumented `GetNumberOfConsoleFonts` API. It is apparently
+ possible to get the table size without this API, by instead calling
+ `GetConsoleFontSize` on each nonnegative index starting with 0 until the API
+ fails by returning (0, 0).
+
+ * The font table grows dynamically. Each time the console is configured with
+ a previously-unused (FaceName, Size) combination, two entries are added to
+ the font table -- one with normal weight and one with bold weight. Fonts
+ added this way are always TrueType fonts.
+
+ * Initially, the font table appears to contain only raster fonts. For
+ example, on an English Windows 8 installation, here is the initial font
+ table:
+ font 0: 4x6
+ font 1: 6x8
+ font 2: 8x8
+ font 3: 16x8
+ font 4: 5x12
+ font 5: 7x12
+ font 6: 8x12 -- the current font
+ font 7: 16x12
+ font 8: 12x16
+ font 9: 10x18
+ `GetNumberOfConsoleFonts` returns 10, and this table matches the raster font
+ sizes according to the console properties dialog.
+
+ * With a Japanese or Chinese locale, the initial font table appears to contain
+ the sizes applicable to both the East Asian raster font, as well as the
+ sizes for the CP437/CP1252 raster font.
+
+ * The index passed to `SetCurrentConsoleFontEx` apparently has no effect.
+ The undocumented `SetConsoleFont` API, however, accepts *only* a font index,
+ and on Windows 8 English, it switches between all 10 fonts, even font index
+ #0.
+
+ * If the index passed to `SetConsoleFont` identifies a Raster Font
+ incompatible with the current code page, then another Raster Font is
+ activated.
+
+ * Passing "Terminal" to `SetCurrentConsoleFontEx` seems to have no effect.
+ Perhaps relatedly, `SetCurrentConsoleFontEx` does not fail if it is given a
+ bogus `FaceName`. Some font is still chosen and activated. Passing a face
+ name and height seems to work reliably, modulo the CP936 issue described
+ below.
+
+
+Console fonts and code pages
+============================
+
+ * On an English Windows installation, the default code page is 437, and it
+ cannot be set to 932 (Shift-JIS). (The API call fails.) Changing the
+ system locale to "Japanese (Japan)" using the Region/Language dialog
+ changes the default CP to 932 and permits changing the console CP between
+ 437 and 932.
+
+ * A console has both an input code page and an output code page
+ (`{Get,Set}ConsoleCP` and `{Get,Set}ConsoleOutputCP`). I'm not going to
+ distinguish between the two for this document; presumably only the output
+ CP matters. The code page can change while the console is open, e.g.
+ by running `mode con: cp select={932,437,1252}` or by calling
+ `SetConsoleOutputCP`.
+
+ * The current code page restricts which TrueType fonts and which Raster Font
+ sizes are available in the console properties dialog. This can change
+ while the console is open.
+
+ * Changing the code page almost(?) always changes the current console font.
+ So far, I don't know how the new font is chosen.
+
+ * With a CP of 932, the only TrueType font available in the console properties
+ dialog is "MS Gothic", displayed as "MS ゴシック". It is still possible to
+ use the English-default TrueType console fonts, Lucida Console and Consolas,
+ via `SetCurrentConsoleFontEx`.
+
+ * When using a Raster Font and CP437 or CP1252, writing a UTF-16 codepoint not
+ representable in the code page instead writes a question mark ('?') to the
+ console. This conversion does not apply with a TrueType font, nor with the
+ Raster Font for CP932 or CP936.
+
+
+ReadConsoleOutput and double-width characters
+==============================================
+
+ * With a Raster Font active, when `ReadConsoleOutputW` reads two cells of a
+ double-width character, it fills only a single `CHAR_INFO` structure. The
+ unused trailing `CHAR_INFO` structures are zero-filled. With a TrueType
+ font active, `ReadConsoleOutputW` instead fills two `CHAR_INFO` structures,
+ the first marked with `COMMON_LVB_LEADING_BYTE` and the second marked with
+ `COMMON_LVB_TRAILING_BYTE`. The flag is a misnomer--there aren't two
+ *bytes*, but two cells, and they have equal `CHAR_INFO.Char.UnicodeChar`
+ values.
+
+ * `ReadConsoleOutputA`, on the other hand, reads two `CHAR_INFO` cells, and
+ if the UTF-16 value can be represented as two bytes in the ANSI/OEM CP, then
+ the two bytes are placed in the two `CHAR_INFO.Char.AsciiChar` values, and
+ the `COMMON_LVB_{LEADING,TRAILING}_BYTE` values are also used. If the
+ codepoint isn't representable, I don't remember what happens -- I think the
+ `AsciiChar` values take on an invalid marker.
+
+ * Reading only one cell of a double-width character reads a space (U+0020)
+ instead. Raster-vs-TrueType and wide-vs-ANSI do not matter.
+ - XXX: what about attributes? Can a double-width character have mismatched
+ color attributes?
+ - XXX: what happens when writing to just one cell of a double-width
+ character?
+
+
+Default Windows fonts for East Asian languages
+==============================================
+CP932 / Japanese: "MS ゴシック" (MS Gothic)
+CP936 / Chinese Simplified: "新宋体" (SimSun)
+
+
+Unreliable character width (half-width vs full-width)
+=====================================================
+
+The half-width vs full-width status of a codepoint depends on at least these variables:
+ * OS version (Win10 legacy and new modes are different versions)
+ * system locale (English vs Japanese vs Chinese Simplified vs Chinese Traditional, etc)
+ * code page (437 vs 932 vs 936, etc)
+ * raster vs TrueType (Terminal vs MS Gothic vs SimSun, etc)
+ * font size
+ * rendered-vs-model (rendered width can be larger or smaller than model width)
+
+Example 1: U+2014 (EM DASH): East_Asian_Width: Ambiguous
+--------------------------------------------------------
+ rendered modeled
+CP932: Win7/8 Raster Fonts half half
+CP932: Win7/8 Gothic 14/15px half full
+CP932: Win7/8 Consolas 14/15px half full
+CP932: Win7/8 Lucida Console 14px half full
+CP932: Win7/8 Lucida Console 15px half half
+CP932: Win10New Raster Fonts half half
+CP932: Win10New Gothic 14/15px half half
+CP932: Win10New Consolas 14/15px half half
+CP932: Win10New Lucida Console 14/15px half half
+
+CP936: Win7/8 Raster Fonts full full
+CP936: Win7/8 SimSun 14px full full
+CP936: Win7/8 SimSun 15px full half
+CP936: Win7/8 Consolas 14/15px half full
+CP936: Win10New Raster Fonts full full
+CP936: Win10New SimSum 14/15px full full
+CP936: Win10New Consolas 14/15px half half
+
+Example 2: U+3044 (HIRAGANA LETTER I): East_Asian_Width: Wide
+-------------------------------------------------------------
+ rendered modeled
+CP932: Win7/8/10N Raster Fonts full full
+CP932: Win7/8/10N Gothic 14/15px full full
+CP932: Win7/8/10N Consolas 14/15px half(*2) full
+CP932: Win7/8/10N Lucida Console 14/15px half(*3) full
+
+CP936: Win7/8/10N Raster Fonts full full
+CP936: Win7/8/10N SimSun 14/15px full full
+CP936: Win7/8/10N Consolas 14/15px full full
+
+Example 3: U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK): East_Asian_Width: Wide
+----------------------------------------------------------------------------------
+ rendered modeled
+CP932: Win7 Raster Fonts full full
+CP932: Win7 Gothic 14/15px full full
+CP932: Win7 Consolas 14/15px half(*2) full
+CP932: Win7 Lucida Console 14px half(*3) full
+CP932: Win7 Lucida Console 15px half(*3) half
+CP932: Win8 Raster Fonts full full
+CP932: Win8 Gothic 14px full half
+CP932: Win8 Gothic 15px full full
+CP932: Win8 Consolas 14/15px half(*2) full
+CP932: Win8 Lucida Console 14px half(*3) full
+CP932: Win8 Lucida Console 15px half(*3) half
+CP932: Win10New Raster Fonts full full
+CP932: Win10New Gothic 14/15px full full
+CP932: Win10New Consolas 14/15px half(*2) half
+CP932: Win10New Lucida Console 14/15px half(*2) half
+
+CP936: Win7/8 Raster Fonts full full
+CP936: Win7/8 SimSun 14px full full
+CP936: Win7/8 SimSun 15px full half
+CP936: Win7/8 Consolas 14px full full
+CP936: Win7/8 Consolas 15px full half
+CP936: Win10New Raster Fonts full full
+CP936: Win10New SimSum 14/15px full full
+CP936: Win10New Consolas 14/15px full full
+
+Example 4: U+4000 (CJK UNIFIED IDEOGRAPH-4000): East_Asian_Width: Wide
+----------------------------------------------------------------------
+ rendered modeled
+CP932: Win7 Raster Fonts half(*1) half
+CP932: Win7 Gothic 14/15px full full
+CP932: Win7 Consolas 14/15px half(*2) full
+CP932: Win7 Lucida Console 14px half(*3) full
+CP932: Win7 Lucida Console 15px half(*3) half
+CP932: Win8 Raster Fonts half(*1) half
+CP932: Win8 Gothic 14px full half
+CP932: Win8 Gothic 15px full full
+CP932: Win8 Consolas 14/15px half(*2) full
+CP932: Win8 Lucida Console 14px half(*3) full
+CP932: Win8 Lucida Console 15px half(*3) half
+CP932: Win10New Raster Fonts half(*1) half
+CP932: Win10New Gothic 14/15px full full
+CP932: Win10New Consolas 14/15px half(*2) half
+CP932: Win10New Lucida Console 14/15px half(*2) half
+
+CP936: Win7/8 Raster Fonts full full
+CP936: Win7/8 SimSun 14px full full
+CP936: Win7/8 SimSun 15px full half
+CP936: Win7/8 Consolas 14px full full
+CP936: Win7/8 Consolas 15px full half
+CP936: Win10New Raster Fonts full full
+CP936: Win10New SimSum 14/15px full full
+CP936: Win10New Consolas 14/15px full full
+
+(*1) Rendered as a half-width filled white box
+(*2) Rendered as a half-width box with a question mark inside
+(*3) Rendered as a half-width empty box
+(!!) One of the only places in Win10New where rendered and modeled width disagree
+
+
+Windows quirk: unreliable font heights with CP936 / Chinese Simplified
+======================================================================
+
+When I set the font to 新宋体 17px, using either the properties dialog or
+`SetCurrentConsoleFontEx`, the height reported by `GetCurrentConsoleFontEx` is
+not 17, but is instead 19. The same problem does not affect Raster Fonts,
+nor have I seen the problem in the English or Japanese locales. I observed
+this with Windows 7 and Windows 10 new mode.
+
+If I set the font using the facename, width, *and* height, then the
+`SetCurrentConsoleFontEx` and `GetCurrentConsoleFontEx` values agree. If I
+set the font using *only* the facename and height, then the two values
+disagree.
+
+
+Windows bug: GetCurrentConsoleFontEx is initially invalid
+=========================================================
+
+ - Assume there is no configured console font name in the registry. In this
+ case, the console defaults to a raster font.
+ - Open a new console and call the `GetCurrentConsoleFontEx` API.
+ - The `FaceName` field of the returned `CONSOLE_FONT_INFOEX` data
+ structure is incorrect. On Windows 7, 8, and 10, I observed that the
+ field was blank. On Windows 8, occasionally, it instead contained:
+ U+AE72 U+75BE U+0001
+ The other fields of the structure all appeared correct:
+ nFont=6 dwFontSize=(8,12) FontFamily=0x30 FontWeight=400
+ - The `FaceName` field becomes initialized easily:
+ - Open the console properties dialog and click OK. (Cancel is not
+ sufficient.)
+ - Call the undocumented `SetConsoleFont` with the current font table
+ index, which is 6 in the example above.
+ - It seems that the console uncritically accepts whatever string is
+ stored in the registry, including a blank string, and passes it on the
+ the `GetCurrentConsoleFontEx` caller. It is possible to get the console
+ to *write* a blank setting into the registry -- simply open the console
+ (default or app-specific) properties and click OK.
diff --git a/src/libs/3rdparty/winpty/misc/winbug-15048.cc b/src/libs/3rdparty/winpty/misc/winbug-15048.cc
new file mode 100644
index 0000000000..0e98d648c5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/misc/winbug-15048.cc
@@ -0,0 +1,201 @@
+/*
+
+Test program demonstrating a problem in Windows 15048's ReadConsoleOutput API.
+
+To compile:
+
+ cl /nologo /EHsc winbug-15048.cc shell32.lib
+
+Example of regressed input:
+
+Case 1:
+
+ > chcp 932
+ > winbug-15048 -face-gothic 3044
+
+ Correct output:
+
+ 1**34 (nb: U+3044 replaced with '**' to avoid MSVC encoding warning)
+ 5678
+
+ ReadConsoleOutputW (both rows, 3 cols)
+ row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007)
+ row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007)
+
+ ReadConsoleOutputW (both rows, 4 cols)
+ row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007) U+0034(0007)
+ row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
+
+ ReadConsoleOutputW (second row)
+ row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
+
+ ...
+
+ Win10 15048 bad output:
+
+ 1**34
+ 5678
+
+ ReadConsoleOutputW (both rows, 3 cols)
+ row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0035(0007)
+ row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0000(0000)
+
+ ReadConsoleOutputW (both rows, 4 cols)
+ row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0034(0007) U+0035(0007)
+ row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) U+0000(0000)
+
+ ReadConsoleOutputW (second row)
+ row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
+
+ ...
+
+ The U+3044 character (HIRAGANA LETTER I) occupies two columns, but it only
+ fills one record in the ReadConsoleOutput output buffer, which has the
+ effect of shifting the first cell of the second row into the last cell of
+ the first row. Ordinarily, the first and second cells would also have the
+ COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE attributes set, which
+ allows winpty to detect the double-column character.
+
+Case 2:
+
+ > chcp 437
+ > winbug-15048 -face "Lucida Console" -h 4 221A
+
+ The same issue happens with U+221A (SQUARE ROOT), but only in certain
+ fonts. The console seems to think this character occupies two columns
+ if the font is sufficiently small. The Windows console properties dialog
+ doesn't allow fonts below 5 pt, but winpty tries to use 2pt and 4pt Lucida
+ Console to allow very large console windows.
+
+Case 3:
+
+ > chcp 437
+ > winbug-15048 -face "Lucida Console" -h 12 FF12
+
+ The console selection system thinks U+FF12 (FULLWIDTH DIGIT TWO) occupies
+ two columns, which happens to be correct, but it's displayed as a single
+ column unrecognized character. It otherwise behaves the same as the other
+ cases.
+
+*/
+
+#include <windows.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+
+#include <string>
+
+#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
+
+// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
+const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
+const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
+const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
+const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
+
+static void set_font(const wchar_t *name, int size) {
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_FONT_INFOEX fontex {};
+ fontex.cbSize = sizeof(fontex);
+ fontex.dwFontSize.Y = size;
+ fontex.FontWeight = 400;
+ fontex.FontFamily = 0x36;
+ wcsncpy(fontex.FaceName, name, COUNT_OF(fontex.FaceName));
+ assert(SetCurrentConsoleFontEx(conout, FALSE, &fontex));
+}
+
+static void usage(const wchar_t *prog) {
+ printf("Usage: %ls [options]\n", prog);
+ printf(" -h HEIGHT\n");
+ printf(" -face FACENAME\n");
+ printf(" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n");
+ printf(" hhhh -- print U+hhhh\n");
+ exit(1);
+}
+
+static void dump_region(SMALL_RECT region, const char *name) {
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ CHAR_INFO buf[1000];
+ memset(buf, 0xcc, sizeof(buf));
+
+ const int w = region.Right - region.Left + 1;
+ const int h = region.Bottom - region.Top + 1;
+
+ assert(ReadConsoleOutputW(
+ conout, buf, { (short)w, (short)h }, { 0, 0 },
+ &region));
+
+ printf("\n");
+ printf("ReadConsoleOutputW (%s)\n", name);
+ for (int y = 0; y < h; ++y) {
+ printf("row %d: ", region.Top + y);
+ for (int i = 0; i < region.Left * 13; ++i) {
+ printf(" ");
+ }
+ for (int x = 0; x < w; ++x) {
+ const int i = y * w + x;
+ printf("U+%04x(%04x) ", buf[i].Char.UnicodeChar, buf[i].Attributes);
+ }
+ printf("\n");
+ }
+}
+
+int main() {
+ wchar_t *cmdline = GetCommandLineW();
+ int argc = 0;
+ wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
+ const wchar_t *font_name = L"Lucida Console";
+ int font_height = 8;
+ int test_ch = 0xff12; // U+FF12 FULLWIDTH DIGIT TWO
+
+ for (int i = 1; i < argc; ++i) {
+ const std::wstring arg = argv[i];
+ const std::wstring next = i + 1 < argc ? argv[i + 1] : L"";
+ if (arg == L"-face" && i + 1 < argc) {
+ font_name = argv[i + 1];
+ i++;
+ } else if (arg == L"-face-gothic") {
+ font_name = kMSGothic;
+ } else if (arg == L"-face-simsun") {
+ font_name = kNSimSun;
+ } else if (arg == L"-face-minglight") {
+ font_name = kMingLight;
+ } else if (arg == L"-face-gulimche") {
+ font_name = kGulimChe;
+ } else if (arg == L"-h" && i + 1 < argc) {
+ font_height = _wtoi(next.c_str());
+ i++;
+ } else if (arg.c_str()[0] != '-') {
+ test_ch = wcstol(arg.c_str(), NULL, 16);
+ } else {
+ printf("Unrecognized argument: %ls\n", arg.c_str());
+ usage(argv[0]);
+ }
+ }
+
+ const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ set_font(font_name, font_height);
+
+ system("cls");
+ DWORD actual = 0;
+ wchar_t output[] = L"1234\n5678\n";
+ output[1] = test_ch;
+ WriteConsoleW(conout, output, 10, &actual, nullptr);
+
+ dump_region({ 0, 0, 3, 1 }, "both rows, 3 cols");
+ dump_region({ 0, 0, 4, 1 }, "both rows, 4 cols");
+ dump_region({ 0, 1, 4, 1 }, "second row");
+ dump_region({ 0, 0, 4, 0 }, "first row");
+ dump_region({ 1, 0, 4, 0 }, "first row, skip 1");
+ dump_region({ 2, 0, 4, 0 }, "first row, skip 2");
+ dump_region({ 3, 0, 4, 0 }, "first row, skip 3");
+
+ set_font(font_name, 14);
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat b/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat
new file mode 100644
index 0000000000..b6bca7b079
--- /dev/null
+++ b/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat
@@ -0,0 +1,36 @@
+@echo off
+
+setlocal
+cd %~dp0..
+set Path=C:\Python27;C:\Program Files\Git\cmd;%Path%
+
+call "%VS140COMNTOOLS%\VsDevCmd.bat" || goto :fail
+
+rmdir /s/q build-libpty 2>NUL
+mkdir build-libpty\win
+mkdir build-libpty\win\x86
+mkdir build-libpty\win\x86_64
+mkdir build-libpty\win\xp
+
+rmdir /s/q src\Release 2>NUL
+rmdir /s/q src\.vs 2>NUL
+del src\*.vcxproj src\*.vcxproj.filters src\*.sln src\*.sdf 2>NUL
+
+call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 --toolset v140_xp || goto :fail
+copy src\Release\Win32\winpty.dll build-libpty\win\xp || goto :fail
+copy src\Release\Win32\winpty-agent.exe build-libpty\win\xp || goto :fail
+
+call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 || goto :fail
+copy src\Release\Win32\winpty.dll build-libpty\win\x86 || goto :fail
+copy src\Release\Win32\winpty-agent.exe build-libpty\win\x86 || goto :fail
+
+call vcbuild.bat --msvc-platform x64 --gyp-msvs-version 2015 || goto :fail
+copy src\Release\x64\winpty.dll build-libpty\win\x86_64 || goto :fail
+copy src\Release\x64\winpty-agent.exe build-libpty\win\x86_64 || goto :fail
+
+echo success
+goto :EOF
+
+:fail
+echo error: build failed
+exit /b 1
diff --git a/src/libs/3rdparty/winpty/ship/common_ship.py b/src/libs/3rdparty/winpty/ship/common_ship.py
new file mode 100644
index 0000000000..b587ac7ce1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/ship/common_ship.py
@@ -0,0 +1,89 @@
+import os
+import sys
+
+# These scripts need to continue using Python 2 rather than 3, because
+# make_msvc_package.py puts the current Python interpreter on the PATH for the
+# sake of gyp, and gyp doesn't work with Python 3 yet.
+# https://bugs.chromium.org/p/gyp/issues/detail?id=36
+if os.name != "nt":
+ sys.exit("Error: ship scripts require native Python 2.7. (wrong os.name)")
+if sys.version_info[0:2] != (2,7):
+ sys.exit("Error: ship scripts require native Python 2.7. (wrong version)")
+
+import glob
+import hashlib
+import shutil
+import subprocess
+from distutils.spawn import find_executable
+
+topDir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+
+with open(topDir + "/VERSION.txt", "rt") as f:
+ winptyVersion = f.read().strip()
+
+def rmrf(patterns):
+ for pattern in patterns:
+ for path in glob.glob(pattern):
+ if os.path.isdir(path) and not os.path.islink(path):
+ print("+ rm -r " + path)
+ sys.stdout.flush()
+ shutil.rmtree(path)
+ elif os.path.isfile(path):
+ print("+ rm " + path)
+ sys.stdout.flush()
+ os.remove(path)
+
+def mkdir(path):
+ if not os.path.isdir(path):
+ os.makedirs(path)
+
+def requireExe(name, guesses):
+ if find_executable(name) is None:
+ for guess in guesses:
+ if os.path.exists(guess):
+ newDir = os.path.dirname(guess)
+ print("Adding " + newDir + " to Path to provide " + name)
+ os.environ["Path"] = newDir + ";" + os.environ["Path"]
+ ret = find_executable(name)
+ if ret is None:
+ sys.exit("Error: required EXE is missing from Path: " + name)
+ return ret
+
+class ModifyEnv:
+ def __init__(self, **kwargs):
+ self._changes = dict(kwargs)
+ self._original = dict()
+
+ def __enter__(self):
+ for var, val in self._changes.items():
+ self._original[var] = os.environ[var]
+ os.environ[var] = val
+
+ def __exit__(self, type, value, traceback):
+ for var, val in self._original.items():
+ os.environ[var] = val
+
+def sha256(path):
+ with open(path, "rb") as fp:
+ return hashlib.sha256(fp.read()).hexdigest()
+
+def checkSha256(path, expected):
+ actual = sha256(path)
+ if actual != expected:
+ sys.exit("error: sha256 hash mismatch on {}: expected {}, found {}".format(
+ path, expected, actual))
+
+requireExe("git.exe", [
+ "C:\\Program Files\\Git\\cmd\\git.exe",
+ "C:\\Program Files (x86)\\Git\\cmd\\git.exe"
+])
+
+commitHash = subprocess.check_output(["git.exe", "rev-parse", "HEAD"]).strip()
+defaultPathEnviron = "C:\\Windows\\System32;C:\\Windows"
+
+ZIP_TOOL = requireExe("7z.exe", [
+ "C:\\Program Files\\7-Zip\\7z.exe",
+ "C:\\Program Files (x86)\\7-Zip\\7z.exe",
+])
+
+requireExe("curl.exe", [])
diff --git a/src/libs/3rdparty/winpty/ship/make_msvc_package.py b/src/libs/3rdparty/winpty/ship/make_msvc_package.py
new file mode 100644
index 0000000000..2d10aac787
--- /dev/null
+++ b/src/libs/3rdparty/winpty/ship/make_msvc_package.py
@@ -0,0 +1,163 @@
+#!python
+
+# Copyright (c) 2016 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+#
+# Run with native CPython 2.7.
+#
+# This script looks for MSVC using a version-specific environment variable,
+# such as VS140COMNTOOLS for MSVC 2015.
+#
+
+import common_ship
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+
+os.chdir(common_ship.topDir)
+
+MSVC_VERSION_TABLE = {
+ "2015" : {
+ "package_name" : "msvc2015",
+ "gyp_version" : "2015",
+ "common_tools_env" : "VS140COMNTOOLS",
+ "xp_toolset" : "v140_xp",
+ },
+ "2013" : {
+ "package_name" : "msvc2013",
+ "gyp_version" : "2013",
+ "common_tools_env" : "VS120COMNTOOLS",
+ "xp_toolset" : "v120_xp",
+ },
+}
+
+ARCH_TABLE = {
+ "x64" : {
+ "msvc_platform" : "x64",
+ },
+ "ia32" : {
+ "msvc_platform" : "Win32",
+ },
+}
+
+def readArguments():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--msvc-version", default="2015")
+ ret = parser.parse_args()
+ if ret.msvc_version not in MSVC_VERSION_TABLE:
+ sys.exit("Error: unrecognized version: " + ret.msvc_version + ". " +
+ "Versions: " + " ".join(sorted(MSVC_VERSION_TABLE.keys())))
+ return ret
+
+ARGS = readArguments()
+
+def checkoutGyp():
+ if os.path.isdir("build-gyp"):
+ return
+ subprocess.check_call([
+ "git.exe",
+ "clone",
+ "https://chromium.googlesource.com/external/gyp",
+ "build-gyp"
+ ])
+
+def cleanMsvc():
+ common_ship.rmrf("""
+ src/Release src/.vs src/gen
+ src/*.vcxproj src/*.vcxproj.filters src/*.sln src/*.sdf
+ """.split())
+
+def build(arch, packageDir, xp=False):
+ archInfo = ARCH_TABLE[arch]
+ versionInfo = MSVC_VERSION_TABLE[ARGS.msvc_version]
+
+ devCmdPath = os.path.join(os.environ[versionInfo["common_tools_env"]], "VsDevCmd.bat")
+ if not os.path.isfile(devCmdPath):
+ sys.exit("Error: MSVC environment script missing: " + devCmdPath)
+
+ toolsetArgument = " --toolset {}".format(versionInfo["xp_toolset"]) if xp else ""
+ newEnv = os.environ.copy()
+ newEnv["PATH"] = os.path.dirname(sys.executable) + ";" + common_ship.defaultPathEnviron
+ commandLine = (
+ '"' + devCmdPath + '" && ' +
+ " vcbuild.bat" +
+ " --gyp-msvs-version " + versionInfo["gyp_version"] +
+ " --msvc-platform " + archInfo["msvc_platform"] +
+ " --commit-hash " + common_ship.commitHash +
+ toolsetArgument
+ )
+
+ subprocess.check_call(commandLine, shell=True, env=newEnv)
+
+ archPackageDir = os.path.join(packageDir, arch)
+ if xp:
+ archPackageDir += "_xp"
+
+ common_ship.mkdir(archPackageDir + "/bin")
+ common_ship.mkdir(archPackageDir + "/lib")
+
+ binSrc = os.path.join(common_ship.topDir, "src/Release", archInfo["msvc_platform"])
+
+ shutil.copy(binSrc + "/winpty.dll", archPackageDir + "/bin")
+ shutil.copy(binSrc + "/winpty-agent.exe", archPackageDir + "/bin")
+ shutil.copy(binSrc + "/winpty-debugserver.exe", archPackageDir + "/bin")
+ shutil.copy(binSrc + "/winpty.lib", archPackageDir + "/lib")
+
+def buildPackage():
+ versionInfo = MSVC_VERSION_TABLE[ARGS.msvc_version]
+
+ packageName = "winpty-%s-%s" % (
+ common_ship.winptyVersion,
+ versionInfo["package_name"],
+ )
+
+ packageRoot = os.path.join(common_ship.topDir, "ship/packages")
+ packageDir = os.path.join(packageRoot, packageName)
+ packageFile = packageDir + ".zip"
+
+ common_ship.rmrf([packageDir])
+ common_ship.rmrf([packageFile])
+ common_ship.mkdir(packageDir)
+
+ checkoutGyp()
+ cleanMsvc()
+ build("ia32", packageDir, True)
+ build("x64", packageDir, True)
+ cleanMsvc()
+ build("ia32", packageDir)
+ build("x64", packageDir)
+
+ topDir = common_ship.topDir
+
+ common_ship.mkdir(packageDir + "/include")
+ shutil.copy(topDir + "/src/include/winpty.h", packageDir + "/include")
+ shutil.copy(topDir + "/src/include/winpty_constants.h", packageDir + "/include")
+ shutil.copy(topDir + "/LICENSE", packageDir)
+ shutil.copy(topDir + "/README.md", packageDir)
+ shutil.copy(topDir + "/RELEASES.md", packageDir)
+
+ subprocess.check_call([common_ship.ZIP_TOOL, "a", packageFile, "."], cwd=packageDir)
+
+if __name__ == "__main__":
+ buildPackage()
diff --git a/src/libs/3rdparty/winpty/ship/ship.py b/src/libs/3rdparty/winpty/ship/ship.py
new file mode 100644
index 0000000000..44f5862e3e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/ship/ship.py
@@ -0,0 +1,104 @@
+#!python
+
+# Copyright (c) 2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+#
+# Run with native CPython 2.7 on a 64-bit computer.
+#
+
+import common_ship
+
+from optparse import OptionParser
+import multiprocessing
+import os
+import shutil
+import subprocess
+import sys
+
+
+def dllVersion(path):
+ version = subprocess.check_output(
+ ["powershell.exe",
+ "[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"" + path + "\").FileVersion"])
+ return version.strip()
+
+
+os.chdir(common_ship.topDir)
+
+
+# Determine other build parameters.
+BUILD_KINDS = {
+ "cygwin": {
+ "path": ["bin"],
+ "dll": "bin\\cygwin1.dll",
+ },
+ "msys2": {
+ "path": ["opt\\bin", "usr\\bin"],
+ "dll": "usr\\bin\\msys-2.0.dll",
+ },
+}
+
+
+def buildTarget(kind, syspath, arch):
+
+ binPaths = [os.path.join(syspath, p) for p in BUILD_KINDS[kind]["path"]]
+ binPaths += common_ship.defaultPathEnviron.split(";")
+ newPath = ";".join(binPaths)
+
+ dllver = dllVersion(os.path.join(syspath, BUILD_KINDS[kind]["dll"]))
+ packageName = "winpty-{}-{}-{}-{}".format(common_ship.winptyVersion, kind, dllver, arch)
+ if os.path.exists("ship\\packages\\" + packageName):
+ shutil.rmtree("ship\\packages\\" + packageName)
+
+ print("+ Setting PATH to: {}".format(newPath))
+ with common_ship.ModifyEnv(PATH=newPath):
+ subprocess.check_call(["sh.exe", "configure"])
+ subprocess.check_call(["make.exe", "clean"])
+ makeBaseCmd = [
+ "make.exe",
+ "COMMIT_HASH=" + common_ship.commitHash,
+ "PREFIX=ship/packages/" + packageName
+ ]
+ subprocess.check_call(makeBaseCmd + ["all", "tests", "-j%d" % multiprocessing.cpu_count()])
+ subprocess.check_call(["build\\trivial_test.exe"])
+ subprocess.check_call(makeBaseCmd + ["install"])
+ subprocess.check_call(["tar.exe", "cvfz",
+ packageName + ".tar.gz",
+ packageName], cwd=os.path.join(os.getcwd(), "ship", "packages"))
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option("--kind", type="choice", choices=["cygwin", "msys2"])
+ parser.add_option("--syspath")
+ parser.add_option("--arch", type="choice", choices=["ia32", "x64"])
+ (args, extra) = parser.parse_args()
+
+ args.kind or parser.error("--kind must be specified")
+ args.arch or parser.error("--arch must be specified")
+ args.syspath or parser.error("--syspath must be specified")
+ extra and parser.error("unexpected positional argument(s)")
+
+ buildTarget(args.kind, args.syspath, args.arch)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/libs/3rdparty/winpty/src/CMakeLists.txt b/src/libs/3rdparty/winpty/src/CMakeLists.txt
new file mode 100644
index 0000000000..22b15111d4
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/CMakeLists.txt
@@ -0,0 +1,111 @@
+if (MSVC)
+ add_compile_definitions(NOMINMAX UNICODE _UNICODE)
+endif()
+
+file(WRITE ${CMAKE_BINARY_DIR}/GenVersion.h.in [=[
+const char GenVersion_Version[] = "@VERSION@";
+const char GenVersion_Commit[] = "@COMMIT_HASH@";
+]=])
+
+file(READ ../VERSION.txt VERSION)
+string(REPLACE "\n" "" VERSION "${VERSION}")
+configure_file(${CMAKE_BINARY_DIR}/GenVersion.h.in ${CMAKE_BINARY_DIR}/GenVersion.h @ONLY)
+
+set(shared_sources
+ shared/AgentMsg.h
+ shared/BackgroundDesktop.h
+ shared/BackgroundDesktop.cc
+ shared/Buffer.h
+ shared/Buffer.cc
+ shared/DebugClient.h
+ shared/DebugClient.cc
+ shared/GenRandom.h
+ shared/GenRandom.cc
+ shared/OsModule.h
+ shared/OwnedHandle.h
+ shared/OwnedHandle.cc
+ shared/StringBuilder.h
+ shared/StringUtil.cc
+ shared/StringUtil.h
+ shared/UnixCtrlChars.h
+ shared/WindowsSecurity.cc
+ shared/WindowsSecurity.h
+ shared/WindowsVersion.h
+ shared/WindowsVersion.cc
+ shared/WinptyAssert.h
+ shared/WinptyAssert.cc
+ shared/WinptyException.h
+ shared/WinptyException.cc
+ shared/WinptyVersion.h
+ shared/WinptyVersion.cc
+ shared/winpty_snprintf.h
+)
+
+#
+# winpty-agent
+#
+
+add_qtc_executable(winpty-agent
+ INCLUDES
+ include ${CMAKE_BINARY_DIR}
+ DEFINES WINPTY_AGENT_ASSERT
+ PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON
+ SOURCES
+ agent/Agent.h
+ agent/Agent.cc
+ agent/AgentCreateDesktop.h
+ agent/AgentCreateDesktop.cc
+ agent/ConsoleFont.cc
+ agent/ConsoleFont.h
+ agent/ConsoleInput.cc
+ agent/ConsoleInput.h
+ agent/ConsoleInputReencoding.cc
+ agent/ConsoleInputReencoding.h
+ agent/ConsoleLine.cc
+ agent/ConsoleLine.h
+ agent/Coord.h
+ agent/DebugShowInput.h
+ agent/DebugShowInput.cc
+ agent/DefaultInputMap.h
+ agent/DefaultInputMap.cc
+ agent/DsrSender.h
+ agent/EventLoop.h
+ agent/EventLoop.cc
+ agent/InputMap.h
+ agent/InputMap.cc
+ agent/LargeConsoleRead.h
+ agent/LargeConsoleRead.cc
+ agent/NamedPipe.h
+ agent/NamedPipe.cc
+ agent/Scraper.h
+ agent/Scraper.cc
+ agent/SimplePool.h
+ agent/SmallRect.h
+ agent/Terminal.h
+ agent/Terminal.cc
+ agent/UnicodeEncoding.h
+ agent/Win32Console.cc
+ agent/Win32Console.h
+ agent/Win32ConsoleBuffer.cc
+ agent/Win32ConsoleBuffer.h
+ agent/main.cc
+ ${shared_sources}
+)
+
+#
+# libwinpty
+#
+
+add_qtc_library(winpty STATIC
+ INCLUDES ${CMAKE_BINARY_DIR}
+ PUBLIC_DEFINES COMPILING_WINPTY_DLL
+ PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON
+ SOURCES
+ libwinpty/AgentLocation.cc
+ libwinpty/AgentLocation.h
+ libwinpty/winpty.cc
+ ${shared_sources}
+)
+
+target_include_directories(winpty
+ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
diff --git a/src/libs/3rdparty/winpty/src/agent/Agent.cc b/src/libs/3rdparty/winpty/src/agent/Agent.cc
new file mode 100644
index 0000000000..986edead13
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Agent.cc
@@ -0,0 +1,612 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Agent.h"
+
+#include <windows.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "../include/winpty_constants.h"
+
+#include "../shared/AgentMsg.h"
+#include "../shared/Buffer.h"
+#include "../shared/DebugClient.h"
+#include "../shared/GenRandom.h"
+#include "../shared/StringBuilder.h"
+#include "../shared/StringUtil.h"
+#include "../shared/WindowsVersion.h"
+#include "../shared/WinptyAssert.h"
+
+#include "ConsoleFont.h"
+#include "ConsoleInput.h"
+#include "NamedPipe.h"
+#include "Scraper.h"
+#include "Terminal.h"
+#include "Win32ConsoleBuffer.h"
+
+namespace {
+
+static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_C_EVENT) {
+ // Do nothing and claim to have handled the event.
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// We can detect the new Windows 10 console by observing the effect of the
+// Mark command. In older consoles, Mark temporarily moves the cursor to the
+// top-left of the console window. In the new console, the cursor isn't
+// initially moved.
+//
+// We might like to use Mark to freeze the console, but we can't, because when
+// the Mark command ends, the console moves the cursor back to its starting
+// point, even if the console application has moved it in the meantime.
+static void detectNewWindows10Console(
+ Win32Console &console, Win32ConsoleBuffer &buffer)
+{
+ if (!isAtLeastWindows8()) {
+ return;
+ }
+
+ ConsoleScreenBufferInfo info = buffer.bufferInfo();
+
+ // Make sure the window isn't 1x1. AFAIK, this should never happen
+ // accidentally. It is difficult to make it happen deliberately.
+ if (info.srWindow.Left == info.srWindow.Right &&
+ info.srWindow.Top == info.srWindow.Bottom) {
+ trace("detectNewWindows10Console: Initial console window was 1x1 -- "
+ "expanding for test");
+ setSmallFont(buffer.conout(), 400, false);
+ buffer.moveWindow(SmallRect(0, 0, 1, 1));
+ buffer.resizeBuffer(Coord(400, 1));
+ buffer.moveWindow(SmallRect(0, 0, 2, 1));
+ // This use of GetLargestConsoleWindowSize ought to be unnecessary
+ // given the behavior I've seen from moveWindow(0, 0, 1, 1), but
+ // I'd like to be especially sure, considering that this code will
+ // rarely be tested.
+ const auto largest = GetLargestConsoleWindowSize(buffer.conout());
+ buffer.moveWindow(
+ SmallRect(0, 0, std::min(largest.X, buffer.bufferSize().X), 1));
+ info = buffer.bufferInfo();
+ ASSERT(info.srWindow.Right > info.srWindow.Left &&
+ "Could not expand console window from 1x1");
+ }
+
+ // Test whether MARK moves the cursor.
+ const Coord initialPosition(info.srWindow.Right, info.srWindow.Bottom);
+ buffer.setCursorPosition(initialPosition);
+ ASSERT(!console.frozen());
+ console.setFreezeUsesMark(true);
+ console.setFrozen(true);
+ const bool isNewW10 = (buffer.cursorPosition() == initialPosition);
+ console.setFrozen(false);
+ buffer.setCursorPosition(Coord(0, 0));
+
+ trace("Attempting to detect new Windows 10 console using MARK: %s",
+ isNewW10 ? "detected" : "not detected");
+ console.setFreezeUsesMark(false);
+ console.setNewW10(isNewW10);
+}
+
+static inline WriteBuffer newPacket() {
+ WriteBuffer packet;
+ packet.putRawValue<uint64_t>(0); // Reserve space for size.
+ return packet;
+}
+
+static HANDLE duplicateHandle(HANDLE h) {
+ HANDLE ret = nullptr;
+ if (!DuplicateHandle(
+ GetCurrentProcess(), h,
+ GetCurrentProcess(), &ret,
+ 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ ASSERT(false && "DuplicateHandle failed!");
+ }
+ return ret;
+}
+
+// It's safe to truncate a handle from 64-bits to 32-bits, or to sign-extend it
+// back to 64-bits. See the MSDN article, "Interprocess Communication Between
+// 32-bit and 64-bit Applications".
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203.aspx
+static int64_t int64FromHandle(HANDLE h) {
+ return static_cast<int64_t>(reinterpret_cast<intptr_t>(h));
+}
+
+} // anonymous namespace
+
+Agent::Agent(LPCWSTR controlPipeName,
+ uint64_t agentFlags,
+ int mouseMode,
+ int initialCols,
+ int initialRows) :
+ m_useConerr((agentFlags & WINPTY_FLAG_CONERR) != 0),
+ m_plainMode((agentFlags & WINPTY_FLAG_PLAIN_OUTPUT) != 0),
+ m_mouseMode(mouseMode)
+{
+ trace("Agent::Agent entered");
+
+ ASSERT(initialCols >= 1 && initialRows >= 1);
+ initialCols = std::min(initialCols, MAX_CONSOLE_WIDTH);
+ initialRows = std::min(initialRows, MAX_CONSOLE_HEIGHT);
+
+ const bool outputColor =
+ !m_plainMode || (agentFlags & WINPTY_FLAG_COLOR_ESCAPES);
+ const Coord initialSize(initialCols, initialRows);
+
+ auto primaryBuffer = openPrimaryBuffer();
+ if (m_useConerr) {
+ m_errorBuffer = Win32ConsoleBuffer::createErrorBuffer();
+ }
+
+ detectNewWindows10Console(m_console, *primaryBuffer);
+
+ m_controlPipe = &connectToControlPipe(controlPipeName);
+ m_coninPipe = &createDataServerPipe(false, L"conin");
+ m_conoutPipe = &createDataServerPipe(true, L"conout");
+ if (m_useConerr) {
+ m_conerrPipe = &createDataServerPipe(true, L"conerr");
+ }
+
+ // Send an initial response packet to winpty.dll containing pipe names.
+ {
+ auto setupPacket = newPacket();
+ setupPacket.putWString(m_coninPipe->name());
+ setupPacket.putWString(m_conoutPipe->name());
+ if (m_useConerr) {
+ setupPacket.putWString(m_conerrPipe->name());
+ }
+ writePacket(setupPacket);
+ }
+
+ std::unique_ptr<Terminal> primaryTerminal;
+ primaryTerminal.reset(new Terminal(*m_conoutPipe,
+ m_plainMode,
+ outputColor));
+ m_primaryScraper.reset(new Scraper(m_console,
+ *primaryBuffer,
+ std::move(primaryTerminal),
+ initialSize));
+ if (m_useConerr) {
+ std::unique_ptr<Terminal> errorTerminal;
+ errorTerminal.reset(new Terminal(*m_conerrPipe,
+ m_plainMode,
+ outputColor));
+ m_errorScraper.reset(new Scraper(m_console,
+ *m_errorBuffer,
+ std::move(errorTerminal),
+ initialSize));
+ }
+
+ m_console.setTitle(m_currentTitle);
+
+ const HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
+ m_consoleInput.reset(
+ new ConsoleInput(conin, m_mouseMode, *this, m_console));
+
+ // Setup Ctrl-C handling. First restore default handling of Ctrl-C. This
+ // attribute is inherited by child processes. Then register a custom
+ // Ctrl-C handler that does nothing. The handler will be called when the
+ // agent calls GenerateConsoleCtrlEvent.
+ SetConsoleCtrlHandler(NULL, FALSE);
+ SetConsoleCtrlHandler(consoleCtrlHandler, TRUE);
+
+ setPollInterval(25);
+}
+
+Agent::~Agent()
+{
+ trace("Agent::~Agent entered");
+ agentShutdown();
+ if (m_childProcess != NULL) {
+ CloseHandle(m_childProcess);
+ }
+}
+
+// Write a "Device Status Report" command to the terminal. The terminal will
+// reply with a row+col escape sequence. Presumably, the DSR reply will not
+// split a keypress escape sequence, so it should be safe to assume that the
+// bytes before it are complete keypresses.
+void Agent::sendDsr()
+{
+ if (!m_plainMode && !m_conoutPipe->isClosed()) {
+ m_conoutPipe->write("\x1B[6n");
+ }
+}
+
+NamedPipe &Agent::connectToControlPipe(LPCWSTR pipeName)
+{
+ NamedPipe &pipe = createNamedPipe();
+ pipe.connectToServer(pipeName, NamedPipe::OpenMode::Duplex);
+ pipe.setReadBufferSize(64 * 1024);
+ return pipe;
+}
+
+// Returns a new server named pipe. It has not yet been connected.
+NamedPipe &Agent::createDataServerPipe(bool write, const wchar_t *kind)
+{
+ const auto name =
+ (WStringBuilder(128)
+ << L"\\\\.\\pipe\\winpty-"
+ << kind << L'-'
+ << GenRandom().uniqueName()).str_moved();
+ NamedPipe &pipe = createNamedPipe();
+ pipe.openServerPipe(
+ name.c_str(),
+ write ? NamedPipe::OpenMode::Writing
+ : NamedPipe::OpenMode::Reading,
+ write ? 8192 : 0,
+ write ? 0 : 256);
+ if (!write) {
+ pipe.setReadBufferSize(64 * 1024);
+ }
+ return pipe;
+}
+
+void Agent::onPipeIo(NamedPipe &namedPipe)
+{
+ if (&namedPipe == m_conoutPipe || &namedPipe == m_conerrPipe) {
+ autoClosePipesForShutdown();
+ } else if (&namedPipe == m_coninPipe) {
+ pollConinPipe();
+ } else if (&namedPipe == m_controlPipe) {
+ pollControlPipe();
+ }
+}
+
+void Agent::pollControlPipe()
+{
+ if (m_controlPipe->isClosed()) {
+ trace("Agent exiting (control pipe is closed)");
+ shutdown();
+ return;
+ }
+
+ while (true) {
+ uint64_t packetSize = 0;
+ const auto amt1 =
+ m_controlPipe->peek(&packetSize, sizeof(packetSize));
+ if (amt1 < sizeof(packetSize)) {
+ break;
+ }
+ ASSERT(packetSize >= sizeof(packetSize) && packetSize <= SIZE_MAX);
+ if (m_controlPipe->bytesAvailable() < packetSize) {
+ if (m_controlPipe->readBufferSize() < packetSize) {
+ m_controlPipe->setReadBufferSize(packetSize);
+ }
+ break;
+ }
+ std::vector<char> packetData;
+ packetData.resize(packetSize);
+ const auto amt2 = m_controlPipe->read(packetData.data(), packetSize);
+ ASSERT(amt2 == packetSize);
+ try {
+ ReadBuffer buffer(std::move(packetData));
+ buffer.getRawValue<uint64_t>(); // Discard the size.
+ handlePacket(buffer);
+ } catch (const ReadBuffer::DecodeError&) {
+ ASSERT(false && "Decode error");
+ }
+ }
+}
+
+void Agent::handlePacket(ReadBuffer &packet)
+{
+ const int type = packet.getInt32();
+ switch (type) {
+ case AgentMsg::StartProcess:
+ handleStartProcessPacket(packet);
+ break;
+ case AgentMsg::SetSize:
+ // TODO: I think it might make sense to collapse consecutive SetSize
+ // messages. i.e. The terminal process can probably generate SetSize
+ // messages faster than they can be processed, and some GUIs might
+ // generate a flood of them, so if we can read multiple SetSize packets
+ // at once, we can ignore the early ones.
+ handleSetSizePacket(packet);
+ break;
+ case AgentMsg::GetConsoleProcessList:
+ handleGetConsoleProcessListPacket(packet);
+ break;
+ default:
+ trace("Unrecognized message, id:%d", type);
+ }
+}
+
+void Agent::writePacket(WriteBuffer &packet)
+{
+ const auto &bytes = packet.buf();
+ packet.replaceRawValue<uint64_t>(0, bytes.size());
+ m_controlPipe->write(bytes.data(), bytes.size());
+}
+
+void Agent::handleStartProcessPacket(ReadBuffer &packet)
+{
+ ASSERT(m_childProcess == nullptr);
+ ASSERT(!m_closingOutputPipes);
+
+ const uint64_t spawnFlags = packet.getInt64();
+ const bool wantProcessHandle = packet.getInt32() != 0;
+ const bool wantThreadHandle = packet.getInt32() != 0;
+ const auto program = packet.getWString();
+ const auto cmdline = packet.getWString();
+ const auto cwd = packet.getWString();
+ const auto env = packet.getWString();
+ const auto desktop = packet.getWString();
+ packet.assertEof();
+
+ auto cmdlineV = vectorWithNulFromString(cmdline);
+ auto desktopV = vectorWithNulFromString(desktop);
+ auto envV = vectorFromString(env);
+
+ LPCWSTR programArg = program.empty() ? nullptr : program.c_str();
+ LPWSTR cmdlineArg = cmdline.empty() ? nullptr : cmdlineV.data();
+ LPCWSTR cwdArg = cwd.empty() ? nullptr : cwd.c_str();
+ LPWSTR envArg = env.empty() ? nullptr : envV.data();
+
+ STARTUPINFOW sui = {};
+ PROCESS_INFORMATION pi = {};
+ sui.cb = sizeof(sui);
+ sui.lpDesktop = desktop.empty() ? nullptr : desktopV.data();
+ BOOL inheritHandles = FALSE;
+ if (m_useConerr) {
+ inheritHandles = TRUE;
+ sui.dwFlags |= STARTF_USESTDHANDLES;
+ sui.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ sui.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ sui.hStdError = m_errorBuffer->conout();
+ }
+
+ const BOOL success =
+ CreateProcessW(programArg, cmdlineArg, nullptr, nullptr,
+ /*bInheritHandles=*/inheritHandles,
+ /*dwCreationFlags=*/CREATE_UNICODE_ENVIRONMENT,
+ envArg, cwdArg, &sui, &pi);
+ const int lastError = success ? 0 : GetLastError();
+
+ trace("CreateProcess: %s %u",
+ (success ? "success" : "fail"),
+ static_cast<unsigned int>(pi.dwProcessId));
+
+ auto reply = newPacket();
+ if (success) {
+ int64_t replyProcess = 0;
+ int64_t replyThread = 0;
+ if (wantProcessHandle) {
+ replyProcess = int64FromHandle(duplicateHandle(pi.hProcess));
+ }
+ if (wantThreadHandle) {
+ replyThread = int64FromHandle(duplicateHandle(pi.hThread));
+ }
+ CloseHandle(pi.hThread);
+ m_childProcess = pi.hProcess;
+ m_autoShutdown = (spawnFlags & WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN) != 0;
+ m_exitAfterShutdown = (spawnFlags & WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN) != 0;
+ reply.putInt32(static_cast<int32_t>(StartProcessResult::ProcessCreated));
+ reply.putInt64(replyProcess);
+ reply.putInt64(replyThread);
+ } else {
+ reply.putInt32(static_cast<int32_t>(StartProcessResult::CreateProcessFailed));
+ reply.putInt32(lastError);
+ }
+ writePacket(reply);
+}
+
+void Agent::handleSetSizePacket(ReadBuffer &packet)
+{
+ const int cols = packet.getInt32();
+ const int rows = packet.getInt32();
+ packet.assertEof();
+ resizeWindow(cols, rows);
+ auto reply = newPacket();
+ writePacket(reply);
+}
+
+void Agent::handleGetConsoleProcessListPacket(ReadBuffer &packet)
+{
+ packet.assertEof();
+
+ auto processList = std::vector<DWORD>(64);
+ auto processCount = GetConsoleProcessList(&processList[0], processList.size());
+
+ // The process list can change while we're trying to read it
+ while (processList.size() < processCount) {
+ // Multiplying by two caps the number of iterations
+ const auto newSize = std::max<DWORD>(processList.size() * 2, processCount);
+ processList.resize(newSize);
+ processCount = GetConsoleProcessList(&processList[0], processList.size());
+ }
+
+ if (processCount == 0) {
+ trace("GetConsoleProcessList failed");
+ }
+
+ auto reply = newPacket();
+ reply.putInt32(processCount);
+ for (DWORD i = 0; i < processCount; i++) {
+ reply.putInt32(processList[i]);
+ }
+ writePacket(reply);
+}
+
+void Agent::pollConinPipe()
+{
+ const std::string newData = m_coninPipe->readAllToString();
+ if (hasDebugFlag("input_separated_bytes")) {
+ // This debug flag is intended to help with testing incomplete escape
+ // sequences and multibyte UTF-8 encodings. (I wonder if the normal
+ // code path ought to advance a state machine one byte at a time.)
+ for (size_t i = 0; i < newData.size(); ++i) {
+ m_consoleInput->writeInput(newData.substr(i, 1));
+ }
+ } else {
+ m_consoleInput->writeInput(newData);
+ }
+}
+
+void Agent::onPollTimeout()
+{
+ m_consoleInput->updateInputFlags();
+ const bool enableMouseMode = m_consoleInput->shouldActivateTerminalMouse();
+
+ // Give the ConsoleInput object a chance to flush input from an incomplete
+ // escape sequence (e.g. pressing ESC).
+ m_consoleInput->flushIncompleteEscapeCode();
+
+ const bool shouldScrapeContent = !m_closingOutputPipes;
+
+ // Check if the child process has exited.
+ if (m_autoShutdown &&
+ m_childProcess != nullptr &&
+ WaitForSingleObject(m_childProcess, 0) == WAIT_OBJECT_0) {
+ CloseHandle(m_childProcess);
+ m_childProcess = nullptr;
+
+ // Close the data socket to signal to the client that the child
+ // process has exited. If there's any data left to send, send it
+ // before closing the socket.
+ m_closingOutputPipes = true;
+ }
+
+ // Scrape for output *after* the above exit-check to ensure that we collect
+ // the child process's final output.
+ if (shouldScrapeContent) {
+ syncConsoleTitle();
+ scrapeBuffers();
+ }
+
+ // We must ensure that we disable mouse mode before closing the CONOUT
+ // pipe, so update the mouse mode here.
+ m_primaryScraper->terminal().enableMouseMode(
+ enableMouseMode && !m_closingOutputPipes);
+
+ autoClosePipesForShutdown();
+}
+
+void Agent::autoClosePipesForShutdown()
+{
+ if (m_closingOutputPipes) {
+ // We don't want to close a pipe before it's connected! If we do, the
+ // libwinpty client may try to connect to a non-existent pipe. This
+ // case is important for short-lived programs.
+ if (m_conoutPipe->isConnected() &&
+ m_conoutPipe->bytesToSend() == 0) {
+ trace("Closing CONOUT pipe (auto-shutdown)");
+ m_conoutPipe->closePipe();
+ }
+ if (m_conerrPipe != nullptr &&
+ m_conerrPipe->isConnected() &&
+ m_conerrPipe->bytesToSend() == 0) {
+ trace("Closing CONERR pipe (auto-shutdown)");
+ m_conerrPipe->closePipe();
+ }
+ if (m_exitAfterShutdown &&
+ m_conoutPipe->isClosed() &&
+ (m_conerrPipe == nullptr || m_conerrPipe->isClosed())) {
+ trace("Agent exiting (exit-after-shutdown)");
+ shutdown();
+ }
+ }
+}
+
+std::unique_ptr<Win32ConsoleBuffer> Agent::openPrimaryBuffer()
+{
+ // If we're using a separate buffer for stderr, and a program were to
+ // activate the stderr buffer, then we could accidentally scrape the same
+ // buffer twice. That probably shouldn't happen in ordinary use, but it
+ // can be avoided anyway by using the original console screen buffer in
+ // that mode.
+ if (!m_useConerr) {
+ return Win32ConsoleBuffer::openConout();
+ } else {
+ return Win32ConsoleBuffer::openStdout();
+ }
+}
+
+void Agent::resizeWindow(int cols, int rows)
+{
+ ASSERT(cols >= 1 && rows >= 1);
+ cols = std::min(cols, MAX_CONSOLE_WIDTH);
+ rows = std::min(rows, MAX_CONSOLE_HEIGHT);
+
+ Win32Console::FreezeGuard guard(m_console, m_console.frozen());
+ const Coord newSize(cols, rows);
+ ConsoleScreenBufferInfo info;
+ auto primaryBuffer = openPrimaryBuffer();
+ m_primaryScraper->resizeWindow(*primaryBuffer, newSize, info);
+ m_consoleInput->setMouseWindowRect(info.windowRect());
+ if (m_errorScraper) {
+ m_errorScraper->resizeWindow(*m_errorBuffer, newSize, info);
+ }
+
+ // Synthesize a WINDOW_BUFFER_SIZE_EVENT event. Normally, Windows
+ // generates this event only when the buffer size changes, not when the
+ // window size changes. This behavior is undesirable in two ways:
+ // - When winpty expands the window horizontally, it must expand the
+ // buffer first, then the window. At least some programs (e.g. the WSL
+ // bash.exe wrapper) use the window width rather than the buffer width,
+ // so there is a short timespan during which they can read the wrong
+ // value.
+ // - If the window's vertical size is changed, no event is generated,
+ // even though a typical well-behaved console program cares about the
+ // *window* height, not the *buffer* height.
+ // This synthesization works around a design flaw in the console. It's probably
+ // harmless. See https://github.com/rprichard/winpty/issues/110.
+ INPUT_RECORD sizeEvent {};
+ sizeEvent.EventType = WINDOW_BUFFER_SIZE_EVENT;
+ sizeEvent.Event.WindowBufferSizeEvent.dwSize = primaryBuffer->bufferSize();
+ DWORD actual {};
+ WriteConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), &sizeEvent, 1, &actual);
+}
+
+void Agent::scrapeBuffers()
+{
+ Win32Console::FreezeGuard guard(m_console, m_console.frozen());
+ ConsoleScreenBufferInfo info;
+ m_primaryScraper->scrapeBuffer(*openPrimaryBuffer(), info);
+ m_consoleInput->setMouseWindowRect(info.windowRect());
+ if (m_errorScraper) {
+ m_errorScraper->scrapeBuffer(*m_errorBuffer, info);
+ }
+}
+
+void Agent::syncConsoleTitle()
+{
+ std::wstring newTitle = m_console.title();
+ if (newTitle != m_currentTitle) {
+ if (!m_plainMode && !m_conoutPipe->isClosed()) {
+ std::string command = std::string("\x1b]0;") +
+ utf8FromWide(newTitle) + "\x07";
+ m_conoutPipe->write(command.c_str());
+ }
+ m_currentTitle = newTitle;
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Agent.h b/src/libs/3rdparty/winpty/src/agent/Agent.h
new file mode 100644
index 0000000000..1dde48fe4a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Agent.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_H
+#define AGENT_H
+
+#include <windows.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "DsrSender.h"
+#include "EventLoop.h"
+#include "Win32Console.h"
+
+class ConsoleInput;
+class NamedPipe;
+class ReadBuffer;
+class Scraper;
+class WriteBuffer;
+class Win32ConsoleBuffer;
+
+class Agent : public EventLoop, public DsrSender
+{
+public:
+ Agent(LPCWSTR controlPipeName,
+ uint64_t agentFlags,
+ int mouseMode,
+ int initialCols,
+ int initialRows);
+ virtual ~Agent();
+ void sendDsr() override;
+
+private:
+ NamedPipe &connectToControlPipe(LPCWSTR pipeName);
+ NamedPipe &createDataServerPipe(bool write, const wchar_t *kind);
+
+private:
+ void pollControlPipe();
+ void handlePacket(ReadBuffer &packet);
+ void writePacket(WriteBuffer &packet);
+ void handleStartProcessPacket(ReadBuffer &packet);
+ void handleSetSizePacket(ReadBuffer &packet);
+ void handleGetConsoleProcessListPacket(ReadBuffer &packet);
+ void pollConinPipe();
+
+protected:
+ virtual void onPollTimeout() override;
+ virtual void onPipeIo(NamedPipe &namedPipe) override;
+
+private:
+ void autoClosePipesForShutdown();
+ std::unique_ptr<Win32ConsoleBuffer> openPrimaryBuffer();
+ void resizeWindow(int cols, int rows);
+ void scrapeBuffers();
+ void syncConsoleTitle();
+
+private:
+ const bool m_useConerr;
+ const bool m_plainMode;
+ const int m_mouseMode;
+ Win32Console m_console;
+ std::unique_ptr<Scraper> m_primaryScraper;
+ std::unique_ptr<Scraper> m_errorScraper;
+ std::unique_ptr<Win32ConsoleBuffer> m_errorBuffer;
+ NamedPipe *m_controlPipe = nullptr;
+ NamedPipe *m_coninPipe = nullptr;
+ NamedPipe *m_conoutPipe = nullptr;
+ NamedPipe *m_conerrPipe = nullptr;
+ bool m_autoShutdown = false;
+ bool m_exitAfterShutdown = false;
+ bool m_closingOutputPipes = false;
+ std::unique_ptr<ConsoleInput> m_consoleInput;
+ HANDLE m_childProcess = nullptr;
+
+ // If the title is initialized to the empty string, then cmd.exe will
+ // sometimes print this error:
+ // Not enough storage is available to process this command.
+ // It happens on Windows 7 when logged into a Cygwin SSH session, for
+ // example. Using a title of a single space character avoids the problem.
+ // See https://github.com/rprichard/winpty/issues/74.
+ std::wstring m_currentTitle = L" ";
+};
+
+#endif // AGENT_H
diff --git a/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc
new file mode 100644
index 0000000000..9ad6503b1c
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "AgentCreateDesktop.h"
+
+#include "../shared/BackgroundDesktop.h"
+#include "../shared/Buffer.h"
+#include "../shared/DebugClient.h"
+#include "../shared/StringUtil.h"
+
+#include "EventLoop.h"
+#include "NamedPipe.h"
+
+namespace {
+
+static inline WriteBuffer newPacket() {
+ WriteBuffer packet;
+ packet.putRawValue<uint64_t>(0); // Reserve space for size.
+ return packet;
+}
+
+class CreateDesktopLoop : public EventLoop {
+public:
+ CreateDesktopLoop(LPCWSTR controlPipeName);
+
+protected:
+ virtual void onPipeIo(NamedPipe &namedPipe) override;
+
+private:
+ void writePacket(WriteBuffer &packet);
+
+ BackgroundDesktop m_desktop;
+ NamedPipe &m_pipe;
+};
+
+CreateDesktopLoop::CreateDesktopLoop(LPCWSTR controlPipeName) :
+ m_pipe(createNamedPipe()) {
+ m_pipe.connectToServer(controlPipeName, NamedPipe::OpenMode::Duplex);
+ auto packet = newPacket();
+ packet.putWString(m_desktop.desktopName());
+ writePacket(packet);
+}
+
+void CreateDesktopLoop::writePacket(WriteBuffer &packet) {
+ const auto &bytes = packet.buf();
+ packet.replaceRawValue<uint64_t>(0, bytes.size());
+ m_pipe.write(bytes.data(), bytes.size());
+}
+
+void CreateDesktopLoop::onPipeIo(NamedPipe &namedPipe) {
+ if (m_pipe.isClosed()) {
+ shutdown();
+ }
+}
+
+} // anonymous namespace
+
+void handleCreateDesktop(LPCWSTR controlPipeName) {
+ try {
+ CreateDesktopLoop loop(controlPipeName);
+ loop.run();
+ trace("Agent exiting...");
+ } catch (const WinptyException &e) {
+ trace("handleCreateDesktop: internal error: %s",
+ utf8FromWide(e.what()).c_str());
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h
new file mode 100644
index 0000000000..2ae539c7fa
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_CREATE_DESKTOP_H
+#define AGENT_CREATE_DESKTOP_H
+
+#include <windows.h>
+
+void handleCreateDesktop(LPCWSTR controlPipeName);
+
+#endif // AGENT_CREATE_DESKTOP_H
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc
new file mode 100644
index 0000000000..aa1f7876d3
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc
@@ -0,0 +1,698 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "ConsoleFont.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <algorithm>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "../shared/DebugClient.h"
+#include "../shared/OsModule.h"
+#include "../shared/StringUtil.h"
+#include "../shared/WindowsVersion.h"
+#include "../shared/WinptyAssert.h"
+#include "../shared/winpty_snprintf.h"
+
+namespace {
+
+#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
+
+// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
+const wchar_t kLucidaConsole[] = L"Lucida Console";
+const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // 932, Japanese
+const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // 936, Chinese Simplified
+const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // 949, Korean
+const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // 950, Chinese Traditional
+
+struct FontSize {
+ short size;
+ int width;
+};
+
+struct Font {
+ const wchar_t *faceName;
+ unsigned int family;
+ short size;
+};
+
+// Ideographs in East Asian languages take two columns rather than one.
+// In the console screen buffer, a "full-width" character will occupy two
+// cells of the buffer, the first with attribute 0x100 and the second with
+// attribute 0x200.
+//
+// Windows does not correctly identify code points as double-width in all
+// configurations. It depends heavily on the code page, the font facename,
+// and (somehow) even the font size. In the 437 code page (MS-DOS), for
+// example, no codepoints are interpreted as double-width. When the console
+// is in an East Asian code page (932, 936, 949, or 950), then sometimes
+// selecting a "Western" facename like "Lucida Console" or "Consolas" doesn't
+// register, or if the font *can* be chosen, then the console doesn't handle
+// double-width correctly. I tested the double-width handling by writing
+// several code points with WriteConsole and checking whether one or two cells
+// were filled.
+//
+// In the Japanese code page (932), Microsoft's default font is MS Gothic.
+// MS Gothic double-width handling seems to be broken with console versions
+// prior to Windows 10 (including Windows 10's legacy mode), and it's
+// especially broken in Windows 8 and 8.1.
+//
+// Test by running: misc/Utf16Echo A2 A3 2014 3044 30FC 4000
+//
+// The first three codepoints are always rendered as half-width with the
+// Windows Japanese fonts. (Of these, the first two must be half-width,
+// but U+2014 could be either.) The last three are rendered as full-width,
+// and they are East_Asian_Width=Wide.
+//
+// Windows 7 fails by modeling all codepoints as full-width with font
+// sizes 22 and above.
+//
+// Windows 8 gets U+00A2, U+00A3, U+2014, U+30FC, and U+4000 wrong, but
+// using a point size not listed in the console properties dialog
+// (e.g. "9") is less wrong:
+//
+// | code point |
+// font | 00A2 00A3 2014 3044 30FC 4000 | cell size
+// ------------+---------------------------------+----------
+// 8 | F F F F H H | 4x8
+// 9 | F F F F F F | 5x9
+// 16 | F F F F H H | 8x16
+// raster 6x13 | H H H F F H(*) | 6x13
+//
+// (*) The Raster Font renders U+4000 as a white box (i.e. an unsupported
+// character).
+//
+
+// See:
+// - misc/Font-Report-June2016 directory for per-size details
+// - misc/font-notes.txt
+// - misc/Utf16Echo.cc, misc/FontSurvey.cc, misc/SetFont.cc, misc/GetFont.cc
+
+const FontSize kLucidaFontSizes[] = {
+ { 5, 3 },
+ { 6, 4 },
+ { 8, 5 },
+ { 10, 6 },
+ { 12, 7 },
+ { 14, 8 },
+ { 16, 10 },
+ { 18, 11 },
+ { 20, 12 },
+ { 36, 22 },
+ { 48, 29 },
+ { 60, 36 },
+ { 72, 43 },
+};
+
+// Japanese. Used on Vista and Windows 7.
+const FontSize k932GothicVista[] = {
+ { 6, 3 },
+ { 8, 4 },
+ { 10, 5 },
+ { 12, 6 },
+ { 13, 7 },
+ { 15, 8 },
+ { 17, 9 },
+ { 19, 10 },
+ { 21, 11 },
+ // All larger fonts are more broken w.r.t. full-size East Asian characters.
+};
+
+// Japanese. Used on Windows 8, 8.1, and the legacy 10 console.
+const FontSize k932GothicWin8[] = {
+ // All of these characters are broken w.r.t. full-size East Asian
+ // characters, but they're equally broken.
+ { 5, 3 },
+ { 7, 4 },
+ { 9, 5 },
+ { 11, 6 },
+ { 13, 7 },
+ { 15, 8 },
+ { 17, 9 },
+ { 20, 10 },
+ { 22, 11 },
+ { 24, 12 },
+ // include extra-large fonts for small terminals
+ { 36, 18 },
+ { 48, 24 },
+ { 60, 30 },
+ { 72, 36 },
+};
+
+// Japanese. Used on the new Windows 10 console.
+const FontSize k932GothicWin10[] = {
+ { 6, 3 },
+ { 8, 4 },
+ { 10, 5 },
+ { 12, 6 },
+ { 14, 7 },
+ { 16, 8 },
+ { 18, 9 },
+ { 20, 10 },
+ { 22, 11 },
+ { 24, 12 },
+ // include extra-large fonts for small terminals
+ { 36, 18 },
+ { 48, 24 },
+ { 60, 30 },
+ { 72, 36 },
+};
+
+// Chinese Simplified.
+const FontSize k936SimSun[] = {
+ { 6, 3 },
+ { 8, 4 },
+ { 10, 5 },
+ { 12, 6 },
+ { 14, 7 },
+ { 16, 8 },
+ { 18, 9 },
+ { 20, 10 },
+ { 22, 11 },
+ { 24, 12 },
+ // include extra-large fonts for small terminals
+ { 36, 18 },
+ { 48, 24 },
+ { 60, 30 },
+ { 72, 36 },
+};
+
+// Korean.
+const FontSize k949GulimChe[] = {
+ { 6, 3 },
+ { 8, 4 },
+ { 10, 5 },
+ { 12, 6 },
+ { 14, 7 },
+ { 16, 8 },
+ { 18, 9 },
+ { 20, 10 },
+ { 22, 11 },
+ { 24, 12 },
+ // include extra-large fonts for small terminals
+ { 36, 18 },
+ { 48, 24 },
+ { 60, 30 },
+ { 72, 36 },
+};
+
+// Chinese Traditional.
+const FontSize k950MingLight[] = {
+ { 6, 3 },
+ { 8, 4 },
+ { 10, 5 },
+ { 12, 6 },
+ { 14, 7 },
+ { 16, 8 },
+ { 18, 9 },
+ { 20, 10 },
+ { 22, 11 },
+ { 24, 12 },
+ // include extra-large fonts for small terminals
+ { 36, 18 },
+ { 48, 24 },
+ { 60, 30 },
+ { 72, 36 },
+};
+
+// Some of these types and functions are missing from the MinGW headers.
+// Others are undocumented.
+
+struct AGENT_CONSOLE_FONT_INFO {
+ DWORD nFont;
+ COORD dwFontSize;
+};
+
+struct AGENT_CONSOLE_FONT_INFOEX {
+ ULONG cbSize;
+ DWORD nFont;
+ COORD dwFontSize;
+ UINT FontFamily;
+ UINT FontWeight;
+ WCHAR FaceName[LF_FACESIZE];
+};
+
+// undocumented XP API
+typedef BOOL WINAPI SetConsoleFont_t(
+ HANDLE hOutput,
+ DWORD dwFontIndex);
+
+// undocumented XP API
+typedef DWORD WINAPI GetNumberOfConsoleFonts_t();
+
+// XP and up
+typedef BOOL WINAPI GetCurrentConsoleFont_t(
+ HANDLE hOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont);
+
+// XP and up
+typedef COORD WINAPI GetConsoleFontSize_t(
+ HANDLE hConsoleOutput,
+ DWORD nFont);
+
+// Vista and up
+typedef BOOL WINAPI GetCurrentConsoleFontEx_t(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
+
+// Vista and up
+typedef BOOL WINAPI SetCurrentConsoleFontEx_t(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
+
+#define GET_MODULE_PROC(mod, funcName) \
+ m_##funcName = reinterpret_cast<funcName##_t*>((mod).proc(#funcName)); \
+
+#define DEFINE_ACCESSOR(funcName) \
+ funcName##_t &funcName() const { \
+ ASSERT(valid()); \
+ return *m_##funcName; \
+ }
+
+class XPFontAPI {
+public:
+ XPFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont);
+ GET_MODULE_PROC(m_kernel32, GetConsoleFontSize);
+ }
+
+ bool valid() const {
+ return m_GetCurrentConsoleFont != NULL &&
+ m_GetConsoleFontSize != NULL;
+ }
+
+ DEFINE_ACCESSOR(GetCurrentConsoleFont)
+ DEFINE_ACCESSOR(GetConsoleFontSize)
+
+private:
+ OsModule m_kernel32;
+ GetCurrentConsoleFont_t *m_GetCurrentConsoleFont;
+ GetConsoleFontSize_t *m_GetConsoleFontSize;
+};
+
+class UndocumentedXPFontAPI : public XPFontAPI {
+public:
+ UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, SetConsoleFont);
+ GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts);
+ }
+
+ bool valid() const {
+ return this->XPFontAPI::valid() &&
+ m_SetConsoleFont != NULL &&
+ m_GetNumberOfConsoleFonts != NULL;
+ }
+
+ DEFINE_ACCESSOR(SetConsoleFont)
+ DEFINE_ACCESSOR(GetNumberOfConsoleFonts)
+
+private:
+ OsModule m_kernel32;
+ SetConsoleFont_t *m_SetConsoleFont;
+ GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts;
+};
+
+class VistaFontAPI : public XPFontAPI {
+public:
+ VistaFontAPI() : m_kernel32(L"kernel32.dll") {
+ GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx);
+ GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx);
+ }
+
+ bool valid() const {
+ return this->XPFontAPI::valid() &&
+ m_GetCurrentConsoleFontEx != NULL &&
+ m_SetCurrentConsoleFontEx != NULL;
+ }
+
+ DEFINE_ACCESSOR(GetCurrentConsoleFontEx)
+ DEFINE_ACCESSOR(SetCurrentConsoleFontEx)
+
+private:
+ OsModule m_kernel32;
+ GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx;
+ SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx;
+};
+
+static std::vector<std::pair<DWORD, COORD> > readFontTable(
+ XPFontAPI &api, HANDLE conout, DWORD maxCount) {
+ std::vector<std::pair<DWORD, COORD> > ret;
+ for (DWORD i = 0; i < maxCount; ++i) {
+ COORD size = api.GetConsoleFontSize()(conout, i);
+ if (size.X == 0 && size.Y == 0) {
+ break;
+ }
+ ret.push_back(std::make_pair(i, size));
+ }
+ return ret;
+}
+
+static void dumpFontTable(HANDLE conout, const char *prefix) {
+ const int kMaxCount = 1000;
+ if (!isTracingEnabled()) {
+ return;
+ }
+ XPFontAPI api;
+ if (!api.valid()) {
+ trace("dumpFontTable: cannot dump font table -- missing APIs");
+ return;
+ }
+ std::vector<std::pair<DWORD, COORD> > table =
+ readFontTable(api, conout, kMaxCount);
+ std::string line;
+ char tmp[128];
+ size_t first = 0;
+ while (first < table.size()) {
+ size_t last = std::min(table.size() - 1, first + 10 - 1);
+ winpty_snprintf(tmp, "%sfonts %02u-%02u:",
+ prefix, static_cast<unsigned>(first), static_cast<unsigned>(last));
+ line = tmp;
+ for (size_t i = first; i <= last; ++i) {
+ if (i % 10 == 5) {
+ line += " - ";
+ }
+ winpty_snprintf(tmp, " %2dx%-2d",
+ table[i].second.X, table[i].second.Y);
+ line += tmp;
+ }
+ trace("%s", line.c_str());
+ first = last + 1;
+ }
+ if (table.size() == kMaxCount) {
+ trace("%sfonts: ... stopped reading at %d fonts ...",
+ prefix, kMaxCount);
+ }
+}
+
+static std::string stringToCodePoints(const std::wstring &str) {
+ std::string ret = "(";
+ for (size_t i = 0; i < str.size(); ++i) {
+ char tmp[32];
+ winpty_snprintf(tmp, "%X", str[i]);
+ if (ret.size() > 1) {
+ ret.push_back(' ');
+ }
+ ret += tmp;
+ }
+ ret.push_back(')');
+ return ret;
+}
+
+static void dumpFontInfoEx(
+ const AGENT_CONSOLE_FONT_INFOEX &infoex,
+ const char *prefix) {
+ if (!isTracingEnabled()) {
+ return;
+ }
+ std::wstring faceName(infoex.FaceName,
+ winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName)));
+ trace("%snFont=%u dwFontSize=(%d,%d) "
+ "FontFamily=0x%x FontWeight=%u FaceName=%s %s",
+ prefix,
+ static_cast<unsigned>(infoex.nFont),
+ infoex.dwFontSize.X, infoex.dwFontSize.Y,
+ infoex.FontFamily, infoex.FontWeight, utf8FromWide(faceName).c_str(),
+ stringToCodePoints(faceName).c_str());
+}
+
+static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, const char *prefix) {
+ if (!isTracingEnabled()) {
+ return;
+ }
+ AGENT_CONSOLE_FONT_INFOEX infoex = {0};
+ infoex.cbSize = sizeof(infoex);
+ if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) {
+ trace("GetCurrentConsoleFontEx call failed");
+ return;
+ }
+ dumpFontInfoEx(infoex, prefix);
+}
+
+static void dumpXPFont(XPFontAPI &api, HANDLE conout, const char *prefix) {
+ if (!isTracingEnabled()) {
+ return;
+ }
+ AGENT_CONSOLE_FONT_INFO info = {0};
+ if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) {
+ trace("GetCurrentConsoleFont call failed");
+ return;
+ }
+ trace("%snFont=%u dwFontSize=(%d,%d)",
+ prefix,
+ static_cast<unsigned>(info.nFont),
+ info.dwFontSize.X, info.dwFontSize.Y);
+}
+
+static bool setFontVista(
+ VistaFontAPI &api,
+ HANDLE conout,
+ const Font &font) {
+ AGENT_CONSOLE_FONT_INFOEX infoex = {};
+ infoex.cbSize = sizeof(AGENT_CONSOLE_FONT_INFOEX);
+ infoex.dwFontSize.Y = font.size;
+ infoex.FontFamily = font.family;
+ infoex.FontWeight = 400;
+ winpty_wcsncpy_nul(infoex.FaceName, font.faceName);
+ dumpFontInfoEx(infoex, "setFontVista: setting font to: ");
+ if (!api.SetCurrentConsoleFontEx()(conout, FALSE, &infoex)) {
+ trace("setFontVista: SetCurrentConsoleFontEx call failed");
+ return false;
+ }
+ memset(&infoex, 0, sizeof(infoex));
+ infoex.cbSize = sizeof(infoex);
+ if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) {
+ trace("setFontVista: GetCurrentConsoleFontEx call failed");
+ return false;
+ }
+ if (wcsncmp(infoex.FaceName, font.faceName,
+ COUNT_OF(infoex.FaceName)) != 0) {
+ trace("setFontVista: face name was not set");
+ dumpFontInfoEx(infoex, "setFontVista: post-call font: ");
+ return false;
+ }
+ // We'd like to verify that the new font size is correct, but we can't
+ // predict what it will be, even though we just set it to `pxSize` through
+ // an apprently symmetric interface. For the Chinese and Korean fonts, the
+ // new `infoex.dwFontSize.Y` value can be slightly larger than the height
+ // we specified.
+ return true;
+}
+
+static Font selectSmallFont(int codePage, int columns, bool isNewW10) {
+ // Iterate over a set of font sizes according to the code page, and select
+ // one.
+
+ const wchar_t *faceName = nullptr;
+ unsigned int fontFamily = 0;
+ const FontSize *table = nullptr;
+ size_t tableSize = 0;
+
+ switch (codePage) {
+ case 932: // Japanese
+ faceName = kMSGothic;
+ fontFamily = 0x36;
+ if (isNewW10) {
+ table = k932GothicWin10;
+ tableSize = COUNT_OF(k932GothicWin10);
+ } else if (isAtLeastWindows8()) {
+ table = k932GothicWin8;
+ tableSize = COUNT_OF(k932GothicWin8);
+ } else {
+ table = k932GothicVista;
+ tableSize = COUNT_OF(k932GothicVista);
+ }
+ break;
+ case 936: // Chinese Simplified
+ faceName = kNSimSun;
+ fontFamily = 0x36;
+ table = k936SimSun;
+ tableSize = COUNT_OF(k936SimSun);
+ break;
+ case 949: // Korean
+ faceName = kGulimChe;
+ fontFamily = 0x36;
+ table = k949GulimChe;
+ tableSize = COUNT_OF(k949GulimChe);
+ break;
+ case 950: // Chinese Traditional
+ faceName = kMingLight;
+ fontFamily = 0x36;
+ table = k950MingLight;
+ tableSize = COUNT_OF(k950MingLight);
+ break;
+ default:
+ faceName = kLucidaConsole;
+ fontFamily = 0x36;
+ table = kLucidaFontSizes;
+ tableSize = COUNT_OF(kLucidaFontSizes);
+ break;
+ }
+
+ size_t bestIndex = static_cast<size_t>(-1);
+ std::tuple<int, int> bestScore = std::make_tuple(-1, -1);
+
+ // We might want to pick the smallest possible font, because we don't know
+ // how large the monitor is (and the monitor size can change). We might
+ // want to pick a larger font to accommodate console programs that resize
+ // the console on their own, like DOS edit.com, which tends to resize the
+ // console to 80 columns.
+
+ for (size_t i = 0; i < tableSize; ++i) {
+ const int width = table[i].width * columns;
+
+ // In general, we'd like to pick a font size where cutting the number
+ // of columns in half doesn't immediately violate the minimum width
+ // constraint. (e.g. To run DOS edit.com, a user might resize their
+ // terminal to ~100 columns so it's big enough to show the 80 columns
+ // post-resize.) To achieve this, give priority to fonts that allow
+ // this halving. We don't want to encourage *very* large fonts,
+ // though, so disable the effect as the number of columns scales from
+ // 80 to 40.
+ const int halfColumns = std::min(columns, std::max(40, columns / 2));
+ const int halfWidth = table[i].width * halfColumns;
+
+ std::tuple<int, int> thisScore = std::make_tuple(-1, -1);
+ if (width >= 160 && halfWidth >= 160) {
+ // Both sizes are good. Prefer the smaller fonts.
+ thisScore = std::make_tuple(2, -width);
+ } else if (width >= 160) {
+ // Prefer the smaller fonts.
+ thisScore = std::make_tuple(1, -width);
+ } else {
+ // Otherwise, prefer the largest font in our table.
+ thisScore = std::make_tuple(0, width);
+ }
+ if (thisScore > bestScore) {
+ bestIndex = i;
+ bestScore = thisScore;
+ }
+ }
+
+ ASSERT(bestIndex != static_cast<size_t>(-1));
+ return Font { faceName, fontFamily, table[bestIndex].size };
+}
+
+static void setSmallFontVista(VistaFontAPI &api, HANDLE conout,
+ int columns, bool isNewW10) {
+ int codePage = GetConsoleOutputCP();
+ const auto font = selectSmallFont(codePage, columns, isNewW10);
+ if (setFontVista(api, conout, font)) {
+ trace("setSmallFontVista: success");
+ return;
+ }
+ if (codePage == 932 || codePage == 936 ||
+ codePage == 949 || codePage == 950) {
+ trace("setSmallFontVista: falling back to default codepage font instead");
+ const auto fontFB = selectSmallFont(0, columns, isNewW10);
+ if (setFontVista(api, conout, fontFB)) {
+ trace("setSmallFontVista: fallback was successful");
+ return;
+ }
+ }
+ trace("setSmallFontVista: failure");
+}
+
+struct FontSizeComparator {
+ bool operator()(const std::pair<DWORD, COORD> &obj1,
+ const std::pair<DWORD, COORD> &obj2) const {
+ int score1 = obj1.second.X + obj1.second.Y;
+ int score2 = obj2.second.X + obj2.second.Y;
+ return score1 < score2;
+ }
+};
+
+static void setSmallFontXP(UndocumentedXPFontAPI &api, HANDLE conout) {
+ // Read the console font table and sort it from smallest to largest.
+ const DWORD fontCount = api.GetNumberOfConsoleFonts()();
+ trace("setSmallFontXP: number of console fonts: %u",
+ static_cast<unsigned>(fontCount));
+ std::vector<std::pair<DWORD, COORD> > table =
+ readFontTable(api, conout, fontCount);
+ std::sort(table.begin(), table.end(), FontSizeComparator());
+ for (size_t i = 0; i < table.size(); ++i) {
+ // Skip especially narrow fonts to permit narrower terminals.
+ if (table[i].second.X < 4) {
+ continue;
+ }
+ trace("setSmallFontXP: setting font to %u",
+ static_cast<unsigned>(table[i].first));
+ if (!api.SetConsoleFont()(conout, table[i].first)) {
+ trace("setSmallFontXP: SetConsoleFont call failed");
+ continue;
+ }
+ AGENT_CONSOLE_FONT_INFO info;
+ if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) {
+ trace("setSmallFontXP: GetCurrentConsoleFont call failed");
+ return;
+ }
+ if (info.nFont != table[i].first) {
+ trace("setSmallFontXP: font was not set");
+ dumpXPFont(api, conout, "setSmallFontXP: post-call font: ");
+ continue;
+ }
+ trace("setSmallFontXP: success");
+ return;
+ }
+ trace("setSmallFontXP: failure");
+}
+
+} // anonymous namespace
+
+// A Windows console window can never be larger than the desktop window. To
+// maximize the possible size of the console in rows*cols, try to configure
+// the console with a small font. Unfortunately, we cannot make the font *too*
+// small, because there is also a minimum window size in pixels.
+void setSmallFont(HANDLE conout, int columns, bool isNewW10) {
+ trace("setSmallFont: attempting to set a small font for %d columns "
+ "(CP=%u OutputCP=%u)",
+ columns,
+ static_cast<unsigned>(GetConsoleCP()),
+ static_cast<unsigned>(GetConsoleOutputCP()));
+ VistaFontAPI vista;
+ if (vista.valid()) {
+ dumpVistaFont(vista, conout, "previous font: ");
+ dumpFontTable(conout, "previous font table: ");
+ setSmallFontVista(vista, conout, columns, isNewW10);
+ dumpVistaFont(vista, conout, "new font: ");
+ dumpFontTable(conout, "new font table: ");
+ return;
+ }
+ UndocumentedXPFontAPI xp;
+ if (xp.valid()) {
+ dumpXPFont(xp, conout, "previous font: ");
+ dumpFontTable(conout, "previous font table: ");
+ setSmallFontXP(xp, conout);
+ dumpXPFont(xp, conout, "new font: ");
+ dumpFontTable(conout, "new font table: ");
+ return;
+ }
+ trace("setSmallFont: neither Vista nor XP APIs detected -- giving up");
+ dumpFontTable(conout, "font table: ");
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h
new file mode 100644
index 0000000000..99cb10698d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef CONSOLEFONT_H
+#define CONSOLEFONT_H
+
+#include <windows.h>
+
+void setSmallFont(HANDLE conout, int columns, bool isNewW10);
+
+#endif // CONSOLEFONT_H
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc
new file mode 100644
index 0000000000..192cac2a29
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc
@@ -0,0 +1,852 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "ConsoleInput.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <algorithm>
+#include <string>
+
+#include "../include/winpty_constants.h"
+
+#include "../shared/DebugClient.h"
+#include "../shared/StringBuilder.h"
+#include "../shared/UnixCtrlChars.h"
+
+#include "ConsoleInputReencoding.h"
+#include "DebugShowInput.h"
+#include "DefaultInputMap.h"
+#include "DsrSender.h"
+#include "UnicodeEncoding.h"
+#include "Win32Console.h"
+
+// MAPVK_VK_TO_VSC isn't defined by the old MinGW.
+#ifndef MAPVK_VK_TO_VSC
+#define MAPVK_VK_TO_VSC 0
+#endif
+
+namespace {
+
+struct MouseRecord {
+ bool release;
+ int flags;
+ COORD coord;
+
+ std::string toString() const;
+};
+
+std::string MouseRecord::toString() const {
+ StringBuilder sb(40);
+ sb << "pos=" << coord.X << ',' << coord.Y
+ << " flags=0x" << hexOfInt(flags);
+ if (release) {
+ sb << " release";
+ }
+ return sb.str_moved();
+}
+
+const unsigned int kIncompleteEscapeTimeoutMs = 1000u;
+
+#define CHECK(cond) \
+ do { \
+ if (!(cond)) { return 0; } \
+ } while(0)
+
+#define ADVANCE() \
+ do { \
+ pch++; \
+ if (pch == stop) { return -1; } \
+ } while(0)
+
+#define SCAN_INT(out, maxLen) \
+ do { \
+ (out) = 0; \
+ CHECK(isdigit(*pch)); \
+ const char *begin = pch; \
+ do { \
+ CHECK(pch - begin + 1 < maxLen); \
+ (out) = (out) * 10 + *pch - '0'; \
+ ADVANCE(); \
+ } while (isdigit(*pch)); \
+ } while(0)
+
+#define SCAN_SIGNED_INT(out, maxLen) \
+ do { \
+ bool negative = false; \
+ if (*pch == '-') { \
+ negative = true; \
+ ADVANCE(); \
+ } \
+ SCAN_INT(out, maxLen); \
+ if (negative) { \
+ (out) = -(out); \
+ } \
+ } while(0)
+
+// Match the Device Status Report console input: ESC [ nn ; mm R
+// Returns:
+// 0 no match
+// >0 match, returns length of match
+// -1 incomplete match
+static int matchDsr(const char *input, int inputSize)
+{
+ int32_t dummy = 0;
+ const char *pch = input;
+ const char *stop = input + inputSize;
+ CHECK(*pch == '\x1B'); ADVANCE();
+ CHECK(*pch == '['); ADVANCE();
+ SCAN_INT(dummy, 8);
+ CHECK(*pch == ';'); ADVANCE();
+ SCAN_INT(dummy, 8);
+ CHECK(*pch == 'R');
+ return pch - input + 1;
+}
+
+static int matchMouseDefault(const char *input, int inputSize,
+ MouseRecord &out)
+{
+ const char *pch = input;
+ const char *stop = input + inputSize;
+ CHECK(*pch == '\x1B'); ADVANCE();
+ CHECK(*pch == '['); ADVANCE();
+ CHECK(*pch == 'M'); ADVANCE();
+ out.flags = (*pch - 32) & 0xFF; ADVANCE();
+ out.coord.X = (*pch - '!') & 0xFF;
+ ADVANCE();
+ out.coord.Y = (*pch - '!') & 0xFF;
+ out.release = false;
+ return pch - input + 1;
+}
+
+static int matchMouse1006(const char *input, int inputSize, MouseRecord &out)
+{
+ const char *pch = input;
+ const char *stop = input + inputSize;
+ int32_t temp;
+ CHECK(*pch == '\x1B'); ADVANCE();
+ CHECK(*pch == '['); ADVANCE();
+ CHECK(*pch == '<'); ADVANCE();
+ SCAN_INT(out.flags, 8);
+ CHECK(*pch == ';'); ADVANCE();
+ SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1;
+ CHECK(*pch == ';'); ADVANCE();
+ SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1;
+ CHECK(*pch == 'M' || *pch == 'm');
+ out.release = (*pch == 'm');
+ return pch - input + 1;
+}
+
+static int matchMouse1015(const char *input, int inputSize, MouseRecord &out)
+{
+ const char *pch = input;
+ const char *stop = input + inputSize;
+ int32_t temp;
+ CHECK(*pch == '\x1B'); ADVANCE();
+ CHECK(*pch == '['); ADVANCE();
+ SCAN_INT(out.flags, 8); out.flags -= 32;
+ CHECK(*pch == ';'); ADVANCE();
+ SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1;
+ CHECK(*pch == ';'); ADVANCE();
+ SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1;
+ CHECK(*pch == 'M');
+ out.release = false;
+ return pch - input + 1;
+}
+
+// Match a mouse input escape sequence of any kind.
+// 0 no match
+// >0 match, returns length of match
+// -1 incomplete match
+static int matchMouseRecord(const char *input, int inputSize, MouseRecord &out)
+{
+ memset(&out, 0, sizeof(out));
+ int ret;
+ if ((ret = matchMouse1006(input, inputSize, out)) != 0) { return ret; }
+ if ((ret = matchMouse1015(input, inputSize, out)) != 0) { return ret; }
+ if ((ret = matchMouseDefault(input, inputSize, out)) != 0) { return ret; }
+ return 0;
+}
+
+#undef CHECK
+#undef ADVANCE
+#undef SCAN_INT
+
+} // anonymous namespace
+
+ConsoleInput::ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender,
+ Win32Console &console) :
+ m_console(console),
+ m_conin(conin),
+ m_mouseMode(mouseMode),
+ m_dsrSender(dsrSender)
+{
+ addDefaultEntriesToInputMap(m_inputMap);
+ if (hasDebugFlag("dump_input_map")) {
+ m_inputMap.dumpInputMap();
+ }
+
+ // Configure Quick Edit mode according to the mouse mode. Enable
+ // InsertMode for two reasons:
+ // - If it's OFF, it's difficult for the user to turn it ON. The
+ // properties dialog is inaccesible. winpty still faithfully handles
+ // the Insert key, which toggles between the insertion and overwrite
+ // modes.
+ // - When we modify the QuickEdit setting, if ExtendedFlags is OFF,
+ // then we must choose the InsertMode setting. I don't *think* this
+ // case happens, though, because a new console always has ExtendedFlags
+ // ON.
+ // See misc/EnableExtendedFlags.txt.
+ DWORD mode = 0;
+ if (!GetConsoleMode(conin, &mode)) {
+ trace("Agent startup: GetConsoleMode failed");
+ } else {
+ mode |= ENABLE_EXTENDED_FLAGS;
+ mode |= ENABLE_INSERT_MODE;
+ if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) {
+ mode |= ENABLE_QUICK_EDIT_MODE;
+ } else {
+ mode &= ~ENABLE_QUICK_EDIT_MODE;
+ }
+ if (!SetConsoleMode(conin, mode)) {
+ trace("Agent startup: SetConsoleMode failed");
+ }
+ }
+
+ updateInputFlags(true);
+}
+
+void ConsoleInput::writeInput(const std::string &input)
+{
+ if (input.size() == 0) {
+ return;
+ }
+
+ if (isTracingEnabled()) {
+ static bool debugInput = hasDebugFlag("input");
+ if (debugInput) {
+ std::string dumpString;
+ for (size_t i = 0; i < input.size(); ++i) {
+ const char ch = input[i];
+ const char ctrl = decodeUnixCtrlChar(ch);
+ if (ctrl != '\0') {
+ dumpString += '^';
+ dumpString += ctrl;
+ } else {
+ dumpString += ch;
+ }
+ }
+ dumpString += " (";
+ for (size_t i = 0; i < input.size(); ++i) {
+ if (i > 0) {
+ dumpString += ' ';
+ }
+ const unsigned char uch = input[i];
+ char buf[32];
+ winpty_snprintf(buf, "%02X", uch);
+ dumpString += buf;
+ }
+ dumpString += ')';
+ trace("input chars: %s", dumpString.c_str());
+ }
+ }
+
+ m_byteQueue.append(input);
+ doWrite(false);
+ if (!m_byteQueue.empty() && !m_dsrSent) {
+ trace("send DSR");
+ m_dsrSender.sendDsr();
+ m_dsrSent = true;
+ }
+ m_lastWriteTick = GetTickCount();
+}
+
+void ConsoleInput::flushIncompleteEscapeCode()
+{
+ if (!m_byteQueue.empty() &&
+ (GetTickCount() - m_lastWriteTick) > kIncompleteEscapeTimeoutMs) {
+ doWrite(true);
+ m_byteQueue.clear();
+ }
+}
+
+void ConsoleInput::updateInputFlags(bool forceTrace)
+{
+ const DWORD mode = inputConsoleMode();
+ const bool newFlagEE = (mode & ENABLE_EXTENDED_FLAGS) != 0;
+ const bool newFlagMI = (mode & ENABLE_MOUSE_INPUT) != 0;
+ const bool newFlagQE = (mode & ENABLE_QUICK_EDIT_MODE) != 0;
+ const bool newFlagEI = (mode & 0x200) != 0;
+ if (forceTrace ||
+ newFlagEE != m_enableExtendedEnabled ||
+ newFlagMI != m_mouseInputEnabled ||
+ newFlagQE != m_quickEditEnabled ||
+ newFlagEI != m_escapeInputEnabled) {
+ trace("CONIN modes: Extended=%s, MouseInput=%s QuickEdit=%s EscapeInput=%s",
+ newFlagEE ? "on" : "off",
+ newFlagMI ? "on" : "off",
+ newFlagQE ? "on" : "off",
+ newFlagEI ? "on" : "off");
+ }
+ m_enableExtendedEnabled = newFlagEE;
+ m_mouseInputEnabled = newFlagMI;
+ m_quickEditEnabled = newFlagQE;
+ m_escapeInputEnabled = newFlagEI;
+}
+
+bool ConsoleInput::shouldActivateTerminalMouse()
+{
+ // Return whether the agent should activate the terminal's mouse mode.
+ if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) {
+ // Some programs (e.g. Cygwin command-line programs like bash.exe and
+ // python2.7.exe) turn off ENABLE_EXTENDED_FLAGS and turn on
+ // ENABLE_MOUSE_INPUT, but do not turn off QuickEdit mode and do not
+ // actually care about mouse input. Only enable the terminal mouse
+ // mode if ENABLE_EXTENDED_FLAGS is on. See
+ // misc/EnableExtendedFlags.txt.
+ return m_mouseInputEnabled && !m_quickEditEnabled &&
+ m_enableExtendedEnabled;
+ } else if (m_mouseMode == WINPTY_MOUSE_MODE_FORCE) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ConsoleInput::doWrite(bool isEof)
+{
+ const char *data = m_byteQueue.c_str();
+ std::vector<INPUT_RECORD> records;
+ size_t idx = 0;
+ while (idx < m_byteQueue.size()) {
+ int charSize = scanInput(records, &data[idx], m_byteQueue.size() - idx, isEof);
+ if (charSize == -1)
+ break;
+ idx += charSize;
+ }
+ m_byteQueue.erase(0, idx);
+ flushInputRecords(records);
+}
+
+void ConsoleInput::flushInputRecords(std::vector<INPUT_RECORD> &records)
+{
+ if (records.size() == 0) {
+ return;
+ }
+ DWORD actual = 0;
+ if (!WriteConsoleInputW(m_conin, records.data(), records.size(), &actual)) {
+ trace("WriteConsoleInputW failed");
+ }
+ records.clear();
+}
+
+// This behavior isn't strictly correct, because the keypresses (probably?)
+// adopt the keyboard state (e.g. Ctrl/Alt/Shift modifiers) of the current
+// window station's keyboard, which has no necessary relationship to the winpty
+// instance. It's unlikely to be an issue in practice, but it's conceivable.
+// (Imagine a foreground SSH server, where the local user holds down Ctrl,
+// while the remote user tries to use WSL navigation keys.) I suspect using
+// the BackgroundDesktop mechanism in winpty would fix the problem.
+//
+// https://github.com/rprichard/winpty/issues/116
+static void sendKeyMessage(HWND hwnd, bool isKeyDown, uint16_t virtualKey)
+{
+ uint32_t scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
+ if (scanCode > 255) {
+ scanCode = 0;
+ }
+ SendMessage(hwnd, isKeyDown ? WM_KEYDOWN : WM_KEYUP, virtualKey,
+ (scanCode << 16) | 1u | (isKeyDown ? 0u : 0xc0000000u));
+}
+
+int ConsoleInput::scanInput(std::vector<INPUT_RECORD> &records,
+ const char *input,
+ int inputSize,
+ bool isEof)
+{
+ ASSERT(inputSize >= 1);
+
+ // Ctrl-C.
+ //
+ // In processed mode, use GenerateConsoleCtrlEvent so that Ctrl-C handlers
+ // are called. GenerateConsoleCtrlEvent unfortunately doesn't interrupt
+ // ReadConsole calls[1]. Using WM_KEYDOWN/UP fixes the ReadConsole
+ // problem, but breaks in background window stations/desktops.
+ //
+ // In unprocessed mode, there's an entry for Ctrl-C in the SimpleEncoding
+ // table in DefaultInputMap.
+ //
+ // [1] https://github.com/rprichard/winpty/issues/116
+ if (input[0] == '\x03' && (inputConsoleMode() & ENABLE_PROCESSED_INPUT)) {
+ flushInputRecords(records);
+ trace("Ctrl-C");
+ const BOOL ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ trace("GenerateConsoleCtrlEvent: %d", ret);
+ return 1;
+ }
+
+ if (input[0] == '\x1B') {
+ // Attempt to match the Device Status Report (DSR) reply.
+ int dsrLen = matchDsr(input, inputSize);
+ if (dsrLen > 0) {
+ trace("Received a DSR reply");
+ m_dsrSent = false;
+ return dsrLen;
+ } else if (!isEof && dsrLen == -1) {
+ // Incomplete DSR match.
+ trace("Incomplete DSR match");
+ return -1;
+ }
+
+ int mouseLen = scanMouseInput(records, input, inputSize);
+ if (mouseLen > 0 || (!isEof && mouseLen == -1)) {
+ return mouseLen;
+ }
+ }
+
+ // Search the input map.
+ InputMap::Key match;
+ bool incomplete;
+ int matchLen = m_inputMap.lookupKey(input, inputSize, match, incomplete);
+ if (!isEof && incomplete) {
+ // Incomplete match -- need more characters (or wait for a
+ // timeout to signify flushed input).
+ trace("Incomplete escape sequence");
+ return -1;
+ } else if (matchLen > 0) {
+ uint32_t winCodePointDn = match.unicodeChar;
+ if ((match.keyState & LEFT_CTRL_PRESSED) && (match.keyState & LEFT_ALT_PRESSED)) {
+ winCodePointDn = '\0';
+ }
+ uint32_t winCodePointUp = winCodePointDn;
+ if (match.keyState & LEFT_ALT_PRESSED) {
+ winCodePointUp = '\0';
+ }
+ appendKeyPress(records, match.virtualKey,
+ winCodePointDn, winCodePointUp, match.keyState,
+ match.unicodeChar, match.keyState);
+ return matchLen;
+ }
+
+ // Recognize Alt-<character>.
+ //
+ // This code doesn't match Alt-ESC, which is encoded as `ESC ESC`, but
+ // maybe it should. I was concerned that pressing ESC rapidly enough could
+ // accidentally trigger Alt-ESC. (e.g. The user would have to be faster
+ // than the DSR flushing mechanism or use a decrepit terminal. The user
+ // might be on a slow network connection.)
+ if (input[0] == '\x1B' && inputSize >= 2 && input[1] != '\x1B') {
+ const int len = utf8CharLength(input[1]);
+ if (len > 0) {
+ if (1 + len > inputSize) {
+ // Incomplete character.
+ trace("Incomplete UTF-8 character in Alt-<Char>");
+ return -1;
+ }
+ appendUtf8Char(records, &input[1], len, true);
+ return 1 + len;
+ }
+ }
+
+ // A UTF-8 character.
+ const int len = utf8CharLength(input[0]);
+ if (len == 0) {
+ static bool debugInput = isTracingEnabled() && hasDebugFlag("input");
+ if (debugInput) {
+ trace("Discarding invalid input byte: %02X",
+ static_cast<unsigned char>(input[0]));
+ }
+ return 1;
+ }
+ if (len > inputSize) {
+ // Incomplete character.
+ trace("Incomplete UTF-8 character");
+ return -1;
+ }
+ appendUtf8Char(records, &input[0], len, false);
+ return len;
+}
+
+int ConsoleInput::scanMouseInput(std::vector<INPUT_RECORD> &records,
+ const char *input,
+ int inputSize)
+{
+ MouseRecord record;
+ const int len = matchMouseRecord(input, inputSize, record);
+ if (len <= 0) {
+ return len;
+ }
+
+ if (isTracingEnabled()) {
+ static bool debugInput = hasDebugFlag("input");
+ if (debugInput) {
+ trace("mouse input: %s", record.toString().c_str());
+ }
+ }
+
+ const int button = record.flags & 0x03;
+ INPUT_RECORD newRecord = {0};
+ newRecord.EventType = MOUSE_EVENT;
+ MOUSE_EVENT_RECORD &mer = newRecord.Event.MouseEvent;
+
+ mer.dwMousePosition.X =
+ m_mouseWindowRect.Left +
+ std::max(0, std::min<int>(record.coord.X,
+ m_mouseWindowRect.width() - 1));
+
+ mer.dwMousePosition.Y =
+ m_mouseWindowRect.Top +
+ std::max(0, std::min<int>(record.coord.Y,
+ m_mouseWindowRect.height() - 1));
+
+ // The modifier state is neatly independent of everything else.
+ if (record.flags & 0x04) { mer.dwControlKeyState |= SHIFT_PRESSED; }
+ if (record.flags & 0x08) { mer.dwControlKeyState |= LEFT_ALT_PRESSED; }
+ if (record.flags & 0x10) { mer.dwControlKeyState |= LEFT_CTRL_PRESSED; }
+
+ if (record.flags & 0x40) {
+ // Mouse wheel
+ mer.dwEventFlags |= MOUSE_WHEELED;
+ if (button == 0) {
+ // up
+ mer.dwButtonState |= 0x00780000;
+ } else if (button == 1) {
+ // down
+ mer.dwButtonState |= 0xff880000;
+ } else {
+ // Invalid -- do nothing
+ return len;
+ }
+ } else {
+ // Ordinary mouse event
+ if (record.flags & 0x20) { mer.dwEventFlags |= MOUSE_MOVED; }
+ if (button == 3) {
+ m_mouseButtonState = 0;
+ // Potentially advance double-click detection.
+ m_doubleClick.released = true;
+ } else {
+ const DWORD relevantFlag =
+ (button == 0) ? FROM_LEFT_1ST_BUTTON_PRESSED :
+ (button == 1) ? FROM_LEFT_2ND_BUTTON_PRESSED :
+ (button == 2) ? RIGHTMOST_BUTTON_PRESSED :
+ 0;
+ ASSERT(relevantFlag != 0);
+ if (record.release) {
+ m_mouseButtonState &= ~relevantFlag;
+ if (relevantFlag == m_doubleClick.button) {
+ // Potentially advance double-click detection.
+ m_doubleClick.released = true;
+ } else {
+ // End double-click detection.
+ m_doubleClick = DoubleClickDetection();
+ }
+ } else if ((m_mouseButtonState & relevantFlag) == 0) {
+ // The button has been newly pressed.
+ m_mouseButtonState |= relevantFlag;
+ // Detect a double-click. This code looks for an exact
+ // coordinate match, which is stricter than what Windows does,
+ // but Windows has pixel coordinates, and we only have terminal
+ // coordinates.
+ if (m_doubleClick.button == relevantFlag &&
+ m_doubleClick.pos == record.coord &&
+ (GetTickCount() - m_doubleClick.tick <
+ GetDoubleClickTime())) {
+ // Record a double-click and end double-click detection.
+ mer.dwEventFlags |= DOUBLE_CLICK;
+ m_doubleClick = DoubleClickDetection();
+ } else {
+ // Begin double-click detection.
+ m_doubleClick.button = relevantFlag;
+ m_doubleClick.pos = record.coord;
+ m_doubleClick.tick = GetTickCount();
+ }
+ }
+ }
+ }
+
+ mer.dwButtonState |= m_mouseButtonState;
+
+ if (m_mouseInputEnabled && !m_quickEditEnabled) {
+ if (isTracingEnabled()) {
+ static bool debugInput = hasDebugFlag("input");
+ if (debugInput) {
+ trace("mouse event: %s", mouseEventToString(mer).c_str());
+ }
+ }
+
+ records.push_back(newRecord);
+ }
+
+ return len;
+}
+
+void ConsoleInput::appendUtf8Char(std::vector<INPUT_RECORD> &records,
+ const char *charBuffer,
+ const int charLen,
+ const bool terminalAltEscape)
+{
+ const uint32_t codePoint = decodeUtf8(charBuffer);
+ if (codePoint == static_cast<uint32_t>(-1)) {
+ static bool debugInput = isTracingEnabled() && hasDebugFlag("input");
+ if (debugInput) {
+ StringBuilder error(64);
+ error << "Discarding invalid UTF-8 sequence:";
+ for (int i = 0; i < charLen; ++i) {
+ error << ' ';
+ error << hexOfInt<true, uint8_t>(charBuffer[i]);
+ }
+ trace("%s", error.c_str());
+ }
+ return;
+ }
+
+ const short charScan = codePoint > 0xFFFF ? -1 : VkKeyScan(codePoint);
+ uint16_t virtualKey = 0;
+ uint16_t winKeyState = 0;
+ uint32_t winCodePointDn = codePoint;
+ uint32_t winCodePointUp = codePoint;
+ uint16_t vtKeyState = 0;
+
+ if (charScan != -1) {
+ virtualKey = charScan & 0xFF;
+ if (charScan & 0x100) {
+ winKeyState |= SHIFT_PRESSED;
+ }
+ if (charScan & 0x200) {
+ winKeyState |= LEFT_CTRL_PRESSED;
+ }
+ if (charScan & 0x400) {
+ winKeyState |= RIGHT_ALT_PRESSED;
+ }
+ if (terminalAltEscape && (winKeyState & LEFT_CTRL_PRESSED)) {
+ // If the terminal escapes a Ctrl-<Key> with Alt, then set the
+ // codepoint to 0. On the other hand, if a character requires
+ // AltGr (like U+00B2 on a German layout), then VkKeyScan will
+ // report both Ctrl and Alt pressed, and we should keep the
+ // codepoint. See https://github.com/rprichard/winpty/issues/109.
+ winCodePointDn = 0;
+ winCodePointUp = 0;
+ }
+ }
+ if (terminalAltEscape) {
+ winCodePointUp = 0;
+ winKeyState |= LEFT_ALT_PRESSED;
+ vtKeyState |= LEFT_ALT_PRESSED;
+ }
+
+ appendKeyPress(records, virtualKey,
+ winCodePointDn, winCodePointUp, winKeyState,
+ codePoint, vtKeyState);
+}
+
+void ConsoleInput::appendKeyPress(std::vector<INPUT_RECORD> &records,
+ const uint16_t virtualKey,
+ const uint32_t winCodePointDn,
+ const uint32_t winCodePointUp,
+ const uint16_t winKeyState,
+ const uint32_t vtCodePoint,
+ const uint16_t vtKeyState)
+{
+ const bool ctrl = (winKeyState & LEFT_CTRL_PRESSED) != 0;
+ const bool leftAlt = (winKeyState & LEFT_ALT_PRESSED) != 0;
+ const bool rightAlt = (winKeyState & RIGHT_ALT_PRESSED) != 0;
+ const bool shift = (winKeyState & SHIFT_PRESSED) != 0;
+ const bool enhanced = (winKeyState & ENHANCED_KEY) != 0;
+ bool hasDebugInput = false;
+
+ if (isTracingEnabled()) {
+ static bool debugInput = hasDebugFlag("input");
+ if (debugInput) {
+ hasDebugInput = true;
+ InputMap::Key key = { virtualKey, winCodePointDn, winKeyState };
+ trace("keypress: %s", key.toString().c_str());
+ }
+ }
+
+ if (m_escapeInputEnabled &&
+ (virtualKey == VK_UP ||
+ virtualKey == VK_DOWN ||
+ virtualKey == VK_LEFT ||
+ virtualKey == VK_RIGHT ||
+ virtualKey == VK_HOME ||
+ virtualKey == VK_END) &&
+ !ctrl && !leftAlt && !rightAlt && !shift) {
+ flushInputRecords(records);
+ if (hasDebugInput) {
+ trace("sending keypress to console HWND");
+ }
+ sendKeyMessage(m_console.hwnd(), true, virtualKey);
+ sendKeyMessage(m_console.hwnd(), false, virtualKey);
+ return;
+ }
+
+ uint16_t stepKeyState = 0;
+ if (ctrl) {
+ stepKeyState |= LEFT_CTRL_PRESSED;
+ appendInputRecord(records, TRUE, VK_CONTROL, 0, stepKeyState);
+ }
+ if (leftAlt) {
+ stepKeyState |= LEFT_ALT_PRESSED;
+ appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState);
+ }
+ if (rightAlt) {
+ stepKeyState |= RIGHT_ALT_PRESSED;
+ appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState | ENHANCED_KEY);
+ }
+ if (shift) {
+ stepKeyState |= SHIFT_PRESSED;
+ appendInputRecord(records, TRUE, VK_SHIFT, 0, stepKeyState);
+ }
+ if (enhanced) {
+ stepKeyState |= ENHANCED_KEY;
+ }
+ if (m_escapeInputEnabled) {
+ reencodeEscapedKeyPress(records, virtualKey, vtCodePoint, vtKeyState);
+ } else {
+ appendCPInputRecords(records, TRUE, virtualKey, winCodePointDn, stepKeyState);
+ }
+ appendCPInputRecords(records, FALSE, virtualKey, winCodePointUp, stepKeyState);
+ if (enhanced) {
+ stepKeyState &= ~ENHANCED_KEY;
+ }
+ if (shift) {
+ stepKeyState &= ~SHIFT_PRESSED;
+ appendInputRecord(records, FALSE, VK_SHIFT, 0, stepKeyState);
+ }
+ if (rightAlt) {
+ stepKeyState &= ~RIGHT_ALT_PRESSED;
+ appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState | ENHANCED_KEY);
+ }
+ if (leftAlt) {
+ stepKeyState &= ~LEFT_ALT_PRESSED;
+ appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState);
+ }
+ if (ctrl) {
+ stepKeyState &= ~LEFT_CTRL_PRESSED;
+ appendInputRecord(records, FALSE, VK_CONTROL, 0, stepKeyState);
+ }
+}
+
+void ConsoleInput::appendCPInputRecords(std::vector<INPUT_RECORD> &records,
+ BOOL keyDown,
+ uint16_t virtualKey,
+ uint32_t codePoint,
+ uint16_t keyState)
+{
+ // This behavior really doesn't match that of the Windows console (in
+ // normal, non-escape-mode). Judging by the copy-and-paste behavior,
+ // Windows apparently handles everything outside of the keyboard layout by
+ // first sending a sequence of Alt+KeyPad events, then finally a key-up
+ // event whose UnicodeChar has the appropriate value. For U+00A2 (CENT
+ // SIGN):
+ //
+ // key: dn rpt=1 scn=56 LAlt-MENU ch=0
+ // key: dn rpt=1 scn=79 LAlt-NUMPAD1 ch=0
+ // key: up rpt=1 scn=79 LAlt-NUMPAD1 ch=0
+ // key: dn rpt=1 scn=76 LAlt-NUMPAD5 ch=0
+ // key: up rpt=1 scn=76 LAlt-NUMPAD5 ch=0
+ // key: dn rpt=1 scn=76 LAlt-NUMPAD5 ch=0
+ // key: up rpt=1 scn=76 LAlt-NUMPAD5 ch=0
+ // key: up rpt=1 scn=56 MENU ch=0xa2
+ //
+ // The Alt+155 value matches the encoding of U+00A2 in CP-437. Curiously,
+ // if I use "chcp 1252" to change the encoding, then copy-and-pasting
+ // produces Alt+162 instead. (U+00A2 is 162 in CP-1252.) However, typing
+ // Alt+155 or Alt+162 produce the same characters regardless of console
+ // code page. (That is, they use CP-437 and yield U+00A2 and U+00F3.)
+ //
+ // For characters outside the BMP, Windows repeats the process for both
+ // UTF-16 code units, e.g, for U+1F300 (CYCLONE):
+ //
+ // key: dn rpt=1 scn=56 LAlt-MENU ch=0
+ // key: dn rpt=1 scn=77 LAlt-NUMPAD6 ch=0
+ // key: up rpt=1 scn=77 LAlt-NUMPAD6 ch=0
+ // key: dn rpt=1 scn=81 LAlt-NUMPAD3 ch=0
+ // key: up rpt=1 scn=81 LAlt-NUMPAD3 ch=0
+ // key: up rpt=1 scn=56 MENU ch=0xd83c
+ // key: dn rpt=1 scn=56 LAlt-MENU ch=0
+ // key: dn rpt=1 scn=77 LAlt-NUMPAD6 ch=0
+ // key: up rpt=1 scn=77 LAlt-NUMPAD6 ch=0
+ // key: dn rpt=1 scn=81 LAlt-NUMPAD3 ch=0
+ // key: up rpt=1 scn=81 LAlt-NUMPAD3 ch=0
+ // key: up rpt=1 scn=56 MENU ch=0xdf00
+ //
+ // In this case, it sends Alt+63 twice, which signifies '?'. Apparently
+ // CMD and Cygwin bash are both able to decode this.
+ //
+ // Also note that typing Alt+NNN still works if NumLock is off, e.g.:
+ //
+ // key: dn rpt=1 scn=56 LAlt-MENU ch=0
+ // key: dn rpt=1 scn=79 LAlt-END ch=0
+ // key: up rpt=1 scn=79 LAlt-END ch=0
+ // key: dn rpt=1 scn=76 LAlt-CLEAR ch=0
+ // key: up rpt=1 scn=76 LAlt-CLEAR ch=0
+ // key: dn rpt=1 scn=76 LAlt-CLEAR ch=0
+ // key: up rpt=1 scn=76 LAlt-CLEAR ch=0
+ // key: up rpt=1 scn=56 MENU ch=0xa2
+ //
+ // Evidently, the Alt+NNN key events are not intended to be decoded to a
+ // character. Maybe programs are looking for a key-up ALT/MENU event with
+ // a non-zero character?
+
+ wchar_t ws[2];
+ const int wslen = encodeUtf16(ws, codePoint);
+
+ if (wslen == 1) {
+ appendInputRecord(records, keyDown, virtualKey, ws[0], keyState);
+ } else if (wslen == 2) {
+ appendInputRecord(records, keyDown, virtualKey, ws[0], keyState);
+ appendInputRecord(records, keyDown, virtualKey, ws[1], keyState);
+ } else {
+ // This situation isn't that bad, but it should never happen,
+ // because invalid codepoints shouldn't reach this point.
+ trace("INTERNAL ERROR: appendInputRecordCP: invalid codePoint: "
+ "U+%04X", codePoint);
+ }
+}
+
+void ConsoleInput::appendInputRecord(std::vector<INPUT_RECORD> &records,
+ BOOL keyDown,
+ uint16_t virtualKey,
+ wchar_t utf16Char,
+ uint16_t keyState)
+{
+ INPUT_RECORD ir = {};
+ ir.EventType = KEY_EVENT;
+ ir.Event.KeyEvent.bKeyDown = keyDown;
+ ir.Event.KeyEvent.wRepeatCount = 1;
+ ir.Event.KeyEvent.wVirtualKeyCode = virtualKey;
+ ir.Event.KeyEvent.wVirtualScanCode =
+ MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
+ ir.Event.KeyEvent.uChar.UnicodeChar = utf16Char;
+ ir.Event.KeyEvent.dwControlKeyState = keyState;
+ records.push_back(ir);
+}
+
+DWORD ConsoleInput::inputConsoleMode()
+{
+ DWORD mode = 0;
+ if (!GetConsoleMode(m_conin, &mode)) {
+ trace("GetConsoleMode failed");
+ return 0;
+ }
+ return mode;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h
new file mode 100644
index 0000000000..e807d973ba
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef CONSOLEINPUT_H
+#define CONSOLEINPUT_H
+
+#include <windows.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Coord.h"
+#include "InputMap.h"
+#include "SmallRect.h"
+
+class Win32Console;
+class DsrSender;
+
+class ConsoleInput
+{
+public:
+ ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender,
+ Win32Console &console);
+ void writeInput(const std::string &input);
+ void flushIncompleteEscapeCode();
+ void setMouseWindowRect(SmallRect val) { m_mouseWindowRect = val; }
+ void updateInputFlags(bool forceTrace=false);
+ bool shouldActivateTerminalMouse();
+
+private:
+ void doWrite(bool isEof);
+ void flushInputRecords(std::vector<INPUT_RECORD> &records);
+ int scanInput(std::vector<INPUT_RECORD> &records,
+ const char *input,
+ int inputSize,
+ bool isEof);
+ int scanMouseInput(std::vector<INPUT_RECORD> &records,
+ const char *input,
+ int inputSize);
+ void appendUtf8Char(std::vector<INPUT_RECORD> &records,
+ const char *charBuffer,
+ int charLen,
+ bool terminalAltEscape);
+ void appendKeyPress(std::vector<INPUT_RECORD> &records,
+ uint16_t virtualKey,
+ uint32_t winCodePointDn,
+ uint32_t winCodePointUp,
+ uint16_t winKeyState,
+ uint32_t vtCodePoint,
+ uint16_t vtKeyState);
+
+public:
+ static void appendCPInputRecords(std::vector<INPUT_RECORD> &records,
+ BOOL keyDown,
+ uint16_t virtualKey,
+ uint32_t codePoint,
+ uint16_t keyState);
+ static void appendInputRecord(std::vector<INPUT_RECORD> &records,
+ BOOL keyDown,
+ uint16_t virtualKey,
+ wchar_t utf16Char,
+ uint16_t keyState);
+
+private:
+ DWORD inputConsoleMode();
+
+private:
+ Win32Console &m_console;
+ HANDLE m_conin = nullptr;
+ int m_mouseMode = 0;
+ DsrSender &m_dsrSender;
+ bool m_dsrSent = false;
+ std::string m_byteQueue;
+ InputMap m_inputMap;
+ DWORD m_lastWriteTick = 0;
+ DWORD m_mouseButtonState = 0;
+ struct DoubleClickDetection {
+ DWORD button = 0;
+ Coord pos;
+ DWORD tick = 0;
+ bool released = false;
+ } m_doubleClick;
+ bool m_enableExtendedEnabled = false;
+ bool m_mouseInputEnabled = false;
+ bool m_quickEditEnabled = false;
+ bool m_escapeInputEnabled = false;
+ SmallRect m_mouseWindowRect;
+};
+
+#endif // CONSOLEINPUT_H
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc
new file mode 100644
index 0000000000..b79545eea9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "ConsoleInputReencoding.h"
+
+#include "ConsoleInput.h"
+
+namespace {
+
+static void outch(std::vector<INPUT_RECORD> &out, wchar_t ch) {
+ ConsoleInput::appendInputRecord(out, TRUE, 0, ch, 0);
+}
+
+} // anonymous namespace
+
+void reencodeEscapedKeyPress(
+ std::vector<INPUT_RECORD> &out,
+ uint16_t virtualKey,
+ uint32_t codePoint,
+ uint16_t keyState) {
+
+ struct EscapedKey {
+ enum { None, Numeric, Letter } kind;
+ wchar_t content[2];
+ };
+
+ EscapedKey escapeCode = {};
+ switch (virtualKey) {
+ case VK_UP: escapeCode = { EscapedKey::Letter, {'A'} }; break;
+ case VK_DOWN: escapeCode = { EscapedKey::Letter, {'B'} }; break;
+ case VK_RIGHT: escapeCode = { EscapedKey::Letter, {'C'} }; break;
+ case VK_LEFT: escapeCode = { EscapedKey::Letter, {'D'} }; break;
+ case VK_CLEAR: escapeCode = { EscapedKey::Letter, {'E'} }; break;
+ case VK_F1: escapeCode = { EscapedKey::Numeric, {'1', '1'} }; break;
+ case VK_F2: escapeCode = { EscapedKey::Numeric, {'1', '2'} }; break;
+ case VK_F3: escapeCode = { EscapedKey::Numeric, {'1', '3'} }; break;
+ case VK_F4: escapeCode = { EscapedKey::Numeric, {'1', '4'} }; break;
+ case VK_F5: escapeCode = { EscapedKey::Numeric, {'1', '5'} }; break;
+ case VK_F6: escapeCode = { EscapedKey::Numeric, {'1', '7'} }; break;
+ case VK_F7: escapeCode = { EscapedKey::Numeric, {'1', '8'} }; break;
+ case VK_F8: escapeCode = { EscapedKey::Numeric, {'1', '9'} }; break;
+ case VK_F9: escapeCode = { EscapedKey::Numeric, {'2', '0'} }; break;
+ case VK_F10: escapeCode = { EscapedKey::Numeric, {'2', '1'} }; break;
+ case VK_F11: escapeCode = { EscapedKey::Numeric, {'2', '3'} }; break;
+ case VK_F12: escapeCode = { EscapedKey::Numeric, {'2', '4'} }; break;
+ case VK_HOME: escapeCode = { EscapedKey::Letter, {'H'} }; break;
+ case VK_INSERT: escapeCode = { EscapedKey::Numeric, {'2'} }; break;
+ case VK_DELETE: escapeCode = { EscapedKey::Numeric, {'3'} }; break;
+ case VK_END: escapeCode = { EscapedKey::Letter, {'F'} }; break;
+ case VK_PRIOR: escapeCode = { EscapedKey::Numeric, {'5'} }; break;
+ case VK_NEXT: escapeCode = { EscapedKey::Numeric, {'6'} }; break;
+ }
+ if (escapeCode.kind != EscapedKey::None) {
+ int flags = 0;
+ if (keyState & SHIFT_PRESSED) { flags |= 0x1; }
+ if (keyState & LEFT_ALT_PRESSED) { flags |= 0x2; }
+ if (keyState & LEFT_CTRL_PRESSED) { flags |= 0x4; }
+ outch(out, L'\x1b');
+ outch(out, L'[');
+ if (escapeCode.kind == EscapedKey::Numeric) {
+ for (wchar_t ch : escapeCode.content) {
+ if (ch != L'\0') {
+ outch(out, ch);
+ }
+ }
+ } else if (flags != 0) {
+ outch(out, L'1');
+ }
+ if (flags != 0) {
+ outch(out, L';');
+ outch(out, L'1' + flags);
+ }
+ if (escapeCode.kind == EscapedKey::Numeric) {
+ outch(out, L'~');
+ } else {
+ outch(out, escapeCode.content[0]);
+ }
+ return;
+ }
+
+ switch (virtualKey) {
+ case VK_BACK:
+ if (keyState & LEFT_ALT_PRESSED) {
+ outch(out, L'\x1b');
+ }
+ outch(out, L'\x7f');
+ return;
+ case VK_TAB:
+ if (keyState & SHIFT_PRESSED) {
+ outch(out, L'\x1b');
+ outch(out, L'[');
+ outch(out, L'Z');
+ return;
+ }
+ break;
+ }
+
+ if (codePoint != 0) {
+ if (keyState & LEFT_ALT_PRESSED) {
+ outch(out, L'\x1b');
+ }
+ ConsoleInput::appendCPInputRecords(out, TRUE, 0, codePoint, 0);
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h
new file mode 100644
index 0000000000..63bc006b5a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_CONSOLE_INPUT_REENCODING_H
+#define AGENT_CONSOLE_INPUT_REENCODING_H
+
+#include <windows.h>
+
+#include <stdint.h>
+
+#include <vector>
+
+void reencodeEscapedKeyPress(
+ std::vector<INPUT_RECORD> &records,
+ uint16_t virtualKey,
+ uint32_t codePoint,
+ uint16_t keyState);
+
+#endif // AGENT_CONSOLE_INPUT_REENCODING_H
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc
new file mode 100644
index 0000000000..1d2bcb7685
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+//
+// ConsoleLine
+//
+// This data structure keep tracks of the previous CHAR_INFO content of an
+// output line and determines when a line has changed. Detecting line changes
+// is made complicated by terminal resizing.
+//
+
+#include "ConsoleLine.h"
+
+#include <algorithm>
+
+#include "../shared/WinptyAssert.h"
+
+static CHAR_INFO blankChar(WORD attributes)
+{
+ // N.B.: As long as we write to UnicodeChar rather than AsciiChar, there
+ // are no padding bytes that could contain uninitialized bytes. This fact
+ // is important for efficient comparison.
+ CHAR_INFO ret;
+ ret.Attributes = attributes;
+ ret.Char.UnicodeChar = L' ';
+ return ret;
+}
+
+static bool isLineBlank(const CHAR_INFO *line, int length, WORD attributes)
+{
+ for (int col = 0; col < length; ++col) {
+ if (line[col].Attributes != attributes ||
+ line[col].Char.UnicodeChar != L' ') {
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool areLinesEqual(
+ const CHAR_INFO *line1,
+ const CHAR_INFO *line2,
+ int length)
+{
+ return memcmp(line1, line2, sizeof(CHAR_INFO) * length) == 0;
+}
+
+ConsoleLine::ConsoleLine() : m_prevLength(0)
+{
+}
+
+void ConsoleLine::reset()
+{
+ m_prevLength = 0;
+ m_prevData.clear();
+}
+
+// Determines whether the given line is sufficiently different from the
+// previously seen line as to justify reoutputting the line. The function
+// also sets the `ConsoleLine` to the given line, exactly as if `setLine` had
+// been called.
+bool ConsoleLine::detectChangeAndSetLine(const CHAR_INFO *const line, const int newLength)
+{
+ ASSERT(newLength >= 1);
+ ASSERT(m_prevLength <= static_cast<int>(m_prevData.size()));
+
+ if (newLength == m_prevLength) {
+ bool equalLines = areLinesEqual(m_prevData.data(), line, newLength);
+ if (!equalLines) {
+ setLine(line, newLength);
+ }
+ return !equalLines;
+ } else {
+ if (m_prevLength == 0) {
+ setLine(line, newLength);
+ return true;
+ }
+
+ ASSERT(m_prevLength >= 1);
+ const WORD prevBlank = m_prevData[m_prevLength - 1].Attributes;
+ const WORD newBlank = line[newLength - 1].Attributes;
+
+ bool equalLines = false;
+ if (newLength < m_prevLength) {
+ // The line has become shorter. The lines are equal if the common
+ // part is equal, and if the newly truncated characters were blank.
+ equalLines =
+ areLinesEqual(m_prevData.data(), line, newLength) &&
+ isLineBlank(m_prevData.data() + newLength,
+ m_prevLength - newLength,
+ newBlank);
+ } else {
+ //
+ // The line has become longer. The lines are equal if the common
+ // part is equal, and if both the extra characters and any
+ // potentially reexposed characters are blank.
+ //
+ // Two of the most relevant terminals for winpty--mintty and
+ // jediterm--don't (currently) erase the obscured content when a
+ // line is cleared, so we should anticipate its existence when
+ // making a terminal wider and reoutput the line. See:
+ //
+ // * https://github.com/mintty/mintty/issues/480
+ // * https://github.com/JetBrains/jediterm/issues/118
+ //
+ ASSERT(newLength > m_prevLength);
+ equalLines =
+ areLinesEqual(m_prevData.data(), line, m_prevLength) &&
+ isLineBlank(m_prevData.data() + m_prevLength,
+ std::min<int>(m_prevData.size(), newLength) - m_prevLength,
+ prevBlank) &&
+ isLineBlank(line + m_prevLength,
+ newLength - m_prevLength,
+ prevBlank);
+ }
+ setLine(line, newLength);
+ return !equalLines;
+ }
+}
+
+void ConsoleLine::setLine(const CHAR_INFO *const line, const int newLength)
+{
+ if (static_cast<int>(m_prevData.size()) < newLength) {
+ m_prevData.resize(newLength);
+ }
+ memcpy(m_prevData.data(), line, sizeof(CHAR_INFO) * newLength);
+ m_prevLength = newLength;
+}
+
+void ConsoleLine::blank(WORD attributes)
+{
+ m_prevData.resize(1);
+ m_prevData[0] = blankChar(attributes);
+ m_prevLength = 1;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h
new file mode 100644
index 0000000000..802c189c75
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef CONSOLE_LINE_H
+#define CONSOLE_LINE_H
+
+#include <windows.h>
+
+#include <vector>
+
+class ConsoleLine
+{
+public:
+ ConsoleLine();
+ void reset();
+ bool detectChangeAndSetLine(const CHAR_INFO *line, int newLength);
+ void setLine(const CHAR_INFO *line, int newLength);
+ void blank(WORD attributes);
+private:
+ int m_prevLength;
+ std::vector<CHAR_INFO> m_prevData;
+};
+
+#endif // CONSOLE_LINE_H
diff --git a/src/libs/3rdparty/winpty/src/agent/Coord.h b/src/libs/3rdparty/winpty/src/agent/Coord.h
new file mode 100644
index 0000000000..74c98addac
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Coord.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef COORD_H
+#define COORD_H
+
+#include <windows.h>
+
+#include <string>
+
+#include "../shared/winpty_snprintf.h"
+
+struct Coord : COORD {
+ Coord()
+ {
+ X = 0;
+ Y = 0;
+ }
+
+ Coord(SHORT x, SHORT y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ Coord(COORD other)
+ {
+ *(COORD*)this = other;
+ }
+
+ Coord(const Coord &other)
+ {
+ *(COORD*)this = *(const COORD*)&other;
+ }
+
+ Coord &operator=(const Coord &other)
+ {
+ *(COORD*)this = *(const COORD*)&other;
+ return *this;
+ }
+
+ bool operator==(const Coord &other) const
+ {
+ return X == other.X && Y == other.Y;
+ }
+
+ bool operator!=(const Coord &other) const
+ {
+ return !(*this == other);
+ }
+
+ Coord operator+(const Coord &other) const
+ {
+ return Coord(X + other.X, Y + other.Y);
+ }
+
+ bool isEmpty() const
+ {
+ return X <= 0 || Y <= 0;
+ }
+
+ std::string toString() const
+ {
+ char ret[32];
+ winpty_snprintf(ret, "(%d,%d)", X, Y);
+ return std::string(ret);
+ }
+};
+
+#endif // COORD_H
diff --git a/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc
new file mode 100644
index 0000000000..191b2e1466
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "DebugShowInput.h"
+
+#include <windows.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "../shared/StringBuilder.h"
+#include "InputMap.h"
+
+namespace {
+
+struct Flag {
+ DWORD value;
+ const char *text;
+};
+
+static const Flag kButtonStates[] = {
+ { FROM_LEFT_1ST_BUTTON_PRESSED, "1" },
+ { FROM_LEFT_2ND_BUTTON_PRESSED, "2" },
+ { FROM_LEFT_3RD_BUTTON_PRESSED, "3" },
+ { FROM_LEFT_4TH_BUTTON_PRESSED, "4" },
+ { RIGHTMOST_BUTTON_PRESSED, "R" },
+};
+
+static const Flag kControlKeyStates[] = {
+ { CAPSLOCK_ON, "CapsLock" },
+ { ENHANCED_KEY, "Enhanced" },
+ { LEFT_ALT_PRESSED, "LAlt" },
+ { LEFT_CTRL_PRESSED, "LCtrl" },
+ { NUMLOCK_ON, "NumLock" },
+ { RIGHT_ALT_PRESSED, "RAlt" },
+ { RIGHT_CTRL_PRESSED, "RCtrl" },
+ { SCROLLLOCK_ON, "ScrollLock" },
+ { SHIFT_PRESSED, "Shift" },
+};
+
+static const Flag kMouseEventFlags[] = {
+ { DOUBLE_CLICK, "Double" },
+ { 8/*MOUSE_HWHEELED*/, "HWheel" },
+ { MOUSE_MOVED, "Move" },
+ { MOUSE_WHEELED, "Wheel" },
+};
+
+static void writeFlags(StringBuilder &out, DWORD flags,
+ const char *remainderName,
+ const Flag *table, size_t tableSize,
+ char pre, char sep, char post) {
+ DWORD remaining = flags;
+ bool wroteSomething = false;
+ for (size_t i = 0; i < tableSize; ++i) {
+ const Flag &f = table[i];
+ if ((f.value & flags) == f.value) {
+ if (!wroteSomething && pre != '\0') {
+ out << pre;
+ } else if (wroteSomething && sep != '\0') {
+ out << sep;
+ }
+ out << f.text;
+ wroteSomething = true;
+ remaining &= ~f.value;
+ }
+ }
+ if (remaining != 0) {
+ if (!wroteSomething && pre != '\0') {
+ out << pre;
+ } else if (wroteSomething && sep != '\0') {
+ out << sep;
+ }
+ out << remainderName << "(0x" << hexOfInt(remaining) << ')';
+ wroteSomething = true;
+ }
+ if (wroteSomething && post != '\0') {
+ out << post;
+ }
+}
+
+template <size_t n>
+static void writeFlags(StringBuilder &out, DWORD flags,
+ const char *remainderName,
+ const Flag (&table)[n],
+ char pre, char sep, char post) {
+ writeFlags(out, flags, remainderName, table, n, pre, sep, post);
+}
+
+} // anonymous namespace
+
+std::string controlKeyStatePrefix(DWORD controlKeyState) {
+ StringBuilder sb;
+ writeFlags(sb, controlKeyState,
+ "keyState", kControlKeyStates, '\0', '-', '-');
+ return sb.str_moved();
+}
+
+std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer) {
+ const uint16_t buttons = mer.dwButtonState & 0xFFFF;
+ const int16_t wheel = mer.dwButtonState >> 16;
+ StringBuilder sb;
+ sb << "pos=" << mer.dwMousePosition.X << ','
+ << mer.dwMousePosition.Y;
+ writeFlags(sb, mer.dwControlKeyState, "keyState", kControlKeyStates, ' ', ' ', '\0');
+ writeFlags(sb, mer.dwEventFlags, "flags", kMouseEventFlags, ' ', ' ', '\0');
+ writeFlags(sb, buttons, "buttons", kButtonStates, ' ', ' ', '\0');
+ if (wheel != 0) {
+ sb << " wheel=" << wheel;
+ }
+ return sb.str_moved();
+}
+
+void debugShowInput(bool enableMouse, bool escapeInput) {
+ HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD origConsoleMode = 0;
+ if (!GetConsoleMode(conin, &origConsoleMode)) {
+ fprintf(stderr, "Error: could not read console mode -- "
+ "is STDIN a console handle?\n");
+ exit(1);
+ }
+ DWORD restoreConsoleMode = origConsoleMode;
+ if (enableMouse && !(restoreConsoleMode & ENABLE_EXTENDED_FLAGS)) {
+ // We need to disable QuickEdit mode, because it blocks mouse events.
+ // If ENABLE_EXTENDED_FLAGS wasn't originally in the console mode, then
+ // we have no way of knowning whether QuickEdit or InsertMode are
+ // currently enabled. Enable them both (eventually), because they're
+ // sensible defaults. This case shouldn't happen typically. See
+ // misc/EnableExtendedFlags.txt.
+ restoreConsoleMode |= ENABLE_EXTENDED_FLAGS;
+ restoreConsoleMode |= ENABLE_QUICK_EDIT_MODE;
+ restoreConsoleMode |= ENABLE_INSERT_MODE;
+ }
+ DWORD newConsoleMode = restoreConsoleMode;
+ newConsoleMode &= ~ENABLE_PROCESSED_INPUT;
+ newConsoleMode &= ~ENABLE_LINE_INPUT;
+ newConsoleMode &= ~ENABLE_ECHO_INPUT;
+ newConsoleMode |= ENABLE_WINDOW_INPUT;
+ if (enableMouse) {
+ newConsoleMode |= ENABLE_MOUSE_INPUT;
+ newConsoleMode &= ~ENABLE_QUICK_EDIT_MODE;
+ } else {
+ newConsoleMode &= ~ENABLE_MOUSE_INPUT;
+ }
+ if (escapeInput) {
+ // As of this writing (2016-06-05), Microsoft has shipped two preview
+ // builds of Windows 10 (14316 and 14342) that include a new "Windows
+ // Subsystem for Linux" that runs Ubuntu in a new subsystem. Running
+ // bash in this subsystem requires the non-legacy console mode, and the
+ // console input buffer is put into a special mode where escape
+ // sequences are written into the console input buffer. This mode is
+ // enabled with the 0x200 flag, which is as-yet undocumented.
+ // See https://github.com/rprichard/winpty/issues/82.
+ newConsoleMode |= 0x200;
+ }
+ if (!SetConsoleMode(conin, newConsoleMode)) {
+ fprintf(stderr, "Error: could not set console mode "
+ "(0x%x -> 0x%x -> 0x%x)\n",
+ static_cast<unsigned int>(origConsoleMode),
+ static_cast<unsigned int>(newConsoleMode),
+ static_cast<unsigned int>(restoreConsoleMode));
+ exit(1);
+ }
+ printf("\nPress any keys -- Ctrl-D exits\n\n");
+ INPUT_RECORD records[32];
+ DWORD actual = 0;
+ bool finished = false;
+ while (!finished &&
+ ReadConsoleInputW(conin, records, 32, &actual) && actual >= 1) {
+ StringBuilder sb;
+ for (DWORD i = 0; i < actual; ++i) {
+ const INPUT_RECORD &record = records[i];
+ if (record.EventType == KEY_EVENT) {
+ const KEY_EVENT_RECORD &ker = record.Event.KeyEvent;
+ InputMap::Key key = {
+ ker.wVirtualKeyCode,
+ ker.uChar.UnicodeChar,
+ static_cast<uint16_t>(ker.dwControlKeyState),
+ };
+ sb << "key: " << (ker.bKeyDown ? "dn" : "up")
+ << " rpt=" << ker.wRepeatCount
+ << " scn=" << (ker.wVirtualScanCode ? "0x" : "") << hexOfInt(ker.wVirtualScanCode)
+ << ' ' << key.toString() << '\n';
+ if ((ker.dwControlKeyState &
+ (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
+ ker.wVirtualKeyCode == 'D') {
+ finished = true;
+ break;
+ } else if (ker.wVirtualKeyCode == 0 &&
+ ker.wVirtualScanCode == 0 &&
+ ker.uChar.UnicodeChar == 4) {
+ // Also look for a zeroed-out Ctrl-D record generated for
+ // ENABLE_VIRTUAL_TERMINAL_INPUT.
+ finished = true;
+ break;
+ }
+ } else if (record.EventType == MOUSE_EVENT) {
+ const MOUSE_EVENT_RECORD &mer = record.Event.MouseEvent;
+ sb << "mouse: " << mouseEventToString(mer) << '\n';
+ } else if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ const WINDOW_BUFFER_SIZE_RECORD &wbsr =
+ record.Event.WindowBufferSizeEvent;
+ sb << "buffer-resized: dwSize=("
+ << wbsr.dwSize.X << ','
+ << wbsr.dwSize.Y << ")\n";
+ } else if (record.EventType == MENU_EVENT) {
+ const MENU_EVENT_RECORD &mer = record.Event.MenuEvent;
+ sb << "menu-event: commandId=0x"
+ << hexOfInt(mer.dwCommandId) << '\n';
+ } else if (record.EventType == FOCUS_EVENT) {
+ const FOCUS_EVENT_RECORD &fer = record.Event.FocusEvent;
+ sb << "focus: " << (fer.bSetFocus ? "gained" : "lost") << '\n';
+ }
+ }
+
+ const auto str = sb.str_moved();
+ fwrite(str.data(), 1, str.size(), stdout);
+ fflush(stdout);
+ }
+ SetConsoleMode(conin, restoreConsoleMode);
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h
new file mode 100644
index 0000000000..4fa13604bd
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_DEBUG_SHOW_INPUT_H
+#define AGENT_DEBUG_SHOW_INPUT_H
+
+#include <windows.h>
+
+#include <string>
+
+std::string controlKeyStatePrefix(DWORD controlKeyState);
+std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer);
+void debugShowInput(bool enableMouse, bool escapeInput);
+
+#endif // AGENT_DEBUG_SHOW_INPUT_H
diff --git a/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc
new file mode 100644
index 0000000000..5e29d98e4e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc
@@ -0,0 +1,422 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "DefaultInputMap.h"
+
+#include <windows.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "../shared/StringBuilder.h"
+#include "../shared/WinptyAssert.h"
+#include "InputMap.h"
+
+#define ESC "\x1B"
+#define DIM(x) (sizeof(x) / sizeof((x)[0]))
+
+namespace {
+
+struct EscapeEncoding {
+ bool alt_prefix_allowed;
+ char prefix;
+ char id;
+ int modifiers;
+ InputMap::Key key;
+};
+
+// Modifiers. A "modifier" is an integer from 2 to 8 that conveys the status
+// of Shift(1), Alt(2), and Ctrl(4). The value is constructed by OR'ing the
+// appropriate value for each active modifier, then adding 1.
+//
+// Details:
+// - kBare: expands to: ESC <prefix> <suffix>
+// - kSemiMod: expands to: ESC <prefix> <numid> ; <mod> <suffix>
+// - kBareMod: expands to: ESC <prefix> <mod> <suffix>
+const int kBare = 0x01;
+const int kSemiMod = 0x02;
+const int kBareMod = 0x04;
+
+// Numeric escape sequences suffixes:
+// - with no flag: accept: ~
+// - kSuffixCtrl: accept: ~ ^
+// - kSuffixShift: accept: ~ $
+// - kSuffixBoth: accept: ~ ^ $ @
+const int kSuffixCtrl = 0x08;
+const int kSuffixShift = 0x10;
+const int kSuffixBoth = kSuffixCtrl | kSuffixShift;
+
+static const EscapeEncoding escapeLetterEncodings[] = {
+ // Conventional arrow keys
+ // kBareMod: Ubuntu /etc/inputrc and IntelliJ/JediTerm use escapes like: ESC [ n ABCD
+ { true, '[', 'A', kBare | kBareMod | kSemiMod, { VK_UP, '\0', 0 } },
+ { true, '[', 'B', kBare | kBareMod | kSemiMod, { VK_DOWN, '\0', 0 } },
+ { true, '[', 'C', kBare | kBareMod | kSemiMod, { VK_RIGHT, '\0', 0 } },
+ { true, '[', 'D', kBare | kBareMod | kSemiMod, { VK_LEFT, '\0', 0 } },
+
+ // putty. putty uses this sequence for Ctrl-Arrow, Shift-Arrow, and
+ // Ctrl-Shift-Arrow, but I can only decode to one choice, so I'm just
+ // leaving the modifier off altogether.
+ { true, 'O', 'A', kBare, { VK_UP, '\0', 0 } },
+ { true, 'O', 'B', kBare, { VK_DOWN, '\0', 0 } },
+ { true, 'O', 'C', kBare, { VK_RIGHT, '\0', 0 } },
+ { true, 'O', 'D', kBare, { VK_LEFT, '\0', 0 } },
+
+ // rxvt, rxvt-unicode
+ // Shift-Ctrl-Arrow can't be identified. It's the same as Shift-Arrow.
+ { true, '[', 'a', kBare, { VK_UP, '\0', SHIFT_PRESSED } },
+ { true, '[', 'b', kBare, { VK_DOWN, '\0', SHIFT_PRESSED } },
+ { true, '[', 'c', kBare, { VK_RIGHT, '\0', SHIFT_PRESSED } },
+ { true, '[', 'd', kBare, { VK_LEFT, '\0', SHIFT_PRESSED } },
+ { true, 'O', 'a', kBare, { VK_UP, '\0', LEFT_CTRL_PRESSED } },
+ { true, 'O', 'b', kBare, { VK_DOWN, '\0', LEFT_CTRL_PRESSED } },
+ { true, 'O', 'c', kBare, { VK_RIGHT, '\0', LEFT_CTRL_PRESSED } },
+ { true, 'O', 'd', kBare, { VK_LEFT, '\0', LEFT_CTRL_PRESSED } },
+
+ // Numpad 5 with NumLock off
+ // * xterm, mintty, and gnome-terminal use `ESC [ E`.
+ // * putty, TERM=cygwin, TERM=linux all use `ESC [ G` for 5
+ // * putty uses `ESC O G` for Ctrl-5 and Shift-5. Omit the modifier
+ // as with putty's arrow keys.
+ // * I never saw modifiers inserted into these escapes, but I think
+ // it should be completely OK with the CSI escapes.
+ { true, '[', 'E', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } },
+ { true, '[', 'G', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } },
+ { true, 'O', 'G', kBare, { VK_CLEAR, '\0', 0 } },
+
+ // Home/End, letter version
+ // * gnome-terminal uses `ESC O [HF]`. I never saw it modified.
+ // kBareMod: IntelliJ/JediTerm uses escapes like: ESC [ n HF
+ { true, '[', 'H', kBare | kBareMod | kSemiMod, { VK_HOME, '\0', 0 } },
+ { true, '[', 'F', kBare | kBareMod | kSemiMod, { VK_END, '\0', 0 } },
+ { true, 'O', 'H', kBare, { VK_HOME, '\0', 0 } },
+ { true, 'O', 'F', kBare, { VK_END, '\0', 0 } },
+
+ // F1-F4, letter version (xterm, VTE, konsole)
+ { true, '[', 'P', kSemiMod, { VK_F1, '\0', 0 } },
+ { true, '[', 'Q', kSemiMod, { VK_F2, '\0', 0 } },
+ { true, '[', 'R', kSemiMod, { VK_F3, '\0', 0 } },
+ { true, '[', 'S', kSemiMod, { VK_F4, '\0', 0 } },
+
+ // GNOME VTE and Konsole have special encodings for modified F1-F4:
+ // * [VTE] ESC O 1 ; n [PQRS]
+ // * [Konsole] ESC O n [PQRS]
+ { false, 'O', 'P', kBare | kBareMod | kSemiMod, { VK_F1, '\0', 0 } },
+ { false, 'O', 'Q', kBare | kBareMod | kSemiMod, { VK_F2, '\0', 0 } },
+ { false, 'O', 'R', kBare | kBareMod | kSemiMod, { VK_F3, '\0', 0 } },
+ { false, 'O', 'S', kBare | kBareMod | kSemiMod, { VK_F4, '\0', 0 } },
+
+ // Handle the "application numpad" escape sequences.
+ //
+ // Terminals output these codes under various circumstances:
+ // * rxvt-unicode: numpad, hold down SHIFT
+ // * rxvt: numpad, by default
+ // * xterm: numpad, after enabling app-mode using DECPAM (`ESC =`). xterm
+ // generates `ESC O <mod> <letter>` for modified numpad presses,
+ // necessitating kBareMod.
+ // * mintty: by combining Ctrl with various keys such as '1' or ','.
+ // Handling those keys is difficult, because mintty is generating the
+ // same sequence for Ctrl-1 and Ctrl-NumPadEnd -- should the virtualKey
+ // be '1' or VK_HOME?
+
+ { true, 'O', 'M', kBare | kBareMod, { VK_RETURN, '\r', 0 } },
+ { true, 'O', 'j', kBare | kBareMod, { VK_MULTIPLY, '*', 0 } },
+ { true, 'O', 'k', kBare | kBareMod, { VK_ADD, '+', 0 } },
+ { true, 'O', 'm', kBare | kBareMod, { VK_SUBTRACT, '-', 0 } },
+ { true, 'O', 'n', kBare | kBareMod, { VK_DELETE, '\0', 0 } },
+ { true, 'O', 'o', kBare | kBareMod, { VK_DIVIDE, '/', 0 } },
+ { true, 'O', 'p', kBare | kBareMod, { VK_INSERT, '\0', 0 } },
+ { true, 'O', 'q', kBare | kBareMod, { VK_END, '\0', 0 } },
+ { true, 'O', 'r', kBare | kBareMod, { VK_DOWN, '\0', 0 } },
+ { true, 'O', 's', kBare | kBareMod, { VK_NEXT, '\0', 0 } },
+ { true, 'O', 't', kBare | kBareMod, { VK_LEFT, '\0', 0 } },
+ { true, 'O', 'u', kBare | kBareMod, { VK_CLEAR, '\0', 0 } },
+ { true, 'O', 'v', kBare | kBareMod, { VK_RIGHT, '\0', 0 } },
+ { true, 'O', 'w', kBare | kBareMod, { VK_HOME, '\0', 0 } },
+ { true, 'O', 'x', kBare | kBareMod, { VK_UP, '\0', 0 } },
+ { true, 'O', 'y', kBare | kBareMod, { VK_PRIOR, '\0', 0 } },
+
+ { true, '[', 'M', kBare | kSemiMod, { VK_RETURN, '\r', 0 } },
+ { true, '[', 'j', kBare | kSemiMod, { VK_MULTIPLY, '*', 0 } },
+ { true, '[', 'k', kBare | kSemiMod, { VK_ADD, '+', 0 } },
+ { true, '[', 'm', kBare | kSemiMod, { VK_SUBTRACT, '-', 0 } },
+ { true, '[', 'n', kBare | kSemiMod, { VK_DELETE, '\0', 0 } },
+ { true, '[', 'o', kBare | kSemiMod, { VK_DIVIDE, '/', 0 } },
+ { true, '[', 'p', kBare | kSemiMod, { VK_INSERT, '\0', 0 } },
+ { true, '[', 'q', kBare | kSemiMod, { VK_END, '\0', 0 } },
+ { true, '[', 'r', kBare | kSemiMod, { VK_DOWN, '\0', 0 } },
+ { true, '[', 's', kBare | kSemiMod, { VK_NEXT, '\0', 0 } },
+ { true, '[', 't', kBare | kSemiMod, { VK_LEFT, '\0', 0 } },
+ { true, '[', 'u', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } },
+ { true, '[', 'v', kBare | kSemiMod, { VK_RIGHT, '\0', 0 } },
+ { true, '[', 'w', kBare | kSemiMod, { VK_HOME, '\0', 0 } },
+ { true, '[', 'x', kBare | kSemiMod, { VK_UP, '\0', 0 } },
+ { true, '[', 'y', kBare | kSemiMod, { VK_PRIOR, '\0', 0 } },
+
+ { false, '[', 'Z', kBare, { VK_TAB, '\t', SHIFT_PRESSED } },
+};
+
+static const EscapeEncoding escapeNumericEncodings[] = {
+ { true, '[', 1, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } },
+ { true, '[', 2, kBare | kSemiMod | kSuffixBoth, { VK_INSERT, '\0', 0 } },
+ { true, '[', 3, kBare | kSemiMod | kSuffixBoth, { VK_DELETE, '\0', 0 } },
+ { true, '[', 4, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } },
+ { true, '[', 5, kBare | kSemiMod | kSuffixBoth, { VK_PRIOR, '\0', 0 } },
+ { true, '[', 6, kBare | kSemiMod | kSuffixBoth, { VK_NEXT, '\0', 0 } },
+ { true, '[', 7, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } },
+ { true, '[', 8, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } },
+ { true, '[', 11, kBare | kSemiMod | kSuffixBoth, { VK_F1, '\0', 0 } },
+ { true, '[', 12, kBare | kSemiMod | kSuffixBoth, { VK_F2, '\0', 0 } },
+ { true, '[', 13, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', 0 } },
+ { true, '[', 14, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', 0 } },
+ { true, '[', 15, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', 0 } },
+ { true, '[', 17, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', 0 } },
+ { true, '[', 18, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', 0 } },
+ { true, '[', 19, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', 0 } },
+ { true, '[', 20, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', 0 } },
+ { true, '[', 21, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', 0 } },
+ { true, '[', 23, kBare | kSemiMod | kSuffixBoth, { VK_F11, '\0', 0 } },
+ { true, '[', 24, kBare | kSemiMod | kSuffixBoth, { VK_F12, '\0', 0 } },
+ { true, '[', 25, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', SHIFT_PRESSED } },
+ { true, '[', 26, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', SHIFT_PRESSED } },
+ { true, '[', 28, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', SHIFT_PRESSED } },
+ { true, '[', 29, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', SHIFT_PRESSED } },
+ { true, '[', 31, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', SHIFT_PRESSED } },
+ { true, '[', 32, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', SHIFT_PRESSED } },
+ { true, '[', 33, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', SHIFT_PRESSED } },
+ { true, '[', 34, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', SHIFT_PRESSED } },
+};
+
+const int kCsiShiftModifier = 1;
+const int kCsiAltModifier = 2;
+const int kCsiCtrlModifier = 4;
+
+static inline bool useEnhancedForVirtualKey(uint16_t vk) {
+ switch (vk) {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_HOME:
+ case VK_END:
+ case VK_PRIOR:
+ case VK_NEXT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void addSimpleEntries(InputMap &inputMap) {
+ struct SimpleEncoding {
+ const char *encoding;
+ InputMap::Key key;
+ };
+
+ static const SimpleEncoding simpleEncodings[] = {
+ // Ctrl-<letter/digit> seems to be handled OK by the default code path.
+
+ { "\x7F", { VK_BACK, '\x08', 0, } },
+ { ESC "\x7F", { VK_BACK, '\x08', LEFT_ALT_PRESSED, } },
+ { "\x03", { 'C', '\x03', LEFT_CTRL_PRESSED, } },
+
+ // Handle special F1-F5 for TERM=linux and TERM=cygwin.
+ { ESC "[[A", { VK_F1, '\0', 0 } },
+ { ESC "[[B", { VK_F2, '\0', 0 } },
+ { ESC "[[C", { VK_F3, '\0', 0 } },
+ { ESC "[[D", { VK_F4, '\0', 0 } },
+ { ESC "[[E", { VK_F5, '\0', 0 } },
+
+ { ESC ESC "[[A", { VK_F1, '\0', LEFT_ALT_PRESSED } },
+ { ESC ESC "[[B", { VK_F2, '\0', LEFT_ALT_PRESSED } },
+ { ESC ESC "[[C", { VK_F3, '\0', LEFT_ALT_PRESSED } },
+ { ESC ESC "[[D", { VK_F4, '\0', LEFT_ALT_PRESSED } },
+ { ESC ESC "[[E", { VK_F5, '\0', LEFT_ALT_PRESSED } },
+ };
+
+ for (size_t i = 0; i < DIM(simpleEncodings); ++i) {
+ auto k = simpleEncodings[i].key;
+ if (useEnhancedForVirtualKey(k.virtualKey)) {
+ k.keyState |= ENHANCED_KEY;
+ }
+ inputMap.set(simpleEncodings[i].encoding,
+ strlen(simpleEncodings[i].encoding),
+ k);
+ }
+}
+
+struct ExpandContext {
+ InputMap &inputMap;
+ const EscapeEncoding &e;
+ char *buffer;
+ char *bufferEnd;
+};
+
+static inline void setEncoding(const ExpandContext &ctx, char *end,
+ uint16_t extraKeyState) {
+ InputMap::Key k = ctx.e.key;
+ k.keyState |= extraKeyState;
+ if (k.keyState & LEFT_CTRL_PRESSED) {
+ switch (k.virtualKey) {
+ case VK_ADD:
+ case VK_DIVIDE:
+ case VK_MULTIPLY:
+ case VK_SUBTRACT:
+ k.unicodeChar = '\0';
+ break;
+ case VK_RETURN:
+ k.unicodeChar = '\n';
+ break;
+ }
+ }
+ if (useEnhancedForVirtualKey(k.virtualKey)) {
+ k.keyState |= ENHANCED_KEY;
+ }
+ ctx.inputMap.set(ctx.buffer, end - ctx.buffer, k);
+}
+
+static inline uint16_t keyStateForMod(int mod) {
+ int ret = 0;
+ if ((mod - 1) & kCsiShiftModifier) ret |= SHIFT_PRESSED;
+ if ((mod - 1) & kCsiAltModifier) ret |= LEFT_ALT_PRESSED;
+ if ((mod - 1) & kCsiCtrlModifier) ret |= LEFT_CTRL_PRESSED;
+ return ret;
+}
+
+static void expandNumericEncodingSuffix(const ExpandContext &ctx, char *p,
+ uint16_t extraKeyState) {
+ ASSERT(p <= ctx.bufferEnd - 1);
+ {
+ char *q = p;
+ *q++ = '~';
+ setEncoding(ctx, q, extraKeyState);
+ }
+ if (ctx.e.modifiers & kSuffixShift) {
+ char *q = p;
+ *q++ = '$';
+ setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED);
+ }
+ if (ctx.e.modifiers & kSuffixCtrl) {
+ char *q = p;
+ *q++ = '^';
+ setEncoding(ctx, q, extraKeyState | LEFT_CTRL_PRESSED);
+ }
+ if (ctx.e.modifiers & (kSuffixCtrl | kSuffixShift)) {
+ char *q = p;
+ *q++ = '@';
+ setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED | LEFT_CTRL_PRESSED);
+ }
+}
+
+template <bool is_numeric>
+static inline void expandEncodingAfterAltPrefix(
+ const ExpandContext &ctx, char *p, uint16_t extraKeyState) {
+ auto appendId = [&](char *&ptr) {
+ const auto idstr = decOfInt(ctx.e.id);
+ ASSERT(ptr <= ctx.bufferEnd - idstr.size());
+ std::copy(idstr.data(), idstr.data() + idstr.size(), ptr);
+ ptr += idstr.size();
+ };
+ ASSERT(p <= ctx.bufferEnd - 2);
+ *p++ = '\x1b';
+ *p++ = ctx.e.prefix;
+ if (ctx.e.modifiers & kBare) {
+ char *q = p;
+ if (is_numeric) {
+ appendId(q);
+ expandNumericEncodingSuffix(ctx, q, extraKeyState);
+ } else {
+ ASSERT(q <= ctx.bufferEnd - 1);
+ *q++ = ctx.e.id;
+ setEncoding(ctx, q, extraKeyState);
+ }
+ }
+ if (ctx.e.modifiers & kBareMod) {
+ ASSERT(!is_numeric && "kBareMod is invalid with numeric sequences");
+ for (int mod = 2; mod <= 8; ++mod) {
+ char *q = p;
+ ASSERT(q <= ctx.bufferEnd - 2);
+ *q++ = '0' + mod;
+ *q++ = ctx.e.id;
+ setEncoding(ctx, q, extraKeyState | keyStateForMod(mod));
+ }
+ }
+ if (ctx.e.modifiers & kSemiMod) {
+ for (int mod = 2; mod <= 8; ++mod) {
+ char *q = p;
+ if (is_numeric) {
+ appendId(q);
+ ASSERT(q <= ctx.bufferEnd - 2);
+ *q++ = ';';
+ *q++ = '0' + mod;
+ expandNumericEncodingSuffix(
+ ctx, q, extraKeyState | keyStateForMod(mod));
+ } else {
+ ASSERT(q <= ctx.bufferEnd - 4);
+ *q++ = '1';
+ *q++ = ';';
+ *q++ = '0' + mod;
+ *q++ = ctx.e.id;
+ setEncoding(ctx, q, extraKeyState | keyStateForMod(mod));
+ }
+ }
+ }
+}
+
+template <bool is_numeric>
+static inline void expandEncoding(const ExpandContext &ctx) {
+ if (ctx.e.alt_prefix_allowed) {
+ // For better or for worse, this code expands all of:
+ // * ESC [ <key> -- <key>
+ // * ESC ESC [ <key> -- Alt-<key>
+ // * ESC [ 1 ; 3 <key> -- Alt-<key>
+ // * ESC ESC [ 1 ; 3 <key> -- Alt-<key> specified twice
+ // I suspect no terminal actually emits the last one (i.e. specifying
+ // the Alt modifier using both methods), but I have seen a terminal
+ // that emitted a prefix ESC for Alt and a non-Alt modifier.
+ char *p = ctx.buffer;
+ ASSERT(p <= ctx.bufferEnd - 1);
+ *p++ = '\x1b';
+ expandEncodingAfterAltPrefix<is_numeric>(ctx, p, LEFT_ALT_PRESSED);
+ }
+ expandEncodingAfterAltPrefix<is_numeric>(ctx, ctx.buffer, 0);
+}
+
+template <bool is_numeric, size_t N>
+static void addEscapes(InputMap &inputMap, const EscapeEncoding (&encodings)[N]) {
+ char buffer[32];
+ for (size_t i = 0; i < DIM(encodings); ++i) {
+ ExpandContext ctx = {
+ inputMap, encodings[i],
+ buffer, buffer + sizeof(buffer)
+ };
+ expandEncoding<is_numeric>(ctx);
+ }
+}
+
+} // anonymous namespace
+
+void addDefaultEntriesToInputMap(InputMap &inputMap) {
+ addEscapes<false>(inputMap, escapeLetterEncodings);
+ addEscapes<true>(inputMap, escapeNumericEncodings);
+ addSimpleEntries(inputMap);
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h
new file mode 100644
index 0000000000..c4b9083678
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef DEFAULT_INPUT_MAP_H
+#define DEFAULT_INPUT_MAP_H
+
+class InputMap;
+
+void addDefaultEntriesToInputMap(InputMap &inputMap);
+
+#endif // DEFAULT_INPUT_MAP_H
diff --git a/src/libs/3rdparty/winpty/src/agent/DsrSender.h b/src/libs/3rdparty/winpty/src/agent/DsrSender.h
new file mode 100644
index 0000000000..1ec0a97d2e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DsrSender.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef DSRSENDER_H
+#define DSRSENDER_H
+
+class DsrSender
+{
+public:
+ virtual void sendDsr() = 0;
+};
+
+#endif // DSRSENDER_H
diff --git a/src/libs/3rdparty/winpty/src/agent/EventLoop.cc b/src/libs/3rdparty/winpty/src/agent/EventLoop.cc
new file mode 100644
index 0000000000..ba5cf18cc8
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/EventLoop.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "EventLoop.h"
+
+#include <algorithm>
+
+#include "NamedPipe.h"
+#include "../shared/DebugClient.h"
+#include "../shared/WinptyAssert.h"
+
+EventLoop::~EventLoop() {
+ for (NamedPipe *pipe : m_pipes) {
+ delete pipe;
+ }
+ m_pipes.clear();
+}
+
+// Enter the event loop. Runs until the I/O or timeout handler calls exit().
+void EventLoop::run()
+{
+ std::vector<HANDLE> waitHandles;
+ DWORD lastTime = GetTickCount();
+ while (!m_exiting) {
+ bool didSomething = false;
+
+ // Attempt to make progress with the pipes.
+ waitHandles.clear();
+ for (size_t i = 0; i < m_pipes.size(); ++i) {
+ if (m_pipes[i]->serviceIo(&waitHandles)) {
+ onPipeIo(*m_pipes[i]);
+ didSomething = true;
+ }
+ }
+
+ // Call the timeout if enough time has elapsed.
+ if (m_pollInterval > 0) {
+ int elapsed = GetTickCount() - lastTime;
+ if (elapsed >= m_pollInterval) {
+ onPollTimeout();
+ lastTime = GetTickCount();
+ didSomething = true;
+ }
+ }
+
+ if (didSomething)
+ continue;
+
+ // If there's nothing to do, wait.
+ DWORD timeout = INFINITE;
+ if (m_pollInterval > 0)
+ timeout = std::max(0, (int)(lastTime + m_pollInterval - GetTickCount()));
+ if (waitHandles.size() == 0) {
+ ASSERT(timeout != INFINITE);
+ if (timeout > 0)
+ Sleep(timeout);
+ } else {
+ DWORD result = WaitForMultipleObjects(waitHandles.size(),
+ waitHandles.data(),
+ FALSE,
+ timeout);
+ ASSERT(result != WAIT_FAILED);
+ }
+ }
+}
+
+NamedPipe &EventLoop::createNamedPipe()
+{
+ NamedPipe *ret = new NamedPipe();
+ m_pipes.push_back(ret);
+ return *ret;
+}
+
+void EventLoop::setPollInterval(int ms)
+{
+ m_pollInterval = ms;
+}
+
+void EventLoop::shutdown()
+{
+ m_exiting = true;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/EventLoop.h b/src/libs/3rdparty/winpty/src/agent/EventLoop.h
new file mode 100644
index 0000000000..eddb0f6267
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/EventLoop.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef EVENTLOOP_H
+#define EVENTLOOP_H
+
+#include <vector>
+
+class NamedPipe;
+
+class EventLoop
+{
+public:
+ virtual ~EventLoop();
+ void run();
+
+protected:
+ NamedPipe &createNamedPipe();
+ void setPollInterval(int ms);
+ void shutdown();
+ virtual void onPollTimeout() {}
+ virtual void onPipeIo(NamedPipe &namedPipe) {}
+
+private:
+ bool m_exiting = false;
+ std::vector<NamedPipe*> m_pipes;
+ int m_pollInterval = 0;
+};
+
+#endif // EVENTLOOP_H
diff --git a/src/libs/3rdparty/winpty/src/agent/InputMap.cc b/src/libs/3rdparty/winpty/src/agent/InputMap.cc
new file mode 100644
index 0000000000..b1fbfc2e30
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/InputMap.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "InputMap.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "DebugShowInput.h"
+#include "SimplePool.h"
+#include "../shared/DebugClient.h"
+#include "../shared/UnixCtrlChars.h"
+#include "../shared/WinptyAssert.h"
+#include "../shared/winpty_snprintf.h"
+
+namespace {
+
+static const char *getVirtualKeyString(int virtualKey)
+{
+ switch (virtualKey) {
+#define WINPTY_GVKS_KEY(x) case VK_##x: return #x;
+ WINPTY_GVKS_KEY(RBUTTON) WINPTY_GVKS_KEY(F9)
+ WINPTY_GVKS_KEY(CANCEL) WINPTY_GVKS_KEY(F10)
+ WINPTY_GVKS_KEY(MBUTTON) WINPTY_GVKS_KEY(F11)
+ WINPTY_GVKS_KEY(XBUTTON1) WINPTY_GVKS_KEY(F12)
+ WINPTY_GVKS_KEY(XBUTTON2) WINPTY_GVKS_KEY(F13)
+ WINPTY_GVKS_KEY(BACK) WINPTY_GVKS_KEY(F14)
+ WINPTY_GVKS_KEY(TAB) WINPTY_GVKS_KEY(F15)
+ WINPTY_GVKS_KEY(CLEAR) WINPTY_GVKS_KEY(F16)
+ WINPTY_GVKS_KEY(RETURN) WINPTY_GVKS_KEY(F17)
+ WINPTY_GVKS_KEY(SHIFT) WINPTY_GVKS_KEY(F18)
+ WINPTY_GVKS_KEY(CONTROL) WINPTY_GVKS_KEY(F19)
+ WINPTY_GVKS_KEY(MENU) WINPTY_GVKS_KEY(F20)
+ WINPTY_GVKS_KEY(PAUSE) WINPTY_GVKS_KEY(F21)
+ WINPTY_GVKS_KEY(CAPITAL) WINPTY_GVKS_KEY(F22)
+ WINPTY_GVKS_KEY(HANGUL) WINPTY_GVKS_KEY(F23)
+ WINPTY_GVKS_KEY(JUNJA) WINPTY_GVKS_KEY(F24)
+ WINPTY_GVKS_KEY(FINAL) WINPTY_GVKS_KEY(NUMLOCK)
+ WINPTY_GVKS_KEY(KANJI) WINPTY_GVKS_KEY(SCROLL)
+ WINPTY_GVKS_KEY(ESCAPE) WINPTY_GVKS_KEY(LSHIFT)
+ WINPTY_GVKS_KEY(CONVERT) WINPTY_GVKS_KEY(RSHIFT)
+ WINPTY_GVKS_KEY(NONCONVERT) WINPTY_GVKS_KEY(LCONTROL)
+ WINPTY_GVKS_KEY(ACCEPT) WINPTY_GVKS_KEY(RCONTROL)
+ WINPTY_GVKS_KEY(MODECHANGE) WINPTY_GVKS_KEY(LMENU)
+ WINPTY_GVKS_KEY(SPACE) WINPTY_GVKS_KEY(RMENU)
+ WINPTY_GVKS_KEY(PRIOR) WINPTY_GVKS_KEY(BROWSER_BACK)
+ WINPTY_GVKS_KEY(NEXT) WINPTY_GVKS_KEY(BROWSER_FORWARD)
+ WINPTY_GVKS_KEY(END) WINPTY_GVKS_KEY(BROWSER_REFRESH)
+ WINPTY_GVKS_KEY(HOME) WINPTY_GVKS_KEY(BROWSER_STOP)
+ WINPTY_GVKS_KEY(LEFT) WINPTY_GVKS_KEY(BROWSER_SEARCH)
+ WINPTY_GVKS_KEY(UP) WINPTY_GVKS_KEY(BROWSER_FAVORITES)
+ WINPTY_GVKS_KEY(RIGHT) WINPTY_GVKS_KEY(BROWSER_HOME)
+ WINPTY_GVKS_KEY(DOWN) WINPTY_GVKS_KEY(VOLUME_MUTE)
+ WINPTY_GVKS_KEY(SELECT) WINPTY_GVKS_KEY(VOLUME_DOWN)
+ WINPTY_GVKS_KEY(PRINT) WINPTY_GVKS_KEY(VOLUME_UP)
+ WINPTY_GVKS_KEY(EXECUTE) WINPTY_GVKS_KEY(MEDIA_NEXT_TRACK)
+ WINPTY_GVKS_KEY(SNAPSHOT) WINPTY_GVKS_KEY(MEDIA_PREV_TRACK)
+ WINPTY_GVKS_KEY(INSERT) WINPTY_GVKS_KEY(MEDIA_STOP)
+ WINPTY_GVKS_KEY(DELETE) WINPTY_GVKS_KEY(MEDIA_PLAY_PAUSE)
+ WINPTY_GVKS_KEY(HELP) WINPTY_GVKS_KEY(LAUNCH_MAIL)
+ WINPTY_GVKS_KEY(LWIN) WINPTY_GVKS_KEY(LAUNCH_MEDIA_SELECT)
+ WINPTY_GVKS_KEY(RWIN) WINPTY_GVKS_KEY(LAUNCH_APP1)
+ WINPTY_GVKS_KEY(APPS) WINPTY_GVKS_KEY(LAUNCH_APP2)
+ WINPTY_GVKS_KEY(SLEEP) WINPTY_GVKS_KEY(OEM_1)
+ WINPTY_GVKS_KEY(NUMPAD0) WINPTY_GVKS_KEY(OEM_PLUS)
+ WINPTY_GVKS_KEY(NUMPAD1) WINPTY_GVKS_KEY(OEM_COMMA)
+ WINPTY_GVKS_KEY(NUMPAD2) WINPTY_GVKS_KEY(OEM_MINUS)
+ WINPTY_GVKS_KEY(NUMPAD3) WINPTY_GVKS_KEY(OEM_PERIOD)
+ WINPTY_GVKS_KEY(NUMPAD4) WINPTY_GVKS_KEY(OEM_2)
+ WINPTY_GVKS_KEY(NUMPAD5) WINPTY_GVKS_KEY(OEM_3)
+ WINPTY_GVKS_KEY(NUMPAD6) WINPTY_GVKS_KEY(OEM_4)
+ WINPTY_GVKS_KEY(NUMPAD7) WINPTY_GVKS_KEY(OEM_5)
+ WINPTY_GVKS_KEY(NUMPAD8) WINPTY_GVKS_KEY(OEM_6)
+ WINPTY_GVKS_KEY(NUMPAD9) WINPTY_GVKS_KEY(OEM_7)
+ WINPTY_GVKS_KEY(MULTIPLY) WINPTY_GVKS_KEY(OEM_8)
+ WINPTY_GVKS_KEY(ADD) WINPTY_GVKS_KEY(OEM_102)
+ WINPTY_GVKS_KEY(SEPARATOR) WINPTY_GVKS_KEY(PROCESSKEY)
+ WINPTY_GVKS_KEY(SUBTRACT) WINPTY_GVKS_KEY(PACKET)
+ WINPTY_GVKS_KEY(DECIMAL) WINPTY_GVKS_KEY(ATTN)
+ WINPTY_GVKS_KEY(DIVIDE) WINPTY_GVKS_KEY(CRSEL)
+ WINPTY_GVKS_KEY(F1) WINPTY_GVKS_KEY(EXSEL)
+ WINPTY_GVKS_KEY(F2) WINPTY_GVKS_KEY(EREOF)
+ WINPTY_GVKS_KEY(F3) WINPTY_GVKS_KEY(PLAY)
+ WINPTY_GVKS_KEY(F4) WINPTY_GVKS_KEY(ZOOM)
+ WINPTY_GVKS_KEY(F5) WINPTY_GVKS_KEY(NONAME)
+ WINPTY_GVKS_KEY(F6) WINPTY_GVKS_KEY(PA1)
+ WINPTY_GVKS_KEY(F7) WINPTY_GVKS_KEY(OEM_CLEAR)
+ WINPTY_GVKS_KEY(F8)
+#undef WINPTY_GVKS_KEY
+ default: return NULL;
+ }
+}
+
+} // anonymous namespace
+
+std::string InputMap::Key::toString() const {
+ std::string ret;
+ ret += controlKeyStatePrefix(keyState);
+ char buf[256];
+ const char *vkString = getVirtualKeyString(virtualKey);
+ if (vkString != NULL) {
+ ret += vkString;
+ } else if ((virtualKey >= 'A' && virtualKey <= 'Z') ||
+ (virtualKey >= '0' && virtualKey <= '9')) {
+ ret += static_cast<char>(virtualKey);
+ } else {
+ winpty_snprintf(buf, "%#x", virtualKey);
+ ret += buf;
+ }
+ if (unicodeChar >= 32 && unicodeChar <= 126) {
+ winpty_snprintf(buf, " ch='%c'",
+ static_cast<char>(unicodeChar));
+ } else {
+ winpty_snprintf(buf, " ch=%#x",
+ static_cast<unsigned int>(unicodeChar));
+ }
+ ret += buf;
+ return ret;
+}
+
+void InputMap::set(const char *encoding, int encodingLen, const Key &key) {
+ ASSERT(encodingLen > 0);
+ setHelper(m_root, encoding, encodingLen, key);
+}
+
+void InputMap::setHelper(Node &node, const char *encoding, int encodingLen, const Key &key) {
+ if (encodingLen == 0) {
+ node.key = key;
+ } else {
+ setHelper(getOrCreateChild(node, encoding[0]), encoding + 1, encodingLen - 1, key);
+ }
+}
+
+InputMap::Node &InputMap::getOrCreateChild(Node &node, unsigned char ch) {
+ Node *ret = getChild(node, ch);
+ if (ret != NULL) {
+ return *ret;
+ }
+ if (node.childCount < Node::kTinyCount) {
+ // Maintain sorted order for the sake of the InputMap dumping.
+ int insertIndex = node.childCount;
+ for (int i = 0; i < node.childCount; ++i) {
+ if (ch < node.u.tiny.values[i]) {
+ insertIndex = i;
+ break;
+ }
+ }
+ for (int j = node.childCount; j > insertIndex; --j) {
+ node.u.tiny.values[j] = node.u.tiny.values[j - 1];
+ node.u.tiny.children[j] = node.u.tiny.children[j - 1];
+ }
+ node.u.tiny.values[insertIndex] = ch;
+ node.u.tiny.children[insertIndex] = ret = m_nodePool.alloc();
+ ++node.childCount;
+ return *ret;
+ }
+ if (node.childCount == Node::kTinyCount) {
+ Branch *branch = m_branchPool.alloc();
+ for (int i = 0; i < node.childCount; ++i) {
+ branch->children[node.u.tiny.values[i]] = node.u.tiny.children[i];
+ }
+ node.u.branch = branch;
+ }
+ node.u.branch->children[ch] = ret = m_nodePool.alloc();
+ ++node.childCount;
+ return *ret;
+}
+
+// Find the longest matching key and node.
+int InputMap::lookupKey(const char *input, int inputSize,
+ Key &keyOut, bool &incompleteOut) const {
+ keyOut = kKeyZero;
+ incompleteOut = false;
+
+ const Node *node = &m_root;
+ InputMap::Key longestMatch = kKeyZero;
+ int longestMatchLen = 0;
+
+ for (int i = 0; i < inputSize; ++i) {
+ unsigned char ch = input[i];
+ node = getChild(*node, ch);
+ if (node == NULL) {
+ keyOut = longestMatch;
+ return longestMatchLen;
+ } else if (node->hasKey()) {
+ longestMatchLen = i + 1;
+ longestMatch = node->key;
+ }
+ }
+ keyOut = longestMatch;
+ incompleteOut = node->childCount > 0;
+ return longestMatchLen;
+}
+
+void InputMap::dumpInputMap() const {
+ std::string encoding;
+ dumpInputMapHelper(m_root, encoding);
+}
+
+void InputMap::dumpInputMapHelper(
+ const Node &node, std::string &encoding) const {
+ if (node.hasKey()) {
+ trace("%s -> %s",
+ encoding.c_str(),
+ node.key.toString().c_str());
+ }
+ for (int i = 0; i < 256; ++i) {
+ const Node *child = getChild(node, i);
+ if (child != NULL) {
+ size_t oldSize = encoding.size();
+ if (!encoding.empty()) {
+ encoding.push_back(' ');
+ }
+ char ctrlChar = decodeUnixCtrlChar(i);
+ if (ctrlChar != '\0') {
+ encoding.push_back('^');
+ encoding.push_back(static_cast<char>(ctrlChar));
+ } else if (i == ' ') {
+ encoding.append("' '");
+ } else {
+ encoding.push_back(static_cast<char>(i));
+ }
+ dumpInputMapHelper(*child, encoding);
+ encoding.resize(oldSize);
+ }
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/InputMap.h b/src/libs/3rdparty/winpty/src/agent/InputMap.h
new file mode 100644
index 0000000000..9a666c7976
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/InputMap.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef INPUT_MAP_H
+#define INPUT_MAP_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+
+#include "SimplePool.h"
+#include "../shared/WinptyAssert.h"
+
+class InputMap {
+public:
+ struct Key {
+ uint16_t virtualKey;
+ uint32_t unicodeChar;
+ uint16_t keyState;
+
+ std::string toString() const;
+ };
+
+private:
+ struct Node;
+
+ struct Branch {
+ Branch() {
+ memset(&children, 0, sizeof(children));
+ }
+
+ Node *children[256];
+ };
+
+ struct Node {
+ Node() : childCount(0) {
+ Key zeroKey = { 0, 0, 0 };
+ key = zeroKey;
+ }
+
+ Key key;
+ int childCount;
+ enum { kTinyCount = 8 };
+ union {
+ Branch *branch;
+ struct {
+ unsigned char values[kTinyCount];
+ Node *children[kTinyCount];
+ } tiny;
+ } u;
+
+ bool hasKey() const {
+ return key.virtualKey != 0 || key.unicodeChar != 0;
+ }
+ };
+
+private:
+ SimplePool<Node, 256> m_nodePool;
+ SimplePool<Branch, 8> m_branchPool;
+ Node m_root;
+
+public:
+ void set(const char *encoding, int encodingLen, const Key &key);
+ int lookupKey(const char *input, int inputSize,
+ Key &keyOut, bool &incompleteOut) const;
+ void dumpInputMap() const;
+
+private:
+ Node *getChild(Node &node, unsigned char ch) {
+ return const_cast<Node*>(getChild(static_cast<const Node&>(node), ch));
+ }
+
+ const Node *getChild(const Node &node, unsigned char ch) const {
+ if (node.childCount <= Node::kTinyCount) {
+ for (int i = 0; i < node.childCount; ++i) {
+ if (node.u.tiny.values[i] == ch) {
+ return node.u.tiny.children[i];
+ }
+ }
+ return NULL;
+ } else {
+ return node.u.branch->children[ch];
+ }
+ }
+
+ void setHelper(Node &node, const char *encoding, int encodingLen, const Key &key);
+ Node &getOrCreateChild(Node &node, unsigned char ch);
+ void dumpInputMapHelper(const Node &node, std::string &encoding) const;
+};
+
+const InputMap::Key kKeyZero = { 0, 0, 0 };
+
+void dumpInputMap(InputMap &inputMap);
+
+#endif // INPUT_MAP_H
diff --git a/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc
new file mode 100644
index 0000000000..80ac640e48
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "LargeConsoleRead.h"
+
+#include <stdlib.h>
+
+#include "../shared/WindowsVersion.h"
+#include "Scraper.h"
+#include "Win32ConsoleBuffer.h"
+
+LargeConsoleReadBuffer::LargeConsoleReadBuffer() :
+ m_rect(0, 0, 0, 0), m_rectWidth(0)
+{
+}
+
+void largeConsoleRead(LargeConsoleReadBuffer &out,
+ Win32ConsoleBuffer &buffer,
+ const SmallRect &readArea,
+ WORD attributesMask) {
+ ASSERT(readArea.Left >= 0 &&
+ readArea.Top >= 0 &&
+ readArea.Right >= readArea.Left &&
+ readArea.Bottom >= readArea.Top &&
+ readArea.width() <= MAX_CONSOLE_WIDTH);
+ const size_t count = readArea.width() * readArea.height();
+ if (out.m_data.size() < count) {
+ out.m_data.resize(count);
+ }
+ out.m_rect = readArea;
+ out.m_rectWidth = readArea.width();
+
+ static const bool useLargeReads = isAtLeastWindows8();
+ if (useLargeReads) {
+ buffer.read(readArea, out.m_data.data());
+ } else {
+ const int maxReadLines = std::max(1, MAX_CONSOLE_WIDTH / readArea.width());
+ int curLine = readArea.Top;
+ while (curLine <= readArea.Bottom) {
+ const SmallRect subReadArea(
+ readArea.Left,
+ curLine,
+ readArea.width(),
+ std::min(maxReadLines, readArea.Bottom + 1 - curLine));
+ buffer.read(subReadArea, out.lineDataMut(curLine));
+ curLine = subReadArea.Bottom + 1;
+ }
+ }
+ if (attributesMask != static_cast<WORD>(~0)) {
+ for (size_t i = 0; i < count; ++i) {
+ out.m_data[i].Attributes &= attributesMask;
+ }
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h
new file mode 100644
index 0000000000..1bcf2c0232
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LARGE_CONSOLE_READ_H
+#define LARGE_CONSOLE_READ_H
+
+#include <windows.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "SmallRect.h"
+#include "../shared/DebugClient.h"
+#include "../shared/WinptyAssert.h"
+
+class Win32ConsoleBuffer;
+
+class LargeConsoleReadBuffer {
+public:
+ LargeConsoleReadBuffer();
+ const SmallRect &rect() const { return m_rect; }
+ const CHAR_INFO *lineData(int line) const {
+ validateLineNumber(line);
+ return &m_data[(line - m_rect.Top) * m_rectWidth];
+ }
+
+private:
+ CHAR_INFO *lineDataMut(int line) {
+ validateLineNumber(line);
+ return &m_data[(line - m_rect.Top) * m_rectWidth];
+ }
+
+ void validateLineNumber(int line) const {
+ if (line < m_rect.Top || line > m_rect.Bottom) {
+ trace("Fatal error: LargeConsoleReadBuffer: invalid line %d for "
+ "read rect %s", line, m_rect.toString().c_str());
+ abort();
+ }
+ }
+
+ SmallRect m_rect;
+ int m_rectWidth;
+ std::vector<CHAR_INFO> m_data;
+
+ friend void largeConsoleRead(LargeConsoleReadBuffer &out,
+ Win32ConsoleBuffer &buffer,
+ const SmallRect &readArea,
+ WORD attributesMask);
+};
+
+#endif // LARGE_CONSOLE_READ_H
diff --git a/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc b/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc
new file mode 100644
index 0000000000..64044e6e5d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "EventLoop.h"
+#include "NamedPipe.h"
+#include "../shared/DebugClient.h"
+#include "../shared/StringUtil.h"
+#include "../shared/WindowsSecurity.h"
+#include "../shared/WinptyAssert.h"
+
+// Returns true if anything happens (data received, data sent, pipe error).
+bool NamedPipe::serviceIo(std::vector<HANDLE> *waitHandles)
+{
+ bool justConnected = false;
+ const auto kError = ServiceResult::Error;
+ const auto kProgress = ServiceResult::Progress;
+ const auto kNoProgress = ServiceResult::NoProgress;
+ if (m_handle == NULL) {
+ return false;
+ }
+ if (m_connectEvent.get() != nullptr) {
+ // We're still connecting this server pipe. Check whether the pipe is
+ // now connected. If it isn't, add the pipe to the list of handles to
+ // wait on.
+ DWORD actual = 0;
+ BOOL success =
+ GetOverlappedResult(m_handle, &m_connectOver, &actual, FALSE);
+ if (!success && GetLastError() == ERROR_PIPE_CONNECTED) {
+ // I'm not sure this can happen, but it's easy to handle if it
+ // does.
+ success = TRUE;
+ }
+ if (!success) {
+ ASSERT(GetLastError() == ERROR_IO_INCOMPLETE &&
+ "Pended ConnectNamedPipe call failed");
+ waitHandles->push_back(m_connectEvent.get());
+ } else {
+ TRACE("Server pipe [%s] connected",
+ utf8FromWide(m_name).c_str());
+ m_connectEvent.dispose();
+ startPipeWorkers();
+ justConnected = true;
+ }
+ }
+ const auto readProgress = m_inputWorker ? m_inputWorker->service() : kNoProgress;
+ const auto writeProgress = m_outputWorker ? m_outputWorker->service() : kNoProgress;
+ if (readProgress == kError || writeProgress == kError) {
+ closePipe();
+ return true;
+ }
+ if (m_inputWorker && m_inputWorker->getWaitEvent() != nullptr) {
+ waitHandles->push_back(m_inputWorker->getWaitEvent());
+ }
+ if (m_outputWorker && m_outputWorker->getWaitEvent() != nullptr) {
+ waitHandles->push_back(m_outputWorker->getWaitEvent());
+ }
+ return justConnected
+ || readProgress == kProgress
+ || writeProgress == kProgress;
+}
+
+// manual reset, initially unset
+static OwnedHandle createEvent() {
+ HANDLE ret = CreateEventW(nullptr, TRUE, FALSE, nullptr);
+ ASSERT(ret != nullptr && "CreateEventW failed");
+ return OwnedHandle(ret);
+}
+
+NamedPipe::IoWorker::IoWorker(NamedPipe &namedPipe) :
+ m_namedPipe(namedPipe),
+ m_event(createEvent())
+{
+}
+
+NamedPipe::ServiceResult NamedPipe::IoWorker::service()
+{
+ ServiceResult progress = ServiceResult::NoProgress;
+ if (m_pending) {
+ DWORD actual = 0;
+ BOOL ret = GetOverlappedResult(m_namedPipe.m_handle, &m_over, &actual, FALSE);
+ if (!ret) {
+ if (GetLastError() == ERROR_IO_INCOMPLETE) {
+ // There is a pending I/O.
+ return progress;
+ } else {
+ // Pipe error.
+ return ServiceResult::Error;
+ }
+ }
+ ResetEvent(m_event.get());
+ m_pending = false;
+ completeIo(actual);
+ m_currentIoSize = 0;
+ progress = ServiceResult::Progress;
+ }
+ DWORD nextSize = 0;
+ bool isRead = false;
+ while (shouldIssueIo(&nextSize, &isRead)) {
+ m_currentIoSize = nextSize;
+ DWORD actual = 0;
+ memset(&m_over, 0, sizeof(m_over));
+ m_over.hEvent = m_event.get();
+ BOOL ret = isRead
+ ? ReadFile(m_namedPipe.m_handle, m_buffer, nextSize, &actual, &m_over)
+ : WriteFile(m_namedPipe.m_handle, m_buffer, nextSize, &actual, &m_over);
+ if (!ret) {
+ if (GetLastError() == ERROR_IO_PENDING) {
+ // There is a pending I/O.
+ m_pending = true;
+ return progress;
+ } else {
+ // Pipe error.
+ return ServiceResult::Error;
+ }
+ }
+ ResetEvent(m_event.get());
+ completeIo(actual);
+ m_currentIoSize = 0;
+ progress = ServiceResult::Progress;
+ }
+ return progress;
+}
+
+// This function is called after CancelIo has returned. We need to block until
+// the I/O operations have completed, which should happen very quickly.
+// https://blogs.msdn.microsoft.com/oldnewthing/20110202-00/?p=11613
+void NamedPipe::IoWorker::waitForCanceledIo()
+{
+ if (m_pending) {
+ DWORD actual = 0;
+ GetOverlappedResult(m_namedPipe.m_handle, &m_over, &actual, TRUE);
+ m_pending = false;
+ }
+}
+
+HANDLE NamedPipe::IoWorker::getWaitEvent()
+{
+ return m_pending ? m_event.get() : NULL;
+}
+
+void NamedPipe::InputWorker::completeIo(DWORD size)
+{
+ m_namedPipe.m_inQueue.append(m_buffer, size);
+}
+
+bool NamedPipe::InputWorker::shouldIssueIo(DWORD *size, bool *isRead)
+{
+ *isRead = true;
+ ASSERT(!m_namedPipe.isConnecting());
+ if (m_namedPipe.isClosed()) {
+ return false;
+ } else if (m_namedPipe.m_inQueue.size() < m_namedPipe.readBufferSize()) {
+ *size = kIoSize;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void NamedPipe::OutputWorker::completeIo(DWORD size)
+{
+ ASSERT(size == m_currentIoSize);
+}
+
+bool NamedPipe::OutputWorker::shouldIssueIo(DWORD *size, bool *isRead)
+{
+ *isRead = false;
+ if (!m_namedPipe.m_outQueue.empty()) {
+ auto &out = m_namedPipe.m_outQueue;
+ const DWORD writeSize = std::min<size_t>(out.size(), kIoSize);
+ std::copy(&out[0], &out[writeSize], m_buffer);
+ out.erase(0, writeSize);
+ *size = writeSize;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+DWORD NamedPipe::OutputWorker::getPendingIoSize()
+{
+ return m_pending ? m_currentIoSize : 0;
+}
+
+void NamedPipe::openServerPipe(LPCWSTR pipeName, OpenMode::t openMode,
+ int outBufferSize, int inBufferSize) {
+ ASSERT(isClosed());
+ ASSERT((openMode & OpenMode::Duplex) != 0);
+ const DWORD winOpenMode =
+ ((openMode & OpenMode::Reading) ? PIPE_ACCESS_INBOUND : 0)
+ | ((openMode & OpenMode::Writing) ? PIPE_ACCESS_OUTBOUND : 0)
+ | FILE_FLAG_FIRST_PIPE_INSTANCE
+ | FILE_FLAG_OVERLAPPED;
+ const auto sd = createPipeSecurityDescriptorOwnerFullControl();
+ ASSERT(sd && "error creating data pipe SECURITY_DESCRIPTOR");
+ SECURITY_ATTRIBUTES sa = {};
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = sd.get();
+ HANDLE handle = CreateNamedPipeW(
+ pipeName,
+ /*dwOpenMode=*/winOpenMode,
+ /*dwPipeMode=*/rejectRemoteClientsPipeFlag(),
+ /*nMaxInstances=*/1,
+ /*nOutBufferSize=*/outBufferSize,
+ /*nInBufferSize=*/inBufferSize,
+ /*nDefaultTimeOut=*/30000,
+ &sa);
+ TRACE("opened server pipe [%s], handle == %p",
+ utf8FromWide(pipeName).c_str(), handle);
+ ASSERT(handle != INVALID_HANDLE_VALUE && "Could not open server pipe");
+ m_name = pipeName;
+ m_handle = handle;
+ m_openMode = openMode;
+
+ // Start an asynchronous connection attempt.
+ m_connectEvent = createEvent();
+ memset(&m_connectOver, 0, sizeof(m_connectOver));
+ m_connectOver.hEvent = m_connectEvent.get();
+ BOOL success = ConnectNamedPipe(m_handle, &m_connectOver);
+ const auto err = GetLastError();
+ if (!success && err == ERROR_PIPE_CONNECTED) {
+ success = TRUE;
+ }
+ if (success) {
+ TRACE("Server pipe [%s] connected", utf8FromWide(pipeName).c_str());
+ m_connectEvent.dispose();
+ startPipeWorkers();
+ } else if (err != ERROR_IO_PENDING) {
+ ASSERT(false && "ConnectNamedPipe call failed");
+ }
+}
+
+void NamedPipe::connectToServer(LPCWSTR pipeName, OpenMode::t openMode)
+{
+ ASSERT(isClosed());
+ ASSERT((openMode & OpenMode::Duplex) != 0);
+ HANDLE handle = CreateFileW(
+ pipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION | FILE_FLAG_OVERLAPPED,
+ NULL);
+ TRACE("connected to [%s], handle == %p",
+ utf8FromWide(pipeName).c_str(), handle);
+ ASSERT(handle != INVALID_HANDLE_VALUE && "Could not connect to pipe");
+ m_name = pipeName;
+ m_handle = handle;
+ m_openMode = openMode;
+ startPipeWorkers();
+}
+
+void NamedPipe::startPipeWorkers()
+{
+ if (m_openMode & OpenMode::Reading) {
+ m_inputWorker.reset(new InputWorker(*this));
+ }
+ if (m_openMode & OpenMode::Writing) {
+ m_outputWorker.reset(new OutputWorker(*this));
+ }
+}
+
+size_t NamedPipe::bytesToSend()
+{
+ ASSERT(m_openMode & OpenMode::Writing);
+ auto ret = m_outQueue.size();
+ if (m_outputWorker != NULL) {
+ ret += m_outputWorker->getPendingIoSize();
+ }
+ return ret;
+}
+
+void NamedPipe::write(const void *data, size_t size)
+{
+ ASSERT(m_openMode & OpenMode::Writing);
+ m_outQueue.append(reinterpret_cast<const char*>(data), size);
+}
+
+void NamedPipe::write(const char *text)
+{
+ write(text, strlen(text));
+}
+
+size_t NamedPipe::readBufferSize()
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ return m_readBufferSize;
+}
+
+void NamedPipe::setReadBufferSize(size_t size)
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ m_readBufferSize = size;
+}
+
+size_t NamedPipe::bytesAvailable()
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ return m_inQueue.size();
+}
+
+size_t NamedPipe::peek(void *data, size_t size)
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ const auto out = reinterpret_cast<char*>(data);
+ const size_t ret = std::min(size, m_inQueue.size());
+ std::copy(&m_inQueue[0], &m_inQueue[ret], out);
+ return ret;
+}
+
+size_t NamedPipe::read(void *data, size_t size)
+{
+ size_t ret = peek(data, size);
+ m_inQueue.erase(0, ret);
+ return ret;
+}
+
+std::string NamedPipe::readToString(size_t size)
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ size_t retSize = std::min(size, m_inQueue.size());
+ std::string ret = m_inQueue.substr(0, retSize);
+ m_inQueue.erase(0, retSize);
+ return ret;
+}
+
+std::string NamedPipe::readAllToString()
+{
+ ASSERT(m_openMode & OpenMode::Reading);
+ std::string ret = m_inQueue;
+ m_inQueue.clear();
+ return ret;
+}
+
+void NamedPipe::closePipe()
+{
+ if (m_handle == NULL) {
+ return;
+ }
+ CancelIo(m_handle);
+ if (m_connectEvent.get() != nullptr) {
+ DWORD actual = 0;
+ GetOverlappedResult(m_handle, &m_connectOver, &actual, TRUE);
+ m_connectEvent.dispose();
+ }
+ if (m_inputWorker) {
+ m_inputWorker->waitForCanceledIo();
+ m_inputWorker.reset();
+ }
+ if (m_outputWorker) {
+ m_outputWorker->waitForCanceledIo();
+ m_outputWorker.reset();
+ }
+ CloseHandle(m_handle);
+ m_handle = NULL;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/NamedPipe.h b/src/libs/3rdparty/winpty/src/agent/NamedPipe.h
new file mode 100644
index 0000000000..0a4d8b0c75
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/NamedPipe.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef NAMEDPIPE_H
+#define NAMEDPIPE_H
+
+#include <windows.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "../shared/OwnedHandle.h"
+
+class EventLoop;
+
+class NamedPipe
+{
+private:
+ // The EventLoop uses these private members.
+ friend class EventLoop;
+ NamedPipe() {}
+ ~NamedPipe() { closePipe(); }
+ bool serviceIo(std::vector<HANDLE> *waitHandles);
+ void startPipeWorkers();
+
+ enum class ServiceResult { NoProgress, Error, Progress };
+
+private:
+ class IoWorker
+ {
+ public:
+ IoWorker(NamedPipe &namedPipe);
+ virtual ~IoWorker() {}
+ ServiceResult service();
+ void waitForCanceledIo();
+ HANDLE getWaitEvent();
+ protected:
+ NamedPipe &m_namedPipe;
+ bool m_pending = false;
+ DWORD m_currentIoSize = 0;
+ OwnedHandle m_event;
+ OVERLAPPED m_over = {};
+ enum { kIoSize = 64 * 1024 };
+ char m_buffer[kIoSize];
+ virtual void completeIo(DWORD size) = 0;
+ virtual bool shouldIssueIo(DWORD *size, bool *isRead) = 0;
+ };
+
+ class InputWorker : public IoWorker
+ {
+ public:
+ InputWorker(NamedPipe &namedPipe) : IoWorker(namedPipe) {}
+ protected:
+ virtual void completeIo(DWORD size) override;
+ virtual bool shouldIssueIo(DWORD *size, bool *isRead) override;
+ };
+
+ class OutputWorker : public IoWorker
+ {
+ public:
+ OutputWorker(NamedPipe &namedPipe) : IoWorker(namedPipe) {}
+ DWORD getPendingIoSize();
+ protected:
+ virtual void completeIo(DWORD size) override;
+ virtual bool shouldIssueIo(DWORD *size, bool *isRead) override;
+ };
+
+public:
+ struct OpenMode {
+ typedef int t;
+ enum { None = 0, Reading = 1, Writing = 2, Duplex = 3 };
+ };
+
+ std::wstring name() const { return m_name; }
+ void openServerPipe(LPCWSTR pipeName, OpenMode::t openMode,
+ int outBufferSize, int inBufferSize);
+ void connectToServer(LPCWSTR pipeName, OpenMode::t openMode);
+ size_t bytesToSend();
+ void write(const void *data, size_t size);
+ void write(const char *text);
+ size_t readBufferSize();
+ void setReadBufferSize(size_t size);
+ size_t bytesAvailable();
+ size_t peek(void *data, size_t size);
+ size_t read(void *data, size_t size);
+ std::string readToString(size_t size);
+ std::string readAllToString();
+ void closePipe();
+ bool isClosed() { return m_handle == nullptr; }
+ bool isConnected() { return !isClosed() && !isConnecting(); }
+ bool isConnecting() { return m_connectEvent.get() != nullptr; }
+
+private:
+ // Input/output buffers
+ std::wstring m_name;
+ OVERLAPPED m_connectOver = {};
+ OwnedHandle m_connectEvent;
+ OpenMode::t m_openMode = OpenMode::None;
+ size_t m_readBufferSize = 64 * 1024;
+ std::string m_inQueue;
+ std::string m_outQueue;
+ HANDLE m_handle = nullptr;
+ std::unique_ptr<InputWorker> m_inputWorker;
+ std::unique_ptr<OutputWorker> m_outputWorker;
+};
+
+#endif // NAMEDPIPE_H
diff --git a/src/libs/3rdparty/winpty/src/agent/Scraper.cc b/src/libs/3rdparty/winpty/src/agent/Scraper.cc
new file mode 100644
index 0000000000..21f9c67104
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Scraper.cc
@@ -0,0 +1,699 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Scraper.h"
+
+#include <windows.h>
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "../shared/WinptyAssert.h"
+#include "../shared/winpty_snprintf.h"
+
+#include "ConsoleFont.h"
+#include "Win32Console.h"
+#include "Win32ConsoleBuffer.h"
+
+namespace {
+
+template <typename T>
+T constrained(T min, T val, T max) {
+ ASSERT(min <= max);
+ return std::min(std::max(min, val), max);
+}
+
+} // anonymous namespace
+
+Scraper::Scraper(
+ Win32Console &console,
+ Win32ConsoleBuffer &buffer,
+ std::unique_ptr<Terminal> terminal,
+ Coord initialSize) :
+ m_console(console),
+ m_terminal(std::move(terminal)),
+ m_ptySize(initialSize)
+{
+ m_consoleBuffer = &buffer;
+
+ resetConsoleTracking(Terminal::OmitClear, buffer.windowRect().top());
+
+ m_bufferData.resize(BUFFER_LINE_COUNT);
+
+ // Setup the initial screen buffer and window size.
+ //
+ // Use SetConsoleWindowInfo to shrink the console window as much as
+ // possible -- to a 1x1 cell at the top-left. This call always succeeds.
+ // Prior to the new Windows 10 console, it also actually resizes the GUI
+ // window to 1x1 cell. Nevertheless, even though the GUI window can
+ // therefore be narrower than its minimum, calling
+ // SetConsoleScreenBufferSize with a 1x1 size still fails.
+ //
+ // While the small font intends to support large buffers, a user could
+ // still hit a limit imposed by their monitor width, so cap the new window
+ // size to GetLargestConsoleWindowSize().
+ setSmallFont(buffer.conout(), initialSize.X, m_console.isNewW10());
+ buffer.moveWindow(SmallRect(0, 0, 1, 1));
+ buffer.resizeBufferRange(Coord(initialSize.X, BUFFER_LINE_COUNT));
+ const auto largest = GetLargestConsoleWindowSize(buffer.conout());
+ buffer.moveWindow(SmallRect(
+ 0, 0,
+ std::min(initialSize.X, largest.X),
+ std::min(initialSize.Y, largest.Y)));
+ buffer.setCursorPosition(Coord(0, 0));
+
+ // For the sake of the color translation heuristic, set the console color
+ // to LtGray-on-Black.
+ buffer.setTextAttribute(Win32ConsoleBuffer::kDefaultAttributes);
+ buffer.clearAllLines(m_consoleBuffer->bufferInfo());
+
+ m_consoleBuffer = nullptr;
+}
+
+Scraper::~Scraper()
+{
+}
+
+// Whether or not the agent is frozen on entry, it will be frozen on exit.
+void Scraper::resizeWindow(Win32ConsoleBuffer &buffer,
+ Coord newSize,
+ ConsoleScreenBufferInfo &finalInfoOut)
+{
+ m_consoleBuffer = &buffer;
+ m_ptySize = newSize;
+ syncConsoleContentAndSize(true, finalInfoOut);
+ m_consoleBuffer = nullptr;
+}
+
+// This function may freeze the agent, but it will not unfreeze it.
+void Scraper::scrapeBuffer(Win32ConsoleBuffer &buffer,
+ ConsoleScreenBufferInfo &finalInfoOut)
+{
+ m_consoleBuffer = &buffer;
+ syncConsoleContentAndSize(false, finalInfoOut);
+ m_consoleBuffer = nullptr;
+}
+
+void Scraper::resetConsoleTracking(
+ Terminal::SendClearFlag sendClear, int64_t scrapedLineCount)
+{
+ for (ConsoleLine &line : m_bufferData) {
+ line.reset();
+ }
+ m_syncRow = -1;
+ m_scrapedLineCount = scrapedLineCount;
+ m_scrolledCount = 0;
+ m_maxBufferedLine = -1;
+ m_dirtyWindowTop = -1;
+ m_dirtyLineCount = 0;
+ m_terminal->reset(sendClear, m_scrapedLineCount);
+}
+
+// Detect window movement. If the window moves down (presumably as a
+// result of scrolling), then assume that all screen buffer lines down to
+// the bottom of the window are dirty.
+void Scraper::markEntireWindowDirty(const SmallRect &windowRect)
+{
+ m_dirtyLineCount = std::max(m_dirtyLineCount,
+ windowRect.top() + windowRect.height());
+}
+
+// Scan the screen buffer and advance the dirty line count when we find
+// non-empty lines.
+void Scraper::scanForDirtyLines(const SmallRect &windowRect)
+{
+ const int w = m_readBuffer.rect().width();
+ ASSERT(m_dirtyLineCount >= 1);
+ const CHAR_INFO *const prevLine =
+ m_readBuffer.lineData(m_dirtyLineCount - 1);
+ WORD prevLineAttr = prevLine[w - 1].Attributes;
+ const int stopLine = windowRect.top() + windowRect.height();
+
+ for (int line = m_dirtyLineCount; line < stopLine; ++line) {
+ const CHAR_INFO *lineData = m_readBuffer.lineData(line);
+ for (int col = 0; col < w; ++col) {
+ const WORD colAttr = lineData[col].Attributes;
+ if (lineData[col].Char.UnicodeChar != L' ' ||
+ colAttr != prevLineAttr) {
+ m_dirtyLineCount = line + 1;
+ break;
+ }
+ }
+ prevLineAttr = lineData[w - 1].Attributes;
+ }
+}
+
+// Clear lines in the line buffer. The `firstRow` parameter is in
+// screen-buffer coordinates.
+void Scraper::clearBufferLines(
+ const int firstRow,
+ const int count)
+{
+ ASSERT(!m_directMode);
+ for (int row = firstRow; row < firstRow + count; ++row) {
+ const int64_t bufLine = row + m_scrolledCount;
+ m_maxBufferedLine = std::max(m_maxBufferedLine, bufLine);
+ m_bufferData[bufLine % BUFFER_LINE_COUNT].blank(
+ Win32ConsoleBuffer::kDefaultAttributes);
+ }
+}
+
+static bool cursorInWindow(const ConsoleScreenBufferInfo &info)
+{
+ return info.dwCursorPosition.Y >= info.srWindow.Top &&
+ info.dwCursorPosition.Y <= info.srWindow.Bottom;
+}
+
+void Scraper::resizeImpl(const ConsoleScreenBufferInfo &origInfo)
+{
+ ASSERT(m_console.frozen());
+ const int cols = m_ptySize.X;
+ const int rows = m_ptySize.Y;
+ Coord finalBufferSize;
+
+ {
+ //
+ // To accommodate Windows 10, erase all lines up to the top of the
+ // visible window. It's hard to tell whether this is strictly
+ // necessary. It ensures that the sync marker won't move downward,
+ // and it ensures that we won't repeat lines that have already scrolled
+ // up into the scrollback.
+ //
+ // It *is* possible for these blank lines to reappear in the visible
+ // window (e.g. if the window is made taller), but because we blanked
+ // the lines in the line buffer, we still don't output them again.
+ //
+ const Coord origBufferSize = origInfo.bufferSize();
+ const SmallRect origWindowRect = origInfo.windowRect();
+
+ if (m_directMode) {
+ for (ConsoleLine &line : m_bufferData) {
+ line.reset();
+ }
+ } else {
+ m_consoleBuffer->clearLines(0, origWindowRect.Top, origInfo);
+ clearBufferLines(0, origWindowRect.Top);
+ if (m_syncRow != -1) {
+ createSyncMarker(std::min(
+ m_syncRow,
+ BUFFER_LINE_COUNT - rows
+ - SYNC_MARKER_LEN
+ - SYNC_MARKER_MARGIN));
+ }
+ }
+
+ finalBufferSize = Coord(
+ cols,
+ // If there was previously no scrollback (e.g. a full-screen app
+ // in direct mode) and we're reducing the window height, then
+ // reduce the console buffer's height too.
+ (origWindowRect.height() == origBufferSize.Y)
+ ? rows
+ : std::max<int>(rows, origBufferSize.Y));
+
+ // Reset the console font size. We need to do this before shrinking
+ // the window, because we might need to make the font bigger to permit
+ // a smaller window width. Making the font smaller could expand the
+ // screen buffer, which would hang the conhost process in the
+ // Windows 10 (10240 build) if the console selection is in progress, so
+ // unfreeze it first.
+ m_console.setFrozen(false);
+ setSmallFont(m_consoleBuffer->conout(), cols, m_console.isNewW10());
+ }
+
+ // We try to make the font small enough so that the entire screen buffer
+ // fits on the monitor, but it can't be guaranteed.
+ const auto largest =
+ GetLargestConsoleWindowSize(m_consoleBuffer->conout());
+ const short visibleCols = std::min<short>(cols, largest.X);
+ const short visibleRows = std::min<short>(rows, largest.Y);
+
+ {
+ // Make the window small enough. We want the console frozen during
+ // this step so we don't accidentally move the window above the cursor.
+ m_console.setFrozen(true);
+ const auto info = m_consoleBuffer->bufferInfo();
+ const auto &bufferSize = info.dwSize;
+ const int tmpWindowWidth = std::min(bufferSize.X, visibleCols);
+ const int tmpWindowHeight = std::min(bufferSize.Y, visibleRows);
+ SmallRect tmpWindowRect(
+ 0,
+ std::min<int>(bufferSize.Y - tmpWindowHeight,
+ info.windowRect().Top),
+ tmpWindowWidth,
+ tmpWindowHeight);
+ if (cursorInWindow(info)) {
+ tmpWindowRect = tmpWindowRect.ensureLineIncluded(
+ info.cursorPosition().Y);
+ }
+ m_consoleBuffer->moveWindow(tmpWindowRect);
+ }
+
+ {
+ // Resize the buffer to the final desired size.
+ m_console.setFrozen(false);
+ m_consoleBuffer->resizeBufferRange(finalBufferSize);
+ }
+
+ {
+ // Expand the window to its full size.
+ m_console.setFrozen(true);
+ const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo();
+
+ SmallRect finalWindowRect(
+ 0,
+ std::min<int>(info.bufferSize().Y - visibleRows,
+ info.windowRect().Top),
+ visibleCols,
+ visibleRows);
+
+ //
+ // Once a line in the screen buffer is "dirty", it should stay visible
+ // in the console window, so that we continue to update its content in
+ // the terminal. This code is particularly (only?) necessary on
+ // Windows 10, where making the buffer wider can rewrap lines and move
+ // the console window upward.
+ //
+ if (!m_directMode && m_dirtyLineCount > finalWindowRect.Bottom + 1) {
+ // In theory, we avoid ensureLineIncluded, because, a massive
+ // amount of output could have occurred while the console was
+ // unfrozen, so that the *top* of the window is now below the
+ // dirtiest tracked line.
+ finalWindowRect = SmallRect(
+ 0, m_dirtyLineCount - visibleRows,
+ visibleCols, visibleRows);
+ }
+
+ // Highest priority constraint: ensure that the cursor remains visible.
+ if (cursorInWindow(info)) {
+ finalWindowRect = finalWindowRect.ensureLineIncluded(
+ info.cursorPosition().Y);
+ }
+
+ m_consoleBuffer->moveWindow(finalWindowRect);
+ m_dirtyWindowTop = finalWindowRect.Top;
+ }
+
+ ASSERT(m_console.frozen());
+}
+
+void Scraper::syncConsoleContentAndSize(
+ bool forceResize,
+ ConsoleScreenBufferInfo &finalInfoOut)
+{
+ // We'll try to avoid freezing the console by reading large chunks (or
+ // all!) of the screen buffer without otherwise attempting to synchronize
+ // with the console application. We can only do this on Windows 10 and up
+ // because:
+ // - Prior to Windows 8, the size of a ReadConsoleOutputW call was limited
+ // by the ~32KB RPC buffer.
+ // - Prior to Windows 10, an out-of-range read region crashes the caller.
+ // (See misc/WindowsBugCrashReader.cc.)
+ //
+ if (!m_console.isNewW10() || forceResize) {
+ m_console.setFrozen(true);
+ }
+
+ const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo();
+ bool cursorVisible = true;
+ CONSOLE_CURSOR_INFO cursorInfo = {};
+ if (!GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo)) {
+ trace("GetConsoleCursorInfo failed");
+ } else {
+ cursorVisible = cursorInfo.bVisible != 0;
+ }
+
+ // If an app resizes the buffer height, then we enter "direct mode", where
+ // we stop trying to track incremental console changes.
+ const bool newDirectMode = (info.bufferSize().Y != BUFFER_LINE_COUNT);
+ if (newDirectMode != m_directMode) {
+ trace("Entering %s mode", newDirectMode ? "direct" : "scrolling");
+ resetConsoleTracking(Terminal::SendClear,
+ newDirectMode ? 0 : info.windowRect().top());
+ m_directMode = newDirectMode;
+
+ // When we switch from direct->scrolling mode, make sure the console is
+ // the right size.
+ if (!m_directMode) {
+ m_console.setFrozen(true);
+ forceResize = true;
+ }
+ }
+
+ if (m_directMode) {
+ // In direct-mode, resizing the console redraws the terminal, so do it
+ // before scraping.
+ if (forceResize) {
+ resizeImpl(info);
+ }
+ directScrapeOutput(info, cursorVisible);
+ } else {
+ if (!m_console.frozen()) {
+ if (!scrollingScrapeOutput(info, cursorVisible, true)) {
+ m_console.setFrozen(true);
+ }
+ }
+ if (m_console.frozen()) {
+ scrollingScrapeOutput(info, cursorVisible, false);
+ }
+ // In scrolling mode, we want to scrape before resizing, because we'll
+ // erase everything in the console buffer up to the top of the console
+ // window.
+ if (forceResize) {
+ resizeImpl(info);
+ }
+ }
+
+ finalInfoOut = forceResize ? m_consoleBuffer->bufferInfo() : info;
+}
+
+// Try to match Windows' behavior w.r.t. to the LVB attribute flags. In some
+// situations, Windows ignores the LVB flags on a character cell because of
+// backwards compatibility -- apparently some programs set the flags without
+// intending to enable reverse-video or underscores.
+//
+// [rprichard 2017-01-15] I haven't actually noticed any old programs that need
+// this treatment -- the motivation for this function comes from the MSDN
+// documentation for SetConsoleMode and ENABLE_LVB_GRID_WORLDWIDE.
+WORD Scraper::attributesMask()
+{
+ const auto WINPTY_ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4u;
+ const auto WINPTY_ENABLE_LVB_GRID_WORLDWIDE = 0x10u;
+ const auto WINPTY_COMMON_LVB_REVERSE_VIDEO = 0x4000u;
+ const auto WINPTY_COMMON_LVB_UNDERSCORE = 0x8000u;
+
+ const auto cp = GetConsoleOutputCP();
+ const auto isCjk = (cp == 932 || cp == 936 || cp == 949 || cp == 950);
+
+ const DWORD outputMode = [this]{
+ ASSERT(this->m_consoleBuffer != nullptr);
+ DWORD mode = 0;
+ if (!GetConsoleMode(this->m_consoleBuffer->conout(), &mode)) {
+ mode = 0;
+ }
+ return mode;
+ }();
+ const bool hasEnableLvbGridWorldwide =
+ (outputMode & WINPTY_ENABLE_LVB_GRID_WORLDWIDE) != 0;
+ const bool hasEnableVtProcessing =
+ (outputMode & WINPTY_ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
+
+ // The new Windows 10 console (as of 14393) seems to respect
+ // COMMON_LVB_REVERSE_VIDEO even in CP437 w/o the other enabling modes, so
+ // try to match that behavior.
+ const auto isReverseSupported =
+ isCjk || hasEnableLvbGridWorldwide || hasEnableVtProcessing || m_console.isNewW10();
+ const auto isUnderscoreSupported =
+ isCjk || hasEnableLvbGridWorldwide || hasEnableVtProcessing;
+
+ WORD mask = ~0;
+ if (!isReverseSupported) { mask &= ~WINPTY_COMMON_LVB_REVERSE_VIDEO; }
+ if (!isUnderscoreSupported) { mask &= ~WINPTY_COMMON_LVB_UNDERSCORE; }
+ return mask;
+}
+
+void Scraper::directScrapeOutput(const ConsoleScreenBufferInfo &info,
+ bool consoleCursorVisible)
+{
+ const SmallRect windowRect = info.windowRect();
+
+ const SmallRect scrapeRect(
+ windowRect.left(), windowRect.top(),
+ std::min<SHORT>(std::min(windowRect.width(), m_ptySize.X),
+ MAX_CONSOLE_WIDTH),
+ std::min<SHORT>(std::min(windowRect.height(), m_ptySize.Y),
+ BUFFER_LINE_COUNT));
+ const int w = scrapeRect.width();
+ const int h = scrapeRect.height();
+
+ const Coord cursor = info.cursorPosition();
+ const bool showTerminalCursor =
+ consoleCursorVisible && scrapeRect.contains(cursor);
+ const int cursorColumn = !showTerminalCursor ? -1 : cursor.X - scrapeRect.Left;
+ const int cursorLine = !showTerminalCursor ? -1 : cursor.Y - scrapeRect.Top;
+
+ if (!showTerminalCursor) {
+ m_terminal->hideTerminalCursor();
+ }
+
+ largeConsoleRead(m_readBuffer, *m_consoleBuffer, scrapeRect, attributesMask());
+
+ for (int line = 0; line < h; ++line) {
+ const CHAR_INFO *const curLine =
+ m_readBuffer.lineData(scrapeRect.top() + line);
+ ConsoleLine &bufLine = m_bufferData[line];
+ if (bufLine.detectChangeAndSetLine(curLine, w)) {
+ const int lineCursorColumn =
+ line == cursorLine ? cursorColumn : -1;
+ m_terminal->sendLine(line, curLine, w, lineCursorColumn);
+ }
+ }
+
+ if (showTerminalCursor) {
+ m_terminal->showTerminalCursor(cursorColumn, cursorLine);
+ }
+}
+
+bool Scraper::scrollingScrapeOutput(const ConsoleScreenBufferInfo &info,
+ bool consoleCursorVisible,
+ bool tentative)
+{
+ const Coord cursor = info.cursorPosition();
+ const SmallRect windowRect = info.windowRect();
+
+ if (m_syncRow != -1) {
+ // If a synchronizing marker was placed into the history, look for it
+ // and adjust the scroll count.
+ const int markerRow = findSyncMarker();
+ if (markerRow == -1) {
+ if (tentative) {
+ // I *think* it's possible to keep going, but it's simple to
+ // bail out.
+ return false;
+ }
+ // Something has happened. Reset the terminal.
+ trace("Sync marker has disappeared -- resetting the terminal"
+ " (m_syncCounter=%u)",
+ m_syncCounter);
+ resetConsoleTracking(Terminal::SendClear, windowRect.top());
+ } else if (markerRow != m_syncRow) {
+ ASSERT(markerRow < m_syncRow);
+ m_scrolledCount += (m_syncRow - markerRow);
+ m_syncRow = markerRow;
+ // If the buffer has scrolled, then the entire window is dirty.
+ markEntireWindowDirty(windowRect);
+ }
+ }
+
+ // Creating a new sync row requires clearing part of the console buffer, so
+ // avoid doing it if there's already a sync row that's good enough.
+ const int newSyncRow =
+ static_cast<int>(windowRect.top()) - SYNC_MARKER_LEN - SYNC_MARKER_MARGIN;
+ const bool shouldCreateSyncRow =
+ newSyncRow >= m_syncRow + SYNC_MARKER_LEN + SYNC_MARKER_MARGIN;
+ if (tentative && shouldCreateSyncRow) {
+ // It's difficult even in principle to put down a new marker if the
+ // console can scroll an arbitrarily amount while we're writing.
+ return false;
+ }
+
+ // Update the dirty line count:
+ // - If the window has moved, the entire window is dirty.
+ // - Everything up to the cursor is dirty.
+ // - All lines above the window are dirty.
+ // - Any non-blank lines are dirty.
+ if (m_dirtyWindowTop != -1) {
+ if (windowRect.top() > m_dirtyWindowTop) {
+ // The window has moved down, presumably as a result of scrolling.
+ markEntireWindowDirty(windowRect);
+ } else if (windowRect.top() < m_dirtyWindowTop) {
+ if (tentative) {
+ // I *think* it's possible to keep going, but it's simple to
+ // bail out.
+ return false;
+ }
+ // The window has moved upward. This is generally not expected to
+ // happen, but the CMD/PowerShell CLS command will move the window
+ // to the top as part of clearing everything else in the console.
+ trace("Window moved upward -- resetting the terminal"
+ " (m_syncCounter=%u)",
+ m_syncCounter);
+ resetConsoleTracking(Terminal::SendClear, windowRect.top());
+ }
+ }
+ m_dirtyWindowTop = windowRect.top();
+ m_dirtyLineCount = std::max(m_dirtyLineCount, cursor.Y + 1);
+ m_dirtyLineCount = std::max(m_dirtyLineCount, (int)windowRect.top());
+
+ // There will be at least one dirty line, because there is a cursor.
+ ASSERT(m_dirtyLineCount >= 1);
+
+ // The first line to scrape, in virtual line coordinates.
+ const int64_t firstVirtLine = std::min(m_scrapedLineCount,
+ windowRect.top() + m_scrolledCount);
+
+ // Read all the data we will need from the console. Start reading with the
+ // first line to scrape, but adjust the the read area upward to account for
+ // scanForDirtyLines' need to read the previous attribute. Read to the
+ // bottom of the window. (It's not clear to me whether the
+ // m_dirtyLineCount adjustment here is strictly necessary. It isn't
+ // necessary so long as the cursor is inside the current window.)
+ const int firstReadLine = std::min<int>(firstVirtLine - m_scrolledCount,
+ m_dirtyLineCount - 1);
+ const int stopReadLine = std::max(windowRect.top() + windowRect.height(),
+ m_dirtyLineCount);
+ ASSERT(firstReadLine >= 0 && stopReadLine > firstReadLine);
+ largeConsoleRead(m_readBuffer,
+ *m_consoleBuffer,
+ SmallRect(0, firstReadLine,
+ std::min<SHORT>(info.bufferSize().X,
+ MAX_CONSOLE_WIDTH),
+ stopReadLine - firstReadLine),
+ attributesMask());
+
+ // If we're scraping the buffer without freezing it, we have to query the
+ // buffer position data separately from the buffer content, so the two
+ // could easily be out-of-sync. If they *are* out-of-sync, abort the
+ // scrape operation and restart it frozen. (We may have updated the
+ // dirty-line high-water-mark, but that should be OK.)
+ if (tentative) {
+ const auto infoCheck = m_consoleBuffer->bufferInfo();
+ if (info.bufferSize() != infoCheck.bufferSize() ||
+ info.windowRect() != infoCheck.windowRect() ||
+ info.cursorPosition() != infoCheck.cursorPosition()) {
+ return false;
+ }
+ if (m_syncRow != -1 && m_syncRow != findSyncMarker()) {
+ return false;
+ }
+ }
+
+ if (shouldCreateSyncRow) {
+ ASSERT(!tentative);
+ createSyncMarker(newSyncRow);
+ }
+
+ // At this point, we're finished interacting (reading or writing) the
+ // console, and we just need to convert our collected data into terminal
+ // output.
+
+ scanForDirtyLines(windowRect);
+
+ // Note that it's possible for all the lines on the current window to
+ // be non-dirty.
+
+ // The line to stop scraping at, in virtual line coordinates.
+ const int64_t stopVirtLine =
+ std::min(m_dirtyLineCount, windowRect.top() + windowRect.height()) +
+ m_scrolledCount;
+
+ const bool showTerminalCursor =
+ consoleCursorVisible && windowRect.contains(cursor);
+ const int64_t cursorLine = !showTerminalCursor ? -1 : cursor.Y + m_scrolledCount;
+ const int cursorColumn = !showTerminalCursor ? -1 : cursor.X;
+
+ if (!showTerminalCursor) {
+ m_terminal->hideTerminalCursor();
+ }
+
+ bool sawModifiedLine = false;
+
+ const int w = m_readBuffer.rect().width();
+ for (int64_t line = firstVirtLine; line < stopVirtLine; ++line) {
+ const CHAR_INFO *curLine =
+ m_readBuffer.lineData(line - m_scrolledCount);
+ ConsoleLine &bufLine = m_bufferData[line % BUFFER_LINE_COUNT];
+ if (line > m_maxBufferedLine) {
+ m_maxBufferedLine = line;
+ sawModifiedLine = true;
+ }
+ if (sawModifiedLine) {
+ bufLine.setLine(curLine, w);
+ } else {
+ sawModifiedLine = bufLine.detectChangeAndSetLine(curLine, w);
+ }
+ if (sawModifiedLine) {
+ const int lineCursorColumn =
+ line == cursorLine ? cursorColumn : -1;
+ m_terminal->sendLine(line, curLine, w, lineCursorColumn);
+ }
+ }
+
+ m_scrapedLineCount = windowRect.top() + m_scrolledCount;
+
+ if (showTerminalCursor) {
+ m_terminal->showTerminalCursor(cursorColumn, cursorLine);
+ }
+
+ return true;
+}
+
+void Scraper::syncMarkerText(CHAR_INFO (&output)[SYNC_MARKER_LEN])
+{
+ // XXX: The marker text generated here could easily collide with ordinary
+ // console output. Does it make sense to try to avoid the collision?
+ char str[SYNC_MARKER_LEN + 1];
+ winpty_snprintf(str, "S*Y*N*C*%08x", m_syncCounter);
+ for (int i = 0; i < SYNC_MARKER_LEN; ++i) {
+ output[i].Char.UnicodeChar = str[i];
+ output[i].Attributes = 7;
+ }
+}
+
+int Scraper::findSyncMarker()
+{
+ ASSERT(m_syncRow >= 0);
+ CHAR_INFO marker[SYNC_MARKER_LEN];
+ CHAR_INFO column[BUFFER_LINE_COUNT];
+ syncMarkerText(marker);
+ SmallRect rect(0, 0, 1, m_syncRow + SYNC_MARKER_LEN);
+ m_consoleBuffer->read(rect, column);
+ int i;
+ for (i = m_syncRow; i >= 0; --i) {
+ int j;
+ for (j = 0; j < SYNC_MARKER_LEN; ++j) {
+ if (column[i + j].Char.UnicodeChar != marker[j].Char.UnicodeChar)
+ break;
+ }
+ if (j == SYNC_MARKER_LEN)
+ return i;
+ }
+ return -1;
+}
+
+void Scraper::createSyncMarker(int row)
+{
+ ASSERT(row >= 1);
+
+ // Clear the lines around the marker to ensure that Windows 10's rewrapping
+ // does not affect the marker.
+ m_consoleBuffer->clearLines(row - 1, SYNC_MARKER_LEN + 1,
+ m_consoleBuffer->bufferInfo());
+
+ // Write a new marker.
+ m_syncCounter++;
+ CHAR_INFO marker[SYNC_MARKER_LEN];
+ syncMarkerText(marker);
+ m_syncRow = row;
+ SmallRect markerRect(0, m_syncRow, 1, SYNC_MARKER_LEN);
+ m_consoleBuffer->write(markerRect, marker);
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Scraper.h b/src/libs/3rdparty/winpty/src/agent/Scraper.h
new file mode 100644
index 0000000000..9c10d80aed
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Scraper.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_SCRAPER_H
+#define AGENT_SCRAPER_H
+
+#include <windows.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "ConsoleLine.h"
+#include "Coord.h"
+#include "LargeConsoleRead.h"
+#include "SmallRect.h"
+#include "Terminal.h"
+
+class ConsoleScreenBufferInfo;
+class Win32Console;
+class Win32ConsoleBuffer;
+
+// We must be able to issue a single ReadConsoleOutputW call of
+// MAX_CONSOLE_WIDTH characters, and a single read of approximately several
+// hundred fewer characters than BUFFER_LINE_COUNT.
+const int BUFFER_LINE_COUNT = 3000;
+const int MAX_CONSOLE_WIDTH = 2500;
+const int MAX_CONSOLE_HEIGHT = 2000;
+const int SYNC_MARKER_LEN = 16;
+const int SYNC_MARKER_MARGIN = 200;
+
+class Scraper {
+public:
+ Scraper(
+ Win32Console &console,
+ Win32ConsoleBuffer &buffer,
+ std::unique_ptr<Terminal> terminal,
+ Coord initialSize);
+ ~Scraper();
+ void resizeWindow(Win32ConsoleBuffer &buffer,
+ Coord newSize,
+ ConsoleScreenBufferInfo &finalInfoOut);
+ void scrapeBuffer(Win32ConsoleBuffer &buffer,
+ ConsoleScreenBufferInfo &finalInfoOut);
+ Terminal &terminal() { return *m_terminal; }
+
+private:
+ void resetConsoleTracking(
+ Terminal::SendClearFlag sendClear, int64_t scrapedLineCount);
+ void markEntireWindowDirty(const SmallRect &windowRect);
+ void scanForDirtyLines(const SmallRect &windowRect);
+ void clearBufferLines(int firstRow, int count);
+ void resizeImpl(const ConsoleScreenBufferInfo &origInfo);
+ void syncConsoleContentAndSize(bool forceResize,
+ ConsoleScreenBufferInfo &finalInfoOut);
+ WORD attributesMask();
+ void directScrapeOutput(const ConsoleScreenBufferInfo &info,
+ bool consoleCursorVisible);
+ bool scrollingScrapeOutput(const ConsoleScreenBufferInfo &info,
+ bool consoleCursorVisible,
+ bool tentative);
+ void syncMarkerText(CHAR_INFO (&output)[SYNC_MARKER_LEN]);
+ int findSyncMarker();
+ void createSyncMarker(int row);
+
+private:
+ Win32Console &m_console;
+ Win32ConsoleBuffer *m_consoleBuffer = nullptr;
+ std::unique_ptr<Terminal> m_terminal;
+
+ int m_syncRow = -1;
+ unsigned int m_syncCounter = 0;
+
+ bool m_directMode = false;
+ Coord m_ptySize;
+ int64_t m_scrapedLineCount = 0;
+ int64_t m_scrolledCount = 0;
+ int64_t m_maxBufferedLine = -1;
+ LargeConsoleReadBuffer m_readBuffer;
+ std::vector<ConsoleLine> m_bufferData;
+ int m_dirtyWindowTop = -1;
+ int m_dirtyLineCount = 0;
+};
+
+#endif // AGENT_SCRAPER_H
diff --git a/src/libs/3rdparty/winpty/src/agent/SimplePool.h b/src/libs/3rdparty/winpty/src/agent/SimplePool.h
new file mode 100644
index 0000000000..41ff94a90d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/SimplePool.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef SIMPLE_POOL_H
+#define SIMPLE_POOL_H
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include "../shared/WinptyAssert.h"
+
+template <typename T, size_t chunkSize>
+class SimplePool {
+public:
+ ~SimplePool();
+ T *alloc();
+ void clear();
+private:
+ struct Chunk {
+ size_t count;
+ T *data;
+ };
+ std::vector<Chunk> m_chunks;
+};
+
+template <typename T, size_t chunkSize>
+SimplePool<T, chunkSize>::~SimplePool() {
+ clear();
+}
+
+template <typename T, size_t chunkSize>
+void SimplePool<T, chunkSize>::clear() {
+ for (size_t ci = 0; ci < m_chunks.size(); ++ci) {
+ Chunk &chunk = m_chunks[ci];
+ for (size_t ti = 0; ti < chunk.count; ++ti) {
+ chunk.data[ti].~T();
+ }
+ free(chunk.data);
+ }
+ m_chunks.clear();
+}
+
+template <typename T, size_t chunkSize>
+T *SimplePool<T, chunkSize>::alloc() {
+ if (m_chunks.empty() || m_chunks.back().count == chunkSize) {
+ T *newData = reinterpret_cast<T*>(malloc(sizeof(T) * chunkSize));
+ ASSERT(newData != NULL);
+ Chunk newChunk = { 0, newData };
+ m_chunks.push_back(newChunk);
+ }
+ Chunk &chunk = m_chunks.back();
+ T *ret = &chunk.data[chunk.count++];
+ new (ret) T();
+ return ret;
+}
+
+#endif // SIMPLE_POOL_H
diff --git a/src/libs/3rdparty/winpty/src/agent/SmallRect.h b/src/libs/3rdparty/winpty/src/agent/SmallRect.h
new file mode 100644
index 0000000000..bad0b88683
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/SmallRect.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef SMALLRECT_H
+#define SMALLRECT_H
+
+#include <windows.h>
+
+#include <algorithm>
+#include <string>
+
+#include "../shared/winpty_snprintf.h"
+#include "Coord.h"
+
+struct SmallRect : SMALL_RECT
+{
+ SmallRect()
+ {
+ Left = Right = Top = Bottom = 0;
+ }
+
+ SmallRect(SHORT x, SHORT y, SHORT width, SHORT height)
+ {
+ Left = x;
+ Top = y;
+ Right = x + width - 1;
+ Bottom = y + height - 1;
+ }
+
+ SmallRect(const COORD &topLeft, const COORD &size)
+ {
+ Left = topLeft.X;
+ Top = topLeft.Y;
+ Right = Left + size.X - 1;
+ Bottom = Top + size.Y - 1;
+ }
+
+ SmallRect(const SMALL_RECT &other)
+ {
+ *(SMALL_RECT*)this = other;
+ }
+
+ SmallRect(const SmallRect &other)
+ {
+ *(SMALL_RECT*)this = *(const SMALL_RECT*)&other;
+ }
+
+ SmallRect &operator=(const SmallRect &other)
+ {
+ *(SMALL_RECT*)this = *(const SMALL_RECT*)&other;
+ return *this;
+ }
+
+ bool contains(const SmallRect &other) const
+ {
+ return other.Left >= Left &&
+ other.Right <= Right &&
+ other.Top >= Top &&
+ other.Bottom <= Bottom;
+ }
+
+ bool contains(const Coord &other) const
+ {
+ return other.X >= Left &&
+ other.X <= Right &&
+ other.Y >= Top &&
+ other.Y <= Bottom;
+ }
+
+ SmallRect intersected(const SmallRect &other) const
+ {
+ int x1 = std::max(Left, other.Left);
+ int x2 = std::min(Right, other.Right);
+ int y1 = std::max(Top, other.Top);
+ int y2 = std::min(Bottom, other.Bottom);
+ return SmallRect(x1,
+ y1,
+ std::max(0, x2 - x1 + 1),
+ std::max(0, y2 - y1 + 1));
+ }
+
+ SmallRect ensureLineIncluded(SHORT line) const
+ {
+ const SHORT h = height();
+ if (line < Top) {
+ return SmallRect(Left, line, width(), h);
+ } else if (line > Bottom) {
+ return SmallRect(Left, line - h + 1, width(), h);
+ } else {
+ return *this;
+ }
+ }
+
+ SHORT top() const { return Top; }
+ SHORT left() const { return Left; }
+ SHORT width() const { return Right - Left + 1; }
+ SHORT height() const { return Bottom - Top + 1; }
+ void setTop(SHORT top) { Top = top; }
+ void setLeft(SHORT left) { Left = left; }
+ void setWidth(SHORT width) { Right = Left + width - 1; }
+ void setHeight(SHORT height) { Bottom = Top + height - 1; }
+ Coord size() const { return Coord(width(), height()); }
+
+ bool operator==(const SmallRect &other) const
+ {
+ return Left == other.Left &&
+ Right == other.Right &&
+ Top == other.Top &&
+ Bottom == other.Bottom;
+ }
+
+ bool operator!=(const SmallRect &other) const
+ {
+ return !(*this == other);
+ }
+
+ std::string toString() const
+ {
+ char ret[64];
+ winpty_snprintf(ret, "(x=%d,y=%d,w=%d,h=%d)",
+ Left, Top, width(), height());
+ return std::string(ret);
+ }
+};
+
+#endif // SMALLRECT_H
diff --git a/src/libs/3rdparty/winpty/src/agent/Terminal.cc b/src/libs/3rdparty/winpty/src/agent/Terminal.cc
new file mode 100644
index 0000000000..afa0a36260
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Terminal.cc
@@ -0,0 +1,535 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Terminal.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+#include "NamedPipe.h"
+#include "UnicodeEncoding.h"
+#include "../shared/DebugClient.h"
+#include "../shared/WinptyAssert.h"
+#include "../shared/winpty_snprintf.h"
+
+#define CSI "\x1b["
+
+// Work around the old MinGW, which lacks COMMON_LVB_LEADING_BYTE and
+// COMMON_LVB_TRAILING_BYTE.
+const int WINPTY_COMMON_LVB_LEADING_BYTE = 0x100;
+const int WINPTY_COMMON_LVB_TRAILING_BYTE = 0x200;
+const int WINPTY_COMMON_LVB_REVERSE_VIDEO = 0x4000;
+const int WINPTY_COMMON_LVB_UNDERSCORE = 0x8000;
+
+const int COLOR_ATTRIBUTE_MASK =
+ FOREGROUND_BLUE |
+ FOREGROUND_GREEN |
+ FOREGROUND_RED |
+ FOREGROUND_INTENSITY |
+ BACKGROUND_BLUE |
+ BACKGROUND_GREEN |
+ BACKGROUND_RED |
+ BACKGROUND_INTENSITY |
+ WINPTY_COMMON_LVB_REVERSE_VIDEO |
+ WINPTY_COMMON_LVB_UNDERSCORE;
+
+const int FLAG_RED = 1;
+const int FLAG_GREEN = 2;
+const int FLAG_BLUE = 4;
+const int FLAG_BRIGHT = 8;
+
+const int BLACK = 0;
+const int DKGRAY = BLACK | FLAG_BRIGHT;
+const int LTGRAY = FLAG_RED | FLAG_GREEN | FLAG_BLUE;
+const int WHITE = LTGRAY | FLAG_BRIGHT;
+
+// SGR parameters (Select Graphic Rendition)
+const int SGR_FORE = 30;
+const int SGR_FORE_HI = 90;
+const int SGR_BACK = 40;
+const int SGR_BACK_HI = 100;
+
+namespace {
+
+static void outUInt(std::string &out, unsigned int n)
+{
+ char buf[32];
+ char *pbuf = &buf[32];
+ *(--pbuf) = '\0';
+ do {
+ *(--pbuf) = '0' + n % 10;
+ n /= 10;
+ } while (n != 0);
+ out.append(pbuf);
+}
+
+static void outputSetColorSgrParams(std::string &out, bool isFore, int color)
+{
+ out.push_back(';');
+ const int sgrBase = isFore ? SGR_FORE : SGR_BACK;
+ if (color & FLAG_BRIGHT) {
+ // Some terminals don't support the 9X/10X "intensive" color parameters
+ // (e.g. the Eclipse TM terminal as of this writing). Those terminals
+ // will quietly ignore a 9X/10X code, and the other terminals will
+ // ignore a 3X/4X code if it's followed by a 9X/10X code. Therefore,
+ // output a 3X/4X code as a fallback, then override it.
+ const int colorBase = color & ~FLAG_BRIGHT;
+ outUInt(out, sgrBase + colorBase);
+ out.push_back(';');
+ outUInt(out, sgrBase + (SGR_FORE_HI - SGR_FORE) + colorBase);
+ } else {
+ outUInt(out, sgrBase + color);
+ }
+}
+
+static void outputSetColor(std::string &out, int color)
+{
+ int fore = 0;
+ int back = 0;
+ if (color & FOREGROUND_RED) fore |= FLAG_RED;
+ if (color & FOREGROUND_GREEN) fore |= FLAG_GREEN;
+ if (color & FOREGROUND_BLUE) fore |= FLAG_BLUE;
+ if (color & FOREGROUND_INTENSITY) fore |= FLAG_BRIGHT;
+ if (color & BACKGROUND_RED) back |= FLAG_RED;
+ if (color & BACKGROUND_GREEN) back |= FLAG_GREEN;
+ if (color & BACKGROUND_BLUE) back |= FLAG_BLUE;
+ if (color & BACKGROUND_INTENSITY) back |= FLAG_BRIGHT;
+
+ if (color & WINPTY_COMMON_LVB_REVERSE_VIDEO) {
+ // n.b.: The COMMON_LVB_REVERSE_VIDEO flag also swaps
+ // FOREGROUND_INTENSITY and BACKGROUND_INTENSITY. Tested on
+ // Windows 10 v14393.
+ std::swap(fore, back);
+ }
+
+ // Translate the fore/back colors into terminal escape codes using
+ // a heuristic that works OK with common white-on-black or
+ // black-on-white color schemes. We don't know which color scheme
+ // the terminal is using. It is ugly to force white-on-black text
+ // on a black-on-white terminal, and it's even ugly to force the
+ // matching scheme. It's probably relevant that the default
+ // fore/back terminal colors frequently do not match any of the 16
+ // palette colors.
+
+ // Typical default terminal color schemes (according to palette,
+ // when possible):
+ // - mintty: LtGray-on-Black(A)
+ // - putty: LtGray-on-Black(A)
+ // - xterm: LtGray-on-Black(A)
+ // - Konsole: LtGray-on-Black(A)
+ // - JediTerm/JetBrains: Black-on-White(B)
+ // - rxvt: Black-on-White(B)
+
+ // If the background is the default color (black), then it will
+ // map to Black(A) or White(B). If we translate White to White,
+ // then a Black background and a White background in the console
+ // are both White with (B). Therefore, we should translate White
+ // using SGR 7 (Invert). The typical finished mapping table for
+ // background grayscale colors is:
+ //
+ // (A) White => LtGray(fore)
+ // (A) Black => Black(back)
+ // (A) LtGray => LtGray
+ // (A) DkGray => DkGray
+ //
+ // (B) White => Black(fore)
+ // (B) Black => White(back)
+ // (B) LtGray => LtGray
+ // (B) DkGray => DkGray
+ //
+
+ out.append(CSI "0");
+ if (back == BLACK) {
+ if (fore == LTGRAY) {
+ // The "default" foreground color. Use the terminal's
+ // default colors.
+ } else if (fore == WHITE) {
+ // Sending the literal color white would behave poorly if
+ // the terminal were black-on-white. Sending Bold is not
+ // guaranteed to alter the color, but it will make the text
+ // visually distinct, so do that instead.
+ out.append(";1");
+ } else if (fore == DKGRAY) {
+ // Set the foreground color to DkGray(90) with a fallback
+ // of LtGray(37) for terminals that don't handle the 9X SGR
+ // parameters (e.g. Eclipse's TM Terminal as of this
+ // writing).
+ out.append(";37;90");
+ } else {
+ outputSetColorSgrParams(out, true, fore);
+ }
+ } else if (back == WHITE) {
+ // Set the background color using Invert on the default
+ // foreground color, and set the foreground color by setting a
+ // background color.
+
+ // Use the terminal's inverted colors.
+ out.append(";7");
+ if (fore == LTGRAY || fore == BLACK) {
+ // We're likely mapping Console White to terminal LtGray or
+ // Black. If they are the Console foreground color, then
+ // don't set a terminal foreground color to avoid creating
+ // invisible text.
+ } else {
+ outputSetColorSgrParams(out, false, fore);
+ }
+ } else {
+ // Set the foreground and background to match exactly that in
+ // the Windows console.
+ outputSetColorSgrParams(out, true, fore);
+ outputSetColorSgrParams(out, false, back);
+ }
+ if (fore == back) {
+ // The foreground and background colors are exactly equal, so
+ // attempt to hide the text using the Conceal SGR parameter,
+ // which some terminals support.
+ out.append(";8");
+ }
+ if (color & WINPTY_COMMON_LVB_UNDERSCORE) {
+ out.append(";4");
+ }
+ out.push_back('m');
+}
+
+static inline unsigned int fixSpecialCharacters(unsigned int ch)
+{
+ if (ch <= 0x1b) {
+ switch (ch) {
+ // The Windows Console has a popup window (e.g. that appears with
+ // F7) that is sometimes bordered with box-drawing characters.
+ // With the Japanese and Korean system locales (CP932 and CP949),
+ // the UnicodeChar values for the box-drawing characters are 1
+ // through 6. Detect this and map the values to the correct
+ // Unicode values.
+ //
+ // N.B. In the English locale, the UnicodeChar values are correct,
+ // and they identify single-line characters rather than
+ // double-line. In the Chinese Simplified and Traditional locales,
+ // the popups use ASCII characters instead.
+ case 1: return 0x2554; // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ case 2: return 0x2557; // BOX DRAWINGS DOUBLE DOWN AND LEFT
+ case 3: return 0x255A; // BOX DRAWINGS DOUBLE UP AND RIGHT
+ case 4: return 0x255D; // BOX DRAWINGS DOUBLE UP AND LEFT
+ case 5: return 0x2551; // BOX DRAWINGS DOUBLE VERTICAL
+ case 6: return 0x2550; // BOX DRAWINGS DOUBLE HORIZONTAL
+
+ // Convert an escape character to some other character. This
+ // conversion only applies to console cells containing an escape
+ // character. In newer versions of Windows 10 (e.g. 10.0.10586),
+ // the non-legacy console recognizes escape sequences in
+ // WriteConsole and interprets them without writing them to the
+ // cells of the screen buffer. In that case, the conversion here
+ // does not apply.
+ case 0x1b: return '?';
+ }
+ }
+ return ch;
+}
+
+static inline bool isFullWidthCharacter(const CHAR_INFO *data, int width)
+{
+ if (width < 2) {
+ return false;
+ }
+ return
+ (data[0].Attributes & WINPTY_COMMON_LVB_LEADING_BYTE) &&
+ (data[1].Attributes & WINPTY_COMMON_LVB_TRAILING_BYTE) &&
+ data[0].Char.UnicodeChar == data[1].Char.UnicodeChar;
+}
+
+// Scan to find a single Unicode Scalar Value. Full-width characters occupy
+// two console cells, and this code also tries to handle UTF-16 surrogate
+// pairs.
+//
+// Windows expands at least some wide characters outside the Basic
+// Multilingual Plane into four cells, such as U+20000:
+// 1. 0xD840, attr=0x107
+// 2. 0xD840, attr=0x207
+// 3. 0xDC00, attr=0x107
+// 4. 0xDC00, attr=0x207
+// Even in the Traditional Chinese locale on Windows 10, this text is rendered
+// as two boxes, but if those boxes are copied-and-pasted, the character is
+// copied correctly.
+static inline void scanUnicodeScalarValue(
+ const CHAR_INFO *data, int width,
+ int &outCellCount, unsigned int &outCharValue)
+{
+ ASSERT(width >= 1);
+
+ const int w1 = isFullWidthCharacter(data, width) ? 2 : 1;
+ const wchar_t c1 = data[0].Char.UnicodeChar;
+
+ if ((c1 & 0xF800) == 0xD800) {
+ // The first cell is either a leading or trailing surrogate pair.
+ if ((c1 & 0xFC00) != 0xD800 ||
+ width <= w1 ||
+ ((data[w1].Char.UnicodeChar & 0xFC00) != 0xDC00)) {
+ // Invalid surrogate pair
+ outCellCount = w1;
+ outCharValue = '?';
+ } else {
+ // Valid surrogate pair
+ outCellCount = w1 + (isFullWidthCharacter(&data[w1], width - w1) ? 2 : 1);
+ outCharValue = decodeSurrogatePair(c1, data[w1].Char.UnicodeChar);
+ }
+ } else {
+ outCellCount = w1;
+ outCharValue = c1;
+ }
+}
+
+} // anonymous namespace
+
+void Terminal::reset(SendClearFlag sendClearFirst, int64_t newLine)
+{
+ if (sendClearFirst == SendClear && !m_plainMode) {
+ // 0m ==> reset SGR parameters
+ // 1;1H ==> move cursor to top-left position
+ // 2J ==> clear the entire screen
+ m_output.write(CSI "0m" CSI "1;1H" CSI "2J");
+ }
+ m_remoteLine = newLine;
+ m_remoteColumn = 0;
+ m_lineData.clear();
+ m_cursorHidden = false;
+ m_remoteColor = -1;
+}
+
+void Terminal::sendLine(int64_t line, const CHAR_INFO *lineData, int width,
+ int cursorColumn)
+{
+ ASSERT(width >= 1);
+
+ moveTerminalToLine(line);
+
+ // If possible, see if we can append to what we've already output for this
+ // line.
+ if (m_lineDataValid) {
+ ASSERT(m_lineData.size() == static_cast<size_t>(m_remoteColumn));
+ if (m_remoteColumn > 0) {
+ // In normal mode, if m_lineData.size() equals `width`, then we
+ // will have trouble outputing the "erase rest of line" command,
+ // which must be output before reaching the end of the line. In
+ // plain mode, we don't output that command, so we're OK with a
+ // full line.
+ bool okWidth = false;
+ if (m_plainMode) {
+ okWidth = static_cast<size_t>(width) >= m_lineData.size();
+ } else {
+ okWidth = static_cast<size_t>(width) > m_lineData.size();
+ }
+ if (!okWidth ||
+ memcmp(m_lineData.data(), lineData,
+ sizeof(CHAR_INFO) * m_lineData.size()) != 0) {
+ m_lineDataValid = false;
+ }
+ }
+ }
+ if (!m_lineDataValid) {
+ // We can't reuse, so we must reset this line.
+ hideTerminalCursor();
+ if (m_plainMode) {
+ // We can't backtrack, so repeat this line.
+ m_output.write("\r\n");
+ } else {
+ m_output.write("\r");
+ }
+ m_lineDataValid = true;
+ m_lineData.clear();
+ m_remoteColumn = 0;
+ }
+
+ std::string &termLine = m_termLineWorkingBuffer;
+ termLine.clear();
+ size_t trimmedLineLength = 0;
+ int trimmedCellCount = m_lineData.size();
+ bool alreadyErasedLine = false;
+
+ int cellCount = 1;
+ for (int i = m_lineData.size(); i < width; i += cellCount) {
+ if (m_outputColor) {
+ int color = lineData[i].Attributes & COLOR_ATTRIBUTE_MASK;
+ if (color != m_remoteColor) {
+ outputSetColor(termLine, color);
+ trimmedLineLength = termLine.size();
+ m_remoteColor = color;
+
+ // All the cells just up to this color change will be output.
+ trimmedCellCount = i;
+ }
+ }
+ unsigned int ch;
+ scanUnicodeScalarValue(&lineData[i], width - i, cellCount, ch);
+ if (ch == ' ') {
+ // Tentatively add this space character. We'll only output it if
+ // we see something interesting after it.
+ termLine.push_back(' ');
+ } else {
+ if (i + cellCount == width) {
+ // We'd like to erase the line after outputting all non-blank
+ // characters, but this doesn't work if the last cell in the
+ // line is non-blank. At the point, the cursor is positioned
+ // just past the end of the line, but in many terminals,
+ // issuing a CSI 0K at that point also erases the last cell in
+ // the line. Work around this behavior by issuing the erase
+ // one character early in that case.
+ if (!m_plainMode) {
+ termLine.append(CSI "0K"); // Erase from cursor to EOL
+ }
+ alreadyErasedLine = true;
+ }
+ ch = fixSpecialCharacters(ch);
+ char enc[4];
+ int enclen = encodeUtf8(enc, ch);
+ if (enclen == 0) {
+ enc[0] = '?';
+ enclen = 1;
+ }
+ termLine.append(enc, enclen);
+ trimmedLineLength = termLine.size();
+
+ // All the cells up to and including this cell will be output.
+ trimmedCellCount = i + cellCount;
+ }
+ }
+
+ if (cursorColumn != -1 && trimmedCellCount > cursorColumn) {
+ // The line content would run past the cursor, so hide it before we
+ // output.
+ hideTerminalCursor();
+ }
+
+ m_output.write(termLine.data(), trimmedLineLength);
+ if (!alreadyErasedLine && !m_plainMode) {
+ m_output.write(CSI "0K"); // Erase from cursor to EOL
+ }
+
+ ASSERT(trimmedCellCount <= width);
+ m_lineData.insert(m_lineData.end(),
+ &lineData[m_lineData.size()],
+ &lineData[trimmedCellCount]);
+ m_remoteColumn = trimmedCellCount;
+}
+
+void Terminal::showTerminalCursor(int column, int64_t line)
+{
+ moveTerminalToLine(line);
+ if (!m_plainMode) {
+ if (m_remoteColumn != column) {
+ char buffer[32];
+ winpty_snprintf(buffer, CSI "%dG", column + 1);
+ m_output.write(buffer);
+ m_lineDataValid = (column == 0);
+ m_lineData.clear();
+ m_remoteColumn = column;
+ }
+ if (m_cursorHidden) {
+ m_output.write(CSI "?25h");
+ m_cursorHidden = false;
+ }
+ }
+}
+
+void Terminal::hideTerminalCursor()
+{
+ if (!m_plainMode) {
+ if (m_cursorHidden) {
+ return;
+ }
+ m_output.write(CSI "?25l");
+ m_cursorHidden = true;
+ }
+}
+
+void Terminal::moveTerminalToLine(int64_t line)
+{
+ if (line == m_remoteLine) {
+ return;
+ }
+
+ // Do not use CPL or CNL. Konsole 2.5.4 does not support Cursor Previous
+ // Line (CPL) -- there are "Undecodable sequence" errors. gnome-terminal
+ // 2.32.0 does handle it. Cursor Next Line (CNL) does nothing if the
+ // cursor is on the last line already.
+
+ hideTerminalCursor();
+
+ if (line < m_remoteLine) {
+ if (m_plainMode) {
+ // We can't backtrack, so instead repeat the lines again.
+ m_output.write("\r\n");
+ m_remoteLine = line;
+ } else {
+ // Backtrack and overwrite previous lines.
+ // CUrsor Up (CUU)
+ char buffer[32];
+ winpty_snprintf(buffer, "\r" CSI "%uA",
+ static_cast<unsigned int>(m_remoteLine - line));
+ m_output.write(buffer);
+ m_remoteLine = line;
+ }
+ } else if (line > m_remoteLine) {
+ while (line > m_remoteLine) {
+ m_output.write("\r\n");
+ m_remoteLine++;
+ }
+ }
+
+ m_lineDataValid = true;
+ m_lineData.clear();
+ m_remoteColumn = 0;
+}
+
+void Terminal::enableMouseMode(bool enabled)
+{
+ if (m_mouseModeEnabled == enabled || m_plainMode) {
+ return;
+ }
+ m_mouseModeEnabled = enabled;
+ if (enabled) {
+ // Start by disabling UTF-8 coordinate mode (1005), just in case we
+ // have a terminal that does not support 1006/1015 modes, and 1005
+ // happens to be enabled. The UTF-8 coordinates can't be unambiguously
+ // decoded.
+ //
+ // Enable basic mouse support first (1000), then try to switch to
+ // button-move mode (1002), then try full mouse-move mode (1003).
+ // Terminals that don't support a mode will be stuck at the highest
+ // mode they do support.
+ //
+ // Enable encoding mode 1015 first, then try to switch to 1006. On
+ // some terminals, both modes will be enabled, but 1006 will have
+ // priority. On other terminals, 1006 wins because it's listed last.
+ //
+ // See misc/MouseInputNotes.txt for details.
+ m_output.write(
+ CSI "?1005l"
+ CSI "?1000h" CSI "?1002h" CSI "?1003h" CSI "?1015h" CSI "?1006h");
+ } else {
+ // Resetting both encoding modes (1006 and 1015) is necessary, but
+ // apparently we only need to use reset on one of the 100[023] modes.
+ // Doing both doesn't hurt.
+ m_output.write(
+ CSI "?1006l" CSI "?1015l" CSI "?1003l" CSI "?1002l" CSI "?1000l");
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Terminal.h b/src/libs/3rdparty/winpty/src/agent/Terminal.h
new file mode 100644
index 0000000000..058eb2650e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Terminal.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef TERMINAL_H
+#define TERMINAL_H
+
+#include <windows.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "Coord.h"
+
+class NamedPipe;
+
+class Terminal
+{
+public:
+ explicit Terminal(NamedPipe &output, bool plainMode, bool outputColor)
+ : m_output(output), m_plainMode(plainMode), m_outputColor(outputColor)
+ {
+ }
+
+ enum SendClearFlag { OmitClear, SendClear };
+ void reset(SendClearFlag sendClearFirst, int64_t newLine);
+ void sendLine(int64_t line, const CHAR_INFO *lineData, int width,
+ int cursorColumn);
+ void showTerminalCursor(int column, int64_t line);
+ void hideTerminalCursor();
+
+private:
+ void moveTerminalToLine(int64_t line);
+
+public:
+ void enableMouseMode(bool enabled);
+
+private:
+ NamedPipe &m_output;
+ int64_t m_remoteLine = 0;
+ int m_remoteColumn = 0;
+ bool m_lineDataValid = true;
+ std::vector<CHAR_INFO> m_lineData;
+ bool m_cursorHidden = false;
+ int m_remoteColor = -1;
+ std::string m_termLineWorkingBuffer;
+ bool m_plainMode = false;
+ bool m_outputColor = true;
+ bool m_mouseModeEnabled = false;
+};
+
+#endif // TERMINAL_H
diff --git a/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h b/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h
new file mode 100644
index 0000000000..6b0de3eff9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNICODE_ENCODING_H
+#define UNICODE_ENCODING_H
+
+#include <stdint.h>
+
+// Encode the Unicode codepoint with UTF-8. The buffer must be at least 4
+// bytes in size.
+static inline int encodeUtf8(char *out, uint32_t code) {
+ if (code < 0x80) {
+ out[0] = code;
+ return 1;
+ } else if (code < 0x800) {
+ out[0] = ((code >> 6) & 0x1F) | 0xC0;
+ out[1] = ((code >> 0) & 0x3F) | 0x80;
+ return 2;
+ } else if (code < 0x10000) {
+ if (code >= 0xD800 && code <= 0xDFFF) {
+ // The code points 0xD800 to 0xDFFF are reserved for UTF-16
+ // surrogate pairs and do not have an encoding in UTF-8.
+ return 0;
+ }
+ out[0] = ((code >> 12) & 0x0F) | 0xE0;
+ out[1] = ((code >> 6) & 0x3F) | 0x80;
+ out[2] = ((code >> 0) & 0x3F) | 0x80;
+ return 3;
+ } else if (code < 0x110000) {
+ out[0] = ((code >> 18) & 0x07) | 0xF0;
+ out[1] = ((code >> 12) & 0x3F) | 0x80;
+ out[2] = ((code >> 6) & 0x3F) | 0x80;
+ out[3] = ((code >> 0) & 0x3F) | 0x80;
+ return 4;
+ } else {
+ // Encoding error
+ return 0;
+ }
+}
+
+// Encode the Unicode codepoint with UTF-16. The buffer must be large enough
+// to hold the output -- either 1 or 2 elements.
+static inline int encodeUtf16(wchar_t *out, uint32_t code) {
+ if (code < 0x10000) {
+ if (code >= 0xD800 && code <= 0xDFFF) {
+ // The code points 0xD800 to 0xDFFF are reserved for UTF-16
+ // surrogate pairs and do not have an encoding in UTF-16.
+ return 0;
+ }
+ out[0] = code;
+ return 1;
+ } else if (code < 0x110000) {
+ code -= 0x10000;
+ out[0] = 0xD800 | (code >> 10);
+ out[1] = 0xDC00 | (code & 0x3FF);
+ return 2;
+ } else {
+ // Encoding error
+ return 0;
+ }
+}
+
+// Return the byte size of a UTF-8 character using the value of the first
+// byte.
+static inline int utf8CharLength(char firstByte) {
+ // This code would probably be faster if it used __builtin_clz.
+ if ((firstByte & 0x80) == 0) {
+ return 1;
+ } else if ((firstByte & 0xE0) == 0xC0) {
+ return 2;
+ } else if ((firstByte & 0xF0) == 0xE0) {
+ return 3;
+ } else if ((firstByte & 0xF8) == 0xF0) {
+ return 4;
+ } else {
+ // Malformed UTF-8.
+ return 0;
+ }
+}
+
+// The pointer must point to 1-4 bytes, as indicated by the first byte.
+// Returns -1 on decoding error.
+static inline uint32_t decodeUtf8(const char *in) {
+ const uint32_t kInvalid = static_cast<uint32_t>(-1);
+ switch (utf8CharLength(in[0])) {
+ case 1: {
+ return in[0];
+ }
+ case 2: {
+ if ((in[1] & 0xC0) != 0x80) {
+ return kInvalid;
+ }
+ uint32_t tmp = 0;
+ tmp = (in[0] & 0x1F) << 6;
+ tmp |= (in[1] & 0x3F);
+ return tmp <= 0x7F ? kInvalid : tmp;
+ }
+ case 3: {
+ if ((in[1] & 0xC0) != 0x80 ||
+ (in[2] & 0xC0) != 0x80) {
+ return kInvalid;
+ }
+ uint32_t tmp = 0;
+ tmp = (in[0] & 0x0F) << 12;
+ tmp |= (in[1] & 0x3F) << 6;
+ tmp |= (in[2] & 0x3F);
+ if (tmp <= 0x07FF || (tmp >= 0xD800 && tmp <= 0xDFFF)) {
+ return kInvalid;
+ } else {
+ return tmp;
+ }
+ }
+ case 4: {
+ if ((in[1] & 0xC0) != 0x80 ||
+ (in[2] & 0xC0) != 0x80 ||
+ (in[3] & 0xC0) != 0x80) {
+ return kInvalid;
+ }
+ uint32_t tmp = 0;
+ tmp = (in[0] & 0x07) << 18;
+ tmp |= (in[1] & 0x3F) << 12;
+ tmp |= (in[2] & 0x3F) << 6;
+ tmp |= (in[3] & 0x3F);
+ if (tmp <= 0xFFFF || tmp > 0x10FFFF) {
+ return kInvalid;
+ } else {
+ return tmp;
+ }
+ }
+ default: {
+ return kInvalid;
+ }
+ }
+}
+
+static inline uint32_t decodeSurrogatePair(wchar_t ch1, wchar_t ch2) {
+ return ((ch1 - 0xD800) << 10) + (ch2 - 0xDC00) + 0x10000;
+}
+
+#endif // UNICODE_ENCODING_H
diff --git a/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc b/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc
new file mode 100644
index 0000000000..cd4abeb191
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// Encode every code-point using this module and verify that it matches the
+// encoding generated using Windows WideCharToMultiByte.
+
+#include "UnicodeEncoding.h"
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+static void correctnessByCode()
+{
+ char mbstr1[4];
+ char mbstr2[4];
+ wchar_t wch[2];
+ for (unsigned int code = 0; code < 0x110000; ++code) {
+
+ // Surrogate pair reserved region.
+ const bool isReserved = (code >= 0xD800 && code <= 0xDFFF);
+
+ int mblen1 = encodeUtf8(mbstr1, code);
+ if (isReserved ? mblen1 != 0 : mblen1 <= 0) {
+ printf("Error: 0x%04X: mblen1=%d\n", code, mblen1);
+ continue;
+ }
+
+ int wlen = encodeUtf16(wch, code);
+ if (isReserved ? wlen != 0 : wlen <= 0) {
+ printf("Error: 0x%04X: wlen=%d\n", code, wlen);
+ continue;
+ }
+
+ if (isReserved) {
+ continue;
+ }
+
+ if (mblen1 != utf8CharLength(mbstr1[0])) {
+ printf("Error: 0x%04X: mblen1=%d, utf8CharLength(mbstr1[0])=%d\n",
+ code, mblen1, utf8CharLength(mbstr1[0]));
+ continue;
+ }
+
+ if (code != decodeUtf8(mbstr1)) {
+ printf("Error: 0x%04X: decodeUtf8(mbstr1)=%u\n",
+ code, decodeUtf8(mbstr1));
+ continue;
+ }
+
+ int mblen2 = WideCharToMultiByte(CP_UTF8, 0, wch, wlen, mbstr2, 4, NULL, NULL);
+ if (mblen1 != mblen2) {
+ printf("Error: 0x%04X: mblen1=%d, mblen2=%d\n", code, mblen1, mblen2);
+ continue;
+ }
+
+ if (memcmp(mbstr1, mbstr2, mblen1) != 0) {
+ printf("Error: 0x%04x: encodings are different\n", code);
+ continue;
+ }
+ }
+}
+
+static const char *encodingStr(char (&output)[128], char (&buf)[4])
+{
+ sprintf(output, "Encoding %02X %02X %02X %02X",
+ static_cast<uint8_t>(buf[0]),
+ static_cast<uint8_t>(buf[1]),
+ static_cast<uint8_t>(buf[2]),
+ static_cast<uint8_t>(buf[3]));
+ return output;
+}
+
+// This test can take a couple of minutes to run.
+static void correctnessByUtf8Encoding()
+{
+ for (uint64_t encoding = 0; encoding <= 0xFFFFFFFF; ++encoding) {
+
+ char mb[4];
+ mb[0] = encoding;
+ mb[1] = encoding >> 8;
+ mb[2] = encoding >> 16;
+ mb[3] = encoding >> 24;
+
+ const int mblen = utf8CharLength(mb[0]);
+ if (mblen == 0) {
+ continue;
+ }
+
+ // Test this module.
+ const uint32_t code1 = decodeUtf8(mb);
+ wchar_t ws1[2] = {};
+ const int wslen1 = encodeUtf16(ws1, code1);
+
+ // Test using Windows. We can't decode a codepoint directly; we have
+ // to do UTF8->UTF16, then decode the surrogate pair.
+ wchar_t ws2[2] = {};
+ const int wslen2 = MultiByteToWideChar(
+ CP_UTF8, MB_ERR_INVALID_CHARS, mb, mblen, ws2, 2);
+ const uint32_t code2 =
+ (wslen2 == 1 ? ws2[0] :
+ wslen2 == 2 ? decodeSurrogatePair(ws2[0], ws2[1]) :
+ static_cast<uint32_t>(-1));
+
+ // Verify that the two implementations match.
+ char prefix[128];
+ if (code1 != code2) {
+ printf("%s: code1=0x%04x code2=0x%04x\n",
+ encodingStr(prefix, mb),
+ code1, code2);
+ continue;
+ }
+ if (wslen1 != wslen2) {
+ printf("%s: wslen1=%d wslen2=%d\n",
+ encodingStr(prefix, mb),
+ wslen1, wslen2);
+ continue;
+ }
+ if (memcmp(ws1, ws2, wslen1 * sizeof(wchar_t)) != 0) {
+ printf("%s: ws1 != ws2\n", encodingStr(prefix, mb));
+ continue;
+ }
+ }
+}
+
+wchar_t g_wch_TEST[] = { 0xD840, 0xDC00 };
+char g_ch_TEST[4];
+wchar_t *volatile g_pwch = g_wch_TEST;
+char *volatile g_pch = g_ch_TEST;
+unsigned int volatile g_code = 0xA2000;
+
+static void performance()
+{
+ {
+ clock_t start = clock();
+ for (long long i = 0; i < 250000000LL; ++i) {
+ int mblen = WideCharToMultiByte(CP_UTF8, 0, g_pwch, 2, g_pch, 4, NULL, NULL);
+ assert(mblen == 4);
+ }
+ clock_t stop = clock();
+ printf("%.3fns per char\n", (double)(stop - start) / CLOCKS_PER_SEC * 4.0);
+ }
+
+ {
+ clock_t start = clock();
+ for (long long i = 0; i < 3000000000LL; ++i) {
+ int mblen = encodeUtf8(g_pch, g_code);
+ assert(mblen == 4);
+ }
+ clock_t stop = clock();
+ printf("%.3fns per char\n", (double)(stop - start) / CLOCKS_PER_SEC / 3.0);
+ }
+}
+
+int main()
+{
+ printf("Testing correctnessByCode...\n");
+ fflush(stdout);
+ correctnessByCode();
+
+ printf("Testing correctnessByUtf8Encoding... (may take a couple minutes)\n");
+ fflush(stdout);
+ correctnessByUtf8Encoding();
+
+ printf("Testing performance...\n");
+ fflush(stdout);
+ performance();
+
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Win32Console.cc b/src/libs/3rdparty/winpty/src/agent/Win32Console.cc
new file mode 100644
index 0000000000..d53de021f5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Win32Console.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Win32Console.h"
+
+#include <windows.h>
+#include <wchar.h>
+
+#include <string>
+
+#include "../shared/DebugClient.h"
+#include "../shared/WinptyAssert.h"
+
+Win32Console::Win32Console() : m_titleWorkBuf(16)
+{
+ // The console window must be non-NULL. It is used for two purposes:
+ // (1) "Freezing" the console to detect the exact number of lines that
+ // have scrolled.
+ // (2) Killing processes attached to the console, by posting a WM_CLOSE
+ // message to the console window.
+ m_hwnd = GetConsoleWindow();
+ ASSERT(m_hwnd != nullptr);
+}
+
+std::wstring Win32Console::title()
+{
+ while (true) {
+ // Calling GetConsoleTitleW is tricky, because its behavior changed
+ // from XP->Vista, then again from Win7->Win8. The Vista+Win7 behavior
+ // is especially broken.
+ //
+ // The MSDN documentation documents nSize as the "size of the buffer
+ // pointed to by the lpConsoleTitle parameter, in characters" and the
+ // successful return value as "the length of the console window's
+ // title, in characters."
+ //
+ // On XP, the function returns the title length, AFTER truncation
+ // (excluding the NUL terminator). If the title is blank, the API
+ // returns 0 and does not NUL-terminate the buffer. To accommodate
+ // XP, the function must:
+ // * Terminate the buffer itself.
+ // * Double the size of the title buffer in a loop.
+ //
+ // On Vista and up, the function returns the non-truncated title
+ // length (excluding the NUL terminator).
+ //
+ // On Vista and Windows 7, there is a bug where the buffer size is
+ // interpreted as a byte count rather than a wchar_t count. To
+ // work around this, we must pass GetConsoleTitleW a buffer that is
+ // twice as large as what is actually needed.
+ //
+ // See misc/*/Test_GetConsoleTitleW.cc for tests demonstrating Windows'
+ // behavior.
+
+ DWORD count = GetConsoleTitleW(m_titleWorkBuf.data(),
+ m_titleWorkBuf.size());
+ const size_t needed = (count + 1) * sizeof(wchar_t);
+ if (m_titleWorkBuf.size() < needed) {
+ m_titleWorkBuf.resize(needed);
+ continue;
+ }
+ m_titleWorkBuf[count] = L'\0';
+ return m_titleWorkBuf.data();
+ }
+}
+
+void Win32Console::setTitle(const std::wstring &title)
+{
+ if (!SetConsoleTitleW(title.c_str())) {
+ trace("SetConsoleTitleW failed");
+ }
+}
+
+void Win32Console::setFrozen(bool frozen) {
+ const int SC_CONSOLE_MARK = 0xFFF2;
+ const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
+ if (frozen == m_frozen) {
+ // Do nothing.
+ } else if (frozen) {
+ // Enter selection mode by activating either Mark or SelectAll.
+ const int command = m_freezeUsesMark ? SC_CONSOLE_MARK
+ : SC_CONSOLE_SELECT_ALL;
+ SendMessage(m_hwnd, WM_SYSCOMMAND, command, 0);
+ m_frozen = true;
+ } else {
+ // Send Escape to cancel the selection.
+ SendMessage(m_hwnd, WM_CHAR, 27, 0x00010001);
+ m_frozen = false;
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Win32Console.h b/src/libs/3rdparty/winpty/src/agent/Win32Console.h
new file mode 100644
index 0000000000..ed83877e99
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Win32Console.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_WIN32_CONSOLE_H
+#define AGENT_WIN32_CONSOLE_H
+
+#include <windows.h>
+
+#include <string>
+#include <vector>
+
+class Win32Console
+{
+public:
+ class FreezeGuard {
+ public:
+ FreezeGuard(Win32Console &console, bool frozen) :
+ m_console(console), m_previous(console.frozen()) {
+ m_console.setFrozen(frozen);
+ }
+ ~FreezeGuard() {
+ m_console.setFrozen(m_previous);
+ }
+ FreezeGuard(const FreezeGuard &other) = delete;
+ FreezeGuard &operator=(const FreezeGuard &other) = delete;
+ private:
+ Win32Console &m_console;
+ bool m_previous;
+ };
+
+ Win32Console();
+
+ HWND hwnd() { return m_hwnd; }
+ std::wstring title();
+ void setTitle(const std::wstring &title);
+ void setFreezeUsesMark(bool useMark) { m_freezeUsesMark = useMark; }
+ void setNewW10(bool isNewW10) { m_isNewW10 = isNewW10; }
+ bool isNewW10() { return m_isNewW10; }
+ void setFrozen(bool frozen=true);
+ bool frozen() { return m_frozen; }
+
+private:
+ HWND m_hwnd = nullptr;
+ bool m_frozen = false;
+ bool m_freezeUsesMark = false;
+ bool m_isNewW10 = false;
+ std::vector<wchar_t> m_titleWorkBuf;
+};
+
+#endif // AGENT_WIN32_CONSOLE_H
diff --git a/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc
new file mode 100644
index 0000000000..ed93f4081f
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Win32ConsoleBuffer.h"
+
+#include <windows.h>
+
+#include "../shared/DebugClient.h"
+#include "../shared/StringBuilder.h"
+#include "../shared/WinptyAssert.h"
+
+std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::openStdout() {
+ return std::unique_ptr<Win32ConsoleBuffer>(
+ new Win32ConsoleBuffer(GetStdHandle(STD_OUTPUT_HANDLE), false));
+}
+
+std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::openConout() {
+ const HANDLE conout = CreateFileW(L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+ return std::unique_ptr<Win32ConsoleBuffer>(
+ new Win32ConsoleBuffer(conout, true));
+}
+
+std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::createErrorBuffer() {
+ SECURITY_ATTRIBUTES sa = {};
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ const HANDLE conout =
+ CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ CONSOLE_TEXTMODE_BUFFER,
+ nullptr);
+ ASSERT(conout != INVALID_HANDLE_VALUE);
+ return std::unique_ptr<Win32ConsoleBuffer>(
+ new Win32ConsoleBuffer(conout, true));
+}
+
+HANDLE Win32ConsoleBuffer::conout() {
+ return m_conout;
+}
+
+void Win32ConsoleBuffer::clearLines(
+ int row,
+ int count,
+ const ConsoleScreenBufferInfo &info) {
+ // TODO: error handling
+ const int width = info.bufferSize().X;
+ DWORD actual = 0;
+ if (!FillConsoleOutputCharacterW(
+ m_conout, L' ', width * count, Coord(0, row),
+ &actual) || static_cast<int>(actual) != width * count) {
+ trace("FillConsoleOutputCharacterW failed");
+ }
+ if (!FillConsoleOutputAttribute(
+ m_conout, kDefaultAttributes, width * count, Coord(0, row),
+ &actual) || static_cast<int>(actual) != width * count) {
+ trace("FillConsoleOutputAttribute failed");
+ }
+}
+
+void Win32ConsoleBuffer::clearAllLines(const ConsoleScreenBufferInfo &info) {
+ clearLines(0, info.bufferSize().Y, info);
+}
+
+ConsoleScreenBufferInfo Win32ConsoleBuffer::bufferInfo() {
+ // TODO: error handling
+ ConsoleScreenBufferInfo info;
+ if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
+ trace("GetConsoleScreenBufferInfo failed");
+ }
+ return info;
+}
+
+Coord Win32ConsoleBuffer::bufferSize() {
+ return bufferInfo().bufferSize();
+}
+
+SmallRect Win32ConsoleBuffer::windowRect() {
+ return bufferInfo().windowRect();
+}
+
+bool Win32ConsoleBuffer::resizeBufferRange(const Coord &initialSize,
+ Coord &finalSize) {
+ if (SetConsoleScreenBufferSize(m_conout, initialSize)) {
+ finalSize = initialSize;
+ return true;
+ }
+ // The font might be too small to accommodate a very narrow console window.
+ // In that case, rather than simply give up, it's better to try wider
+ // buffer sizes until the call succeeds.
+ Coord size = initialSize;
+ while (size.X < 20) {
+ size.X++;
+ if (SetConsoleScreenBufferSize(m_conout, size)) {
+ finalSize = size;
+ trace("SetConsoleScreenBufferSize: initial size (%d,%d) failed, "
+ "but wider size (%d,%d) succeeded",
+ initialSize.X, initialSize.Y,
+ finalSize.X, finalSize.Y);
+ return true;
+ }
+ }
+ trace("SetConsoleScreenBufferSize failed: "
+ "tried (%d,%d) through (%d,%d)",
+ initialSize.X, initialSize.Y,
+ size.X, size.Y);
+ return false;
+}
+
+void Win32ConsoleBuffer::resizeBuffer(const Coord &size) {
+ // TODO: error handling
+ if (!SetConsoleScreenBufferSize(m_conout, size)) {
+ trace("SetConsoleScreenBufferSize failed: size=(%d,%d)",
+ size.X, size.Y);
+ }
+}
+
+void Win32ConsoleBuffer::moveWindow(const SmallRect &rect) {
+ // TODO: error handling
+ if (!SetConsoleWindowInfo(m_conout, TRUE, &rect)) {
+ trace("SetConsoleWindowInfo failed");
+ }
+}
+
+Coord Win32ConsoleBuffer::cursorPosition() {
+ return bufferInfo().dwCursorPosition;
+}
+
+void Win32ConsoleBuffer::setCursorPosition(const Coord &coord) {
+ // TODO: error handling
+ if (!SetConsoleCursorPosition(m_conout, coord)) {
+ trace("SetConsoleCursorPosition failed");
+ }
+}
+
+void Win32ConsoleBuffer::read(const SmallRect &rect, CHAR_INFO *data) {
+ // TODO: error handling
+ SmallRect tmp(rect);
+ if (!ReadConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp) &&
+ isTracingEnabled()) {
+ StringBuilder sb(256);
+ auto outStruct = [&](const SMALL_RECT &sr) {
+ sb << "{L=" << sr.Left << ",T=" << sr.Top
+ << ",R=" << sr.Right << ",B=" << sr.Bottom << '}';
+ };
+ sb << "Win32ConsoleBuffer::read: ReadConsoleOutput failed: readRegion=";
+ outStruct(rect);
+ CONSOLE_SCREEN_BUFFER_INFO info = {};
+ if (GetConsoleScreenBufferInfo(m_conout, &info)) {
+ sb << ", dwSize=(" << info.dwSize.X << ',' << info.dwSize.Y
+ << "), srWindow=";
+ outStruct(info.srWindow);
+ } else {
+ sb << ", GetConsoleScreenBufferInfo also failed";
+ }
+ trace("%s", sb.c_str());
+ }
+}
+
+void Win32ConsoleBuffer::write(const SmallRect &rect, const CHAR_INFO *data) {
+ // TODO: error handling
+ SmallRect tmp(rect);
+ if (!WriteConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp)) {
+ trace("WriteConsoleOutput failed");
+ }
+}
+
+void Win32ConsoleBuffer::setTextAttribute(WORD attributes) {
+ if (!SetConsoleTextAttribute(m_conout, attributes)) {
+ trace("SetConsoleTextAttribute failed");
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h
new file mode 100644
index 0000000000..a68d8d304f
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef AGENT_WIN32_CONSOLE_BUFFER_H
+#define AGENT_WIN32_CONSOLE_BUFFER_H
+
+#include <windows.h>
+
+#include <string.h>
+
+#include <memory>
+
+#include "Coord.h"
+#include "SmallRect.h"
+
+class ConsoleScreenBufferInfo : public CONSOLE_SCREEN_BUFFER_INFO {
+public:
+ ConsoleScreenBufferInfo()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+
+ Coord bufferSize() const { return dwSize; }
+ SmallRect windowRect() const { return srWindow; }
+ Coord cursorPosition() const { return dwCursorPosition; }
+};
+
+class Win32ConsoleBuffer {
+private:
+ Win32ConsoleBuffer(HANDLE conout, bool owned) :
+ m_conout(conout), m_owned(owned)
+ {
+ }
+
+public:
+ static const int kDefaultAttributes = 7;
+
+ ~Win32ConsoleBuffer() {
+ if (m_owned) {
+ CloseHandle(m_conout);
+ }
+ }
+
+ static std::unique_ptr<Win32ConsoleBuffer> openStdout();
+ static std::unique_ptr<Win32ConsoleBuffer> openConout();
+ static std::unique_ptr<Win32ConsoleBuffer> createErrorBuffer();
+
+ Win32ConsoleBuffer(const Win32ConsoleBuffer &other) = delete;
+ Win32ConsoleBuffer &operator=(const Win32ConsoleBuffer &other) = delete;
+
+ HANDLE conout();
+ void clearLines(int row, int count, const ConsoleScreenBufferInfo &info);
+ void clearAllLines(const ConsoleScreenBufferInfo &info);
+
+ // Buffer and window sizes.
+ ConsoleScreenBufferInfo bufferInfo();
+ Coord bufferSize();
+ SmallRect windowRect();
+ void resizeBuffer(const Coord &size);
+ bool resizeBufferRange(const Coord &initialSize, Coord &finalSize);
+ bool resizeBufferRange(const Coord &initialSize) {
+ Coord dummy;
+ return resizeBufferRange(initialSize, dummy);
+ }
+ void moveWindow(const SmallRect &rect);
+
+ // Cursor.
+ Coord cursorPosition();
+ void setCursorPosition(const Coord &point);
+
+ // Screen content.
+ void read(const SmallRect &rect, CHAR_INFO *data);
+ void write(const SmallRect &rect, const CHAR_INFO *data);
+
+ void setTextAttribute(WORD attributes);
+
+private:
+ HANDLE m_conout = nullptr;
+ bool m_owned = false;
+};
+
+#endif // AGENT_WIN32_CONSOLE_BUFFER_H
diff --git a/src/libs/3rdparty/winpty/src/agent/main.cc b/src/libs/3rdparty/winpty/src/agent/main.cc
new file mode 100644
index 0000000000..427cb3a3aa
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/main.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <wchar.h>
+#include <shellapi.h>
+
+#include "../shared/StringUtil.h"
+#include "../shared/WindowsVersion.h"
+#include "../shared/WinptyAssert.h"
+#include "../shared/WinptyVersion.h"
+
+#include "Agent.h"
+#include "AgentCreateDesktop.h"
+#include "DebugShowInput.h"
+
+const char USAGE[] =
+"Usage: %ls controlPipeName flags mouseMode cols rows\n"
+"Usage: %ls controlPipeName --create-desktop\n"
+"\n"
+"Ordinarily, this program is launched by winpty.dll and is not directly\n"
+"useful to winpty users. However, it also has options intended for\n"
+"debugging winpty.\n"
+"\n"
+"Usage: %ls [options]\n"
+"\n"
+"Options:\n"
+" --show-input [--with-mouse] [--escape-input]\n"
+" Dump INPUT_RECORDs from the console input buffer\n"
+" --with-mouse: Include MOUSE_INPUT_RECORDs in the dump\n"
+" output\n"
+" --escape-input: Direct the new Windows 10 console to use\n"
+" escape sequences for input\n"
+" --version Print the winpty version\n";
+
+static uint64_t winpty_atoi64(const char *str) {
+ return strtoll(str, NULL, 10);
+}
+
+int main() {
+ dumpWindowsVersion();
+ dumpVersionToTrace();
+
+ // Technically, we should free the CommandLineToArgvW return value using
+ // a single call to LocalFree, but the call will never actually happen in
+ // the normal case.
+ int argc = 0;
+ wchar_t *cmdline = GetCommandLineW();
+ ASSERT(cmdline != nullptr && "GetCommandLineW returned NULL");
+ wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
+ ASSERT(argv != nullptr && "CommandLineToArgvW returned NULL");
+
+ if (argc == 2 && !wcscmp(argv[1], L"--version")) {
+ dumpVersionToStdout();
+ return 0;
+ }
+
+ if (argc >= 2 && !wcscmp(argv[1], L"--show-input")) {
+ bool withMouse = false;
+ bool escapeInput = false;
+ for (int i = 2; i < argc; ++i) {
+ if (!wcscmp(argv[i], L"--with-mouse")) {
+ withMouse = true;
+ } else if (!wcscmp(argv[i], L"--escape-input")) {
+ escapeInput = true;
+ } else {
+ fprintf(stderr, "Unrecognized --show-input option: %ls\n",
+ argv[i]);
+ return 1;
+ }
+ }
+ debugShowInput(withMouse, escapeInput);
+ return 0;
+ }
+
+ if (argc == 3 && !wcscmp(argv[2], L"--create-desktop")) {
+ handleCreateDesktop(argv[1]);
+ return 0;
+ }
+
+ if (argc != 6) {
+ fprintf(stderr, USAGE, argv[0], argv[0], argv[0]);
+ return 1;
+ }
+
+ Agent agent(argv[1],
+ winpty_atoi64(utf8FromWide(argv[2]).c_str()),
+ atoi(utf8FromWide(argv[3]).c_str()),
+ atoi(utf8FromWide(argv[4]).c_str()),
+ atoi(utf8FromWide(argv[5]).c_str()));
+ agent.run();
+
+ // The Agent destructor shouldn't return, but if it does, exit
+ // unsuccessfully.
+ return 1;
+}
diff --git a/src/libs/3rdparty/winpty/src/agent/subdir.mk b/src/libs/3rdparty/winpty/src/agent/subdir.mk
new file mode 100644
index 0000000000..1c7d37e3e5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/subdir.mk
@@ -0,0 +1,61 @@
+# Copyright (c) 2011-2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+ALL_TARGETS += build/winpty-agent.exe
+
+$(eval $(call def_mingw_target,agent,-DWINPTY_AGENT_ASSERT))
+
+AGENT_OBJECTS = \
+ build/agent/agent/Agent.o \
+ build/agent/agent/AgentCreateDesktop.o \
+ build/agent/agent/ConsoleFont.o \
+ build/agent/agent/ConsoleInput.o \
+ build/agent/agent/ConsoleInputReencoding.o \
+ build/agent/agent/ConsoleLine.o \
+ build/agent/agent/DebugShowInput.o \
+ build/agent/agent/DefaultInputMap.o \
+ build/agent/agent/EventLoop.o \
+ build/agent/agent/InputMap.o \
+ build/agent/agent/LargeConsoleRead.o \
+ build/agent/agent/NamedPipe.o \
+ build/agent/agent/Scraper.o \
+ build/agent/agent/Terminal.o \
+ build/agent/agent/Win32Console.o \
+ build/agent/agent/Win32ConsoleBuffer.o \
+ build/agent/agent/main.o \
+ build/agent/shared/BackgroundDesktop.o \
+ build/agent/shared/Buffer.o \
+ build/agent/shared/DebugClient.o \
+ build/agent/shared/GenRandom.o \
+ build/agent/shared/OwnedHandle.o \
+ build/agent/shared/StringUtil.o \
+ build/agent/shared/WindowsSecurity.o \
+ build/agent/shared/WindowsVersion.o \
+ build/agent/shared/WinptyAssert.o \
+ build/agent/shared/WinptyException.o \
+ build/agent/shared/WinptyVersion.o
+
+build/agent/shared/WinptyVersion.o : build/gen/GenVersion.h
+
+build/winpty-agent.exe : $(AGENT_OBJECTS)
+ $(info Linking $@)
+ @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^
+
+-include $(AGENT_OBJECTS:.o=.d)
diff --git a/src/libs/3rdparty/winpty/src/configurations.gypi b/src/libs/3rdparty/winpty/src/configurations.gypi
new file mode 100644
index 0000000000..e990a60338
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/configurations.gypi
@@ -0,0 +1,60 @@
+# By default gyp/msbuild build for 32-bit Windows. This gyp include file
+# defines configurations for both 32-bit and 64-bit Windows. To use it, run:
+#
+# C:\...\winpty\src>gyp -I configurations.gypi
+#
+# This command generates Visual Studio project files with a Release
+# configuration and two Platforms--Win32 and x64. Both can be built:
+#
+# C:\...\winpty\src>msbuild winpty.sln /p:Platform=Win32
+# C:\...\winpty\src>msbuild winpty.sln /p:Platform=x64
+#
+# The output is placed in:
+#
+# C:\...\winpty\src\Release\Win32
+# C:\...\winpty\src\Release\x64
+#
+# Windows XP note: By default, the project files will use the default "toolset"
+# for the given MSVC version. For MSVC 2013 and MSVC 2015, the default toolset
+# generates binaries that do not run on Windows XP. To target Windows XP,
+# select the XP-specific toolset by passing
+# -D WINPTY_MSBUILD_TOOLSET={v120_xp,v140_xp} to gyp (v120_xp == MSVC 2013,
+# v140_xp == MSVC 2015). Unfortunately, it isn't possible to have a single
+# project file with configurations for both XP and post-XP. This seems to be a
+# limitation of the MSVC project file format.
+#
+# This file is not included by default, because I suspect it would interfere
+# with node-gyp, which has a different system for building 32-vs-64-bit
+# binaries. It uses a common.gypi, and the project files it generates can only
+# build a single architecture, the output paths are not differentiated by
+# architecture.
+
+{
+ 'variables': {
+ 'WINPTY_MSBUILD_TOOLSET%': '',
+ },
+ 'target_defaults': {
+ 'default_configuration': 'Release_Win32',
+ 'configurations': {
+ 'Release_Win32': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Release_x64': {
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ 'msvs_configuration_attributes': {
+ 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)\\$(Platform)',
+ 'IntermediateDirectory': '$(ConfigurationName)\\$(Platform)\\obj\\$(ProjectName)',
+ },
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '1', # /SUBSYSTEM:CONSOLE
+ },
+ 'VCCLCompilerTool': {
+ 'RuntimeLibrary': '0', # MultiThreaded (/MT)
+ },
+ },
+ 'msbuild_toolset' : '<(WINPTY_MSBUILD_TOOLSET)',
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc b/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc
new file mode 100644
index 0000000000..353d31c1c6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <cstdio>
+#include <cstdlib>
+
+#include <windows.h>
+
+#include "../shared/WindowsSecurity.h"
+#include "../shared/WinptyException.h"
+
+const wchar_t *kPipeName = L"\\\\.\\pipe\\DebugServer";
+
+// A message may not be larger than this size.
+const int MSG_SIZE = 4096;
+
+static void usage(const char *program, int code) {
+ printf("Usage: %s [--everyone]\n"
+ "\n"
+ "Creates the named pipe %ls and reads messages. Prints each\n"
+ "message to stdout. By default, only the current user can send messages.\n"
+ "Pass --everyone to let anyone send a message.\n"
+ "\n"
+ "Use the WINPTY_DEBUG environment variable to enable winpty trace output.\n"
+ "(e.g. WINPTY_DEBUG=trace for the default trace output.) Set WINPTYDBG=1\n"
+ "to enable trace with older winpty versions.\n",
+ program, kPipeName);
+ exit(code);
+}
+
+int main(int argc, char *argv[]) {
+ bool everyone = false;
+ for (int i = 1; i < argc; ++i) {
+ std::string arg = argv[i];
+ if (arg == "--everyone") {
+ everyone = true;
+ } else if (arg == "-h" || arg == "--help") {
+ usage(argv[0], 0);
+ } else {
+ usage(argv[0], 1);
+ }
+ }
+
+ SecurityDescriptor sd;
+ PSECURITY_ATTRIBUTES psa = nullptr;
+ SECURITY_ATTRIBUTES sa = {};
+ if (everyone) {
+ try {
+ sd = createPipeSecurityDescriptorOwnerFullControlEveryoneWrite();
+ } catch (const WinptyException &e) {
+ fprintf(stderr,
+ "error creating security descriptor: %ls\n", e.what());
+ exit(1);
+ }
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = sd.get();
+ psa = &sa;
+ }
+
+ HANDLE serverPipe = CreateNamedPipeW(
+ kPipeName,
+ /*dwOpenMode=*/PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ /*dwPipeMode=*/PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE |
+ rejectRemoteClientsPipeFlag(),
+ /*nMaxInstances=*/1,
+ /*nOutBufferSize=*/MSG_SIZE,
+ /*nInBufferSize=*/MSG_SIZE,
+ /*nDefaultTimeOut=*/10 * 1000,
+ psa);
+
+ if (serverPipe == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "error: could not create %ls pipe: error %u\n",
+ kPipeName, static_cast<unsigned>(GetLastError()));
+ exit(1);
+ }
+
+ char msgBuffer[MSG_SIZE + 1];
+
+ while (true) {
+ if (!ConnectNamedPipe(serverPipe, nullptr)) {
+ fprintf(stderr, "error: ConnectNamedPipe failed\n");
+ fflush(stderr);
+ exit(1);
+ }
+ DWORD bytesRead = 0;
+ if (!ReadFile(serverPipe, msgBuffer, MSG_SIZE, &bytesRead, nullptr)) {
+ fprintf(stderr, "error: ReadFile on pipe failed\n");
+ fflush(stderr);
+ DisconnectNamedPipe(serverPipe);
+ continue;
+ }
+ msgBuffer[bytesRead] = '\n';
+ fwrite(msgBuffer, 1, bytesRead + 1, stdout);
+ fflush(stdout);
+
+ DWORD bytesWritten = 0;
+ WriteFile(serverPipe, "OK", 2, &bytesWritten, nullptr);
+ DisconnectNamedPipe(serverPipe);
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/debugserver/subdir.mk b/src/libs/3rdparty/winpty/src/debugserver/subdir.mk
new file mode 100644
index 0000000000..beed1bd597
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/debugserver/subdir.mk
@@ -0,0 +1,41 @@
+# Copyright (c) 2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+ALL_TARGETS += build/winpty-debugserver.exe
+
+$(eval $(call def_mingw_target,debugserver,))
+
+DEBUGSERVER_OBJECTS = \
+ build/debugserver/debugserver/DebugServer.o \
+ build/debugserver/shared/DebugClient.o \
+ build/debugserver/shared/OwnedHandle.o \
+ build/debugserver/shared/StringUtil.o \
+ build/debugserver/shared/WindowsSecurity.o \
+ build/debugserver/shared/WindowsVersion.o \
+ build/debugserver/shared/WinptyAssert.o \
+ build/debugserver/shared/WinptyException.o
+
+build/debugserver/shared/WindowsVersion.o : build/gen/GenVersion.h
+
+build/winpty-debugserver.exe : $(DEBUGSERVER_OBJECTS)
+ $(info Linking $@)
+ @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^
+
+-include $(DEBUGSERVER_OBJECTS:.o=.d)
diff --git a/src/libs/3rdparty/winpty/src/include/winpty.h b/src/libs/3rdparty/winpty/src/include/winpty.h
new file mode 100644
index 0000000000..fdfe4bca21
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/include/winpty.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011-2016 Ryan Prichard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef WINPTY_H
+#define WINPTY_H
+
+#include <windows.h>
+
+#include "winpty_constants.h"
+
+/* On 32-bit Windows, winpty functions have the default __cdecl (not __stdcall)
+ * calling convention. (64-bit Windows has only a single calling convention.)
+ * When compiled with __declspec(dllexport), with either MinGW or MSVC, the
+ * winpty functions are unadorned--no underscore prefix or '@nn' suffix--so
+ * GetProcAddress can be used easily. */
+#ifdef COMPILING_WINPTY_DLL
+#define WINPTY_API __declspec(dllexport)
+#else
+#define WINPTY_API __declspec(dllimport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The winpty API uses wide characters, instead of UTF-8, to avoid conversion
+ * complications related to surrogates. Windows generally tolerates unpaired
+ * surrogates in text, which makes conversion to and from UTF-8 ambiguous and
+ * complicated. (There are different UTF-8 variants that deal with UTF-16
+ * surrogates differently.) */
+
+
+
+/*****************************************************************************
+ * Error handling. */
+
+/* All the APIs have an optional winpty_error_t output parameter. If a
+ * non-NULL argument is specified, then either the API writes NULL to the
+ * value (on success) or writes a newly allocated winpty_error_t object. The
+ * object must be freed using winpty_error_free. */
+
+/* An error object. */
+typedef struct winpty_error_s winpty_error_t;
+typedef winpty_error_t *winpty_error_ptr_t;
+
+/* An error code -- one of WINPTY_ERROR_xxx. */
+typedef DWORD winpty_result_t;
+
+/* Gets the error code from the error object. */
+WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err);
+
+/* Returns a textual representation of the error. The string is freed when
+ * the error is freed. */
+WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err);
+
+/* Free the error object. Every error returned from the winpty API must be
+ * freed. */
+WINPTY_API void winpty_error_free(winpty_error_ptr_t err);
+
+
+
+/*****************************************************************************
+ * Configuration of a new agent. */
+
+/* The winpty_config_t object is not thread-safe. */
+typedef struct winpty_config_s winpty_config_t;
+
+/* Allocate a winpty_config_t value. Returns NULL on error. There are no
+ * required settings -- the object may immediately be used. agentFlags is a
+ * set of zero or more WINPTY_FLAG_xxx values. An unrecognized flag results
+ * in an assertion failure. */
+WINPTY_API winpty_config_t *
+winpty_config_new(UINT64 agentFlags, winpty_error_ptr_t *err /*OPTIONAL*/);
+
+/* Free the cfg object after passing it to winpty_open. */
+WINPTY_API void winpty_config_free(winpty_config_t *cfg);
+
+WINPTY_API void
+winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows);
+
+/* Set the mouse mode to one of the WINPTY_MOUSE_MODE_xxx constants. */
+WINPTY_API void
+winpty_config_set_mouse_mode(winpty_config_t *cfg, int mouseMode);
+
+/* Amount of time to wait for the agent to startup and to wait for any given
+ * agent RPC request. Must be greater than 0. Can be INFINITE. */
+WINPTY_API void
+winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs);
+
+
+
+/*****************************************************************************
+ * Start the agent. */
+
+/* The winpty_t object is thread-safe. */
+typedef struct winpty_s winpty_t;
+
+/* Starts the agent. Returns NULL on error. This process will connect to the
+ * agent over a control pipe, and the agent will open data pipes (e.g. CONIN
+ * and CONOUT). */
+WINPTY_API winpty_t *
+winpty_open(const winpty_config_t *cfg,
+ winpty_error_ptr_t *err /*OPTIONAL*/);
+
+/* A handle to the agent process. This value is valid for the lifetime of the
+ * winpty_t object. Do not close it. */
+WINPTY_API HANDLE winpty_agent_process(winpty_t *wp);
+
+
+
+/*****************************************************************************
+ * I/O pipes. */
+
+/* Returns the names of named pipes used for terminal I/O. Each input or
+ * output direction uses a different half-duplex pipe. The agent creates
+ * these pipes, and the client can connect to them using ordinary I/O methods.
+ * The strings are freed when the winpty_t object is freed.
+ *
+ * winpty_conerr_name returns NULL unless WINPTY_FLAG_CONERR is specified.
+ *
+ * N.B.: CreateFile does not block when connecting to a local server pipe. If
+ * the server pipe does not exist or is already connected, then it fails
+ * instantly. */
+WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp);
+WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp);
+WINPTY_API LPCWSTR winpty_conerr_name(winpty_t *wp);
+
+
+
+/*****************************************************************************
+ * winpty agent RPC call: process creation. */
+
+/* The winpty_spawn_config_t object is not thread-safe. */
+typedef struct winpty_spawn_config_s winpty_spawn_config_t;
+
+/* winpty_spawn_config strings do not need to live as long as the config
+ * object. They are copied. Returns NULL on error. spawnFlags is a set of
+ * zero or more WINPTY_SPAWN_FLAG_xxx values. An unrecognized flag results in
+ * an assertion failure.
+ *
+ * env is a a pointer to an environment block like that passed to
+ * CreateProcess--a contiguous array of NUL-terminated "VAR=VAL" strings
+ * followed by a final NUL terminator.
+ *
+ * N.B.: If you want to gather all of the child's output, you may want the
+ * WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN flag.
+ */
+WINPTY_API winpty_spawn_config_t *
+winpty_spawn_config_new(UINT64 spawnFlags,
+ LPCWSTR appname /*OPTIONAL*/,
+ LPCWSTR cmdline /*OPTIONAL*/,
+ LPCWSTR cwd /*OPTIONAL*/,
+ LPCWSTR env /*OPTIONAL*/,
+ winpty_error_ptr_t *err /*OPTIONAL*/);
+
+/* Free the cfg object after passing it to winpty_spawn. */
+WINPTY_API void winpty_spawn_config_free(winpty_spawn_config_t *cfg);
+
+/*
+ * Spawns the new process.
+ *
+ * The function initializes all output parameters to zero or NULL.
+ *
+ * On success, the function returns TRUE. For each of process_handle and
+ * thread_handle that is non-NULL, the HANDLE returned from CreateProcess is
+ * duplicated from the agent and returned to the winpty client. The client is
+ * responsible for closing these HANDLES.
+ *
+ * On failure, the function returns FALSE, and if err is non-NULL, then *err
+ * is set to an error object.
+ *
+ * If the agent's CreateProcess call failed, then *create_process_error is set
+ * to GetLastError(), and the WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED error
+ * is returned.
+ *
+ * winpty_spawn can only be called once per winpty_t object. If it is called
+ * before the output data pipe(s) is/are connected, then collected output is
+ * buffered until the pipes are connected, rather than being discarded.
+ *
+ * N.B.: GetProcessId works even if the process has exited. The PID is not
+ * recycled until the NT process object is freed.
+ * (https://blogs.msdn.microsoft.com/oldnewthing/20110107-00/?p=11803)
+ */
+WINPTY_API BOOL
+winpty_spawn(winpty_t *wp,
+ const winpty_spawn_config_t *cfg,
+ HANDLE *process_handle /*OPTIONAL*/,
+ HANDLE *thread_handle /*OPTIONAL*/,
+ DWORD *create_process_error /*OPTIONAL*/,
+ winpty_error_ptr_t *err /*OPTIONAL*/);
+
+
+
+/*****************************************************************************
+ * winpty agent RPC calls: everything else */
+
+/* Change the size of the Windows console window. */
+WINPTY_API BOOL
+winpty_set_size(winpty_t *wp, int cols, int rows,
+ winpty_error_ptr_t *err /*OPTIONAL*/);
+
+/* Gets a list of processes attached to the console. */
+WINPTY_API int
+winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount,
+ winpty_error_ptr_t *err /*OPTIONAL*/);
+
+/* Frees the winpty_t object and the OS resources contained in it. This
+ * call breaks the connection with the agent, which should then close its
+ * console, terminating the processes attached to it.
+ *
+ * This function must not be called if any other threads are using the
+ * winpty_t object. Undefined behavior results. */
+WINPTY_API void winpty_free(winpty_t *wp);
+
+
+
+/****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WINPTY_H */
diff --git a/src/libs/3rdparty/winpty/src/include/winpty_constants.h b/src/libs/3rdparty/winpty/src/include/winpty_constants.h
new file mode 100644
index 0000000000..11e34cf171
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/include/winpty_constants.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016 Ryan Prichard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef WINPTY_CONSTANTS_H
+#define WINPTY_CONSTANTS_H
+
+/*
+ * You may want to include winpty.h instead, which includes this header.
+ *
+ * This file is split out from winpty.h so that the agent can access the
+ * winpty flags without also declaring the libwinpty APIs.
+ */
+
+/*****************************************************************************
+ * Error codes. */
+
+#define WINPTY_ERROR_SUCCESS 0
+#define WINPTY_ERROR_OUT_OF_MEMORY 1
+#define WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED 2
+#define WINPTY_ERROR_LOST_CONNECTION 3
+#define WINPTY_ERROR_AGENT_EXE_MISSING 4
+#define WINPTY_ERROR_UNSPECIFIED 5
+#define WINPTY_ERROR_AGENT_DIED 6
+#define WINPTY_ERROR_AGENT_TIMEOUT 7
+#define WINPTY_ERROR_AGENT_CREATION_FAILED 8
+
+
+
+/*****************************************************************************
+ * Configuration of a new agent. */
+
+/* Create a new screen buffer (connected to the "conerr" terminal pipe) and
+ * pass it to child processes as the STDERR handle. This flag also prevents
+ * the agent from reopening CONOUT$ when it polls -- regardless of whether the
+ * active screen buffer changes, winpty continues to monitor the original
+ * primary screen buffer. */
+#define WINPTY_FLAG_CONERR 0x1ull
+
+/* Don't output escape sequences. */
+#define WINPTY_FLAG_PLAIN_OUTPUT 0x2ull
+
+/* Do output color escape sequences. These escapes are output by default, but
+ * are suppressed with WINPTY_FLAG_PLAIN_OUTPUT. Use this flag to reenable
+ * them. */
+#define WINPTY_FLAG_COLOR_ESCAPES 0x4ull
+
+/* On XP and Vista, winpty needs to put the hidden console on a desktop in a
+ * service window station so that its polling does not interfere with other
+ * (visible) console windows. To create this desktop, it must change the
+ * process' window station (i.e. SetProcessWindowStation) for the duration of
+ * the winpty_open call. In theory, this change could interfere with the
+ * winpty client (e.g. other threads, spawning children), so winpty by default
+ * spawns a special agent process to create the hidden desktop. Spawning
+ * processes on Windows is slow, though, so if
+ * WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION is set, winpty changes this
+ * process' window station instead.
+ * See https://github.com/rprichard/winpty/issues/58. */
+#define WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION 0x8ull
+
+#define WINPTY_FLAG_MASK (0ull \
+ | WINPTY_FLAG_CONERR \
+ | WINPTY_FLAG_PLAIN_OUTPUT \
+ | WINPTY_FLAG_COLOR_ESCAPES \
+ | WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION \
+)
+
+/* QuickEdit mode is initially disabled, and the agent does not send mouse
+ * mode sequences to the terminal. If it receives mouse input, though, it
+ * still writes MOUSE_EVENT_RECORD values into CONIN. */
+#define WINPTY_MOUSE_MODE_NONE 0
+
+/* QuickEdit mode is initially enabled. As CONIN enters or leaves mouse
+ * input mode (i.e. where ENABLE_MOUSE_INPUT is on and ENABLE_QUICK_EDIT_MODE
+ * is off), the agent enables or disables mouse input on the terminal.
+ *
+ * This is the default mode. */
+#define WINPTY_MOUSE_MODE_AUTO 1
+
+/* QuickEdit mode is initially disabled, and the agent enables the terminal's
+ * mouse input mode. It does not disable terminal mouse mode (until exit). */
+#define WINPTY_MOUSE_MODE_FORCE 2
+
+
+
+/*****************************************************************************
+ * winpty agent RPC call: process creation. */
+
+/* If the spawn is marked "auto-shutdown", then the agent shuts down console
+ * output once the process exits. The agent stops polling for new console
+ * output, and once all pending data has been written to the output pipe, the
+ * agent closes the pipe. (At that point, the pipe may still have data in it,
+ * which the client may read. Once all the data has been read, further reads
+ * return EOF.) */
+#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ull
+
+/* After the agent shuts down output, and after all output has been written
+ * into the pipe(s), exit the agent by closing the console. If there any
+ * surviving processes still attached to the console, they are killed.
+ *
+ * Note: With this flag, an RPC call (e.g. winpty_set_size) issued after the
+ * agent exits will fail with an I/O or dead-agent error. */
+#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
+
+/* All the spawn flags. */
+#define WINPTY_SPAWN_FLAG_MASK (0ull \
+ | WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN \
+ | WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN \
+)
+
+
+
+#endif /* WINPTY_CONSTANTS_H */
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc
new file mode 100644
index 0000000000..82d00b2da2
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "AgentLocation.h"
+
+#include <windows.h>
+
+#include <string>
+
+#include "../shared/WinptyAssert.h"
+
+#include "LibWinptyException.h"
+
+#define AGENT_EXE L"winpty-agent.exe"
+
+static HMODULE getCurrentModule() {
+ HMODULE module;
+ if (!GetModuleHandleExW(
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ reinterpret_cast<LPCWSTR>(getCurrentModule),
+ &module)) {
+ ASSERT(false && "GetModuleHandleEx failed");
+ }
+ return module;
+}
+
+static std::wstring getModuleFileName(HMODULE module) {
+ const int bufsize = 4096;
+ wchar_t path[bufsize];
+ int size = GetModuleFileNameW(module, path, bufsize);
+ ASSERT(size != 0 && size != bufsize);
+ return std::wstring(path);
+}
+
+static std::wstring dirname(const std::wstring &path) {
+ std::wstring::size_type pos = path.find_last_of(L"\\/");
+ if (pos == std::wstring::npos) {
+ return L"";
+ } else {
+ return path.substr(0, pos);
+ }
+}
+
+static bool pathExists(const std::wstring &path) {
+ return GetFileAttributesW(path.c_str()) != 0xFFFFFFFF;
+}
+
+std::wstring findAgentProgram() {
+ std::wstring progDir = dirname(getModuleFileName(getCurrentModule()));
+ std::wstring ret = progDir + (L"\\" AGENT_EXE);
+ if (!pathExists(ret)) {
+ throw LibWinptyException(
+ WINPTY_ERROR_AGENT_EXE_MISSING,
+ (L"agent executable does not exist: '" + ret + L"'").c_str());
+ }
+ return ret;
+}
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h
new file mode 100644
index 0000000000..a96b854cd2
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBWINPTY_AGENT_LOCATION_H
+#define LIBWINPTY_AGENT_LOCATION_H
+
+#include <string>
+
+std::wstring findAgentProgram();
+
+#endif // LIBWINPTY_AGENT_LOCATION_H
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h b/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h
new file mode 100644
index 0000000000..2274798d23
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIB_WINPTY_EXCEPTION_H
+#define LIB_WINPTY_EXCEPTION_H
+
+#include "../include/winpty.h"
+
+#include "../shared/WinptyException.h"
+
+#include <memory>
+#include <string>
+
+class LibWinptyException : public WinptyException {
+public:
+ LibWinptyException(winpty_result_t code, const wchar_t *what) :
+ m_code(code), m_what(std::make_shared<std::wstring>(what)) {}
+
+ winpty_result_t code() const WINPTY_NOEXCEPT {
+ return m_code;
+ }
+
+ const wchar_t *what() const WINPTY_NOEXCEPT override {
+ return m_what->c_str();
+ }
+
+ std::shared_ptr<std::wstring> whatSharedStr() const WINPTY_NOEXCEPT {
+ return m_what;
+ }
+
+private:
+ winpty_result_t m_code;
+ // Using a shared_ptr ensures that copying the object raises no exception.
+ std::shared_ptr<std::wstring> m_what;
+};
+
+#endif // LIB_WINPTY_EXCEPTION_H
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h b/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h
new file mode 100644
index 0000000000..93e992d5c5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBWINPTY_WINPTY_INTERNAL_H
+#define LIBWINPTY_WINPTY_INTERNAL_H
+
+#include <memory>
+#include <string>
+
+#include "../include/winpty.h"
+
+#include "../shared/Mutex.h"
+#include "../shared/OwnedHandle.h"
+
+// The structures in this header are not intended to be accessed directly by
+// client programs.
+
+struct winpty_error_s {
+ winpty_result_t code;
+ const wchar_t *msgStatic;
+ // Use a pointer to a std::shared_ptr so that the struct remains simple
+ // enough to statically initialize, for the benefit of static error
+ // objects like kOutOfMemory.
+ std::shared_ptr<std::wstring> *msgDynamic;
+};
+
+struct winpty_config_s {
+ uint64_t flags = 0;
+ int cols = 80;
+ int rows = 25;
+ int mouseMode = WINPTY_MOUSE_MODE_AUTO;
+ DWORD timeoutMs = 30000;
+};
+
+struct winpty_s {
+ Mutex mutex;
+ OwnedHandle agentProcess;
+ OwnedHandle controlPipe;
+ DWORD agentTimeoutMs = 0;
+ OwnedHandle ioEvent;
+ std::wstring spawnDesktopName;
+ std::wstring coninPipeName;
+ std::wstring conoutPipeName;
+ std::wstring conerrPipeName;
+};
+
+struct winpty_spawn_config_s {
+ uint64_t winptyFlags = 0;
+ std::wstring appname;
+ std::wstring cmdline;
+ std::wstring cwd;
+ std::wstring env;
+};
+
+#endif // LIBWINPTY_WINPTY_INTERNAL_H
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk b/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk
new file mode 100644
index 0000000000..ba32bad6e6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk
@@ -0,0 +1,46 @@
+# Copyright (c) 2011-2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+ALL_TARGETS += build/winpty.dll
+
+$(eval $(call def_mingw_target,libwinpty,-DCOMPILING_WINPTY_DLL))
+
+LIBWINPTY_OBJECTS = \
+ build/libwinpty/libwinpty/AgentLocation.o \
+ build/libwinpty/libwinpty/winpty.o \
+ build/libwinpty/shared/BackgroundDesktop.o \
+ build/libwinpty/shared/Buffer.o \
+ build/libwinpty/shared/DebugClient.o \
+ build/libwinpty/shared/GenRandom.o \
+ build/libwinpty/shared/OwnedHandle.o \
+ build/libwinpty/shared/StringUtil.o \
+ build/libwinpty/shared/WindowsSecurity.o \
+ build/libwinpty/shared/WindowsVersion.o \
+ build/libwinpty/shared/WinptyAssert.o \
+ build/libwinpty/shared/WinptyException.o \
+ build/libwinpty/shared/WinptyVersion.o
+
+build/libwinpty/shared/WinptyVersion.o : build/gen/GenVersion.h
+
+build/winpty.dll : $(LIBWINPTY_OBJECTS)
+ $(info Linking $@)
+ @$(MINGW_CXX) $(MINGW_LDFLAGS) -shared -o $@ $^ -Wl,--out-implib,build/winpty.lib
+
+-include $(LIBWINPTY_OBJECTS:.o=.d)
diff --git a/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc b/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc
new file mode 100644
index 0000000000..3d977498ef
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc
@@ -0,0 +1,970 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <windows.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "../include/winpty.h"
+
+#include "../shared/AgentMsg.h"
+#include "../shared/BackgroundDesktop.h"
+#include "../shared/Buffer.h"
+#include "../shared/DebugClient.h"
+#include "../shared/GenRandom.h"
+#include "../shared/OwnedHandle.h"
+#include "../shared/StringBuilder.h"
+#include "../shared/StringUtil.h"
+#include "../shared/WindowsSecurity.h"
+#include "../shared/WindowsVersion.h"
+#include "../shared/WinptyAssert.h"
+#include "../shared/WinptyException.h"
+#include "../shared/WinptyVersion.h"
+
+#include "AgentLocation.h"
+#include "LibWinptyException.h"
+#include "WinptyInternal.h"
+
+
+
+/*****************************************************************************
+ * Error handling -- translate C++ exceptions to an optional error object
+ * output and log the result. */
+
+static const winpty_error_s kOutOfMemory = {
+ WINPTY_ERROR_OUT_OF_MEMORY,
+ L"Out of memory",
+ nullptr
+};
+
+static const winpty_error_s kBadRpcPacket = {
+ WINPTY_ERROR_UNSPECIFIED,
+ L"Bad RPC packet",
+ nullptr
+};
+
+static const winpty_error_s kUncaughtException = {
+ WINPTY_ERROR_UNSPECIFIED,
+ L"Uncaught C++ exception",
+ nullptr
+};
+
+/* Gets the error code from the error object. */
+WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err) {
+ return err != nullptr ? err->code : WINPTY_ERROR_SUCCESS;
+}
+
+/* Returns a textual representation of the error. The string is freed when
+ * the error is freed. */
+WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err) {
+ if (err != nullptr) {
+ if (err->msgStatic != nullptr) {
+ return err->msgStatic;
+ } else {
+ ASSERT(err->msgDynamic != nullptr);
+ std::wstring *msgPtr = err->msgDynamic->get();
+ ASSERT(msgPtr != nullptr);
+ return msgPtr->c_str();
+ }
+ } else {
+ return L"Success";
+ }
+}
+
+/* Free the error object. Every error returned from the winpty API must be
+ * freed. */
+WINPTY_API void winpty_error_free(winpty_error_ptr_t err) {
+ if (err != nullptr && err->msgDynamic != nullptr) {
+ delete err->msgDynamic;
+ delete err;
+ }
+}
+
+static void translateException(winpty_error_ptr_t *&err) {
+ winpty_error_ptr_t ret = nullptr;
+ try {
+ try {
+ throw;
+ } catch (const ReadBuffer::DecodeError&) {
+ ret = const_cast<winpty_error_ptr_t>(&kBadRpcPacket);
+ } catch (const LibWinptyException &e) {
+ std::unique_ptr<winpty_error_t> obj(new winpty_error_t);
+ obj->code = e.code();
+ obj->msgStatic = nullptr;
+ obj->msgDynamic =
+ new std::shared_ptr<std::wstring>(e.whatSharedStr());
+ ret = obj.release();
+ } catch (const WinptyException &e) {
+ std::unique_ptr<winpty_error_t> obj(new winpty_error_t);
+ std::shared_ptr<std::wstring> msg(new std::wstring(e.what()));
+ obj->code = WINPTY_ERROR_UNSPECIFIED;
+ obj->msgStatic = nullptr;
+ obj->msgDynamic = new std::shared_ptr<std::wstring>(msg);
+ ret = obj.release();
+ }
+ } catch (const std::bad_alloc&) {
+ ret = const_cast<winpty_error_ptr_t>(&kOutOfMemory);
+ } catch (...) {
+ ret = const_cast<winpty_error_ptr_t>(&kUncaughtException);
+ }
+ trace("libwinpty error: code=%u msg='%s'",
+ static_cast<unsigned>(ret->code),
+ utf8FromWide(winpty_error_msg(ret)).c_str());
+ if (err != nullptr) {
+ *err = ret;
+ } else {
+ winpty_error_free(ret);
+ }
+}
+
+#define API_TRY \
+ if (err != nullptr) { *err = nullptr; } \
+ try
+
+#define API_CATCH(ret) \
+ catch (...) { translateException(err); return (ret); }
+
+
+
+/*****************************************************************************
+ * Configuration of a new agent. */
+
+WINPTY_API winpty_config_t *
+winpty_config_new(UINT64 flags, winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT((flags & WINPTY_FLAG_MASK) == flags);
+ std::unique_ptr<winpty_config_t> ret(new winpty_config_t);
+ ret->flags = flags;
+ return ret.release();
+ } API_CATCH(nullptr)
+}
+
+WINPTY_API void winpty_config_free(winpty_config_t *cfg) {
+ delete cfg;
+}
+
+WINPTY_API void
+winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows) {
+ ASSERT(cfg != nullptr && cols > 0 && rows > 0);
+ cfg->cols = cols;
+ cfg->rows = rows;
+}
+
+WINPTY_API void
+winpty_config_set_mouse_mode(winpty_config_t *cfg, int mouseMode) {
+ ASSERT(cfg != nullptr &&
+ mouseMode >= WINPTY_MOUSE_MODE_NONE &&
+ mouseMode <= WINPTY_MOUSE_MODE_FORCE);
+ cfg->mouseMode = mouseMode;
+}
+
+WINPTY_API void
+winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs) {
+ ASSERT(cfg != nullptr && timeoutMs > 0);
+ cfg->timeoutMs = timeoutMs;
+}
+
+
+
+/*****************************************************************************
+ * Agent I/O. */
+
+namespace {
+
+// Once an I/O operation fails with ERROR_IO_PENDING, the caller *must* wait
+// for it to complete, even after calling CancelIo on it! See
+// https://blogs.msdn.microsoft.com/oldnewthing/20110202-00/?p=11613. This
+// class enforces that requirement.
+class PendingIo {
+ HANDLE m_file;
+ OVERLAPPED &m_over;
+ bool m_finished;
+public:
+ // The file handle and OVERLAPPED object must live as long as the PendingIo
+ // object.
+ PendingIo(HANDLE file, OVERLAPPED &over) :
+ m_file(file), m_over(over), m_finished(false) {}
+ ~PendingIo() {
+ if (!m_finished) {
+ // We're not usually that interested in CancelIo's return value.
+ // In any case, we must not throw an exception in this dtor.
+ CancelIo(m_file);
+ waitForCompletion();
+ }
+ }
+ std::tuple<BOOL, DWORD> waitForCompletion(DWORD &actual) WINPTY_NOEXCEPT {
+ m_finished = true;
+ const BOOL success =
+ GetOverlappedResult(m_file, &m_over, &actual, TRUE);
+ return std::make_tuple(success, GetLastError());
+ }
+ std::tuple<BOOL, DWORD> waitForCompletion() WINPTY_NOEXCEPT {
+ DWORD actual = 0;
+ return waitForCompletion(actual);
+ }
+};
+
+} // anonymous namespace
+
+static void handlePendingIo(winpty_t &wp, OVERLAPPED &over, BOOL &success,
+ DWORD &lastError, DWORD &actual) {
+ if (!success && lastError == ERROR_IO_PENDING) {
+ PendingIo io(wp.controlPipe.get(), over);
+ const HANDLE waitHandles[2] = { wp.ioEvent.get(),
+ wp.agentProcess.get() };
+ DWORD waitRet = WaitForMultipleObjects(
+ 2, waitHandles, FALSE, wp.agentTimeoutMs);
+ if (waitRet != WAIT_OBJECT_0) {
+ // The I/O is still pending. Cancel it, close the I/O event, and
+ // throw an exception.
+ if (waitRet == WAIT_OBJECT_0 + 1) {
+ throw LibWinptyException(WINPTY_ERROR_AGENT_DIED, L"agent died");
+ } else if (waitRet == WAIT_TIMEOUT) {
+ throw LibWinptyException(WINPTY_ERROR_AGENT_TIMEOUT,
+ L"agent timed out");
+ } else if (waitRet == WAIT_FAILED) {
+ throwWindowsError(L"WaitForMultipleObjects failed");
+ } else {
+ ASSERT(false &&
+ "unexpected WaitForMultipleObjects return value");
+ }
+ }
+ std::tie(success, lastError) = io.waitForCompletion(actual);
+ }
+}
+
+static void handlePendingIo(winpty_t &wp, OVERLAPPED &over, BOOL &success,
+ DWORD &lastError) {
+ DWORD actual = 0;
+ handlePendingIo(wp, over, success, lastError, actual);
+}
+
+static void handleReadWriteErrors(winpty_t &wp, BOOL success, DWORD lastError,
+ const wchar_t *genericErrMsg) {
+ if (!success) {
+ // If the pipe connection is broken after it's been connected, then
+ // later I/O operations fail with ERROR_BROKEN_PIPE (reads) or
+ // ERROR_NO_DATA (writes). With Wine, they may also fail with
+ // ERROR_PIPE_NOT_CONNECTED. See this gist[1].
+ //
+ // [1] https://gist.github.com/rprichard/8dd8ca134b39534b7da2733994aa07ba
+ if (lastError == ERROR_BROKEN_PIPE || lastError == ERROR_NO_DATA ||
+ lastError == ERROR_PIPE_NOT_CONNECTED) {
+ throw LibWinptyException(WINPTY_ERROR_LOST_CONNECTION,
+ L"lost connection to agent");
+ } else {
+ throwWindowsError(genericErrMsg, lastError);
+ }
+ }
+}
+
+// Calls ConnectNamedPipe to wait until the agent connects to the control pipe.
+static void
+connectControlPipe(winpty_t &wp) {
+ OVERLAPPED over = {};
+ over.hEvent = wp.ioEvent.get();
+ BOOL success = ConnectNamedPipe(wp.controlPipe.get(), &over);
+ DWORD lastError = GetLastError();
+ handlePendingIo(wp, over, success, lastError);
+ if (!success && lastError == ERROR_PIPE_CONNECTED) {
+ success = TRUE;
+ }
+ if (!success) {
+ throwWindowsError(L"ConnectNamedPipe failed", lastError);
+ }
+}
+
+static void writeData(winpty_t &wp, const void *data, size_t amount) {
+ // Perform a single pipe write.
+ DWORD actual = 0;
+ OVERLAPPED over = {};
+ over.hEvent = wp.ioEvent.get();
+ BOOL success = WriteFile(wp.controlPipe.get(), data, amount,
+ &actual, &over);
+ DWORD lastError = GetLastError();
+ if (!success) {
+ handlePendingIo(wp, over, success, lastError, actual);
+ handleReadWriteErrors(wp, success, lastError, L"WriteFile failed");
+ ASSERT(success);
+ }
+ // TODO: Can a partial write actually happen somehow?
+ ASSERT(actual == amount && "WriteFile wrote fewer bytes than requested");
+}
+
+static inline WriteBuffer newPacket() {
+ WriteBuffer packet;
+ packet.putRawValue<uint64_t>(0); // Reserve space for size.
+ return packet;
+}
+
+static void writePacket(winpty_t &wp, WriteBuffer &packet) {
+ const auto &buf = packet.buf();
+ packet.replaceRawValue<uint64_t>(0, buf.size());
+ writeData(wp, buf.data(), buf.size());
+}
+
+static size_t readData(winpty_t &wp, void *data, size_t amount) {
+ DWORD actual = 0;
+ OVERLAPPED over = {};
+ over.hEvent = wp.ioEvent.get();
+ BOOL success = ReadFile(wp.controlPipe.get(), data, amount,
+ &actual, &over);
+ DWORD lastError = GetLastError();
+ if (!success) {
+ handlePendingIo(wp, over, success, lastError, actual);
+ handleReadWriteErrors(wp, success, lastError, L"ReadFile failed");
+ }
+ return actual;
+}
+
+static void readAll(winpty_t &wp, void *data, size_t amount) {
+ while (amount > 0) {
+ const size_t chunk = readData(wp, data, amount);
+ ASSERT(chunk <= amount && "readData result is larger than amount");
+ data = reinterpret_cast<char*>(data) + chunk;
+ amount -= chunk;
+ }
+}
+
+static uint64_t readUInt64(winpty_t &wp) {
+ uint64_t ret = 0;
+ readAll(wp, &ret, sizeof(ret));
+ return ret;
+}
+
+// Returns a reply packet's payload.
+static ReadBuffer readPacket(winpty_t &wp) {
+ const uint64_t packetSize = readUInt64(wp);
+ if (packetSize < sizeof(packetSize) || packetSize > SIZE_MAX) {
+ throwWinptyException(L"Agent RPC error: invalid packet size");
+ }
+ const size_t payloadSize = packetSize - sizeof(packetSize);
+ std::vector<char> bytes(payloadSize);
+ readAll(wp, bytes.data(), bytes.size());
+ return ReadBuffer(std::move(bytes));
+}
+
+static OwnedHandle createControlPipe(const std::wstring &name) {
+ const auto sd = createPipeSecurityDescriptorOwnerFullControl();
+ if (!sd) {
+ throwWinptyException(
+ L"could not create the control pipe's SECURITY_DESCRIPTOR");
+ }
+ SECURITY_ATTRIBUTES sa = {};
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = sd.get();
+ HANDLE ret = CreateNamedPipeW(name.c_str(),
+ /*dwOpenMode=*/
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_FIRST_PIPE_INSTANCE |
+ FILE_FLAG_OVERLAPPED,
+ /*dwPipeMode=*/rejectRemoteClientsPipeFlag(),
+ /*nMaxInstances=*/1,
+ /*nOutBufferSize=*/8192,
+ /*nInBufferSize=*/256,
+ /*nDefaultTimeOut=*/30000,
+ &sa);
+ if (ret == INVALID_HANDLE_VALUE) {
+ throwWindowsError(L"CreateNamedPipeW failed");
+ }
+ return OwnedHandle(ret);
+}
+
+
+
+/*****************************************************************************
+ * Start the agent. */
+
+static OwnedHandle createEvent() {
+ // manual reset, initially unset
+ HANDLE h = CreateEventW(nullptr, TRUE, FALSE, nullptr);
+ if (h == nullptr) {
+ throwWindowsError(L"CreateEventW failed");
+ }
+ return OwnedHandle(h);
+}
+
+// For debugging purposes, provide a way to keep the console on the main window
+// station, visible.
+static bool shouldShowConsoleWindow() {
+ char buf[32];
+ return GetEnvironmentVariableA("WINPTY_SHOW_CONSOLE", buf, sizeof(buf)) > 0;
+}
+
+static bool shouldCreateBackgroundDesktop(bool &createUsingAgent) {
+ // Prior to Windows 7, winpty's repeated selection-deselection loop
+ // prevented the user from interacting with their *visible* console
+ // windows, unless we placed the console onto a background desktop.
+ // The SetProcessWindowStation call interferes with the clipboard and
+ // isn't thread-safe, though[1]. The call should perhaps occur in a
+ // special agent subprocess. Spawning a process in a background desktop
+ // also breaks ConEmu, but marking the process SW_HIDE seems to correct
+ // that[2].
+ //
+ // Windows 7 moved a lot of console handling out of csrss.exe and into
+ // a per-console conhost.exe process, which may explain why it isn't
+ // affected.
+ //
+ // This is a somewhat risky change, so there are low-level flags to
+ // assist in debugging if there are issues.
+ //
+ // [1] https://github.com/rprichard/winpty/issues/58
+ // [2] https://github.com/rprichard/winpty/issues/70
+ bool ret = !shouldShowConsoleWindow() && !isAtLeastWindows7();
+ const bool force = hasDebugFlag("force_desktop");
+ const bool force_spawn = hasDebugFlag("force_desktop_spawn");
+ const bool force_curproc = hasDebugFlag("force_desktop_curproc");
+ const bool suppress = hasDebugFlag("no_desktop");
+ if (force + force_spawn + force_curproc + suppress > 1) {
+ trace("error: Only one of force_desktop, force_desktop_spawn, "
+ "force_desktop_curproc, and no_desktop may be set");
+ } else if (force) {
+ ret = true;
+ } else if (force_spawn) {
+ ret = true;
+ createUsingAgent = true;
+ } else if (force_curproc) {
+ ret = true;
+ createUsingAgent = false;
+ } else if (suppress) {
+ ret = false;
+ }
+ return ret;
+}
+
+static bool shouldSpecifyHideFlag() {
+ const bool force = hasDebugFlag("force_sw_hide");
+ const bool suppress = hasDebugFlag("no_sw_hide");
+ bool ret = !shouldShowConsoleWindow();
+ if (force && suppress) {
+ trace("error: Both the force_sw_hide and no_sw_hide flags are set");
+ } else if (force) {
+ ret = true;
+ } else if (suppress) {
+ ret = false;
+ }
+ return ret;
+}
+
+static OwnedHandle startAgentProcess(
+ const std::wstring &desktop,
+ const std::wstring &controlPipeName,
+ const std::wstring &params,
+ DWORD creationFlags,
+ DWORD &agentPid) {
+ const std::wstring exePath = findAgentProgram();
+ const std::wstring cmdline =
+ (WStringBuilder(256)
+ << L"\"" << exePath << L"\" "
+ << controlPipeName << L' '
+ << params).str_moved();
+
+ auto cmdlineV = vectorWithNulFromString(cmdline);
+ auto desktopV = vectorWithNulFromString(desktop);
+
+ // Start the agent.
+ STARTUPINFOW sui = {};
+ sui.cb = sizeof(sui);
+ sui.lpDesktop = desktop.empty() ? nullptr : desktopV.data();
+
+ if (shouldSpecifyHideFlag()) {
+ sui.dwFlags |= STARTF_USESHOWWINDOW;
+ sui.wShowWindow = SW_HIDE;
+ }
+ PROCESS_INFORMATION pi = {};
+ const BOOL success =
+ CreateProcessW(exePath.c_str(),
+ cmdlineV.data(),
+ nullptr, nullptr,
+ /*bInheritHandles=*/FALSE,
+ /*dwCreationFlags=*/creationFlags,
+ nullptr, nullptr,
+ &sui, &pi);
+ if (!success) {
+ const DWORD lastError = GetLastError();
+ const auto errStr =
+ (WStringBuilder(256)
+ << L"winpty-agent CreateProcess failed: cmdline='" << cmdline
+ << L"' err=0x" << whexOfInt(lastError)).str_moved();
+ throw LibWinptyException(
+ WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str());
+ }
+ CloseHandle(pi.hThread);
+ TRACE("Created agent successfully, pid=%u, cmdline=%s",
+ static_cast<unsigned int>(pi.dwProcessId),
+ utf8FromWide(cmdline).c_str());
+ agentPid = pi.dwProcessId;
+ return OwnedHandle(pi.hProcess);
+}
+
+static void verifyPipeClientPid(HANDLE serverPipe, DWORD agentPid) {
+ const auto client = getNamedPipeClientProcessId(serverPipe);
+ const auto success = std::get<0>(client);
+ const auto lastError = std::get<2>(client);
+ if (success == GetNamedPipeClientProcessId_Result::Success) {
+ const auto clientPid = std::get<1>(client);
+ if (clientPid != agentPid) {
+ WStringBuilder errMsg;
+ errMsg << L"Security check failed: pipe client pid (" << clientPid
+ << L") does not match agent pid (" << agentPid << L")";
+ throwWinptyException(errMsg.c_str());
+ }
+ } else if (success == GetNamedPipeClientProcessId_Result::UnsupportedOs) {
+ trace("Pipe client PID security check skipped: "
+ "GetNamedPipeClientProcessId unsupported on this OS version");
+ } else {
+ throwWindowsError(L"GetNamedPipeClientProcessId failed", lastError);
+ }
+}
+
+static std::unique_ptr<winpty_t>
+createAgentSession(const winpty_config_t *cfg,
+ const std::wstring &desktop,
+ const std::wstring &params,
+ DWORD creationFlags) {
+ std::unique_ptr<winpty_t> wp(new winpty_t);
+ wp->agentTimeoutMs = cfg->timeoutMs;
+ wp->ioEvent = createEvent();
+
+ // Create control server pipe.
+ const auto pipeName =
+ L"\\\\.\\pipe\\winpty-control-" + GenRandom().uniqueName();
+ wp->controlPipe = createControlPipe(pipeName);
+
+ DWORD agentPid = 0;
+ wp->agentProcess = startAgentProcess(
+ desktop, pipeName, params, creationFlags, agentPid);
+ connectControlPipe(*wp.get());
+ verifyPipeClientPid(wp->controlPipe.get(), agentPid);
+
+ return std::move(wp);
+}
+
+namespace {
+
+class AgentDesktop {
+public:
+ virtual std::wstring name() = 0;
+ virtual ~AgentDesktop() {}
+};
+
+class AgentDesktopDirect : public AgentDesktop {
+public:
+ AgentDesktopDirect(BackgroundDesktop &&desktop) :
+ m_desktop(std::move(desktop))
+ {
+ }
+ std::wstring name() override { return m_desktop.desktopName(); }
+private:
+ BackgroundDesktop m_desktop;
+};
+
+class AgentDesktopIndirect : public AgentDesktop {
+public:
+ AgentDesktopIndirect(std::unique_ptr<winpty_t> &&wp,
+ std::wstring &&desktopName) :
+ m_wp(std::move(wp)),
+ m_desktopName(std::move(desktopName))
+ {
+ }
+ std::wstring name() override { return m_desktopName; }
+private:
+ std::unique_ptr<winpty_t> m_wp;
+ std::wstring m_desktopName;
+};
+
+} // anonymous namespace
+
+std::unique_ptr<AgentDesktop>
+setupBackgroundDesktop(const winpty_config_t *cfg) {
+ bool useDesktopAgent =
+ !(cfg->flags & WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION);
+ const bool useDesktop = shouldCreateBackgroundDesktop(useDesktopAgent);
+
+ if (!useDesktop) {
+ return std::unique_ptr<AgentDesktop>();
+ }
+
+ if (useDesktopAgent) {
+ auto wp = createAgentSession(
+ cfg, std::wstring(), L"--create-desktop", DETACHED_PROCESS);
+
+ // Read the desktop name.
+ auto packet = readPacket(*wp.get());
+ auto desktopName = packet.getWString();
+ packet.assertEof();
+
+ if (desktopName.empty()) {
+ return std::unique_ptr<AgentDesktop>();
+ } else {
+ return std::unique_ptr<AgentDesktop>(
+ new AgentDesktopIndirect(std::move(wp),
+ std::move(desktopName)));
+ }
+ } else {
+ try {
+ BackgroundDesktop desktop;
+ return std::unique_ptr<AgentDesktop>(new AgentDesktopDirect(
+ std::move(desktop)));
+ } catch (const WinptyException &e) {
+ trace("Error: failed to create background desktop, "
+ "using original desktop instead: %s",
+ utf8FromWide(e.what()).c_str());
+ return std::unique_ptr<AgentDesktop>();
+ }
+ }
+}
+
+WINPTY_API winpty_t *
+winpty_open(const winpty_config_t *cfg,
+ winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT(cfg != nullptr);
+ dumpWindowsVersion();
+ dumpVersionToTrace();
+
+ // Setup a background desktop for the agent.
+ auto desktop = setupBackgroundDesktop(cfg);
+ const auto desktopName = desktop ? desktop->name() : std::wstring();
+
+ // Start the primary agent session.
+ const auto params =
+ (WStringBuilder(128)
+ << cfg->flags << L' '
+ << cfg->mouseMode << L' '
+ << cfg->cols << L' '
+ << cfg->rows).str_moved();
+ auto wp = createAgentSession(cfg, desktopName, params,
+ CREATE_NEW_CONSOLE);
+
+ // Close handles to the background desktop and restore the original
+ // window station. This must wait until we know the agent is running
+ // -- if we close these handles too soon, then the desktop and
+ // windowstation will be destroyed before the agent can connect with
+ // them.
+ //
+ // If we used a separate agent process to create the desktop, we
+ // disconnect from that process here, allowing it to exit.
+ desktop.reset();
+
+ // If we ran the agent process on a background desktop, then when we
+ // spawn a child process from the agent, it will need to be explicitly
+ // placed back onto the original desktop.
+ if (!desktopName.empty()) {
+ wp->spawnDesktopName = getCurrentDesktopName();
+ }
+
+ // Get the CONIN/CONOUT pipe names.
+ auto packet = readPacket(*wp.get());
+ wp->coninPipeName = packet.getWString();
+ wp->conoutPipeName = packet.getWString();
+ if (cfg->flags & WINPTY_FLAG_CONERR) {
+ wp->conerrPipeName = packet.getWString();
+ }
+ packet.assertEof();
+
+ return wp.release();
+ } API_CATCH(nullptr)
+}
+
+WINPTY_API HANDLE winpty_agent_process(winpty_t *wp) {
+ ASSERT(wp != nullptr);
+ return wp->agentProcess.get();
+}
+
+
+
+/*****************************************************************************
+ * I/O pipes. */
+
+static const wchar_t *cstrFromWStringOrNull(const std::wstring &str) {
+ try {
+ return str.c_str();
+ } catch (const std::bad_alloc&) {
+ return nullptr;
+ }
+}
+
+WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp) {
+ ASSERT(wp != nullptr);
+ return cstrFromWStringOrNull(wp->coninPipeName);
+}
+
+WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp) {
+ ASSERT(wp != nullptr);
+ return cstrFromWStringOrNull(wp->conoutPipeName);
+}
+
+WINPTY_API LPCWSTR winpty_conerr_name(winpty_t *wp) {
+ ASSERT(wp != nullptr);
+ if (wp->conerrPipeName.empty()) {
+ return nullptr;
+ } else {
+ return cstrFromWStringOrNull(wp->conerrPipeName);
+ }
+}
+
+
+
+/*****************************************************************************
+ * winpty agent RPC calls. */
+
+namespace {
+
+// Close the control pipe if something goes wrong with the pipe communication,
+// which could leave the control pipe in an inconsistent state.
+class RpcOperation {
+public:
+ RpcOperation(winpty_t &wp) : m_wp(wp) {
+ if (m_wp.controlPipe.get() == nullptr) {
+ throwWinptyException(L"Agent shutdown due to RPC failure");
+ }
+ }
+ ~RpcOperation() {
+ if (!m_success) {
+ trace("~RpcOperation: Closing control pipe");
+ m_wp.controlPipe.dispose(true);
+ }
+ }
+ void success() { m_success = true; }
+private:
+ winpty_t &m_wp;
+ bool m_success = false;
+};
+
+} // anonymous namespace
+
+
+
+/*****************************************************************************
+ * winpty agent RPC call: process creation. */
+
+// Return a std::wstring containing every character of the environment block.
+// Typically, the block is non-empty, so the std::wstring returned ends with
+// two NUL terminators. (These two terminators are counted in size(), so
+// calling c_str() produces a triply-terminated string.)
+static std::wstring wstringFromEnvBlock(const wchar_t *env) {
+ std::wstring envStr;
+ if (env != NULL) {
+ const wchar_t *p = env;
+ while (*p != L'\0') {
+ p += wcslen(p) + 1;
+ }
+ p++;
+ envStr.assign(env, p);
+
+ // Assuming the environment was non-empty, envStr now ends with two NUL
+ // terminators.
+ //
+ // If the environment were empty, though, then envStr would only be
+ // singly terminated, but the MSDN documentation thinks an env block is
+ // always doubly-terminated, so add an extra NUL just in case it
+ // matters.
+ const auto envStrSz = envStr.size();
+ if (envStrSz == 1) {
+ ASSERT(envStr[0] == L'\0');
+ envStr.push_back(L'\0');
+ } else {
+ ASSERT(envStrSz >= 3);
+ ASSERT(envStr[envStrSz - 3] != L'\0');
+ ASSERT(envStr[envStrSz - 2] == L'\0');
+ ASSERT(envStr[envStrSz - 1] == L'\0');
+ }
+ }
+ return envStr;
+}
+
+WINPTY_API winpty_spawn_config_t *
+winpty_spawn_config_new(UINT64 winptyFlags,
+ LPCWSTR appname /*OPTIONAL*/,
+ LPCWSTR cmdline /*OPTIONAL*/,
+ LPCWSTR cwd /*OPTIONAL*/,
+ LPCWSTR env /*OPTIONAL*/,
+ winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT((winptyFlags & WINPTY_SPAWN_FLAG_MASK) == winptyFlags);
+ std::unique_ptr<winpty_spawn_config_t> cfg(new winpty_spawn_config_t);
+ cfg->winptyFlags = winptyFlags;
+ if (appname != nullptr) { cfg->appname = appname; }
+ if (cmdline != nullptr) { cfg->cmdline = cmdline; }
+ if (cwd != nullptr) { cfg->cwd = cwd; }
+ if (env != nullptr) { cfg->env = wstringFromEnvBlock(env); }
+ return cfg.release();
+ } API_CATCH(nullptr)
+}
+
+WINPTY_API void winpty_spawn_config_free(winpty_spawn_config_t *cfg) {
+ delete cfg;
+}
+
+// It's safe to truncate a handle from 64-bits to 32-bits, or to sign-extend it
+// back to 64-bits. See the MSDN article, "Interprocess Communication Between
+// 32-bit and 64-bit Applications".
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203.aspx
+static inline HANDLE handleFromInt64(int64_t i) {
+ return reinterpret_cast<HANDLE>(static_cast<intptr_t>(i));
+}
+
+// Given a process and a handle in that process, duplicate the handle into the
+// current process and close it in the originating process.
+static inline OwnedHandle stealHandle(HANDLE process, HANDLE handle) {
+ HANDLE result = nullptr;
+ if (!DuplicateHandle(process, handle,
+ GetCurrentProcess(),
+ &result, 0, FALSE,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ throwWindowsError(L"DuplicateHandle of process handle");
+ }
+ return OwnedHandle(result);
+}
+
+WINPTY_API BOOL
+winpty_spawn(winpty_t *wp,
+ const winpty_spawn_config_t *cfg,
+ HANDLE *process_handle /*OPTIONAL*/,
+ HANDLE *thread_handle /*OPTIONAL*/,
+ DWORD *create_process_error /*OPTIONAL*/,
+ winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT(wp != nullptr && cfg != nullptr);
+
+ if (process_handle != nullptr) { *process_handle = nullptr; }
+ if (thread_handle != nullptr) { *thread_handle = nullptr; }
+ if (create_process_error != nullptr) { *create_process_error = 0; }
+
+ LockGuard<Mutex> lock(wp->mutex);
+ RpcOperation rpc(*wp);
+
+ // Send spawn request.
+ auto packet = newPacket();
+ packet.putInt32(AgentMsg::StartProcess);
+ packet.putInt64(cfg->winptyFlags);
+ packet.putInt32(process_handle != nullptr);
+ packet.putInt32(thread_handle != nullptr);
+ packet.putWString(cfg->appname);
+ packet.putWString(cfg->cmdline);
+ packet.putWString(cfg->cwd);
+ packet.putWString(cfg->env);
+ packet.putWString(wp->spawnDesktopName);
+ writePacket(*wp, packet);
+
+ // Receive reply.
+ auto reply = readPacket(*wp);
+ const auto result = static_cast<StartProcessResult>(reply.getInt32());
+ if (result == StartProcessResult::CreateProcessFailed) {
+ const DWORD lastError = reply.getInt32();
+ reply.assertEof();
+ if (create_process_error != nullptr) {
+ *create_process_error = lastError;
+ }
+ rpc.success();
+ throw LibWinptyException(WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED,
+ L"CreateProcess failed");
+ } else if (result == StartProcessResult::ProcessCreated) {
+ const HANDLE remoteProcess = handleFromInt64(reply.getInt64());
+ const HANDLE remoteThread = handleFromInt64(reply.getInt64());
+ reply.assertEof();
+ OwnedHandle localProcess;
+ OwnedHandle localThread;
+ if (remoteProcess != nullptr) {
+ localProcess =
+ stealHandle(wp->agentProcess.get(), remoteProcess);
+ }
+ if (remoteThread != nullptr) {
+ localThread =
+ stealHandle(wp->agentProcess.get(), remoteThread);
+ }
+ if (process_handle != nullptr) {
+ *process_handle = localProcess.release();
+ }
+ if (thread_handle != nullptr) {
+ *thread_handle = localThread.release();
+ }
+ rpc.success();
+ } else {
+ throwWinptyException(
+ L"Agent RPC error: invalid StartProcessResult");
+ }
+ return TRUE;
+ } API_CATCH(FALSE)
+}
+
+
+
+/*****************************************************************************
+ * winpty agent RPC calls: everything else */
+
+WINPTY_API BOOL
+winpty_set_size(winpty_t *wp, int cols, int rows,
+ winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT(wp != nullptr && cols > 0 && rows > 0);
+ LockGuard<Mutex> lock(wp->mutex);
+ RpcOperation rpc(*wp);
+ auto packet = newPacket();
+ packet.putInt32(AgentMsg::SetSize);
+ packet.putInt32(cols);
+ packet.putInt32(rows);
+ writePacket(*wp, packet);
+ readPacket(*wp).assertEof();
+ rpc.success();
+ return TRUE;
+ } API_CATCH(FALSE)
+}
+
+WINPTY_API int
+winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount,
+ winpty_error_ptr_t *err /*OPTIONAL*/) {
+ API_TRY {
+ ASSERT(wp != nullptr);
+ ASSERT(processList != nullptr);
+ LockGuard<Mutex> lock(wp->mutex);
+ RpcOperation rpc(*wp);
+ auto packet = newPacket();
+ packet.putInt32(AgentMsg::GetConsoleProcessList);
+ writePacket(*wp, packet);
+ auto reply = readPacket(*wp);
+
+ auto actualProcessCount = reply.getInt32();
+
+ if (actualProcessCount <= processCount) {
+ for (auto i = 0; i < actualProcessCount; i++) {
+ processList[i] = reply.getInt32();
+ }
+ }
+
+ reply.assertEof();
+ rpc.success();
+ return actualProcessCount;
+ } API_CATCH(0)
+}
+
+WINPTY_API void winpty_free(winpty_t *wp) {
+ // At least in principle, CloseHandle can fail, so this deletion can
+ // fail. It won't throw an exception, but maybe there's an error that
+ // should be propagated?
+ delete wp;
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/AgentMsg.h b/src/libs/3rdparty/winpty/src/shared/AgentMsg.h
new file mode 100644
index 0000000000..ab60c6b961
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/AgentMsg.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_AGENT_MSG_H
+#define WINPTY_SHARED_AGENT_MSG_H
+
+struct AgentMsg
+{
+ enum Type {
+ StartProcess,
+ SetSize,
+ GetConsoleProcessList,
+ };
+};
+
+enum class StartProcessResult {
+ CreateProcessFailed,
+ ProcessCreated,
+};
+
+#endif // WINPTY_SHARED_AGENT_MSG_H
diff --git a/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc
new file mode 100644
index 0000000000..1bea7e53dd
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "BackgroundDesktop.h"
+
+#include <memory>
+
+#include "DebugClient.h"
+#include "StringUtil.h"
+#include "WinptyException.h"
+
+namespace {
+
+static std::wstring getObjectName(HANDLE object) {
+ BOOL success;
+ DWORD lengthNeeded = 0;
+ GetUserObjectInformationW(object, UOI_NAME,
+ nullptr, 0,
+ &lengthNeeded);
+ ASSERT(lengthNeeded % sizeof(wchar_t) == 0);
+ std::unique_ptr<wchar_t[]> tmp(
+ new wchar_t[lengthNeeded / sizeof(wchar_t)]);
+ success = GetUserObjectInformationW(object, UOI_NAME,
+ tmp.get(), lengthNeeded,
+ nullptr);
+ if (!success) {
+ throwWindowsError(L"GetUserObjectInformationW failed");
+ }
+ return std::wstring(tmp.get());
+}
+
+static std::wstring getDesktopName(HWINSTA winsta, HDESK desk) {
+ return getObjectName(winsta) + L"\\" + getObjectName(desk);
+}
+
+} // anonymous namespace
+
+// Get a non-interactive window station for the agent.
+// TODO: review security w.r.t. windowstation and desktop.
+BackgroundDesktop::BackgroundDesktop() {
+ try {
+ m_originalStation = GetProcessWindowStation();
+ if (m_originalStation == nullptr) {
+ throwWindowsError(
+ L"BackgroundDesktop ctor: "
+ L"GetProcessWindowStation returned NULL");
+ }
+ m_newStation =
+ CreateWindowStationW(nullptr, 0, WINSTA_ALL_ACCESS, nullptr);
+ if (m_newStation == nullptr) {
+ throwWindowsError(
+ L"BackgroundDesktop ctor: CreateWindowStationW returned NULL");
+ }
+ if (!SetProcessWindowStation(m_newStation)) {
+ throwWindowsError(
+ L"BackgroundDesktop ctor: SetProcessWindowStation failed");
+ }
+ m_newDesktop = CreateDesktopW(
+ L"Default", nullptr, nullptr, 0, GENERIC_ALL, nullptr);
+ if (m_newDesktop == nullptr) {
+ throwWindowsError(
+ L"BackgroundDesktop ctor: CreateDesktopW failed");
+ }
+ m_newDesktopName = getDesktopName(m_newStation, m_newDesktop);
+ TRACE("Created background desktop: %s",
+ utf8FromWide(m_newDesktopName).c_str());
+ } catch (...) {
+ dispose();
+ throw;
+ }
+}
+
+void BackgroundDesktop::dispose() WINPTY_NOEXCEPT {
+ if (m_originalStation != nullptr) {
+ SetProcessWindowStation(m_originalStation);
+ m_originalStation = nullptr;
+ }
+ if (m_newDesktop != nullptr) {
+ CloseDesktop(m_newDesktop);
+ m_newDesktop = nullptr;
+ }
+ if (m_newStation != nullptr) {
+ CloseWindowStation(m_newStation);
+ m_newStation = nullptr;
+ }
+}
+
+std::wstring getCurrentDesktopName() {
+ // MSDN says that the handles returned by GetProcessWindowStation and
+ // GetThreadDesktop do not need to be passed to CloseWindowStation and
+ // CloseDesktop, respectively.
+ const HWINSTA winsta = GetProcessWindowStation();
+ if (winsta == nullptr) {
+ throwWindowsError(
+ L"getCurrentDesktopName: "
+ L"GetProcessWindowStation returned NULL");
+ }
+ const HDESK desk = GetThreadDesktop(GetCurrentThreadId());
+ if (desk == nullptr) {
+ throwWindowsError(
+ L"getCurrentDesktopName: "
+ L"GetThreadDesktop returned NULL");
+ }
+ return getDesktopName(winsta, desk);
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h
new file mode 100644
index 0000000000..c692e57dc4
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_BACKGROUND_DESKTOP_H
+#define WINPTY_SHARED_BACKGROUND_DESKTOP_H
+
+#include <windows.h>
+
+#include <string>
+
+#include "WinptyException.h"
+
+class BackgroundDesktop {
+public:
+ BackgroundDesktop();
+ ~BackgroundDesktop() { dispose(); }
+ void dispose() WINPTY_NOEXCEPT;
+ const std::wstring &desktopName() const { return m_newDesktopName; }
+
+ BackgroundDesktop(const BackgroundDesktop &other) = delete;
+ BackgroundDesktop &operator=(const BackgroundDesktop &other) = delete;
+
+ // We can't default the move constructor and assignment operator with
+ // MSVC 2013. We *could* if we required at least MSVC 2015 to build.
+
+ BackgroundDesktop(BackgroundDesktop &&other) :
+ m_originalStation(other.m_originalStation),
+ m_newStation(other.m_newStation),
+ m_newDesktop(other.m_newDesktop),
+ m_newDesktopName(std::move(other.m_newDesktopName)) {
+ other.m_originalStation = nullptr;
+ other.m_newStation = nullptr;
+ other.m_newDesktop = nullptr;
+ }
+ BackgroundDesktop &operator=(BackgroundDesktop &&other) {
+ dispose();
+ m_originalStation = other.m_originalStation;
+ m_newStation = other.m_newStation;
+ m_newDesktop = other.m_newDesktop;
+ m_newDesktopName = std::move(other.m_newDesktopName);
+ other.m_originalStation = nullptr;
+ other.m_newStation = nullptr;
+ other.m_newDesktop = nullptr;
+ return *this;
+ }
+
+private:
+ HWINSTA m_originalStation = nullptr;
+ HWINSTA m_newStation = nullptr;
+ HDESK m_newDesktop = nullptr;
+ std::wstring m_newDesktopName;
+};
+
+std::wstring getCurrentDesktopName();
+
+#endif // WINPTY_SHARED_BACKGROUND_DESKTOP_H
diff --git a/src/libs/3rdparty/winpty/src/shared/Buffer.cc b/src/libs/3rdparty/winpty/src/shared/Buffer.cc
new file mode 100644
index 0000000000..158a629d56
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/Buffer.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Buffer.h"
+
+#include <stdint.h>
+
+#include "DebugClient.h"
+#include "WinptyAssert.h"
+
+// Define the READ_BUFFER_CHECK() macro. It *must* evaluate its condition,
+// exactly once.
+#define READ_BUFFER_CHECK(cond) \
+ do { \
+ if (!(cond)) { \
+ trace("decode error: %s", #cond); \
+ throw DecodeError(); \
+ } \
+ } while (false)
+
+enum class Piece : uint8_t { Int32, Int64, WString };
+
+void WriteBuffer::putRawData(const void *data, size_t len) {
+ const auto p = reinterpret_cast<const char*>(data);
+ m_buf.insert(m_buf.end(), p, p + len);
+}
+
+void WriteBuffer::replaceRawData(size_t pos, const void *data, size_t len) {
+ ASSERT(pos <= m_buf.size() && len <= m_buf.size() - pos);
+ const auto p = reinterpret_cast<const char*>(data);
+ std::copy(p, p + len, &m_buf[pos]);
+}
+
+void WriteBuffer::putInt32(int32_t i) {
+ putRawValue(Piece::Int32);
+ putRawValue(i);
+}
+
+void WriteBuffer::putInt64(int64_t i) {
+ putRawValue(Piece::Int64);
+ putRawValue(i);
+}
+
+// len is in characters, excluding NUL, i.e. the number of wchar_t elements
+void WriteBuffer::putWString(const wchar_t *str, size_t len) {
+ putRawValue(Piece::WString);
+ putRawValue(static_cast<uint64_t>(len));
+ putRawData(str, sizeof(wchar_t) * len);
+}
+
+void ReadBuffer::getRawData(void *data, size_t len) {
+ ASSERT(m_off <= m_buf.size());
+ READ_BUFFER_CHECK(len <= m_buf.size() - m_off);
+ const char *const inp = &m_buf[m_off];
+ std::copy(inp, inp + len, reinterpret_cast<char*>(data));
+ m_off += len;
+}
+
+int32_t ReadBuffer::getInt32() {
+ READ_BUFFER_CHECK(getRawValue<Piece>() == Piece::Int32);
+ return getRawValue<int32_t>();
+}
+
+int64_t ReadBuffer::getInt64() {
+ READ_BUFFER_CHECK(getRawValue<Piece>() == Piece::Int64);
+ return getRawValue<int64_t>();
+}
+
+std::wstring ReadBuffer::getWString() {
+ READ_BUFFER_CHECK(getRawValue<Piece>() == Piece::WString);
+ const uint64_t charLen = getRawValue<uint64_t>();
+ READ_BUFFER_CHECK(charLen <= SIZE_MAX / sizeof(wchar_t));
+ // To be strictly conforming, we can't use the convenient wstring
+ // constructor, because the string in m_buf mightn't be aligned.
+ std::wstring ret;
+ if (charLen > 0) {
+ const size_t byteLen = charLen * sizeof(wchar_t);
+ ret.resize(charLen);
+ getRawData(&ret[0], byteLen);
+ }
+ return ret;
+}
+
+void ReadBuffer::assertEof() {
+ READ_BUFFER_CHECK(m_off == m_buf.size());
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/Buffer.h b/src/libs/3rdparty/winpty/src/shared/Buffer.h
new file mode 100644
index 0000000000..c2dd382e5b
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/Buffer.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_BUFFER_H
+#define WINPTY_SHARED_BUFFER_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+#include <string>
+
+#include "WinptyException.h"
+
+class WriteBuffer {
+private:
+ std::vector<char> m_buf;
+
+public:
+ WriteBuffer() {}
+
+ template <typename T> void putRawValue(const T &t) {
+ putRawData(&t, sizeof(t));
+ }
+ template <typename T> void replaceRawValue(size_t pos, const T &t) {
+ replaceRawData(pos, &t, sizeof(t));
+ }
+
+ void putRawData(const void *data, size_t len);
+ void replaceRawData(size_t pos, const void *data, size_t len);
+ void putInt32(int32_t i);
+ void putInt64(int64_t i);
+ void putWString(const wchar_t *str, size_t len);
+ void putWString(const wchar_t *str) { putWString(str, wcslen(str)); }
+ void putWString(const std::wstring &str) { putWString(str.data(), str.size()); }
+ std::vector<char> &buf() { return m_buf; }
+
+ // MSVC 2013 does not generate these automatically, so help it out.
+ WriteBuffer(WriteBuffer &&other) : m_buf(std::move(other.m_buf)) {}
+ WriteBuffer &operator=(WriteBuffer &&other) {
+ m_buf = std::move(other.m_buf);
+ return *this;
+ }
+};
+
+class ReadBuffer {
+public:
+ class DecodeError : public WinptyException {
+ virtual const wchar_t *what() const WINPTY_NOEXCEPT override {
+ return L"DecodeError: RPC message decoding error";
+ }
+ };
+
+private:
+ std::vector<char> m_buf;
+ size_t m_off = 0;
+
+public:
+ explicit ReadBuffer(std::vector<char> &&buf) : m_buf(std::move(buf)) {}
+
+ template <typename T> T getRawValue() {
+ T ret = {};
+ getRawData(&ret, sizeof(ret));
+ return ret;
+ }
+
+ void getRawData(void *data, size_t len);
+ int32_t getInt32();
+ int64_t getInt64();
+ std::wstring getWString();
+ void assertEof();
+
+ // MSVC 2013 does not generate these automatically, so help it out.
+ ReadBuffer(ReadBuffer &&other) :
+ m_buf(std::move(other.m_buf)), m_off(other.m_off) {}
+ ReadBuffer &operator=(ReadBuffer &&other) {
+ m_buf = std::move(other.m_buf);
+ m_off = other.m_off;
+ return *this;
+ }
+};
+
+#endif // WINPTY_SHARED_BUFFER_H
diff --git a/src/libs/3rdparty/winpty/src/shared/DebugClient.cc b/src/libs/3rdparty/winpty/src/shared/DebugClient.cc
new file mode 100644
index 0000000000..bafe0c8954
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/DebugClient.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "DebugClient.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <string>
+
+#include "winpty_snprintf.h"
+
+const wchar_t *const kPipeName = L"\\\\.\\pipe\\DebugServer";
+
+void *volatile g_debugConfig;
+
+namespace {
+
+// It would be easy to accidentally trample on the Windows LastError value
+// by adding logging/debugging code. Ensure that can't happen by saving and
+// restoring the value. This saving and restoring doesn't happen along the
+// fast path.
+class PreserveLastError {
+public:
+ PreserveLastError() : m_lastError(GetLastError()) {}
+ ~PreserveLastError() { SetLastError(m_lastError); }
+private:
+ DWORD m_lastError;
+};
+
+} // anonymous namespace
+
+static void sendToDebugServer(const char *message)
+{
+ HANDLE tracePipe = INVALID_HANDLE_VALUE;
+
+ do {
+ // The default impersonation level is SECURITY_IMPERSONATION, which allows
+ // a sufficiently authorized named pipe server to impersonate the client.
+ // There's no need for impersonation in this debugging system, so reduce
+ // the impersonation level to SECURITY_IDENTIFICATION, which allows a
+ // server to merely identify us.
+ tracePipe = CreateFileW(
+ kPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
+ NULL);
+ } while (tracePipe == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_PIPE_BUSY &&
+ WaitNamedPipeW(kPipeName, NMPWAIT_WAIT_FOREVER));
+
+ if (tracePipe != INVALID_HANDLE_VALUE) {
+ DWORD newMode = PIPE_READMODE_MESSAGE;
+ SetNamedPipeHandleState(tracePipe, &newMode, NULL, NULL);
+ char response[16];
+ DWORD actual = 0;
+ TransactNamedPipe(tracePipe,
+ const_cast<char*>(message), strlen(message),
+ response, sizeof(response), &actual, NULL);
+ CloseHandle(tracePipe);
+ }
+}
+
+// Get the current UTC time as milliseconds from the epoch (ignoring leap
+// seconds). Use the Unix epoch for consistency with DebugClient.py. There
+// are 134774 days between 1601-01-01 (the Win32 epoch) and 1970-01-01 (the
+// Unix epoch).
+static long long unixTimeMillis()
+{
+ FILETIME fileTime;
+ GetSystemTimeAsFileTime(&fileTime);
+ long long msTime = (((long long)fileTime.dwHighDateTime << 32) +
+ fileTime.dwLowDateTime) / 10000;
+ return msTime - 134774LL * 24 * 3600 * 1000;
+}
+
+static const char *getDebugConfig()
+{
+ if (g_debugConfig == NULL) {
+ PreserveLastError preserve;
+ const int bufSize = 256;
+ char buf[bufSize];
+ DWORD actualSize =
+ GetEnvironmentVariableA("WINPTY_DEBUG", buf, bufSize);
+ if (actualSize == 0 || actualSize >= static_cast<DWORD>(bufSize)) {
+ buf[0] = '\0';
+ }
+ const size_t len = strlen(buf) + 1;
+ char *newConfig = new char[len];
+ std::copy(buf, buf + len, newConfig);
+ void *oldValue = InterlockedCompareExchangePointer(
+ &g_debugConfig, newConfig, NULL);
+ if (oldValue != NULL) {
+ delete [] newConfig;
+ }
+ }
+ return static_cast<const char*>(g_debugConfig);
+}
+
+bool isTracingEnabled()
+{
+ static bool disabled, enabled;
+ if (disabled) {
+ return false;
+ } else if (enabled) {
+ return true;
+ } else {
+ // Recognize WINPTY_DEBUG=1 for backwards compatibility.
+ PreserveLastError preserve;
+ bool value = hasDebugFlag("trace") || hasDebugFlag("1");
+ disabled = !value;
+ enabled = value;
+ return value;
+ }
+}
+
+bool hasDebugFlag(const char *flag)
+{
+ if (strchr(flag, ',') != NULL) {
+ trace("INTERNAL ERROR: hasDebugFlag flag has comma: '%s'", flag);
+ abort();
+ }
+ const char *const configCStr = getDebugConfig();
+ if (configCStr[0] == '\0') {
+ return false;
+ }
+ PreserveLastError preserve;
+ std::string config(configCStr);
+ std::string flagStr(flag);
+ config = "," + config + ",";
+ flagStr = "," + flagStr + ",";
+ return config.find(flagStr) != std::string::npos;
+}
+
+void trace(const char *format, ...)
+{
+ if (!isTracingEnabled())
+ return;
+
+ PreserveLastError preserve;
+ char message[1024];
+
+ va_list ap;
+ va_start(ap, format);
+ winpty_vsnprintf(message, format, ap);
+ message[sizeof(message) - 1] = '\0';
+ va_end(ap);
+
+ const int currentTime = (int)(unixTimeMillis() % (100000 * 1000));
+
+ char moduleName[1024];
+ moduleName[0] = '\0';
+ GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
+ const char *baseName = strrchr(moduleName, '\\');
+ baseName = (baseName != NULL) ? baseName + 1 : moduleName;
+
+ char fullMessage[1024];
+ winpty_snprintf(fullMessage,
+ "[%05d.%03d %s,p%04d,t%04d]: %s",
+ currentTime / 1000, currentTime % 1000,
+ baseName, (int)GetCurrentProcessId(), (int)GetCurrentThreadId(),
+ message);
+ fullMessage[sizeof(fullMessage) - 1] = '\0';
+
+ sendToDebugServer(fullMessage);
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/DebugClient.h b/src/libs/3rdparty/winpty/src/shared/DebugClient.h
new file mode 100644
index 0000000000..b126071130
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/DebugClient.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011-2012 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef DEBUGCLIENT_H
+#define DEBUGCLIENT_H
+
+#include "winpty_snprintf.h"
+
+bool isTracingEnabled();
+bool hasDebugFlag(const char *flag);
+void trace(const char *format, ...) WINPTY_SNPRINTF_FORMAT(1, 2);
+
+// This macro calls trace without evaluating the arguments.
+#define TRACE(format, ...) \
+ do { \
+ if (isTracingEnabled()) { \
+ trace((format), ## __VA_ARGS__); \
+ } \
+ } while (false)
+
+#endif // DEBUGCLIENT_H
diff --git a/src/libs/3rdparty/winpty/src/shared/GenRandom.cc b/src/libs/3rdparty/winpty/src/shared/GenRandom.cc
new file mode 100644
index 0000000000..6d7920643a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/GenRandom.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "GenRandom.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "DebugClient.h"
+#include "StringBuilder.h"
+
+static volatile LONG g_pipeCounter;
+
+GenRandom::GenRandom() : m_advapi32(L"advapi32.dll") {
+ // First try to use the pseudo-documented RtlGenRandom function from
+ // advapi32.dll. Creating a CryptoAPI context is slow, and RtlGenRandom
+ // avoids the overhead. It's documented in this blog post[1] and on
+ // MSDN[2] with a disclaimer about future breakage. This technique is
+ // apparently built-in into the MSVC CRT, though, for the rand_s function,
+ // so perhaps it is stable enough.
+ //
+ // [1] http://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx
+ // [2] https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx
+ //
+ // Both RtlGenRandom and the Crypto API functions exist in XP and up.
+ m_rtlGenRandom = reinterpret_cast<RtlGenRandom_t*>(
+ m_advapi32.proc("SystemFunction036"));
+ // The OsModule class logs an error message if the proc is nullptr.
+ if (m_rtlGenRandom != nullptr) {
+ return;
+ }
+
+ // Fall back to the crypto API.
+ m_cryptProvIsValid =
+ CryptAcquireContext(&m_cryptProv, nullptr, nullptr,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) != 0;
+ if (!m_cryptProvIsValid) {
+ trace("GenRandom: CryptAcquireContext failed: %u",
+ static_cast<unsigned>(GetLastError()));
+ }
+}
+
+GenRandom::~GenRandom() {
+ if (m_cryptProvIsValid) {
+ CryptReleaseContext(m_cryptProv, 0);
+ }
+}
+
+// Returns false if the context is invalid or the generation fails.
+bool GenRandom::fillBuffer(void *buffer, size_t size) {
+ memset(buffer, 0, size);
+ bool success = false;
+ if (m_rtlGenRandom != nullptr) {
+ success = m_rtlGenRandom(buffer, size) != 0;
+ if (!success) {
+ trace("GenRandom: RtlGenRandom/SystemFunction036 failed: %u",
+ static_cast<unsigned>(GetLastError()));
+ }
+ } else if (m_cryptProvIsValid) {
+ success =
+ CryptGenRandom(m_cryptProv, size,
+ reinterpret_cast<BYTE*>(buffer)) != 0;
+ if (!success) {
+ trace("GenRandom: CryptGenRandom failed, size=%d, lasterror=%u",
+ static_cast<int>(size),
+ static_cast<unsigned>(GetLastError()));
+ }
+ }
+ return success;
+}
+
+// Returns an empty string if either of CryptAcquireContext or CryptGenRandom
+// fail.
+std::string GenRandom::randomBytes(size_t numBytes) {
+ std::string ret(numBytes, '\0');
+ if (!fillBuffer(&ret[0], numBytes)) {
+ return std::string();
+ }
+ return ret;
+}
+
+std::wstring GenRandom::randomHexString(size_t numBytes) {
+ const std::string bytes = randomBytes(numBytes);
+ std::wstring ret(bytes.size() * 2, L'\0');
+ for (size_t i = 0; i < bytes.size(); ++i) {
+ static const wchar_t hex[] = L"0123456789abcdef";
+ ret[i * 2] = hex[static_cast<uint8_t>(bytes[i]) >> 4];
+ ret[i * 2 + 1] = hex[static_cast<uint8_t>(bytes[i]) & 0xF];
+ }
+ return ret;
+}
+
+// Returns a 64-bit value representing the number of 100-nanosecond intervals
+// since January 1, 1601.
+static uint64_t systemTimeAsUInt64() {
+ FILETIME monotonicTime = {};
+ GetSystemTimeAsFileTime(&monotonicTime);
+ return (static_cast<uint64_t>(monotonicTime.dwHighDateTime) << 32) |
+ static_cast<uint64_t>(monotonicTime.dwLowDateTime);
+}
+
+// Generates a unique and hard-to-guess case-insensitive string suitable for
+// use in a pipe filename or a Windows object name.
+std::wstring GenRandom::uniqueName() {
+ // First include enough information to avoid collisions assuming
+ // cooperative software. This code assumes that a process won't die and
+ // be replaced with a recycled PID within a single GetSystemTimeAsFileTime
+ // interval.
+ WStringBuilder sb(64);
+ sb << GetCurrentProcessId()
+ << L'-' << InterlockedIncrement(&g_pipeCounter)
+ << L'-' << whexOfInt(systemTimeAsUInt64());
+ // It isn't clear to me how the crypto APIs would fail. It *probably*
+ // doesn't matter that much anyway? In principle, a predictable pipe name
+ // is subject to a local denial-of-service attack.
+ auto random = randomHexString(16);
+ if (!random.empty()) {
+ sb << L'-' << random;
+ }
+ return sb.str_moved();
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/GenRandom.h b/src/libs/3rdparty/winpty/src/shared/GenRandom.h
new file mode 100644
index 0000000000..746cb1ecf7
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/GenRandom.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_GEN_RANDOM_H
+#define WINPTY_GEN_RANDOM_H
+
+// The original MinGW requires that we include wincrypt.h. With MinGW-w64 and
+// MSVC, including windows.h is sufficient.
+#include <windows.h>
+#include <wincrypt.h>
+
+#include <string>
+
+#include "OsModule.h"
+
+class GenRandom {
+ typedef BOOLEAN WINAPI RtlGenRandom_t(PVOID, ULONG);
+
+ OsModule m_advapi32;
+ RtlGenRandom_t *m_rtlGenRandom = nullptr;
+ bool m_cryptProvIsValid = false;
+ HCRYPTPROV m_cryptProv = 0;
+
+public:
+ GenRandom();
+ ~GenRandom();
+ bool fillBuffer(void *buffer, size_t size);
+ std::string randomBytes(size_t numBytes);
+ std::wstring randomHexString(size_t numBytes);
+ std::wstring uniqueName();
+
+ // Return true if the crypto context was successfully initialized.
+ bool valid() const {
+ return m_rtlGenRandom != nullptr || m_cryptProvIsValid;
+ }
+};
+
+#endif // WINPTY_GEN_RANDOM_H
diff --git a/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat b/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat
new file mode 100644
index 0000000000..a9f8e9cef0
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat
@@ -0,0 +1,13 @@
+@echo off
+
+REM -- Echo the git commit hash. If git isn't available for some reason,
+REM -- output nothing instead.
+
+git rev-parse HEAD >NUL 2>NUL && (
+ git rev-parse HEAD
+) || (
+ echo none
+)
+
+REM -- Set ERRORLEVEL to 0 using this cryptic syntax.
+(call )
diff --git a/src/libs/3rdparty/winpty/src/shared/Mutex.h b/src/libs/3rdparty/winpty/src/shared/Mutex.h
new file mode 100644
index 0000000000..98215365ad
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/Mutex.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// Recent 4.x MinGW and MinGW-w64 gcc compilers lack std::mutex and
+// std::lock_guard. I have a 5.2.0 MinGW-w64 compiler packaged through MSYS2
+// that *is* new enough, but that's one compiler against several deficient
+// ones. Wrap CRITICAL_SECTION instead.
+
+#ifndef WINPTY_SHARED_MUTEX_H
+#define WINPTY_SHARED_MUTEX_H
+
+#include <windows.h>
+
+class Mutex {
+ CRITICAL_SECTION m_mutex;
+public:
+ Mutex() { InitializeCriticalSection(&m_mutex); }
+ ~Mutex() { DeleteCriticalSection(&m_mutex); }
+ void lock() { EnterCriticalSection(&m_mutex); }
+ void unlock() { LeaveCriticalSection(&m_mutex); }
+
+ Mutex(const Mutex &other) = delete;
+ Mutex &operator=(const Mutex &other) = delete;
+};
+
+template <typename T>
+class LockGuard {
+ T &m_lock;
+public:
+ LockGuard(T &lock) : m_lock(lock) { m_lock.lock(); }
+ ~LockGuard() { m_lock.unlock(); }
+
+ LockGuard(const LockGuard &other) = delete;
+ LockGuard &operator=(const LockGuard &other) = delete;
+};
+
+#endif // WINPTY_SHARED_MUTEX_H
diff --git a/src/libs/3rdparty/winpty/src/shared/OsModule.h b/src/libs/3rdparty/winpty/src/shared/OsModule.h
new file mode 100644
index 0000000000..9713fa2b2d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/OsModule.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_OS_MODULE_H
+#define WINPTY_SHARED_OS_MODULE_H
+
+#include <windows.h>
+
+#include <string>
+
+#include "DebugClient.h"
+#include "WinptyAssert.h"
+#include "WinptyException.h"
+
+class OsModule {
+ HMODULE m_module;
+public:
+ enum class LoadErrorBehavior { Abort, Throw };
+ OsModule(const wchar_t *fileName,
+ LoadErrorBehavior behavior=LoadErrorBehavior::Abort) {
+ m_module = LoadLibraryW(fileName);
+ if (behavior == LoadErrorBehavior::Abort) {
+ ASSERT(m_module != NULL);
+ } else {
+ if (m_module == nullptr) {
+ const auto err = GetLastError();
+ throwWindowsError(
+ (L"LoadLibraryW error: " + std::wstring(fileName)).c_str(),
+ err);
+ }
+ }
+ }
+ ~OsModule() {
+ FreeLibrary(m_module);
+ }
+ HMODULE handle() const { return m_module; }
+ FARPROC proc(const char *funcName) {
+ FARPROC ret = GetProcAddress(m_module, funcName);
+ if (ret == NULL) {
+ trace("GetProcAddress: %s is missing", funcName);
+ }
+ return ret;
+ }
+};
+
+#endif // WINPTY_SHARED_OS_MODULE_H
diff --git a/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc
new file mode 100644
index 0000000000..7b173536e6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "OwnedHandle.h"
+
+#include "DebugClient.h"
+#include "WinptyException.h"
+
+void OwnedHandle::dispose(bool nothrow) {
+ if (m_h != nullptr && m_h != INVALID_HANDLE_VALUE) {
+ if (!CloseHandle(m_h)) {
+ trace("CloseHandle(%p) failed", m_h);
+ if (!nothrow) {
+ throwWindowsError(L"CloseHandle failed");
+ }
+ }
+ }
+ m_h = nullptr;
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h
new file mode 100644
index 0000000000..70a8d6163a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_OWNED_HANDLE_H
+#define WINPTY_SHARED_OWNED_HANDLE_H
+
+#include <windows.h>
+
+class OwnedHandle {
+ HANDLE m_h;
+public:
+ OwnedHandle() : m_h(nullptr) {}
+ explicit OwnedHandle(HANDLE h) : m_h(h) {}
+ ~OwnedHandle() { dispose(true); }
+ void dispose(bool nothrow=false);
+ HANDLE get() const { return m_h; }
+ HANDLE release() { HANDLE ret = m_h; m_h = nullptr; return ret; }
+ OwnedHandle(const OwnedHandle &other) = delete;
+ OwnedHandle(OwnedHandle &&other) : m_h(other.release()) {}
+ OwnedHandle &operator=(const OwnedHandle &other) = delete;
+ OwnedHandle &operator=(OwnedHandle &&other) {
+ dispose();
+ m_h = other.release();
+ return *this;
+ }
+};
+
+#endif // WINPTY_SHARED_OWNED_HANDLE_H
diff --git a/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h b/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h
new file mode 100644
index 0000000000..7d9b8f8b4a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_PRECOMPILED_HEADER_H
+#define WINPTY_PRECOMPILED_HEADER_H
+
+#include <windows.h>
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <array>
+#include <limits>
+#include <memory>
+#include <new>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#endif // WINPTY_PRECOMPILED_HEADER_H
diff --git a/src/libs/3rdparty/winpty/src/shared/StringBuilder.h b/src/libs/3rdparty/winpty/src/shared/StringBuilder.h
new file mode 100644
index 0000000000..f3155bdd29
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/StringBuilder.h
@@ -0,0 +1,227 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// Efficient integer->string conversion and string concatenation. The
+// hexadecimal conversion may optionally have leading zeros. Other ways to
+// convert integers to strings in C++ suffer these drawbacks:
+//
+// * std::stringstream: Inefficient, even more so than stdio.
+//
+// * std::to_string: No hexadecimal output, tends to use heap allocation, not
+// supported on Cygwin.
+//
+// * stdio routines: Requires parsing a format string (inefficient). The
+// caller *must* know how large the content is for correctness. The
+// string-printf functions are extremely inconsistent on Windows. In
+// particular, 64-bit integers, wide strings, and return values are
+// problem areas.
+//
+// StringBuilderTest.cc is a standalone program that tests this header.
+
+#ifndef WINPTY_STRING_BUILDER_H
+#define WINPTY_STRING_BUILDER_H
+
+#include <array>
+#include <string>
+#include <type_traits>
+
+#ifdef STRING_BUILDER_TESTING
+#include <assert.h>
+#define STRING_BUILDER_CHECK(cond) assert(cond)
+#else
+#define STRING_BUILDER_CHECK(cond)
+#endif // STRING_BUILDER_TESTING
+
+#include "WinptyAssert.h"
+
+template <typename C, size_t sz>
+struct ValueString {
+ std::array<C, sz> m_array;
+ size_t m_offset;
+ size_t m_size;
+
+ const C *c_str() const { return m_array.data() + m_offset; }
+ const C *data() const { return m_array.data() + m_offset; }
+ size_t size() const { return m_size; }
+ std::basic_string<C> str() const {
+ return std::basic_string<C>(data(), m_size);
+ }
+};
+
+#ifdef _MSC_VER
+// Disable an MSVC /SDL error that forbids unsigned negation. Signed negation
+// invokes undefined behavior for INTxx_MIN, so unsigned negation is simpler to
+// reason about. (We assume twos-complement in any case.)
+#define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) \
+ ( \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4146)) \
+ (x) \
+ __pragma(warning(pop)) \
+ )
+#else
+#define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) (x)
+#endif
+
+// Formats an integer as decimal without leading zeros.
+template <typename C, typename I>
+ValueString<C, sizeof(I) * 3 + 1 + 1> gdecOfInt(const I value) {
+ typedef typename std::make_unsigned<I>::type U;
+ auto unsValue = static_cast<U>(value);
+ const bool isNegative = (value < 0);
+ if (isNegative) {
+ unsValue = STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(-unsValue);
+ }
+ decltype(gdecOfInt<C, I>(value)) out;
+ auto &arr = out.m_array;
+ C *const endp = arr.data() + arr.size();
+ C *outp = endp;
+ *(--outp) = '\0';
+ STRING_BUILDER_CHECK(outp >= arr.data());
+ do {
+ const int digit = unsValue % 10;
+ unsValue /= 10;
+ *(--outp) = '0' + digit;
+ STRING_BUILDER_CHECK(outp >= arr.data());
+ } while (unsValue != 0);
+ if (isNegative) {
+ *(--outp) = '-';
+ STRING_BUILDER_CHECK(outp >= arr.data());
+ }
+ out.m_offset = outp - arr.data();
+ out.m_size = endp - outp - 1;
+ return out;
+}
+
+template <typename I> decltype(gdecOfInt<char, I>(0)) decOfInt(I i) {
+ return gdecOfInt<char>(i);
+}
+
+template <typename I> decltype(gdecOfInt<wchar_t, I>(0)) wdecOfInt(I i) {
+ return gdecOfInt<wchar_t>(i);
+}
+
+// Formats an integer as hexadecimal, with or without leading zeros.
+template <typename C, bool leadingZeros=false, typename I>
+ValueString<C, sizeof(I) * 2 + 1> ghexOfInt(const I value) {
+ typedef typename std::make_unsigned<I>::type U;
+ const auto unsValue = static_cast<U>(value);
+ static const C hex[16] = {'0','1','2','3','4','5','6','7',
+ '8','9','a','b','c','d','e','f'};
+ decltype(ghexOfInt<C, leadingZeros, I>(value)) out;
+ auto &arr = out.m_array;
+ C *outp = arr.data();
+ int inIndex = 0;
+ int shift = sizeof(I) * 8 - 4;
+ const int len = sizeof(I) * 2;
+ if (!leadingZeros) {
+ for (; inIndex < len - 1; ++inIndex, shift -= 4) {
+ STRING_BUILDER_CHECK(shift >= 0 && shift < sizeof(unsValue) * 8);
+ const int digit = (unsValue >> shift) & 0xF;
+ if (digit != 0) {
+ break;
+ }
+ }
+ }
+ for (; inIndex < len; ++inIndex, shift -= 4) {
+ const int digit = (unsValue >> shift) & 0xF;
+ *(outp++) = hex[digit];
+ STRING_BUILDER_CHECK(outp <= arr.data() + arr.size());
+ }
+ *(outp++) = '\0';
+ STRING_BUILDER_CHECK(outp <= arr.data() + arr.size());
+ out.m_offset = 0;
+ out.m_size = outp - arr.data() - 1;
+ return out;
+}
+
+template <bool leadingZeros=false, typename I>
+decltype(ghexOfInt<char, leadingZeros, I>(0)) hexOfInt(I i) {
+ return ghexOfInt<char, leadingZeros, I>(i);
+}
+
+template <bool leadingZeros=false, typename I>
+decltype(ghexOfInt<wchar_t, leadingZeros, I>(0)) whexOfInt(I i) {
+ return ghexOfInt<wchar_t, leadingZeros, I>(i);
+}
+
+template <typename C>
+class GStringBuilder {
+public:
+ typedef std::basic_string<C> StringType;
+
+ GStringBuilder() {}
+ GStringBuilder(size_t capacity) {
+ m_out.reserve(capacity);
+ }
+
+ GStringBuilder &operator<<(C ch) { m_out.push_back(ch); return *this; }
+ GStringBuilder &operator<<(const C *str) { m_out.append(str); return *this; }
+ GStringBuilder &operator<<(const StringType &str) { m_out.append(str); return *this; }
+
+ template <size_t sz>
+ GStringBuilder &operator<<(const ValueString<C, sz> &str) {
+ m_out.append(str.data(), str.size());
+ return *this;
+ }
+
+private:
+ // Forbid output of char/wchar_t for GStringBuilder if the type doesn't
+ // exactly match the builder element type. The code still allows
+ // signed char and unsigned char, but I'm a little worried about what
+ // happens if a user tries to output int8_t or uint8_t.
+ template <typename P>
+ typename std::enable_if<
+ (std::is_same<P, char>::value || std::is_same<P, wchar_t>::value) &&
+ !std::is_same<C, P>::value, GStringBuilder&>::type
+ operator<<(P ch) {
+ ASSERT(false && "Method was not supposed to be reachable.");
+ return *this;
+ }
+
+public:
+ GStringBuilder &operator<<(short i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(unsigned short i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(int i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(unsigned int i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(long i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(unsigned long i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(long long i) { return *this << gdecOfInt<C>(i); }
+ GStringBuilder &operator<<(unsigned long long i) { return *this << gdecOfInt<C>(i); }
+
+ GStringBuilder &operator<<(const void *p) {
+ m_out.push_back(static_cast<C>('0'));
+ m_out.push_back(static_cast<C>('x'));
+ *this << ghexOfInt<C>(reinterpret_cast<uintptr_t>(p));
+ return *this;
+ }
+
+ StringType str() { return m_out; }
+ StringType str_moved() { return std::move(m_out); }
+ const C *c_str() const { return m_out.c_str(); }
+
+private:
+ StringType m_out;
+};
+
+typedef GStringBuilder<char> StringBuilder;
+typedef GStringBuilder<wchar_t> WStringBuilder;
+
+#endif // WINPTY_STRING_BUILDER_H
diff --git a/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc b/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc
new file mode 100644
index 0000000000..e6c2d3138c
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#define STRING_BUILDER_TESTING
+
+#include "StringBuilder.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <iomanip>
+#include <sstream>
+
+void display(const std::string &str) { fprintf(stderr, "%s", str.c_str()); }
+void display(const std::wstring &str) { fprintf(stderr, "%ls", str.c_str()); }
+
+#define CHECK_EQ(x, y) \
+ do { \
+ const auto xval = (x); \
+ const auto yval = (y); \
+ if (xval != yval) { \
+ fprintf(stderr, "error: %s:%d: %s != %s: ", \
+ __FILE__, __LINE__, #x, #y); \
+ display(xval); \
+ fprintf(stderr, " != "); \
+ display(yval); \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+
+template <typename C, typename I>
+std::basic_string<C> decOfIntSS(const I value) {
+ // std::to_string and std::to_wstring are missing in Cygwin as of this
+ // writing (early 2016).
+ std::basic_stringstream<C> ss;
+ ss << +value; // We must promote char to print it as an integer.
+ return ss.str();
+}
+
+
+template <typename C, bool leadingZeros=false, typename I>
+std::basic_string<C> hexOfIntSS(const I value) {
+ typedef typename std::make_unsigned<I>::type U;
+ const unsigned long long u64Value = value & static_cast<U>(~0);
+ std::basic_stringstream<C> ss;
+ if (leadingZeros) {
+ ss << std::setfill(static_cast<C>('0')) << std::setw(sizeof(I) * 2);
+ }
+ ss << std::hex << u64Value;
+ return ss.str();
+}
+
+template <typename I>
+void testValue(I value) {
+ CHECK_EQ(decOfInt(value).str(), (decOfIntSS<char>(value)));
+ CHECK_EQ(wdecOfInt(value).str(), (decOfIntSS<wchar_t>(value)));
+ CHECK_EQ((hexOfInt<false>(value).str()), (hexOfIntSS<char, false>(value)));
+ CHECK_EQ((hexOfInt<true>(value).str()), (hexOfIntSS<char, true>(value)));
+ CHECK_EQ((whexOfInt<false>(value).str()), (hexOfIntSS<wchar_t, false>(value)));
+ CHECK_EQ((whexOfInt<true>(value).str()), (hexOfIntSS<wchar_t, true>(value)));
+}
+
+template <typename I>
+void testType() {
+ typedef typename std::make_unsigned<I>::type U;
+ const U quarter = static_cast<U>(1) << (sizeof(U) * 8 - 2);
+ for (unsigned quarterIndex = 0; quarterIndex < 4; ++quarterIndex) {
+ for (int offset = -18; offset <= 18; ++offset) {
+ const I value = quarter * quarterIndex + static_cast<U>(offset);
+ testValue(value);
+ }
+ }
+ testValue(static_cast<I>(42));
+ testValue(static_cast<I>(123456));
+ testValue(static_cast<I>(0xdeadfacecafebeefull));
+}
+
+int main() {
+ testType<char>();
+
+ testType<signed char>();
+ testType<signed short>();
+ testType<signed int>();
+ testType<signed long>();
+ testType<signed long long>();
+
+ testType<unsigned char>();
+ testType<unsigned short>();
+ testType<unsigned int>();
+ testType<unsigned long>();
+ testType<unsigned long long>();
+
+ StringBuilder() << static_cast<const void*>("TEST");
+ WStringBuilder() << static_cast<const void*>("TEST");
+
+ fprintf(stderr, "All tests completed!\n");
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/StringUtil.cc b/src/libs/3rdparty/winpty/src/shared/StringUtil.cc
new file mode 100644
index 0000000000..3a85a3ec94
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/StringUtil.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "StringUtil.h"
+
+#include <windows.h>
+
+#include "WinptyAssert.h"
+
+// Workaround. MinGW (from mingw.org) does not have wcsnlen. MinGW-w64 *does*
+// have wcsnlen, but use this function for consistency.
+size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen) {
+ ASSERT(s != NULL);
+ for (size_t i = 0; i < maxlen; ++i) {
+ if (s[i] == L'\0') {
+ return i;
+ }
+ }
+ return maxlen;
+}
+
+std::string utf8FromWide(const std::wstring &input) {
+ int mblen = WideCharToMultiByte(
+ CP_UTF8, 0,
+ input.data(), input.size(),
+ NULL, 0, NULL, NULL);
+ if (mblen <= 0) {
+ return std::string();
+ }
+ std::vector<char> tmp(mblen);
+ int mblen2 = WideCharToMultiByte(
+ CP_UTF8, 0,
+ input.data(), input.size(),
+ tmp.data(), tmp.size(),
+ NULL, NULL);
+ ASSERT(mblen2 == mblen);
+ return std::string(tmp.data(), tmp.size());
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/StringUtil.h b/src/libs/3rdparty/winpty/src/shared/StringUtil.h
new file mode 100644
index 0000000000..e4bf3c9121
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/StringUtil.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_STRING_UTIL_H
+#define WINPTY_SHARED_STRING_UTIL_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "WinptyAssert.h"
+
+size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen);
+std::string utf8FromWide(const std::wstring &input);
+
+// Return a vector containing each character in the string.
+template <typename T>
+std::vector<T> vectorFromString(const std::basic_string<T> &str) {
+ return std::vector<T>(str.begin(), str.end());
+}
+
+// Return a vector containing each character in the string, followed by a
+// NUL terminator.
+template <typename T>
+std::vector<T> vectorWithNulFromString(const std::basic_string<T> &str) {
+ std::vector<T> ret;
+ ret.reserve(str.size() + 1);
+ ret.insert(ret.begin(), str.begin(), str.end());
+ ret.push_back('\0');
+ return ret;
+}
+
+// A safer(?) version of wcsncpy that is accepted by MSVC's /SDL mode.
+template <size_t N>
+wchar_t *winpty_wcsncpy(wchar_t (&d)[N], const wchar_t *s) {
+ ASSERT(s != nullptr);
+ size_t i = 0;
+ for (; i < N; ++i) {
+ if (s[i] == L'\0') {
+ break;
+ }
+ d[i] = s[i];
+ }
+ for (; i < N; ++i) {
+ d[i] = L'\0';
+ }
+ return d;
+}
+
+// Like wcsncpy, but ensure that the destination buffer is NUL-terminated.
+template <size_t N>
+wchar_t *winpty_wcsncpy_nul(wchar_t (&d)[N], const wchar_t *s) {
+ static_assert(N > 0, "array cannot be 0-size");
+ winpty_wcsncpy(d, s);
+ d[N - 1] = L'\0';
+ return d;
+}
+
+#endif // WINPTY_SHARED_STRING_UTIL_H
diff --git a/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h b/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h
new file mode 100644
index 0000000000..716a027fcb
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// Convenience header library for using the high-resolution performance counter
+// to measure how long some process takes.
+
+#ifndef TIME_MEASUREMENT_H
+#define TIME_MEASUREMENT_H
+
+#include <windows.h>
+#include <assert.h>
+#include <stdint.h>
+
+class TimeMeasurement {
+public:
+ TimeMeasurement() {
+ static double freq = static_cast<double>(getFrequency());
+ m_freq = freq;
+ m_start = value();
+ }
+
+ double elapsed() {
+ uint64_t elapsedTicks = value() - m_start;
+ return static_cast<double>(elapsedTicks) / m_freq;
+ }
+
+private:
+ uint64_t getFrequency() {
+ LARGE_INTEGER freq;
+ BOOL success = QueryPerformanceFrequency(&freq);
+ assert(success && "QueryPerformanceFrequency failed");
+ return freq.QuadPart;
+ }
+
+ uint64_t value() {
+ LARGE_INTEGER ret;
+ BOOL success = QueryPerformanceCounter(&ret);
+ assert(success && "QueryPerformanceCounter failed");
+ return ret.QuadPart;
+ }
+
+ uint64_t m_start;
+ double m_freq;
+};
+
+#endif // TIME_MEASUREMENT_H
diff --git a/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h b/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h
new file mode 100644
index 0000000000..39dfa62ec9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNIX_CTRL_CHARS_H
+#define UNIX_CTRL_CHARS_H
+
+inline char decodeUnixCtrlChar(char ch) {
+ const char ctrlKeys[] = {
+ /* 0x00 */ '@', /* 0x01 */ 'A', /* 0x02 */ 'B', /* 0x03 */ 'C',
+ /* 0x04 */ 'D', /* 0x05 */ 'E', /* 0x06 */ 'F', /* 0x07 */ 'G',
+ /* 0x08 */ 'H', /* 0x09 */ 'I', /* 0x0A */ 'J', /* 0x0B */ 'K',
+ /* 0x0C */ 'L', /* 0x0D */ 'M', /* 0x0E */ 'N', /* 0x0F */ 'O',
+ /* 0x10 */ 'P', /* 0x11 */ 'Q', /* 0x12 */ 'R', /* 0x13 */ 'S',
+ /* 0x14 */ 'T', /* 0x15 */ 'U', /* 0x16 */ 'V', /* 0x17 */ 'W',
+ /* 0x18 */ 'X', /* 0x19 */ 'Y', /* 0x1A */ 'Z', /* 0x1B */ '[',
+ /* 0x1C */ '\\', /* 0x1D */ ']', /* 0x1E */ '^', /* 0x1F */ '_',
+ };
+ unsigned char uch = ch;
+ if (uch < 32) {
+ return ctrlKeys[uch];
+ } else if (uch == 127) {
+ return '?';
+ } else {
+ return '\0';
+ }
+}
+
+#endif // UNIX_CTRL_CHARS_H
diff --git a/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat b/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat
new file mode 100644
index 0000000000..ea2a7d64ed
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat
@@ -0,0 +1,20 @@
+@echo off
+
+rem -- Echo the git commit hash. If git isn't available for some reason,
+rem -- output nothing instead.
+
+mkdir ..\gen 2>nul
+
+set /p VERSION=<..\..\VERSION.txt
+set COMMIT=%1
+
+echo // AUTO-GENERATED BY %0 %*>..\gen\GenVersion.h
+echo const char GenVersion_Version[] = "%VERSION%";>>..\gen\GenVersion.h
+echo const char GenVersion_Commit[] = "%COMMIT%";>>..\gen\GenVersion.h
+
+rem -- The winpty.gyp file expects the script to output the include directory,
+rem -- relative to src.
+echo gen
+
+rem -- Set ERRORLEVEL to 0 using this cryptic syntax.
+(call )
diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc
new file mode 100644
index 0000000000..711a8637c8
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc
@@ -0,0 +1,460 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WindowsSecurity.h"
+
+#include <array>
+
+#include "DebugClient.h"
+#include "OsModule.h"
+#include "OwnedHandle.h"
+#include "StringBuilder.h"
+#include "WindowsVersion.h"
+#include "WinptyAssert.h"
+#include "WinptyException.h"
+
+namespace {
+
+struct LocalFreer {
+ void operator()(void *ptr) {
+ if (ptr != nullptr) {
+ LocalFree(reinterpret_cast<HLOCAL>(ptr));
+ }
+ }
+};
+
+typedef std::unique_ptr<void, LocalFreer> PointerLocal;
+
+template <typename T>
+SecurityItem<T> localItem(typename T::type v) {
+ typedef typename T::type P;
+ struct Impl : SecurityItem<T>::Impl {
+ P m_v;
+ Impl(P v) : m_v(v) {}
+ virtual ~Impl() {
+ LocalFree(reinterpret_cast<HLOCAL>(m_v));
+ }
+ };
+ return SecurityItem<T>(v, std::unique_ptr<Impl>(new Impl { v }));
+}
+
+Sid allocatedSid(PSID v) {
+ struct Impl : Sid::Impl {
+ PSID m_v;
+ Impl(PSID v) : m_v(v) {}
+ virtual ~Impl() {
+ if (m_v != nullptr) {
+ FreeSid(m_v);
+ }
+ }
+ };
+ return Sid(v, std::unique_ptr<Impl>(new Impl { v }));
+}
+
+} // anonymous namespace
+
+// Returns a handle to the thread's effective security token. If the thread
+// is impersonating another user, its token is returned, and otherwise, the
+// process' security token is opened. The handle is opened with TOKEN_QUERY.
+static OwnedHandle openSecurityTokenForQuery() {
+ HANDLE token = nullptr;
+ // It is unclear to me whether OpenAsSelf matters for winpty, or what the
+ // most appropriate value is.
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY,
+ /*OpenAsSelf=*/FALSE, &token)) {
+ if (GetLastError() != ERROR_NO_TOKEN) {
+ throwWindowsError(L"OpenThreadToken failed");
+ }
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
+ throwWindowsError(L"OpenProcessToken failed");
+ }
+ }
+ ASSERT(token != nullptr &&
+ "OpenThreadToken/OpenProcessToken token is NULL");
+ return OwnedHandle(token);
+}
+
+// Returns the TokenOwner of the thread's effective security token.
+Sid getOwnerSid() {
+ struct Impl : Sid::Impl {
+ std::unique_ptr<char[]> buffer;
+ };
+
+ OwnedHandle token = openSecurityTokenForQuery();
+ DWORD actual = 0;
+ BOOL success;
+ success = GetTokenInformation(token.get(), TokenOwner,
+ nullptr, 0, &actual);
+ if (success) {
+ throwWinptyException(L"getOwnerSid: GetTokenInformation: "
+ L"expected ERROR_INSUFFICIENT_BUFFER");
+ } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ throwWindowsError(L"getOwnerSid: GetTokenInformation: "
+ L"expected ERROR_INSUFFICIENT_BUFFER");
+ }
+ std::unique_ptr<Impl> impl(new Impl);
+ impl->buffer = std::unique_ptr<char[]>(new char[actual]);
+ success = GetTokenInformation(token.get(), TokenOwner,
+ impl->buffer.get(), actual, &actual);
+ if (!success) {
+ throwWindowsError(L"getOwnerSid: GetTokenInformation");
+ }
+ TOKEN_OWNER tmp;
+ ASSERT(actual >= sizeof(tmp));
+ std::copy(
+ impl->buffer.get(),
+ impl->buffer.get() + sizeof(tmp),
+ reinterpret_cast<char*>(&tmp));
+ return Sid(tmp.Owner, std::move(impl));
+}
+
+Sid wellKnownSid(
+ const wchar_t *debuggingName,
+ SID_IDENTIFIER_AUTHORITY authority,
+ BYTE authorityCount,
+ DWORD subAuthority0/*=0*/,
+ DWORD subAuthority1/*=0*/) {
+ PSID psid = nullptr;
+ if (!AllocateAndInitializeSid(&authority, authorityCount,
+ subAuthority0,
+ subAuthority1,
+ 0, 0, 0, 0, 0, 0,
+ &psid)) {
+ const auto err = GetLastError();
+ const auto msg =
+ std::wstring(L"wellKnownSid: error getting ") +
+ debuggingName + L" SID";
+ throwWindowsError(msg.c_str(), err);
+ }
+ return allocatedSid(psid);
+}
+
+Sid builtinAdminsSid() {
+ // S-1-5-32-544
+ SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
+ return wellKnownSid(L"BUILTIN\\Administrators group",
+ authority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID, // 32
+ DOMAIN_ALIAS_RID_ADMINS); // 544
+}
+
+Sid localSystemSid() {
+ // S-1-5-18
+ SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
+ return wellKnownSid(L"LocalSystem account",
+ authority, 1,
+ SECURITY_LOCAL_SYSTEM_RID); // 18
+}
+
+Sid everyoneSid() {
+ // S-1-1-0
+ SID_IDENTIFIER_AUTHORITY authority = { SECURITY_WORLD_SID_AUTHORITY };
+ return wellKnownSid(L"Everyone account",
+ authority, 1,
+ SECURITY_WORLD_RID); // 0
+}
+
+static SecurityDescriptor finishSecurityDescriptor(
+ size_t daclEntryCount,
+ EXPLICIT_ACCESSW *daclEntries,
+ Acl &outAcl) {
+ {
+ PACL aclRaw = nullptr;
+ DWORD aclError =
+ SetEntriesInAclW(daclEntryCount,
+ daclEntries,
+ nullptr, &aclRaw);
+ if (aclError != ERROR_SUCCESS) {
+ WStringBuilder sb(64);
+ sb << L"finishSecurityDescriptor: "
+ << L"SetEntriesInAcl failed: " << aclError;
+ throwWinptyException(sb.c_str());
+ }
+ outAcl = localItem<AclTag>(aclRaw);
+ }
+
+ const PSECURITY_DESCRIPTOR sdRaw =
+ reinterpret_cast<PSECURITY_DESCRIPTOR>(
+ LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
+ if (sdRaw == nullptr) {
+ throwWinptyException(L"finishSecurityDescriptor: LocalAlloc failed");
+ }
+ SecurityDescriptor sd = localItem<SecurityDescriptorTag>(sdRaw);
+ if (!InitializeSecurityDescriptor(sdRaw, SECURITY_DESCRIPTOR_REVISION)) {
+ throwWindowsError(
+ L"finishSecurityDescriptor: InitializeSecurityDescriptor");
+ }
+ if (!SetSecurityDescriptorDacl(sdRaw, TRUE, outAcl.get(), FALSE)) {
+ throwWindowsError(
+ L"finishSecurityDescriptor: SetSecurityDescriptorDacl");
+ }
+
+ return std::move(sd);
+}
+
+// Create a security descriptor that grants full control to the local system
+// account, built-in administrators, and the owner.
+SecurityDescriptor
+createPipeSecurityDescriptorOwnerFullControl() {
+
+ struct Impl : SecurityDescriptor::Impl {
+ Sid localSystem;
+ Sid builtinAdmins;
+ Sid owner;
+ std::array<EXPLICIT_ACCESSW, 3> daclEntries = {};
+ Acl dacl;
+ SecurityDescriptor value;
+ };
+
+ std::unique_ptr<Impl> impl(new Impl);
+ impl->localSystem = localSystemSid();
+ impl->builtinAdmins = builtinAdminsSid();
+ impl->owner = getOwnerSid();
+
+ for (auto &ea : impl->daclEntries) {
+ ea.grfAccessPermissions = GENERIC_ALL;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ }
+ impl->daclEntries[0].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->localSystem.get());
+ impl->daclEntries[1].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->builtinAdmins.get());
+ impl->daclEntries[2].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->owner.get());
+
+ impl->value = finishSecurityDescriptor(
+ impl->daclEntries.size(),
+ impl->daclEntries.data(),
+ impl->dacl);
+
+ const auto retValue = impl->value.get();
+ return SecurityDescriptor(retValue, std::move(impl));
+}
+
+SecurityDescriptor
+createPipeSecurityDescriptorOwnerFullControlEveryoneWrite() {
+
+ struct Impl : SecurityDescriptor::Impl {
+ Sid localSystem;
+ Sid builtinAdmins;
+ Sid owner;
+ Sid everyone;
+ std::array<EXPLICIT_ACCESSW, 4> daclEntries = {};
+ Acl dacl;
+ SecurityDescriptor value;
+ };
+
+ std::unique_ptr<Impl> impl(new Impl);
+ impl->localSystem = localSystemSid();
+ impl->builtinAdmins = builtinAdminsSid();
+ impl->owner = getOwnerSid();
+ impl->everyone = everyoneSid();
+
+ for (auto &ea : impl->daclEntries) {
+ ea.grfAccessPermissions = GENERIC_ALL;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ }
+ impl->daclEntries[0].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->localSystem.get());
+ impl->daclEntries[1].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->builtinAdmins.get());
+ impl->daclEntries[2].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->owner.get());
+ impl->daclEntries[3].Trustee.ptstrName =
+ reinterpret_cast<LPWSTR>(impl->everyone.get());
+ // Avoid using FILE_GENERIC_WRITE because it includes FILE_APPEND_DATA,
+ // which is equal to FILE_CREATE_PIPE_INSTANCE. Instead, include all the
+ // flags that comprise FILE_GENERIC_WRITE, except for the one.
+ impl->daclEntries[3].grfAccessPermissions =
+ FILE_GENERIC_READ |
+ FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA |
+ STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
+
+ impl->value = finishSecurityDescriptor(
+ impl->daclEntries.size(),
+ impl->daclEntries.data(),
+ impl->dacl);
+
+ const auto retValue = impl->value.get();
+ return SecurityDescriptor(retValue, std::move(impl));
+}
+
+SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle) {
+ PACL dacl = nullptr;
+ PSECURITY_DESCRIPTOR sd = nullptr;
+ const DWORD errCode = GetSecurityInfo(handle, SE_KERNEL_OBJECT,
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ nullptr, nullptr, &dacl, nullptr, &sd);
+ if (errCode != ERROR_SUCCESS) {
+ throwWindowsError(L"GetSecurityInfo failed");
+ }
+ return localItem<SecurityDescriptorTag>(sd);
+}
+
+// The (SID/SD)<->string conversion APIs are useful for testing/debugging, so
+// create convenient accessor functions for them. They're too slow for
+// ordinary use. The APIs exist in XP and up, but the MinGW headers only
+// declare the SID<->string APIs, not the SD APIs. MinGW also gets the
+// prototype wrong for ConvertStringSidToSidW (LPWSTR instead of LPCWSTR) and
+// requires WINVER to be defined. MSVC and MinGW-w64 get everything right, but
+// for consistency, use LoadLibrary/GetProcAddress for all four APIs.
+
+typedef BOOL WINAPI ConvertStringSidToSidW_t(
+ LPCWSTR StringSid,
+ PSID *Sid);
+
+typedef BOOL WINAPI ConvertSidToStringSidW_t(
+ PSID Sid,
+ LPWSTR *StringSid);
+
+typedef BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW_t(
+ LPCWSTR StringSecurityDescriptor,
+ DWORD StringSDRevision,
+ PSECURITY_DESCRIPTOR *SecurityDescriptor,
+ PULONG SecurityDescriptorSize);
+
+typedef BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorW_t(
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ DWORD RequestedStringSDRevision,
+ SECURITY_INFORMATION SecurityInformation,
+ LPWSTR *StringSecurityDescriptor,
+ PULONG StringSecurityDescriptorLen);
+
+#define GET_MODULE_PROC(mod, funcName) \
+ const auto p##funcName = \
+ reinterpret_cast<funcName##_t*>( \
+ mod.proc(#funcName)); \
+ if (p##funcName == nullptr) { \
+ throwWinptyException( \
+ L"" L ## #funcName L" API is missing from ADVAPI32.DLL"); \
+ }
+
+const DWORD kSDDL_REVISION_1 = 1;
+
+std::wstring sidToString(PSID sid) {
+ OsModule advapi32(L"advapi32.dll");
+ GET_MODULE_PROC(advapi32, ConvertSidToStringSidW);
+ wchar_t *sidString = NULL;
+ BOOL success = pConvertSidToStringSidW(sid, &sidString);
+ if (!success) {
+ throwWindowsError(L"ConvertSidToStringSidW failed");
+ }
+ PointerLocal freer(sidString);
+ return std::wstring(sidString);
+}
+
+Sid stringToSid(const std::wstring &str) {
+ // Cast the string from const wchar_t* to LPWSTR because the function is
+ // incorrectly prototyped in the MinGW sddl.h header. The API does not
+ // modify the string -- it is correctly prototyped as taking LPCWSTR in
+ // MinGW-w64, MSVC, and MSDN.
+ OsModule advapi32(L"advapi32.dll");
+ GET_MODULE_PROC(advapi32, ConvertStringSidToSidW);
+ PSID psid = nullptr;
+ BOOL success = pConvertStringSidToSidW(const_cast<LPWSTR>(str.c_str()),
+ &psid);
+ if (!success) {
+ const auto err = GetLastError();
+ throwWindowsError(
+ (std::wstring(L"ConvertStringSidToSidW failed on \"") +
+ str + L'"').c_str(),
+ err);
+ }
+ return localItem<SidTag>(psid);
+}
+
+SecurityDescriptor stringToSd(const std::wstring &str) {
+ OsModule advapi32(L"advapi32.dll");
+ GET_MODULE_PROC(advapi32, ConvertStringSecurityDescriptorToSecurityDescriptorW);
+ PSECURITY_DESCRIPTOR desc = nullptr;
+ if (!pConvertStringSecurityDescriptorToSecurityDescriptorW(
+ str.c_str(), kSDDL_REVISION_1, &desc, nullptr)) {
+ const auto err = GetLastError();
+ throwWindowsError(
+ (std::wstring(L"ConvertStringSecurityDescriptorToSecurityDescriptorW failed on \"") +
+ str + L'"').c_str(),
+ err);
+ }
+ return localItem<SecurityDescriptorTag>(desc);
+}
+
+std::wstring sdToString(PSECURITY_DESCRIPTOR sd) {
+ OsModule advapi32(L"advapi32.dll");
+ GET_MODULE_PROC(advapi32, ConvertSecurityDescriptorToStringSecurityDescriptorW);
+ wchar_t *sdString = nullptr;
+ if (!pConvertSecurityDescriptorToStringSecurityDescriptorW(
+ sd,
+ kSDDL_REVISION_1,
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ &sdString,
+ nullptr)) {
+ throwWindowsError(
+ L"ConvertSecurityDescriptorToStringSecurityDescriptor failed");
+ }
+ PointerLocal freer(sdString);
+ return std::wstring(sdString);
+}
+
+// Vista added a useful flag to CreateNamedPipe, PIPE_REJECT_REMOTE_CLIENTS,
+// that rejects remote connections. Return this flag on Vista, or return 0
+// otherwise.
+DWORD rejectRemoteClientsPipeFlag() {
+ if (isAtLeastWindowsVista()) {
+ // MinGW lacks this flag; MinGW-w64 has it.
+ const DWORD kPIPE_REJECT_REMOTE_CLIENTS = 8;
+ return kPIPE_REJECT_REMOTE_CLIENTS;
+ } else {
+ trace("Omitting PIPE_REJECT_REMOTE_CLIENTS on pre-Vista OS");
+ return 0;
+ }
+}
+
+typedef BOOL WINAPI GetNamedPipeClientProcessId_t(
+ HANDLE Pipe,
+ PULONG ClientProcessId);
+
+std::tuple<GetNamedPipeClientProcessId_Result, DWORD, DWORD>
+getNamedPipeClientProcessId(HANDLE serverPipe) {
+ OsModule kernel32(L"kernel32.dll");
+ const auto pGetNamedPipeClientProcessId =
+ reinterpret_cast<GetNamedPipeClientProcessId_t*>(
+ kernel32.proc("GetNamedPipeClientProcessId"));
+ if (pGetNamedPipeClientProcessId == nullptr) {
+ return std::make_tuple(
+ GetNamedPipeClientProcessId_Result::UnsupportedOs, 0, 0);
+ }
+ ULONG pid = 0;
+ if (!pGetNamedPipeClientProcessId(serverPipe, &pid)) {
+ return std::make_tuple(
+ GetNamedPipeClientProcessId_Result::Failure, 0, GetLastError());
+ }
+ return std::make_tuple(
+ GetNamedPipeClientProcessId_Result::Success,
+ static_cast<DWORD>(pid),
+ 0);
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h
new file mode 100644
index 0000000000..5f9d53aff6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_WINDOWS_SECURITY_H
+#define WINPTY_WINDOWS_SECURITY_H
+
+#include <windows.h>
+#include <aclapi.h>
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+
+// PSID and PSECURITY_DESCRIPTOR are both pointers to void, but we want
+// Sid and SecurityDescriptor to be different types.
+struct SidTag { typedef PSID type; };
+struct AclTag { typedef PACL type; };
+struct SecurityDescriptorTag { typedef PSECURITY_DESCRIPTOR type; };
+
+template <typename T>
+class SecurityItem {
+public:
+ struct Impl {
+ virtual ~Impl() {}
+ };
+
+private:
+ typedef typename T::type P;
+ P m_v;
+ std::unique_ptr<Impl> m_pimpl;
+
+public:
+ P get() const { return m_v; }
+ operator bool() const { return m_v != nullptr; }
+
+ SecurityItem() : m_v(nullptr) {}
+ SecurityItem(P v, std::unique_ptr<Impl> &&pimpl) :
+ m_v(v), m_pimpl(std::move(pimpl)) {}
+ SecurityItem(SecurityItem &&other) :
+ m_v(other.m_v), m_pimpl(std::move(other.m_pimpl)) {
+ other.m_v = nullptr;
+ }
+ SecurityItem &operator=(SecurityItem &&other) {
+ m_v = other.m_v;
+ other.m_v = nullptr;
+ m_pimpl = std::move(other.m_pimpl);
+ return *this;
+ }
+};
+
+typedef SecurityItem<SidTag> Sid;
+typedef SecurityItem<AclTag> Acl;
+typedef SecurityItem<SecurityDescriptorTag> SecurityDescriptor;
+
+Sid getOwnerSid();
+Sid wellKnownSid(
+ const wchar_t *debuggingName,
+ SID_IDENTIFIER_AUTHORITY authority,
+ BYTE authorityCount,
+ DWORD subAuthority0=0,
+ DWORD subAuthority1=0);
+Sid builtinAdminsSid();
+Sid localSystemSid();
+Sid everyoneSid();
+
+SecurityDescriptor createPipeSecurityDescriptorOwnerFullControl();
+SecurityDescriptor createPipeSecurityDescriptorOwnerFullControlEveryoneWrite();
+SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle);
+
+std::wstring sidToString(PSID sid);
+Sid stringToSid(const std::wstring &str);
+SecurityDescriptor stringToSd(const std::wstring &str);
+std::wstring sdToString(PSECURITY_DESCRIPTOR sd);
+
+DWORD rejectRemoteClientsPipeFlag();
+
+enum class GetNamedPipeClientProcessId_Result {
+ Success,
+ Failure,
+ UnsupportedOs,
+};
+
+std::tuple<GetNamedPipeClientProcessId_Result, DWORD, DWORD>
+getNamedPipeClientProcessId(HANDLE serverPipe);
+
+#endif // WINPTY_WINDOWS_SECURITY_H
diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc
new file mode 100644
index 0000000000..d89b00d838
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WindowsVersion.h"
+
+#include <windows.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include "DebugClient.h"
+#include "OsModule.h"
+#include "StringBuilder.h"
+#include "StringUtil.h"
+#include "WinptyAssert.h"
+#include "WinptyException.h"
+
+namespace {
+
+typedef std::tuple<DWORD, DWORD> Version;
+
+// This function can only return a version up to 6.2 unless the executable is
+// manifested for a newer version of Windows. See the MSDN documentation for
+// GetVersionEx.
+OSVERSIONINFOEX getWindowsVersionInfo() {
+ // Allow use of deprecated functions (i.e. GetVersionEx). We need to use
+ // GetVersionEx for the old MinGW toolchain and with MSVC when it targets XP.
+ // Having two code paths makes code harder to test, and it's not obvious how
+ // to detect the presence of a new enough SDK. (Including ntverp.h and
+ // examining VER_PRODUCTBUILD apparently works, but even then, MinGW-w64 and
+ // MSVC seem to use different version numbers.)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4996)
+#endif
+ OSVERSIONINFOEX info = {};
+ info.dwOSVersionInfoSize = sizeof(info);
+ const auto success = GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&info));
+ ASSERT(success && "GetVersionEx failed");
+ return info;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+
+Version getWindowsVersion() {
+ const auto info = getWindowsVersionInfo();
+ return Version(info.dwMajorVersion, info.dwMinorVersion);
+}
+
+struct ModuleNotFound : WinptyException {
+ virtual const wchar_t *what() const WINPTY_NOEXCEPT override {
+ return L"ModuleNotFound";
+ }
+};
+
+// Throws WinptyException on error.
+std::wstring getSystemDirectory() {
+ wchar_t systemDirectory[MAX_PATH];
+ const UINT size = GetSystemDirectoryW(systemDirectory, MAX_PATH);
+ if (size == 0) {
+ throwWindowsError(L"GetSystemDirectory failed");
+ } else if (size >= MAX_PATH) {
+ throwWinptyException(
+ L"GetSystemDirectory: path is longer than MAX_PATH");
+ }
+ return systemDirectory;
+}
+
+#define GET_VERSION_DLL_API(name) \
+ const auto p ## name = \
+ reinterpret_cast<decltype(name)*>( \
+ versionDll.proc(#name)); \
+ if (p ## name == nullptr) { \
+ throwWinptyException(L ## #name L" is missing"); \
+ }
+
+// Throws WinptyException on error.
+VS_FIXEDFILEINFO getFixedFileInfo(const std::wstring &path) {
+ // version.dll is not a conventional KnownDll, so if we link to it, there's
+ // a danger of accidentally loading a malicious DLL. In a more typical
+ // application, perhaps we'd guard against this security issue by
+ // controlling which directories this code runs in (e.g. *not* the
+ // "Downloads" directory), but that's harder for the winpty library.
+ OsModule versionDll(
+ (getSystemDirectory() + L"\\version.dll").c_str(),
+ OsModule::LoadErrorBehavior::Throw);
+ GET_VERSION_DLL_API(GetFileVersionInfoSizeW);
+ GET_VERSION_DLL_API(GetFileVersionInfoW);
+ GET_VERSION_DLL_API(VerQueryValueW);
+ DWORD size = pGetFileVersionInfoSizeW(path.c_str(), nullptr);
+ if (!size) {
+ // I see ERROR_FILE_NOT_FOUND on Win7 and
+ // ERROR_RESOURCE_DATA_NOT_FOUND on WinXP.
+ if (GetLastError() == ERROR_FILE_NOT_FOUND ||
+ GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND) {
+ throw ModuleNotFound();
+ } else {
+ throwWindowsError(
+ (L"GetFileVersionInfoSizeW failed on " + path).c_str());
+ }
+ }
+ std::unique_ptr<char[]> versionBuffer(new char[size]);
+ if (!pGetFileVersionInfoW(path.c_str(), 0, size, versionBuffer.get())) {
+ throwWindowsError((L"GetFileVersionInfoW failed on " + path).c_str());
+ }
+ VS_FIXEDFILEINFO *versionInfo = nullptr;
+ UINT versionInfoSize = 0;
+ if (!pVerQueryValueW(
+ versionBuffer.get(), L"\\",
+ reinterpret_cast<void**>(&versionInfo), &versionInfoSize) ||
+ versionInfo == nullptr ||
+ versionInfoSize != sizeof(VS_FIXEDFILEINFO) ||
+ versionInfo->dwSignature != 0xFEEF04BD) {
+ throwWinptyException((L"VerQueryValueW failed on " + path).c_str());
+ }
+ return *versionInfo;
+}
+
+uint64_t productVersionFromInfo(const VS_FIXEDFILEINFO &info) {
+ return (static_cast<uint64_t>(info.dwProductVersionMS) << 32) |
+ (static_cast<uint64_t>(info.dwProductVersionLS));
+}
+
+uint64_t fileVersionFromInfo(const VS_FIXEDFILEINFO &info) {
+ return (static_cast<uint64_t>(info.dwFileVersionMS) << 32) |
+ (static_cast<uint64_t>(info.dwFileVersionLS));
+}
+
+std::string versionToString(uint64_t version) {
+ StringBuilder b(32);
+ b << ((uint16_t)(version >> 48));
+ b << '.';
+ b << ((uint16_t)(version >> 32));
+ b << '.';
+ b << ((uint16_t)(version >> 16));
+ b << '.';
+ b << ((uint16_t)(version >> 0));
+ return b.str_moved();
+}
+
+} // anonymous namespace
+
+// Returns true for Windows Vista (or Windows Server 2008) or newer.
+bool isAtLeastWindowsVista() {
+ return getWindowsVersion() >= Version(6, 0);
+}
+
+// Returns true for Windows 7 (or Windows Server 2008 R2) or newer.
+bool isAtLeastWindows7() {
+ return getWindowsVersion() >= Version(6, 1);
+}
+
+// Returns true for Windows 8 (or Windows Server 2012) or newer.
+bool isAtLeastWindows8() {
+ return getWindowsVersion() >= Version(6, 2);
+}
+
+#define WINPTY_IA32 1
+#define WINPTY_X64 2
+
+#if defined(_M_IX86) || defined(__i386__)
+#define WINPTY_ARCH WINPTY_IA32
+#elif defined(_M_X64) || defined(__x86_64__)
+#define WINPTY_ARCH WINPTY_X64
+#endif
+
+typedef BOOL WINAPI IsWow64Process_t(HANDLE hProcess, PBOOL Wow64Process);
+
+void dumpWindowsVersion() {
+ if (!isTracingEnabled()) {
+ return;
+ }
+ const auto info = getWindowsVersionInfo();
+ StringBuilder b;
+ b << info.dwMajorVersion << '.' << info.dwMinorVersion
+ << '.' << info.dwBuildNumber << ' '
+ << "SP" << info.wServicePackMajor << '.' << info.wServicePackMinor
+ << ' ';
+ switch (info.wProductType) {
+ case VER_NT_WORKSTATION: b << "Client"; break;
+ case VER_NT_DOMAIN_CONTROLLER: b << "DomainController"; break;
+ case VER_NT_SERVER: b << "Server"; break;
+ default:
+ b << "product=" << info.wProductType; break;
+ }
+ b << ' ';
+#if WINPTY_ARCH == WINPTY_IA32
+ b << "IA32";
+ OsModule kernel32(L"kernel32.dll");
+ IsWow64Process_t *pIsWow64Process =
+ reinterpret_cast<IsWow64Process_t*>(
+ kernel32.proc("IsWow64Process"));
+ if (pIsWow64Process != nullptr) {
+ BOOL result = false;
+ const BOOL success = pIsWow64Process(GetCurrentProcess(), &result);
+ if (!success) {
+ b << " WOW64:error";
+ } else if (success && result) {
+ b << " WOW64";
+ }
+ } else {
+ b << " WOW64:missingapi";
+ }
+#elif WINPTY_ARCH == WINPTY_X64
+ b << "X64";
+#endif
+ const auto dllVersion = [](const wchar_t *dllPath) -> std::string {
+ try {
+ const auto info = getFixedFileInfo(dllPath);
+ StringBuilder fb(64);
+ fb << utf8FromWide(dllPath) << ':';
+ fb << "F:" << versionToString(fileVersionFromInfo(info)) << '/'
+ << "P:" << versionToString(productVersionFromInfo(info));
+ return fb.str_moved();
+ } catch (const ModuleNotFound&) {
+ return utf8FromWide(dllPath) + ":none";
+ } catch (const WinptyException &e) {
+ trace("Error getting %s version: %s",
+ utf8FromWide(dllPath).c_str(), utf8FromWide(e.what()).c_str());
+ return utf8FromWide(dllPath) + ":error";
+ }
+ };
+ b << ' ' << dllVersion(L"kernel32.dll");
+ // ConEmu provides a DLL that hooks many Windows APIs, especially console
+ // APIs. Its existence and version number could be useful in debugging.
+#if WINPTY_ARCH == WINPTY_IA32
+ b << ' ' << dllVersion(L"ConEmuHk.dll");
+#elif WINPTY_ARCH == WINPTY_X64
+ b << ' ' << dllVersion(L"ConEmuHk64.dll");
+#endif
+ trace("Windows version: %s", b.c_str());
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h
new file mode 100644
index 0000000000..a80798417e
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SHARED_WINDOWS_VERSION_H
+#define WINPTY_SHARED_WINDOWS_VERSION_H
+
+bool isAtLeastWindowsVista();
+bool isAtLeastWindows7();
+bool isAtLeastWindows8();
+void dumpWindowsVersion();
+
+#endif // WINPTY_SHARED_WINDOWS_VERSION_H
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc
new file mode 100644
index 0000000000..1ff0de475a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WinptyAssert.h"
+
+#include <windows.h>
+#include <stdlib.h>
+
+#include "DebugClient.h"
+
+void assertTrace(const char *file, int line, const char *cond) {
+ trace("Assertion failed: %s, file %s, line %d",
+ cond, file, line);
+}
+
+#ifdef WINPTY_AGENT_ASSERT
+
+void agentShutdown() {
+ HWND hwnd = GetConsoleWindow();
+ if (hwnd != NULL) {
+ PostMessage(hwnd, WM_CLOSE, 0, 0);
+ Sleep(30000);
+ trace("Agent shutdown: WM_CLOSE did not end agent process");
+ } else {
+ trace("Agent shutdown: GetConsoleWindow() is NULL");
+ }
+ // abort() prints a message to the console, and if it is frozen, then the
+ // process would hang, so instead use exit(). (We shouldn't ever get here,
+ // though, because the WM_CLOSE message should have ended this process.)
+ exit(1);
+}
+
+void agentAssertFail(const char *file, int line, const char *cond) {
+ assertTrace(file, line, cond);
+ agentShutdown();
+}
+
+#endif
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h
new file mode 100644
index 0000000000..b2b8b5e64c
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011-2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_ASSERT_H
+#define WINPTY_ASSERT_H
+
+#ifdef WINPTY_AGENT_ASSERT
+
+void agentShutdown();
+void agentAssertFail(const char *file, int line, const char *cond);
+
+// Calling the standard assert() function does not work in the agent because
+// the error message would be printed to the console, and the only way the
+// user can see the console is via a working agent! Moreover, the console may
+// be frozen, so attempting to write to it would block forever. This custom
+// assert function instead sends the message to the DebugServer, then attempts
+// to close the console, then quietly exits.
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ agentAssertFail(__FILE__, __LINE__, #cond); \
+ } \
+ } while(0)
+
+#else
+
+void assertTrace(const char *file, int line, const char *cond);
+
+// In the other targets, log the assert failure to the debugserver, then fail
+// using the ordinary assert mechanism. In case assert is compiled out, fail
+// using abort. The amount of code inlined is unfortunate, but asserts aren't
+// used much outside the agent.
+#include <assert.h>
+#include <stdlib.h>
+#define ASSERT_CONDITION(cond) (false && (cond))
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ assertTrace(__FILE__, __LINE__, #cond); \
+ assert(ASSERT_CONDITION(#cond)); \
+ abort(); \
+ } \
+ } while(0)
+
+#endif
+
+#endif // WINPTY_ASSERT_H
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyException.cc b/src/libs/3rdparty/winpty/src/shared/WinptyException.cc
new file mode 100644
index 0000000000..d0d48823d2
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyException.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WinptyException.h"
+
+#include <memory>
+#include <string>
+
+#include "StringBuilder.h"
+
+namespace {
+
+class ExceptionImpl : public WinptyException {
+public:
+ ExceptionImpl(const wchar_t *what) :
+ m_what(std::make_shared<std::wstring>(what)) {}
+ virtual const wchar_t *what() const WINPTY_NOEXCEPT override {
+ return m_what->c_str();
+ }
+private:
+ // Using a shared_ptr ensures that copying the object raises no exception.
+ std::shared_ptr<std::wstring> m_what;
+};
+
+} // anonymous namespace
+
+void throwWinptyException(const wchar_t *what) {
+ throw ExceptionImpl(what);
+}
+
+void throwWindowsError(const wchar_t *prefix, DWORD errorCode) {
+ WStringBuilder sb(64);
+ if (prefix != nullptr) {
+ sb << prefix << L": ";
+ }
+ // It might make sense to use FormatMessage here, but IIRC, its API is hard
+ // to figure out.
+ sb << L"Windows error " << errorCode;
+ throwWinptyException(sb.c_str());
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyException.h b/src/libs/3rdparty/winpty/src/shared/WinptyException.h
new file mode 100644
index 0000000000..ec353369e5
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyException.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_EXCEPTION_H
+#define WINPTY_EXCEPTION_H
+
+#include <windows.h>
+
+#if defined(__GNUC__)
+#define WINPTY_NOEXCEPT noexcept
+#elif defined(_MSC_VER) && _MSC_VER >= 1900
+#define WINPTY_NOEXCEPT noexcept
+#else
+#define WINPTY_NOEXCEPT
+#endif
+
+class WinptyException {
+public:
+ virtual const wchar_t *what() const WINPTY_NOEXCEPT = 0;
+ virtual ~WinptyException() {}
+};
+
+void throwWinptyException(const wchar_t *what);
+void throwWindowsError(const wchar_t *prefix, DWORD error=GetLastError());
+
+#endif // WINPTY_EXCEPTION_H
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc
new file mode 100644
index 0000000000..76bb8a584d
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WinptyVersion.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "DebugClient.h"
+
+// This header is auto-generated by either the Makefile (Unix) or
+// UpdateGenVersion.bat (gyp). It is placed in a 'gen' directory, which is
+// added to the search path.
+#include "GenVersion.h"
+
+void dumpVersionToStdout() {
+ printf("winpty version %s\n", GenVersion_Version);
+ printf("commit %s\n", GenVersion_Commit);
+}
+
+void dumpVersionToTrace() {
+ trace("winpty version %s (commit %s)",
+ GenVersion_Version,
+ GenVersion_Commit);
+}
diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h
new file mode 100644
index 0000000000..e6224d7b84
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_VERSION_H
+#define WINPTY_VERSION_H
+
+void dumpVersionToStdout();
+void dumpVersionToTrace();
+
+#endif // WINPTY_VERSION_H
diff --git a/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h b/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h
new file mode 100644
index 0000000000..e716f245e8
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2016 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef WINPTY_SNPRINTF_H
+#define WINPTY_SNPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "WinptyAssert.h"
+
+#if defined(__CYGWIN__) || defined(__MSYS__)
+#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg) \
+ __attribute__((format(printf, (fmtarg), ((vararg)))))
+#elif defined(__GNUC__)
+#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg) \
+ __attribute__((format(ms_printf, (fmtarg), ((vararg)))))
+#else
+#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg)
+#endif
+
+// Returns a value between 0 and size - 1 (inclusive) on success. Returns -1
+// on failure (including truncation). The output buffer is always
+// NUL-terminated.
+inline int
+winpty_vsnprintf(char *out, size_t size, const char *fmt, va_list ap) {
+ ASSERT(size > 0);
+ out[0] = '\0';
+#if defined(_MSC_VER) && _MSC_VER < 1900
+ // MSVC 2015 added a C99-conforming vsnprintf.
+ int count = _vsnprintf_s(out, size, _TRUNCATE, fmt, ap);
+#else
+ // MinGW configurations frequently provide a vsnprintf function that simply
+ // calls one of the MS _vsnprintf* functions, which are not C99 conformant.
+ int count = vsnprintf(out, size, fmt, ap);
+#endif
+ if (count < 0 || static_cast<size_t>(count) >= size) {
+ // On truncation, some *printf* implementations return the
+ // non-truncated size, but other implementations returns -1. Return
+ // -1 for consistency.
+ count = -1;
+ // Guarantee NUL termination.
+ out[size - 1] = '\0';
+ } else {
+ // Guarantee NUL termination.
+ out[count] = '\0';
+ }
+ return count;
+}
+
+// Wraps winpty_vsnprintf.
+inline int winpty_snprintf(char *out, size_t size, const char *fmt, ...)
+ WINPTY_SNPRINTF_FORMAT(3, 4);
+inline int winpty_snprintf(char *out, size_t size, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ const int count = winpty_vsnprintf(out, size, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+// Wraps winpty_vsnprintf with automatic size determination.
+template <size_t size>
+int winpty_vsnprintf(char (&out)[size], const char *fmt, va_list ap) {
+ return winpty_vsnprintf(out, size, fmt, ap);
+}
+
+// Wraps winpty_vsnprintf with automatic size determination.
+template <size_t size>
+int winpty_snprintf(char (&out)[size], const char *fmt, ...)
+ WINPTY_SNPRINTF_FORMAT(2, 3);
+template <size_t size>
+int winpty_snprintf(char (&out)[size], const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ const int count = winpty_vsnprintf(out, size, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+#endif // WINPTY_SNPRINTF_H
diff --git a/src/libs/3rdparty/winpty/src/subdir.mk b/src/libs/3rdparty/winpty/src/subdir.mk
new file mode 100644
index 0000000000..9ae8031b08
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/subdir.mk
@@ -0,0 +1,5 @@
+include src/agent/subdir.mk
+include src/debugserver/subdir.mk
+include src/libwinpty/subdir.mk
+include src/tests/subdir.mk
+include src/unix-adapter/subdir.mk
diff --git a/src/libs/3rdparty/winpty/src/tests/subdir.mk b/src/libs/3rdparty/winpty/src/tests/subdir.mk
new file mode 100644
index 0000000000..18799c4a5a
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/tests/subdir.mk
@@ -0,0 +1,28 @@
+# Copyright (c) 2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+build/%.exe : src/tests/%.cc build/winpty.dll
+ $(info Building $@)
+ @$(MINGW_CXX) $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS) -o $@ $^
+
+TEST_PROGRAMS = \
+ build/trivial_test.exe
+
+-include $(TEST_PROGRAMS:.exe=.d)
diff --git a/src/libs/3rdparty/winpty/src/tests/trivial_test.cc b/src/libs/3rdparty/winpty/src/tests/trivial_test.cc
new file mode 100644
index 0000000000..2188a4befb
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/tests/trivial_test.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <windows.h>
+
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cwchar>
+#include <vector>
+
+#include "../include/winpty.h"
+#include "../shared/DebugClient.h"
+
+static std::vector<unsigned char> filterContent(
+ const std::vector<unsigned char> &content) {
+ std::vector<unsigned char> result;
+ auto it = content.begin();
+ const auto itEnd = content.end();
+ while (it < itEnd) {
+ if (*it == '\r') {
+ // Filter out carriage returns. Sometimes the output starts with
+ // a single CR; other times, it has multiple CRs.
+ it++;
+ } else if (*it == '\x1b' && (it + 1) < itEnd && *(it + 1) == '[') {
+ // Filter out escape sequences. They have no interior letters and
+ // end with a single letter.
+ it += 2;
+ while (it < itEnd && !isalpha(*it)) {
+ it++;
+ }
+ it++;
+ } else {
+ // Let everything else through.
+ result.push_back(*it);
+ it++;
+ }
+ }
+ return result;
+}
+
+// Read bytes from the non-overlapped file handle until the file is closed or
+// until an I/O error occurs.
+static std::vector<unsigned char> readAll(HANDLE handle) {
+ unsigned char buf[1024];
+ std::vector<unsigned char> result;
+ while (true) {
+ DWORD amount = 0;
+ BOOL ret = ReadFile(handle, buf, sizeof(buf), &amount, nullptr);
+ if (!ret || amount == 0) {
+ break;
+ }
+ result.insert(result.end(), buf, buf + amount);
+ }
+ return result;
+}
+
+static void parentTest() {
+ wchar_t program[1024];
+ wchar_t cmdline[1024];
+ GetModuleFileNameW(nullptr, program, 1024);
+
+ {
+ // XXX: We'd like to use swprintf, which is part of C99 and takes a
+ // size_t maxlen argument. MinGW-w64 has this function, as does MSVC.
+ // The old MinGW doesn't, though -- instead, it apparently provides an
+ // swprintf taking no maxlen argument. This *might* be a regression?
+ // (There is also no swnprintf, but that function is obsolescent with a
+ // correct swprintf, and it isn't in POSIX or ISO C.)
+ //
+ // Visual C++ 6 also provided this non-conformant swprintf, and I'm
+ // guessing MSVCRT.DLL does too. (My impression is that the old MinGW
+ // prefers to rely on MSVCRT.DLL for convenience?)
+ //
+ // I could compile differently for old MinGW, but what if it fixes its
+ // function later? Instead, use a workaround. It's starting to make
+ // sense to drop MinGW support in favor of MinGW-w64. This is too
+ // annoying.
+ //
+ // grepbait: OLD-MINGW / WINPTY_TARGET_MSYS1
+ cmdline[0] = L'\0';
+ wcscat(cmdline, L"\"");
+ wcscat(cmdline, program);
+ wcscat(cmdline, L"\" CHILD");
+ }
+ // swnprintf(cmdline, sizeof(cmdline) / sizeof(cmdline[0]),
+ // L"\"%ls\" CHILD", program);
+
+ auto agentCfg = winpty_config_new(0, nullptr);
+ assert(agentCfg != nullptr);
+ auto pty = winpty_open(agentCfg, nullptr);
+ assert(pty != nullptr);
+ winpty_config_free(agentCfg);
+
+ HANDLE conin = CreateFileW(
+ winpty_conin_name(pty),
+ GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
+ HANDLE conout = CreateFileW(
+ winpty_conout_name(pty),
+ GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
+ assert(conin != INVALID_HANDLE_VALUE);
+ assert(conout != INVALID_HANDLE_VALUE);
+
+ auto spawnCfg = winpty_spawn_config_new(
+ WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, program, cmdline,
+ nullptr, nullptr, nullptr);
+ assert(spawnCfg != nullptr);
+ HANDLE process = nullptr;
+ BOOL spawnSuccess = winpty_spawn(
+ pty, spawnCfg, &process, nullptr, nullptr, nullptr);
+ assert(spawnSuccess && process != nullptr);
+
+ auto content = readAll(conout);
+ content = filterContent(content);
+
+ std::vector<unsigned char> expectedContent = {
+ 'H', 'I', '\n', 'X', 'Y', '\n'
+ };
+ DWORD exitCode = 0;
+ assert(GetExitCodeProcess(process, &exitCode) && exitCode == 42);
+ CloseHandle(process);
+ CloseHandle(conin);
+ CloseHandle(conout);
+ assert(content == expectedContent);
+ winpty_free(pty);
+}
+
+static void childTest() {
+ printf("HI\nXY\n");
+ exit(42);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) {
+ parentTest();
+ } else {
+ childTest();
+ }
+ return 0;
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc
new file mode 100644
index 0000000000..39f1e09685
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "InputHandler.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "../shared/DebugClient.h"
+#include "Util.h"
+#include "WakeupFd.h"
+
+InputHandler::InputHandler(
+ HANDLE conin, int inputfd, WakeupFd &completionWakeup) :
+ m_conin(conin),
+ m_inputfd(inputfd),
+ m_completionWakeup(completionWakeup),
+ m_threadHasBeenJoined(false),
+ m_shouldShutdown(0),
+ m_threadCompleted(0)
+{
+ pthread_create(&m_thread, NULL, InputHandler::threadProcS, this);
+}
+
+void InputHandler::shutdown() {
+ startShutdown();
+ if (!m_threadHasBeenJoined) {
+ int ret = pthread_join(m_thread, NULL);
+ assert(ret == 0 && "pthread_join failed");
+ m_threadHasBeenJoined = true;
+ }
+}
+
+void InputHandler::threadProc() {
+ std::vector<char> buffer(4096);
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ while (true) {
+ // Handle shutdown.
+ m_wakeup.reset();
+ if (m_shouldShutdown) {
+ trace("InputHandler: shutting down");
+ break;
+ }
+
+ // Block until data arrives.
+ {
+ const int max_fd = std::max(m_inputfd, m_wakeup.fd());
+ FD_SET(m_inputfd, &readfds);
+ FD_SET(m_wakeup.fd(), &readfds);
+ selectWrapper("InputHandler", max_fd + 1, &readfds);
+ if (!FD_ISSET(m_inputfd, &readfds)) {
+ continue;
+ }
+ }
+
+ const int numRead = read(m_inputfd, &buffer[0], buffer.size());
+ if (numRead == -1 && errno == EINTR) {
+ // Apparently, this read is interrupted on Cygwin 1.7 by a SIGWINCH
+ // signal even though I set the SA_RESTART flag on the handler.
+ continue;
+ }
+
+ // tty is closed, or the read failed for some unexpected reason.
+ if (numRead <= 0) {
+ trace("InputHandler: tty read failed: numRead=%d", numRead);
+ break;
+ }
+
+ DWORD written = 0;
+ BOOL ret = WriteFile(m_conin,
+ &buffer[0], numRead,
+ &written, NULL);
+ if (!ret || written != static_cast<DWORD>(numRead)) {
+ if (!ret && GetLastError() == ERROR_BROKEN_PIPE) {
+ trace("InputHandler: pipe closed: written=%u",
+ static_cast<unsigned int>(written));
+ } else {
+ trace("InputHandler: write failed: "
+ "ret=%d lastError=0x%x numRead=%d written=%u",
+ ret,
+ static_cast<unsigned int>(GetLastError()),
+ numRead,
+ static_cast<unsigned int>(written));
+ }
+ break;
+ }
+ }
+ m_threadCompleted = 1;
+ m_completionWakeup.set();
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h
new file mode 100644
index 0000000000..9c3f540d63
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNIX_ADAPTER_INPUT_HANDLER_H
+#define UNIX_ADAPTER_INPUT_HANDLER_H
+
+#include <windows.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "WakeupFd.h"
+
+// Connect a Cygwin blocking fd to winpty CONIN.
+class InputHandler {
+public:
+ InputHandler(HANDLE conin, int inputfd, WakeupFd &completionWakeup);
+ ~InputHandler() { shutdown(); }
+ bool isComplete() { return m_threadCompleted; }
+ void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); }
+ void shutdown();
+
+private:
+ static void *threadProcS(void *pvthis) {
+ reinterpret_cast<InputHandler*>(pvthis)->threadProc();
+ return NULL;
+ }
+ void threadProc();
+
+ HANDLE m_conin;
+ int m_inputfd;
+ pthread_t m_thread;
+ WakeupFd &m_completionWakeup;
+ WakeupFd m_wakeup;
+ bool m_threadHasBeenJoined;
+ volatile sig_atomic_t m_shouldShutdown;
+ volatile sig_atomic_t m_threadCompleted;
+};
+
+#endif // UNIX_ADAPTER_INPUT_HANDLER_H
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc
new file mode 100644
index 0000000000..573b8adced
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "OutputHandler.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "../shared/DebugClient.h"
+#include "Util.h"
+#include "WakeupFd.h"
+
+OutputHandler::OutputHandler(
+ HANDLE conout, int outputfd, WakeupFd &completionWakeup) :
+ m_conout(conout),
+ m_outputfd(outputfd),
+ m_completionWakeup(completionWakeup),
+ m_threadHasBeenJoined(false),
+ m_threadCompleted(0)
+{
+ pthread_create(&m_thread, NULL, OutputHandler::threadProcS, this);
+}
+
+void OutputHandler::shutdown() {
+ if (!m_threadHasBeenJoined) {
+ int ret = pthread_join(m_thread, NULL);
+ assert(ret == 0 && "pthread_join failed");
+ m_threadHasBeenJoined = true;
+ }
+}
+
+void OutputHandler::threadProc() {
+ std::vector<char> buffer(4096);
+ while (true) {
+ DWORD numRead = 0;
+ BOOL ret = ReadFile(m_conout,
+ &buffer[0], buffer.size(),
+ &numRead, NULL);
+ if (!ret || numRead == 0) {
+ if (!ret && GetLastError() == ERROR_BROKEN_PIPE) {
+ trace("OutputHandler: pipe closed: numRead=%u",
+ static_cast<unsigned int>(numRead));
+ } else {
+ trace("OutputHandler: read failed: "
+ "ret=%d lastError=0x%x numRead=%u",
+ ret,
+ static_cast<unsigned int>(GetLastError()),
+ static_cast<unsigned int>(numRead));
+ }
+ break;
+ }
+ if (!writeAll(m_outputfd, &buffer[0], numRead)) {
+ break;
+ }
+ }
+ m_threadCompleted = 1;
+ m_completionWakeup.set();
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h
new file mode 100644
index 0000000000..48241c5538
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNIX_ADAPTER_OUTPUT_HANDLER_H
+#define UNIX_ADAPTER_OUTPUT_HANDLER_H
+
+#include <windows.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "WakeupFd.h"
+
+// Connect winpty CONOUT/CONERR to a Cygwin blocking fd.
+class OutputHandler {
+public:
+ OutputHandler(HANDLE conout, int outputfd, WakeupFd &completionWakeup);
+ ~OutputHandler() { shutdown(); }
+ bool isComplete() { return m_threadCompleted; }
+ void shutdown();
+
+private:
+ static void *threadProcS(void *pvthis) {
+ reinterpret_cast<OutputHandler*>(pvthis)->threadProc();
+ return NULL;
+ }
+ void threadProc();
+
+ HANDLE m_conout;
+ int m_outputfd;
+ pthread_t m_thread;
+ WakeupFd &m_completionWakeup;
+ bool m_threadHasBeenJoined;
+ volatile sig_atomic_t m_threadCompleted;
+};
+
+#endif // UNIX_ADAPTER_OUTPUT_HANDLER_H
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc b/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc
new file mode 100644
index 0000000000..e13f84a529
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "Util.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../shared/DebugClient.h"
+
+// Write the entire buffer, restarting it as necessary.
+bool writeAll(int fd, const void *buffer, size_t size) {
+ size_t written = 0;
+ while (written < size) {
+ int ret = write(fd,
+ reinterpret_cast<const char*>(buffer) + written,
+ size - written);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ }
+ if (ret <= 0) {
+ trace("write failed: "
+ "fd=%d errno=%d size=%u written=%d ret=%d",
+ fd,
+ errno,
+ static_cast<unsigned int>(size),
+ static_cast<unsigned int>(written),
+ ret);
+ return false;
+ }
+ assert(static_cast<size_t>(ret) <= size - written);
+ written += ret;
+ }
+ assert(written == size);
+ return true;
+}
+
+bool writeStr(int fd, const char *str) {
+ return writeAll(fd, str, strlen(str));
+}
+
+void selectWrapper(const char *diagName, int nfds, fd_set *readfds) {
+ int ret = select(nfds, readfds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ FD_ZERO(readfds);
+ return;
+ }
+#ifdef WINPTY_TARGET_MSYS1
+ // The select system call sometimes fails with EAGAIN instead of EINTR.
+ // This apparantly only happens with the old Cygwin fork "MSYS" used in
+ // the mingw.org project. select is not supposed to fail with EAGAIN,
+ // and EAGAIN does not make much sense as an error code. (The whole
+ // point of select is to block.)
+ if (errno == EAGAIN) {
+ trace("%s select returned EAGAIN: interpreting like EINTR",
+ diagName);
+ FD_ZERO(readfds);
+ return;
+ }
+#endif
+ fprintf(stderr, "Internal error: %s select failed: "
+ "error %d", diagName, errno);
+ abort();
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/Util.h b/src/libs/3rdparty/winpty/src/unix-adapter/Util.h
new file mode 100644
index 0000000000..cadb4c82a9
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/Util.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNIX_ADAPTER_UTIL_H
+#define UNIX_ADAPTER_UTIL_H
+
+#include <stdlib.h>
+#include <sys/select.h>
+
+bool writeAll(int fd, const void *buffer, size_t size);
+bool writeStr(int fd, const char *str);
+void selectWrapper(const char *diagName, int nfds, fd_set *readfds);
+
+#endif // UNIX_ADAPTER_UTIL_H
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc
new file mode 100644
index 0000000000..6b47379015
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "WakeupFd.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void setFdNonBlock(int fd) {
+ int status = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, status | O_NONBLOCK);
+}
+
+WakeupFd::WakeupFd() {
+ int pipeFd[2];
+ if (pipe(pipeFd) != 0) {
+ perror("Could not create internal wakeup pipe");
+ abort();
+ }
+ m_pipeReadFd = pipeFd[0];
+ m_pipeWriteFd = pipeFd[1];
+ setFdNonBlock(m_pipeReadFd);
+ setFdNonBlock(m_pipeWriteFd);
+}
+
+WakeupFd::~WakeupFd() {
+ close(m_pipeReadFd);
+ close(m_pipeWriteFd);
+}
+
+void WakeupFd::set() {
+ char dummy = 0;
+ int ret;
+ do {
+ ret = write(m_pipeWriteFd, &dummy, 1);
+ } while (ret < 0 && errno == EINTR);
+}
+
+void WakeupFd::reset() {
+ char tmpBuf[256];
+ while (true) {
+ int amount = read(m_pipeReadFd, tmpBuf, sizeof(tmpBuf));
+ if (amount < 0 && errno == EAGAIN) {
+ break;
+ } else if (amount <= 0) {
+ perror("error reading from internal wakeup pipe");
+ abort();
+ }
+ }
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h
new file mode 100644
index 0000000000..dd8d362aa1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef UNIX_ADAPTER_WAKEUP_FD_H
+#define UNIX_ADAPTER_WAKEUP_FD_H
+
+class WakeupFd {
+public:
+ WakeupFd();
+ ~WakeupFd();
+ int fd() { return m_pipeReadFd; }
+ void set();
+ void reset();
+
+private:
+ // Do not allow copying the WakeupFd object.
+ WakeupFd(const WakeupFd &other);
+ WakeupFd &operator=(const WakeupFd &other);
+
+private:
+ int m_pipeReadFd;
+ int m_pipeWriteFd;
+};
+
+#endif // UNIX_ADAPTER_WAKEUP_FD_H
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/main.cc b/src/libs/3rdparty/winpty/src/unix-adapter/main.cc
new file mode 100644
index 0000000000..992cb70e44
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/main.cc
@@ -0,0 +1,729 @@
+// Copyright (c) 2011-2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// MSYS's sys/cygwin.h header only declares cygwin_internal if WINVER is
+// defined, which is defined in windows.h. Therefore, include windows.h early.
+#include <windows.h>
+
+#include <assert.h>
+#include <cygwin/version.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/cygwin.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <winpty.h>
+#include "../shared/DebugClient.h"
+#include "../shared/UnixCtrlChars.h"
+#include "../shared/WinptyVersion.h"
+#include "InputHandler.h"
+#include "OutputHandler.h"
+#include "Util.h"
+#include "WakeupFd.h"
+
+#define CSI "\x1b["
+
+static WakeupFd *g_mainWakeup = NULL;
+
+static WakeupFd &mainWakeup()
+{
+ if (g_mainWakeup == NULL) {
+ static const char msg[] = "Internal error: g_mainWakeup is NULL\r\n";
+ write(STDERR_FILENO, msg, sizeof(msg) - 1);
+ abort();
+ }
+ return *g_mainWakeup;
+}
+
+struct SavedTermiosMode {
+ int count;
+ bool valid[3];
+ termios mode[3];
+};
+
+// Put the input terminal into non-canonical mode.
+static SavedTermiosMode setRawTerminalMode(
+ bool allowNonTtys, bool setStdout, bool setStderr)
+{
+ SavedTermiosMode ret;
+ const char *const kNames[3] = { "stdin", "stdout", "stderr" };
+
+ ret.valid[0] = true;
+ ret.valid[1] = setStdout;
+ ret.valid[2] = setStderr;
+
+ for (int i = 0; i < 3; ++i) {
+ if (!ret.valid[i]) {
+ continue;
+ }
+ if (!isatty(i)) {
+ ret.valid[i] = false;
+ if (!allowNonTtys) {
+ fprintf(stderr, "%s is not a tty\n", kNames[i]);
+ exit(1);
+ }
+ } else {
+ ret.valid[i] = true;
+ if (tcgetattr(i, &ret.mode[i]) < 0) {
+ perror("tcgetattr failed");
+ exit(1);
+ }
+ }
+ }
+
+ if (ret.valid[STDIN_FILENO]) {
+ termios buf;
+ if (tcgetattr(STDIN_FILENO, &buf) < 0) {
+ perror("tcgetattr failed");
+ exit(1);
+ }
+ buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ buf.c_cflag &= ~(CSIZE | PARENB);
+ buf.c_cflag |= CS8;
+ buf.c_cc[VMIN] = 1; // blocking read
+ buf.c_cc[VTIME] = 0;
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &buf) < 0) {
+ fprintf(stderr, "tcsetattr failed\n");
+ exit(1);
+ }
+ }
+
+ for (int i = STDOUT_FILENO; i <= STDERR_FILENO; ++i) {
+ if (!ret.valid[i]) {
+ continue;
+ }
+ termios buf;
+ if (tcgetattr(i, &buf) < 0) {
+ perror("tcgetattr failed");
+ exit(1);
+ }
+ buf.c_cflag &= ~(CSIZE | PARENB);
+ buf.c_cflag |= CS8;
+ buf.c_oflag &= ~OPOST;
+ if (tcsetattr(i, TCSAFLUSH, &buf) < 0) {
+ fprintf(stderr, "tcsetattr failed\n");
+ exit(1);
+ }
+ }
+
+ return ret;
+}
+
+static void restoreTerminalMode(const SavedTermiosMode &original)
+{
+ for (int i = 0; i < 3; ++i) {
+ if (!original.valid[i]) {
+ continue;
+ }
+ if (tcsetattr(i, TCSAFLUSH, &original.mode[i]) < 0) {
+ perror("error restoring terminal mode");
+ exit(1);
+ }
+ }
+}
+
+static void debugShowKey(bool allowNonTtys)
+{
+ printf("\nPress any keys -- Ctrl-D exits\n\n");
+ const SavedTermiosMode saved =
+ setRawTerminalMode(allowNonTtys, false, false);
+ char buf[128];
+ while (true) {
+ const ssize_t len = read(STDIN_FILENO, buf, sizeof(buf));
+ if (len <= 0) {
+ break;
+ }
+ for (int i = 0; i < len; ++i) {
+ char ctrl = decodeUnixCtrlChar(buf[i]);
+ if (ctrl == '\0') {
+ putchar(buf[i]);
+ } else {
+ putchar('^');
+ putchar(ctrl);
+ }
+ }
+ for (int i = 0; i < len; ++i) {
+ unsigned char uch = buf[i];
+ printf("\t%3d %04o 0x%02x\n", uch, uch, uch);
+ fflush(stdout);
+ }
+ if (buf[0] == 4) {
+ // Ctrl-D
+ break;
+ }
+ }
+ restoreTerminalMode(saved);
+}
+
+static void terminalResized(int signo)
+{
+ mainWakeup().set();
+}
+
+static void registerResizeSignalHandler()
+{
+ struct sigaction resizeSigAct;
+ memset(&resizeSigAct, 0, sizeof(resizeSigAct));
+ resizeSigAct.sa_handler = terminalResized;
+ resizeSigAct.sa_flags = SA_RESTART;
+ sigaction(SIGWINCH, &resizeSigAct, NULL);
+}
+
+// Convert the path to a Win32 path if it is a POSIX path, and convert slashes
+// to backslashes.
+static std::string convertPosixPathToWin(const std::string &path)
+{
+ char *tmp;
+#if defined(CYGWIN_VERSION_CYGWIN_CONV) && \
+ CYGWIN_VERSION_API_MINOR >= CYGWIN_VERSION_CYGWIN_CONV
+ // MSYS2 and versions of Cygwin released after 2009 or so use this API.
+ // The original MSYS still lacks this API.
+ ssize_t newSize = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE,
+ path.c_str(), NULL, 0);
+ assert(newSize >= 0);
+ tmp = new char[newSize + 1];
+ ssize_t success = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE,
+ path.c_str(), tmp, newSize + 1);
+ assert(success == 0);
+#else
+ // In the current Cygwin header file, this API is documented as deprecated
+ // because it's restricted to paths of MAX_PATH length. In the CVS version
+ // of MSYS, the newer API doesn't exist, and this older API is implemented
+ // using msys_p2w, which seems like it would handle paths larger than
+ // MAX_PATH, but there's no way to query how large the new path is.
+ // Hopefully, this is large enough.
+ tmp = new char[MAX_PATH + path.size()];
+ cygwin_conv_to_win32_path(path.c_str(), tmp);
+#endif
+ for (int i = 0; tmp[i] != '\0'; ++i) {
+ if (tmp[i] == '/')
+ tmp[i] = '\\';
+ }
+ std::string ret(tmp);
+ delete [] tmp;
+ return ret;
+}
+
+static std::string resolvePath(const std::string &path)
+{
+ char ret[PATH_MAX];
+ ret[0] = '\0';
+ if (realpath(path.c_str(), ret) != ret) {
+ return std::string();
+ }
+ return ret;
+}
+
+template <size_t N>
+static bool endsWith(const std::string &path, const char (&suf)[N])
+{
+ const size_t suffixLen = N - 1;
+ char actualSuf[N];
+ if (path.size() < suffixLen) {
+ return false;
+ }
+ strcpy(actualSuf, &path.c_str()[path.size() - suffixLen]);
+ for (size_t i = 0; i < suffixLen; ++i) {
+ actualSuf[i] = tolower(actualSuf[i]);
+ }
+ return !strcmp(actualSuf, suf);
+}
+
+static std::string findProgram(
+ const char *winptyProgName,
+ const std::string &prog)
+{
+ std::string candidate;
+ if (prog.find('/') == std::string::npos &&
+ prog.find('\\') == std::string::npos) {
+ // XXX: It would be nice to use a lambda here (once/if old MSYS support
+ // is dropped).
+ // Search the PATH.
+ const char *const pathVar = getenv("PATH");
+ const std::string pathList(pathVar ? pathVar : "");
+ size_t elpos = 0;
+ while (true) {
+ const size_t elend = pathList.find(':', elpos);
+ candidate = pathList.substr(elpos, elend - elpos);
+ if (!candidate.empty() && *(candidate.end() - 1) != '/') {
+ candidate += '/';
+ }
+ candidate += prog;
+ candidate = resolvePath(candidate);
+ if (!candidate.empty()) {
+ int perm = X_OK;
+ if (endsWith(candidate, ".bat") || endsWith(candidate, ".cmd")) {
+#ifdef __MSYS__
+ // In MSYS/MSYS2, batch files don't have the execute bit
+ // set, so just check that they're readable.
+ perm = R_OK;
+#endif
+ } else if (endsWith(candidate, ".com") || endsWith(candidate, ".exe")) {
+ // Do nothing.
+ } else {
+ // Make the exe extension explicit so that we don't try to
+ // run shell scripts with CreateProcess/winpty_spawn.
+ candidate += ".exe";
+ }
+ if (!access(candidate.c_str(), perm)) {
+ break;
+ }
+ }
+ if (elend == std::string::npos) {
+ fprintf(stderr, "%s: error: cannot start '%s': Not found in PATH\n",
+ winptyProgName, prog.c_str());
+ exit(1);
+ } else {
+ elpos = elend + 1;
+ }
+ }
+ } else {
+ candidate = resolvePath(prog);
+ if (candidate.empty()) {
+ std::string errstr(strerror(errno));
+ fprintf(stderr, "%s: error: cannot start '%s': %s\n",
+ winptyProgName, prog.c_str(), errstr.c_str());
+ exit(1);
+ }
+ }
+ return convertPosixPathToWin(candidate);
+}
+
+// Convert argc/argv into a Win32 command-line following the escaping convention
+// documented on MSDN. (e.g. see CommandLineToArgvW documentation)
+static std::string argvToCommandLine(const std::vector<std::string> &argv)
+{
+ std::string result;
+ for (size_t argIndex = 0; argIndex < argv.size(); ++argIndex) {
+ if (argIndex > 0)
+ result.push_back(' ');
+ const char *arg = argv[argIndex].c_str();
+ const bool quote =
+ strchr(arg, ' ') != NULL ||
+ strchr(arg, '\t') != NULL ||
+ *arg == '\0';
+ if (quote)
+ result.push_back('\"');
+ int bsCount = 0;
+ for (const char *p = arg; *p != '\0'; ++p) {
+ if (*p == '\\') {
+ bsCount++;
+ } else if (*p == '\"') {
+ result.append(bsCount * 2 + 1, '\\');
+ result.push_back('\"');
+ bsCount = 0;
+ } else {
+ result.append(bsCount, '\\');
+ bsCount = 0;
+ result.push_back(*p);
+ }
+ }
+ if (quote) {
+ result.append(bsCount * 2, '\\');
+ result.push_back('\"');
+ } else {
+ result.append(bsCount, '\\');
+ }
+ }
+ return result;
+}
+
+static wchar_t *heapMbsToWcs(const char *text)
+{
+ // Calling mbstowcs with a NULL first argument seems to be broken on MSYS.
+ // Instead of returning the size of the converted string, it returns 0.
+ // Using strlen(text) * 2 is probably big enough.
+ size_t maxLen = strlen(text) * 2 + 1;
+ wchar_t *ret = new wchar_t[maxLen];
+ size_t len = mbstowcs(ret, text, maxLen);
+ assert(len != (size_t)-1 && len < maxLen);
+ return ret;
+}
+
+static char *heapWcsToMbs(const wchar_t *text)
+{
+ // Calling wcstombs with a NULL first argument seems to be broken on MSYS.
+ // Instead of returning the size of the converted string, it returns 0.
+ // Using wcslen(text) * 3 is big enough for UTF-8 and probably other
+ // encodings. For UTF-8, codepoints that fit in a single wchar
+ // (U+0000 to U+FFFF) are encoded using 1-3 bytes. The remaining code
+ // points needs two wchar's and are encoded using 4 bytes.
+ size_t maxLen = wcslen(text) * 3 + 1;
+ char *ret = new char[maxLen];
+ size_t len = wcstombs(ret, text, maxLen);
+ if (len == (size_t)-1 || len >= maxLen) {
+ delete [] ret;
+ return NULL;
+ } else {
+ return ret;
+ }
+}
+
+static std::string wcsToMbs(const wchar_t *text)
+{
+ std::string ret;
+ const char *ptr = heapWcsToMbs(text);
+ if (ptr != NULL) {
+ ret = ptr;
+ delete [] ptr;
+ }
+ return ret;
+}
+
+void setupWin32Environment()
+{
+ std::map<std::string, std::string> varsToCopy;
+ const char *vars[] = {
+ "WINPTY_DEBUG",
+ "WINPTY_SHOW_CONSOLE",
+ NULL
+ };
+ for (int i = 0; vars[i] != NULL; ++i) {
+ const char *cstr = getenv(vars[i]);
+ if (cstr != NULL && cstr[0] != '\0') {
+ varsToCopy[vars[i]] = cstr;
+ }
+ }
+
+#if defined(__MSYS__) && CYGWIN_VERSION_API_MINOR >= 48 || \
+ !defined(__MSYS__) && CYGWIN_VERSION_API_MINOR >= 153
+ // Use CW_SYNC_WINENV to copy the Unix environment to the Win32
+ // environment. The command performs special translation on some variables
+ // (such as PATH and TMP). It also copies the debugging environment
+ // variables.
+ //
+ // Note that the API minor versions have diverged in Cygwin and MSYS.
+ // CW_SYNC_WINENV was added to Cygwin in version 153. (Cygwin's
+ // include/cygwin/version.h says that CW_SETUP_WINENV was added in 153.
+ // The flag was renamed 8 days after it was added, but the API docs weren't
+ // updated.) The flag was added to MSYS in version 48.
+ //
+ // Also, in my limited testing, this call seems to be necessary with Cygwin
+ // but unnecessary with MSYS. Perhaps MSYS is automatically syncing the
+ // Unix environment with the Win32 environment before starting console.exe?
+ // It shouldn't hurt to call it for MSYS.
+ cygwin_internal(CW_SYNC_WINENV);
+#endif
+
+ // Copy debugging environment variables from the Cygwin environment
+ // to the Win32 environment so the agent will inherit it.
+ for (std::map<std::string, std::string>::iterator it = varsToCopy.begin();
+ it != varsToCopy.end();
+ ++it) {
+ wchar_t *nameW = heapMbsToWcs(it->first.c_str());
+ wchar_t *valueW = heapMbsToWcs(it->second.c_str());
+ SetEnvironmentVariableW(nameW, valueW);
+ delete [] nameW;
+ delete [] valueW;
+ }
+
+ // Clear the TERM variable. The child process's immediate console/terminal
+ // environment is a Windows console, not the terminal that winpty is
+ // communicating with. Leaving the TERM variable set can break programs in
+ // various ways. (e.g. arrows keys broken in Cygwin less, IronPython's
+ // help(...) function doesn't start, misc programs decide they should
+ // output color escape codes on pre-Win10). See
+ // https://github.com/rprichard/winpty/issues/43.
+ SetEnvironmentVariableW(L"TERM", NULL);
+}
+
+static void usage(const char *program, int exitCode)
+{
+ printf("Usage: %s [options] [--] program [args]\n", program);
+ printf("\n");
+ printf("Options:\n");
+ printf(" -h, --help Show this help message\n");
+ printf(" --mouse Enable terminal mouse input\n");
+ printf(" --showkey Dump STDIN escape sequences\n");
+ printf(" --version Show the winpty version number\n");
+ exit(exitCode);
+}
+
+struct Arguments {
+ std::vector<std::string> childArgv;
+ bool mouseInput;
+ bool testAllowNonTtys;
+ bool testConerr;
+ bool testPlainOutput;
+ bool testColorEscapes;
+};
+
+static void parseArguments(int argc, char *argv[], Arguments &out)
+{
+ out.mouseInput = false;
+ out.testAllowNonTtys = false;
+ out.testConerr = false;
+ out.testPlainOutput = false;
+ out.testColorEscapes = false;
+ bool doShowKeys = false;
+ const char *const program = argc >= 1 ? argv[0] : "<program>";
+ int argi = 1;
+ while (argi < argc) {
+ std::string arg(argv[argi++]);
+ if (arg.size() >= 1 && arg[0] == '-') {
+ if (arg == "-h" || arg == "--help") {
+ usage(program, 0);
+ } else if (arg == "--mouse") {
+ out.mouseInput = true;
+ } else if (arg == "--showkey") {
+ doShowKeys = true;
+ } else if (arg == "--version") {
+ dumpVersionToStdout();
+ exit(0);
+ } else if (arg == "-Xallow-non-tty") {
+ out.testAllowNonTtys = true;
+ } else if (arg == "-Xconerr") {
+ out.testConerr = true;
+ } else if (arg == "-Xplain") {
+ out.testPlainOutput = true;
+ } else if (arg == "-Xcolor") {
+ out.testColorEscapes = true;
+ } else if (arg == "--") {
+ break;
+ } else {
+ fprintf(stderr, "Error: unrecognized option: '%s'\n",
+ arg.c_str());
+ exit(1);
+ }
+ } else {
+ out.childArgv.push_back(arg);
+ break;
+ }
+ }
+ for (; argi < argc; ++argi) {
+ out.childArgv.push_back(argv[argi]);
+ }
+ if (doShowKeys) {
+ debugShowKey(out.testAllowNonTtys);
+ exit(0);
+ }
+ if (out.childArgv.size() == 0) {
+ usage(program, 1);
+ }
+}
+
+static std::string errorMessageToString(DWORD err)
+{
+ // Use FormatMessageW rather than FormatMessageA, because we want to use
+ // wcstombs to convert to the Cygwin locale, which might not match the
+ // codepage FormatMessageA would use. We need to convert using wcstombs,
+ // rather than print using %ls, because %ls doesn't work in the original
+ // MSYS.
+ wchar_t *wideMsgPtr = NULL;
+ const DWORD formatRet = FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<wchar_t*>(&wideMsgPtr),
+ 0,
+ NULL);
+ if (formatRet == 0 || wideMsgPtr == NULL) {
+ return std::string();
+ }
+ std::string msg = wcsToMbs(wideMsgPtr);
+ LocalFree(wideMsgPtr);
+ const size_t pos = msg.find_last_not_of(" \r\n\t");
+ if (pos == std::string::npos) {
+ msg.clear();
+ } else {
+ msg.erase(pos + 1);
+ }
+ return msg;
+}
+
+static std::string formatErrorMessage(DWORD err)
+{
+ char buf[64];
+ sprintf(buf, "error %#x", static_cast<unsigned int>(err));
+ std::string ret = errorMessageToString(err);
+ if (ret.empty()) {
+ ret += buf;
+ } else {
+ ret += " (";
+ ret += buf;
+ ret += ")";
+ }
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ setlocale(LC_ALL, "");
+
+ g_mainWakeup = new WakeupFd();
+
+ Arguments args;
+ parseArguments(argc, argv, args);
+
+ setupWin32Environment();
+
+ winsize sz = { 0 };
+ sz.ws_col = 80;
+ sz.ws_row = 25;
+ ioctl(STDIN_FILENO, TIOCGWINSZ, &sz);
+
+ DWORD agentFlags = WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION;
+ if (args.testConerr) { agentFlags |= WINPTY_FLAG_CONERR; }
+ if (args.testPlainOutput) { agentFlags |= WINPTY_FLAG_PLAIN_OUTPUT; }
+ if (args.testColorEscapes) { agentFlags |= WINPTY_FLAG_COLOR_ESCAPES; }
+ winpty_config_t *agentCfg = winpty_config_new(agentFlags, NULL);
+ assert(agentCfg != NULL);
+ winpty_config_set_initial_size(agentCfg, sz.ws_col, sz.ws_row);
+ if (args.mouseInput) {
+ winpty_config_set_mouse_mode(agentCfg, WINPTY_MOUSE_MODE_FORCE);
+ }
+
+ winpty_error_ptr_t openErr = NULL;
+ winpty_t *wp = winpty_open(agentCfg, &openErr);
+ if (wp == NULL) {
+ fprintf(stderr, "Error creating winpty: %s\n",
+ wcsToMbs(winpty_error_msg(openErr)).c_str());
+ exit(1);
+ }
+ winpty_config_free(agentCfg);
+ winpty_error_free(openErr);
+
+ HANDLE conin = CreateFileW(winpty_conin_name(wp), GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ HANDLE conout = CreateFileW(winpty_conout_name(wp), GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ assert(conin != INVALID_HANDLE_VALUE);
+ assert(conout != INVALID_HANDLE_VALUE);
+ HANDLE conerr = NULL;
+ if (args.testConerr) {
+ conerr = CreateFileW(winpty_conerr_name(wp), GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ assert(conerr != INVALID_HANDLE_VALUE);
+ }
+
+ HANDLE childHandle = NULL;
+
+ {
+ // Start the child process under the console.
+ args.childArgv[0] = findProgram(argv[0], args.childArgv[0]);
+ std::string cmdLine = argvToCommandLine(args.childArgv);
+ wchar_t *cmdLineW = heapMbsToWcs(cmdLine.c_str());
+
+ winpty_spawn_config_t *spawnCfg = winpty_spawn_config_new(
+ WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
+ NULL, cmdLineW, NULL, NULL, NULL);
+ assert(spawnCfg != NULL);
+
+ winpty_error_ptr_t spawnErr = NULL;
+ DWORD lastError = 0;
+ BOOL spawnRet = winpty_spawn(wp, spawnCfg, &childHandle, NULL,
+ &lastError, &spawnErr);
+ winpty_spawn_config_free(spawnCfg);
+
+ if (!spawnRet) {
+ winpty_result_t spawnCode = winpty_error_code(spawnErr);
+ if (spawnCode == WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED) {
+ fprintf(stderr, "%s: error: cannot start '%s': %s\n",
+ argv[0],
+ cmdLine.c_str(),
+ formatErrorMessage(lastError).c_str());
+ } else {
+ fprintf(stderr, "%s: error: cannot start '%s': internal error: %s\n",
+ argv[0],
+ cmdLine.c_str(),
+ wcsToMbs(winpty_error_msg(spawnErr)).c_str());
+ }
+ exit(1);
+ }
+ winpty_error_free(spawnErr);
+ delete [] cmdLineW;
+ }
+
+ registerResizeSignalHandler();
+ SavedTermiosMode mode =
+ setRawTerminalMode(args.testAllowNonTtys, true, args.testConerr);
+
+ InputHandler inputHandler(conin, STDIN_FILENO, mainWakeup());
+ OutputHandler outputHandler(conout, STDOUT_FILENO, mainWakeup());
+ OutputHandler *errorHandler = NULL;
+ if (args.testConerr) {
+ errorHandler = new OutputHandler(conerr, STDERR_FILENO, mainWakeup());
+ }
+
+ while (true) {
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(mainWakeup().fd(), &readfds);
+ selectWrapper("main thread", mainWakeup().fd() + 1, &readfds);
+ mainWakeup().reset();
+
+ // Check for terminal resize.
+ {
+ winsize sz2;
+ ioctl(STDIN_FILENO, TIOCGWINSZ, &sz2);
+ if (memcmp(&sz, &sz2, sizeof(sz)) != 0) {
+ sz = sz2;
+ winpty_set_size(wp, sz.ws_col, sz.ws_row, NULL);
+ }
+ }
+
+ // Check for an I/O handler shutting down (possibly indicating that the
+ // child process has exited).
+ if (inputHandler.isComplete() || outputHandler.isComplete() ||
+ (errorHandler != NULL && errorHandler->isComplete())) {
+ break;
+ }
+ }
+
+ // Kill the agent connection. This will kill the agent, closing the CONIN
+ // and CONOUT pipes on the agent pipe, prompting our I/O handler to shut
+ // down.
+ winpty_free(wp);
+
+ inputHandler.shutdown();
+ outputHandler.shutdown();
+ CloseHandle(conin);
+ CloseHandle(conout);
+
+ if (errorHandler != NULL) {
+ errorHandler->shutdown();
+ delete errorHandler;
+ CloseHandle(conerr);
+ }
+
+ restoreTerminalMode(mode);
+
+ DWORD exitCode = 0;
+ if (!GetExitCodeProcess(childHandle, &exitCode)) {
+ exitCode = 1;
+ }
+ CloseHandle(childHandle);
+ return exitCode;
+}
diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk b/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk
new file mode 100644
index 0000000000..200193a1b1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk
@@ -0,0 +1,41 @@
+# Copyright (c) 2011-2015 Ryan Prichard
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+ALL_TARGETS += build/$(UNIX_ADAPTER_EXE)
+
+$(eval $(call def_unix_target,unix-adapter,))
+
+UNIX_ADAPTER_OBJECTS = \
+ build/unix-adapter/unix-adapter/InputHandler.o \
+ build/unix-adapter/unix-adapter/OutputHandler.o \
+ build/unix-adapter/unix-adapter/Util.o \
+ build/unix-adapter/unix-adapter/WakeupFd.o \
+ build/unix-adapter/unix-adapter/main.o \
+ build/unix-adapter/shared/DebugClient.o \
+ build/unix-adapter/shared/WinptyAssert.o \
+ build/unix-adapter/shared/WinptyVersion.o
+
+build/unix-adapter/shared/WinptyVersion.o : build/gen/GenVersion.h
+
+build/$(UNIX_ADAPTER_EXE) : $(UNIX_ADAPTER_OBJECTS) build/winpty.dll
+ $(info Linking $@)
+ @$(UNIX_CXX) $(UNIX_LDFLAGS) -o $@ $^
+
+-include $(UNIX_ADAPTER_OBJECTS:.o=.d)
diff --git a/src/libs/3rdparty/winpty/src/winpty.gyp b/src/libs/3rdparty/winpty/src/winpty.gyp
new file mode 100644
index 0000000000..7ee68d55e6
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/winpty.gyp
@@ -0,0 +1,206 @@
+{
+ # The MSVC generator is the default. Select the compiler version by
+ # passing -G msvs_version=<ver> to gyp. <ver> is a string like 2013e.
+ # See gyp\pylib\gyp\MSVSVersion.py for sample version strings. You
+ # can also pass configurations.gypi to gyp for 32-bit and 64-bit builds.
+ # See that file for details.
+ #
+ # Pass --format=make to gyp to generate a Makefile instead. The Makefile
+ # can be configured by passing variables to make, e.g.:
+ # make -j4 CXX=i686-w64-mingw32-g++ LDFLAGS="-static -static-libgcc -static-libstdc++"
+
+ 'variables': {
+ 'WINPTY_COMMIT_HASH%': '<!(cmd /c "cd shared && GetCommitHash.bat")',
+ },
+ 'target_defaults' : {
+ 'defines' : [
+ 'UNICODE',
+ '_UNICODE',
+ '_WIN32_WINNT=0x0501',
+ 'NOMINMAX',
+ ],
+ 'include_dirs': [
+ # Add the 'src/gen' directory to the include path and force gyp to
+ # run the script (re)generating the version header.
+ '<!(cmd /c "cd shared && UpdateGenVersion.bat <(WINPTY_COMMIT_HASH)")',
+ ],
+ },
+ 'targets' : [
+ {
+ 'target_name' : 'winpty-agent',
+ 'type' : 'executable',
+ 'include_dirs' : [
+ 'include',
+ ],
+ 'defines' : [
+ 'WINPTY_AGENT_ASSERT',
+ ],
+ 'libraries' : [
+ '-ladvapi32',
+ '-lshell32',
+ '-luser32',
+ ],
+ 'msvs_settings': {
+ # Specify this setting here to override a setting from somewhere
+ # else, such as node's common.gypi.
+ 'VCCLCompilerTool': {
+ 'ExceptionHandling': '1', # /EHsc
+ },
+ },
+ 'sources' : [
+ 'agent/Agent.h',
+ 'agent/Agent.cc',
+ 'agent/AgentCreateDesktop.h',
+ 'agent/AgentCreateDesktop.cc',
+ 'agent/ConsoleFont.cc',
+ 'agent/ConsoleFont.h',
+ 'agent/ConsoleInput.cc',
+ 'agent/ConsoleInput.h',
+ 'agent/ConsoleInputReencoding.cc',
+ 'agent/ConsoleInputReencoding.h',
+ 'agent/ConsoleLine.cc',
+ 'agent/ConsoleLine.h',
+ 'agent/Coord.h',
+ 'agent/DebugShowInput.h',
+ 'agent/DebugShowInput.cc',
+ 'agent/DefaultInputMap.h',
+ 'agent/DefaultInputMap.cc',
+ 'agent/DsrSender.h',
+ 'agent/EventLoop.h',
+ 'agent/EventLoop.cc',
+ 'agent/InputMap.h',
+ 'agent/InputMap.cc',
+ 'agent/LargeConsoleRead.h',
+ 'agent/LargeConsoleRead.cc',
+ 'agent/NamedPipe.h',
+ 'agent/NamedPipe.cc',
+ 'agent/Scraper.h',
+ 'agent/Scraper.cc',
+ 'agent/SimplePool.h',
+ 'agent/SmallRect.h',
+ 'agent/Terminal.h',
+ 'agent/Terminal.cc',
+ 'agent/UnicodeEncoding.h',
+ 'agent/Win32Console.cc',
+ 'agent/Win32Console.h',
+ 'agent/Win32ConsoleBuffer.cc',
+ 'agent/Win32ConsoleBuffer.h',
+ 'agent/main.cc',
+ 'shared/AgentMsg.h',
+ 'shared/BackgroundDesktop.h',
+ 'shared/BackgroundDesktop.cc',
+ 'shared/Buffer.h',
+ 'shared/Buffer.cc',
+ 'shared/DebugClient.h',
+ 'shared/DebugClient.cc',
+ 'shared/GenRandom.h',
+ 'shared/GenRandom.cc',
+ 'shared/OsModule.h',
+ 'shared/OwnedHandle.h',
+ 'shared/OwnedHandle.cc',
+ 'shared/StringBuilder.h',
+ 'shared/StringUtil.cc',
+ 'shared/StringUtil.h',
+ 'shared/UnixCtrlChars.h',
+ 'shared/WindowsSecurity.cc',
+ 'shared/WindowsSecurity.h',
+ 'shared/WindowsVersion.h',
+ 'shared/WindowsVersion.cc',
+ 'shared/WinptyAssert.h',
+ 'shared/WinptyAssert.cc',
+ 'shared/WinptyException.h',
+ 'shared/WinptyException.cc',
+ 'shared/WinptyVersion.h',
+ 'shared/WinptyVersion.cc',
+ 'shared/winpty_snprintf.h',
+ ],
+ },
+ {
+ 'target_name' : 'winpty',
+ 'type' : 'shared_library',
+ 'include_dirs' : [
+ 'include',
+ ],
+ 'defines' : [
+ 'COMPILING_WINPTY_DLL',
+ ],
+ 'libraries' : [
+ '-ladvapi32',
+ '-luser32',
+ ],
+ 'msvs_settings': {
+ # Specify this setting here to override a setting from somewhere
+ # else, such as node's common.gypi.
+ 'VCCLCompilerTool': {
+ 'ExceptionHandling': '1', # /EHsc
+ },
+ },
+ 'sources' : [
+ 'include/winpty.h',
+ 'libwinpty/AgentLocation.cc',
+ 'libwinpty/AgentLocation.h',
+ 'libwinpty/winpty.cc',
+ 'shared/AgentMsg.h',
+ 'shared/BackgroundDesktop.h',
+ 'shared/BackgroundDesktop.cc',
+ 'shared/Buffer.h',
+ 'shared/Buffer.cc',
+ 'shared/DebugClient.h',
+ 'shared/DebugClient.cc',
+ 'shared/GenRandom.h',
+ 'shared/GenRandom.cc',
+ 'shared/OsModule.h',
+ 'shared/OwnedHandle.h',
+ 'shared/OwnedHandle.cc',
+ 'shared/StringBuilder.h',
+ 'shared/StringUtil.cc',
+ 'shared/StringUtil.h',
+ 'shared/WindowsSecurity.cc',
+ 'shared/WindowsSecurity.h',
+ 'shared/WindowsVersion.h',
+ 'shared/WindowsVersion.cc',
+ 'shared/WinptyAssert.h',
+ 'shared/WinptyAssert.cc',
+ 'shared/WinptyException.h',
+ 'shared/WinptyException.cc',
+ 'shared/WinptyVersion.h',
+ 'shared/WinptyVersion.cc',
+ 'shared/winpty_snprintf.h',
+ ],
+ },
+ {
+ 'target_name' : 'winpty-debugserver',
+ 'type' : 'executable',
+ 'msvs_settings': {
+ # Specify this setting here to override a setting from somewhere
+ # else, such as node's common.gypi.
+ 'VCCLCompilerTool': {
+ 'ExceptionHandling': '1', # /EHsc
+ },
+ },
+ 'sources' : [
+ 'debugserver/DebugServer.cc',
+ 'shared/DebugClient.h',
+ 'shared/DebugClient.cc',
+ 'shared/OwnedHandle.h',
+ 'shared/OwnedHandle.cc',
+ 'shared/OsModule.h',
+ 'shared/StringBuilder.h',
+ 'shared/StringUtil.cc',
+ 'shared/StringUtil.h',
+ 'shared/WindowsSecurity.h',
+ 'shared/WindowsSecurity.cc',
+ 'shared/WindowsVersion.h',
+ 'shared/WindowsVersion.cc',
+ 'shared/WinptyAssert.h',
+ 'shared/WinptyAssert.cc',
+ 'shared/WinptyException.h',
+ 'shared/WinptyException.cc',
+ 'shared/winpty_snprintf.h',
+ ],
+ 'libraries' : [
+ '-ladvapi32',
+ ],
+ }
+ ],
+}
diff --git a/src/libs/3rdparty/winpty/vcbuild.bat b/src/libs/3rdparty/winpty/vcbuild.bat
new file mode 100644
index 0000000000..f3787a20f1
--- /dev/null
+++ b/src/libs/3rdparty/winpty/vcbuild.bat
@@ -0,0 +1,83 @@
+@echo off
+
+REM -- Script requirements:
+REM --
+REM -- * git This program must be in the Path to check out
+REM -- build-gyp. If that directory already exists, then
+REM -- git isn't necessary, but if it is missing, no
+REM -- commit hash will be embedded into binaries.
+REM --
+REM -- * python A non-Cygwin Python 2 python.exe must be in the
+REM -- Path to run gyp.
+REM --
+REM -- * msbuild msbuild must be in the Path. It is probably
+REM -- important to have msbuild from the correct MSVC
+REM -- release.
+REM --
+REM -- The script's output binaries are in the src/Release/{Win32,x64}
+REM -- directory.
+
+REM -------------------------------------------------------------------------
+REM -- Parse arguments
+
+setlocal
+cd %~dp0
+set GYP_ARGS=
+set MSVC_PLATFORM=x64
+
+:ParamLoop
+if "%1" == "" goto :ParamDone
+if "%1" == "--msvc-platform" (
+ REM -- One of Win32 or x64.
+ set MSVC_PLATFORM=%2
+ shift && shift
+ goto :ParamLoop
+)
+if "%1" == "--gyp-msvs-version" (
+ set GYP_ARGS=%GYP_ARGS% -G msvs_version=%2
+ shift && shift
+ goto :ParamLoop
+)
+if "%1" == "--toolset" (
+ set GYP_ARGS=%GYP_ARGS% -D WINPTY_MSBUILD_TOOLSET=%2
+ shift && shift
+ goto :ParamLoop
+)
+if "%1" == "--commit-hash" (
+ set GYP_ARGS=%GYP_ARGS% -D WINPTY_COMMIT_HASH=%2
+ shift && shift
+ goto :ParamLoop
+)
+echo error: Unrecognized argument: %1
+exit /b 1
+:ParamDone
+
+REM -------------------------------------------------------------------------
+REM -- Check out GYP. GYP doesn't seem to have releases, so just use the
+REM -- current master commit.
+
+if not exist build-gyp (
+ git clone https://chromium.googlesource.com/external/gyp build-gyp || (
+ echo error: GYP clone failed
+ exit /b 1
+ )
+)
+
+REM -------------------------------------------------------------------------
+REM -- Run gyp to generate MSVC project files.
+
+cd src
+
+call ..\build-gyp\gyp.bat winpty.gyp -I configurations.gypi %GYP_ARGS%
+if errorlevel 1 (
+ echo error: GYP failed
+ exit /b 1
+)
+
+REM -------------------------------------------------------------------------
+REM -- Compile the project.
+
+msbuild winpty.sln /m /p:Platform=%MSVC_PLATFORM% || (
+ echo error: msbuild failed
+ exit /b 1
+)
diff --git a/src/libs/3rdparty/winpty/winpty.qbs b/src/libs/3rdparty/winpty/winpty.qbs
new file mode 100644
index 0000000000..35d56f9265
--- /dev/null
+++ b/src/libs/3rdparty/winpty/winpty.qbs
@@ -0,0 +1,205 @@
+import qbs
+import qbs.TextFile
+
+Project {
+ name: "Winpty"
+ condition: qbs.targetOS.contains("windows")
+
+ Product {
+ name: "winpty_genversion_header"
+ type: "hpp"
+
+ Group {
+ files: "VERSION.txt"
+ fileTags: "txt.in"
+ }
+
+ Rule {
+ inputs: "txt.in"
+ Artifact {
+ filePath: "GenVersion.h"
+ fileTags: "hpp"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating GenVersion.h";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var inFile = new TextFile(input.filePath);
+ var versionTxt = inFile.readAll();
+ inFile.close();
+ // remove any line endings
+ versionTxt = versionTxt.replace(/[\r\n]/g, "");
+
+ var content = 'const char GenVersion_Version[] = "@VERSION@";\n'
+ + 'const char GenVersion_Commit[] = "@COMMIT_HASH@";\n';
+ content = content.replace(/@VERSION@/g, versionTxt);
+
+ var outFile = new TextFile(output.filePath, TextFile.WriteOnly);
+ outFile.truncate();
+ outFile.write(content);
+ outFile.close();
+ }
+ return cmd;
+ }
+ }
+
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: exportingProduct.buildDirectory
+ }
+ }
+
+ QtcTool {
+ name: "winpty-agent"
+ Depends { name: "winpty_genversion_header" }
+ Depends { name: "cpp" }
+
+ useQt: false
+
+ cpp.includePaths: base.concat([sourceDirectory + "/include", buildDirectory])
+ cpp.defines: base.concat(["WINPTY_AGENT_ASSERT",
+ "NOMINMAX", "UNICODE", "_UNICODE"
+ ])
+ cpp.dynamicLibraries: ["user32", "shell32", "advapi32"]
+
+ files: [
+ "src/agent/Agent.h",
+ "src/agent/Agent.cc",
+ "src/agent/AgentCreateDesktop.h",
+ "src/agent/AgentCreateDesktop.cc",
+ "src/agent/ConsoleFont.cc",
+ "src/agent/ConsoleFont.h",
+ "src/agent/ConsoleInput.cc",
+ "src/agent/ConsoleInput.h",
+ "src/agent/ConsoleInputReencoding.cc",
+ "src/agent/ConsoleInputReencoding.h",
+ "src/agent/ConsoleLine.cc",
+ "src/agent/ConsoleLine.h",
+ "src/agent/Coord.h",
+ "src/agent/DebugShowInput.h",
+ "src/agent/DebugShowInput.cc",
+ "src/agent/DefaultInputMap.h",
+ "src/agent/DefaultInputMap.cc",
+ "src/agent/DsrSender.h",
+ "src/agent/EventLoop.h",
+ "src/agent/EventLoop.cc",
+ "src/agent/InputMap.h",
+ "src/agent/InputMap.cc",
+ "src/agent/LargeConsoleRead.h",
+ "src/agent/LargeConsoleRead.cc",
+ "src/agent/NamedPipe.h",
+ "src/agent/NamedPipe.cc",
+ "src/agent/Scraper.h",
+ "src/agent/Scraper.cc",
+ "src/agent/SimplePool.h",
+ "src/agent/SmallRect.h",
+ "src/agent/Terminal.h",
+ "src/agent/Terminal.cc",
+ "src/agent/UnicodeEncoding.h",
+ "src/agent/Win32Console.cc",
+ "src/agent/Win32Console.h",
+ "src/agent/Win32ConsoleBuffer.cc",
+ "src/agent/Win32ConsoleBuffer.h",
+ "src/agent/main.cc",
+ ]
+
+ Group {
+ name: "Shared sources"
+ prefix: "src/shared/"
+ files: [
+ "AgentMsg.h",
+ "BackgroundDesktop.h",
+ "BackgroundDesktop.cc",
+ "Buffer.h",
+ "Buffer.cc",
+ "DebugClient.h",
+ "DebugClient.cc",
+ "GenRandom.h",
+ "GenRandom.cc",
+ "OsModule.h",
+ "OwnedHandle.h",
+ "OwnedHandle.cc",
+ "StringBuilder.h",
+ "StringUtil.cc",
+ "StringUtil.h",
+ "UnixCtrlChars.h",
+ "WindowsSecurity.cc",
+ "WindowsSecurity.h",
+ "WindowsVersion.h",
+ "WindowsVersion.cc",
+ "WinptyAssert.h",
+ "WinptyAssert.cc",
+ "WinptyException.h",
+ "WinptyException.cc",
+ "WinptyVersion.h",
+ "WinptyVersion.cc",
+ "winpty_snprintf.h",
+ ]
+ }
+ }
+
+ QtcLibrary {
+ name: "winpty"
+ type: "staticlibrary"
+
+ Depends { name: "winpty_genversion_header" }
+ Depends { name: "cpp" }
+
+ useNonGuiPchFile: false
+ useGuiPchFile: false
+
+ cpp.defines: base.concat(["COMPILING_WINPTY_DLL",
+ "NOMINMAX", "UNICODE", "_UNICODE"
+ ])
+ cpp.dynamicLibraries: ["user32", "shell32", "advapi32"]
+ cpp.includePaths: base.concat(sourceDirectory + "/src/include")
+
+
+ files: [
+ "src/libwinpty/AgentLocation.cc",
+ "src/libwinpty/AgentLocation.h",
+ "src/libwinpty/winpty.cc",
+ ]
+
+ Group {
+ name: "Shared sources" // FIXME duplication
+ prefix: "src/shared/"
+ files: [
+ "AgentMsg.h",
+ "BackgroundDesktop.h",
+ "BackgroundDesktop.cc",
+ "Buffer.h",
+ "Buffer.cc",
+ "DebugClient.h",
+ "DebugClient.cc",
+ "GenRandom.h",
+ "GenRandom.cc",
+ "OsModule.h",
+ "OwnedHandle.h",
+ "OwnedHandle.cc",
+ "StringBuilder.h",
+ "StringUtil.cc",
+ "StringUtil.h",
+ "UnixCtrlChars.h",
+ "WindowsSecurity.cc",
+ "WindowsSecurity.h",
+ "WindowsVersion.h",
+ "WindowsVersion.cc",
+ "WinptyAssert.h",
+ "WinptyAssert.cc",
+ "WinptyException.h",
+ "WinptyException.cc",
+ "WinptyVersion.h",
+ "WinptyVersion.cc",
+ "winpty_snprintf.h",
+ ]
+ }
+
+ Export {
+ Depends { name: "cpp" }
+ cpp.defines: "COMPILING_WINPTY_DLL"
+ cpp.includePaths: exportingProduct.sourceDirectory + "/src/include"
+ }
+ }
+}