Coverage Report

Created: 2026-03-12 06:35

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