/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, 58> 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 | | "screen.xterm-256color"_s, |
92 | | "st-256color"_s, |
93 | | "tmux"_s, |
94 | | "tmux-256color"_s, |
95 | | "vt100"_s, |
96 | | "xterm"_s, |
97 | | "xterm-16color"_s, |
98 | | "xterm-256color"_s, |
99 | | "xterm-88color"_s, |
100 | | "xterm-color"_s, |
101 | | "xterm-debian"_s, |
102 | | "xterm-ghostty"_s, |
103 | | "xterm-kitty"_s, |
104 | | "xterm-termite"_s, |
105 | | } }; |
106 | | |
107 | | bool TermIsVT100() |
108 | 0 | { |
109 | 0 | if (cm::optional<std::string> term = cmSystemTools::GetEnvVar("TERM")) { |
110 | | // NOLINTNEXTLINE(readability-qualified-auto) |
111 | 0 | auto i = std::lower_bound(kVT100Names.begin(), kVT100Names.end(), *term); |
112 | 0 | if (i != kVT100Names.end() && *i == *term) { |
113 | 0 | return true; |
114 | 0 | } |
115 | 0 | } |
116 | 0 | return false; |
117 | 0 | } |
118 | | #endif |
119 | | |
120 | | } // anonymous namespace |
121 | | |
122 | | Stream::Stream(std::ios& s, FILE* file, Direction direction) |
123 | 0 | : IOS_(s) |
124 | 0 | , FD_(cm_fileno(file)) |
125 | 0 | { |
126 | | #ifdef _WIN32 |
127 | | auto h = reinterpret_cast<HANDLE>(_get_osfhandle(this->FD_)); |
128 | | if (GetConsoleMode(h, &this->ConsoleOrigMode_)) { |
129 | | this->Console_ = h; |
130 | | DWORD vtMode = this->ConsoleOrigMode_ | |
131 | | (direction == Direction::In ? ENABLE_VIRTUAL_TERMINAL_INPUT |
132 | | : ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
133 | | if (SetConsoleMode(this->Console_, vtMode)) { |
134 | | this->Kind_ = TermKind::VT100; |
135 | | } else { |
136 | | SetConsoleMode(this->Console_, this->ConsoleOrigMode_); |
137 | | this->Kind_ = TermKind::Console; |
138 | | } |
139 | | } |
140 | | #else |
141 | 0 | static_cast<void>(direction); |
142 | 0 | if (isatty(this->FD_) && TermIsVT100()) { |
143 | 0 | this->Kind_ = TermKind::VT100; |
144 | 0 | } |
145 | 0 | #endif |
146 | 0 | } |
147 | | |
148 | | #ifdef _WIN32 |
149 | | Stream::~Stream() |
150 | | { |
151 | | this->Destroy(); |
152 | | } |
153 | | |
154 | | void Stream::Destroy() |
155 | | { |
156 | | if (this->Console_) { |
157 | | this->IOS_.rdbuf()->pubsync(); |
158 | | SetConsoleMode(this->Console_, this->ConsoleOrigMode_); |
159 | | this->Console_ = nullptr; |
160 | | } |
161 | | } |
162 | | #else |
163 | 0 | Stream::~Stream() = default; |
164 | | #endif |
165 | | |
166 | | IStream::IStream(std::istream& is, FILE* file) |
167 | 0 | : Stream(is, file, Direction::In) |
168 | 0 | { |
169 | 0 | } |
170 | | |
171 | | std::istream& IStream::IOS() const |
172 | 0 | { |
173 | 0 | return dynamic_cast<std::istream&>(this->Stream::IOS()); |
174 | 0 | } |
175 | | |
176 | | OStream::OStream(std::ostream& os, FILE* file) |
177 | 0 | : Stream(os, file, Direction::Out) |
178 | 0 | { |
179 | 0 | } |
180 | | |
181 | | std::ostream& OStream::IOS() const |
182 | 0 | { |
183 | 0 | return dynamic_cast<std::ostream&>(this->Stream::IOS()); |
184 | 0 | } |
185 | | |
186 | | } |
187 | | } |