cmStdIoStream.cxx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 "cmStdIoStream.h"
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstdio>
  7. #include <istream> // IWYU pragma: keep
  8. #include <ostream> // IWYU pragma: keep
  9. #ifdef _WIN32
  10. # include <windows.h>
  11. # include <io.h> // for _get_osfhandle
  12. #else
  13. # include <string>
  14. # include <cm/optional>
  15. # include <cm/string_view>
  16. # include <cmext/string_view>
  17. # include <unistd.h>
  18. #endif
  19. #include "cm_fileno.hxx"
  20. #ifndef _WIN32
  21. # include "cmSystemTools.h"
  22. #endif
  23. namespace cm {
  24. namespace StdIo {
  25. namespace {
  26. #ifndef _WIN32
  27. // List of known `TERM` names that support VT100 escape sequences.
  28. // Order by `LC_COLLATE=C sort` to search using `std::lower_bound`.
  29. std::array<cm::string_view, 56> const kVT100Names{ {
  30. "Eterm"_s,
  31. "alacritty"_s,
  32. "alacritty-direct"_s,
  33. "ansi"_s,
  34. "color-xterm"_s,
  35. "con132x25"_s,
  36. "con132x30"_s,
  37. "con132x43"_s,
  38. "con132x60"_s,
  39. "con80x25"_s,
  40. "con80x28"_s,
  41. "con80x30"_s,
  42. "con80x43"_s,
  43. "con80x50"_s,
  44. "con80x60"_s,
  45. "cons25"_s,
  46. "console"_s,
  47. "cygwin"_s,
  48. "dtterm"_s,
  49. "eterm-color"_s,
  50. "gnome"_s,
  51. "gnome-256color"_s,
  52. "konsole"_s,
  53. "konsole-256color"_s,
  54. "kterm"_s,
  55. "linux"_s,
  56. "linux-c"_s,
  57. "mach-color"_s,
  58. "mlterm"_s,
  59. "msys"_s,
  60. "putty"_s,
  61. "putty-256color"_s,
  62. "rxvt"_s,
  63. "rxvt-256color"_s,
  64. "rxvt-cygwin"_s,
  65. "rxvt-cygwin-native"_s,
  66. "rxvt-unicode"_s,
  67. "rxvt-unicode-256color"_s,
  68. "screen"_s,
  69. "screen-256color"_s,
  70. "screen-256color-bce"_s,
  71. "screen-bce"_s,
  72. "screen-w"_s,
  73. "screen.linux"_s,
  74. "st-256color"_s,
  75. "tmux"_s,
  76. "tmux-256color"_s,
  77. "vt100"_s,
  78. "xterm"_s,
  79. "xterm-16color"_s,
  80. "xterm-256color"_s,
  81. "xterm-88color"_s,
  82. "xterm-color"_s,
  83. "xterm-debian"_s,
  84. "xterm-kitty"_s,
  85. "xterm-termite"_s,
  86. } };
  87. bool TermIsVT100()
  88. {
  89. if (cm::optional<std::string> term = cmSystemTools::GetEnvVar("TERM")) {
  90. // NOLINTNEXTLINE(readability-qualified-auto)
  91. auto i = std::lower_bound(kVT100Names.begin(), kVT100Names.end(), *term);
  92. if (i != kVT100Names.end() && *i == *term) {
  93. return true;
  94. }
  95. }
  96. return false;
  97. }
  98. #endif
  99. } // anonymous namespace
  100. Stream::Stream(std::ios& s, FILE* file, Direction direction)
  101. : IOS_(s)
  102. , FD_(cm_fileno(file))
  103. {
  104. #ifdef _WIN32
  105. DWORD mode;
  106. auto h = reinterpret_cast<HANDLE>(_get_osfhandle(this->FD_));
  107. if (GetConsoleMode(h, &mode)) {
  108. this->Console_ = h;
  109. DWORD vtMode = mode |
  110. (direction == Direction::In ? ENABLE_VIRTUAL_TERMINAL_INPUT
  111. : ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  112. if (SetConsoleMode(this->Console_, vtMode)) {
  113. this->Kind_ = TermKind::VT100;
  114. } else {
  115. SetConsoleMode(this->Console_, mode);
  116. this->Kind_ = TermKind::Console;
  117. }
  118. }
  119. #else
  120. static_cast<void>(direction);
  121. if (isatty(this->FD_) && TermIsVT100()) {
  122. this->Kind_ = TermKind::VT100;
  123. }
  124. #endif
  125. }
  126. IStream::IStream(std::istream& is, FILE* file)
  127. : Stream(is, file, Direction::In)
  128. {
  129. }
  130. std::istream& IStream::IOS() const
  131. {
  132. return dynamic_cast<std::istream&>(this->Stream::IOS());
  133. }
  134. OStream::OStream(std::ostream& os, FILE* file)
  135. : Stream(os, file, Direction::Out)
  136. {
  137. }
  138. std::ostream& OStream::IOS() const
  139. {
  140. return dynamic_cast<std::ostream&>(this->Stream::IOS());
  141. }
  142. }
  143. }