Skip to content

Commit

Permalink
Fix chrono_test.locale
Browse files Browse the repository at this point in the history
  • Loading branch information
phprus committed Jun 11, 2021
1 parent a5d1fb0 commit 0ec6d16
Showing 1 changed file with 28 additions and 3 deletions.
31 changes: 28 additions & 3 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,15 @@ inline auto do_write(const std::tm& time, const std::locale& loc, char format,
if (end.failed()) FMT_THROW(format_error("failed to format time"));
auto str = os.str();
if (!detail::is_utf8() || loc == std::locale::classic()) return str;
// char16_t and char32_t codecvts are broken in MSVC (linkage errors).
using code_unit = conditional_t<FMT_MSC_VER != 0, wchar_t, char16_t>;
// char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
// gcc-4.
#if FMT_MSC_VER != 0 || \
(defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
// macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5+
using code_unit = wchar_t;
#else
using code_unit = char32_t;
#endif
auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
auto mb = std::mbstate_t();
const char* from_next = nullptr;
Expand All @@ -312,12 +319,30 @@ inline auto do_write(const std::tm& time, const std::locale& loc, char format,
FMT_THROW(format_error("failed to format time"));
str.clear();
for (code_unit* p = buf; p != to_next; ++p) {
auto c = *p;
uint32_t c = static_cast<uint32_t>(*p);
if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
// surrogate pair
++p;
if (p == to_next || (c & 0xfffffc00) != 0xd800 ||
(static_cast<uint32_t>(*p) & 0xfffffc00) != 0xdc00) {
FMT_THROW(format_error("failed to format time"));
}
c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
}
if (c < 0x80) {
str.push_back(static_cast<char>(c));
} else if (c < 0x800) {
str.push_back(static_cast<char>(0xc0 | (c >> 6)));
str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
str.push_back(static_cast<char>(0xe0 | (c >> 12)));
str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else if (c >= 0x10000 && c <= 0x10ffff) {
str.push_back(static_cast<char>(0xf0 | (c >> 18)));
str.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else {
FMT_THROW(format_error("failed to format time"));
}
Expand Down

0 comments on commit 0ec6d16

Please sign in to comment.