UTF-8 Terminal I/O recoding patch for Links 0.99

"BC Sittler" <[email protected]>
Newsgroups gmane.comp.web.links.list
Message-ID <[email protected]>
Hi Links-ers,

New features (like FreeBSD line-drawing graphics support)
have broken the earlier patch. The new one is attached to
this message in two forms, plaintext and binary.

Also, has anyone considered adding full support for the
FreeBSD console character set, so that e.g. CP437 webpages
appear correctly under FreeBSD in Links?

Anyhow, it's good to see a new version of Links :)

Full description of the patch:

Do you use xterm, screen, gnome-terminal, the Linux
console, the os x terminal, or another UCS/Unicode-
capable terminal or terminal emulator with the UTF-8
character encoding, and want to use the Links web
browser with non-ASCII webpages? If so, this patch
may be of use. It allows use of any of the Links
display charsets (collectively covering about 750
Unicode characters in Links 0.99) with a UTF-8 terminal.
It even allows fast switching back and forth at run-time
between different display charsets without any terminal
reconfiguration.

This is a new version of the UTF-8 Terminal I/O recoding
patch for Links 0.99. It allows limited use of non-ASCII
characters in UTF-8 terminals and terminal emulators by
translating Links's internal display charset (and line-
drawing graphics) to UTF-8 before sending them to the
terminal, and by translating keystroke input from UTF-8
to Link's internal display charset before processing it.
While this is not full UTF-8 support by any means, it is
enough to use non-ASCII web sites on a UTF-8 terminal
exactly as you would on a non-UTF-8 terminal, with the
added feature of being able to switch between the
different Links display charsets without reconfiguring
your terminal.

By default, the UTF-8 Terminal I/O recoding does not occur,
so you may continue to use Links as you are accustomed to
on non-UTF-8 terminals.

To use it, you must enable the "UTF-8 I/O" option in the
"Terminal options" screen. This setting is specific to
a terminal type, just like the other Terminal options,
and is saved in the config file by appending the word
"utf-8" to the "terminal" or "terminal2" line in links.cfg,
so it is backward-compatible and degrades nicely (versions
of Links without the patch simply ignore that word.)

NOTE: In concept this is similar to the "luit" program, but
integrated into Links. It does not magically make Links
UCS/Unicode-aware. So e.g. this does not add CJK support.

Anyhow, enjoy!
-Ben

-- 
___________________________________________________________
Sign-up for Ads Free at Mail.com
http://promo.mail.com/adsfreejump.htm

_______________________________________________
Links-list mailing list
[email protected]
http://linuxfromscratch.org/mailman/listinfo/links-list
links-0.99-utf-8.txt (text/plain, 11.2 KB)
diff -u --recursive links-0.99.orig/charsets.c links-0.99/charsets.c
--- links-0.99.orig/charsets.c	2003-02-05 02:18:17.000000000 -0800
+++ links-0.99/charsets.c	2004-01-05 18:35:02.000000000 -0800
@@ -89,7 +89,7 @@
 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0x0000, 0x0000, 0x0000,
 };
 
-static inline unsigned char *u2cp(int u, int to)
+unsigned char *u2cp(int u, int to)
 {
 	int j, s;
 	if (u < 128) return strings[u];
@@ -140,6 +140,22 @@
 	return utf_buffer;
 }
 
+/* this slow and ugly code is used by the terminal utf_8_io */
+unsigned char *cp2utf_8(int from, int c)
+{
+	int j;
+
+	if (codepages[from].table == table_utf_8) return strings[c];
+	for (j = 0; codepages[from].table[j].c; j++) {
+		if (codepages[from].table[j].c == c)
+		{
+			return encode_utf_8(codepages[from].table[j].u);
+		}
+	}
+	if (c < 128) return strings[c];
+	return encode_utf_8(UCS_NO_CHAR);
+}
+
 void add_utf_8(struct conv_table *ct, int u, unsigned char *str)
 {
 	unsigned char *p = encode_utf_8(u);
diff -u --recursive links-0.99.orig/default.c links-0.99/default.c
--- links-0.99.orig/default.c	2003-11-18 14:38:22.000000000 -0800
+++ links-0.99/default.c	2004-01-05 18:35:02.000000000 -0800
@@ -575,6 +575,7 @@
 	}
 }
 
