diff --git a/examples/main.cpp b/examples/main.cpp index 9ab32f4a97..4789ed7145 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -37,7 +37,7 @@ int bc::system::main(int argc, char* argv[]) system::cout << "Enter text to input..." << std::endl; std::string console; system::cin >> console; - system::cout << "input[0] : " << console << std::endl; + system::cout << "input[0] : " << console << std::endl; if (argc > 1) system::cout << "argv[1] : " << argv[1] << std::endl; diff --git a/include/bitcoin/system/unicode/utf8_everywhere/console_streambuf.hpp b/include/bitcoin/system/unicode/utf8_everywhere/console_streambuf.hpp index 7232c8d8e7..5e552c9c5e 100644 --- a/include/bitcoin/system/unicode/utf8_everywhere/console_streambuf.hpp +++ b/include/bitcoin/system/unicode/utf8_everywhere/console_streambuf.hpp @@ -35,30 +35,30 @@ class BC_API console_streambuf public: DELETE_COPY_MOVE(console_streambuf); - /// Initialize stdio to use utf8 translation on Windows. - static void initialize(size_t stream_buffer_size) THROWS; + /// Initialize console in/out to use utf8 translation on Windows. + static void set_input(size_t stream_buffer_size) THROWS; + static void set_output() THROWS; protected: /// Protected construction, use static initialize method. - console_streambuf(const std::wstreambuf& stream_buffer, - size_t stream_buffer_size) THROWS; + console_streambuf(const std::wstreambuf& buffer, size_t size) THROWS; /// Delete stream buffer. virtual ~console_streambuf() NOEXCEPT; /// Alternate console read. - virtual std::streamsize xsgetn(wchar_t* buffer, - std::streamsize size) THROWS; + std::streamsize xsgetn(wchar_t* buffer, + std::streamsize size) THROWS override; /// Alternate console read. - virtual std::wstreambuf::int_type underflow() THROWS; + std::wstreambuf::int_type underflow() THROWS override; #ifdef HAVE_MSC private: // These are not thread safe. // The constructed buffer size. - size_t buffer_size_; + const size_t buffer_size_; // The dynamically-allocated buffers. wchar_t* buffer_; diff --git a/include/bitcoin/system/unicode/utf8_everywhere/unicode_istream.hpp b/include/bitcoin/system/unicode/utf8_everywhere/unicode_istream.hpp index 9bacd76552..e6e7c09816 100644 --- a/include/bitcoin/system/unicode/utf8_everywhere/unicode_istream.hpp +++ b/include/bitcoin/system/unicode/utf8_everywhere/unicode_istream.hpp @@ -35,7 +35,7 @@ class BC_API unicode_istream /// Construct instance of a conditionally-narrowing input stream. unicode_istream(std::istream& narrow_stream, std::wistream& wide_stream, - size_t wide_buffer_size) THROWS; + size_t wide_size) THROWS; /// Delete the unicode_streambuf that wraps wide_stream. virtual ~unicode_istream() NOEXCEPT; diff --git a/include/bitcoin/system/unicode/utf8_everywhere/unicode_ostream.hpp b/include/bitcoin/system/unicode/utf8_everywhere/unicode_ostream.hpp index af4d5141fa..700ee2705b 100644 --- a/include/bitcoin/system/unicode/utf8_everywhere/unicode_ostream.hpp +++ b/include/bitcoin/system/unicode/utf8_everywhere/unicode_ostream.hpp @@ -34,7 +34,7 @@ class BC_API unicode_ostream /// Construct instance of a conditionally-widening output stream. unicode_ostream(std::ostream& narrow_stream, std::wostream& wide_stream, - size_t wide_buffer_size) THROWS; + size_t wide_size) THROWS; /// Delete the unicode_streambuf that wraps wide_stream. virtual ~unicode_ostream() NOEXCEPT; diff --git a/include/bitcoin/system/unicode/utf8_everywhere/unicode_streambuf.hpp b/include/bitcoin/system/unicode/utf8_everywhere/unicode_streambuf.hpp index 4e468945f8..ee36723cde 100644 --- a/include/bitcoin/system/unicode/utf8_everywhere/unicode_streambuf.hpp +++ b/include/bitcoin/system/unicode/utf8_everywhere/unicode_streambuf.hpp @@ -37,30 +37,30 @@ class BC_API unicode_streambuf DELETE_COPY_MOVE(unicode_streambuf); /// Construct unicode stream buffer from a weak reference to a wide buffer. - unicode_streambuf(std::wstreambuf* wide_buffer, size_t size) THROWS; + unicode_streambuf(std::wstreambuf* buffer, size_t size) THROWS; /// Synchronize stream buffer. virtual ~unicode_streambuf() NOEXCEPT; protected: /// Underflow for support of input streams. - virtual std::streambuf::int_type underflow() THROWS; + std::streambuf::int_type underflow() THROWS override; /// Overflow for support of output streams. - virtual std::streambuf::int_type overflow( - std::streambuf::int_type character) THROWS; + std::streambuf::int_type overflow( + std::streambuf::int_type character) THROWS override; - //// Sync for support of output streams. - virtual int sync() THROWS; + /// Sync for support of output streams. + int sync() THROWS override; private: // These are not thread safe. // The constructed wide buffer size in number of characters. - size_t wide_size_; + const size_t wide_size_; // The derived narrow buffer size in utf8 (bytes). - size_t narrow_size_; + const size_t narrow_size_; // The dynamically-allocated buffers. wchar_t* wide_; diff --git a/src/unicode/utf8_everywhere/console_streambuf.cpp b/src/unicode/utf8_everywhere/console_streambuf.cpp index b5532ee0f3..9e6263d230 100644 --- a/src/unicode/utf8_everywhere/console_streambuf.cpp +++ b/src/unicode/utf8_everywhere/console_streambuf.cpp @@ -38,13 +38,14 @@ static LPVOID get_input_handle() THROWS return handle; } -// Hack for faulty std::wcin translation of non-ASCII keyboard input. -void console_streambuf::initialize(size_t stream_buffer_size) THROWS +void console_streambuf::set_input(size_t stream_buffer_size) THROWS { - // Set the console to operate in UTF-8 for this process. + // Set console input to operate in UTF-8 for this process. + // learn.microsoft.com/en-us/windows/console/setconsolecp if (SetConsoleCP(CP_UTF8) == FALSE) - throw runtime_exception("Failed to set console to utf8."); + throw runtime_exception("Failed to set console input to utf8."); + // Hack for faulty std::wcin translation of non-ASCII keyboard input. DWORD console_mode; if (GetConsoleMode(get_input_handle(), &console_mode) != FALSE) { @@ -53,10 +54,19 @@ void console_streambuf::initialize(size_t stream_buffer_size) THROWS } } -console_streambuf::console_streambuf( - const std::wstreambuf& stream_buffer, size_t size) THROWS - : buffer_size_(size), buffer_(new wchar_t[buffer_size_]), - std::wstreambuf(stream_buffer) +void console_streambuf::set_output() THROWS +{ + // Set console output to operate in UTF-8 for this process. + // learn.microsoft.com/en-us/windows/console/setconsoleoutputcp + if (SetConsoleOutputCP(CP_UTF8) == FALSE) + throw runtime_exception("Failed to set console output to utf8."); +} + +console_streambuf::console_streambuf(const std::wstreambuf& buffer, + size_t size) THROWS + : buffer_size_(size), + buffer_(new wchar_t[size]), + std::wstreambuf(buffer) { } @@ -92,7 +102,11 @@ std::wstreambuf::int_type console_streambuf::underflow() THROWS #else -void console_streambuf::initialize(size_t) THROWS +void console_streambuf::set_input(size_t) THROWS +{ +} + +void console_streambuf::set_output() THROWS { } diff --git a/src/unicode/utf8_everywhere/environment.cpp b/src/unicode/utf8_everywhere/environment.cpp index c0db6f49f2..12f48f615b 100644 --- a/src/unicode/utf8_everywhere/environment.cpp +++ b/src/unicode/utf8_everywhere/environment.cpp @@ -235,7 +235,7 @@ static std::once_flag io_mutex; // Static initializer for bc::system::cin. std::istream& cin_stream() THROWS { - std::call_once(io_mutex, console_streambuf::initialize, utf16_buffer_size); + std::call_once(io_mutex, console_streambuf::set_input, utf16_buffer_size); static unicode_istream input(std::cin, std::wcin, utf16_buffer_size); return input; } @@ -243,7 +243,7 @@ std::istream& cin_stream() THROWS // Static initializer for bc::system::cout. std::ostream& cout_stream() THROWS { - std::call_once(io_mutex, console_streambuf::initialize, utf16_buffer_size); + std::call_once(io_mutex, console_streambuf::set_output); static unicode_ostream output(std::cout, std::wcout, utf16_buffer_size); return output; } @@ -251,7 +251,7 @@ std::ostream& cout_stream() THROWS // Static initializer for bc::system::cerr. std::ostream& cerr_stream() THROWS { - std::call_once(io_mutex, console_streambuf::initialize, utf16_buffer_size); + std::call_once(io_mutex, console_streambuf::set_output); static unicode_ostream error(std::cerr, std::wcerr, utf16_buffer_size); return error; } diff --git a/src/unicode/utf8_everywhere/unicode_istream.cpp b/src/unicode/utf8_everywhere/unicode_istream.cpp index fd01bfca2a..41f19c588d 100644 --- a/src/unicode/utf8_everywhere/unicode_istream.cpp +++ b/src/unicode/utf8_everywhere/unicode_istream.cpp @@ -24,16 +24,13 @@ namespace libbitcoin { namespace system { -unicode_istream::unicode_istream( #ifdef HAVE_MSC - std::istream&, std::wistream& wide_stream, - size_t wide_buffer_size) THROWS -#else - std::istream& narrow_stream, std::wistream&, size_t) -#endif -#ifdef HAVE_MSC - : std::istream(new unicode_streambuf(wide_stream.rdbuf(), wide_buffer_size)) +unicode_istream::unicode_istream(std::istream&, std::wistream& wide_stream, + size_t wide_size) THROWS + : std::istream(new unicode_streambuf(wide_stream.rdbuf(), wide_size)) #else +unicode_istream::unicode_istream(std::istream& narrow_stream, + std::wistream&, size_t) THROWS : std::istream(narrow_stream.rdbuf()) #endif { diff --git a/src/unicode/utf8_everywhere/unicode_ostream.cpp b/src/unicode/utf8_everywhere/unicode_ostream.cpp index 83a806bddd..1a16529b85 100644 --- a/src/unicode/utf8_everywhere/unicode_ostream.cpp +++ b/src/unicode/utf8_everywhere/unicode_ostream.cpp @@ -24,16 +24,13 @@ namespace libbitcoin { namespace system { -unicode_ostream::unicode_ostream( #ifdef HAVE_MSC - std::ostream&, std::wostream& wide_stream, - size_t wide_buffer_size) THROWS -#else - std::ostream& narrow_stream, std::wostream&, size_t) -#endif -#ifdef HAVE_MSC - : std::ostream(new unicode_streambuf(wide_stream.rdbuf(), wide_buffer_size)) +unicode_ostream::unicode_ostream(std::ostream&, std::wostream& wide_stream, + size_t wide_size) THROWS + : std::ostream(new unicode_streambuf(wide_stream.rdbuf(), wide_size)) #else +unicode_ostream::unicode_ostream(std::ostream& narrow_stream, + std::wostream&, size_t) THROWS : std::ostream(narrow_stream.rdbuf()) #endif { diff --git a/src/unicode/utf8_everywhere/unicode_streambuf.cpp b/src/unicode/utf8_everywhere/unicode_streambuf.cpp index 20140d3706..7b38afbdb6 100644 --- a/src/unicode/utf8_everywhere/unicode_streambuf.cpp +++ b/src/unicode/utf8_everywhere/unicode_streambuf.cpp @@ -28,15 +28,15 @@ namespace libbitcoin { namespace system { -unicode_streambuf::unicode_streambuf(std::wstreambuf* wide_buffer, +unicode_streambuf::unicode_streambuf(std::wstreambuf* buffer, size_t size) THROWS : wide_size_(size), narrow_size_(wide_size_ * utf8_max_character_size), narrow_(new char[narrow_size_]), wide_(new wchar_t[narrow_size_]), - wide_buffer_(wide_buffer) + wide_buffer_(buffer) { - if (is_zero(wide_size_) || wide_buffer == nullptr || + if (is_zero(wide_size_) || is_null(wide_buffer_) || wide_size_ > (bc::max_size_t / utf8_max_character_size)) throw runtime_exception("unicode_streambuf parameters"); @@ -63,7 +63,7 @@ std::streambuf::int_type unicode_streambuf::underflow() THROWS // streamsize is signed. const auto size = static_cast(wide_size_); - // Read from the wide input buffer (non-negative). + // Read from the wide input buffer, blocking (non-negative). const auto read = wide_buffer_->sgetn(wide_, size); // Handle read termination. @@ -90,7 +90,7 @@ std::streambuf::int_type unicode_streambuf::underflow() THROWS // MSVC does not support a UTF8 locale and as such streams interpret // narrow characters in the default locale. This implementation // assumes the stream will treat each byte of a multibyte narrow -// chracter as an individual single byte character. +// character as an individual single byte character. std::streambuf::int_type unicode_streambuf::overflow( std::streambuf::int_type character) THROWS { @@ -134,7 +134,6 @@ std::streambuf::int_type unicode_streambuf::overflow( return traits_type::eof(); } - // C++17: parallel policy for copy_n. // write is necessarily no greater than unwritten. // Copy the fractional character to the beginning of the buffer. std::copy_n(&narrow_[write - unwritten], unwritten, narrow_); @@ -155,6 +154,10 @@ std::streambuf::int_type unicode_streambuf::overflow( // Flush our output sequence. int unicode_streambuf::sync() THROWS { + // Bypass for input. + if (is_null(std::streambuf::pptr())) + return std::streambuf::sync(); + const int success = zero; const int failure = negative_one;