Re: [PATCH] tty improvement for Unicode/UTF-8 mode

Bruno Haible (haible@ilog.fr)
Mon, 9 Aug 1999 23:04:22 +0200 (MET DST)


Same patch again, in unidiff format now.

For inclusion in the development kernel:

The patch below fixes the "cooked" mode editing behaviour of ttys in
Unicode/UTF-8 mode. The line editor in n_tty.c up to now assumes that
every byte >= 0x20 is a character and occupies one screen position. For
ttys in UTF-8 mode, this is not true any more. The patch fixes the two
following problems in line editing on UTF-8 ttys:

1. When the user types BackSpace, a multi-byte character has to be
erased, not only a single byte. Also, in ECHOPRT mode, the entire
multi-byte character has to be echoed to the screen, not only one
byte.

2. When the user types a Tab or backspaces over a Tab, the kernel
needs to have the proper notion of the column number of the cursor
(tty->column). For a multi-byte character, the column number increases
by 1, not by the number of bytes that make up the character.

The program which sets up the tty (xterm, rlogind, telnetd etc.) has to tell
the kernel that the tty will be in UTF-8 mode. For this purpose, a new
tty attribute is introduced, part of the "struct termio" structure.

The patch has been tested with console and xterm in UTF-8 mode, directly
and across rlogin and telnet.

Bruno

--- linux-2.3.12/include/linux/tty.h.bak Wed Jul 28 22:56:37 1999
+++ linux-2.3.12/include/linux/tty.h Sun Aug 8 15:27:01 1999
@@ -195,6 +195,7 @@
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
+#define I_IUTF8(tty) _I_FLAG((tty),IUTF8)

#define O_OPOST(tty) _O_FLAG((tty),OPOST)
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
--- linux-2.3.12/include/asm-i386/termbits.h.bak Fri Jan 8 20:11:45 1999
+++ linux-2.3.12/include/asm-i386/termbits.h Sun Aug 8 15:27:00 1999
@@ -51,6 +51,7 @@
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
+#define IUTF8 0040000

/* c_oflag bits */
#define OPOST 0000001
--- linux-2.3.12/include/asm-mips/termbits.h.bak Fri Jan 8 20:11:45 1999
+++ linux-2.3.12/include/asm-mips/termbits.h Sun Aug 8 15:27:00 1999
@@ -80,6 +80,9 @@
#if defined (__USE_BSD) || defined (__KERNEL__)
#define IMAXBEL 0020000 /* Ring bell when input queue is full. */
#endif
+#if defined (__USE_GNU) || defined (__KERNEL__)
+#define IUTF8 0040000
+#endif

/* c_oflag bits */
#define OPOST 0000001 /* Perform output processing. */
--- linux-2.3.12/include/asm-alpha/termbits.h.bak Fri Jan 8 20:11:45 1999
+++ linux-2.3.12/include/asm-alpha/termbits.h Sun Aug 8 15:27:00 1999
@@ -62,6 +62,9 @@
# define IUCLC 0010000
# define IMAXBEL 0020000
#endif
+#if defined(__KERNEL__) || defined(__USE_GNU)
+# define IUTF8 0040000
+#endif

/* c_oflag bits */
#define OPOST 0000001
--- linux-2.3.12/include/asm-m68k/termbits.h.bak Fri Jan 8 20:11:45 1999
+++ linux-2.3.12/include/asm-m68k/termbits.h Sun Aug 8 15:27:00 1999
@@ -52,6 +52,7 @@
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
+#define IUTF8 0040000

/* c_oflag bits */
#define OPOST 0000001
--- linux-2.3.12/include/asm-sparc/termbits.h.bak Thu Mar 11 01:53:37 1999
+++ linux-2.3.12/include/asm-sparc/termbits.h Sun Aug 8 15:27:01 1999
@@ -78,6 +78,7 @@
#define IXANY 0x00000800
#define IXOFF 0x00001000
#define IMAXBEL 0x00002000
+#define IUTF8 0x00004000

