Get rid of wchar_t for good

This commit is contained in:
Přemysl Eric Janouch 2014-10-16 01:50:20 +02:00
parent b8dc6bb3cc
commit da3a4842f1
3 changed files with 53 additions and 63 deletions

View File

@ -44,8 +44,6 @@ include_directories (${ZLIB_INCLUDE_DIRS}
# Configuration # Configuration
include (CheckFunctionExists) include (CheckFunctionExists)
CHECK_FUNCTION_EXISTS ("wcwidth" HAVE_WCWIDTH)
set (CMAKE_REQUIRED_LIBRARIES ${dependencies_LIBRARIES}) set (CMAKE_REQUIRED_LIBRARIES ${dependencies_LIBRARIES})
CHECK_FUNCTION_EXISTS ("resize_term" HAVE_RESIZE_TERM) CHECK_FUNCTION_EXISTS ("resize_term" HAVE_RESIZE_TERM)

View File

@ -8,7 +8,6 @@
#define GETTEXT_PACKAGE PROJECT_NAME #define GETTEXT_PACKAGE PROJECT_NAME
#define GETTEXT_DIRNAME "${CMAKE_INSTALL_PREFIX}/share/locale" #define GETTEXT_DIRNAME "${CMAKE_INSTALL_PREFIX}/share/locale"
#cmakedefine HAVE_WCWIDTH
#cmakedefine HAVE_RESIZE_TERM #cmakedefine HAVE_RESIZE_TERM
#endif /* ! CONFIG_H */ #endif /* ! CONFIG_H */

View File

@ -1,7 +1,7 @@
/* /*
* StarDict terminal UI * StarDict terminal UI
* *
* Copyright (c) 2013, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2013 - 2014, Přemysl Janouch <p.janouch@gmail.com>
* All rights reserved. * All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -18,9 +18,6 @@
* *
*/ */
#define _XOPEN_SOURCE 500 //!< wcwidth
#define _XOPEN_SOURCE_EXTENDED //!< Yes, we want ncursesw.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <locale.h> #include <locale.h>
@ -57,17 +54,6 @@ unichar_width (gunichar ch)
return 1 + g_unichar_iswide (ch); return 1 + g_unichar_iswide (ch);
} }
#ifndef HAVE_WCWIDTH
#define wcwidth(x) 1
#endif // ! HAVE_WCWIDTH
static gboolean
is_character_in_locale (wchar_t c)
{
wchar_t s[] = { c, 0 };
return wcstombs (NULL, s, 0) != (size_t) -1;
}
// --- Application ------------------------------------------------------------- // --- Application -------------------------------------------------------------
/** Data relating to one entry within the dictionary. */ /** Data relating to one entry within the dictionary. */
@ -87,7 +73,7 @@ struct application
GMainLoop * loop; //!< Main loop GMainLoop * loop; //!< Main loop
termo_t * tk; //!< termo handle termo_t * tk; //!< termo handle
guint tk_timeout; //!< termo timeout guint tk_timeout; //!< termo timeout
GIConv utf8_to_wchar; //!< utf-8 -> wchar_t conversion GIConv ucs4_to_locale; //!< UTF-32 -> locale conversion
StardictDict * dict; //!< The current dictionary StardictDict * dict; //!< The current dictionary
guint show_help : 1; //!< Whether help can be shown guint show_help : 1; //!< Whether help can be shown
@ -235,7 +221,9 @@ app_init (Application *self, const gchar *filename)
self->division = 0.5; self->division = 0.5;
self->utf8_to_wchar = g_iconv_open ("wchar_t//translit", "utf-8"); const char *charset;
(void) g_get_charset (&charset);
self->ucs4_to_locale = g_iconv_open (charset, "UTF-32");
app_reload_view (self); app_reload_view (self);
} }
@ -255,36 +243,44 @@ app_destroy (Application *self)
g_free (self->search_label); g_free (self->search_label);
g_array_free (self->input, TRUE); g_array_free (self->input, TRUE);
g_iconv_close (self->utf8_to_wchar); g_iconv_close (self->ucs4_to_locale);
} }
/** Write the given utf-8 string padded with spaces. /** Returns if the Unicode character is representable in the current locale. */
static gboolean
app_is_character_in_locale (Application *self, gunichar ch)
{
gchar *tmp = g_convert_with_iconv ((const gchar *) &ch, sizeof ch,
self->ucs4_to_locale, NULL, NULL, NULL);
if (!tmp)
return FALSE;
g_free (tmp);
return TRUE;
}
/** Write the given UTF-8 string padded with spaces.
* @param[in] n The number of characters to write, or -1 for the whole string. * @param[in] n The number of characters to write, or -1 for the whole string.
* @param[in] attrs Text attributes for the text, without padding. * @param[in] attrs Text attributes for the text, without padding.
* To change the attributes of all output, use attrset(). * To change the attributes of all output, use attrset().
* @return The number of wide characters written. * @return The number of characters output.
*/ */
static gsize static gsize
app_add_utf8_string (Application *self, const gchar *str, int attrs, int n) app_add_utf8_string (Application *self, const gchar *str, int attrs, int n)
{ {
wchar_t *wide_str = (wchar_t *) g_convert_with_iconv
(str, -1, self->utf8_to_wchar, NULL, NULL, NULL);
g_return_val_if_fail (wide_str != NULL, 0);
ssize_t wide_len = wcslen (wide_str);
wchar_t padding = L' ', error = L'?', ellipsis = L'';
if (!n) if (!n)
return 0; return 0;
// Compute how many wide characters fit in the limit glong ucs4_len;
gint cols, i; gunichar *ucs4 = g_utf8_to_ucs4_fast (str, -1, &ucs4_len);
for (cols = i = 0; i < wide_len; i++)
{
if (!is_character_in_locale (wide_str[i]))
wide_str[i] = error;
gint width = wcwidth (wide_str[i]); // Replace invalid chars and compute how many characters fit in the limit
gint cols, i;
for (cols = i = 0; i < ucs4_len; i++)
{
if (!app_is_character_in_locale (self, ucs4[i]))
ucs4[i] = '?';
gint width = unichar_width (ucs4[i]);
if (n >= 0 && cols + width > n) if (n >= 0 && cols + width > n)
break; break;
cols += width; cols += width;
@ -294,49 +290,46 @@ app_add_utf8_string (Application *self, const gchar *str, int attrs, int n)
n = cols; n = cols;
// Append ellipsis if the whole string didn't fit // Append ellipsis if the whole string didn't fit
gunichar ellipsis = L'';
gint ellipsis_width = unichar_width (ellipsis);
gint len = i; gint len = i;
if (len != wide_len) if (len != ucs4_len)
{ {
if (is_character_in_locale (ellipsis)) if (app_is_character_in_locale (self, ellipsis))
{ {
if (cols + wcwidth (ellipsis) > n) if (cols + ellipsis_width > n)
cols -= wcwidth (wide_str[len - 1]); cols -= unichar_width (ucs4[len - 1]);
else else
len++; len++;
wide_str[len - 1] = ellipsis; ucs4[len - 1] = ellipsis;
cols += wcwidth (ellipsis); cols += ellipsis_width;
} }
else if (n >= 3 && len >= 3) else if (n >= 3 && len >= 3)
{ {
// With zero-width characters this overflows // With zero-width characters this overflows
// It's just a fallback anyway // It's just a fallback anyway
cols -= wcwidth (wide_str[len - 1]); cols -= unichar_width (ucs4[len - 1]); ucs4[len - 1] = '.';
cols -= wcwidth (wide_str[len - 2]); cols -= unichar_width (ucs4[len - 2]); ucs4[len - 2] = '.';
cols -= wcwidth (wide_str[len - 3]); cols -= unichar_width (ucs4[len - 3]); ucs4[len - 3] = '.';
cols += 3; cols += 3;
wide_str[len - 1] = L'.';
wide_str[len - 2] = L'.';
wide_str[len - 3] = L'.';
} }
} }
cchar_t cch; guchar *locale_str;
for (i = 0; i < len; i++) gsize locale_str_len;
{ locale_str = (guchar *) g_convert_with_iconv ((const gchar *) ucs4,
if (setcchar (&cch, &wide_str[i], attrs, 0, NULL) == OK) len * sizeof *ucs4, self->ucs4_to_locale, NULL, &locale_str_len, NULL);
add_wch (&cch); g_return_val_if_fail (locale_str != NULL, 0);
else
// This shouldn't happen
cols -= wcwidth (wide_str[i]);
}
setcchar (&cch, &padding, A_NORMAL, 0, NULL); for (gsize i = 0; i < locale_str_len; i++)
addch (locale_str[i] | attrs);
while (cols++ < n) while (cols++ < n)
add_wch (&cch); addch (' ');
g_free (wide_str); g_free (locale_str);
g_free (ucs4);
return n; return n;
} }
@ -454,7 +447,7 @@ app_redraw_view (Application *self)
guint left_width = app_get_left_column_width (self); guint left_width = app_get_left_column_width (self);
app_add_utf8_string (self, ve->word, 0, left_width); app_add_utf8_string (self, ve->word, 0, left_width);
addwstr (L" "); addstr (" ");
app_add_utf8_string (self, app_add_utf8_string (self,
ve->definitions[k], 0, COLS - left_width - 1); ve->definitions[k], 0, COLS - left_width - 1);