Commit be758139 authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by Linus Torvalds

[PATCH] tty utf8 mode

This sounds like a good moment to come with this patch.

This is essentially a five-year-old patch by Bruno Haible.  It
introduces utf8 mode, and the effect it has on erasing input characters.

(Side note - without stty support, this is not very useful, but now
the infrastructure is in place)
parent e5bf4651
...@@ -172,6 +172,16 @@ ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) ...@@ -172,6 +172,16 @@ ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
return n; return n;
} }
static inline int is_utf8_continuation(unsigned char c)
{
return (c & 0xc0) == 0x80;
}
static inline int is_continuation(unsigned char c, struct tty_struct *tty)
{
return I_IUTF8(tty) && is_utf8_continuation(c);
}
/* /*
* Perform OPOST processing. Returns -1 when the output device is * Perform OPOST processing. Returns -1 when the output device is
* full and the character must be retried. * full and the character must be retried.
...@@ -226,7 +236,7 @@ static int opost(unsigned char c, struct tty_struct *tty) ...@@ -226,7 +236,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
default: default:
if (O_OLCUC(tty)) if (O_OLCUC(tty))
c = toupper(c); c = toupper(c);
if (!iscntrl(c)) if (!iscntrl(c) && !is_continuation(c, tty))
tty->column++; tty->column++;
break; break;
} }
...@@ -330,7 +340,7 @@ static inline void finish_erasing(struct tty_struct *tty) ...@@ -330,7 +340,7 @@ static inline void finish_erasing(struct tty_struct *tty)
static void eraser(unsigned char c, struct tty_struct *tty) static void eraser(unsigned char c, struct tty_struct *tty)
{ {
enum { ERASE, WERASE, KILL } kill_type; enum { ERASE, WERASE, KILL } kill_type;
int head, seen_alnums; int head, seen_alnums, cnt;
unsigned long flags; unsigned long flags;
if (tty->read_head == tty->canon_head) { if (tty->read_head == tty->canon_head) {
...@@ -368,8 +378,18 @@ static void eraser(unsigned char c, struct tty_struct *tty) ...@@ -368,8 +378,18 @@ static void eraser(unsigned char c, struct tty_struct *tty)
seen_alnums = 0; seen_alnums = 0;
while (tty->read_head != tty->canon_head) { while (tty->read_head != tty->canon_head) {
head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1); head = tty->read_head;
c = tty->read_buf[head];
/* erase a single possibly multibyte character */
do {
head = (head - 1) & (N_TTY_BUF_SIZE-1);
c = tty->read_buf[head];
} while (is_continuation(c, tty) && head != tty->canon_head);
/* do not partially erase */
if (is_continuation(c, tty))
break;
if (kill_type == WERASE) { if (kill_type == WERASE) {
/* Equivalent to BSD's ALTWERASE. */ /* Equivalent to BSD's ALTWERASE. */
if (isalnum(c) || c == '_') if (isalnum(c) || c == '_')
...@@ -377,9 +397,10 @@ static void eraser(unsigned char c, struct tty_struct *tty) ...@@ -377,9 +397,10 @@ static void eraser(unsigned char c, struct tty_struct *tty)
else if (seen_alnums) else if (seen_alnums)
break; break;
} }
cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
tty->read_head = head; tty->read_head = head;
tty->read_cnt--; tty->read_cnt -= cnt;
spin_unlock_irqrestore(&tty->read_lock, flags); spin_unlock_irqrestore(&tty->read_lock, flags);
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) { if (L_ECHOPRT(tty)) {
...@@ -388,7 +409,12 @@ static void eraser(unsigned char c, struct tty_struct *tty) ...@@ -388,7 +409,12 @@ static void eraser(unsigned char c, struct tty_struct *tty)
tty->column++; tty->column++;
tty->erasing = 1; tty->erasing = 1;
} }
/* if cnt > 1, output a multi-byte character */
echo_char(c, tty); 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)) { } else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty); echo_char(ERASE_CHAR(tty), tty);
} else if (c == '\t') { } else if (c == '\t') {
...@@ -403,7 +429,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) ...@@ -403,7 +429,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
else if (iscntrl(c)) { else if (iscntrl(c)) {
if (L_ECHOCTL(tty)) if (L_ECHOCTL(tty))
col += 2; col += 2;
} else } else if (!is_continuation(c, tty))
col++; col++;
tail = (tail+1) & (N_TTY_BUF_SIZE-1); tail = (tail+1) & (N_TTY_BUF_SIZE-1);
} }
......
...@@ -56,12 +56,10 @@ struct termios { ...@@ -56,12 +56,10 @@ struct termios {
#define ICRNL 0000400 #define ICRNL 0000400
#define IXON 0001000 #define IXON 0001000
#define IXOFF 0002000 #define IXOFF 0002000
#if !defined(KERNEL) || defined(__USE_BSD) #define IXANY 0004000
/* POSIX.1 doesn't want these... */ #define IUCLC 0010000
# define IXANY 0004000 #define IMAXBEL 0020000
# define IUCLC 0010000 #define IUTF8 0040000
# define IMAXBEL 0020000
#endif
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -49,6 +49,7 @@ struct termios { ...@@ -49,6 +49,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -49,6 +49,7 @@ struct termios { ...@@ -49,6 +49,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -53,6 +53,7 @@ struct termios { ...@@ -53,6 +53,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -52,6 +52,7 @@ struct termios { ...@@ -52,6 +52,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -51,6 +51,7 @@ struct termios { ...@@ -51,6 +51,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -60,6 +60,7 @@ struct termios { ...@@ -60,6 +60,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -52,6 +52,7 @@ struct termios { ...@@ -52,6 +52,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -77,6 +77,7 @@ struct termios { ...@@ -77,6 +77,7 @@ struct termios {
#define IXANY 0004000 /* Any character will restart after stop. */ #define IXANY 0004000 /* Any character will restart after stop. */
#define IXOFF 0010000 /* Enable start/stop input control. */ #define IXOFF 0010000 /* Enable start/stop input control. */
#define IMAXBEL 0020000 /* Ring bell when input queue is full. */ #define IMAXBEL 0020000 /* Ring bell when input queue is full. */
#define IUTF8 0040000 /* Input is UTF8 */
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 /* Perform output processing. */ #define OPOST 0000001 /* Perform output processing. */
......
...@@ -52,6 +52,7 @@ struct termios { ...@@ -52,6 +52,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0040000 #define IMAXBEL 0040000
#define IUTF8 0100000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -58,6 +58,7 @@ struct termios { ...@@ -58,6 +58,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IUCLC 0010000 #define IUCLC 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -66,6 +66,7 @@ struct termios { ...@@ -66,6 +66,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IUCLC 0010000 #define IUCLC 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -59,6 +59,7 @@ struct termios { ...@@ -59,6 +59,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -51,6 +51,7 @@ struct termios { ...@@ -51,6 +51,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -78,6 +78,7 @@ struct termios { ...@@ -78,6 +78,7 @@ struct termios {
#define IXANY 0x00000800 #define IXANY 0x00000800
#define IXOFF 0x00001000 #define IXOFF 0x00001000
#define IMAXBEL 0x00002000 #define IMAXBEL 0x00002000
#define IUTF8 0x00004000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0x00000001 #define OPOST 0x00000001
......
...@@ -80,6 +80,7 @@ struct termios { ...@@ -80,6 +80,7 @@ struct termios {
#define IXANY 0x00000800 #define IXANY 0x00000800
#define IXOFF 0x00001000 #define IXOFF 0x00001000
#define IMAXBEL 0x00002000 #define IMAXBEL 0x00002000
#define IUTF8 0x00004000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0x00000001 #define OPOST 0x00000001
......
...@@ -52,6 +52,7 @@ struct termios { ...@@ -52,6 +52,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -51,6 +51,7 @@ struct termios { ...@@ -51,6 +51,7 @@ struct termios {
#define IXANY 0004000 #define IXANY 0004000
#define IXOFF 0010000 #define IXOFF 0010000
#define IMAXBEL 0020000 #define IMAXBEL 0020000
#define IUTF8 0040000
/* c_oflag bits */ /* c_oflag bits */
#define OPOST 0000001 #define OPOST 0000001
......
...@@ -184,6 +184,7 @@ struct tty_flip_buffer { ...@@ -184,6 +184,7 @@ struct tty_flip_buffer {
#define I_IXANY(tty) _I_FLAG((tty),IXANY) #define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF) #define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL) #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_OPOST(tty) _O_FLAG((tty),OPOST)
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC) #define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment