diff --git a/include/fmt/std.h b/include/fmt/std.h index 2bab00f2..6ff7de63 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -102,19 +102,19 @@ template struct ubitint {}; #if FMT_CPP_LIB_FILESYSTEM template -auto get_path_string(const std::filesystem::path& p, - const std::basic_string& native) { +auto get_path_string(const std::basic_string& native) { if constexpr (std::is_same_v && std::is_same_v) { return to_utf8(native, to_utf8_error_policy::wtf); + } else if constexpr (std::is_same_v) { + return native; } else { - return p.string(); + return std::filesystem::path(native).string(); } } template void write_escaped_path(basic_memory_buffer& quoted, - const std::filesystem::path& p, const std::basic_string& native) { if constexpr (std::is_same_v && std::is_same_v) { @@ -126,7 +126,8 @@ void write_escaped_path(basic_memory_buffer& quoted, write_escaped_string( std::back_inserter(quoted), native); } else { - write_escaped_string(std::back_inserter(quoted), p.string()); + write_escaped_string(std::back_inserter(quoted), + std::filesystem::path(native).string()); } } @@ -337,11 +338,11 @@ template struct formatter { detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, ctx); if (!debug_) { - auto s = detail::get_path_string(p, path_string); + auto s = detail::get_path_string(path_string); return detail::write(ctx.out(), basic_string_view(s), specs); } auto quoted = basic_memory_buffer(); - detail::write_escaped_path(quoted, p, path_string); + detail::write_escaped_path(quoted, path_string); return detail::write(ctx.out(), basic_string_view(quoted.data(), quoted.size()), specs); diff --git a/test/std-test.cc b/test/std-test.cc index eaf238b4..7d992584 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -14,6 +14,7 @@ #include "fmt/os.h" // fmt::system_category #include "fmt/ranges.h" +#include "fmt/xchar.h" #include "gtest-extra.h" // StartsWith #ifdef __cpp_lib_filesystem @@ -32,9 +33,18 @@ TEST(std_test, path) { EXPECT_EQ(fmt::format("{:?}", path("foo\"bar")), "\"foo\\\"bar\""); EXPECT_EQ(fmt::format("{:g}", path("/usr/bin")), "/usr/bin"); + + // libstdc++ collapses repeated separators in the generic format. + const path repeated = "a//b"; + EXPECT_EQ(fmt::format("{:g}", repeated), repeated.generic_string()); + EXPECT_EQ(fmt::format(L"{:g}", repeated), repeated.generic_wstring()); + EXPECT_EQ(fmt::format(L"{:?g}", repeated), + L"\"" + repeated.generic_wstring() + L"\""); # ifdef _WIN32 EXPECT_EQ(fmt::format("{}", path("C:\\foo")), "C:\\foo"); EXPECT_EQ(fmt::format("{:g}", path("C:\\foo")), "C:/foo"); + EXPECT_EQ(fmt::format(L"{}", path(L"C:\\foo")), L"C:\\foo"); + EXPECT_EQ(fmt::format(L"{:g}", path(L"C:\\foo")), L"C:/foo"); EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448" L"\x0447\x044B\x043D\x0430")),