mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-24 19:20:12 +00:00
Improve handling of Unicode in paths
This commit is contained in:
parent
53162142b2
commit
02cae7e48a
@ -56,12 +56,23 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
|||||||
}
|
}
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
template <>
|
template <>
|
||||||
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
|
inline void write_escaped_path<char>(memory_buffer& quoted,
|
||||||
const std::filesystem::path& p) {
|
const std::filesystem::path& p) {
|
||||||
auto s = p.u8string();
|
auto buf = basic_memory_buffer<wchar_t>();
|
||||||
write_escaped_string<char>(
|
write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
|
||||||
std::back_inserter(quoted),
|
for (unsigned c : buf) {
|
||||||
string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
|
// Convert UTF-16 to UTF-8.
|
||||||
|
if (c < 0x80) {
|
||||||
|
quoted.push_back(static_cast<unsigned char>(c));
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
quoted.push_back(0b1100'0000 | ((c >> 6) & 0b01'1111));
|
||||||
|
quoted.push_back(0b1000'0000 | (c & 0b11'1111));
|
||||||
|
} else {
|
||||||
|
quoted.push_back(0b1110'0000 | ((c >> 12) & 0b01'1111));
|
||||||
|
quoted.push_back(0b1000'0000 | ((c >> 6) & 0b11'1111));
|
||||||
|
quoted.push_back(0b1000'0000 | (c & 0b11'1111));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
template <>
|
template <>
|
||||||
@ -86,7 +97,7 @@ struct formatter<std::filesystem::path, Char>
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
|
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
|
||||||
typename FormatContext::iterator {
|
typename FormatContext::iterator {
|
||||||
basic_memory_buffer<Char> quoted;
|
auto quoted = basic_memory_buffer<Char>();
|
||||||
detail::write_escaped_path(quoted, p);
|
detail::write_escaped_path(quoted, p);
|
||||||
return formatter<basic_string_view<Char>>::format(
|
return formatter<basic_string_view<Char>>::format(
|
||||||
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
|
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
using testing::StartsWith;
|
using testing::StartsWith;
|
||||||
|
|
||||||
TEST(std_test, path) {
|
|
||||||
#ifdef __cpp_lib_filesystem
|
#ifdef __cpp_lib_filesystem
|
||||||
|
TEST(std_test, path) {
|
||||||
EXPECT_EQ(fmt::format("{:8}", std::filesystem::path("foo")), "\"foo\" ");
|
EXPECT_EQ(fmt::format("{:8}", std::filesystem::path("foo")), "\"foo\" ");
|
||||||
EXPECT_EQ(fmt::format("{}", std::filesystem::path("foo\"bar.txt")),
|
EXPECT_EQ(fmt::format("{}", std::filesystem::path("foo\"bar.txt")),
|
||||||
"\"foo\\\"bar.txt\"");
|
"\"foo\\\"bar.txt\"");
|
||||||
@ -26,32 +26,25 @@ TEST(std_test, path) {
|
|||||||
"\"foo\\\"bar.txt\"");
|
"\"foo\\\"bar.txt\"");
|
||||||
|
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
// File.txt in Russian.
|
EXPECT_EQ(fmt::format("{}", std::filesystem::path(
|
||||||
const wchar_t unicode_path[] = {0x424, 0x430, 0x439, 0x43b, 0x2e,
|
L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448"
|
||||||
0x74, 0x78, 0x74, 0};
|
L"\x0447\x044B\x043D\x0430")),
|
||||||
const char unicode_u8path[] = {'"', char(0xd0), char(0xa4), char(0xd0),
|
"\"Шчучыншчына\"");
|
||||||
char(0xb0), char(0xd0), char(0xb9), char(0xd0),
|
// EXPECT_EQ(fmt::format("{}", std::filesystem::path(L"\xd800")),
|
||||||
char(0xbb), '.', 't', 'x',
|
// "\\x{d800}");
|
||||||
't', '"', '\0'};
|
|
||||||
EXPECT_EQ(fmt::format("{}", std::filesystem::path(unicode_path)),
|
|
||||||
unicode_u8path);
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_std_test, format_vector_path) {
|
|
||||||
// Test ambiguity problem described in #2954.
|
// Test ambiguity problem described in #2954.
|
||||||
#ifdef __cpp_lib_filesystem
|
TEST(ranges_std_test, format_vector_path) {
|
||||||
auto p = std::filesystem::path("foo/bar.txt");
|
auto p = std::filesystem::path("foo/bar.txt");
|
||||||
auto c = std::vector<std::string>{"abc", "def"};
|
auto c = std::vector<std::string>{"abc", "def"};
|
||||||
EXPECT_EQ(fmt::format("path={}, range={}", p, c),
|
EXPECT_EQ(fmt::format("path={}, range={}", p, c),
|
||||||
"path=\"foo/bar.txt\", range=[\"abc\", \"def\"]");
|
"path=\"foo/bar.txt\", range=[\"abc\", \"def\"]");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that path is not escaped twice in the debug mode.
|
||||||
TEST(ranges_std_test, format_quote_path) {
|
TEST(ranges_std_test, format_quote_path) {
|
||||||
// Test that path is not escaped twice in the debug mode.
|
|
||||||
#ifdef __cpp_lib_filesystem
|
|
||||||
auto vec =
|
auto vec =
|
||||||
std::vector<std::filesystem::path>{"path1/file1.txt", "path2/file2.txt"};
|
std::vector<std::filesystem::path>{"path1/file1.txt", "path2/file2.txt"};
|
||||||
EXPECT_EQ(fmt::format("{}", vec),
|
EXPECT_EQ(fmt::format("{}", vec),
|
||||||
@ -61,8 +54,8 @@ TEST(ranges_std_test, format_quote_path) {
|
|||||||
EXPECT_EQ(fmt::format("{}", o), "optional(\"path/file.txt\")");
|
EXPECT_EQ(fmt::format("{}", o), "optional(\"path/file.txt\")");
|
||||||
EXPECT_EQ(fmt::format("{:?}", o), "optional(\"path/file.txt\")");
|
EXPECT_EQ(fmt::format("{:?}", o), "optional(\"path/file.txt\")");
|
||||||
# endif
|
# endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(std_test, thread_id) {
|
TEST(std_test, thread_id) {
|
||||||
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
|
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
|
||||||
@ -215,13 +208,4 @@ TEST(std_test, exception) {
|
|||||||
} catch (const std::system_error& ex) {
|
} catch (const std::system_error& ex) {
|
||||||
EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: "));
|
EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: "));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_lib_filesystem
|
|
||||||
try {
|
|
||||||
throw std::filesystem::filesystem_error("message", std::error_code());
|
|
||||||
} catch (const std::filesystem::filesystem_error& ex) {
|
|
||||||
EXPECT_THAT(fmt::format("{:t}", ex),
|
|
||||||
StartsWith("std::filesystem::filesystem_error: "));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user