/src/CMake/Source/cmStdIoStream.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmStdIoStream.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <array> |
7 | | #include <cstdio> |
8 | | #include <istream> // IWYU pragma: keep |
9 | | #include <ostream> // IWYU pragma: keep |
10 | | |
11 | | #ifdef _WIN32 |
12 | | # include <windows.h> |
13 | | |
14 | | # include <io.h> // for _get_osfhandle |
15 | | #else |
16 | | # include <string> |
17 | | |
18 | | # include <cm/optional> |
19 | | # include <cm/string_view> |
20 | | # include <cmext/string_view> |
21 | | |
22 | | # include <unistd.h> |
23 | | #endif |
24 | | |
25 | | #include "cm_fileno.hxx" |
26 | | |
27 | | #ifndef _WIN32 |
28 | | # include "cmSystemTools.h" |
29 | | #endif |
30 | | |
31 | | namespace cm { |
32 | | namespace StdIo { |
33 | | |
34 | | namespace { |
35 | | |
36 | | #ifdef _WIN32 |
37 | | # ifndef ENABLE_VIRTUAL_TERMINAL_INPUT |
38 | | # define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 |
39 | | # endif |
40 | | # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING |
41 | | # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 |
42 | | # endif |
43 | | #else |
44 | | // List of known `TERM` names that support VT100 escape sequences. |
45 | | // Order by `LC_COLLATE=C sort` to search using `std::lower_bound`. |
46 | | std::array<cm::string_view, 57> const kVT100Names{ { |
47 | | "Eterm"_s, |
48 | | "alacritty"_s, |
49 | | "alacritty-direct"_s, |
50 | | "ansi"_s, |
51 | | "color-xterm"_s, |
52 | | "con132x25"_s, |
53 | | "con132x30"_s, |
54 | | "con132x43"_s, |
55 | | "con132x60"_s, |
56 | | "con80x25"_s, |
57 | | "con80x28"_s, |
58 | | "con80x30"_s, |
59 | | "con80x43"_s, |
60 | | "con80x50"_s, |
61 | | "con80x60"_s, |
62 | | "cons25"_s, |
63 | | "console"_s, |
64 | | "cygwin"_s, |
65 | | "dtterm"_s, |
66 | | "eterm-color"_s, |
67 | | "gnome"_s, |
68 | | "gnome-256color"_s, |
69 | | "konsole"_s, |
70 | | "konsole-256color"_s, |
71 | | "kterm"_s, |
72 | | "linux"_s, |
73 | | "linux-c"_s, |
74 | | "mach-color"_s, |
75 | | "mlterm"_s, |
76 | | "msys"_s, |
77 | | "putty"_s, |
78 | | "putty-256color"_s, |
79 | | "rxvt"_s, |
80 | | "rxvt-256color"_s, |
81 | | "rxvt-cygwin"_s, |
82 | | "rxvt-cygwin-native"_s, |
83 | | "rxvt-unicode"_s, |
84 | | "rxvt-unicode-256color"_s, |
85 | | "screen"_s, |
86 | | "screen-256color"_s, |
87 | | "screen-256color-bce"_s, |
88 | | "screen-bce"_s, |
89 | | "screen-w"_s, |
90 | | "screen.linux"_s, |
91 | | "st-256color"_s, |
92 | | "tmux"_s, |
93 | | "tmux-256color"_s, |
94 | | "vt100"_s, |
95 | | "xterm"_s, |
96 | | "xterm-16color"_s, |
97 | | "xterm-256color"_s, |
98 | | "xterm-88color"_s, |
99 | | "xterm-color"_s, |
100 | | "xterm-debian"_s, |
101 | | "xterm-ghostty"_s, |
102 | | "xterm-kitty"_s, |
103 | | "xterm-termite"_s, |
104 | | } }; |
105 | | |
106 | | bool TermIsVT100() |
107 | 0 | { |
108 | 0 | if (cm::optional<std::string> term = cmSystemTools::GetEnvVar("TERM")) { |
109 | | // NOLINTNEXTLINE(readability-qualified-auto) |
110 | 0 | auto i = std::lower_bound(kVT100Names.begin(), kVT100Names.end(), *term); |
111 | 0 | if (i != kVT100Names.end() && *i == *term) { |
112 | 0 | return true; |
113 | 0 | } |
114 | 0 | } |
115 | 0 | return false; |
116 | 0 | } |
117 | | #endif |
118 | | |
119 | | } // anonymous namespace |
120 | | |
121 | | Stream::Stream(std::ios& s, FILE* file, Direction direction) |
122 | 0 | : IOS_(s) |
123 | 0 | , FD_(cm_fileno(file)) |
124 | 0 | { |
125 | | #ifdef _WIN32 |
126 | | auto h = reinterpret_cast<HANDLE>(_get_osfhandle(this->FD_)); |
127 | | if (GetConsoleMode(h, &this->ConsoleOrigMode_)) { |
128 | | this->Console_ = h; |
129 | | DWORD vtMode = this->ConsoleOrigMode_ | |
130 | | (direction == Direction::In ? ENABLE_VIRTUAL_TERMINAL_INPUT |
131 | | : ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
132 | | if (SetConsoleMode(this->Console_, vtMode)) { |
133 | | this->Kind_ = TermKind::VT100; |
134 | | } else { |
135 | | SetConsoleMode(this->Console_, this->ConsoleOrigMode_); |
136 | | this->Kind_ = TermKind::Console; |
137 | | } |
138 | | } |
139 | | #else |
140 | 0 | static_cast<void>(direction); |
141 | 0 | if (isatty(this->FD_) && TermIsVT100()) { |
142 | 0 | this->Kind_ = TermKind::VT100; |
143 | 0 | } |
144 | 0 | #endif |
145 | 0 | } |
146 | | |
147 | | #ifdef _WIN32 |
148 | | Stream::~Stream() |
149 | | { |
150 | | this->Destroy(); |
151 | | } |
152 | | |
153 | | void Stream::Destroy() |
154 | | { |
155 | | if (this->Console_) { |
156 | | this->IOS_.rdbuf()->pubsync(); |
157 | | SetConsoleMode(this->Console_, this->ConsoleOrigMode_); |
158 | | this->Console_ = nullptr; |
159 | | } |
160 | | } |
161 | | #else |
162 | 0 | Stream::~Stream() = default; |
163 | | #endif |
164 | | |
165 | | IStream::IStream(std::istream& is, FILE* file) |
166 | 0 | : Stream(is, file, Direction::In) |
167 | 0 | { |
168 | 0 | } |
169 | | |
170 | | std::istream& IStream::IOS() const |
171 | 0 | { |
172 | 0 | return dynamic_cast<std::istream&>(this->Stream::IOS()); |
173 | 0 | } |
174 | | |
175 | | OStream::OStream(std::ostream& os, FILE* file) |
176 | 0 | : Stream(os, file, Direction::Out) |
177 | 0 | { |
178 | 0 | } |
179 | | |
180 | | std::ostream& OStream::IOS() const |
181 | 0 | { |
182 | 0 | return dynamic_cast<std::ostream&>(this->Stream::IOS()); |
183 | 0 | } |
184 | | |
185 | | } |
186 | | } |