| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmStdIoStream.h" | |
| #include <algorithm> | |
| #include <array> | |
| #include <cstdio> | |
| #include <istream> // IWYU pragma: keep | |
| #include <ostream> // IWYU pragma: keep | |
| #ifdef _WIN32 | |
| # include <windows.h> | |
| # include <io.h> // for _get_osfhandle | |
| #else | |
| # include <string> | |
| # include <cm/optional> | |
| # include <cm/string_view> | |
| # include <cmext/string_view> | |
| # include <unistd.h> | |
| #endif | |
| #include "cm_fileno.hxx" | |
| #ifndef _WIN32 | |
| # include "cmSystemTools.h" | |
| #endif | |
| namespace cm { | |
| namespace StdIo { | |
| namespace { | |
| #ifdef _WIN32 | |
| # ifndef ENABLE_VIRTUAL_TERMINAL_INPUT | |
| # define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 | |
| # endif | |
| # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING | |
| # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 | |
| # endif | |
| #else | |
| // List of known `TERM` names that support VT100 escape sequences. | |
| // Order by `LC_COLLATE=C sort` to search using `std::lower_bound`. | |
| std::array<cm::string_view, 58> const kVT100Names{ { | |
| "Eterm"_s, | |
| "alacritty"_s, | |
| "alacritty-direct"_s, | |
| "ansi"_s, | |
| "color-xterm"_s, | |
| "con132x25"_s, | |
| "con132x30"_s, | |
| "con132x43"_s, | |
| "con132x60"_s, | |
| "con80x25"_s, | |
| "con80x28"_s, | |
| "con80x30"_s, | |
| "con80x43"_s, | |
| "con80x50"_s, | |
| "con80x60"_s, | |
| "cons25"_s, | |
| "console"_s, | |
| "cygwin"_s, | |
| "dtterm"_s, | |
| "eterm-color"_s, | |
| "gnome"_s, | |
| "gnome-256color"_s, | |
| "konsole"_s, | |
| "konsole-256color"_s, | |
| "kterm"_s, | |
| "linux"_s, | |
| "linux-c"_s, | |
| "mach-color"_s, | |
| "mlterm"_s, | |
| "msys"_s, | |
| "putty"_s, | |
| "putty-256color"_s, | |
| "rxvt"_s, | |
| "rxvt-256color"_s, | |
| "rxvt-cygwin"_s, | |
| "rxvt-cygwin-native"_s, | |
| "rxvt-unicode"_s, | |
| "rxvt-unicode-256color"_s, | |
| "screen"_s, | |
| "screen-256color"_s, | |
| "screen-256color-bce"_s, | |
| "screen-bce"_s, | |
| "screen-w"_s, | |
| "screen.linux"_s, | |
| "screen.xterm-256color"_s, | |
| "st-256color"_s, | |
| "tmux"_s, | |
| "tmux-256color"_s, | |
| "vt100"_s, | |
| "xterm"_s, | |
| "xterm-16color"_s, | |
| "xterm-256color"_s, | |
| "xterm-88color"_s, | |
| "xterm-color"_s, | |
| "xterm-debian"_s, | |
| "xterm-ghostty"_s, | |
| "xterm-kitty"_s, | |
| "xterm-termite"_s, | |
| } }; | |
| bool TermIsVT100() | |
| { | |
| if (cm::optional<std::string> term = cmSystemTools::GetEnvVar("TERM")) { | |
| // NOLINTNEXTLINE(readability-qualified-auto) | |
| auto i = std::lower_bound(kVT100Names.begin(), kVT100Names.end(), *term); | |
| if (i != kVT100Names.end() && *i == *term) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| #endif | |
| } // anonymous namespace | |
| Stream::Stream(std::ios& s, FILE* file, Direction direction) | |
| : IOS_(s) | |
| , FD_(cm_fileno(file)) | |
| { | |
| #ifdef _WIN32 | |
| auto h = reinterpret_cast<HANDLE>(_get_osfhandle(this->FD_)); | |
| if (GetConsoleMode(h, &this->ConsoleOrigMode_)) { | |
| this->Console_ = h; | |
| DWORD vtMode = this->ConsoleOrigMode_ | | |
| (direction == Direction::In ? ENABLE_VIRTUAL_TERMINAL_INPUT | |
| : ENABLE_VIRTUAL_TERMINAL_PROCESSING); | |
| if (SetConsoleMode(this->Console_, vtMode)) { | |
| this->Kind_ = TermKind::VT100; | |
| } else { | |
| SetConsoleMode(this->Console_, this->ConsoleOrigMode_); | |
| this->Kind_ = TermKind::Console; | |
| } | |
| } | |
| #else | |
| static_cast<void>(direction); | |
| if (isatty(this->FD_) && TermIsVT100()) { | |
| this->Kind_ = TermKind::VT100; | |
| } | |
| #endif | |
| } | |
| #ifdef _WIN32 | |
| Stream::~Stream() | |
| { | |
| this->Destroy(); | |
| } | |
| void Stream::Destroy() | |
| { | |
| if (this->Console_) { | |
| this->IOS_.rdbuf()->pubsync(); | |
| SetConsoleMode(this->Console_, this->ConsoleOrigMode_); | |
| this->Console_ = nullptr; | |
| } | |
| } | |
| #else | |
| Stream::~Stream() = default; | |
| #endif | |
| IStream::IStream(std::istream& is, FILE* file) | |
| : Stream(is, file, Direction::In) | |
| { | |
| } | |
| std::istream& IStream::IOS() const | |
| { | |
| return dynamic_cast<std::istream&>(this->Stream::IOS()); | |
| } | |
| OStream::OStream(std::ostream& os, FILE* file) | |
| : Stream(os, file, Direction::Out) | |
| { | |
| } | |
| std::ostream& OStream::IOS() const | |
| { | |
| return dynamic_cast<std::ostream&>(this->Stream::IOS()); | |
| } | |
| } | |
| } |