Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmStdIoInit.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 "cmStdIoInit.h"
4
5
#include <cerrno>
6
#include <cstdio>
7
#include <cstdlib>
8
#include <iostream>
9
10
#include <fcntl.h>
11
12
#ifdef _WIN32
13
#  include <windows.h>
14
15
#  include <io.h> // for _close, _dup2, _get_osfhandle
16
17
#  include "cm_fileno.hxx"
18
#else
19
#  include <unistd.h>
20
#endif
21
22
#include "cmStdIoStream.h"
23
24
namespace cm {
25
namespace StdIo {
26
27
namespace {
28
29
#ifdef _WIN32
30
void InitStdPipe(int stdFd, DWORD nStdHandle, FILE* stream,
31
                 wchar_t const* mode)
32
{
33
  if (cm_fileno(stream) >= 0) {
34
    return;
35
  }
36
  _close(stdFd);
37
  _wfreopen(L"NUL", mode, stream);
38
  int fd = cm_fileno(stream);
39
  if (fd < 0) {
40
    perror("failed to open NUL for missing stdio pipe");
41
    abort();
42
  }
43
  if (fd != stdFd) {
44
    _dup2(fd, stdFd);
45
  }
46
  SetStdHandle(nStdHandle, reinterpret_cast<HANDLE>(_get_osfhandle(fd)));
47
}
48
#else
49
void InitStdPipe(int fd)
50
0
{
51
0
  if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
52
0
    return;
53
0
  }
54
55
0
  int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
56
0
  if (f == -1) {
57
0
    perror("failed to open /dev/null for missing stdio pipe");
58
0
    abort();
59
0
  }
60
0
  if (f != fd) {
61
0
    dup2(f, fd);
62
0
    close(f);
63
0
  }
64
0
}
65
#endif
66
67
struct InitStdPipes
68
{
69
  InitStdPipes()
70
0
  {
71
#ifdef _WIN32
72
    InitStdPipe(0, STD_INPUT_HANDLE, stdin, L"rb");
73
    InitStdPipe(1, STD_OUTPUT_HANDLE, stdout, L"wb");
74
    InitStdPipe(2, STD_ERROR_HANDLE, stderr, L"wb");
75
#else
76
0
    InitStdPipe(STDIN_FILENO);
77
0
    InitStdPipe(STDOUT_FILENO);
78
0
    InitStdPipe(STDERR_FILENO);
79
0
#endif
80
0
  }
81
};
82
83
} // anonymous namespace
84
85
class Globals
86
{
87
public:
88
  std::ios::Init InitIos;
89
  InitStdPipes InitPipes;
90
  IStream StdIn{ std::cin, stdin };
91
  OStream StdOut{ std::cout, stdout };
92
  OStream StdErr{ std::cerr, stderr };
93
94
  Globals();
95
96
#ifdef _WIN32
97
  static BOOL WINAPI CtrlHandler(DWORD /*dwCtrlType*/)
98
  {
99
    Get().StdErr.Destroy();
100
    Get().StdOut.Destroy();
101
    Get().StdIn.Destroy();
102
    return FALSE;
103
  }
104
#endif
105
106
  static Globals& Get();
107
};
108
109
#ifdef _WIN32
110
Globals::Globals()
111
{
112
  SetConsoleCtrlHandler(CtrlHandler, TRUE);
113
}
114
#else
115
0
Globals::Globals() = default;
116
#endif
117
118
Globals& Globals::Get()
119
0
{
120
0
  static Globals globals;
121
0
  return globals;
122
0
}
123
124
Init::Init()
125
0
{
126
0
  Globals::Get();
127
0
}
128
129
IStream& In()
130
0
{
131
0
  return Globals::Get().StdIn;
132
0
}
133
134
OStream& Out()
135
0
{
136
0
  return Globals::Get().StdOut;
137
0
}
138
139
OStream& Err()
140
0
{
141
0
  return Globals::Get().StdErr;
142
0
}
143
144
}
145
}