Index: src/locale.cpp =================================================================== --- src/locale.cpp +++ src/locale.cpp @@ -5768,6 +5768,26 @@ pat.field[3] = value; } +static char checked_string_to_char_convert(const char* ptr) { + /* + // FIXME: The input character is multiple bytes. Do something... + if (ptr[0] && ptr[1]) + __throw_runtime_error("locale not supported"); + */ + return *ptr; +} + +static wchar_t checked_string_to_wchar_convert(const char* ptr, + __locale_struct* loc) { + mbstate_t mb = {0}; + wchar_t out; + size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc); + if (ret == static_cast(-1) || ret == static_cast(-2)) { + __throw_runtime_error("locale not supported"); + } + return out; +} + template<> void moneypunct_byname::init(const char* nm) @@ -5780,11 +5800,11 @@ lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) - __decimal_point_ = *lc->mon_decimal_point; + __decimal_point_ = checked_string_to_char_convert(lc->mon_decimal_point); else __decimal_point_ = base::do_decimal_point(); if (*lc->mon_thousands_sep) - __thousands_sep_ = *lc->mon_thousands_sep; + __thousands_sep_ = checked_string_to_char_convert(lc->mon_thousands_sep); else __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; @@ -5823,11 +5843,11 @@ lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) - __decimal_point_ = *lc->mon_decimal_point; + __decimal_point_ = checked_string_to_char_convert(lc->mon_decimal_point); else __decimal_point_ = base::do_decimal_point(); if (*lc->mon_thousands_sep) - __thousands_sep_ = *lc->mon_thousands_sep; + __thousands_sep_ = checked_string_to_char_convert(lc->mon_thousands_sep); else __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; @@ -5882,11 +5902,13 @@ " failed to construct for " + string(nm)); lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) - __decimal_point_ = static_cast(*lc->mon_decimal_point); + __decimal_point_ = checked_string_to_wchar_convert(lc->mon_decimal_point, + loc.get()); else __decimal_point_ = base::do_decimal_point(); if (*lc->mon_thousands_sep) - __thousands_sep_ = static_cast(*lc->mon_thousands_sep); + __thousands_sep_ = checked_string_to_wchar_convert(lc->mon_thousands_sep, + loc.get()); else __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; @@ -5948,11 +5970,13 @@ lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) - __decimal_point_ = static_cast(*lc->mon_decimal_point); + __decimal_point_ = checked_string_to_wchar_convert(lc->mon_decimal_point, + loc.get()); else __decimal_point_ = base::do_decimal_point(); if (*lc->mon_thousands_sep) - __thousands_sep_ = static_cast(*lc->mon_thousands_sep); + __thousands_sep_ = checked_string_to_wchar_convert(lc->mon_thousands_sep, + loc.get()); else __thousands_sep_ = base::do_thousands_sep(); __grouping_ = lc->mon_grouping; Index: test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp =================================================================== --- test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp +++ test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/decimal_point.pass.cpp @@ -12,9 +12,6 @@ // REQUIRES: locale.ru_RU.UTF-8 // REQUIRES: locale.zh_CN.UTF-8 -// Russia uses ',' for the decimal separator. GLIBC returns '.' -// XFAIL: linux - // // class moneypunct_byname @@ -25,6 +22,7 @@ #include #include +#include "test_macros.h" #include "platform_support.h" // locale name macros class Fnf @@ -112,21 +110,30 @@ assert(f.decimal_point() == L','); } +// The below tests fail due to GLIBC's use of U00A0 as mon_decimal_point +// and U002E as mon_decimal_point. +// TODO: Fix decimal_point for 'char'. +// related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006 +#ifndef TEST_HAS_GLIBC { Fnf f(LOCALE_ru_RU_UTF_8, 1); - assert(f.decimal_point() == ','); + assert(f.decimal_point() == '.'); } { Fnt f(LOCALE_ru_RU_UTF_8, 1); - assert(f.decimal_point() == ','); + assert(f.decimal_point() == '.'); } + const wchar_t sep = L'.'; +#else + const wchar_t sep = L'\u002E'; +#endif { Fwf f(LOCALE_ru_RU_UTF_8, 1); - assert(f.decimal_point() == L','); + assert(f.decimal_point() == sep); } { Fwt f(LOCALE_ru_RU_UTF_8, 1); - assert(f.decimal_point() == L','); + assert(f.decimal_point() == sep); } { Index: test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp =================================================================== --- test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp +++ test/std/localization/locale.categories/category.monetary/locale.moneypunct.byname/thousands_sep.pass.cpp @@ -18,16 +18,11 @@ // charT thousands_sep() const; -// Failure related to GLIBC's use of U00A0 as mon_thousands_sep -// and U002E as mon_decimal_point. -// TODO: U00A0 should be investigated. -// Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006 -// XFAIL: linux-gnu - #include #include #include +#include "test_macros.h" #include "platform_support.h" // locale name macros class Fnf @@ -114,7 +109,11 @@ Fwt f(LOCALE_fr_FR_UTF_8, 1); assert(f.thousands_sep() == L' '); } - +// The below tests fail due to GLIBC's use of U00A0 as mon_thousands_sep +// and U002E as mon_decimal_point. +// TODO: Fix thousands_sep for 'char'. +// related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006 +#ifndef TEST_HAS_GLIBC { Fnf f(LOCALE_ru_RU_UTF_8, 1); assert(f.thousands_sep() == ' '); @@ -123,13 +122,17 @@ Fnt f(LOCALE_ru_RU_UTF_8, 1); assert(f.thousands_sep() == ' '); } + const wchar_t sep = L' '; +#else + const wchar_t sep = L'\u00A0'; +#endif { Fwf f(LOCALE_ru_RU_UTF_8, 1); - assert(f.thousands_sep() == L' '); + assert(f.thousands_sep() == sep); } { Fwt f(LOCALE_ru_RU_UTF_8, 1); - assert(f.thousands_sep() == L' '); + assert(f.thousands_sep() == sep); } {