[PATCH] D27167: [libc++] Support multibyte decimal_point and thousands_sep

Eric van Gyzen via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 28 09:03:10 PST 2016


vangyzen created this revision.
vangyzen added a subscriber: cfe-commits.
Herald added a subscriber: emaste.
Herald added a reviewer: EricWF.

numpunct_byname<wchar_t> assumed that decimal_point and thousands_sep
were ASCII and simply copied the first byte from them.  Add support
for multibyte strings in these fields.

I found this problem on FreeBSD 11, where thousands_sep in fr_FR.UTF-8
is a no-break space (U+00A0).


https://reviews.llvm.org/D27167

Files:
  src/locale.cpp


Index: src/locale.cpp
===================================================================
--- src/locale.cpp
+++ src/locale.cpp
@@ -4281,23 +4281,51 @@
 {
 }
 
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wmissing-braces"
+#endif
+
 void
 numpunct_byname<wchar_t>::__init(const char* nm)
 {
     if (strcmp(nm, "C") != 0)
     {
         __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale);
         if (loc == nullptr)
-            __throw_runtime_error("numpunct_byname<char>::numpunct_byname"
-                                " failed to construct for " + string(nm));
+            __throw_runtime_error("numpunct_byname<wchar_t>::numpunct_byname"
+                                  " failed to construct for " + string(nm));
 
         lconv* lc = __libcpp_localeconv_l(loc.get());
-        if (*lc->decimal_point)
-            __decimal_point_ = *lc->decimal_point;
-        if (*lc->thousands_sep)
-            __thousands_sep_ = *lc->thousands_sep;
+        if (*lc->decimal_point) {
+            size_t len = strlen(lc->decimal_point);
+            mbstate_t mbs = {0};
+            wchar_t wc;
+            size_t nb = __libcpp_mbrtowc_l(&wc, lc->decimal_point, len, &mbs,
+                loc.get());
+            if (nb == len) {
+                __decimal_point_ = wc;
+            } else {
+                __throw_runtime_error("numpunct_byname<wchar_t>: decimal_point"
+                                      " is not a valid multibyte character: " +
+                                      string(lc->decimal_point));
+            }
+        }
+        if (*lc->thousands_sep) {
+            size_t len = strlen(lc->thousands_sep);
+            mbstate_t mbs = {0};
+            wchar_t wc;
+            size_t nb = __libcpp_mbrtowc_l(&wc, lc->thousands_sep, len, &mbs,
+                loc.get());
+            if (nb == len) {
+                __thousands_sep_ = wc;
+            } else {
+                __throw_runtime_error("numpunct_byname<wchar_t>: thousands_sep"
+                                      " is not a valid multibyte character: " +
+                                      string(lc->thousands_sep));
+            }
+        }
         __grouping_ = lc->grouping;
-        // locallization for truename and falsename is not available
+        // localization for truename and falsename is not available
     }
 }
 
@@ -4861,10 +4889,6 @@
     return result;
 }
 
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wmissing-braces"
-#endif
-
 template <>
 wstring
 __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D27167.79411.patch
Type: text/x-patch
Size: 2611 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20161128/b93fe9b2/attachment-0001.bin>


More information about the cfe-commits mailing list