From 5f94ca33cf7772e0c36b5b3e5b1cf1ab01f60180 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 May 2010 14:12:26 +0200 Subject: [PATCH] cfdisk: support non-ascii characters in input MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit On Sat, Apr 03, 2010 at 12:58:48PM +0000, Jorge wrote: > When you want to write changes to disk you're asked for a > confirmation, like this one: > > Are you sure you want to write the partition table to disk? (yes > or no) > > There is no problem on the English version, but when you launch the > program in Spanish you get this: > > ¿Está seguro de que desea escribir la tabla de particiones en el > disco? > (sí o no): > > You can't type the "í" character. Trying to do so will end in no > input at all. That is, typing in my keyboard "´" then "i" leads to > nothing. So you can't write changes to disk, and you must launch the > program in English for it to operate. Reported-by: Jorge Addresses: https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/205327 Signed-off-by: Karel Zak --- fdisk/Makefile.am | 2 +- fdisk/cfdisk.c | 55 +++++++++++++++++++++++++++++++++++++++------- include/mbsalign.h | 8 ++++--- lib/mbsalign.c | 34 ++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 12 deletions(-) diff --git a/fdisk/Makefile.am b/fdisk/Makefile.am index 862fa016..7b87d6cf 100644 --- a/fdisk/Makefile.am +++ b/fdisk/Makefile.am @@ -53,7 +53,7 @@ endif if USE_SLANG sbin_PROGRAMS += cfdisk dist_man_MANS += cfdisk.8 -cfdisk_SOURCES = cfdisk.c $(fdisk_common) +cfdisk_SOURCES = cfdisk.c $(fdisk_common) ../lib/mbsalign.c cfdisk_CFLAGS = $(cflags_blkid) cfdisk_LDADD = -lslang $(ldadd_blkid) else diff --git a/fdisk/cfdisk.c b/fdisk/cfdisk.c index 8de285b4..b1eaceeb 100644 --- a/fdisk/cfdisk.c +++ b/fdisk/cfdisk.c @@ -83,11 +83,16 @@ #include #endif +#ifdef HAVE_WIDECHAR +#include +#endif + #include "nls.h" #include "blkdev.h" #include "xstrncpy.h" #include "common.h" #include "gpt.h" +#include "mbsalign.h" #ifdef __GNU__ #define DEFAULT_DEVICE "/dev/hd0" @@ -407,10 +412,10 @@ fdexit(int ret) { static int get_string(char *str, int len, char *def) { - unsigned char c; - int i = 0; - int x, y; + size_t cells = 0, i = 0; + int x, y, key; int use_def = FALSE; + wint_t c; getyx(stdscr, y, x); clrtoeol(); @@ -424,7 +429,13 @@ get_string(char *str, int len, char *def) { } refresh(); + +#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR) + while ((key = get_wch(&c)) != ERR && + c != '\r' && c != '\n' && c != KEY_ENTER) { +#else while ((c = getch()) != '\n' && c != CR) { +#endif switch (c) { case ESC: move(y, x); @@ -433,10 +444,14 @@ get_string(char *str, int len, char *def) { return GS_ESCAPE; case DEL: case '\b': + case KEY_BACKSPACE: if (i > 0) { - str[--i] = 0; - mvaddch(y, x+i, ' '); - move(y, x+i); + cells--; + i = mbs_truncate(str, &cells); + if (i < 0) + return GS_ESCAPE; + mvaddch(y, x + cells, ' '); + move(y, x + cells); } else if (use_def) { clrtoeol(); use_def = FALSE; @@ -444,15 +459,39 @@ get_string(char *str, int len, char *def) { putchar(BELL); break; default: +#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR) + if (i < len && iswprint(c)) { + wchar_t wc = (wchar_t) c; + char s[MB_CUR_MAX + 1]; + int sz = wctomb(s, wc); + + if (sz + i < len) { + s[sz] = '\0'; + mvaddnstr(y, x + cells, s, sz); + if (use_def) { + clrtoeol(); + use_def = FALSE; + } + memcpy(str + i, s, sz); + i += sz; + str[i] = '\0'; + cells += wcwidth(wc); + } else + putchar(BELL); + } +#else if (i < len && isprint(c)) { - mvaddch(y, x+i, c); + mvaddch(y, x + cells, c); if (use_def) { clrtoeol(); use_def = FALSE; } str[i++] = c; str[i] = 0; - } else + cells++; + } +#endif + else putchar(BELL); } refresh(); diff --git a/include/mbsalign.h b/include/mbsalign.h index b8a588c2..fd957b39 100644 --- a/include/mbsalign.h +++ b/include/mbsalign.h @@ -38,6 +38,8 @@ enum { #endif }; -size_t -mbsalign (const char *src, char *dest, size_t dest_size, - size_t *width, mbs_align_t align, int flags); +extern size_t mbs_truncate(char *str, size_t *width); + +extern size_t mbsalign (const char *src, char *dest, + size_t dest_size, size_t *width, + mbs_align_t align, int flags); diff --git a/lib/mbsalign.c b/lib/mbsalign.c index c1a5472e..82ffc09c 100644 --- a/lib/mbsalign.c +++ b/lib/mbsalign.c @@ -99,6 +99,40 @@ rpl_wcswidth (const wchar_t *s, size_t n) } #endif +/* Truncate multi-byte string to @width and returns number of + * bytes of the new string @str, and in @width returns number + * of cells. + */ +size_t +mbs_truncate(char *str, size_t *width) +{ + size_t bytes = strlen(str); +#ifdef HAVE_WIDECHAR + size_t sz = mbstowcs(NULL, str, 0); + wchar_t *wcs = NULL; + + if (sz == (size_t) -1) + goto done; + + wcs = malloc((sz + 1) * sizeof(wchar_t)); + if (!wcs) + goto done; + + if (!mbstowcs(wcs, str, sz)) + goto done; + *width = wc_truncate(wcs, *width); + bytes = wcstombs(str, wcs, bytes); +done: + free(wcs); +#else + if (*width < bytes) + bytes = *width; +#endif + if (bytes >= 0) + str[bytes] = '\0'; + return bytes; +} + /* Write N_SPACES space characters to DEST while ensuring nothing is written beyond DEST_END. A terminating NUL is always added to DEST. -- 2.39.5