[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

editing behaviour of ttys




Hello all,

Welcome to this mailing list. Since I assume that all of you know about
the most important URLs (Markus Kuhn's Unicode page, Roman Czyborra's
writings, etc.) and are already running an xterm in UTF-8 mode, let me
start right away. With a kernel issue.

Any comment about the following patch? (Which I already sent to
linux-kernel@vger.rutgers.edu, but it was ignored.)

Andries, what's your opinion? - because Linus said that if a patch comes
from you, he puts it in :-)

If this patch goes into the kernel, a similar patch will come for glibc
(for the header files), and then for xterm, rlogind and telnetd.

Bruno

-----------------------------------------------------------------------------

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 it 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);
 				}
-
Linux-UTF8:   i18n of Linux on all levels
Archive:      http://mail.nl.linux.org/lists/