Code

release v0.29
[ncmpc.git] / src / charset.c
index 701fd2105bd6eb1afaf5a4e8a67cb64170c8abc3..61a34cbcf449a6dd0eb870cfc9dd239d83109cf5 100644 (file)
@@ -1,6 +1,6 @@
-/*
- * (c) 2006 by Kalle Wallin <kaw@linux.se>
- * Copyright (C) 2008 Max Kellermann <max@duempel.org>
+/* ncmpc (Ncurses MPD Client)
+ * (c) 2004-2017 The Music Player Daemon Project
+ * Project homepage: http://musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #include "charset.h"
-#include "i18n.h"
 
 #include <assert.h>
 #include <string.h>
 #include <glib.h>
 
-extern void screen_status_printf(const char *format, ...);
-
+#ifdef ENABLE_LOCALE
 static bool noconvert = true;
 static const char *charset;
 
@@ -35,12 +33,31 @@ charset_init(void)
        noconvert = g_get_charset(&charset);
        return charset;
 }
+#endif
+
+#ifdef HAVE_CURSES_ENHANCED
+static inline unsigned
+unicode_char_width(gunichar ch)
+{
+       if (g_unichar_iszerowidth(ch))
+               return 0;
+
+       if (g_unichar_iswide(ch))
+               return 2;
+
+       return 1;
+}
+#endif /* HAVE_CURSES_ENHANCED */
 
 unsigned
 utf8_width(const char *str)
 {
        assert(str != NULL);
 
+#if defined(ENABLE_MULTIBYTE) && !defined(HAVE_CURSES_ENHANCED)
+       return g_utf8_strlen(str, -1);
+#else
+#ifdef HAVE_CURSES_ENHANCED
        if (g_utf8_validate(str, -1, NULL)) {
                size_t len = g_utf8_strlen(str, -1);
                unsigned width = 0;
@@ -48,68 +65,170 @@ utf8_width(const char *str)
 
                while (len--) {
                        c = g_utf8_get_char(str);
-                       width += g_unichar_iswide(c) ? 2 : 1;
+                       width += unicode_char_width(c);
                        str += g_unichar_to_utf8(c, NULL);
                }
 
                return width;
        } else
+#endif
                return strlen(str);
+#endif
+}
+
+unsigned
+locale_width(const char *p)
+{
+#if defined(ENABLE_LOCALE) && defined(ENABLE_MULTIBYTE)
+       char *utf8;
+       unsigned width;
+
+       if (noconvert)
+               return utf8_width(p);
+
+       utf8 = locale_to_utf8(p);
+       width = utf8_width(utf8);
+       g_free(utf8);
+
+       return width;
+#else
+       return strlen(p);
+#endif
+}
+
+gcc_unused
+static unsigned
+ascii_cut_width(char *p, unsigned max_width)
+{
+       size_t length = strlen(p);
+       if (length <= (size_t)max_width)
+               return (unsigned)length;
+
+       p[max_width] = 0;
+       return max_width;
+}
+
+gcc_unused
+static unsigned
+narrow_cut_width(char *p, unsigned max_width)
+{
+       size_t length = g_utf8_strlen(p, -1);
+       if (length <= (size_t)max_width)
+               return (unsigned)length;
+
+       *g_utf8_offset_to_pointer(p, max_width) = 0;
+       return max_width;
+}
+
+gcc_unused
+static unsigned
+wide_cut_width(char *p, unsigned max_width)
+{
+       size_t length = g_utf8_strlen(p, -1);
+       unsigned width = 0, prev_width;
+
+       while (length-- > 0) {
+               gunichar c = g_utf8_get_char(p);
+               prev_width = width;
+               width += g_unichar_iswide(c) ? 2 : 1;
+               if (width > max_width) {
+                       /* too wide - cut the rest off */
+                       *p = 0;
+                       return prev_width;
+               }
+
+               p += g_unichar_to_utf8(c, NULL);
+       }
+
+       return width;
+}
+
+unsigned
+utf8_cut_width(char *p, unsigned max_width)
+{
+       assert(p != NULL);
+
+#ifdef HAVE_CURSES_ENHANCED
+       if (!g_utf8_validate(p, -1, NULL))
+               return ascii_cut_width(p, max_width);
+
+       return wide_cut_width(p, max_width);
+#elif defined(ENABLE_MULTIBYTE) && !defined(HAVE_CURSES_ENHANCED)
+       return narrow_cut_width(p, max_width);
+#else
+       return ascii_cut_width(p, max_width);
+#endif
 }
 
 char *
 utf8_to_locale(const char *utf8str)
 {
-       gchar *str;
-       gsize rb, wb;
-       GError *error;
-
+#ifdef ENABLE_LOCALE
        assert(utf8str != NULL);
 
        if (noconvert)
                return g_strdup(utf8str);
 
-       rb = 0; /* bytes read */
-       wb = 0; /* bytes written */
-       error = NULL;
-       str = g_locale_from_utf8(utf8str,
-                                strlen(utf8str),
-                                &wb, &rb,
-                                &error);
-       if (error) {
-               screen_status_printf(_("Error: Unable to convert characters to %s"),
-                                    charset);
-               g_error_free(error);
+       gchar *str = g_convert_with_fallback(utf8str, -1,
+                                            charset, "utf-8",
+                                            NULL, NULL, NULL, NULL);
+       if (str == NULL)
                return g_strdup(utf8str);
-       }
 
        return str;
+#else
+       return g_strdup(utf8str);
+#endif
 }
 
 char *
 locale_to_utf8(const char *localestr)
 {
-       gchar *str;
-       gsize rb, wb;
-       GError *error;
-
+#ifdef ENABLE_LOCALE
        assert(localestr != NULL);
 
        if (noconvert)
                return g_strdup(localestr);
 
-       rb = 0; /* bytes read */
-       wb = 0; /* bytes written */
-       error = NULL;
-       str = g_locale_to_utf8(localestr,
-                              strlen(localestr),
-                              &wb, &rb,
-                              &error);
-       if (error) {
-               screen_status_printf(_("Error: Unable to convert characters to UTF-8"));
-               g_error_free(error);
+       gchar *str = g_convert_with_fallback(localestr, -1,
+                                            "utf-8", charset,
+                                            NULL, NULL, NULL, NULL);
+       if (str == NULL)
                return g_strdup(localestr);
-       }
 
        return str;
+#else
+       return g_strdup(localestr);
+#endif
+}
+
+char *
+replace_utf8_to_locale(char *src)
+{
+#ifdef ENABLE_LOCALE
+       assert(src != NULL);
+
+       if (noconvert)
+               return src;
+
+       return utf8_to_locale(src);
+#else
+       return src;
+#endif
+}
+
+
+char *
+replace_locale_to_utf8(char *src)
+{
+#ifdef ENABLE_LOCALE
+       assert(src != NULL);
+
+       if (noconvert)
+               return src;
+
+       return locale_to_utf8(src);
+#else
+       return src;
+#endif
 }