cmStdIoInit.cxx 1.8 KB

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