|
|
498c49 |
From e2b89cbdcba7475047ca3c46fc7d03825355b3ff Mon Sep 17 00:00:00 2001
|
|
|
498c49 |
From: Daiki Ueno <ueno@unixuser.org>
|
|
|
498c49 |
Date: Wed, 10 Aug 2011 12:50:43 +0900
|
|
|
498c49 |
Subject: [PATCH] Add wide-char support to pinentry-curses.
|
|
|
498c49 |
|
|
|
498c49 |
---
|
|
|
498c49 |
configure.ac | 2 +-
|
|
|
498c49 |
m4/curses.m4 | 20 +++++-
|
|
|
498c49 |
pinentry/pinentry-curses.c | 150 +++++++++++++++++++++++++++++++++++++--------
|
|
|
498c49 |
3 files changed, 143 insertions(+), 29 deletions(-)
|
|
|
498c49 |
|
|
|
498c49 |
diff --git a/configure.ac b/configure.ac
|
|
|
498c49 |
index 4b8ed79..bcbe26e 100644
|
|
|
498c49 |
--- a/configure.ac
|
|
|
498c49 |
+++ b/configure.ac
|
|
|
498c49 |
@@ -158,7 +158,7 @@ fi
|
|
|
498c49 |
|
|
|
498c49 |
# Checks for header files.
|
|
|
498c49 |
AC_HEADER_STDC
|
|
|
498c49 |
-AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h utime.h)
|
|
|
498c49 |
+AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h utime.h wchar.h)
|
|
|
498c49 |
|
|
|
498c49 |
dnl Checks for library functions.
|
|
|
498c49 |
AC_CHECK_FUNCS(seteuid stpcpy mmap)
|
|
|
498c49 |
diff --git a/m4/curses.m4 b/m4/curses.m4
|
|
|
498c49 |
index 1e1cb4f..3a01881 100644
|
|
|
498c49 |
--- a/m4/curses.m4
|
|
|
498c49 |
+++ b/m4/curses.m4
|
|
|
498c49 |
@@ -28,7 +28,13 @@ AC_DEFUN([IU_LIB_NCURSES], [
|
|
|
498c49 |
AC_ARG_ENABLE(ncurses, [ --disable-ncurses don't prefer -lncurses over -lcurses],
|
|
|
498c49 |
, enable_ncurses=yes)
|
|
|
498c49 |
if test "$enable_ncurses" = yes; then
|
|
|
498c49 |
- AC_CHECK_LIB(ncurses, initscr, LIBNCURSES="-lncurses")
|
|
|
498c49 |
+ AC_CHECK_LIB(ncursesw, initscr, LIBNCURSES="-lncursesw",
|
|
|
498c49 |
+ AC_CHECK_LIB(ncurses, initscr, LIBNCURSES="-lncurses"))
|
|
|
498c49 |
+ if test "$ac_cv_lib_ncursesw_initscr" = yes; then
|
|
|
498c49 |
+ have_ncursesw=yes
|
|
|
498c49 |
+ else
|
|
|
498c49 |
+ have_ncursesw=no
|
|
|
498c49 |
+ fi
|
|
|
498c49 |
if test "$LIBNCURSES"; then
|
|
|
498c49 |
# Use ncurses header files instead of the ordinary ones, if possible;
|
|
|
498c49 |
# is there a better way of doing this, that avoids looking in specific
|
|
|
498c49 |
@@ -53,9 +59,14 @@ AC_DEFUN([IU_LIB_NCURSES], [
|
|
|
498c49 |
else
|
|
|
498c49 |
AC_CACHE_CHECK(for ncurses include dir,
|
|
|
498c49 |
inetutils_cv_includedir_ncurses,
|
|
|
498c49 |
+ if test "$have_ncursesw" = yes; then
|
|
|
498c49 |
+ ncursesdir=ncursesw
|
|
|
498c49 |
+ else
|
|
|
498c49 |
+ ncursesdir=ncurses
|
|
|
498c49 |
+ fi
|
|
|
498c49 |
for D in $includedir $prefix/include /local/include /usr/local/include /include /usr/include; do
|
|
|
498c49 |
- if test -d $D/ncurses; then
|
|
|
498c49 |
- inetutils_cv_includedir_ncurses="$D/ncurses"
|
|
|
498c49 |
+ if test -d $D/$ncursesdir; then
|
|
|
498c49 |
+ inetutils_cv_includedir_ncurses="$D/$ncursesdir"
|
|
|
498c49 |
break
|
|
|
498c49 |
fi
|
|
|
498c49 |
test "$inetutils_cv_includedir_ncurses" \
|
|
|
498c49 |
@@ -68,6 +79,9 @@ AC_DEFUN([IU_LIB_NCURSES], [
|
|
|
498c49 |
NCURSES_INCLUDE="-I$inetutils_cv_includedir_ncurses"
|
|
|
498c49 |
fi
|
|
|
498c49 |
fi
|
|
|
498c49 |
+ if test $have_ncursesw = yes; then
|
|
|
498c49 |
+ AC_DEFINE(HAVE_NCURSESW, 1, [Define if you have working ncursesw])
|
|
|
498c49 |
+ fi
|
|
|
498c49 |
fi
|
|
|
498c49 |
AC_SUBST(NCURSES_INCLUDE)
|
|
|
498c49 |
AC_SUBST(LIBNCURSES)])dnl
|
|
|
498c49 |
diff --git a/pinentry/pinentry-curses.c b/pinentry/pinentry-curses.c
|
|
|
498c49 |
index 76ddbdd..585059f 100644
|
|
|
498c49 |
--- a/pinentry/pinentry-curses.c
|
|
|
498c49 |
+++ b/pinentry/pinentry-curses.c
|
|
|
498c49 |
@@ -42,6 +42,10 @@
|
|
|
498c49 |
|
|
|
498c49 |
#include <memory.h>
|
|
|
498c49 |
|
|
|
498c49 |
+#ifdef HAVE_WCHAR_H
|
|
|
498c49 |
+#include <wchar.h>
|
|
|
498c49 |
+#endif /*HAVE_WCHAR_H*/
|
|
|
498c49 |
+
|
|
|
498c49 |
#include "pinentry.h"
|
|
|
498c49 |
|
|
|
498c49 |
/* FIXME: We should allow configuration of these button labels and in
|
|
|
498c49 |
@@ -94,6 +98,24 @@ struct dialog
|
|
|
498c49 |
typedef struct dialog *dialog_t;
|
|
|
498c49 |
|
|
|
498c49 |
|
|
|
498c49 |
+#ifdef HAVE_NCURSESW
|
|
|
498c49 |
+typedef wchar_t CH;
|
|
|
498c49 |
+#define STRLEN(x) wcslen (x)
|
|
|
498c49 |
+#define ADDCH(x) addnwstr (&x, 1);
|
|
|
498c49 |
+#define CHWIDTH(x) wcwidth (x)
|
|
|
498c49 |
+#define NULLCH L'\0'
|
|
|
498c49 |
+#define NLCH L'\n'
|
|
|
498c49 |
+#define SPCH L' '
|
|
|
498c49 |
+#else
|
|
|
498c49 |
+typedef char CH;
|
|
|
498c49 |
+#define STRLEN(x) strlen (x)
|
|
|
498c49 |
+#define ADDCH(x) addch ((unsigned char) x)
|
|
|
498c49 |
+#define CHWIDTH(x) 1
|
|
|
498c49 |
+#define NULLCH '\0'
|
|
|
498c49 |
+#define NLCH '\n'
|
|
|
498c49 |
+#define SPCH ' '
|
|
|
498c49 |
+#endif
|
|
|
498c49 |
+
|
|
|
498c49 |
/* Return the next line up to MAXLEN columns wide in START and LEN.
|
|
|
498c49 |
The first invocation should have 0 as *LEN. If the line ends with
|
|
|
498c49 |
a \n, it is a normal line that will be continued. If it is a '\0'
|
|
|
498c49 |
@@ -101,40 +123,95 @@ typedef struct dialog *dialog_t;
|
|
|
498c49 |
there is a forced line break. A full line is returned and will be
|
|
|
498c49 |
continued in the next line. */
|
|
|
498c49 |
static void
|
|
|
498c49 |
-collect_line (int maxlen, char **start_p, int *len_p)
|
|
|
498c49 |
+collect_line (int maxwidth, wchar_t **start_p, int *len_p)
|
|
|
498c49 |
{
|
|
|
498c49 |
int last_space = 0;
|
|
|
498c49 |
int len = *len_p;
|
|
|
498c49 |
- char *end;
|
|
|
498c49 |
+ int width = 0;
|
|
|
498c49 |
+ CH *end;
|
|
|
498c49 |
|
|
|
498c49 |
/* Skip to next line. */
|
|
|
498c49 |
*start_p += len;
|
|
|
498c49 |
/* Skip leading space. */
|
|
|
498c49 |
- while (**start_p == ' ')
|
|
|
498c49 |
+ while (**start_p == SPCH)
|
|
|
498c49 |
(*start_p)++;
|
|
|
498c49 |
|
|
|
498c49 |
end = *start_p;
|
|
|
498c49 |
len = 0;
|
|
|
498c49 |
|
|
|
498c49 |
- while (len < maxlen - 1 && *end && *end != '\n')
|
|
|
498c49 |
+ while (width < maxwidth - 1 && *end != NULLCH && *end != NLCH)
|
|
|
498c49 |
{
|
|
|
498c49 |
len++;
|
|
|
498c49 |
end++;
|
|
|
498c49 |
- if (*end == ' ')
|
|
|
498c49 |
+ if (*end == SPCH)
|
|
|
498c49 |
last_space = len;
|
|
|
498c49 |
+ width += CHWIDTH (*end);
|
|
|
498c49 |
}
|
|
|
498c49 |
|
|
|
498c49 |
- if (*end && *end != '\n' && last_space != 0)
|
|
|
498c49 |
+ if (*end != NULLCH && *end != NLCH && last_space != 0)
|
|
|
498c49 |
{
|
|
|
498c49 |
/* We reached the end of the available space, but still have
|
|
|
498c49 |
characters to go in this line. We can break the line into
|
|
|
498c49 |
two parts at a space. */
|
|
|
498c49 |
len = last_space;
|
|
|
498c49 |
- (*start_p)[len] = '\n';
|
|
|
498c49 |
+ (*start_p)[len] = NLCH;
|
|
|
498c49 |
}
|
|
|
498c49 |
*len_p = len + 1;
|
|
|
498c49 |
}
|
|
|
498c49 |
|
|
|
498c49 |
+#ifdef HAVE_NCURSESW
|
|
|
498c49 |
+static CH *
|
|
|
498c49 |
+utf8_to_local (char *lc_ctype, char *string)
|
|
|
498c49 |
+{
|
|
|
498c49 |
+ mbstate_t ps;
|
|
|
498c49 |
+ size_t len;
|
|
|
498c49 |
+ char *local;
|
|
|
498c49 |
+ const char *p;
|
|
|
498c49 |
+ wchar_t *wcs = NULL;
|
|
|
498c49 |
+ char *old_ctype = NULL;
|
|
|
498c49 |
+
|
|
|
498c49 |
+ local = pinentry_utf8_to_local (lc_ctype, string);
|
|
|
498c49 |
+ if (!local)
|
|
|
498c49 |
+ return NULL;
|
|
|
498c49 |
+
|
|
|
498c49 |
+ old_ctype = strdup (setlocale (LC_CTYPE, NULL));
|
|
|
498c49 |
+ setlocale (LC_CTYPE, lc_ctype? lc_ctype : "");
|
|
|
498c49 |
+
|
|
|
498c49 |
+ p = local;
|
|
|
498c49 |
+ memset (&ps, 0, sizeof(mbstate_t));
|
|
|
498c49 |
+ len = mbsrtowcs (NULL, &p, strlen (string), &ps);
|
|
|
498c49 |
+ if (len == (size_t)-1)
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ free (local);
|
|
|
498c49 |
+ goto leave;
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+ wcs = calloc (len + 1, sizeof(wchar_t));
|
|
|
498c49 |
+ if (!wcs)
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ free (local);
|
|
|
498c49 |
+ goto leave;
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+
|
|
|
498c49 |
+ p = local;
|
|
|
498c49 |
+ memset (&ps, 0, sizeof(mbstate_t));
|
|
|
498c49 |
+ mbsrtowcs (wcs, &p, len, &ps);
|
|
|
498c49 |
+
|
|
|
498c49 |
+ leave:
|
|
|
498c49 |
+ if (old_ctype)
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ setlocale (LC_CTYPE, old_ctype);
|
|
|
498c49 |
+ free (old_ctype);
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+
|
|
|
498c49 |
+ return wcs;
|
|
|
498c49 |
+}
|
|
|
498c49 |
+#else
|
|
|
498c49 |
+static CH *
|
|
|
498c49 |
+utf8_to_local (const char *lc_ctype, const char *string)
|
|
|
498c49 |
+{
|
|
|
498c49 |
+ return pinentry_utf8_to_local (lc_ctype, string);
|
|
|
498c49 |
+}
|
|
|
498c49 |
+#endif
|
|
|
498c49 |
|
|
|
498c49 |
static int
|
|
|
498c49 |
dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
@@ -148,16 +225,15 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
int xpos;
|
|
|
498c49 |
int description_x = 0;
|
|
|
498c49 |
int error_x = 0;
|
|
|
498c49 |
- char *description = NULL;
|
|
|
498c49 |
- char *error = NULL;
|
|
|
498c49 |
- char *prompt = NULL;
|
|
|
498c49 |
+ CH *description = NULL;
|
|
|
498c49 |
+ CH *error = NULL;
|
|
|
498c49 |
+ CH *prompt = NULL;
|
|
|
498c49 |
|
|
|
498c49 |
#define COPY_OUT(what) \
|
|
|
498c49 |
do \
|
|
|
498c49 |
if (pinentry->what) \
|
|
|
498c49 |
{ \
|
|
|
498c49 |
- what = pinentry_utf8_to_local (pinentry->lc_ctype, \
|
|
|
498c49 |
- pinentry->what); \
|
|
|
498c49 |
+ what = utf8_to_local (pinentry->lc_ctype, pinentry->what); \
|
|
|
498c49 |
if (!what) \
|
|
|
498c49 |
{ \
|
|
|
498c49 |
err = 1; \
|
|
|
498c49 |
@@ -214,7 +290,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
y = 1; /* Top frame. */
|
|
|
498c49 |
if (description)
|
|
|
498c49 |
{
|
|
|
498c49 |
- char *start = description;
|
|
|
498c49 |
+ CH *start = description;
|
|
|
498c49 |
int len = 0;
|
|
|
498c49 |
|
|
|
498c49 |
do
|
|
|
498c49 |
@@ -232,7 +308,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
{
|
|
|
498c49 |
if (error)
|
|
|
498c49 |
{
|
|
|
498c49 |
- char *p = error;
|
|
|
498c49 |
+ CH *p = error;
|
|
|
498c49 |
int err_x = 0;
|
|
|
498c49 |
|
|
|
498c49 |
while (*p)
|
|
|
498c49 |
@@ -287,7 +363,9 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
|
|
|
498c49 |
new_x = MIN_PINENTRY_LENGTH;
|
|
|
498c49 |
if (prompt)
|
|
|
498c49 |
- new_x += strlen (prompt) + 1; /* One space after prompt. */
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ new_x += STRLEN (prompt) + 1; /* One space after prompt. */
|
|
|
498c49 |
+ }
|
|
|
498c49 |
if (new_x > size_x - 4)
|
|
|
498c49 |
new_x = size_x - 4;
|
|
|
498c49 |
if (new_x > x)
|
|
|
498c49 |
@@ -335,7 +413,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
ypos++;
|
|
|
498c49 |
if (description)
|
|
|
498c49 |
{
|
|
|
498c49 |
- char *start = description;
|
|
|
498c49 |
+ CH *start = description;
|
|
|
498c49 |
int len = 0;
|
|
|
498c49 |
|
|
|
498c49 |
do
|
|
|
498c49 |
@@ -347,9 +425,11 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
addch (' ');
|
|
|
498c49 |
collect_line (size_x - 4, &start, &len;;
|
|
|
498c49 |
for (i = 0; i < len - 1; i++)
|
|
|
498c49 |
- addch ((unsigned char) start[i]);
|
|
|
498c49 |
- if (start[len - 1] && start[len - 1] != '\n')
|
|
|
498c49 |
- addch ((unsigned char) start[len - 1]);
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ ADDCH (start[i]);
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+ if (start[len - 1] != NULLCH && start[len - 1] != NLCH)
|
|
|
498c49 |
+ ADDCH (start[len - 1]);
|
|
|
498c49 |
ypos++;
|
|
|
498c49 |
}
|
|
|
498c49 |
while (start[len - 1]);
|
|
|
498c49 |
@@ -363,7 +443,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
|
|
|
498c49 |
if (error)
|
|
|
498c49 |
{
|
|
|
498c49 |
- char *p = error;
|
|
|
498c49 |
+ CH *p = error;
|
|
|
498c49 |
i = 0;
|
|
|
498c49 |
|
|
|
498c49 |
while (*p)
|
|
|
498c49 |
@@ -378,11 +458,11 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
}
|
|
|
498c49 |
else
|
|
|
498c49 |
standout ();
|
|
|
498c49 |
- for (;*p && *p != '\n'; p++)
|
|
|
498c49 |
+ for (;*p && *p != NLCH; p++)
|
|
|
498c49 |
if (i < x - 4)
|
|
|
498c49 |
{
|
|
|
498c49 |
i++;
|
|
|
498c49 |
- addch ((unsigned char) *p);
|
|
|
498c49 |
+ ADDCH (*p);
|
|
|
498c49 |
}
|
|
|
498c49 |
if (USE_COLORS && pinentry->color_so != PINENTRY_COLOR_NONE)
|
|
|
498c49 |
{
|
|
|
498c49 |
@@ -410,14 +490,16 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
|
|
|
498c49 |
dialog->pin_size = x - 4;
|
|
|
498c49 |
if (prompt)
|
|
|
498c49 |
{
|
|
|
498c49 |
- char *p = prompt;
|
|
|
498c49 |
- i = strlen (prompt);
|
|
|
498c49 |
+ CH *p = prompt;
|
|
|
498c49 |
+ i = STRLEN (prompt);
|
|
|
498c49 |
if (i > x - 4 - MIN_PINENTRY_LENGTH)
|
|
|
498c49 |
i = x - 4 - MIN_PINENTRY_LENGTH;
|
|
|
498c49 |
dialog->pin_x += i + 1;
|
|
|
498c49 |
dialog->pin_size -= i + 1;
|
|
|
498c49 |
while (i-- > 0)
|
|
|
498c49 |
- addch ((unsigned char) *(p++));
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ ADDCH (*(p++));
|
|
|
498c49 |
+ }
|
|
|
498c49 |
addch (' ');
|
|
|
498c49 |
}
|
|
|
498c49 |
for (i = 0; i < dialog->pin_size; i++)
|
|
|
498c49 |
@@ -631,6 +713,17 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
|
|
|
498c49 |
SCREEN *screen = 0;
|
|
|
498c49 |
int done = 0;
|
|
|
498c49 |
char *pin_utf8;
|
|
|
498c49 |
+#ifdef HAVE_NCURSESW
|
|
|
498c49 |
+ char *old_ctype = NULL;
|
|
|
498c49 |
+
|
|
|
498c49 |
+ if (pinentry->lc_ctype)
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ old_ctype = strdup (setlocale (LC_CTYPE, NULL));
|
|
|
498c49 |
+ setlocale (LC_CTYPE, pinentry->lc_ctype);
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+ else
|
|
|
498c49 |
+ setlocale (LC_CTYPE, "");
|
|
|
498c49 |
+#endif
|
|
|
498c49 |
|
|
|
498c49 |
/* Open the desired terminal if necessary. */
|
|
|
498c49 |
if (tty_name)
|
|
|
498c49 |
@@ -804,6 +897,13 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
|
|
|
498c49 |
if (screen)
|
|
|
498c49 |
delscreen (screen);
|
|
|
498c49 |
|
|
|
498c49 |
+#ifdef HAVE_NCURSESW
|
|
|
498c49 |
+ if (old_ctype)
|
|
|
498c49 |
+ {
|
|
|
498c49 |
+ setlocale (LC_CTYPE, old_ctype);
|
|
|
498c49 |
+ free (old_ctype);
|
|
|
498c49 |
+ }
|
|
|
498c49 |
+#endif
|
|
|
498c49 |
if (ttyfi)
|
|
|
498c49 |
fclose (ttyfi);
|
|
|
498c49 |
if (ttyfo)
|
|
|
498c49 |
--
|
|
|
498c49 |
1.8.3.1
|
|
|
498c49 |
|