util/LocaleString: replacement for locale_width() using wcswidth()
authorMax Kellermann <max@musicpd.org>
Wed, 12 Sep 2018 18:18:18 +0000 (20:18 +0200)
committerMax Kellermann <max@musicpd.org>
Wed, 12 Sep 2018 18:18:18 +0000 (20:18 +0200)
src/SongPage.cxx
src/charset.cxx
src/charset.hxx
src/util/LocaleString.cxx
src/util/LocaleString.hxx
src/wreadln.cxx

index 141708f..da208d3 100644 (file)
@@ -31,6 +31,7 @@
 #include "charset.hxx"
 #include "time_format.hxx"
 #include "mpdclient.hxx"
+#include "util/LocaleString.hxx"
 #include "util/Macros.hxx"
 #include "util/StringStrip.hxx"
 #include "util/StringUTF8.hxx"
@@ -180,14 +181,14 @@ static Page *
 screen_song_init(ScreenManager &_screen, WINDOW *w, Size size)
 {
        for (unsigned i = 0; tag_labels[i].label != nullptr; ++i) {
-               unsigned width = locale_width(gettext(tag_labels[i].label));
+               unsigned width = StringWidthMB(gettext(tag_labels[i].label));
                if (width > max_tag_label_width)
                        max_tag_label_width = width;
        }
 
        for (unsigned i = 0; i < ARRAY_SIZE(stats_labels); ++i) {
                if (stats_labels[i] != nullptr) {
-                       unsigned width = locale_width(gettext(stats_labels[i]));
+                       unsigned width = StringWidthMB(gettext(stats_labels[i]));
 
                        if (width > max_stats_label_width)
                                max_stats_label_width = width;
@@ -212,7 +213,7 @@ SongPage::Paint() const
 void
 SongPage::AppendLine(const char *label, const char *value, unsigned label_col)
 {
-       const unsigned label_width = locale_width(label) + 2;
+       const unsigned label_width = StringWidthMB(label) + 2;
 
        assert(label != nullptr);
        assert(value != nullptr);
index 89236aa..67a22d9 100644 (file)
@@ -37,24 +37,6 @@ charset_init()
 }
 #endif
 
-unsigned
-locale_width(const char *p)
-{
-#if defined(ENABLE_LOCALE) && defined(ENABLE_MULTIBYTE)
-       char *utf8;
-
-       if (noconvert)
-               return utf8_width(p);
-
-       utf8 = locale_to_utf8(p);
-       AtScopeExit(utf8) { g_free(utf8); };
-
-       return utf8_width(utf8);
-#else
-       return strlen(p);
-#endif
-}
-
 char *
 utf8_to_locale(const char *utf8str)
 {
index 8c9e571..9fcbd6e 100644 (file)
@@ -28,13 +28,6 @@ const char *
 charset_init();
 #endif
 
-/**
- * Returns the number of terminal cells occupied by this string.
- */
-gcc_pure
-unsigned
-locale_width(const char *p);
-
 char *utf8_to_locale(const char *str);
 char *locale_to_utf8(const char *str);
 
index 59e4c64..733b159 100644 (file)
@@ -63,3 +63,35 @@ PrevCharMB(const char *start, const char *reference)
 
        return p;
 }
+
+size_t
+StringWidthMB(const char *s, size_t length)
+{
+       const char *const end = s + length;
+       auto state = std::mbstate_t();
+
+       size_t width = 0;
+       while (s < end) {
+               wchar_t w;
+               std::size_t n = std::mbrtowc(&w, s, end - s, &state);
+               if (n == std::size_t(-2))
+                       break;
+
+               if (n == std::size_t(-1) || n == 0) {
+                       ++s;
+               } else {
+                       s += n;
+                       int cw = wcwidth(w);
+                       if (cw > 0)
+                               width += cw;
+               }
+       }
+
+       return width;
+}
+
+size_t
+StringWidthMB(const char *s)
+{
+       return StringWidthMB(s, strlen(s));
+}
index fcc8b11..7f1c010 100644 (file)
@@ -51,4 +51,15 @@ gcc_pure
 const char *
 PrevCharMB(const char *start, const char *reference);
 
+/**
+ * Returns the number of terminal cells occupied by this multi-byte
+ * string.
+ */
+gcc_pure
+size_t
+StringWidthMB(const char *s, size_t length);
+
+size_t
+StringWidthMB(const char *s);
+
 #endif
index d6d86f6..7206bc6 100644 (file)
@@ -91,8 +91,7 @@ byte_to_screen(const char *data, size_t x)
 #if defined(HAVE_CURSES_ENHANCED) || defined(ENABLE_MULTIBYTE)
        assert(x <= strlen(data));
 
-       const std::string partial(data, x);
-       return locale_width(partial.c_str());
+       return StringWidthMB(data, x);
 #else
        (void)data;
 
@@ -106,14 +105,14 @@ static size_t
 screen_to_bytes(const char *data, unsigned width)
 {
 #if defined(HAVE_CURSES_ENHANCED) || defined(ENABLE_MULTIBYTE)
-       std::string dup(data);
+       size_t length = strlen(data);
 
        while (true) {
-               unsigned p_width = locale_width(dup.c_str());
+               unsigned p_width = StringWidthMB(data, length);
                if (p_width <= width)
-                       return dup.length();
+                       return length;
 
-               dup.pop_back();
+               --length;
        }
 #else
        (void)data;
@@ -142,10 +141,8 @@ right_align_bytes(const char *data, size_t right, unsigned width)
 
        assert(right <= strlen(data));
 
-       const std::string dup(data, right);
-
        while (start < right) {
-               if (locale_width(dup.c_str() + start) < width)
+               if (StringWidthMB(data + start, right - start) < width)
                        break;
 
                start += CharSizeMB(data + start, right - start);