+/* terminal NAME(str) MODE(0-3) M11_HACK(0-1) BLOCK_CURSOR.RESTRICT_852.COL(0-7) CHARSET(str) [ UTF_8_IO("utf-8") ]*/
 unsigned char *term_rd(struct option *o, unsigned char *c)
 {
 	struct term_spec *ts;
@@ -585,6 +586,7 @@
 		mem_free(w);
 		goto end;
 	}
+        ts->utf_8_io = 0;
 	mem_free(w);
 	if (!(w = get_token(&c))) goto err;
 	if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
@@ -604,6 +606,9 @@
 	if ((i = get_cp_index(w)) == -1) goto err_f;
 	ts->charset = i;
 	mem_free(w);
+        if (!(w = get_token(&c))) goto end;
+        if (!(strcasecmp(w, "utf-8"))) ts->utf_8_io = 1;
+        mem_free(w);
 	end:
 	return NULL;
 	err_f:
@@ -612,6 +617,7 @@
 	return "Error reading terminal specification";
 }
 
+/* terminal2 NAME(str) MODE(0-3) M11_HACK(0-1) RESTRICT_852(0-1) COL(0-1) CHARSET(str) [ UTF_8_IO("utf-8") ]*/
 unsigned char *term2_rd(struct option *o, unsigned char *c)
 {
 	struct term_spec *ts;
@@ -622,6 +628,7 @@
 		mem_free(w);
 		goto end;
 	}
+        ts->utf_8_io = 0;
 	mem_free(w);
 	if (!(w = get_token(&c))) goto err;
 	if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
@@ -643,6 +650,9 @@
 	if ((i = get_cp_index(w)) == -1) goto err_f;
 	ts->charset = i;
 	mem_free(w);
+        if (!(w = get_token(&c))) goto end;
+        if (!(strcasecmp(w, "utf-8"))) ts->utf_8_io = 1;
+        mem_free(w);
 	end:
 	return NULL;
 	err_f:
@@ -665,6 +675,10 @@
 		add_num_to_str(s, l, !!ts->col + !!ts->restrict_852 * 2 + !!ts->block_cursor * 4);
 		add_to_str(s, l, " ");
 		add_to_str(s, l, get_cp_mime_name(ts->charset));
+                if (ts->utf_8_io)
+                {
+                    add_to_str(s, l, " utf-8");
+                }
 	}
 }
 
diff -u --recursive links-0.99.orig/intl/english.lng links-0.99/intl/english.lng
--- links-0.99.orig/intl/english.lng	2003-12-14 13:33:27.000000000 -0800
+++ links-0.99/intl/english.lng	2004-01-05 18:35:29.000000000 -0800
@@ -49,6 +49,7 @@
 T_KOI8R_FRAMES, "KOI8-R frames",
 T_FREEBSD_FRAMES, "FreeBSD frames",
 T_USE_11M, "Use ^[[11m",
+T_UTF_8_IO, "UTF-8 I/O",
 T_RESTRICT_FRAMES_IN_CP850_852, "Restrict frames in cp850/852",
 T_BLOCK_CURSOR, "Block cursor",
 T_COLOR, "Color",
diff -u --recursive links-0.99.orig/links.h links-0.99/links.h
--- links-0.99.orig/links.h	2003-12-14 13:29:45.000000000 -0800
+++ links-0.99/links.h	2004-01-05 19:05:35.000000000 -0800
@@ -1020,6 +1020,11 @@
 	int qlen;
 	struct list_head windows;
 	unsigned char *title;