/* c_oflag bits */
#define OPOST 0x00000001
--- linux-2.3.12/include/asm-ppc/termbits.h.bak Thu Mar 11 06:30:32 1999
+++ linux-2.3.12/include/asm-ppc/termbits.h Sun Aug 8 15:27:01 1999
@@ -63,6 +63,9 @@
# define IUCLC 0010000
# define IMAXBEL 0020000
#endif
+#if defined(__KERNEL__) || defined(__USE_GNU)
+# define IUTF8 0040000
+#endif

/* c_oflag bits */
#define OPOST 0000001
--- linux-2.3.12/include/asm-sparc64/termbits.h.bak Thu Mar 11 01:53:38 1999
+++ linux-2.3.12/include/asm-sparc64/termbits.h Sun Aug 8 15:27:01 1999
@@ -80,6 +80,7 @@
#define IXANY 0x00000800
#define IXOFF 0x00001000
#define IMAXBEL 0x00002000
+#define IUTF8 0x00004000

/* c_oflag bits */
#define OPOST 0x00000001
--- linux-2.3.12/include/asm-arm/termbits.h.bak Fri Jan 8 20:11:45 1999
+++ linux-2.3.12/include/asm-arm/termbits.h Sun Aug 8 15:27:00 1999
@@ -51,6 +51,7 @@
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
+#define IUTF8 0040000

/* c_oflag bits */
#define OPOST 0000001
--- linux-2.3.12/drivers/char/n_tty.c.bak Tue May 11 23:37:40 1999
+++ linux-2.3.12/drivers/char/n_tty.c Sun Aug 8 15:27:01 1999
@@ -178,7 +178,7 @@
default:
if (O_OLCUC(tty))
c = toupper(c);
- if (!iscntrl(c))
+ if (!iscntrl(c) && !(I_IUTF8(tty) && ((c & 0xC0) == 0x80)))
tty->column++;
break;
}
@@ -282,7 +282,7 @@
static void eraser(unsigned char c, struct tty_struct *tty)
{
enum { ERASE, WERASE, KILL } kill_type;
- int head, seen_alnums;
+ int head, seen_alnums, cnt;

if (tty->read_head == tty->canon_head) {
/* opost('\a', tty); */ /* what do you think? */
@@ -315,8 +315,19 @@

seen_alnums = 0;
while (tty->read_head != tty->canon_head) {
- head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
- c = tty->read_buf[head];
+ head = tty->read_head;
+ if (I_IUTF8(tty)) {
+ /* erase a multi-byte character */
+ do {
+ head = (head - 1) & (N_TTY_BUF_SIZE-1);
+ c = tty->read_buf[head];
+ } while (((c & 0xC0) == 0x80) && (head != tty->canon_head));
+ if ((c & 0xC0) == 0x80)
+ break;
+ } else {
+ head = (head - 1) & (N_TTY_BUF_SIZE-1);
+ c = tty->read_buf[head];
+ }
if (kill_type == WERASE) {
/* Equivalent to BSD's ALTWERASE. */
if (isalnum(c) || c == '_')
@@ -324,8 +335,9 @@
else if (seen_alnums)
break;
}
+ cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
+ tty->read_cnt -= cnt;
tty->read_head = head;
- tty->read_cnt--;
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
@@ -333,7 +345,12 @@
tty->column++;
tty->erasing = 1;
}
+ /* if cnt > 1, output a multi-byte character */
echo_char(c, tty);
+ while (--cnt > 0) {
+ head = (head+1) & (N_TTY_BUF_SIZE-1);
+ put_char(tty->read_buf[head], tty);
+ }
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') {
@@ -348,7 +365,7 @@
else if (iscntrl(c)) {
if (L_ECHOCTL(tty))
col += 2;
- } else
+ } else if (!(I_IUTF8(tty) && ((c & 0xC0) == 0x80)))
col++;
tail = (tail+1) & (N_TTY_BUF_SIZE-1);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/