]> err.no Git - util-linux/commitdiff
cfdisk: support non-ascii characters in input
authorKarel Zak <kzak@redhat.com>
Fri, 7 May 2010 12:12:26 +0000 (14:12 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 7 May 2010 12:12:26 +0000 (14:12 +0200)
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 <yo@jorgesuarezdelis.name>
Addresses: https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/205327
Signed-off-by: Karel Zak <kzak@redhat.com>
fdisk/Makefile.am
fdisk/cfdisk.c
include/mbsalign.h
lib/mbsalign.c

index 862fa01620ef25ca6b3971a4cf918c91e751f90b..7b87d6cf57605e038a7d820518a8dec613bdb069 100644 (file)
@@ -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
index 8de285b4c773d675d5aa8c87f52fb8abe0a703ed..b1eaceebbdfea7f31f3915005d66b938109d3d59 100644 (file)
 #include <blkid.h>
 #endif
 
+#ifdef HAVE_WIDECHAR
+#include <wctype.h>
+#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();
index b8a588c207b5aa46e4bb9f611e4c53525608eb70..fd957b398a2a4e1eedafc626a7a03bcec0e53e56 100644 (file)
@@ -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);
index c1a5472e87f97ff11c0d2f783a1a77365b8ef702..82ffc09cd86db53fd794e39b5fbde1c97948f766 100644 (file)
@@ -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.