+	struct {
+		int ucs;
+		int len;
+		int min;
+	} utf_8;
 };
 
 struct term_spec {
@@ -1028,6 +1033,7 @@
 	unsigned char term[MAX_TERM_LEN];
 	int mode;
 	int m11_hack;
+	int utf_8_io;
 	int restrict_852;
 	int block_cursor;
 	int col;
@@ -1729,6 +1735,9 @@
 void do_auth_dialog(struct session *);
 /* charsets.c */
 
+/* UCS/Unicode replacement character */
+#define UCS_NO_CHAR 0xFFFD
+
 #include "codepage.h"
 
 struct conv_table {
@@ -1747,6 +1756,8 @@
 unsigned char *get_cp_mime_name(int);
 int is_cp_special(int);
 void free_conv_table();
+unsigned char *cp2utf_8(int, int);
+unsigned char *u2cp(int, int);
 
 /* view.c */
 
diff -u --recursive links-0.99.orig/menu.c links-0.99/menu.c
--- links-0.99.orig/menu.c	2003-11-18 14:38:24.000000000 -0800
+++ links-0.99/menu.c	2004-01-05 18:46:26.000000000 -0800
@@ -385,15 +385,15 @@
 	cls_redraw_all_terminals();
 }
 
-unsigned char *td_labels[] = { TEXT(T_NO_FRAMES), TEXT(T_VT_100_FRAMES), TEXT(T_LINUX_OR_OS2_FRAMES), TEXT(T_KOI8R_FRAMES), TEXT(T_FREEBSD_FRAMES), TEXT(T_USE_11M), TEXT(T_RESTRICT_FRAMES_IN_CP850_852), TEXT(T_BLOCK_CURSOR), TEXT(T_COLOR), NULL };
+unsigned char *td_labels[] = { TEXT(T_NO_FRAMES), TEXT(T_VT_100_FRAMES), TEXT(T_LINUX_OR_OS2_FRAMES), TEXT(T_KOI8R_FRAMES), TEXT(T_FREEBSD_FRAMES), TEXT(T_USE_11M), TEXT(T_RESTRICT_FRAMES_IN_CP850_852), TEXT(T_BLOCK_CURSOR), TEXT(T_COLOR), TEXT(T_UTF_8_IO), NULL };
 
 void terminal_options(struct terminal *term, void *xxx, struct session *ses)
 {
 	struct dialog *d;
 	struct term_spec *ts = new_term_spec(term->term);
 	if (!ts) return;
-	if (!(d = mem_alloc(sizeof(struct dialog) + 12 * sizeof(struct dialog_item)))) return;
-	memset(d, 0, sizeof(struct dialog) + 12 * sizeof(struct dialog_item));
+	if (!(d = mem_alloc(sizeof(struct dialog) + 13 * sizeof(struct dialog_item)))) return;
+	memset(d, 0, sizeof(struct dialog) + 13 * sizeof(struct dialog_item));
 	d->title = TEXT(T_TERMINAL_OPTIONS);
 	d->fn = checkbox_list_fn;
 	d->udata = td_labels;
@@ -439,15 +439,19 @@
 	d->items[8].gid = 0;
 	d->items[8].dlen = sizeof(int);
 	d->items[8].data = (void *)&ts->col;
-	d->items[9].type = D_BUTTON;
-	d->items[9].gid = B_ENTER;
-	d->items[9].fn = ok_dialog;
-	d->items[9].text = TEXT(T_OK);
+	d->items[9].type = D_CHECKBOX;
+	d->items[9].gid = 0;
+	d->items[9].dlen = sizeof(int);
+	d->items[9].data = (void *)&ts->utf_8_io;
 	d->items[10].type = D_BUTTON;
-	d->items[10].gid = B_ESC;
-	d->items[10].fn = cancel_dialog;
-	d->items[10].text = TEXT(T_CANCEL);
-	d->items[11].type = D_END;
+	d->items[10].gid = B_ENTER;
+	d->items[10].fn = ok_dialog;
+	d->items[10].text = TEXT(T_OK);
+	d->items[11].type = D_BUTTON;
+	d->items[11].gid = B_ESC;
+	d->items[11].fn = cancel_dialog;
+	d->items[11].text = TEXT(T_CANCEL);
+	d->items[12].type = D_END;
  	do_dialog(term, d, getml(d, NULL));
 }
 
diff -u --recursive links-0.99.orig/terminal.c links-0.99/terminal.c
--- links-0.99.orig/terminal.c	2003-11-28 06:36:27.000000000 -0800
+++ links-0.99/terminal.c	2004-01-05 19:20:43.000000000 -0800
@@ -345,6 +345,25 @@
 	return term;
 }
 
+static inline void term_send_event(struct terminal *term, struct event *ev)
+{
+	((struct window *)&term->windows)->next->handler(term->windows.next, ev, 0);
+}
+
+static inline void term_send_ucs(struct terminal *term, struct event *ev, int u)
+{
+	unsigned char *recoded;
+
+	if (u == 0xA0) u = ' ';
+	recoded = u2cp(u, term->spec->charset);
+	if (! recoded) recoded = "*";
+	while (*recoded) {
+		ev->x = *recoded;
+		term_send_event(term, ev);
+		recoded ++;
+	}
+}
+
 void in_term(struct terminal *term)
 {
 	struct event *ev;
@@ -405,7 +424,40 @@
 			goto send_redraw;
 		}
 		else if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C) ((struct window *)&term->windows)->prev->handler(term->windows.prev, ev, 0);
