Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}