diff --git a/stl/inc/__msvc_filebuf.hpp b/stl/inc/__msvc_filebuf.hpp index 4d8e76dbc17..4a219f592ed 100644 --- a/stl/inc/__msvc_filebuf.hpp +++ b/stl/inc/__msvc_filebuf.hpp @@ -384,9 +384,9 @@ class basic_filebuf : public basic_streambuf<_Elem, _Traits> { // stream buffer } #if _HAS_CXX23 && defined(_CPPRTTI) - template - friend ios_base::iostate _Print_noformat_unicode(ostream&, string_view); -#endif + template + friend ios_base::iostate _Do_on_maybe_unicode_console(ostream&, _UnicodeConsoleFn, _FallbackFn); +#endif // ^^^ _HAS_CXX23 && defined(_CPPRTTI) ^^^ protected: int_type __CLR_OR_THIS_CALL overflow(int_type _Meta = _Traits::eof()) override { // put an element to stream diff --git a/stl/inc/__msvc_print.hpp b/stl/inc/__msvc_print.hpp index edaedc8f3de..2f9c4963cc4 100644 --- a/stl/inc/__msvc_print.hpp +++ b/stl/inc/__msvc_print.hpp @@ -55,6 +55,9 @@ _NODISCARD _Success_(return == __std_win_error::_Success) __std_win_error __stdcall __std_print_to_unicode_console(_In_ __std_unicode_console_handle _Console_handle, _In_reads_(_Str_size) const char* _Str, _In_ size_t _Str_size) noexcept; +_NODISCARD _Success_(return == __std_win_error::_Success) __std_win_error + __stdcall __std_print_newline_only_to_unicode_console(_In_ __std_unicode_console_handle _Console_handle) noexcept; + } // extern "C" _STD_BEGIN diff --git a/stl/inc/ostream b/stl/inc/ostream index 40a60377077..3357fd3aad1 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -95,6 +95,24 @@ ios_base::iostate _Print_noformat_nonunicode(ostream& _Ostr, const string_view _ return _State; } +template +ios_base::iostate _Print_newline_only_nonunicode(ostream& _Ostr) { + // *LOCKED* + // + // This function is called from a context in which an ostream::sentry has been + // constructed. + ios_base::iostate _State = ios_base::goodbit; + + _TRY_IO_BEGIN + const bool _Was_insertion_successful = _Ostr.rdbuf()->sputc('\n') == '\n'; + if (!_Was_insertion_successful) [[unlikely]] { + _State |= ios_base::badbit; + } + _CATCH_IO_(ios_base, _Ostr) + + return _State; +} + template void _Vprint_nonunicode_impl( const _Add_newline _Add_nl, ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) { @@ -117,8 +135,9 @@ void _Vprint_nonunicode_impl( _Ostr.setstate(_State); } -template -ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str) { +template +ios_base::iostate _Do_on_maybe_unicode_console( + ostream& _Ostr, _UnicodeConsoleFn _Unicode_console_func, _FallbackFn _Fallback_func) { // *LOCKED* // // This function is called from a context in which an ostream::sentry has been @@ -136,7 +155,7 @@ ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str // If we got nullptr, then it probably isn't being used for a unicode console... if (_Filebuf == nullptr) { - _State |= _STD _Print_noformat_nonunicode(_Ostr, _Str); + _State |= _Fallback_func(); return _State; } @@ -175,18 +194,40 @@ ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str } const __std_win_error _Unicode_console_print_result = - __std_print_to_unicode_console(_Unicode_console_retrieval_result._Console_handle, _Str.data(), _Str.size()); + _Unicode_console_func(_Unicode_console_retrieval_result._Console_handle); if (_Unicode_console_print_result != __std_win_error::_Success) [[unlikely]] { _State |= ios_base::badbit; } _CATCH_IO_(ios_base, _Ostr) } else { - _State |= _STD _Print_noformat_nonunicode(_Ostr, _Str); + _State |= _Fallback_func(); } return _State; } +template +ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str) { + const auto _Unicode_console = [&](const __std_unicode_console_handle _Console_handle) { + return __std_print_to_unicode_console(_Console_handle, _Str.data(), _Str.size()); + }; + + const auto _Fallback = [&] { return _STD _Print_noformat_nonunicode(_Ostr, _Str); }; + + return _STD _Do_on_maybe_unicode_console(_Ostr, _Unicode_console, _Fallback); +} + +template +ios_base::iostate _Print_newline_only_unicode(ostream& _Ostr) { + const auto _Unicode_console = [](const __std_unicode_console_handle _Console_handle) { + return __std_print_newline_only_to_unicode_console(_Console_handle); + }; + + const auto _Fallback = [&] { return _STD _Print_newline_only_nonunicode(_Ostr); }; + + return _STD _Do_on_maybe_unicode_console(_Ostr, _Unicode_console, _Fallback); +} + template void _Vprint_unicode_impl( const _Add_newline _Add_nl, ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) { @@ -258,7 +299,20 @@ void println(ostream& _Ostr, const format_string<_Types...> _Fmt, _Types&&... _A _EXPORT_STD template // improves throughput, see GH-2329 void println(ostream& _Ostr) { - _STD print(_Ostr, "\n"); + const ostream::sentry _Ok(_Ostr); + ios_base::iostate _State = ios_base::goodbit; + + if (!_Ok) [[unlikely]] { + _State |= ios_base::badbit; + } else [[likely]] { + if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) { + _State |= _STD _Print_newline_only_unicode(_Ostr); + } else { + _State |= _STD _Print_newline_only_nonunicode(_Ostr); + } + } + + _Ostr.setstate(_State); } _EXPORT_STD template // improves throughput, see GH-2329 diff --git a/stl/inc/print b/stl/inc/print index 7111b5558d8..ccb812ddd52 100644 --- a/stl/inc/print +++ b/stl/inc/print @@ -192,6 +192,32 @@ inline void _Vprint_unicode_noformat_impl(FILE* const _Stream, const string_view _STD _Do_on_maybe_unicode_console(_Stream, _Unicode_console, _Fallback); } +inline void _Fputc_newline(FILE* const _Stream) { + const bool _Was_write_successful = _CSTD fputc('\n', _Stream) == '\n'; + + if (!_Was_write_successful) [[unlikely]] { + _Throw_system_error(static_cast(errno)); + } +} + +inline void _Print_newline_only_unicode(FILE* const _Stream) { + const auto _Unicode_console = [&](const __std_unicode_console_handle _Console_handle) { + const bool _Was_flush_successful = _CSTD fflush(_Stream) == 0; + if (!_Was_flush_successful) [[unlikely]] { + _Throw_system_error(static_cast(errno)); + } + + const __std_win_error _Console_print_result = __std_print_newline_only_to_unicode_console(_Console_handle); + if (_Console_print_result != __std_win_error::_Success) [[unlikely]] { + _STD _Throw_system_error_from_std_win_error(_Console_print_result); + } + }; + + const auto _Fallback = [&] { _STD _Fputc_newline(_Stream); }; + + _STD _Do_on_maybe_unicode_console(_Stream, _Unicode_console, _Fallback); +} + // Format to intermediate string buffer, then print to unicode console/file inline void _Vprint_unicode_buffered_impl( const _Add_newline _Add_nl, FILE* const _Stream, const string_view _Fmt_str, const format_args _Fmt_args) { @@ -271,7 +297,11 @@ void println(FILE* const _Stream, const format_string<_Types...> _Fmt, _Types&&. _EXPORT_STD template // improves throughput, see GH-2329 void println(FILE* _Stream) { - _STD print(_Stream, "\n"); + if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) { + _STD _Print_newline_only_unicode(_Stream); + } else { + _STD _Fputc_newline(_Stream); + } } _EXPORT_STD template // improves throughput, see GH-2329 diff --git a/stl/src/print.cpp b/stl/src/print.cpp index 61efeec768e..77c31478675 100644 --- a/stl/src/print.cpp +++ b/stl/src/print.cpp @@ -297,4 +297,22 @@ extern "C" { } } +[[nodiscard]] _Success_(return == __std_win_error::_Success) __std_win_error + __stdcall __std_print_newline_only_to_unicode_console( + _In_ const __std_unicode_console_handle _Console_handle) noexcept { + if (_Console_handle == __std_unicode_console_handle::_Invalid) [[unlikely]] { + return __std_win_error::_Invalid_parameter; + } + + const auto _Actual_console_handle = reinterpret_cast(_Console_handle); + + const BOOL _Write_result = WriteConsoleW(_Actual_console_handle, L"\n", 1, nullptr, nullptr); + + if (!_Write_result) [[unlikely]] { + return static_cast<__std_win_error>(GetLastError()); + } + + return __std_win_error::_Success; +} + } // extern "C"