Coverage Report

Created: 2026-10-28 06:38

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, 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
}