cmStdIoInit.cxx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. #include <cerrno>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <iostream>
  8. #include <fcntl.h>
  9. #ifdef _WIN32
  10. # include <windows.h>
  11. # include <io.h> // for _close, _dup2, _get_osfhandle
  12. # include "cm_fileno.hxx"
  13. #else
  14. # include <unistd.h>
  15. #endif
  16. #include "cmStdIoStream.h"
  17. namespace cm {
  18. namespace StdIo {
  19. namespace {
  20. #ifdef _WIN32
  21. void InitStdPipe(int stdFd, DWORD nStdHandle, FILE* stream,
  22. wchar_t const* mode)
  23. {
  24. if (cm_fileno(stream) >= 0) {
  25. return;
  26. }
  27. _close(stdFd);
  28. _wfreopen(L"NUL", mode, stream);
  29. int fd = cm_fileno(stream);
  30. if (fd < 0) {
  31. perror("failed to open NUL for missing stdio pipe");
  32. abort();
  33. }
  34. if (fd != stdFd) {
  35. _dup2(fd, stdFd);
  36. }
  37. SetStdHandle(nStdHandle, reinterpret_cast<HANDLE>(_get_osfhandle(fd)));
  38. }
  39. #else
  40. void InitStdPipe(int fd)
  41. {
  42. if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
  43. return;
  44. }
  45. int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
  46. if (f == -1) {
  47. perror("failed to open /dev/null for missing stdio pipe");
  48. abort();
  49. }
  50. if (f != fd) {
  51. dup2(f, fd);
  52. close(f);
  53. }
  54. }
  55. #endif
  56. struct InitStdPipes
  57. {
  58. InitStdPipes()
  59. {
  60. #ifdef _WIN32
  61. InitStdPipe(0, STD_INPUT_HANDLE, stdin, L"rb");
  62. InitStdPipe(1, STD_OUTPUT_HANDLE, stdout, L"wb");
  63. InitStdPipe(2, STD_ERROR_HANDLE, stderr, L"wb");
  64. #else
  65. InitStdPipe(STDIN_FILENO);
  66. InitStdPipe(STDOUT_FILENO);
  67. InitStdPipe(STDERR_FILENO);
  68. #endif
  69. }
  70. };
  71. } // anonymous namespace
  72. class Globals
  73. {
  74. public:
  75. std::ios::Init InitIos;
  76. InitStdPipes InitPipes;
  77. IStream StdIn{ std::cin, stdin };
  78. OStream StdOut{ std::cout, stdout };
  79. OStream StdErr{ std::cerr, stderr };
  80. static Globals& Get();
  81. };
  82. Globals& Globals::Get()
  83. {
  84. static Globals globals;
  85. return globals;
  86. }
  87. Init::Init()
  88. {
  89. Globals::Get();
  90. }
  91. IStream& In()
  92. {
  93. return Globals::Get().StdIn;
  94. }
  95. OStream& Out()
  96. {
  97. return Globals::Get().StdOut;
  98. }
  99. OStream& Err()
  100. {
  101. return Globals::Get().StdErr;
  102. }
  103. }
  104. }