/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file LICENSE.rst or https://cmake.org/licensing for details. */ #include "cmStdIoInit.h" #include #include #include #include #include #ifdef _WIN32 # include # include // for _close, _dup2, _get_osfhandle # include "cm_fileno.hxx" #else # include #endif #include "cmStdIoStream.h" namespace cm { namespace StdIo { namespace { #ifdef _WIN32 void InitStdPipe(int stdFd, DWORD nStdHandle, FILE* stream, wchar_t const* mode) { if (cm_fileno(stream) >= 0) { return; } _close(stdFd); _wfreopen(L"NUL", mode, stream); int fd = cm_fileno(stream); if (fd < 0) { perror("failed to open NUL for missing stdio pipe"); abort(); } if (fd != stdFd) { _dup2(fd, stdFd); } SetStdHandle(nStdHandle, reinterpret_cast(_get_osfhandle(fd))); } #else void InitStdPipe(int fd) { if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) { return; } int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY); if (f == -1) { perror("failed to open /dev/null for missing stdio pipe"); abort(); } if (f != fd) { dup2(f, fd); close(f); } } #endif struct InitStdPipes { InitStdPipes() { #ifdef _WIN32 InitStdPipe(0, STD_INPUT_HANDLE, stdin, L"rb"); InitStdPipe(1, STD_OUTPUT_HANDLE, stdout, L"wb"); InitStdPipe(2, STD_ERROR_HANDLE, stderr, L"wb"); #else InitStdPipe(STDIN_FILENO); InitStdPipe(STDOUT_FILENO); InitStdPipe(STDERR_FILENO); #endif } }; } // anonymous namespace class Globals { public: std::ios::Init InitIos; InitStdPipes InitPipes; IStream StdIn{ std::cin, stdin }; OStream StdOut{ std::cout, stdout }; OStream StdErr{ std::cerr, stderr }; static Globals& Get(); }; Globals& Globals::Get() { static Globals globals; return globals; } Init::Init() { Globals::Get(); } IStream& In() { return Globals::Get().StdIn; } OStream& Out() { return Globals::Get().StdOut; } OStream& Err() { return Globals::Get().StdErr; } } }