-		else ((struct window *)&term->windows)->next->handler(term->windows.next, ev, 0);
+		else if (ev->ev == EV_KBD) {
+			if (term->utf_8.len) {
+				if ((ev->x & 0xC0) == 0x80 && term->spec->utf_8_io) {
+					term->utf_8.ucs <<= 6;
+					term->utf_8.ucs |= ev->x & 0x3F;
+					if (! --term->utf_8.len) {
+						int u = term->utf_8.ucs;
+
+						if (u < term->utf_8.min) u = UCS_NO_CHAR;
+						term_send_ucs(term, ev, u);
+					}
+					goto mm;
+				} else {
+					term->utf_8.len = 0;
+					term_send_ucs(term, ev, UCS_NO_CHAR);
+				}
+			}
+			if (ev->x < 0x80 || ev->x > 0xFF || ! term->spec->utf_8_io) {
+				term_send_event(term, ev);
+				goto mm;
+			} else if ((ev->x & 0xC0) == 0xC0 && (ev->x & 0xFE) != 0xFE) {
+				int mask, len = 0, cov = 0x80;
+
+				for (mask = 0x80; ev->x & mask; mask >>= 1) {
+					len++;
+					term->utf_8.min = cov;
+					cov = 1 << (1 + 5 * len);
+				}
+				term->utf_8.len = len - 1;
+				term->utf_8.ucs = ev->x & (mask - 1);
+				goto mm;
+			}
+			term_send_ucs(term, ev, UCS_NO_CHAR);
+		} else term_send_event(term, ev);
 	}
 	if (ev->ev == EV_ABORT) {
 		destroy_terminal(term);
@@ -425,6 +477,14 @@
 
 unsigned char frame_dumb[48] =	"   ||||++||++++++--|-+||++--|-+----++++++++     ";
 unsigned char frame_vt100[48] =	"aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla    ";
+unsigned char frame_vt100_u[48] = {
+	177,177,177,179,180,180,180,191,
+	191,180,179,191,217,217,217,191,
+	192,193,194,195,196,197,195,195,
+	192,218,193,194,195,196,197,193,
+	193,194,194,192,192,218,218,197,
+	197,217,218,177, 32, 32, 32, 32
+};
 unsigned char frame_koi[48] = {
 	144,145,146,129,135,178,180,167,
 	166,181,161,168,174,173,172,131,
@@ -456,7 +516,7 @@
 	unsigned char c = ch & 0xff;							\
 	unsigned char A = ch >> 8 & 0x7f;						\
 	if (s->mode == TERM_LINUX) {							\
-		if (s->m11_hack) {							\
+		if (s->m11_hack && !s->utf_8_io) {					\
 			if (ch >> 15 != mode) {						\
 				if (!(mode = ch >> 15)) add_to_str(&a, &l, "\033[10m");	\
 				else add_to_str(&a, &l, "\033[11m");			\
@@ -465,14 +525,16 @@
 		if (s->restrict_852 && (ch >> 15) && c >= 176 && c < 224) {		\
 			if (frame_restrict[c - 176]) c = frame_restrict[c - 176];	\
 		}									\
-	} else if (s->mode == TERM_VT100) {						\
+	} else if (s->mode == TERM_VT100 && !s->utf_8_io) {				\
 		if (ch >> 15 != mode) {							\
 			if (!(mode = ch >> 15)) add_to_str(&a, &l, "\x0f");		\
 			else add_to_str(&a, &l, "\x0e");				\
 		}									\
 		if (mode && c >= 176 && c < 224) c = frame_vt100[c - 176];		\
+	} else if (s->mode == TERM_VT100 && (ch >> 15) && c >= 176 && c < 224) {	\
+		c = frame_vt100_u[c - 176];						\
 	} else if (s->mode == TERM_KOI8 && (ch >> 15) && c >= 176 && c < 224) { c = frame_koi[c - 176];\
-	} else if (s->mode == TERM_FREEBSD && (ch >> 15) && c >= 176 && c < 224) { c = frame_freebsd[c - 176];\
+	} else if (s->mode == TERM_FREEBSD && (ch >> 15) && c >= 176 && c < 224 && !s->utf_8_io) { c = frame_freebsd[c - 176];\
 	} else if (s->mode == TERM_DUMB && (ch >> 15) && c >= 176 && c < 224) c = frame_dumb[c - 176];\
 	if (!(A & 0100) && (A >> 3) == (A & 7)) A = (A & 070) | 7 * !(A & 020);		\
 	if (A != attrib) {								\
@@ -491,7 +553,20 @@
 		if (attrib & 0100) add_to_str(&a, &l, ";1");				\
 		add_to_str(&a, &l, "m");						\
 	}										\
-	if (c >= ' ' && c != 127/* && c != 155*/) add_chr_to_str(&a, &l, c);		\
+	if (c >= ' ' && c != 127/* && c != 155*/) {					\
+		int charset = s->charset;						\
+											\
+		if (ch >> 15) {								\
+			int frames_charset = (s->mode == TERM_LINUX || s->mode == TERM_VT100 || s->mode == TERM_FREEBSD) \
+						? get_cp_index("cp437")			\
+						: s->mode == TERM_KOI8			\
+						? get_cp_index("koi8-r")		\
+						: -1;					\
+			if (frames_charset != -1) charset = frames_charset;		\
+		}									\
+		if (s->utf_8_io) add_to_str(&a, &l, cp2utf_8(charset, c));		\
+		else add_chr_to_str(&a, &l, c);						\
+	}										\
 	else if (!c || c == 1) add_chr_to_str(&a, &l, ' ');				\
 	else add_chr_to_str(&a, &l, '.');						\
 	cx++;										\
links-0.99-utf-8.diff (application/octet-stream, 11.2 KB)
diff -u --recursive links-0.99.orig/charsets.c links-0.99/charsets.c
--- links-0.99.orig/charsets.c	2003-02-05 02:18:17.000000000 -0800
+++ links-0.99/charsets.c	2004-01-05 18:35:02.000000000 -0800
@@ -89,7 +89,7 @@
 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0x0000, 0x0000, 0x0000,
 };
 
-static inline unsigned char *u2cp(int u, int to)
+unsigned char *u2cp(int u, int to)
 {
 	int j, s;
 	if (u < 128) return strings[u];
@@ -140,6 +140,22 @@
 	return utf_buffer;
 }
 
+/* this slow and ugly code is used by the terminal utf_8_io */
+unsigned char *cp2utf_8(int from, int c)
+{
+	int j;
+
+	if (codepages[from].table == table_utf_8) return strings[c];
+	for (j = 0; codepages[from].table[j].c; j++) {
+		if (codepages[from].table[j].c == c)
+		{
+			return encode_utf_8(codepages[from].table[j].u);
+		}
+	}
+	if (c < 128) return strings[c];
+	return encode_utf_8(UCS_NO_CHAR);
+}
+
 void add_utf_8(struct conv_table *ct, int u, unsigned char *str)
 {
 	unsigned char *p = encode_utf_8(u);
diff -u --recursive links-0.99.orig/default.c links-0.99/default.c
--- links-0.99.orig/default.c	2003-11-18 14:38:22.000000000 -0800
+++ links-0.99/default.c	2004-01-05 18:35:02.000000000 -0800
@@ -575,6 +575,7 @@
 	}
 }
 
+/* terminal NAME(str) MODE(0-3) M11_HACK(0-1) BLOCK_CURSOR.RESTRICT_852.COL(0-7) CHARSET(str) [ UTF_8_IO("utf-8") ]*/
 unsigned char *term_rd(struct option *o, unsigned char *c)
 {
 	struct term_spec *ts;
@@ -585,6 +586,7 @@
 		mem_free(w);
 		goto end;
 	}
+        ts->utf_8_io = 0;
 	mem_free(w);
 	if (!(w = get_token(&c))) goto err;
 	if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
@@ -604,6 +606,9 @@
 	if ((i = get_cp_index(w)) == -1) goto err_f;
 	ts->charset = i;
 	mem_free(w);
+        if (!(w = get_token(&c))) goto end;
+        if (!(strcasecmp(w, "utf-8"))) ts->utf_8_io = 1;
+        mem_free(w);
 	end:
 	return NULL;
 	err_f:
@@ -612,6 +617,7 @@
 	return "Error reading terminal specification";
 }
 
+/* terminal2 NAME(str) MODE(0-3) M11_HACK(0-1) RESTRICT_852(0-1) COL(0-1) CHARSET(str) [ UTF_8_IO("utf-8") ]*/
 unsigned char *term2_rd(struct option *o, unsigned char *c)
 {
 	struct term_spec *ts;
@@ -622,6 +628,7 @@
 		mem_free(w);
 		goto end;
 	}
+        ts->utf_8_io = 0;
 	mem_free(w);
 	if (!(w = get_token(&c))) goto err;
 	if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
@@ -643,6 +650,9 @@
 	if ((i = get_cp_index(w)) == -1) goto err_f;
 	ts->charset = i;
 	mem_free(w);
+        if (!(w = get_token(&c))) goto end;
+        if (!(strcasecmp(w, "utf-8"))) ts->utf_8_io = 1;
+        mem_free(w);
 	end:
 	return NULL;
 	err_f:
@@ -665,6 +675,10 @@
 		add_num_to_str(s, l, !!ts->col + !!ts->restrict_852 * 2 + !!ts->block_cursor * 4);
 		add_to_str(s, l, " ");
 		add_to_str(s, l, get_cp_mime_name(ts->charset));
+                if (ts->utf_8_io)
+                {
+                    add_to_str(s, l, " utf-8");
+                }
 	}
 }
 
