diff --git a/include/fmt/os.h b/include/fmt/os.h index 3fbd6905..6a405cd4 100644 --- a/include/fmt/os.h +++ b/include/fmt/os.h @@ -117,6 +117,8 @@ FMT_API const std::error_category& system_category() noexcept; namespace detail { FMT_API void format_windows_error(buffer& out, int error_code, const char* message) noexcept; +FMT_API bool append_system_error_message_as_utf8(buffer& buf, + string_view message) noexcept; } FMT_API std::system_error vwindows_error(int error_code, string_view fmt, diff --git a/include/fmt/std.h b/include/fmt/std.h index b6b98bb7..2e33f718 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -546,6 +546,13 @@ struct formatter& buf, + string_view message) noexcept; +} +#endif + template <> struct formatter { private: format_specs specs_; @@ -584,7 +591,12 @@ template <> struct formatter { ctx); auto buf = memory_buffer(); if (specs_.type() == presentation_type::string) { +#ifdef _WIN32 + if (!detail::append_system_error_message_as_utf8(buf, ec.message())) + buf.append(ec.message()); +#else buf.append(ec.message()); +#endif } else { buf.append(string_view(ec.category().name())); buf.push_back(':'); diff --git a/src/os.cc b/src/os.cc index 0e1d582a..4e2cbcfa 100644 --- a/src/os.cc +++ b/src/os.cc @@ -165,6 +165,29 @@ void report_windows_error(int error_code, const char* message) noexcept { do_report_error(detail::format_windows_error, error_code, message); } +namespace detail { +bool append_system_error_message_as_utf8(buffer& buf, + string_view message) noexcept { + FMT_TRY { + if (message.empty()) return true; + const int size = static_cast(message.size()); + const int wide_size = + MultiByteToWideChar(CP_ACP, 0, message.data(), size, nullptr, 0); + if (wide_size == 0) return false; + std::wstring wide(static_cast(wide_size), L'\0'); + if (MultiByteToWideChar(CP_ACP, 0, message.data(), size, wide.data(), + wide_size) == 0) + return false; + auto utf8_message = to_utf8(); + if (!utf8_message.convert(wide)) return false; + buf.append(string_view(utf8_message.c_str(), utf8_message.size())); + return true; + } + FMT_CATCH(...) {} + return false; +} +} // namespace detail + #endif // _WIN32 buffered_file::~buffered_file() noexcept {