]>
Commit | Line | Data |
---|---|---|
f67539c2 | 1 | // Copyright (c) 2012 Artyom Beilis (Tonkikh) |
1e59de90 | 2 | // Copyright (c) 2020-2021 Alexander Grund |
f67539c2 | 3 | // |
1e59de90 TL |
4 | // Distributed under the Boost Software License, Version 1.0. |
5 | // (See accompanying file LICENSE or copy at | |
f67539c2 | 6 | // http://www.boost.org/LICENSE_1_0.txt) |
1e59de90 | 7 | |
f67539c2 TL |
8 | #define BOOST_NOWIDE_SOURCE |
9 | #include <boost/nowide/iostream.hpp> | |
10 | ||
11 | #ifndef BOOST_WINDOWS | |
12 | ||
13 | namespace boost { | |
14 | namespace nowide { | |
1e59de90 | 15 | // LCOV_EXCL_START |
f67539c2 TL |
16 | /// Avoid empty compilation unit warnings |
17 | /// \internal | |
18 | BOOST_NOWIDE_DECL void dummy_exported_function() | |
19 | {} | |
1e59de90 | 20 | // LCOV_EXCL_STOP |
f67539c2 TL |
21 | } // namespace nowide |
22 | } // namespace boost | |
23 | ||
24 | #else | |
25 | ||
1e59de90 | 26 | #include "console_buffer.hpp" |
f67539c2 | 27 | #include <cassert> |
f67539c2 | 28 | #include <iostream> |
f67539c2 TL |
29 | |
30 | #ifndef NOMINMAX | |
31 | #define NOMINMAX | |
32 | #endif | |
f67539c2 TL |
33 | #include <windows.h> |
34 | ||
35 | namespace boost { | |
36 | namespace nowide { | |
37 | namespace detail { | |
38 | ||
39 | namespace { | |
40 | bool is_atty_handle(HANDLE h) | |
41 | { | |
1e59de90 TL |
42 | DWORD dummy; |
43 | return h && GetConsoleMode(h, &dummy) != FALSE; | |
f67539c2 TL |
44 | } |
45 | } // namespace | |
46 | ||
1e59de90 | 47 | class console_output_buffer final : public console_output_buffer_base |
f67539c2 | 48 | { |
1e59de90 TL |
49 | HANDLE handle_; |
50 | ||
f67539c2 | 51 | public: |
1e59de90 | 52 | explicit console_output_buffer(HANDLE handle) : handle_(handle) |
f67539c2 TL |
53 | {} |
54 | ||
55 | protected: | |
1e59de90 TL |
56 | bool |
57 | do_write(const wchar_t* buffer, std::size_t num_chars_to_write, std::size_t& num_chars_written) override | |
f67539c2 | 58 | { |
f67539c2 | 59 | DWORD size = 0; |
1e59de90 TL |
60 | const bool result = |
61 | WriteConsoleW(handle_, buffer, static_cast<DWORD>(num_chars_to_write), &size, 0) != 0; | |
62 | num_chars_written = size; | |
63 | return result; | |
f67539c2 | 64 | } |
f67539c2 TL |
65 | }; |
66 | ||
1e59de90 | 67 | class console_input_buffer final : public console_input_buffer_base |
f67539c2 | 68 | { |
1e59de90 TL |
69 | HANDLE handle_; |
70 | ||
f67539c2 | 71 | public: |
1e59de90 | 72 | explicit console_input_buffer(HANDLE handle) : handle_(handle) |
f67539c2 TL |
73 | {} |
74 | ||
75 | protected: | |
1e59de90 | 76 | bool do_read(wchar_t* buffer, std::size_t num_chars_to_read, std::size_t& num_chars_read) override |
20effc67 | 77 | { |
1e59de90 TL |
78 | DWORD size = 0; |
79 | const auto to_read_size = static_cast<DWORD>(num_chars_to_read); | |
80 | const bool result = ReadConsoleW(handle_, buffer, to_read_size, &size, 0) != 0; | |
81 | num_chars_read = size; | |
82 | return result; | |
f67539c2 | 83 | } |
f67539c2 TL |
84 | }; |
85 | ||
1e59de90 | 86 | winconsole_ostream::winconsole_ostream(const bool isBuffered, winconsole_ostream* tieStream) : std::ostream(0) |
f67539c2 | 87 | { |
1e59de90 TL |
88 | HANDLE h; |
89 | if(isBuffered) | |
90 | h = GetStdHandle(STD_OUTPUT_HANDLE); | |
91 | else | |
92 | h = GetStdHandle(STD_ERROR_HANDLE); | |
f67539c2 TL |
93 | if(is_atty_handle(h)) |
94 | { | |
95 | d.reset(new console_output_buffer(h)); | |
96 | std::ostream::rdbuf(d.get()); | |
97 | } else | |
98 | { | |
1e59de90 TL |
99 | std::ostream::rdbuf(isBuffered ? std::cout.rdbuf() : std::cerr.rdbuf()); |
100 | assert(rdbuf()); | |
f67539c2 TL |
101 | } |
102 | if(tieStream) | |
1e59de90 | 103 | { |
f67539c2 | 104 | tie(tieStream); |
1e59de90 TL |
105 | setf(ios_base::unitbuf); // If tieStream is set, this is cerr -> set unbuffered |
106 | } | |
f67539c2 TL |
107 | } |
108 | winconsole_ostream::~winconsole_ostream() | |
109 | { | |
110 | try | |
111 | { | |
112 | flush(); | |
113 | } catch(...) | |
1e59de90 | 114 | {} // LCOV_EXCL_LINE |
f67539c2 TL |
115 | } |
116 | ||
117 | winconsole_istream::winconsole_istream(winconsole_ostream* tieStream) : std::istream(0) | |
118 | { | |
119 | HANDLE h = GetStdHandle(STD_INPUT_HANDLE); | |
120 | if(is_atty_handle(h)) | |
121 | { | |
122 | d.reset(new console_input_buffer(h)); | |
123 | std::istream::rdbuf(d.get()); | |
124 | } else | |
125 | { | |
126 | std::istream::rdbuf(std::cin.rdbuf()); | |
1e59de90 | 127 | assert(rdbuf()); |
f67539c2 TL |
128 | } |
129 | if(tieStream) | |
130 | tie(tieStream); | |
131 | } | |
132 | ||
133 | winconsole_istream::~winconsole_istream() | |
134 | {} | |
135 | ||
136 | } // namespace detail | |
137 | ||
1e59de90 TL |
138 | // Make sure those are initialized as early as possible |
139 | #ifdef BOOST_MSVC | |
140 | #pragma warning(disable : 4073) | |
141 | #pragma init_seg(lib) | |
142 | #endif | |
143 | #ifdef BOOST_NOWIDE_HAS_INIT_PRIORITY | |
144 | #define BOOST_NOWIDE_INIT_PRIORITY __attribute__((init_priority(101))) | |
145 | #else | |
146 | #define BOOST_NOWIDE_INIT_PRIORITY | |
147 | #endif | |
148 | detail::winconsole_ostream cout BOOST_NOWIDE_INIT_PRIORITY(true, nullptr); | |
149 | detail::winconsole_istream cin BOOST_NOWIDE_INIT_PRIORITY(&cout); | |
150 | detail::winconsole_ostream cerr BOOST_NOWIDE_INIT_PRIORITY(false, &cout); | |
151 | detail::winconsole_ostream clog BOOST_NOWIDE_INIT_PRIORITY(false, nullptr); | |
f67539c2 TL |
152 | } // namespace nowide |
153 | } // namespace boost | |
154 | ||
155 | #endif |