diff -u --recursive links-0.99.orig/intl/english.lng links-0.99/intl/english.lng
--- links-0.99.orig/intl/english.lng	2003-12-14 13:33:27.000000000 -0800
+++ links-0.99/intl/english.lng	2004-01-05 18:35:29.000000000 -0800
@@ -49,6 +49,7 @@
 T_KOI8R_FRAMES, "KOI8-R frames",
 T_FREEBSD_FRAMES, "FreeBSD frames",
 T_USE_11M, "Use ^[[11m",
+T_UTF_8_IO, "UTF-8 I/O",
 T_RESTRICT_FRAMES_IN_CP850_852, "Restrict frames in cp850/852",
 T_BLOCK_CURSOR, "Block cursor",
 T_COLOR, "Color",
diff -u --recursive links-0.99.orig/links.h links-0.99/links.h
--- links-0.99.orig/links.h	2003-12-14 13:29:45.000000000 -0800
+++ links-0.99/links.h	2004-01-05 19:05:35.000000000 -0800
@@ -1020,6 +1020,11 @@
 	int qlen;
 	struct list_head windows;
 	unsigned char *title;
+	struct {
+		int ucs;
+		int len;
+		int min;
+	} utf_8;
 };
 
 struct term_spec {
@@ -1028,6 +1033,7 @@
 	unsigned char term[MAX_TERM_LEN];
 	int mode;
 	int m11_hack;
+	int utf_8_io;
 	int restrict_852;
 	int block_cursor;
 	int col;
@@ -1729,6 +1735,9 @@
 void do_auth_dialog(struct session *);
 /* charsets.c */
 
+/* UCS/Unicode replacement character */
+#define UCS_NO_CHAR 0xFFFD
+
 #include "codepage.h"
 
 struct conv_table {
@@ -1747,6 +1756,8 @@
 unsigned char *get_cp_mime_name(int);
 int is_cp_special(int);
 void free_conv_table();
+unsigned char *cp2utf_8(int, int);
+unsigned char *u2cp(int, int);
 
 /* view.c */
 
diff -u --recursive links-0.99.orig/menu.c links-0.99/menu.c
--- links-0.99.orig/menu.c	2003-11-18 14:38:24.000000000 -0800
+++ links-0.99/menu.c	2004-01-05 18:46:26.000000000 -0800
@@ -385,15 +385,15 @@
 	cls_redraw_all_terminals();
 }
 
-unsigned char *td_labels[] = { TEXT(T_NO_FRAMES), TEXT(T_VT_100_FRAMES), TEXT(T_LINUX_OR_OS2_FRAMES), TEXT(T_KOI8R_FRAMES), TEXT(T_FREEBSD_FRAMES), TEXT(T_USE_11M), TEXT(T_RESTRICT_FRAMES_IN_CP850_852), TEXT(T_BLOCK_CURSOR), TEXT(T_COLOR), NULL };
+unsigned char *td_labels[] = { TEXT(T_NO_FRAMES), TEXT(T_VT_100_FRAMES), TEXT(T_LINUX_OR_OS2_FRAMES), TEXT(T_KOI8R_FRAMES), TEXT(T_FREEBSD_FRAMES), TEXT(T_USE_11M), TEXT(T_RESTRICT_FRAMES_IN_CP850_852), TEXT(T_BLOCK_CURSOR), TEXT(T_COLOR), TEXT(T_UTF_8_IO), NULL };
 
 void terminal_options(struct terminal *term, void *xxx, struct session *ses)
 {
 	struct dialog *d;
 	struct term_spec *ts = new_term_spec(term->term);
 	if (!ts) return;
-	if (!(d = mem_alloc(sizeof(struct dialog) + 12 * sizeof(struct dialog_item)))) return;
-	memset(d, 0, sizeof(struct dialog) + 12 * sizeof(struct dialog_item));
+	if (!(d = mem_alloc(sizeof(struct dialog) + 13 * sizeof(struct dialog_item)))) return;
+	memset(d, 0, sizeof(struct dialog) + 13 * sizeof(struct dialog_item));
 	d->title = TEXT(T_TERMINAL_OPTIONS);
 	d->fn = checkbox_list_fn;
 	d->udata = td_labels;
@@ -439,15 +439,19 @@
 	d->items[8].gid = 0;
 	d->items[8].dlen = sizeof(int);
 	d->items[8].data = (void *)&ts->col;
-	d->items[9].type = D_BUTTON;
-	d->items[9].gid = B_ENTER;
-	d->items[9].fn = ok_dialog;
-	d->items[9].text = TEXT(T_OK);
+	d->items[9].type = D_CHECKBOX;
+	d->items[9].gid = 0;
+	d->items[9].dlen = sizeof(int);
+	d->items[9].data = (void *)&ts->utf_8_io;
 	d->items[10].type = D_BUTTON;
-	d->items[10].gid = B_ESC;
-	d->items[10].fn = cancel_dialog;
-	d->items[10].text = TEXT(T_CANCEL);
-	d->items[11].type = D_END;
+	d->items[10].gid = B_ENTER;
+	d->items[10].fn = ok_dialog;
+	d->items[10].text = TEXT(T_OK);
+	d->items[11].type = D_BUTTON;
+	d->items[11].gid = B_ESC;
+	d->items[11].fn = cancel_dialog;
+	d->items[11].text = TEXT(T_CANCEL);
+	d->items[12].type = D_END;
  	do_dialog(term, d, getml(d, NULL));
 }
 
diff -u --recursive links-0.99.orig/terminal.c links-0.99/terminal.c
--- links-0.99.orig/terminal.c	2003-11-28 06:36:27.000000000 -0800
+++ links-0.99/terminal.c	2004-01-05 19:20:43.000000000 -0800
@@ -345,6 +345,25 @@
 	return term;
 }
 
+static inline void term_send_event(struct terminal *term, struct event *ev)
+{
+	((struct window *)&term->windows)->next->handler(term->windows.next, ev, 0);
+}
+
+static inline void term_send_ucs(struct terminal *term, struct event *ev, int u)
+{
+	unsigned char *recoded;
+
+	if (u == 0xA0) u = ' ';
+	recoded = u2cp(u, term->spec->charset);
+	if (! recoded) recoded = "*";
+	while (*recoded) {
+		ev->x = *recoded;
+		term_send_event(term, ev);
+		recoded ++;
+	}
+}
+
 void in_term(struct terminal *term)
 {
 	struct event *ev;
@@ -405,7 +424,40 @@
 			goto send_redraw;
 		}
 		else if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C) ((struct window *)&term->windows)->prev->handler(term->windows.prev, ev, 0);
-		else ((struct window *)&term->windows)->next->handler(term->windows.next, ev, 0);
+		else if (ev->ev == EV_KBD) {
+			if (term->utf_8.len) {
+				if ((ev->x & 0xC0) == 0x80 && term->spec->utf_8_io) {
+					term->utf_8.ucs <<= 6;
+					term->utf_8.ucs |= ev->x & 0x3F;
+					if (! --term->utf_8.len) {
+						int u = term->utf_8.ucs;
+
+						if (u < term->utf_8.min) u = UCS_NO_CHAR;
+						term_send_ucs(term, ev, u);
+					}
+					goto mm;
+				} else {
+					term->utf_8.len = 0;
+					term_send_ucs(term, ev, UCS_NO_CHAR);
+				}
+			}
+			if (ev->x < 0x80 || ev->x > 0xFF || ! term->spec->utf_8_io) {
+				term_send_event(term, ev);
+				goto mm;
+			} else if ((ev->x & 0xC0) == 0xC0 && (ev->x & 0xFE) != 0xFE) {
+				int mask, len = 0, cov = 0x80;
+
+				for (mask = 0x80; ev->x & mask; mask >>= 1) {
+					len++;
+					term->utf_8.min = cov;
+					cov = 1 << (1 + 5 * len);
+				}
+				term->utf_8.len = len - 1;
+				term->utf_8.ucs = ev->x & (mask - 1);
+				goto mm;
+			}
+			term_send_ucs(term, ev, UCS_NO_CHAR);
+		} else term_send_event(term, ev);
 	}
 	if (ev->ev == EV_ABORT) {
 		destroy_terminal(term);
@@ -425,6 +477,14 @@
 
 unsigned char frame_dumb[48] =	"   ||||++||++++++--|-+||++--|-+----++++++++     ";
 unsigned char frame_vt100[48] =	"aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla    ";
+unsigned char frame_vt100_u[48] = {
+	177,177,177,179,180,180,180,191,
+	191,180,179,191,217,217,217,191,
+	192,193,194,195,196,197,195,195,
+	192,218,193,194,195,196,197,193,
+	193,194,194,192,192,218,218,197,
+	197,217,218,177, 32, 32, 32, 32
+};
 unsigned char frame_koi[48] = {
 	144,145,146,129,135,178,180,167,
 	166,181,161,168,174,173,172,131,
@@ -456,7 +516,7 @@
 	unsigned char c = ch & 0xff;							\
 	unsigned char A = ch >> 8 & 0x7f;						\
 	if (s->mode == TERM_LINUX) {							\
-		if (s->m11_hack) {							\
+		if (s->m11_hack && !s->utf_8_io) {					\
 			if (ch >> 15 != mode) {						\
 				if (!(mode = ch >> 15)) add_to_str(&a, &l, "\033[10m");	\
 				else add_to_str(&a, &l, "\033[11m");			\
@@ -465,14 +525,16 @@
 		if (s->restrict_852 && (ch >> 15) && c >= 176 && c < 224) {		\
 			if (frame_restrict[c - 176]) c = frame_restrict[c - 176];	\
 		}									\
-	} else if (s->mode == TERM_VT100) {						\
+	} else if (s->mode == TERM_VT100 && !s->utf_8_io) {				\
 		if (ch >> 15 != mode) {							\
 			if (!(mode = ch >> 15)) add_to_str(&a, &l, "\x0f");		\
 			else add_to_str(&a, &l, "\x0e");				\
 		}									\
 		if (mode && c >= 176 && c < 224) c = frame_vt100[c - 176];		\
+	} else if (s->mode == TERM_VT100 && (ch >> 15) && c >= 176 && c < 224) {	\
+		c = frame_vt100_u[c - 176];						\
 	} else if (s->mode == TERM_KOI8 && (ch >> 15) && c >= 176 && c < 224) { c = frame_koi[c - 176];\
-	} else if (s->mode == TERM_FREEBSD && (ch >> 15) && c >= 176 && c < 224) { c = frame_freebsd[c - 176];\
+	} else if (s->mode == TERM_FREEBSD && (ch >> 15) && c >= 176 && c < 224 && !s->utf_8_io) { c = frame_freebsd[c - 176];\
 	} else if (s->mode == TERM_DUMB && (ch >> 15) && c >= 176 && c < 224) c = frame_dumb[c - 176];\
 	if (!(A & 0100) && (A >> 3) == (A & 7)) A = (A & 070) | 7 * !(A & 020);		\
 	if (A != attrib) {								\
@@ -491,7 +553,20 @@
 		if (attrib & 0100) add_to_str(&a, &l, ";1");				\
 		add_to_str(&a, &l, "m");						\
 	}										\
-	if (c >= ' ' && c != 127/* && c != 155*/) add_chr_to_str(&a, &l, c);		\
+	if (c >= ' ' && c != 127/* && c != 155*/) {					\
+		int charset = s->charset;						\
+											\
+		if (ch >> 15) {								\
+			int frames_charset = (s->mode == TERM_LINUX || s->mode == TERM_VT100 || s->mode == TERM_FREEBSD) \
+						? get_cp_index("cp437")			\
+						: s->mode == TERM_KOI8			\
+						? get_cp_index("koi8-r")		\
+						: -1;					\
+			if (frames_charset != -1) charset = frames_charset;		\
+		}									\
+		if (s->utf_8_io) add_to_str(&a, &l, cp2utf_8(charset, c));		\
+		else add_chr_to_str(&a, &l, c);						\
+	}										\
 	else if (!c || c == 1) add_chr_to_str(&a, &l, ' ');				\
 	else add_chr_to_str(&a, &l, '.');						\
 	cx++;										\
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.