about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GridText.c1715
-rw-r--r--src/GridText.h28
-rw-r--r--src/HTFWriter.c63
-rw-r--r--src/HTInit.c216
-rw-r--r--src/HTML.c818
-rw-r--r--src/HTML.h19
-rw-r--r--src/HTNestedList.h5
-rw-r--r--src/LYCharSets.c7
-rw-r--r--src/LYCharUtils.c156
-rw-r--r--src/LYCharUtils.h45
-rw-r--r--src/LYCurses.h2
-rw-r--r--src/LYDownload.c32
-rw-r--r--src/LYEditmap.c2
-rw-r--r--src/LYForms.c26
-rw-r--r--src/LYGetFile.c28
-rw-r--r--src/LYGetFile.h2
-rw-r--r--src/LYGlobalDefs.h2
-rw-r--r--src/LYHistory.c162
-rw-r--r--src/LYHistory.h1
-rw-r--r--src/LYKeymap.c10
-rw-r--r--src/LYLocal.c2
-rw-r--r--src/LYMain.c80
-rw-r--r--src/LYMainLoop.c107
-rw-r--r--src/LYMap.c33
-rw-r--r--src/LYNews.c7
-rw-r--r--src/LYOptions.c87
-rw-r--r--src/LYPrint.c17
-rw-r--r--src/LYReadCFG.c104
-rw-r--r--src/LYStrings.c173
-rw-r--r--src/LYStrings.h4
-rw-r--r--src/LYUtils.c62
-rw-r--r--src/TRSTable.c1335
-rw-r--r--src/TRSTable.h15
-rw-r--r--src/UCAuto.c16
-rw-r--r--src/UCAux.c64
-rw-r--r--src/chrtrans/cp1250_uni.tbl41
-rw-r--r--src/chrtrans/cp1252_uni.tbl28
-rw-r--r--src/chrtrans/cp437_uni.tbl39
-rw-r--r--src/chrtrans/cp737_uni.tbl24
-rw-r--r--src/chrtrans/cp850_uni.tbl54
-rw-r--r--src/chrtrans/cp852_uni.tbl61
-rw-r--r--src/chrtrans/def7_uni.tbl213
-rw-r--r--src/chrtrans/iso01_uni.tbl26
-rw-r--r--src/chrtrans/iso02_uni.tbl40
-rw-r--r--src/chrtrans/iso05_uni.tbl41
-rw-r--r--src/chrtrans/iso07_uni.tbl61
-rw-r--r--src/chrtrans/iso09_uni.tbl32
-rw-r--r--src/chrtrans/koi8r_uni.tbl33
-rw-r--r--src/chrtrans/mac_uni.tbl4
-rw-r--r--src/chrtrans/makeuctb.c43
-rw-r--r--src/makefile.dos2
-rw-r--r--src/makefile.dsl2
-rw-r--r--src/makefile.in2
-rw-r--r--src/makefile.wsl2
54 files changed, 5088 insertions, 1105 deletions
diff --git a/src/GridText.c b/src/GridText.c
index 069da98e..6b89dc21 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -1,4 +1,4 @@
-/*
+/*		Character grid hypertext object
 **		===============================
 */
 
@@ -32,6 +32,7 @@
 #include <LYEdit.h>
 #include <LYPrint.h>
 #include <LYPrettySrc.h>
+#include <TRSTable.h>
 #ifdef EXP_CHARTRANS_AUTOSWITCH
 #include <UCAuto.h>
 #endif /* EXP_CHARTRANS_AUTOSWITCH */
@@ -91,6 +92,8 @@ struct _HTStream {			/* only know it as object */
 #define TITLE_LINES  1
 #define IS_UTF_EXTRA(ch) (text->T.output_utf8 && \
 			  ((unsigned char)(ch)&0xc0) == 0x80)
+#define UTF8_XNEGLEN(c) (c&0xC0? 0 :c&32? 1 :c&16? 2 :c&8? 3 :c&4? 4 :c&2? 5:0)
+#define UTF_XLEN(c) UTF8_XNEGLEN(((char)~(c)))
 
 extern BOOL HTPassHighCtrlRaw;
 extern HTCJKlang HTCJK;
@@ -191,7 +194,7 @@ typedef struct _HTTabID {
 
 
 /*	Notes on struct _Htext:
-**	next_line is valid if state is false.
+**	next_line is valid if stale is false.
 **	top_of_screen line means the line at the top of the screen
 **			or just under the title if there is one.
 */
@@ -219,6 +222,7 @@ struct _HText {
 	int			chars;		/* Number of them */
 	TextAnchor *		first_anchor;	/* Singly linked list */
 	TextAnchor *		last_anchor;
+	TextAnchor *		last_anchor_before_stbl;
 	HTList *		forms;		/* also linked internally */
 	int			last_anchor_number;	/* user number */
 	BOOL			source;		/* Is the text source? */
@@ -240,10 +244,12 @@ struct _HText {
 	BOOL			in_line_1;		/* of paragraph */
 	BOOL			stale;			/* Must refresh */
 	BOOL			page_has_target; /* has target on screen */
+	BOOL			has_utf8; /* has utf-8 on screen or line */
 #ifdef DISP_PARTIAL
 	int			first_lineno_last_disp_partial;
 	int			last_lineno_last_disp_partial;
 #endif
+	STable_info *		stbl;
 
 	HTkcode			kcode;			/* Kanji code? */
 	enum grid_state       { S_text, S_esc, S_dollar, S_paren,
@@ -350,6 +356,8 @@ PRIVATE char underscore_string[MAX_LINE + 1];
 PUBLIC char star_string[MAX_LINE + 1];
 
 PRIVATE int ctrl_chars_on_this_line = 0; /* num of ctrl chars in current line */
+PRIVATE int utfxtra_on_this_line = 0; /* num of UTF-8 extra bytes in line,
+				       they *also* count as ctrl chars. */
 
 PRIVATE HTStyle default_style =
 	{ 0,  "(Unstyled)", "",
@@ -883,18 +891,36 @@ PUBLIC void HText_free ARGS1(
 /*	Output a line
 **	-------------
 */
-PRIVATE int display_line ARGS2(
+PRIVATE int display_line ARGS4(
 	HTLine *,	line,
-	HText *,	text)
+	HText *,	text,
+	int,		scrline GCC_UNUSED,
+	CONST char*,	target)
 {
     register int i, j;
     char buffer[7];
     char *data;
     size_t utf_extra = 0;
+    char LastDisplayChar = ' ';
 #ifdef USE_COLOR_STYLE
     int current_style = 0;
+#define inunderline NO
+#define inbold NO
+#else
+    BOOL inbold=NO, inunderline=NO;
+#endif
+#if defined(SHOW_WHEREIS_TARGETS) && !defined(USE_COLOR_STYLE)
+    CONST char *cp_tgt;
+    int i_start_tgt=0, i_after_tgt;
+    int HitOffset, LenNeeded;
+    BOOL intarget=NO;
+#else
+#define intarget NO
+#endif /* SHOW_WHEREIS_TARGETS && !USE_COLOR_STYLE */
+
+#ifndef NCURSES_VERSION
+    text->has_utf8 = NO; /* use as per-line flag, except with ncurses */
 #endif
-    char LastDisplayChar = ' ';
 
     /*
      *  Set up the multibyte character buffer,
@@ -930,7 +956,75 @@ PRIVATE int display_line ARGS2(
      */
     data = line->data;
     i++;
+
+#ifndef USE_COLOR_STYLE
+#if defined(SHOW_WHEREIS_TARGETS)
+    /*
+     *  If the target is on this line, it will be emphasized.
+     */
+    i_after_tgt = i;
+    if (target) {
+	if (case_sensitive)
+	    cp_tgt = LYno_attr_mbcs_strstr(data,
+					   target,
+					   text->T.output_utf8,
+					   &HitOffset,
+					   &LenNeeded);
+	else
+	    cp_tgt = LYno_attr_mbcs_case_strstr(data,
+						target,
+						text->T.output_utf8,
+						&HitOffset,
+						&LenNeeded);
+	if (cp_tgt) {
+	    if (((int)line->offset + LenNeeded) >= LYcols) {
+		cp_tgt = NULL;
+	    } else {
+		text->page_has_target = YES;
+		i_start_tgt = i + HitOffset;
+		i_after_tgt = i + LenNeeded;
+	    }
+	}
+    } else {
+	cp_tgt = NULL;
+    }
+#endif /* SHOW_WHEREIS_TARGETS */
+#endif /* USE_COLOR_STYLE */
+
     while ((i < LYcols) && ((buffer[0] = *data) != '\0')) {
+
+#ifndef USE_COLOR_STYLE
+#if defined(SHOW_WHEREIS_TARGETS)
+	if (cp_tgt && i >= i_after_tgt) {
+	    if (intarget) {
+
+		if (case_sensitive)
+		    cp_tgt = LYno_attr_mbcs_strstr(data,
+						target,
+						text->T.output_utf8,
+						&HitOffset,
+						&LenNeeded);
+		else
+		    cp_tgt = LYno_attr_mbcs_case_strstr(data,
+						     target,
+						text->T.output_utf8,
+						&HitOffset,
+						&LenNeeded);
+		if (cp_tgt) {
+		    i_start_tgt = i + HitOffset;
+		    i_after_tgt = i + LenNeeded;
+		}
+		if (!cp_tgt || i_start_tgt != i) {
+		    LYstopTargetEmphasis();
+		    intarget = NO;
+		    if (inbold)		start_bold();
+		    if (inunderline)	start_underline();
+		}
+	    }
+	}
+#endif /* SHOW_WHEREIS_TARGETS */
+#endif /* USE_COLOR_STYLE */
+
 	data++;
 
 #if defined(USE_COLOR_STYLE) || defined(SLSC)
@@ -951,14 +1045,17 @@ PRIVATE int display_line ARGS2(
 		    addch('_');
 		    i++;
 		} else {
+		    inunderline = YES;
+		    if (!intarget) {
 #if (defined(DOSPATH) || defined(WIN_EX)) && !defined(USE_SLANG)
-		    if (LYShowColor == SHOW_COLOR_NEVER)
-			start_bold();
-		    else
-			start_underline();
+			if (LYShowColor == SHOW_COLOR_NEVER)
+			    start_bold();
+			else
+			    start_underline();
 #else
-		    start_underline();
+			start_underline();
 #endif	/* DOSPATH ... */
+		    }
 		}
 		break;
 
@@ -967,6 +1064,8 @@ PRIVATE int display_line ARGS2(
 		    addch('_');
 		    i++;
 		} else {
+		    inunderline = NO;
+		    if (!intarget) {
 #if (defined(DOSPATH) || defined(WIN_EX)) && !defined(USE_SLANG)
 		    if (LYShowColor == SHOW_COLOR_NEVER)
 			stop_bold();
@@ -975,15 +1074,20 @@ PRIVATE int display_line ARGS2(
 #else
 		    stop_underline();
 #endif	/* DOSPATH ... */
+		    }
 		}
 		break;
 
 	    case LY_BOLD_START_CHAR:
-		start_bold();
+		inbold = YES;
+		if (!intarget)
+		    start_bold();
 		break;
 
 	    case LY_BOLD_END_CHAR:
-		stop_bold ();
+		inbold = NO;
+		if (!intarget)
+		    stop_bold();
 		break;
 
 #endif
@@ -1014,12 +1118,25 @@ PRIVATE int display_line ARGS2(
 		     *  Make it a hard hyphen and fall through. - FM
 		     */
 		    buffer[0] = '-';
-		    i++;
 		}
 
 	    default:
+#ifndef USE_COLOR_STYLE
+#if defined(SHOW_WHEREIS_TARGETS)
+		if (!intarget && cp_tgt && i >= i_start_tgt) {
+		    /*
+		     *  Start the emphasis.
+		     */
+		    if (data > cp_tgt) {
+			LYstartTargetEmphasis();
+			intarget = YES;
+		    }
+		}
+#endif /* SHOW_WHEREIS_TARGETS */
+#endif /* USE_COLOR_STYLE */
 		i++;
 		if (text->T.output_utf8 && !isascii(buffer[0])) {
+		    text->has_utf8 = YES;
 		    if ((*buffer & 0xe0) == 0xc0) {
 			utf_extra = 1;
 		    } else if ((*buffer & 0xf0) == 0xe0) {
@@ -1057,6 +1174,7 @@ PRIVATE int display_line ARGS2(
 		     */
 		    buffer[1] = *data;
 		    data++;
+		    i++;
 		    addstr(buffer);
 		    buffer[1] = '\0';
 		    /*
@@ -1072,17 +1190,42 @@ PRIVATE int display_line ARGS2(
 		     */
 		    LastDisplayChar = 'M';
 		} else {
+#if 0	/* last-ditch attempt to prevent 0x9B to screen - disabled  */
+#if defined(UNIX) || defined(VMS)
+		    if (!dump_output_immediately &&
+			(unsigned char)buffer[0] == 128+27) {
+			addstr("~^");
+			buffer[0] ^= 0xc0;
+		    }
+#endif
+#endif
 		    addstr(buffer);
 		    LastDisplayChar = buffer[0];
 		}
 	} /* end of switch */
     } /* end of while */
 
+#if !defined(NCURSES_VERSION)
+    if (text->has_utf8) {
+#ifdef USE_SLANG
+	SLsmg_touch_lines(scrline, 1);
+#else
+	touchline(stdscr, scrline, 1);
+#endif
+	text->has_utf8 = NO;	/* we had some, but have dealt with it. */
+    }
+#endif
     /*
      *  Add the return.
      */
     addch('\n');
 
+#if defined(SHOW_WHEREIS_TARGETS) && !defined(USE_COLOR_STYLE)
+    if (intarget)
+	LYstopTargetEmphasis();
+#else
+#undef intarget
+#endif /* SHOW_WHEREIS_TARGETS && !USE_COLOR_STYLE */
 #ifndef USE_COLOR_STYLE
     stop_underline();
     stop_bold();
@@ -1258,63 +1401,45 @@ PRIVATE void display_scrollbar ARGS1(
     int i;
     int h = display_lines - 2 * (LYsb_arrow!=0); /* Height of the scrollbar */
     int off = (LYsb_arrow != 0);		 /* Start of the scrollbar */
-    int top_skip, bot_skip, sh;
+    int top_skip, bot_skip, sh, shown;
 
     LYsb_begin = LYsb_end = -1;
     if (!LYsb || !text || h <= 2
 	|| (text->Lines + 1) <= display_lines)
 	return;
 
+    if (text->top_of_screen >= text->Lines + 1 - display_lines) {
+	/* Only part of the screen shows actual text */
+	shown = text->Lines + 1 - text->top_of_screen;
+
+	if (shown <= 0)
+	    shown = 1;
+    } else
+	shown = display_lines;
     /* Each cell of scrollbar represents text->Lines/h lines of text. */
     /* Always smaller than h */
-    sh = (display_lines*h + text->Lines/2)/(text->Lines + 1);
+    sh = (shown*h + text->Lines/2)/(text->Lines + 1);
     if (sh <= 0)
 	sh = 1;
-    if (sh >= h)
-	sh = h - 1;
-
-    /* Always non-zero if not top, which is text->top_of_screen != 0 . */
-    top_skip = (text->top_of_screen * h + text->Lines)/(text->Lines + 1);
-    if (top_skip >= h)
-	top_skip = h - 1;
-
-    /* End happens when
-       (text->Lines + 1 - (text->top_of_screen + display_lines - 1))
-       is either 0 or 1. */
-    bot_skip =
-	(text->Lines + 1 - (text->top_of_screen + display_lines - 1) - 1);
-    if (bot_skip < 0)
-	bot_skip = 0;
-    bot_skip = (bot_skip * h + text->Lines)/(text->Lines + 1);
-
-    /* Now make sure the height is always sh unless top_skip==bot_skip==1  */
-    if (top_skip + bot_skip + sh != h && !(top_skip == 1 && bot_skip == 1)) {
-	/* One which is smaller takes precedence. */
-	if (top_skip < bot_skip) {
-	    int t = h - top_skip - sh;
-
-	    if (t < top_skip)
-		bot_skip = top_skip;
-	    else
-		bot_skip = t;
-	} else {
-	    int t = h - bot_skip - sh;
+    if (sh >= h - 1)
+	sh = h - 2;		/* Position at ends indicates BEG and END */
 
-	    if (t < bot_skip)
-		top_skip = bot_skip;
-	    else
-		top_skip = t;
-	}
-    }
-    /* Ensure the bar is visible if h >= 3 */
-    if (top_skip + bot_skip >= h)
-	bot_skip = h - top_skip;
-    if (top_skip + bot_skip == h && h >= 3) {
-	if (bot_skip > 1)
-	    bot_skip--;
-	else
-	    top_skip--;
+    if (text->top_of_screen == 0)
+	top_skip = 0;
+    else if (text->Lines - (text->top_of_screen + display_lines - 1) <= 0)
+	top_skip = h - sh;
+    else {
+	/* text->top_of_screen between 1 and text->Lines - display_lines
+	   corresponds to top_skip between 1 and h - sh - 1 */
+	/* Use rounding to get as many positions into top_skip==h - sh - 1
+	   as into top_skip == 1:
+	   1--->1, text->Lines - display_lines + 1--->h - sh. */
+	top_skip = 1 +
+	    1. * (h - sh - 1) * text->top_of_screen
+		/(text->Lines - display_lines + 1);
     }
+    bot_skip = h - sh - top_skip;
+
     LYsb_begin = top_skip;
     LYsb_end = h - bot_skip;
 
@@ -1391,12 +1516,13 @@ PRIVATE void display_page ARGS3(
 {
     HTLine * line = NULL;
     int i;
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#if defined(USE_COLOR_STYLE) && defined(SHOW_WHEREIS_TARGETS)
     char *cp;
 #endif
     char tmp[7];
     int last_screen;
     TextAnchor *Anchor_ptr = NULL;
+    int stop_before_for_anchors;
     FormInfo *FormInfo_ptr;
     BOOL display_flag = FALSE;
     HTAnchor *link_dest;
@@ -1435,6 +1561,7 @@ PRIVATE void display_page ARGS3(
 #endif /* DISP_PARTIAL */
 
     tmp[0] = tmp[1] = tmp[2] = '\0';
+    if (target && *target == '\0') target = NULL;
     text->page_has_target = NO;
     if (display_lines <= 0) {
 	/*  No screen space to display anything!
@@ -1522,6 +1649,7 @@ PRIVATE void display_page ARGS3(
 #endif
 
     text->top_of_screen = line_number;
+    text->top_of_screen_line = line;
     display_title(text);  /* will move cursor to top of screen */
     display_flag=TRUE;
 
@@ -1534,11 +1662,20 @@ PRIVATE void display_page ARGS3(
     LynxResetScreenCache();
 #endif /* USE_COLOR_STYLE */
 
+#ifdef DISP_PARTIAL
+    if (display_partial && text->stbl) {
+	stop_before_for_anchors = Stbl_getStartLine(text->stbl);
+	if (stop_before_for_anchors > line_number+(display_lines))
+	    stop_before_for_anchors = line_number+(display_lines);
+    } else
+#endif
+	stop_before_for_anchors = line_number+(display_lines);
+
     /*
      *  Output the page.
      */
     if (line) {
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#if defined(USE_COLOR_STYLE) && defined(SHOW_WHEREIS_TARGETS)
 	char *data;
 	int offset, HitOffset, LenNeeded;
 #endif
@@ -1571,9 +1708,10 @@ PRIVATE void display_page ARGS3(
 		move((i + 2), 0);
 	    else
 #endif
-	    display_line(line, text);
+	    display_line(line, text, i+1, target);
 
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#if defined(SHOW_WHEREIS_TARGETS)
+#ifdef USE_COLOR_STYLE		/* otherwise done in display_line - kw */
 	    /*
 	     *  If the target is on this line, recursively
 	     *  seek and emphasize it. - FM
@@ -1619,59 +1757,15 @@ PRIVATE void display_page ARGS3(
 			 */
 			x_pos--;
 
-		    } else if (cp == &data[itmp]) {
-			/*
-			 *  First printable character of target.
-			 */
-			move((i + 1), x_pos);
-			if (text->T.output_utf8 && !isascii(tmp[0])) {
-			    if ((*tmp & 0xe0) == 0xc0) {
-				utf_extra = 1;
-			    } else if ((*tmp & 0xf0) == 0xe0) {
-				utf_extra = 2;
-			    } else if ((*tmp & 0xf8) == 0xf0) {
-				utf_extra = 3;
-			    } else if ((*tmp & 0xfc) == 0xf8) {
-				utf_extra = 4;
-			    } else if ((*tmp & 0xfe) == 0xfc) {
-				utf_extra = 5;
-			    } else {
-				/*
-				 *  Garbage.
-				 */
-				utf_extra = 0;
-			    }
-			    if (strlen(&line->data[itmp+1]) < utf_extra) {
-				/*
-				 *  Shouldn't happen.
-				 */
-				utf_extra = 0;
-			    }
-			}
-			if (utf_extra) {
-			    strncpy(&tmp[1], &line->data[itmp+1], utf_extra);
-			    tmp[utf_extra+1] = '\0';
-			    itmp += utf_extra;
-			    addstr(tmp);
-			    tmp[1] = '\0';
-			    written += (utf_extra + 1);
-			    utf_extra = 0;
-			} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		    } else if (&data[itmp] >= cp) {
+			if (cp == &data[itmp]) {
 			    /*
-			     *  For CJK strings, by Masanobu Kimura.
+			     *  First printable character of target.
 			     */
-			    tmp[1] = data[++itmp];
-			    addstr(tmp);
-			    tmp[1] = '\0';
-			    written += 2;
-			} else {
-			    addstr(tmp);
-			    written++;
+			    move((i + 1), x_pos);
 			}
-
-		    } else if (&data[itmp] > cp) {
 			/*
-			 *  Output all the other printable target chars.
+			 *  Output all the printable target chars.
 			 */
 			if (text->T.output_utf8 && !isascii(tmp[0])) {
 			    if ((*tmp & 0xe0) == 0xc0) {
@@ -1714,6 +1808,15 @@ PRIVATE void display_page ARGS3(
 			    tmp[1] = '\0';
 			    written += 2;
 			} else {
+#if 0	/* last-ditch attempt to prevent 0x9B to screen - disabled  */
+#if defined(UNIX) || defined(VMS)
+			    if (!dump_output_immediately &&
+				(unsigned char)tmp[0] == 128+27) {
+				addstr("~^");
+				tmp[0] ^= 0xc0;
+			    }
+#endif
+#endif
 			    addstr(tmp);
 			    written++;
 			}
@@ -1736,7 +1839,8 @@ PRIVATE void display_page ARGS3(
 		 */
 		move((i + 2), 0);
 	    } /* end while */
-#endif /* FANCY CURSES || USE_SLANG */
+#endif /* USE_COLOR_STYLE */
+#endif /* SHOW_WHEREIS_TARGETS */
 
 	    /*
 	     *  Stop if this is the last line.  Otherwise, make sure
@@ -1774,11 +1878,11 @@ PRIVATE void display_page ARGS3(
      */
     nlinks = 0;
     for (Anchor_ptr=text->first_anchor;  Anchor_ptr != NULL &&
-		Anchor_ptr->line_num <= line_number+(display_lines);
+		Anchor_ptr->line_num <= stop_before_for_anchors;
 					    Anchor_ptr = Anchor_ptr->next) {
 
 	if (Anchor_ptr->line_num >= line_number &&
-		Anchor_ptr->line_num < line_number+(display_lines)) {
+		Anchor_ptr->line_num < stop_before_for_anchors) {
 	    /*
 	     *  Load normal hypertext anchors.
 	     */
@@ -1968,11 +2072,19 @@ PRIVATE void display_page ARGS3(
     }
 #endif /* DISP_PARTIAL */
 
-    if (HTCJK != NOCJK) {
+    if (text->has_utf8) {
+	/*
+	 *  For other than ncurses, repainting is taken care of
+	 *  by touching lines in display_line and highlight. - kw 1999-10-07
+	 */
+	clearok(curscr, TRUE);
+    } else if (HTCJK != NOCJK) {
 	/*
 	 *  For non-multibyte curses.
+	 *
+	 *  Is this repainting necessary??  Let's try without.
 	 */
-	lynx_force_repaint();
+	/*clearok(curscr, TRUE);*/
     }
     refresh();
 
@@ -1993,6 +2105,17 @@ PUBLIC void HText_beginAppend ARGS1(
 }
 
 
+/* LYcols_cu is the notion that the display library has of the screen
+   width.  Normally it is the same as LYcols, but there may be a
+   difference via SLANG_MBCS_HACK.  LYcols_cu is used to try to prevent
+   that the display library wraps or truncates a line with UTF-8 chars
+   when it shouldn't. - kw */
+#ifdef USE_SLANG
+#define LYcols_cu SLtt_Screen_Cols
+#else
+#define LYcols_cu LYcols
+#endif
+
 /*	Add a new line of text
 **	----------------------
 **
@@ -2037,6 +2160,7 @@ PRIVATE void split_line ARGS2(
      */
     HTLine * previous = text->last_line;
     int ctrl_chars_on_previous_line = 0;
+    int utfxtra_on_previous_line = utfxtra_on_this_line;
     char * cp;
     /* can't wrap in middle of multibyte sequences, so allocate 2 extra */
     HTLine * line = (HTLine *)LY_CALLOC(1, LINE_SIZE(MAX_LINE)+2);
@@ -2044,6 +2168,7 @@ PRIVATE void split_line ARGS2(
 	outofmem(__FILE__, "split_line_1");
 
     ctrl_chars_on_this_line = 0; /*reset since we are going to a new line*/
+    utfxtra_on_this_line = 0;	/*reset too, we'll count them*/
     text->LastChar = ' ';
 
 #ifdef DEBUG_APPCH
@@ -2218,14 +2343,16 @@ PRIVATE void split_line ARGS2(
 	    for (i = (plen - 1); i >= 0; i--) {
 		if (p[i] == LY_BOLD_START_CHAR ||
 		    p[i] == LY_BOLD_END_CHAR ||
-		    IS_UTF_EXTRA(p[i]) ||
 		    p[i] == LY_SOFT_HYPHEN) {
 		    ctrl_chars_on_this_line++;
+		} else if (IS_UTF_EXTRA(p[i])) {
+		    utfxtra_on_this_line++;
 		}
 		if (p[i] == LY_SOFT_HYPHEN && (int)text->permissible_split < i) {
 		    text->permissible_split = i + 1;
 		}
 	    }
+	    ctrl_chars_on_this_line += utfxtra_on_this_line;
 	}
 
 	/*
@@ -2450,13 +2577,12 @@ PRIVATE void split_line ARGS2(
      *  Align left, right or center.
      */
     spare = 0;
-    ctrl_chars_on_previous_line = 0; /* - VH */
     if (
 #ifdef EXP_JUSTIFY_ELTS
 	this_line_was_splitted ||
 #endif
 	(style->alignment == HT_CENTER ||
-	 style->alignment == HT_RIGHT) ) {
+	 style->alignment == HT_RIGHT) || text->stbl) {
 	/* Calculate spare character positions if needed */
 	for (cp = previous->data; *cp; cp++) {
 	    if (*cp == LY_UNDERLINE_START_CHAR ||
@@ -2466,17 +2592,56 @@ PRIVATE void split_line ARGS2(
 		IS_UTF_EXTRA(*cp) ||
 		*cp == LY_SOFT_HYPHEN)
 		ctrl_chars_on_previous_line++;
+	    if ((previous->size > 0) &&
+		(int)(previous->data[previous->size-1] == LY_SOFT_HYPHEN))
+		ctrl_chars_on_previous_line--;
 	}
 	/* @@ first line indent */
 	spare =  (LYcols-1) -
 	    (int)style->rightIndent - indent +
-	    ctrl_chars_on_previous_line - previous->size -
-	    ((previous->size > 0) &&
-	     (int)(previous->data[previous->size-1] ==
-		   LY_SOFT_HYPHEN ?
-		   1 : 0));
+	    ctrl_chars_on_previous_line - previous->size;
+	if (spare > 0 && text->T.output_utf8 && ctrl_chars_on_previous_line) {
+	    utfxtra_on_previous_line -= utfxtra_on_this_line;
+	    if (utfxtra_on_previous_line) {
+		int spare_cu = (LYcols_cu-1) -
+		    utfxtra_on_previous_line - indent +
+		    ctrl_chars_on_previous_line - previous->size;
+		    /*
+		     *  Shift non-leftaligned UTF-8 lines that would be
+		     *  mishandled by the display library towards the left
+		     *  if this would make them fit.  The resulting display
+		     *  will not be as intended, but this is better than
+		     *  having them split by curses.  (But that may still
+		     *  happen anyway by curses space movement optimization).
+		     * - kw
+		     */
+		if (spare_cu < spare) {
+		    if (spare_cu >= 0) {
+			spare = spare_cu;
+		    } else if (indent + (int)previous->offset + spare_cu >= 0)
+		    { /* subtract overdraft from effective indentation */
+			indent += (int)previous->offset + spare_cu;
+			previous->offset = 0;
+			spare = 0;
+		    }
+		}
+	    }
+	}
     }
 
+    if (text->stbl)
+	/*
+	 *  Notify simple table stuff of line split, so that it can
+	 *  set the last cell's length.  The last cell should and
+	 *  its row should really end here, or on one of the following
+	 *  lines with no more characters added after the break.
+	 *  We don't know whether a cell has been started, so ignore
+	 *  errors here. - kw
+	 */
+	Stbl_lineBreak(text->stbl,
+		       text->Lines - 1,
+		       previous->size - ctrl_chars_on_previous_line);
+
     switch (style->alignment) {
 	case HT_CENTER :
 	    previous->offset = previous->offset + indent + spare/2;
@@ -3014,7 +3179,7 @@ PUBLIC void HText_appendCharacter ARGS2(
 {
     HTLine * line;
     HTStyle * style;
-    int indent;
+    int indent, utfx;
 
 #ifdef DEBUG_APPCH
 #ifdef CJK_EX
@@ -3141,6 +3306,7 @@ PUBLIC void HText_appendCharacter ARGS2(
     style = text->style;
 
     indent = text->in_line_1 ? (int)style->indent1st : (int)style->leftIndent;
+    utfx = utfxtra_on_this_line;
 
     if (HTCJK != NOCJK) {
 	switch(text->state) {
@@ -3293,7 +3459,8 @@ PUBLIC void HText_appendCharacter ARGS2(
     }
 
 #ifdef CJK_EX	/* MOJI-BAKE Fix! 1997/10/12 -- 10/31 (Fri) 00:22:57 - JH7AYN */
-    if (ch == LY_BOLD_START_CHAR || ch == LY_BOLD_END_CHAR) {
+    if (HTCJK != NOCJK &&	/* added condition - kw */
+	(ch == LY_BOLD_START_CHAR || ch == LY_BOLD_END_CHAR)) {
 	text->permissible_split = (int)line->size;	/* Can split here */
 	if (HTCJK == JAPANESE)
 	    text->kcode = NOKANJI;
@@ -3371,11 +3538,66 @@ PUBLIC void HText_appendCharacter ARGS2(
 	return;
     }
 
-    if (IS_UTF_EXTRA(ch)) {
-	line->data[line->size++] = ch;
-	line->data[line->size] = '\0';
-	ctrl_chars_on_this_line++;
-	return;
+    if (text->T.output_utf8) {
+	if (IS_UTF_EXTRA(ch)) {
+	    if ((line->size > (MAX_LINE-1))
+		|| (indent + (int)(line->offset + line->size) +
+		    utfx - ctrl_chars_on_this_line +
+		    ((line->size > 0) &&
+		     (int)(line->data[line->size-1] ==
+				LY_SOFT_HYPHEN ?
+					     1 : 0)) >= (LYcols_cu-1))
+		) {
+		if (!text->permissible_split || text->source) {
+		    text->permissible_split = line->size;
+		    while (text->permissible_split > 0 &&
+			   IS_UTF_EXTRA(line->data[text->permissible_split-1]))
+			text->permissible_split--;
+		    if (text->permissible_split &&
+			(line->data[text->permissible_split-1] & 0x80))
+			text->permissible_split--;
+		    if (text->permissible_split == line->size)
+			text->permissible_split = 0;
+		}
+		split_line(text, text->permissible_split);
+		line = text->last_line;
+		if (text->source && line->size - ctrl_chars_on_this_line
+		    + utfxtra_on_this_line == 0)
+		    HText_appendCharacter (text, LY_SOFT_NEWLINE);
+	    }
+	    line->data[line->size++] = ch;
+	    line->data[line->size] = '\0';
+	    utfxtra_on_this_line++;
+	    ctrl_chars_on_this_line++;
+	    return;
+	} else if (ch & 0x80) {
+	    if ((line->size > (MAX_LINE-7))
+#if 0	/* the equivalent should already happen below */
+		|| (indent + (int)(line->offset + line->size) +
+		    utfx - ctrl_chars_on_this_line +
+		    ((line->size > 0) &&
+		     (int)(line->data[line->size-1] ==
+				LY_SOFT_HYPHEN ?
+					     1 : 0)) >= (LYcols_cu))
+#endif /* 0 */
+		) {
+		if (!text->permissible_split || text->source) {
+		    text->permissible_split = line->size;
+		    while (text->permissible_split > 0 &&
+			   (line->data[text->permissible_split-1] & 0x80)
+			   == 0xC0) {
+			text->permissible_split--;
+		    }
+		    if (text->permissible_split == line->size)
+			text->permissible_split = 0;
+		}
+		split_line(text, text->permissible_split);
+		line = text->last_line;
+		if (text->source && line->size - ctrl_chars_on_this_line
+		    + utfxtra_on_this_line == 0)
+		    HText_appendCharacter (text, LY_SOFT_NEWLINE);
+	    }
+	}
     }
 
     /*
@@ -3432,8 +3654,8 @@ PUBLIC void HText_appendCharacter ARGS2(
      */
     if (ch == '\t') {
 	CONST HTTabStop * Tab;
-	int target;	/* Where to tab to */
-	int here;
+	int target, target_cu;	/* Where to tab to */
+	int here, here_cu;	/* in _cu we try to guess what curses thinks */
 
 	if (line->size > 0 && line->data[line->size-1] == LY_SOFT_HYPHEN) {
 	    /*
@@ -3445,6 +3667,7 @@ PUBLIC void HText_appendCharacter ARGS2(
 	}
 	here = ((int)(line->size + line->offset) + indent)
 		- ctrl_chars_on_this_line; /* Consider special chars GAB */
+	here_cu = here + utfxtra_on_this_line;
 	if (style->tabs) {	/* Use tab table */
 	    for (Tab = style->tabs;
 		Tab->position <= here;
@@ -3472,6 +3695,11 @@ PUBLIC void HText_appendCharacter ARGS2(
 #endif
 	}
 
+	if (target >= here)
+	    target_cu = target;
+	else
+	    target_cu = target + (here_cu - here);
+
 	if (target > (LYcols-1) - (int)style->rightIndent &&
 	    HTOutputFormat != WWW_SOURCE) {
 	    new_line(text);
@@ -3480,6 +3708,8 @@ PUBLIC void HText_appendCharacter ARGS2(
 	     *  Can split here. - FM
 	     */
 	    text->permissible_split = line->size;
+	    if (target_cu > (LYcols-1))
+		target -= target_cu - (LYcols-1);
 	    if (line->size == 0) {
 		line->offset = line->offset + target - here;
 	    } else {
@@ -3492,14 +3722,17 @@ PUBLIC void HText_appendCharacter ARGS2(
 	}
 	return;
     } /* if tab */
-    else {
+    else if (text->source && text == HTMainText) {
 	/*
 	 * If we're displaying document source, wrap long lines to keep all of
 	 * the source visible.
 	 */
 	int target = (int)(line->offset + line->size) - ctrl_chars_on_this_line;
-	if ((target >= (LYcols-1) - style->rightIndent) &&
-		HTisDocumentSource()) {
+	int target_cu = target + utfxtra_on_this_line;
+	if (target >= (LYcols-1) - style->rightIndent ||
+	    (text->T.output_utf8 &&
+	     target_cu + UTF_XLEN(ch) >= (LYcols_cu-1))
+	    ) {
 	    new_line(text);
 	    line = text->last_line;
 	    HText_appendCharacter (text, LY_SOFT_NEWLINE);
@@ -3524,8 +3757,10 @@ PUBLIC void HText_appendCharacter ARGS2(
      */
 check_IgnoreExcess:
     if (text->IgnoreExcess &&
-	((indent + (int)line->offset + (int)line->size) +
-	(int)style->rightIndent - ctrl_chars_on_this_line) >= (LYcols-1))
+	(((indent + (int)line->offset + (int)line->size) +
+	  (int)style->rightIndent - ctrl_chars_on_this_line) >= (LYcols-1) ||
+	 ((indent + (int)line->offset + (int)line->size) +
+	  utfxtra_on_this_line - ctrl_chars_on_this_line) >= (LYcols_cu-1)))
 	return;
 
     /*
@@ -3536,7 +3771,15 @@ check_IgnoreExcess:
 	 ((line->size > 0) &&
 	  (int)(line->data[line->size-1] ==
 				LY_SOFT_HYPHEN ?
-					     1 : 0))) >= (LYcols - 1)) {
+					     1 : 0))) >= (LYcols - 1) ||
+	(text->T.output_utf8 &&
+	 (((indent + (int)line->offset + (int)line->size) +
+	   utfxtra_on_this_line - ctrl_chars_on_this_line +
+	   UTF_XLEN(ch) +
+	   ((line->size > 0) &&
+	    (int)(line->data[line->size-1] ==
+				LY_SOFT_HYPHEN ?
+					     1 : 0))) >= (LYcols_cu - 1)))) {
 
 	if (style->wordWrap && HTOutputFormat != WWW_SOURCE) {
 #ifdef EXP_JUSTIFY_ELTS
@@ -3746,8 +3989,26 @@ PUBLIC void _internal_HTC ARGS3(HText *,text, int,style, int,dir)
 
 	line = text->last_line;
 
-	if (line->numstyles < MAX_STYLES_ON_LINE) {
+	if (line->numstyles > 0 && dir == 0 &&
+	    line->styles[line->numstyles].direction &&
+	    line->styles[line->numstyles].style == style &&
+	    line->styles[line->numstyles].horizpos
+	    == (int)line->size - ctrl_chars_on_this_line) {
+	    /*
+	     *  If this is an OFF change directly preceded by an
+	     *	ON for the same style, just remove the previous one. - kw
+	     */
+	    line->numstyles--;
+	} else if (line->numstyles < MAX_STYLES_ON_LINE) {
 	    line->styles[line->numstyles].horizpos  = line->size;
+	    /*
+	     *  Special chars for bold and underlining usually don't
+	     *  occur with color style, but soft hyphen can.
+	     *  And in UTF-8 display mode all non-initial bytes are
+	     *  counted as ctrl_chars. - kw
+	     */
+	    if (line->styles[line->numstyles].horizpos >= ctrl_chars_on_this_line)
+		line->styles[line->numstyles].horizpos -= ctrl_chars_on_this_line;
 	    line->styles[line->numstyles].style     = style;
 	    line->styles[line->numstyles].direction = dir;
 	    line->numstyles++;
@@ -3796,6 +4057,475 @@ PUBLIC void HText_setIgnoreExcess ARGS2(
     text->IgnoreExcess = ignore;
 }
 
+/*		Simple table handling - private
+**		-------------------------------
+*/
+
+/*
+ *  Given a line and two int arrays of old/now position, this function
+ *  does the actual work of creating a new line where spaces have been
+ *  inserted in appropriate places - so that characters at/after the old
+ *  position end up at/after the new position, for each pair, if possible.
+ *  Some necessary changes for anchors starting on this line are also done
+ *  here if needed.
+ *  Returns a newly allocated HTLine* if changes were made
+ *    (caller has to free the old one).
+ *  Returns NULL if no changes needed.
+ * - kw
+ */
+PRIVATE HTLine * insert_blanks_in_line ARGS6(
+    HTLine *,		line,
+    int,		line_number,
+    HText *,		text,
+    int,		ninserts,
+    int *,		oldpos,
+    int *,		newpos)
+{
+    int i;
+    int ioldb, inewb;		/* count bytes */
+    int ioldc = 0, inewc = 0;	/* count visible characters (positions) */
+    int ip = 0;			/* count oldpos,newpos insertion pairs */
+    int acurshift, ashift = 0;	/* for shifting of anchors in this line */
+#if defined(USE_COLOR_STYLE)
+    int stcurshift, stshift = 0; /* for shifting of styles in this line */
+    int istyle;
+#endif
+    int added_chars = 0;
+    HTLine * mod_line;
+    char * newdata;
+    TextAnchor * a;
+    if (!(line && line->size && ninserts))
+	return NULL;
+    for (i = 0; i < ninserts; i++)
+	if (newpos[i] > oldpos[i] &&
+	    (newpos[i] - oldpos[i]) > added_chars)
+	    added_chars = newpos[i] - oldpos[i];
+    if (line->size + added_chars > MAX_LINE - 2)
+	return NULL;
+    if (line == text->last_line)
+	mod_line = (HTLine *) calloc(1, LINE_SIZE(MAX_LINE));
+    else
+	mod_line = (HTLine *) calloc(1, LINE_SIZE(line->size + added_chars));
+    if (!mod_line)
+	return NULL;
+    memcpy(mod_line, line, LINE_SIZE(1));
+    newdata = mod_line->data;
+    for (ioldb = 0, inewb = 0; ioldb < (int)line->size; ioldb++) {
+	if ((line->data[ioldb] == LY_BOLD_START_CHAR ||
+	     line->data[ioldb] == LY_UNDERLINE_START_CHAR ||
+	     !IsSpecialAttrChar(line->data[ioldb])) &&
+	    (!(text && text->T.output_utf8) ||
+	     (unsigned char)line->data[ioldb] < 128 ||
+	     ((unsigned char)(line->data[ioldb] & 0xc0) == 0xc0))) {
+	    /*
+	     *  A new displayable character starts here.  Time to check
+	     *  whether this is a position to insert spaces.
+	     */
+	    while (ip < ninserts && oldpos[ip] <= ioldc) {
+		if (inewc < newpos[ip]) {
+		    /*
+		     *  Yup, spaces to insert.  We also have to update
+		     *  anchor positions for anchors that start on the
+		     *  same line, this is a pain.  Let's do it first.
+		     *  Note: we rely on a->line_pos counting bytes, not
+		     *  characters.  That's one reason why HText_trimHightext
+		     *  has to be prevented from acting on these anchors in
+		     *  partial display mode before we get a chance to
+		     *  deal with them here.
+		     */
+		    acurshift = 0;
+		    for (a = text->last_anchor_before_stbl ?
+			     text->last_anchor_before_stbl->next :
+			     text->first_anchor;
+			 a && a->line_num <= line_number; a = a->next) {
+			if (a->line_num == line_number)
+			    if (a->line_pos - ashift >= ioldb) {
+				acurshift = newpos[ip] - inewc;
+				a->line_pos += acurshift;
+				a->start += acurshift;
+			    }
+		    }
+		    ashift += acurshift;
+
+		    /*  doing something for color styles here.
+		     *  we rely on horizpos counting characters
+		     *  (display positions), not bytes. */
+#if defined(USE_COLOR_STYLE)
+#define NStyle mod_line->styles[istyle]
+		    stcurshift = 0;
+		    for (istyle = 0; istyle < line->numstyles;
+			 istyle++) {
+			if (NStyle.horizpos - stshift >= ioldc) {
+			    stcurshift = newpos[ip] - inewc;
+			    NStyle.horizpos += stcurshift;
+			}
+		    }
+		    stshift += stcurshift;
+#endif
+		    /*
+		     *  Now insert the spaces.
+		     */
+		    for (; inewc < newpos[ip]; inewc++) {
+			newdata[inewb++] = ' ';
+		    }
+		}
+		ip++;	/* done with this oldpos[ip],newpos[ip] pair. */
+	    }
+	    /*
+	     *  Copy character data over, advance position pointers.
+	     */
+	    newdata[inewb++] = line->data[ioldb];
+	    if (!(line->data[ioldb] == LY_BOLD_START_CHAR ||
+		  line->data[ioldb] == LY_UNDERLINE_START_CHAR)) {
+		ioldc++;
+		inewc++;
+	    }
+	} else {
+	    /*
+	     *  Just copy special attribute chars and utf-8 additional
+	     *  bytes over, don't advance position pointers.
+	     */
+	    newdata[inewb++] = line->data[ioldb];
+	}
+    }
+    newdata[inewb] = '\0';
+    mod_line->size = inewb;
+    return mod_line;
+}
+
+/*
+ *  HText_insertBlanksInStblLines fixes up table lines when simple table
+ *  processing is closed, by calling insert_blanks_in_line for lines
+ *  that need fixup.  Also recalculates alignment for those lines,
+ *  does additional updating of anchor positions, and makes sure the
+ *  display of the lines on screen will be updated after partial display
+ *  upon return to mainloop. - kw
+ */
+PRIVATE int HText_insertBlanksInStblLines ARGS2(
+    HText *,		me,
+    int,		ncols)
+{
+    HTLine *line;
+    HTLine *mod_line, *first_line = NULL;
+    int *	oldpos;
+    int *	newpos;
+    int		ninserts, lineno;
+    int		first_lineno, last_lineno, first_lineno_pass2;
+    int		added_chars_before = 0;
+    TextAnchor * a;
+    int lines_changed = 0;
+    int max_width = 0, indent, spare, table_offset;
+    HTStyle *style;
+    short alignment;
+    int i = 0;
+
+    lineno = first_lineno = Stbl_getStartLine(me->stbl);
+    if (lineno < 0 || lineno > me->Lines)
+	return -1;
+    /*
+     *  oldpos, newpos: allocate space for two int arrays.
+     */
+    oldpos = (int *) calloc(2 * ncols, sizeof(int));
+    if (!oldpos)
+	return -1;
+    else
+	newpos = oldpos + ncols;
+    for (line = me->last_line->next; i < lineno; line = line->next, i++) {
+	if (!line) {
+	    free(oldpos);
+	    return -1;
+	}
+    }
+    first_lineno_pass2 = last_lineno = me->Lines;
+    for (; line && lineno <= last_lineno; line = line->next, lineno++) {
+	if (added_chars_before) {
+	    for (a = me->last_anchor_before_stbl ?
+		     me->last_anchor_before_stbl->next : me->first_anchor;
+		 a && a->line_num <= lineno; a = a->next) {
+		if (a->line_num == lineno)
+		    a->start += added_chars_before;
+	    }
+	}
+	ninserts = Stbl_getFixupPositions(me->stbl, lineno, oldpos, newpos);
+	if (ninserts < 0)
+	    continue;
+	if (!first_line) {
+	    first_line = line;
+	    first_lineno_pass2 = lineno;
+	    if (TRACE) {
+		int ip;
+		CTRACE((tfp, "line %d first to adjust  --  newpos:",
+		       lineno));
+		for (ip = 0; ip < ncols; ip++)
+		    fprintf(tfp, " %d", newpos[ip]);
+		fprintf(tfp, "\r\n");
+	    }
+	}
+	if (line == me->last_line) {
+	    if (line->size == 0 || !HText_TrueLineSize(line, me, FALSE))
+		continue;
+	    /*
+	     *  Last ditch effort to end the table with a line break,
+	     *  if HTML_end_element didn't do it. - kw
+	     */
+	    if (first_line == line) /* obscure: all table on last line... */
+		first_line = NULL;
+	    new_line(me);
+	    line = me->last_line->prev;
+	    if (first_line == NULL)
+		first_line = line;
+	}
+	if (ninserts == 0) {
+	    /*  Do it also for no positions (but not error) */
+	    int width = HText_TrueLineSize(line, me, FALSE);
+	    if (width > max_width)
+		max_width = width;
+	    CTRACE((tfp, "line %d true/max width:%d/%d oldpos: NONE\r\n",
+		   lineno, width, max_width));
+	    continue;
+	}
+	mod_line = insert_blanks_in_line(line, lineno, me,
+					 ninserts, oldpos, newpos);
+	if (mod_line) {
+	    if (line == me->last_line) {
+		me->last_line = mod_line;
+	    } else {
+		me->chars += (mod_line->size - line->size);
+		added_chars_before += (mod_line->size - line->size);
+	    }
+	    line->prev->next = mod_line;
+	    line->next->prev = mod_line;
+	    lines_changed++;
+	    if (line == first_line)
+		first_line = mod_line;
+	    free(line);
+	    line = mod_line;
+#ifdef DISP_PARTIAL
+	    /*
+	     *  Make sure modified lines get fully re-displayed after
+	     *  loading with partial display is done.
+	     */
+	    if (me->first_lineno_last_disp_partial >= 0) {
+		if (me->first_lineno_last_disp_partial >= lineno) {
+		    me->first_lineno_last_disp_partial =
+			me->last_lineno_last_disp_partial = -1;
+		} else if (me->last_lineno_last_disp_partial >= lineno) {
+		    me->last_lineno_last_disp_partial = lineno - 1;
+		}
+	    }
+#endif
+	}
+	{
+	    int width = HText_TrueLineSize(line, me, FALSE);
+	    if (width > max_width)
+		max_width = width;
+	    if (TRACE) {
+		int ip;
+		CTRACE((tfp, "line %d true/max width:%d/%d oldpos:",
+		       lineno, width, max_width));
+		for (ip = 0; ip < ninserts; ip++)
+		    fprintf(tfp, " %d", oldpos[ip]);
+		fprintf(tfp, "\r\n");
+	    }
+	}
+    }
+    /*
+     *  Line offsets have been set based on the paragraph style, and
+     *  have already been updated for centering or right-alignment
+     *  for each line in split_line.  Here we want to undo all that, and
+     *  align the table as a whole (i.e. all lines for which
+     *  Stbl_getFixupPositions returned >= 0).  All those lines have to
+     *  get the same offset, for the simple table formatting mechanism
+     *  to make sense, and that may not actually be the case at this point.
+     *
+     *  What indentation and alignment do we want for the table as
+     *  a whole?  Let's take most style properties from me->style.
+     *  With some luck, it is the appropriate style for the element
+     *  enclosing the TABLE.  But let's take alignment from the attribute
+     *  of the TABLE itself instead, if it was specified.
+     *
+     *  Note that this logic assumes that all lines have been finished
+     *  by split_line.  The order of calls made by HTML_end_element for
+     *  HTML_TABLE should take care of this.
+     */
+    style = me->style;
+    alignment = Stbl_getAlignment(me->stbl);
+    if (alignment == HT_ALIGN_NONE)
+	alignment = style->alignment;
+    indent = style->leftIndent;
+    /* Calculate spare character positions */
+    spare = (LYcols-1) -
+	(int)style->rightIndent - indent - max_width;
+    if (spare < 0 && (int)style->rightIndent + spare >= 0) {
+	/*
+	 *  Not enough room!  But we can fit if we ignore right indentation,
+	 *  so let's do that.
+	 */
+	spare = 0;
+    } else if (spare < 0) {
+	spare += style->rightIndent; /* ignore right indent, but need more */
+    }
+    if (spare < 0 && indent + spare >= 0) {
+	/*
+	 *  Still not enough room.  But we can move to the left.
+	 */
+	indent += spare;
+	spare = 0;
+    } else if (spare < 0) {
+	/*
+	 *  Still not enough.  Something went wrong.  Try the best we
+	 *  can do.
+	 */
+	CTRACE((tfp, "insertBlanks: resulting table too wide by %d positions!",
+	       -spare));
+	indent = spare = 0;
+    }
+    /*
+     *  Align left, right or center.
+     */
+    switch (alignment) {
+	case HT_CENTER :
+	    table_offset = indent + spare/2;
+	    break;
+	case HT_RIGHT :
+	    table_offset = indent + spare;
+	    break;
+	case HT_LEFT :
+	case HT_JUSTIFY :
+	default:
+	    table_offset = indent;
+	    break;
+    } /* switch */
+
+    CTRACE((tfp, "changing offsets"));
+    for (line = first_line, lineno = first_lineno_pass2;
+	 line && lineno <= last_lineno && line != me->last_line;
+	 line = line->next, lineno++) {
+	ninserts = Stbl_getFixupPositions(me->stbl, lineno, oldpos, newpos);
+	if (ninserts >= 0 && (int) line->offset != table_offset) {
+#ifdef DISP_PARTIAL
+	    /*  As above make sure modified lines get fully re-displayed */
+	    if (me->first_lineno_last_disp_partial >= 0) {
+		if (me->first_lineno_last_disp_partial >= lineno) {
+		    me->first_lineno_last_disp_partial =
+			me->last_lineno_last_disp_partial = -1;
+		} else if (me->last_lineno_last_disp_partial >= lineno) {
+		    me->last_lineno_last_disp_partial = lineno - 1;
+		}
+	    }
+#endif
+	    CTRACE((tfp, " %d:%d", lineno, table_offset - line->offset));
+	    line->offset = table_offset;
+	}
+    }
+    CTRACE((tfp, " %d:done\r\n", lineno));
+    free(oldpos);
+    return lines_changed;
+}
+
+/*		Simple table handling - public functions
+**		----------------------------------------
+*/
+
+/*	Cancel simple table handling
+*/
+PUBLIC void HText_cancelStbl ARGS1(
+	HText *,	me)
+{
+    if (!me || !me->stbl) {
+	CTRACE((tfp, "cancelStbl: ignored.\n"));
+	return;
+    }
+    CTRACE((tfp, "cancelStbl: ok, will do.\n"));
+    Stbl_free(me->stbl);
+    me->stbl = NULL;
+}
+/*	Start simple table handling
+*/
+PUBLIC void HText_startStblTABLE ARGS2(
+	HText *,	me,
+	short,		alignment)
+{
+    if (!me)
+	return;
+    if (me->stbl)
+	HText_cancelStbl(me);	/* auto cancel previously open table */
+    me->stbl = Stbl_startTABLE(alignment);
+    if (me->stbl) {
+	CTRACE((tfp, "startStblTABLE: started.\n"));
+	me->last_anchor_before_stbl = me->last_anchor;
+    } else {
+	CTRACE((tfp, "startStblTABLE: failed.\n"));
+    }
+}
+/*	Finish simple table handling
+*/
+PUBLIC void HText_endStblTABLE ARGS1(
+	HText *,	me)
+{
+    int ncols, lines_changed = 0;
+    if (!me || !me->stbl) {
+	CTRACE((tfp, "endStblTABLE: ignored.\n"));
+	return;
+    }
+    CTRACE((tfp, "endStblTABLE: ok, will try.\n"));
+    ncols = Stbl_finishTABLE(me->stbl);
+    CTRACE((tfp, "endStblTABLE: ncols = %d.\n", ncols));
+    if (ncols > 0) {
+	lines_changed = HText_insertBlanksInStblLines(me, ncols);
+	CTRACE((tfp, "endStblTABLE: changed %d lines, done.\n", lines_changed));
+    }
+    Stbl_free(me->stbl);
+    me->stbl = NULL;
+}
+/*	Start simple table row
+*/
+PUBLIC void HText_startStblTR ARGS2(
+	HText *,	me,
+	short,		alignment)
+{
+    if (!me || !me->stbl)
+	return;
+    if (Stbl_addRowToTable(me->stbl, alignment, me->Lines) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+/*	Finish simple table row
+*/
+PUBLIC void HText_endStblTR ARGS1(
+	HText *,	me)
+{
+    if (!me || !me->stbl)
+	return;
+    /* should this do something?? */
+}
+/*	Finish simple table cell
+*/
+PUBLIC void HText_startStblTD ARGS4(
+	HText *,	me,
+	int,		colspan,
+	short,		alignment,
+	BOOL,		isheader)
+{
+    if (!me || !me->stbl)
+	return;
+    if (colspan <= 0)
+	colspan = 1;
+    if (Stbl_addCellToTable(me->stbl, colspan, alignment, isheader,
+			    me->Lines, HText_LastLineSize(me,FALSE)) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+/*	Finish simple table cell
+*/
+PUBLIC void HText_endStblTD ARGS1(
+	HText *,	me)
+{
+    if (!me || !me->stbl)
+	return;
+    if (Stbl_finishCellInTable(me->stbl, YES,
+			       me->Lines, HText_LastLineSize(me,FALSE)) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+
 /*		Anchor handling
 **		---------------
 */
@@ -4393,6 +5123,8 @@ PUBLIC void HText_endAppend ARGS1(
     new_line(text);
 
     if (text->halted) {
+	if (text->stbl)
+	    HText_cancelStbl(text);
 	/*
 	 *  If output was stopped because memory was low, and we made
 	 *  it to the end of the document, reset those flags and hope
@@ -4400,6 +5132,12 @@ PUBLIC void HText_endAppend ARGS1(
 	 */
 	LYFakeZap(NO);
 	text->halted = 0;
+    } else if (text->stbl) {
+	/*
+	 *  Could happen if TABLE end tag was missing.
+	 *  Alternatively we could cancel in this case. - kw
+	 */
+	HText_endStblTABLE(text);
     }
 
     /*
@@ -4431,7 +5169,7 @@ PUBLIC void HText_endAppend ARGS1(
      *  Fix up the anchor structure values and
      *  create the hightext strings. - FM
      */
-    HText_trimHightext(text, TRUE);
+    HText_trimHightext(text, TRUE, -1);
 }
 
 
@@ -4454,14 +5192,15 @@ PUBLIC void HText_endAppend ARGS1(
 **  if applicable) fields indicate x positions in terms of displayed
 **  character cells, and the extent field apparently is unimportant;
 **  the anchor text has been copied to the hightext (and possibly
-**  hightext2) fields (which should be NULL up to this point), with
-**  special attribute chars removed.
+**  hightext2) fields (which should have been NULL up to that point),
+**  with special attribute chars removed.
 **  This needs to be done so that display_page finds the anchors in the
 **  form it expects when it sets the links[] elements.
 */
-PUBLIC void HText_trimHightext ARGS2(
+PUBLIC void HText_trimHightext ARGS3(
 	HText *,	text,
-	BOOLEAN,	final)
+	BOOLEAN,	final,
+	int,		stop_before)
 {
     int cur_line, cur_char, cur_shift;
     TextAnchor *anchor_ptr;
@@ -4472,8 +5211,15 @@ PUBLIC void HText_trimHightext ARGS2(
     if (!text)
 	return;
 
-    CTRACE((tfp, "Gridtext: Entering HText_trimHightext %s\n",
-		final ? "(final)" : "(partial)"));
+    if (final) {
+	CTRACE((tfp, "Gridtext: Entering HText_trimHightext (final)\n"));
+    } else {
+	if (stop_before < 0 || stop_before > text->Lines)
+	    stop_before = text->Lines;
+	CTRACE((tfp,
+	       "Gridtext: Entering HText_trimHightext (partial: 0..%d/%d)\n",
+	       stop_before, text->Lines));
+    }
 
     /*
      *  Get the first line.
@@ -4507,7 +5253,7 @@ re_parse:
 	     *  the last line, or the very end of preceding line.
 	     *  The last line is probably still not finished. - kw
 	     */
-	    if (cur_line >= text->Lines)
+	    if (cur_line >= stop_before)
 		break;
 	    if (anchor_ptr->start >= text->chars - 1)
 		break;
@@ -4607,7 +5353,7 @@ re_parse:
 	    HTLine *line_ptr2 = line_ptr->next;
 
 	    if (!final) {
-		if (cur_line + 1 >= text->Lines) {
+		if (cur_line + 1 >= stop_before) {
 		    FREE(anchor_ptr->hightext); /* bail out */
 		    break;
 		}
@@ -5524,7 +6270,9 @@ PUBLIC void HTCheckFnameForCompression ARGS3(
 		     *  file for us, but the anchor claims otherwise,
 		     *  so tweak the suffix. - FM
 		     */
-		    *dot = '\0';
+		    if (cp == dot+1)
+			cp--;
+		    *cp = '\0';
 		} else {
 		    /*
 		     *  The anchor claims it's gzipped, and we
@@ -5554,7 +6302,9 @@ PUBLIC void HTCheckFnameForCompression ARGS3(
 		     *  file for us, but the anchor claims otherwise,
 		     *  so tweak the suffix. - FM
 		     */
-		    *dot = '\0';
+		    if (cp == dot+1)
+			cp--;
+		    *cp = '\0';
 		} else {
 		    /*
 		     *  The anchor claims it's compressed, and
@@ -5647,6 +6397,7 @@ PUBLIC void HText_pageDisplay ARGS2(
     }
 
     if (display_partial) {
+	int stop_before = -1;
 	/*
 	**  Garbage is reported from forms input fields in incremental mode.
 	**  So we start HText_trimHightext() to forget this side effect.
@@ -5656,7 +6407,9 @@ PUBLIC void HText_pageDisplay ARGS2(
 	**  (FALSE =  indicate that we are in partial mode)
 	**  Multiple calls of HText_trimHightext works without problem now.
 	*/
-	HText_trimHightext(HTMainText, FALSE);
+	if (HTMainText && HTMainText->stbl)
+	    stop_before = Stbl_getStartLine(HTMainText->stbl);
+	HText_trimHightext(HTMainText, FALSE, stop_before);
     }
 #endif
 
@@ -9360,8 +10113,9 @@ PUBLIC int HText_SubmitForm ARGS4(
 		    }
 		    fclose(fd);
 		    /* we need to modify the mime-type here */
+		    /* could use LYGetFileInfo for that and for other
+		       headers that should be transmitted - kw */
 
-		    /* Argh.  We need counted-length strings here */
 		    HTSprintf(&query,
 				   "%s%s%s%s%s",
 				   escaped1,
@@ -10662,7 +11416,7 @@ PRIVATE void insert_new_textarea_anchor ARGS2(
     f->maxlength       = anchor->input_field->maxlength;
     f->no_cache        = anchor->input_field->no_cache;
     f->disabled        = anchor->input_field->disabled;
-    f->value_cs        = current_char_set; 
+    f->value_cs        = current_char_set; /* use current setting - kw */
 
     /*  Init all the fields in the new HTLine (but see the #if).   */
     l->next	       = htline->next;
@@ -10880,6 +11634,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
 
     char       *ed_temp;
     FILE       *fp;
+    int		rv;
 
     TextAnchor *anchor_ptr;
     TextAnchor *start_anchor  = NULL;
@@ -10981,12 +11736,28 @@ PUBLIC int HText_ExtEditForm ARGS1(
     HTSprintf0 (&tbuf, "%s %s %s", editor, ed_offset, ed_temp);
 #endif
 
-    if (LYSystem (tbuf)) {   /* finally the editor is called */
+#ifdef UNIX
+    errno = 0;
+#endif
+    rv = LYSystem (tbuf);	/* finally the editor is called */
+    if (rv) {
 	/*
 	 *  If something went wrong, we should probably return soon;
 	 *  currently we don't, but at least put out a message. - kw
 	 */
-	HTAlwaysAlert(NULL, ERROR_SPAWNING_EDITOR);
+#ifdef UNIX
+	int rvhi = (rv >> 8);
+	CTRACE((tfp, "ExtEditForm: system() returned %d (0x%x), %s\n",
+	       rv, rv, errno ? LYStrerror(errno) : "reason unknown"));
+	LYFixCursesOn("show error warning:");
+	if (rv != -1 && (rv && 0xff) && !rvhi) {
+	    HTAlwaysAlert(NULL, gettext("Editor killed by signal"));
+	} else if (!(rv == -1 || (rvhi == 127 && errno))) {
+	    HTUserMsg2(gettext("Editor returned with error status, %s"),
+		       errno ? LYStrerror(errno) : gettext("reason unknown."));
+	} else
+#endif
+	    HTAlwaysAlert(NULL, ERROR_SPAWNING_EDITOR);
     }
 
 #ifdef UNIX
@@ -11258,6 +12029,7 @@ PUBLIC int HText_InsertFile ARGS1(
     char       *lp;
     char       *cp;
     int		entry_line = form_link->anchor_line_num;
+    int		file_cs;
     int		match_tag  = 0;
     int		newlines   = 0;
     int		len;
@@ -11294,10 +12066,33 @@ PUBLIC int HText_InsertFile ARGS1(
 
     } else {
 
-	if ((fbuf = (char *) calloc (size + 1, (sizeof(char)))) == NULL)
-	    outofmem(__FILE__, "HText_InsertFile");
+	if ((fbuf = (char *) calloc (size + 1, (sizeof(char)))) == NULL) {
+	    /*
+	     *  This could be huge - don't exit if we don't have enough
+	     *  memory for it. - kw
+	     */ /*outofmem(__FILE__, "HText_InsertFile");*/
+	    free(fn);
+	    HTAlert(MEMORY_EXHAUSTED_FILE);
+	    return 0;
+	}
+
+	/* Try to make the same assumption for the charset of the inserted
+	 * file as we would for normal loading of that file, i.e. taking
+	 * assume_local_charset and suffix mappings into account.
+	 * If there is a mismatch with the display character set, characters
+	 * may be displayed wrong, too bad; but the user has a chance to
+	 * correct this by editing the lines, which will update f->value_cs
+	 * again. - kw
+	 */
+	LYGetFileInfo(fn, 0, 0, 0, 0, 0, &file_cs);
 
 	fp   = fopen (fn, "r");
+	if (!fp) {
+	    free(fbuf);
+	    free(fn);
+	    HTAlert(FILE_CANNOT_OPEN_R);
+	    return 0;
+	}
 	size = fread (fbuf, 1, size, fp);
 	fclose (fp);
 	FREE(fn);
@@ -11387,7 +12182,7 @@ PUBLIC int HText_InsertFile ARGS1(
     f->maxlength       = anchor_ptr->input_field->maxlength;
     f->no_cache        = anchor_ptr->input_field->no_cache;
     f->disabled        = anchor_ptr->input_field->disabled;
-    f->value_cs        = current_char_set; 
+    f->value_cs        = (file_cs >= 0) ? file_cs : current_char_set;
 
     /*  Init all the fields in the new HTLine (but see the #if).   */
     l->offset	       = htline->offset;
@@ -11474,6 +12269,13 @@ PUBLIC int HText_InsertFile ARGS1(
 	StrAllocCopy(anchor_ptr->input_field->value, line);
 
 	/*
+	 *  insert_new_textarea_anchor always uses current_char_set,
+	 *  we may want something else, so fix it up. - kw
+	 */
+	 if (file_cs >= 0)
+	     anchor_ptr->input_field->value_cs = file_cs;
+
+	/*
 	 *  And do the next line of insert text, for the next anchor ...
 	 */
 	lp += len;
@@ -11673,6 +12475,15 @@ PRIVATE void redraw_part_of_line ARGS4(
 		     */
 		    LastDisplayChar = 'M';
 		} else {
+#if 0	/* last-ditch attempt to prevent 0x9B to screen - disabled  */
+#if defined(UNIX) || defined(VMS)
+		    if (!dump_output_immediately &&
+			(unsigned char)buffer[0] == 128+27) {
+			addstr("~^");
+			buffer[0] ^= 0xc0;
+		    }
+#endif
+#endif
 		    addstr(buffer);
 		    LastDisplayChar = buffer[0];
 		}
@@ -11696,6 +12507,588 @@ PRIVATE void redraw_part_of_line ARGS4(
 }
 #endif /* defined(USE_COLOR_STYLE) && !defined(NO_HILIT_FIX)  */
 
+#ifndef USE_COLOR_STYLE
+/*
+ *  Function move_to_glyph is called from LYMoveToLink and does all
+ *  the real work for it.
+ *  The pair LYMoveToLink()/move_to_glyph() is similar to the pair
+ *  redraw_lines_of_link()/redraw_part_of_line(), some key differences:
+ *   LYMoveToLink/move_to_glyph		redraw_*
+ *   -----------------------------------------------------------------
+ *   - used without color style         - used with color style
+ *   - handles showing WHEREIS target	- WHEREIS handled elsewhere
+ *   - handles only one line		- handles first two lines for
+ *					  hypertext anchors
+ *   - right columns position for UTF-8
+ *     by redrawing as necessary
+ *   - currently used for highlight	- currently used for highlight
+ *     ON and OFF			  OFF
+ *
+ *  Eventually the two sets of function should be unified, and should handle
+ *  UTF-8 positioning, both lines of hypertext anchors, and WHEREIS in all
+ *  cases.  If possible.  The complex WHEREIS target logic in highlight()
+ *  could then be completely removed. - kw
+ */
+PRIVATE void move_to_glyph ARGS10(
+	int,		YP,
+	int,		XP,
+	int,		XP_draw_min,
+	char *,		data,
+	int,		datasize,
+	unsigned,	offset,
+	CONST char *,	target,
+	char *,		hightext,
+	int,		flags,
+	BOOL,		utf_flag)
+{
+    register int i;
+    char buffer[7];
+    CONST char *end_of_data;
+    size_t utf_extra = 0;
+#if defined(SHOW_WHEREIS_TARGETS)
+    CONST char *cp_tgt;
+    int i_start_tgt=0, i_after_tgt;
+    int HitOffset, LenNeeded;
+#endif /* SHOW_WHEREIS_TARGETS */
+    BOOL intarget = NO, inunderline = NO, inbold = NO;
+    BOOL drawing = NO, inU = NO, hadutf8 = NO;
+    BOOL incurlink = NO, drawingtarget = NO, flag = NO;
+    char *sdata = data;
+    char LastDisplayChar = ' ';
+    int XP_link = XP;
+    int linkvlen;
+
+    int	len;
+
+    if (flags & 1)
+	flag = YES;
+    if (flags & 2)
+	inU = YES;
+    /* Set up the multibyte character buffer  */
+    buffer[0] = buffer[1] = buffer[2] = '\0';
+    /*
+     *  Add offset, making sure that we do not
+     *  go over the COLS limit on the display.
+     */
+    i = (int)offset;
+    if (i > (int)LYcols - 1)
+	i = (int)LYcols - 1;
+
+    linkvlen = hightext ? LYmbcsstrlen(hightext, utf_flag) : 0;
+
+    /*
+     *  Scan through the data, making sure that we do not
+     *  go over the COLS limit on the display etc.
+     */
+    len = datasize;
+    end_of_data = data + len;
+
+#if defined(SHOW_WHEREIS_TARGETS)
+    /*
+     *  If the target overlaps with the part of this line that
+     *  we are drawing, it will be emphasized.
+     */
+    i_after_tgt = i;
+    if (target) {
+	if (case_sensitive)
+	    cp_tgt = LYno_attr_mbcs_strstr(sdata,
+					   target,
+					   utf_flag,
+					   &HitOffset,
+					   &LenNeeded);
+	else
+	    cp_tgt = LYno_attr_mbcs_case_strstr(sdata,
+						target,
+						utf_flag,
+						&HitOffset,
+						&LenNeeded);
+	if (cp_tgt) {
+	    if ((int)offset + LenNeeded >= LYcols ||
+		((int)offset + HitOffset >= XP + linkvlen)) {
+		cp_tgt = NULL;
+	    } else {
+		i_start_tgt = i + HitOffset;
+		i_after_tgt = i + LenNeeded;
+	    }
+	}
+    } else {
+	cp_tgt = NULL;
+    }
+#endif /* SHOW_WHEREIS_TARGETS */
+
+
+    /*
+     *  Iterate through the line data from the start, keeping track of
+     *  the display ("glyph") position in i.  Drawing will be turned
+     *  on when either the first UTF-8 sequence (that occurs after
+     *  XP_draw_min) is found, or when we reach the link itself (if
+     *  highlight is non-NULL). - kw
+     */
+    while ((i < LYcols - 1) && data < end_of_data && (*data != '\0')) {
+
+	if (data && hightext && i >= XP && !incurlink) {
+
+	/*
+	 *  We reached the position of link itself, and highlight is
+	 *  non-NULL.  We switch data from being a pointer into the HTLine
+	 *  to be a pointer into hightext.  Normally (as long as this
+	 *  routine is applied to normal hyperlink anchors) the text in
+	 *  hightext will be identical to that part of the HTLine that
+	 *  data was already pointing to, except that special attribute
+	 *  chars LY_BOLD_START_CHAR etc. have been stripped out (see
+	 *  HText_trimHightext).  So the switching should not result in
+	 *  any different display, but it ensures that it doesn't go
+	 *  unnoticed if somehow hightext got messed up somewhere else.
+	 *  This is also useful in preparation for using this function
+	 *  for something else than normal hyperlink anchors, i.e. form
+	 *  fields.
+	 *  Turn on drawing here or make sure it gets turned on before the
+	 *  next actual normal character is handled. - kw
+	 */
+	    data = hightext;
+	    len = strlen(hightext);
+	    end_of_data = hightext + len;
+	    XP += linkvlen;
+	    incurlink = YES;
+	    if (cp_tgt) {
+		if (flag && i_after_tgt >= XP)
+		    i_after_tgt = XP - 1;
+	    }
+	    /*
+	     *  The logic of where to set intarget drawingtarget etc.
+	     *  and when to react to it should be cleaned up (here and
+	     *  further below).  For now this seems to work but isn't
+	     *  very clear.  The complications arise from reproducing
+	     *  the behavior (previously done in highlight()) for target
+	     *  strings that fall into or overlap a link: use target
+	     *  emphasis for the target string, except for the first
+	     *  and last character of the anchor text if the anchor is
+	     *  highlighted as "current link". - kw
+	     */
+	    if (!drawing) {
+#ifdef SHOW_WHEREIS_TARGETS
+		if (intarget) {
+		    if (i_after_tgt > i) {
+			move(YP, i);
+			if (flag) {
+			    drawing = YES;
+			    drawingtarget = NO;
+			    if (inunderline)	inU = YES;
+			    lynx_start_link_color (flag, inU);
+			} else {
+			    drawing = YES;
+			    drawingtarget = YES;
+			    LYstartTargetEmphasis();
+			}
+		    }
+#if 0
+		} else {
+		    if (inunderline)	inU = YES;
+		    lynx_start_link_color (flag, inU);
+#endif
+		}
+#endif /* SHOW_WHEREIS_TARGETS */
+	    } else {
+#ifdef SHOW_WHEREIS_TARGETS
+		if (intarget && i_after_tgt > i) {
+		    if (flag && (data == hightext)) {
+			drawingtarget = NO;
+			LYstopTargetEmphasis();
+		    }
+		} else if (!intarget)
+#endif /* SHOW_WHEREIS_TARGETS */
+		{
+		    if (inunderline)	inU = YES;
+		    if (inunderline)	stop_underline();
+		    if (inbold)		stop_bold();
+		    lynx_start_link_color (flag, inU);
+		}
+
+	    }
+	}
+	if (i >= XP || data >= end_of_data)
+	    break;
+	if ((buffer[0] = *data) == '\0')
+	    break;
+
+
+#if defined(SHOW_WHEREIS_TARGETS)
+	/*
+	 *  Look for a subsequent occurrence of the target string,
+	 *  if we had a previous one and have now stepped past it. - kw
+	 */
+	if (cp_tgt && i >= i_after_tgt) {
+	    if (intarget) {
+
+		if (incurlink && flag && i == XP - 1)
+		    cp_tgt = NULL;
+		else if (case_sensitive)
+		    cp_tgt = LYno_attr_mbcs_strstr(sdata,
+						   target,
+						   utf_flag,
+						   &HitOffset,
+						   &LenNeeded);
+		else
+		    cp_tgt = LYno_attr_mbcs_case_strstr(sdata,
+							target,
+							utf_flag,
+							&HitOffset,
+							&LenNeeded);
+		if (cp_tgt) {
+		    i_start_tgt = i + HitOffset;
+		    i_after_tgt = i + LenNeeded;
+		    if (incurlink) {
+			if (flag && i_start_tgt == XP_link)
+			    i_start_tgt++;
+			if (flag && i_start_tgt == XP - 1)
+			    i_start_tgt++;
+			if (flag && i_after_tgt >= XP)
+			    i_after_tgt = XP - 1;
+			if (flag && i_start_tgt >= XP)
+			    cp_tgt = NULL;
+		    } else if (i_start_tgt == XP) {
+			if (flag)
+			    i_start_tgt++;
+		    }
+		}
+		if (!cp_tgt || i_start_tgt != i) {
+		    intarget = NO;
+		    if (drawing) {
+			if (drawingtarget) {
+			    drawingtarget = NO;
+			    LYstopTargetEmphasis();
+			    if (incurlink) {
+				lynx_start_link_color (flag, inU);
+			    }
+			}
+			if (!incurlink) {
+			    if (inbold)		start_bold();
+			    if (inunderline)	start_underline();
+			}
+		    }
+		}
+	    }
+	}
+#endif /* SHOW_WHEREIS_TARGETS */
+
+	/*
+	 *  Advance data to point to the next input char (for the
+	 *  next round).  Advance sdata, used for searching for a
+	 *  target string, so that they stays in synch.  As long
+	 *  as we are not within the highlight text, data and sdata
+	 *  have identical values.  After we have switched data to
+	 *  point into hightext, sdata remains a pointer into the
+	 *  HTLine (so that we don't miss a partial target match at
+	 *  the end of the anchor text).  So sdata has to sometimes
+	 *  skip additional special attribute characters that are
+	 *  not present in highlight in order to stay in synch. - kw
+	 */
+	data++;
+	if (*sdata) {
+	    do sdata++;
+		while (incurlink && *sdata && sdata != data &&
+		       IsSpecialAttrChar(*(sdata-1)));
+	}
+
+	switch (buffer[0]) {
+
+	    case LY_UNDERLINE_START_CHAR:
+		if (!drawing || !incurlink) inunderline = YES;
+		if (drawing && !intarget && !incurlink)
+		    start_underline();
+		break;
+
+	    case LY_UNDERLINE_END_CHAR:
+		inunderline = NO;
+		if (drawing && !intarget && !incurlink)
+		    stop_underline();
+		break;
+
+	    case LY_BOLD_START_CHAR:
+		if (!drawing || !incurlink) inbold = YES;
+		if (drawing && !intarget && !incurlink)
+		    start_bold();
+		break;
+
+	    case LY_BOLD_END_CHAR:
+		inbold = NO;
+		if (drawing && !intarget && !incurlink)
+		    stop_bold();
+		break;
+
+	    case LY_SOFT_NEWLINE:
+		if (drawing) {
+		    addch('+');
+		}
+		i++;
+		break;
+
+	    case LY_SOFT_HYPHEN:
+		if (*data != '\0' ||
+		    isspace((unsigned char)LastDisplayChar) ||
+		    LastDisplayChar == '-') {
+		    /*
+		     *  Ignore the soft hyphen if it is not the last
+		     *  character in the line.  Also ignore it if it
+		     *  first character following the margin, or if it
+		     *  is preceded by a white character (we loaded 'M'
+		     *  into LastDisplayChar if it was a multibyte
+		     *  character) or hyphen, though it should have
+		     *  been excluded by HText_appendCharacter() or by
+		     *  split_line() in those cases. - FM
+		     */
+		    break;
+		} else {
+		    /*
+		     *  Make it a hard hyphen and fall through. - FM
+		     */
+		    buffer[0] = '-';
+		}
+
+	    default:
+		/*
+		 *  We have got an actual normal displayable character, or
+		 *  the start of one.  Before proceeding check whether
+		 *  drawing needs to be turned on now. - kw
+		 */
+#if defined(SHOW_WHEREIS_TARGETS)
+		if (incurlink) {
+		    if (intarget && flag && i == XP - 1 &&
+			i_after_tgt > i)
+			i_after_tgt = i;
+		}
+		if (cp_tgt && i >= i_start_tgt && sdata > cp_tgt) {
+		    if (!intarget ||
+			(intarget && incurlink && !drawingtarget)) {
+
+			if (incurlink && drawing &&
+			    !(flag &&
+			      (i == XP_link || i == XP - 1))) {
+			    lynx_stop_link_color (flag, inU);
+			}
+			if (incurlink && !drawing) {
+			    move(YP, i);
+			    if (inunderline)	inU = YES;
+			    if (flag && (i == XP_link || i == XP - 1)) {
+				lynx_start_link_color (flag, inU);
+				drawingtarget = NO;
+			    } else {
+				LYstartTargetEmphasis();
+				drawingtarget = YES;
+			    }
+			    drawing = YES;
+			} else if (incurlink && drawing &&
+				   intarget && !drawingtarget &&
+				   (flag &&
+				    (i == XP_link))) {
+			    if (inunderline)	inU = YES;
+			    lynx_start_link_color (flag, inU);
+			} else if (drawing &&
+				   !(flag &&
+				     (i == XP_link || (incurlink && i == XP - 1)))) {
+			    LYstartTargetEmphasis();
+			    drawingtarget = YES;
+			}
+			intarget = YES;
+		    }
+		} else
+#endif /* SHOW_WHEREIS_TARGETS */
+		    if (incurlink) {
+			if (!drawing) {
+			    move(YP, i);
+			    if (inunderline)	inU = YES;
+			    lynx_start_link_color (flag, inU);
+			    drawing = YES;
+			}
+		    }
+
+		i++;
+		if (utf_flag && !isascii((unsigned char)buffer[0])) {
+		    hadutf8 = YES;
+		    if ((*buffer & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*buffer & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*buffer & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*buffer & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*buffer & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			 /*
+			  *  Garbage.
+			  */
+			utf_extra = 0;
+		    }
+		    if (strlen(data) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
+			utf_extra = 0;
+		    }
+		    LastDisplayChar = 'M';
+		}
+		if (utf_extra) {
+		    strncpy(&buffer[1], data, utf_extra);
+		    buffer[utf_extra+1] = '\0';
+		    if (!drawing && i >= XP_draw_min) {
+			move(YP, i - 1);
+			drawing = YES;
+#if defined(SHOW_WHEREIS_TARGETS)
+			if (intarget) {
+			    drawingtarget = YES;
+			    LYstartTargetEmphasis();
+			} else
+#endif /* SHOW_WHEREIS_TARGETS */
+			{
+			    if (inbold)
+				start_bold();
+			    if (inunderline)
+				start_underline();
+			}
+		    }
+		    addstr(buffer);
+		    buffer[1] = '\0';
+		    sdata += utf_extra; data += utf_extra;
+		    utf_extra = 0;
+		} else if (HTCJK != NOCJK && !isascii(buffer[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
+		    if (drawing && (i < LYcols - 1)) {
+			buffer[1] = *data;
+			addstr(buffer);
+			buffer[1] = '\0';
+		    }
+		    i++;
+		    sdata++; data++;
+		    /*
+		     *  For now, load 'M' into LastDisplayChar,
+		     *  but we should check whether it's white
+		     *  and if so, use ' '.  I don't know if
+		     *  there actually are white CJK characters,
+		     *  and we're loading ' ' for multibyte
+		     *  spacing characters in this code set,
+		     *  but this will become an issue when
+		     *  the development code set's multibyte
+		     *  character handling is used. - FM
+		     */
+		    LastDisplayChar = 'M';
+		} else {
+		    if (drawing) {
+#if 0	/* last-ditch attempt to prevent 0x9B to screen - disabled  */
+#if defined(UNIX) || defined(VMS)
+			if (!dump_output_immediately &&
+			    (unsigned char)buffer[0] == 128+27) {
+			    addstr("~^");
+			    buffer[0] ^= 0xc0;
+			}
+#endif
+#endif
+			addstr(buffer);
+		    }
+		    LastDisplayChar = buffer[0];
+		}
+	} /* end of switch */
+    } /* end of while */
+
+    if (!drawing) {
+	move(YP, i);
+	lynx_start_link_color (flag, inU);
+    } else {
+#if defined(SHOW_WHEREIS_TARGETS)
+	if (drawingtarget) {
+	    LYstopTargetEmphasis();
+	    lynx_start_link_color (flag, inU);
+	}
+#endif /* SHOW_WHEREIS_TARGETS */
+	if (hadutf8) {
+#ifdef USE_SLANG
+	    SLsmg_touch_lines(YP, 1);
+#elif defined(NCURSES_VERSION)
+	    touchline(stdscr, YP, 1);
+#else
+	    touchwin(stdscr);
+#endif
+	}
+    }
+    return;
+}
+#endif /* !USE_COLOR_STYLE */
+
+#ifndef USE_COLOR_STYLE
+/*
+ *  Move cursor position to a link's place in the display.
+ *  The "moving to" is done by scanning through the line's
+ *  character data in the corresponding HTLine of HTMainText,
+ *  and starting to draw when a UTF-8 encoded non-ASCII character
+ *  is encountered before the link (with some protection against
+ *  overwriting form fields).  This refreshing of preceding data is
+ *  necessary for preventing curses's or slang's display logic from
+ *  getting too clever; their logic counts character positions wrong
+ *  since they don't know about multi-byte characters that take up
+ *  only one screen position.  So we have to make them forget their
+ *  idea of what's in a screen line drawn previously.
+ *  If hightext is non-NULL, it should be the anchor text for a normal
+ *  link as stored in a links[] element, and the anchor text will be
+ *  drawn too, with appropriate attributes. - kw
+ */
+PUBLIC void LYMoveToLink ARGS6(
+	int,		cur,
+	CONST char *,	target,
+	char *,		hightext,
+	int,		flag,
+	BOOL,		inU,
+	BOOL,		utf_flag)
+{
+#define pvtTITLE_HEIGHT 1
+    HTLine* todr;
+    int i, n=0;
+    int XP_draw_min = 0;
+    int flags = ((flag == ON) ? 1 : 0) | (inU ? 2 : 0);
+
+    /*
+     *  We need to protect changed form text fields preceding this
+     *  link on the same line against overwriting. - kw
+     */
+    for (i = cur-1; i >= 0; i++) {
+	if (links[i].ly < links[cur].ly)
+	    break;
+	if (links[i].type == WWW_FORM_LINK_TYPE) {
+	    XP_draw_min = links[i].ly + links[i].form->size;
+	    break;
+	}
+    }
+
+    /*  Find the right HTLine. */
+    if (!HTMainText) {
+	todr = NULL;
+    } else if (HTMainText->stale) {
+	todr = HTMainText->last_line->next;
+	n = links[cur].ly - pvtTITLE_HEIGHT + HTMainText->top_of_screen;
+    } else {
+	todr = HTMainText->top_of_screen_line;
+	n = links[cur].ly - pvtTITLE_HEIGHT;
+    }
+    for (i = 0; i < n && todr; i++) {
+	todr = (todr == HTMainText->last_line) ? NULL : todr->next;
+    }
+    if (todr) {
+	if (target && *target == '\0') target = NULL;
+	move_to_glyph(links[cur].ly, links[cur].lx, XP_draw_min,
+		      todr->data, todr->size, todr->offset,
+		      target, hightext, flags, utf_flag);
+    } else {
+	/*  This should not happen. */
+	move_to_glyph(links[cur].ly, links[cur].lx, XP_draw_min,
+		      "", 0, links[cur].lx,
+		      target, hightext, flags, utf_flag);
+	/* move(links[cur].ly, links[cur].lx); */
+    }
+}
+#endif /* !USE_COLOR_STYLE */
+
 /*
   This is used only if compiled with lss support. It's called to draw
   regular link (1st two lines of link) when it's being unhighlighted in
@@ -11764,5 +13157,7 @@ PUBLIC void HText_updateKcode ARGS2(
 
 PUBLIC int HTMainText_Get_UCLYhndl NOARGS
 {
-    return (HTMainText ? HTMainText->node_anchor->UCStages->s[0].C.UChndl : 0);
+    return (HTMainText ?
+	    HTAnchor_getUCLYhndl(HTMainText->node_anchor, UCT_STAGE_MIME)
+	    : -1);
 }
diff --git a/src/GridText.h b/src/GridText.h
index 5fb73f07..190d97fa 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -32,7 +32,7 @@
 #ifndef LY_SOFT_HYPHEN
 #define LY_SOFT_HYPHEN		((char)7)
 #endif /* !LY_SOFT_HYPHEN */
-#define LY_SOFT_NEWLINE 	((char)8)
+#define LY_SOFT_NEWLINE		((char)8)
 
 #ifdef EBCDIC
 #define IsSpecialAttrChar(a)  (((a) > '\002') && ((a) <= '\011') && ((a)!='\t'))
@@ -196,6 +196,15 @@ extern int HText_getTabIDColumn PARAMS((HText *text, CONST char *name));
 extern int HText_HiddenLinkCount PARAMS((HText *text));
 extern char * HText_HiddenLinkAt PARAMS((HText *text, int number));
 
+/* "simple table" stuff */
+extern void HText_cancelStbl PARAMS((HText *));
+extern void HText_startStblTABLE PARAMS((HText *, short));
+extern void HText_endStblTABLE PARAMS((HText *));
+extern void HText_startStblTR PARAMS((HText *, short));
+extern void HText_endStblTR PARAMS((HText *));
+extern void HText_startStblTD PARAMS((HText *, int, short, BOOL));
+extern void HText_endStblTD PARAMS((HText *));
+
 /* forms stuff */
 extern void HText_beginForm PARAMS((
 	char *		action,
@@ -213,17 +222,18 @@ extern char * HText_setLastOptionValue PARAMS((
 	HText *		text,
 	char *		value,
 	char *		submit_value,
-	int 		order,
+	int		order,
 	BOOLEAN		checked,
-	int 		val_cs,
-	int 		submit_val_cs));
+	int		val_cs,
+	int		submit_val_cs));
 extern int HText_beginInput PARAMS((
 	HText *		text,
 	BOOL		underline,
 	InputFieldData *I));
 extern void HText_trimHightext PARAMS((
 	HText *		text,
-	BOOLEAN 	final));
+	BOOLEAN		final,
+	int		stop_before));
 extern int HText_SubmitForm PARAMS((
 	FormInfo *	submit_item,
 	document *	doc,
@@ -279,6 +289,14 @@ extern int HText_InsertFile PARAMS((
 	struct link *	form_link));
 
 extern void redraw_lines_of_link PARAMS((int cur));
+extern void LYMoveToLink PARAMS((
+	int		cur,
+	CONST char *	target,
+	char *		hightext,
+	int		flag,
+	BOOL		inU,
+	BOOL		utf_flag));
+
 
 #ifdef USE_PSRC
 extern void HTMark_asSource NOPARAMS;
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index 8b1308c1..faae9477 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -171,24 +171,25 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 		 *  and remove any previous uncompressed copy. - FM
 		 */
 		StrAllocCopy(path, me->anchor->FileCache);
-		if ((len = strlen(path)) > 3) {
-		    if (!strcasecomp(&path[len-3], "bz2")) {
-			    path[len-4] = '\0';
-			    remove(path);
-		    } else if (!strcasecomp(&path[len-2], "gz")) {
+		if ((len = strlen(path)) > 3 &&
+		    !strcasecomp(&path[len-2], "gz")) {
 #ifdef USE_ZLIB
-			if (!skip_loadfile) {
-			    use_gzread = YES;
-			} else
+		    if (!skip_loadfile) {
+			use_gzread = YES;
+		    } else
 #endif /* USE_ZLIB */
-			{
-			    path[len-3] = '\0';
-			    remove(path);
-			}
-		    } else if (!strcasecomp(&path[len-1], "Z")) {
-			path[len-2] = '\0';
+		    {
+			path[len-3] = '\0';
 			remove(path);
 		    }
+#ifdef BZIP2_PATH
+		} else if (len > 4 && !strcasecomp(&path[len-3], "bz2")) {
+		    path[len-4] = '\0';
+		    remove(path);
+#endif /* BZIP2_PATH */
+		} else if (len > 2 && !strcasecomp(&path[len-1], "Z")) {
+		    path[len-2] = '\0';
+		    remove(path);
 		}
 		if (!use_gzread) {
 		    if (!dump_output_immediately) {
@@ -216,7 +217,7 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 			refresh();
 		    }
 		    HTAlert(ERROR_UNCOMPRESSING_TEMP);
-		    remove(me->anchor->FileCache);
+		    LYRemoveTemp(me->anchor->FileCache);
 		    FREE(me->anchor->FileCache);
 		} else {
 		    /*
@@ -437,7 +438,7 @@ PRIVATE void HTFWriter_abort ARGS2(
     LYCloseTempFP(me->fp);
     FREE(me->viewer_command);
     if (me->end_command) {		/* Temp file */
-	CTRACE((tfp, "HTFWriter: Aborting: file not executed.\n"));
+	CTRACE((tfp, "HTFWriter: Aborting: file not executed or saved.\n"));
 	FREE(me->end_command);
 	if (me->remove_command) {
 	    LYSystem(me->remove_command);
@@ -913,7 +914,6 @@ PUBLIC HTStream* HTCompressed ARGS3(
     char *uncompress_mask = NULL;
     char *compress_suffix = "";
     CONST char *middle;
-    FILE *fp = NULL;
 
     /*
      *	Deal with any inappropriate invocations of this function,
@@ -938,12 +938,7 @@ PUBLIC HTStream* HTCompressed ARGS3(
 	     *	We have a presentation mapping for it. - FM
 	     */
 	    can_present = TRUE;
-	    if (!strcasecomp(anchor->content_encoding, "x-bzip2") ||
-		!strcasecomp(anchor->content_encoding, "bzip")) {
-		StrAllocCopy(uncompress_mask, BZIP2_PATH);
-		StrAllocCat(uncompress_mask, " -d %s");
-		compress_suffix = "bz2";
-	    } else if (!strcasecomp(anchor->content_encoding, "x-gzip") ||
+	    if (!strcasecomp(anchor->content_encoding, "x-gzip") ||
 		!strcasecomp(anchor->content_encoding, "gzip")) {
 		/*
 		 *  It's compressed with the modern gzip. - FM
@@ -951,6 +946,13 @@ PUBLIC HTStream* HTCompressed ARGS3(
 		StrAllocCopy(uncompress_mask, GZIP_PATH);
 		StrAllocCat(uncompress_mask, " -d --no-name %s");
 		compress_suffix = "gz";
+#ifdef BZIP2_PATH
+	    } else if (!strcasecomp(anchor->content_encoding, "x-bzip2") ||
+		!strcasecomp(anchor->content_encoding, "bzip")) {
+		StrAllocCopy(uncompress_mask, BZIP2_PATH);
+		StrAllocCat(uncompress_mask, " -d %s");
+		compress_suffix = "bz2";
+#endif /* BZIP2_PATH */
 	    } else if (!strcasecomp(anchor->content_encoding, "x-compress") ||
 		       !strcasecomp(anchor->content_encoding, "compress")) {
 		/*
@@ -976,7 +978,15 @@ PUBLIC HTStream* HTCompressed ARGS3(
 	 *  and pass it back to be handled as that type. - FM
 	 */
 	if (strchr(anchor->content_encoding, '/') == NULL) {
-	    StrAllocCopy(type, "application/");
+	    /*
+	     *  Use "x-" prefix, none of the types we are likely to
+	     *  construct here are official.  That is we generate
+	     *  "application/x-gzip" and so on. - kw
+	     */
+	    if (!strncasecomp(anchor->content_encoding, "x-", 2))
+		StrAllocCopy(type, "application/");
+	    else
+		StrAllocCopy(type, "application/x-");
 	    StrAllocCat(type, anchor->content_encoding);
 	} else {
 	    StrAllocCopy(type, anchor->content_encoding);
@@ -1008,10 +1018,7 @@ PUBLIC HTStream* HTCompressed ARGS3(
      *	Remove any old versions of the file. - FM
      */
     if (anchor->FileCache) {
-	while ((fp = fopen(anchor->FileCache, "r")) != NULL) {
-	    fclose(fp);
-	    remove(anchor->FileCache);
-	}
+	LYRemoveTemp(anchor->FileCache);
 	FREE(anchor->FileCache);
     }
 
diff --git a/src/HTInit.c b/src/HTInit.c
index 811af8b5..f7ce2bcc 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -45,15 +45,17 @@ PUBLIC void HTFormatInit NOARGS
  if (LYgetXDisplay() != 0) {	/* Must have X11 */
   HTSetPresentation("application/postscript", "ghostview %s&",
   							    1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/gif",        XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-xbm",      XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-xbitmap",  XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-png",      XLoadImageCommand,  2.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/png",        XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-rgb",      XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/x-tiff",     XLoadImageCommand,  2.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/tiff",       XLoadImageCommand,  1.0, 3.0, 0.0, 0);
-  HTSetPresentation("image/jpeg",       XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+  if (XLoadImageCommand && *XLoadImageCommand) {
+      HTSetPresentation("image/gif",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/x-xbm",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/x-xbitmap",XLoadImageCommand,1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/x-png",	XLoadImageCommand,  2.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/png",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/x-rgb",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/x-tiff", XLoadImageCommand,  2.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/tiff",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+      HTSetPresentation("image/jpeg",	XLoadImageCommand,  1.0, 3.0, 0.0, 0);
+  }
   HTSetPresentation("video/mpeg",       "mpeg_play %s &",   1.0, 3.0, 0.0, 0);
 
  }
@@ -693,16 +695,45 @@ PRIVATE int HTLoadTypesConfigFile ARGS1(
 **	which are of the same format but are originals or regenerated,
 **	with different values.
 */
-
+/*
+ *  Additional notes: the encoding parameter may be taken into account when
+ *  looking for a match; for that purpose "7bit", "8bit", and "binary" are
+ *  equivalent.
+ *  Use of mixed case and of pseudo MIME types with embedded spaces should
+ *  be avoided.  It was once necessary for getting the fancy strings into
+ *  type labels in FTP directory listings, but that can now be done with
+ *  the description field (using HTSetSuffix5).  AFAIK the only effect of
+ *  such "fancy" (and mostly invalid) types that cannot be reproduced by
+ *  using a description fields is some statusline messages in SaveToFile
+ *  (HTFWriter.c).  And showing the user an invalid MIME type as the
+ *  'Content-type:' is not such a hot idea anyway, IMO.  Still, if you
+ *  want it, it is still possible (even in lynx.cfg now), but use of it
+ *  in the defaults below has been reduced.
+ *  Case variations rely on peculiar behavior of HTAtom.c for matching.
+ *  They lead to surprising behavior, Lynx retains the case of a string
+ *  in the form first encountered after starting up.  So while later suffix
+ *  rules generally override or modify earlier ones, the case used for a
+ *  MIME time is determined by the first suffix rule (or other occurrence).
+ *  Matching in HTAtom_for is effectively case insensitive, except for the
+ *  first character of the string which is treated as case-sensitive by the
+ *  hash function there; best not to rely on that, rather convert MIME types
+ *  to lowercase on input as is already done in most places (And HTAtom could
+ *  become consistently case-sensitive, as in newer W3C libwww).
+ *  - kw 1999-10-12
+ */
 PUBLIC void HTFileInit NOARGS
 {
     FILE *fp;
 
+#ifdef BUILTIN_SUFFIX_MAPS
+    if (LYUseBuiltinSuffixes)
+    {
     CTRACE((tfp, "HTFileInit: Loading default (HTInit) extension maps.\n"));
 
     /* default suffix interpretation */
-    HTSetSuffix("*",		"text/plain", "7bit", 1.0);
-    HTSetSuffix("*.*",		"text/plain", "7bit", 1.0);
+    HTSetSuffix("*",		"text/plain", "8bit", 1.0);
+    HTSetSuffix("*.*",		"text/plain", "8bit", 1.0);
+
 
 #ifdef EXEC_SCRIPTS
     /*
@@ -718,7 +749,15 @@ PUBLIC void HTFileInit NOARGS
 #endif /* !VMS */
 #endif /* EXEC_SCRIPTS */
 
-
+    /*
+     *  Some of the old incarnation of the mappings is preserved
+     *  and can be had by defining TRADITIONAL_SUFFIXES.  This
+     *  is for some cases where I felt the old rules might be preferred
+     *  by someone, for some reason.  It's not done consistently.
+     *  A lot more of this stuff could probably be changed too or
+     *  omitted, now that nearly the equivalent functionality is
+     *  available in lynx.cfg. - kw 1999-10-12
+     */
     HTSetSuffix(".saveme",	"application/x-Binary", "binary", 1.0);
     HTSetSuffix(".dump",	"application/x-Binary", "binary", 1.0);
     HTSetSuffix(".bin",		"application/x-Binary", "binary", 1.0);
@@ -731,61 +770,104 @@ PUBLIC void HTFileInit NOARGS
     HTSetSuffix(".AXP_exe",	"application/x-Executable", "binary", 1.0);
     HTSetSuffix(".VAX-exe",	"application/x-Executable", "binary", 1.0);
     HTSetSuffix(".VAX_exe",	"application/x-Executable", "binary", 1.0);
-    HTSetSuffix(".exe",		"application/x-Executable", "binary", 1.0);
+    HTSetSuffix5(".exe",	"application/octet-stream", "binary", "Executable", 1.0);
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".exe.Z",	"application/x-Comp. Executable",
     							     "binary", 1.0);
-
     HTSetSuffix(".Z",	        "application/UNIX Compressed", "binary", 1.0);
-
     HTSetSuffix(".tar_Z",	"application/UNIX Compr. Tar", "binary", 1.0);
     HTSetSuffix(".tar.Z",	"application/UNIX Compr. Tar", "binary", 1.0);
+#else
+    HTSetSuffix5(".Z",	        "application/x-compress", "binary", "UNIX Compressed", 1.0);
+    HTSetSuffix5(".Z",	        NULL, "compress",      "UNIX Compressed", 1.0);
+    HTSetSuffix5(".exe.Z",	"application/octet-stream", "compress",
+    						       "Executable", 1.0);
+    HTSetSuffix5(".tar_Z",	"application/x-tar", "compress",
+						       "UNIX Compr. Tar", 1.0);
+    HTSetSuffix5(".tar.Z",	"application/x-tar", "compress",
+						       "UNIX Compr. Tar", 1.0);
+#endif
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix("-gz",		"application/GNU Compressed", "binary", 1.0);
     HTSetSuffix("_gz",		"application/GNU Compressed", "binary", 1.0);
     HTSetSuffix(".gz",		"application/GNU Compressed", "binary", 1.0);
 
     HTSetSuffix5(".tar.gz",	"application/x-tar", "binary", "GNU Compr. Tar", 1.0);
     HTSetSuffix5(".tgz",	"application/x-tar", "gzip", "GNU Compr. Tar", 1.0);
+#else
+    HTSetSuffix5("-gz",		"application/x-gzip", "binary", "GNU Compressed", 1.0);
+    HTSetSuffix5("_gz",		"application/x-gzip", "binary", "GNU Compressed", 1.0);
+    HTSetSuffix5(".gz",		"application/x-gzip", "binary", "GNU Compressed", 1.0);
+    HTSetSuffix5("-gz",		NULL, "gzip", "GNU Compressed", 1.0);
+    HTSetSuffix5("_gz",		NULL, "gzip", "GNU Compressed", 1.0);
+    HTSetSuffix5(".gz",		NULL, "gzip", "GNU Compressed", 1.0);
+
+    HTSetSuffix5(".tar.gz",	"application/x-tar", "gzip", "GNU Compr. Tar", 1.0);
+    HTSetSuffix5(".tgz",	"application/x-tar", "gzip", "GNU Compr. Tar", 1.0);
+#endif
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".src",		"application/x-WAIS-source", "8bit", 1.0);
     HTSetSuffix(".wsrc",	"application/x-WAIS-source", "8bit", 1.0);
+#else
+    HTSetSuffix5(".wsrc",	"application/x-wais-source", "8bit", "WAIS-source", 1.0);
+#endif
 
-    HTSetSuffix(".zip",		"application/x-Zip File", "binary", 1.0);
+    HTSetSuffix5(".zip",	"application/zip", "binary", "Zip File", 1.0);
 
     HTSetSuffix(".bz2",		"application/x-bzip2", "binary", 1.0);
 
     HTSetSuffix(".bz2",		"application/x-bzip2", "binary", 1.0);
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".uu",		"application/x-UUencoded", "8bit", 1.0);
 
     HTSetSuffix(".hqx",		"application/x-Binhex", "8bit", 1.0);
 
     HTSetSuffix(".o",		"application/x-Prog. Object", "binary", 1.0);
     HTSetSuffix(".a",		"application/x-Prog. Library", "binary", 1.0);
+#else
+    HTSetSuffix5(".uu",		"application/x-uuencoded", "7bit", "UUencoded", 1.0);
+
+    HTSetSuffix5(".hqx",	"application/mac-binhex40", "8bit", "Mac BinHex", 1.0);
+
+    HTSetSuffix5(".o",		"application/octet-stream", "binary", "Prog. Object", 0.5);
+    HTSetSuffix5(".a",		"application/octet-stream", "binary", "Prog. Library", 0.5);
+    HTSetSuffix5(".so",		"application/octet-stream", "binary", "Shared Lib", 0.5);
+#endif
 
     HTSetSuffix5(".oda",	"application/oda", "binary", "ODA", 1.0);
 
     HTSetSuffix5(".pdf",	"application/pdf", "binary", "PDF", 1.0);
 
-    HTSetSuffix(".eps",		"application/Postscript", "8bit", 1.0);
-    HTSetSuffix(".ai",		"application/Postscript", "8bit", 1.0);
-    HTSetSuffix(".ps",		"application/Postscript", "8bit", 1.0);
+    HTSetSuffix5(".eps",	"application/postscript", "8bit", "Postscript", 1.0);
+    HTSetSuffix5(".ai",		"application/postscript", "8bit", "Postscript", 1.0);
+    HTSetSuffix5(".ps",		"application/postscript", "8bit", "Postscript", 1.0);
 
-    HTSetSuffix(".rtf",		"application/RTF", "8bit", 1.0);
+    HTSetSuffix5(".rtf",	"application/rtf", "8bit", "RTF", 1.0);
 
-    HTSetSuffix(".dvi",		"application/x-DVI", "8bit", 1.0);
+    HTSetSuffix5(".dvi",	"application/x-dvi", "8bit", "DVI", 1.0);
 
-    HTSetSuffix(".hdf",		"application/x-HDF", "8bit", 1.0);
+    HTSetSuffix5(".hdf",	"application/x-hdf", "8bit", "HDF", 1.0);
 
     HTSetSuffix(".cdf",		"application/x-netcdf", "8bit", 1.0);
     HTSetSuffix(".nc",		"application/x-netcdf", "8bit", 1.0);
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".latex",	"application/x-Latex", "8bit", 1.0);
     HTSetSuffix(".tex",  	"application/x-Tex", "8bit", 1.0);
     HTSetSuffix(".texinfo",	"application/x-Texinfo", "8bit", 1.0);
     HTSetSuffix(".texi",	"application/x-Texinfo", "8bit", 1.0);
+#else
+    HTSetSuffix5(".latex",	"application/x-latex", "8bit", "LaTeX", 1.0);
+    HTSetSuffix5(".tex",  	"text/x-tex", "8bit", "TeX", 1.0);
+    HTSetSuffix5(".texinfo",	"application/x-texinfo", "8bit", "Texinfo", 1.0);
+    HTSetSuffix5(".texi",	"application/x-texinfo", "8bit", "Texinfo", 1.0);
+#endif
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".t",		"application/x-Troff", "8bit", 1.0);
     HTSetSuffix(".tr",		"application/x-Troff", "8bit", 1.0);
     HTSetSuffix(".roff",	"application/x-Troff", "8bit", 1.0);
@@ -793,51 +875,80 @@ PUBLIC void HTFileInit NOARGS
     HTSetSuffix(".man",		"application/x-Troff-man", "8bit", 1.0);
     HTSetSuffix(".me",		"application/x-Troff-me", "8bit", 1.0);
     HTSetSuffix(".ms",		"application/x-Troff-ms", "8bit", 1.0);
+#else
+    HTSetSuffix5(".t",		"application/x-troff", "8bit", "Troff", 1.0);
+    HTSetSuffix5(".tr",		"application/x-troff", "8bit", "Troff", 1.0);
+    HTSetSuffix5(".roff",	"application/x-troff", "8bit", "Troff", 1.0);
+
+    HTSetSuffix5(".man",	"application/x-troff-man", "8bit", "Man Page", 1.0);
+    HTSetSuffix5(".me",		"application/x-troff-me", "8bit", "Troff me", 1.0);
+    HTSetSuffix5(".ms",		"application/x-troff-ms", "8bit", "Troff ms", 1.0);
+#endif
 
     HTSetSuffix(".zoo",		"application/x-Zoo File", "binary", 1.0);
 
+#if defined(TRADITIONAL_SUFFIXES) || defined(VMS)
     HTSetSuffix(".bak",		"application/x-VMS BAK File", "binary", 1.0);
     HTSetSuffix(".bkp",		"application/x-VMS BAK File", "binary", 1.0);
     HTSetSuffix(".bck",		"application/x-VMS BAK File", "binary", 1.0);
 
-    HTSetSuffix(".bkp_gz",	"application/x-GNU BAK File", "binary", 1.0);
-    HTSetSuffix(".bkp-gz",	"application/x-GNU BAK File", "binary", 1.0);
-    HTSetSuffix(".bck_gz",	"application/x-GNU BAK File", "binary", 1.0);
-    HTSetSuffix(".bck-gz",	"application/x-GNU BAK File", "binary", 1.0);
+    HTSetSuffix(".bkp_gz",	"application/octet-stream", "gzip", "GNU BAK File", 1.0);
+    HTSetSuffix(".bkp-gz",	"application/octet-stream", "gzip", "GNU BAK File", 1.0);
+    HTSetSuffix(".bck_gz",	"application/octet-stream", "gzip", "GNU BAK File", 1.0);
+    HTSetSuffix(".bck-gz",	"application/octet-stream", "gzip", "GNU BAK File", 1.0);
 
-    HTSetSuffix(".bkp-Z",	"application/x-Comp. BAK File", "binary", 1.0);
-    HTSetSuffix(".bkp_Z",	"application/x-Comp. BAK File", "binary", 1.0);
-    HTSetSuffix(".bck-Z",	"application/x-Comp. BAK File", "binary", 1.0);
-    HTSetSuffix(".bck_Z",	"application/x-Comp. BAK File", "binary", 1.0);
+    HTSetSuffix(".bkp-Z",	"application/octet-stream", "compress", "Comp. BAK File", 1.0);
+    HTSetSuffix(".bkp_Z",	"application/octet-stream", "compress", "Comp. BAK File", 1.0);
+    HTSetSuffix(".bck-Z",	"application/octet-stream", "compress", "Comp. BAK File", 1.0);
+    HTSetSuffix(".bck_Z",	"application/octet-stream", "compress", "Comp. BAK File", 1.0);
+#else
+    HTSetSuffix5(".bak",	NULL, "binary", "Backup", 0.5);
+    HTSetSuffix5(".bkp",	"application/octet-stream", "binary", "VMS BAK File", 1.0);
+    HTSetSuffix5(".bck",	"application/octet-stream", "binary", "VMS BAK File", 1.0);
+#endif
 
+#if defined(TRADITIONAL_SUFFIXES) || defined(VMS)
     HTSetSuffix(".hlb",		"application/x-VMS Help Libr.", "binary", 1.0);
     HTSetSuffix(".olb",		"application/x-VMS Obj. Libr.", "binary", 1.0);
     HTSetSuffix(".tlb",		"application/x-VMS Text Libr.", "binary", 1.0);
     HTSetSuffix(".obj",		"application/x-VMS Prog. Obj.", "binary", 1.0);
     HTSetSuffix(".decw$book",	"application/x-DEC BookReader", "binary", 1.0);
     HTSetSuffix(".mem",		"application/x-RUNOFF-MANUAL", "8bit", 1.0);
+#else
+    HTSetSuffix5(".hlb",	"application/octet-stream", "binary", "VMS Help Libr.", 1.0);
+    HTSetSuffix5(".olb",	"application/octet-stream", "binary", "VMS Obj. Libr.", 1.0);
+    HTSetSuffix5(".tlb",	"application/octet-stream", "binary", "VMS Text Libr.", 1.0);
+    HTSetSuffix5(".obj",	"application/octet-stream", "binary", "Prog. Object", 1.0);
+    HTSetSuffix5(".decw$book",	"application/octet-stream", "binary", "DEC BookReader", 1.0);
+    HTSetSuffix5(".mem",	"text/x-runoff-manual", "8bit", "RUNOFF-MANUAL", 1.0);
+#endif
 
     HTSetSuffix(".vsd",		"application/visio", "binary", 1.0);
 
-    HTSetSuffix(".lha",		"application/x-lha File", "binary", 1.0);
-    HTSetSuffix(".lzh",		"application/x-lzh File", "binary", 1.0);
-
-    HTSetSuffix(".sea",		"application/x-sea File", "binary", 1.0);
-    HTSetSuffix(".sit",		"application/x-sit File", "binary", 1.0);
-
-    HTSetSuffix(".dms",		"application/x-dms File", "binary", 1.0);
-
-    HTSetSuffix(".iff",		"application/x-iff File", "binary", 1.0);
+    HTSetSuffix5(".lha",	"application/x-lha", "binary", "lha File", 1.0);
+    HTSetSuffix5(".lzh",	"application/x-lzh", "binary", "lzh File", 1.0);
+    HTSetSuffix5(".sea",	"application/x-sea", "binary", "sea File", 1.0);
+#ifdef TRADITIONAL_SUFFIXES
+    HTSetSuffix5(".sit",	"application/x-sit", "binary", "sit File", 1.0);
+#else
+    HTSetSuffix5(".sit",	"application/x-stuffit", "binary", "StuffIt", 1.0);
+#endif
+    HTSetSuffix5(".dms",	"application/x-dms", "binary", "dms File", 1.0);
+    HTSetSuffix5(".iff",	"application/x-iff", "binary", "iff File", 1.0);
 
     HTSetSuffix(".bcpio",	"application/x-bcpio", "binary", 1.0);
     HTSetSuffix(".cpio",	"application/x-cpio", "binary", 1.0);
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".gtar",	"application/x-gtar", "binary", 1.0);
+#endif
 
     HTSetSuffix(".shar",	"application/x-shar", "8bit", 1.0);
     HTSetSuffix(".share",	"application/x-share", "8bit", 1.0);
 
+#ifdef TRADITIONAL_SUFFIXES
     HTSetSuffix(".sh",		"application/x-sh", "8bit", 1.0); /* xtra */
+#endif
 
     HTSetSuffix(".sv4cpio",	"application/x-sv4cpio", "binary", 1.0);
     HTSetSuffix(".sv4crc",	"application/x-sv4crc", "binary", 1.0);
@@ -908,6 +1019,31 @@ PUBLIC void HTFileInit NOARGS
     HTSetSuffix(".htm",		"text/html", "8bit", 1.0);
     HTSetSuffix(".html",	"text/html", "8bit", 1.0);
 
+    } else { /* LYSuffixRules */
+    /*
+     *  Note that even .html -> text/html, .htm -> text/html are omitted
+     *  if default maps are compiled in but then skipped because of a
+     *  configuration file directive.  Whoever changes the config file
+     *  in this way can easily also add the SUFFIX rules there. - kw
+     */
+    CTRACE((tfp, "HTFileInit: Skipping all default (HTInit) extension maps!\n"));
+    } /* LYSuffixRules */
+
+#else /* BUILTIN_SUFFIX_MAPS */
+
+    CTRACE((tfp, "HTFileInit: Default (HTInit) extension maps not compiled in.\n"));
+    /*
+     *  The followin two are still used if BUILTIN_SUFFIX_MAPS was
+     *  undefined.  Without one of them, lynx would always need to
+     *  have a mapping specified in a lynx.cfg or mime.types file
+     *  to be usable for local HTML files at all.  That includes
+     *  many of the generated user interface pages. - kw
+     */
+    HTSetSuffix(".htm",		"text/html", "8bit", 1.0);
+    HTSetSuffix(".html",	"text/html", "8bit", 1.0);
+#endif /* BUILTIN_SUFFIX_MAPS */
+
+
     /* These should override the default extensions as necessary. */
     HTLoadExtensionsConfigFile(global_extension_map);
 
diff --git a/src/HTML.c b/src/HTML.c
index 01a6aabb..464a05b1 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -109,7 +109,8 @@ PRIVATE HTStyleSheet * styleSheet = NULL;	/* Application-wide */
 
 /*	Module-wide style cache
 */
-PRIVATE HTStyle *styles[HTML_ELEMENTS+31]; /* adding 24 nested list styles  */
+PRIVATE HTStyle *styles[HTML_ELEMENTS+HTML_EXTRA_ELEMENTS];
+					   /* adding 24 nested list styles  */
 					   /* and 3 header alignment styles */
 					   /* and 3 div alignment styles    */
 PRIVATE HTStyle *default_style = NULL;
@@ -123,11 +124,11 @@ PRIVATE int i_prior_style = -1;
 /*
  *	Private function....
  */
-PRIVATE void HTML_end_element PARAMS((HTStructured *me,
+PRIVATE int HTML_end_element PARAMS((HTStructured *me,
 				      int element_number,
 				      char **include));
 
-PRIVATE void HTML_start_element PARAMS((
+PRIVATE int HTML_start_element PARAMS((
 	HTStructured *		me,
 	int			element_number,
 	CONST BOOL*		present,
@@ -236,7 +237,7 @@ PUBLIC void HTML_put_character ARGS2(HTStructured *, me, char, c)
      *	Ignore all non-MAP content when just
      *	scanning a document for MAPs. - FM
      */
-    if (LYMapsOnly)
+    if (LYMapsOnly && me->sp[0].tag_number != HTML_OBJECT)
 	return;
 
     /*
@@ -465,7 +466,7 @@ PUBLIC void HTML_put_string ARGS2(HTStructured *, me, CONST char *, s)
     char* translated_string = NULL;
 #endif
 
-    if (LYMapsOnly || s == NULL)
+    if (s == NULL || (LYMapsOnly && me->sp[0].tag_number != HTML_OBJECT))
 	return;
 #ifdef USE_PSRC
     if (psrc_convert_string) {
@@ -623,10 +624,10 @@ PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
     CONST char* p;
     CONST char* e = s+l;
 
-    if (LYMapsOnly)
+    if (LYMapsOnly && me->sp[0].tag_number != HTML_OBJECT)
 	return;
 
-    for (p = s; s < e; p++)
+    for (p = s; p < e; p++)
 	HTML_put_character(me, *p);
 }
 
@@ -759,10 +760,159 @@ PRIVATE void HTMLSRC_apply_markup ARGS4(
 
 #endif /* USE_PSRC*/
 
+PRIVATE void LYStartArea ARGS5(
+	HTStructured *,		obj,
+	CONST char *,		href,
+	CONST char *,		alt,
+	CONST char *,		title,
+	int,			tag_charset)
+{
+    BOOL		new_present[HTML_AREA_ATTRIBUTES];
+    CONST char *		new_value[HTML_AREA_ATTRIBUTES];
+    int i;
+
+    for (i = 0; i < HTML_AREA_ATTRIBUTES; i++)
+	 new_present[i] = NO;
+
+    if (alt) {
+	new_present[HTML_AREA_ALT] = YES;
+	new_value[HTML_AREA_ALT] = (CONST char *)alt;
+    }
+    if (title && *title) {
+	new_present[HTML_AREA_TITLE] = YES;
+	new_value[HTML_AREA_TITLE] = (CONST char *)title;
+    }
+    if (href) {
+	new_present[HTML_AREA_HREF] = YES;
+	new_value[HTML_AREA_HREF] = (CONST char *)href;
+    }
+
+    (*obj->isa->start_element)(obj, HTML_AREA, new_present, new_value,
+			       tag_charset, 0);
+}
+
+PRIVATE void LYHandleFIG ARGS9(
+	HTStructured *,		me,
+	CONST BOOL*,		present,
+	CONST char **,		value,
+	BOOL,			isobject,
+	BOOL,			imagemap,
+	CONST char *,		id,
+	CONST char *,		src,
+	BOOL,			convert,
+	BOOL,			start)
+{
+    if (start == TRUE) {
+	me->inFIG = TRUE;
+	if (me->inA) {
+	    SET_SKIP_STACK(HTML_A);
+	    HTML_end_element(me, HTML_A, NULL);
+	}
+	if (!isobject) {
+	    LYEnsureDoubleSpace(me);
+	    LYResetParagraphAlignment(me);
+	    me->inFIGwithP = TRUE;
+	} else {
+	    me->inFIGwithP = FALSE;
+	    HTML_put_character(me, ' ');  /* space char may be ignored */
+	}
+	if (id && *id) {
+	    if (present && convert) {
+		CHECK_ID(HTML_FIG_ID);
+	    } else
+		LYHandleID(me, id);
+	}
+	me->in_word = NO;
+	me->inP = FALSE;
+
+	if (clickable_images && src && src != '\0') {
+	    char *href = NULL;
+	    StrAllocCopy(href, src);
+	    CHECK_FOR_INTERN(href);
+	    LYLegitimizeHREF(me, &href, TRUE, TRUE);
+	    if (*href) {
+		char *temp = NULL;
+		/*
+		 *  Check whether a base tag is in effect. - FM
+		 */
+		if ((me->inBASE && *href != '#') &&
+		    (temp = HTParse(href, me->base_href, PARSE_ALL)) &&
+		    *temp != '\0')
+		    /*
+		     *	Use reference related to the base.
+		     */
+		    StrAllocCopy(href, temp);
+		FREE(temp);
+
+		/*
+		 *  Check whether to fill in localhost. - FM
+		 */
+		LYFillLocalFileURL(&href,
+				   ((*href != '#' &&
+				     me->inBASE) ?
+				   me->base_href : me->node_anchor->address));
+
+		me->CurrentA = HTAnchor_findChildAndLink(
+					me->node_anchor,	/* Parent */
+					NULL,			/* Tag */
+					href,			/* Addresss */
+					INTERN_LT);		/* Type */
+		HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		HTML_put_string(me, (isobject ?
+		      (imagemap ? "(IMAGE)" : "(OBJECT)") : "[FIGURE]"));
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		HText_endAnchor(me->text, 0);
+		HTML_put_character(me, '-');
+		HTML_put_character(me, ' '); /* space char may be ignored */
+		me->in_word = NO;
+	    }
+	    FREE(href);
+	}
+    } else {			/* handle end tag */
+	if (me->inFIGwithP) {
+	    LYEnsureDoubleSpace(me);
+	} else {
+	    HTML_put_character(me, ' ');  /* space char may be ignored */
+	}
+	LYResetParagraphAlignment(me);
+	me->inFIGwithP = FALSE;
+	me->inFIG = FALSE;
+	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
+	if (me->List_Nesting_Level >= 0) {
+	    UPDATE_STYLE;
+	    HText_NegateLineOne(me->text);
+	}
+    }
+}
+
+PRIVATE void clear_objectdata ARGS1(
+	HTStructured *,		me)
+{
+    if (me) {
+	HTChunkClear(&me->object);
+	me->object_started = FALSE;
+	me->object_declare = FALSE;
+	me->object_shapes = FALSE;
+	me->object_ismap = FALSE;
+	FREE(me->object_usemap);
+	FREE(me->object_id);
+	FREE(me->object_title);
+	FREE(me->object_data);
+	FREE(me->object_type);
+	FREE(me->object_classid);
+	FREE(me->object_codebase);
+	FREE(me->object_codetype);
+	FREE(me->object_name);
+    }
+}
+
 /*	Start Element
 **	-------------
 */
-PRIVATE void HTML_start_element ARGS6(
+PRIVATE int HTML_start_element ARGS6(
 	HTStructured *,		me,
 	int,			element_number,
 	CONST BOOL*,		present,
@@ -787,8 +937,10 @@ PRIVATE void HTML_start_element ARGS6(
     HTChildAnchor *ID_A = NULL;		     /* HTML_foo_ID anchor */
     int url_type = 0, i = 0;
     char *cp = NULL;
-    int ElementNumber = element_number;
+    HTMLElement ElementNumber = element_number;
     BOOL intern_flag = FALSE;
+    short stbl_align = HT_ALIGN_NONE;
+    int status = HT_OK;
 #ifdef USE_COLOR_STYLE
     char* class_name;
 #  if OPT_SCN
@@ -883,7 +1035,7 @@ PRIVATE void HTML_start_element ARGS6(
 	    PSRCSTOP(tag);
 	    PSRCSTART(abracket); PUTC('>'); PSRCSTOP(abracket);
 	    psrc_nested_call=FALSE;
-	    return;
+	    return HT_OK;
 	} /*if (!psrc_nested_call) */
 	/*fall through*/
     }
@@ -891,8 +1043,9 @@ PRIVATE void HTML_start_element ARGS6(
 
     if (LYMapsOnly) {
 	if (!(ElementNumber == HTML_MAP || ElementNumber == HTML_AREA ||
-	      ElementNumber == HTML_BASE)) {
-	    return;
+	      ElementNumber == HTML_BASE || ElementNumber == HTML_OBJECT ||
+	      ElementNumber == HTML_A)) {
+	    return HT_OK;
 	}
     } else if (!me->text) {
 	UPDATE_STYLE;
@@ -1461,6 +1614,12 @@ PRIVATE void HTML_start_element ARGS6(
 		HText_beginAnchor(me->text, me->inUnderline, ID_A);
 		HText_endAnchor(me->text, 0);
 		HText_setToolbar(me->text);
+	    } else {
+		/*
+		 *  Add collapsible space to separate link from previous
+		 *  generated links. - kw
+		 */
+		HTML_put_character(me, ' ');
 	    }
 	    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
 	    if (me->inBoldH == FALSE)
@@ -1740,7 +1899,7 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_MARQUEE:
 	change_paragraph_style(me, styles[HTML_BANNER]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == ElementNumber)
+	if (me->sp->tag_number == (int) ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	/*
 	 *  Treat this as a toolbar if we don't have one
@@ -2062,6 +2221,13 @@ PRIVATE void HTML_start_element ARGS6(
 	    CTRACE((tfp, "HTML: TAB tag has no attributes.  Ignored.\n"));
 	    break;
 	}
+	/*
+	 *  If page author is using TAB within a TABLE, it's probably
+	 *  formatted specifically to work well for Lynx without simple
+	 *  table tracking code.  Cancel tracking, it would only make
+	 *  things worse. - kw
+	 */
+	HText_cancelStbl(me->text);
 	UPDATE_STYLE;
 
 	CANT_JUSTIFY_THIS_LINE
@@ -2215,13 +2381,23 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_KBD:
     case HTML_SAMP:
     case HTML_SMALL:
-    case HTML_SUB:
-    case HTML_SUP:
     case HTML_TT:
     case HTML_VAR:
 	CHECK_ID(HTML_GEN_ID);
 	break; /* ignore */
 
+    case HTML_SUP:
+	if (isxdigit((unsigned char)HText_getLastChar(me->text))) {
+	    HText_appendCharacter(me->text, '^');
+	}
+	CHECK_ID(HTML_GEN_ID);
+	break;
+
+    case HTML_SUB:
+	HText_appendCharacter(me->text, '[');
+	CHECK_ID(HTML_GEN_ID);
+	break;
+
     case HTML_DEL:
     case HTML_S:
     case HTML_STRIKE:
@@ -2285,7 +2461,7 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_BQ:
 	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == ElementNumber)
+	if (me->sp->tag_number == (int) ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	CHECK_ID(HTML_BQ_ID);
 	break;
@@ -2293,7 +2469,7 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_NOTE:
 	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == ElementNumber)
+	if (me->sp->tag_number == (int) ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	CHECK_ID(HTML_NOTE_ID);
 	{
@@ -2337,7 +2513,7 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_ADDRESS:
 	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == ElementNumber)
+	if (me->sp->tag_number == (int) ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	CHECK_ID(HTML_ADDRESS_ID);
 	break;
@@ -2778,7 +2954,7 @@ PRIVATE void HTML_start_element ARGS6(
     case HTML_FN:
 	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == ElementNumber)
+	if (me->sp->tag_number == (int) ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	CHECK_ID(HTML_FN_ID);
 	if (me->inUnderline == FALSE)
@@ -2794,6 +2970,25 @@ PRIVATE void HTML_start_element ARGS6(
 	break;
 
     case HTML_A:
+	    /*
+	     *  If we are looking for client-side image maps,
+	     *  then handle an A within a MAP that has a COORDS
+	     *  attribute as an AREA tag.  Unfortunately we lose
+	     *  the anchor text this way for the LYNXIMGMAP, we
+	     *  would have to do much more parsing to collect it.
+	     *  After potentially handling the A as AREA, always return
+	     *  immediately if only looking for image maps, without
+	     *  pushing anything on the style stack. - kw
+	     */
+	if (me->map_address && present && present[HTML_A_COORDS])
+	    LYStartArea(me,
+			present[HTML_A_HREF] ? value[HTML_A_HREF] : NULL,
+			NULL,
+			present[HTML_A_TITLE] ? value[HTML_A_TITLE] : NULL,
+			tag_charset);
+	if (LYMapsOnly) {
+	    return HT_OK;
+	}
 	/*
 	 *  A may have been declared SGML_EMPTY in HTMLDTD.c, and
 	 *  SGML_character() in SGML.c may check for an A end
@@ -3533,6 +3728,16 @@ PRIVATE void HTML_start_element ARGS6(
 	}
 
 	/*
+	 *  Generate a target anchor in this place in the containing
+	 *  document.  MAP can now contain block markup, if it doesn't
+	 *  contain any AREAs (or A anchors with COORDS converted to AREAs)
+	 *  the current location can be used as a fallback for following
+	 *  a USEMAP link. - kw
+	 */
+	 if (!LYMapsOnly)
+	     LYHandleID(me, id_string);
+
+	/*
 	 *  Load map_address. - FM
 	 */
 	if (id_string) {
@@ -3677,6 +3882,20 @@ PRIVATE void HTML_start_element ARGS6(
 	break;
 
     case HTML_FIG:
+	if (present)
+	    LYHandleFIG(me, present, value,
+			present[HTML_FIG_ISOBJECT],
+			present[HTML_FIG_IMAGEMAP],
+			present[HTML_FIG_ID] ? value[HTML_FIG_ID] : NULL,
+			present[HTML_FIG_SRC] ? value[HTML_FIG_SRC] : NULL,
+			YES, TRUE);
+	else
+	    LYHandleFIG(me, NULL, NULL,
+			0,
+			0,
+			NULL,
+			NULL, YES, TRUE);
+#if 0
 	me->inFIG = TRUE;
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
@@ -3741,6 +3960,7 @@ PRIVATE void HTML_start_element ARGS6(
 	    }
 	    FREE(href);
 	}
+#endif
 	break;
 
     case HTML_OBJECT:
@@ -3847,9 +4067,81 @@ PRIVATE void HTML_start_element ARGS6(
 		}
 	    }
 	    /*
-	     *	Set flag that we are accumulating OBJECT content. - FM
+	     *  If we can determine now that we are not going to do anything
+	     *  special to the OBJECT element's SGML contents, like skipping
+	     *  it completely or collecting it up in order to add something
+	     *  after it, then generate any output that should be emitted in the
+	     *  place of the OBJECT start tag NOW, then don't initialize special
+	     *  handling but return, letting our SGML parser know that further
+	     *  content is to be parsed normally not literally.  We could defer
+	     *  this until we have collected the contents and then recycle the
+	     *  contents (as was previously always done), but that has a higher
+	     *  chance of completely losing content in case of nesting errors
+	     *  in the input, incomplete transmissions, etc. - kw
 	     */
-	    me->object_started = TRUE;
+	    if ((!present ||
+		 (me->object_declare == FALSE && me->object_name == NULL &&
+		  me->object_shapes == FALSE && me->object_usemap == NULL))) {
+		if (!LYMapsOnly) {
+		    if (!clickable_images || me->object_data == NULL ||
+			!(me->object_data != NULL &&
+			  me->object_classid == NULL &&
+			  me->object_codebase == NULL &&
+			  me->object_codetype == NULL))
+			FREE(me->object_data);
+		    if (me->object_data) {
+			HTStartAnchor5(me,
+				       me->object_id ? value[HTML_OBJECT_ID]
+					: NULL,
+				       value[HTML_OBJECT_DATA],
+				       value[HTML_OBJECT_TYPE],
+				       tag_charset);
+			if ((me->object_type != NULL) &&
+			    !strncasecomp(me->object_type, "image/", 6))
+			    HTML_put_string(me, "(IMAGE)");
+			else
+			    HTML_put_string(me, "(OBJECT)");
+			HTML_end_element(me,HTML_A,NULL);
+		    } else if (me->object_id)
+			LYHandleID(me, me->object_id);
+		}
+		clear_objectdata(me);
+		/*
+		 *  We do NOT want the HTML_put_* functions that are going
+		 *  to be called for the OBJECT's character content to
+		 *  add to the chunk, so we don't push on the stack.
+		 *  Instead we keep a counter for open OBJECT tags that
+		 *  are treated this way, so HTML_end_element can skip
+		 *  handling the corresponding end tag that is going to
+		 *  arrive unexpectedly as far as our stack is concerned.
+		 */
+		status = HT_PARSER_OTHER_CONTENT;
+		if (me->sp[0].tag_number == HTML_FIG &&
+		    me->objects_figged_open > 0) {
+		    ElementNumber = HTML_OBJECT_M;
+		} else {
+		    me->objects_mixed_open++;
+		    SET_SKIP_STACK(HTML_OBJECT);
+		}
+	    } else if (me->object_declare == FALSE && me->object_name == NULL &&
+		       me->object_shapes == TRUE) {
+		LYHandleFIG(me, present, value,
+		    1,
+		    1 || me->object_ismap,
+		    me->object_id,
+		    (me->object_data && !me->object_classid) ? value[HTML_OBJECT_DATA] : NULL,
+		    NO, TRUE);
+		clear_objectdata(me);
+		status = HT_PARSER_OTHER_CONTENT;
+		me->objects_figged_open++;
+		ElementNumber = HTML_FIG;
+
+	    } else {
+		/*
+		 *	Set flag that we are accumulating OBJECT content. - FM
+		 */
+		me->object_started = TRUE;
+	    }
 	}
 	break;
 
@@ -5477,11 +5769,22 @@ PRIVATE void HTML_start_element ARGS6(
 
     case HTML_TABLE:
 	/*
-	 *  Not implemented.  Just treat as a division
+	 *  Not fully implemented.  Just treat as a division
 	 *  with respect to any ALIGN attribute, with
 	 *  a default of HT_LEFT, or leave as a PRE
 	 *  block if we are presently in one. - FM
+	 *
+	 *  Also notify simple table tracking code unless
+	 *  in a preformatted section, or (currently) non-left
+	 *  alignment.  But first cancel tracking any already
+	 *  open (enclosing) table.
+	 *
+	 *  If page author is using a TABLE within PRE, it's probably
+	 *  formatted specifically to work well for Lynx without simple
+	 *  table tracking code.  Cancel tracking, it would only make
+	 *  things worse. - kw
 	 */
+	HText_cancelStbl(me->text);
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
 	    HTML_end_element(me, HTML_A, include);
@@ -5525,33 +5828,41 @@ PRIVATE void HTML_start_element ARGS6(
 		change_paragraph_style(me, styles[HTML_DCENTER]);
 		UPDATE_STYLE;
 		me->current_default_alignment = styles[HTML_DCENTER]->alignment;
-
 #endif
+		stbl_align = HT_CENTER;
+
 	    } else if (!strcasecomp(value[HTML_TABLE_ALIGN], "right")) {
 		me->DivisionAlignments[me->Division_Level] = HT_RIGHT;
 		change_paragraph_style(me, styles[HTML_DRIGHT]);
 		UPDATE_STYLE;
 		me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
+		stbl_align = HT_RIGHT;
 	    } else {
 		me->DivisionAlignments[me->Division_Level] = HT_LEFT;
 		change_paragraph_style(me, styles[HTML_DLEFT]);
 		UPDATE_STYLE;
 		me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+		if (!strcasecomp(value[HTML_TABLE_ALIGN], "left") ||
+		    !strcasecomp(value[HTML_TABLE_ALIGN], "justify"))
+		    stbl_align = HT_LEFT;
 	    }
 	} else {
 	    me->DivisionAlignments[me->Division_Level] = HT_LEFT;
 	    change_paragraph_style(me, styles[HTML_DLEFT]);
 	    UPDATE_STYLE;
 	    me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+	    /* stbl_align remains HT_ALIGN_NONE */
 	}
 	CHECK_ID(HTML_TABLE_ID);
+	HText_startStblTABLE(me->text, stbl_align);
 	break;
 
     case HTML_TR:
 	/*
-	 *  Not yet implemented.  Just start a new row,
+	 *  Not fully implemented.  Just start a new row,
 	 *  if needed, act on an ALIGN attribute if present,
 	 *  and check for an ID link. - FM
+	 *  Also notify simple table tracking code. - kw
 	 */
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
@@ -5571,6 +5882,7 @@ PRIVATE void HTML_start_element ARGS6(
 	if (!strcmp(me->sp->style->name, "Preformatted")) {
 	    CHECK_ID(HTML_TR_ID);
 	    me->inP = FALSE;
+/*	    HText_cancelStbl(me->text);  seems unnecessary here - kw */
 	    break;
 	}
 	if (LYoverride_default_alignment(me)) {
@@ -5584,33 +5896,37 @@ PRIVATE void HTML_start_element ARGS6(
 	    me->sp->style->alignment = (short) me->current_default_alignment;
 	}
 	if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) {
-#ifdef SH_EX
 	    if (!strcasecomp(value[HTML_TR_ALIGN], "center") &&
-		!(me->List_Nesting_Level >= 0 && !me->inP))
+		!(me->List_Nesting_Level >= 0 && !me->inP)) {
+#ifdef SH_EX
 		if (no_table_center)
 		    me->sp->style->alignment = HT_LEFT;
 		else
 		    me->sp->style->alignment = HT_CENTER;
 #else
-	    if (!strcasecomp(value[HTML_TR_ALIGN], "center") &&
-		!(me->List_Nesting_Level >= 0 && !me->inP))
 		me->sp->style->alignment = HT_CENTER;
 #endif
-	    else if (!strcasecomp(value[HTML_TR_ALIGN], "right") &&
-		!(me->List_Nesting_Level >= 0 && !me->inP))
+		stbl_align = HT_CENTER;
+	    } else if (!strcasecomp(value[HTML_TR_ALIGN], "right") &&
+		       !(me->List_Nesting_Level >= 0 && !me->inP)) {
 		me->sp->style->alignment = HT_RIGHT;
-	    else if (!strcasecomp(value[HTML_TR_ALIGN], "left") ||
-		     !strcasecomp(value[HTML_TR_ALIGN], "justify"))
+		stbl_align = HT_RIGHT;
+	    } else if (!strcasecomp(value[HTML_TR_ALIGN], "left") ||
+		       !strcasecomp(value[HTML_TR_ALIGN], "justify")) {
 		me->sp->style->alignment = HT_LEFT;
+		stbl_align = HT_LEFT;
+	    }
 	}
 
 	CHECK_ID(HTML_TR_ID);
 	me->inP = FALSE;
+	HText_startStblTR(me->text, stbl_align);
 	break;
 
     case HTML_THEAD:
     case HTML_TFOOT:
     case HTML_TBODY:
+	HText_endStblTR(me->text);
 	/*
 	 *  Not yet implemented.  Just check for an ID link. - FM
 	 */
@@ -5639,28 +5955,12 @@ PRIVATE void HTML_start_element ARGS6(
 	    SET_SKIP_STACK(HTML_U);
 	    HTML_end_element(me, HTML_U, include);
 	}
+/*	HText_cancelStbl(me->text);  we ingnore it instead - kw */
 	UPDATE_STYLE;
 	CHECK_ID(HTML_COL_ID);
 	break;
 
     case HTML_TH:
-	if (me->inA) {
-	    SET_SKIP_STACK(HTML_A);
-	    HTML_end_element(me, HTML_A, include);
-	}
-	if (me->Underline_Level > 0) {
-	    SET_SKIP_STACK(HTML_U);
-	    HTML_end_element(me, HTML_U, include);
-	}
-	UPDATE_STYLE;
-	CHECK_ID(HTML_TD_ID);
-	/*
-	 *  Not yet implemented.  Just add a collapsible space and break. - FM
-	 */
-	HTML_put_character(me, ' ');
-	me->in_word = NO;
-	break;
-
     case HTML_TD:
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
@@ -5673,9 +5973,29 @@ PRIVATE void HTML_start_element ARGS6(
 	UPDATE_STYLE;
 	CHECK_ID(HTML_TD_ID);
 	/*
-	 *  Not yet implemented.  Just add a collapsible space and break. - FM
+	 *  Not fully implemented.  Just add a collapsible space and break. - FM
+	 *  Also notify simple table tracking code. - kw
 	 */
 	HTML_put_character(me, ' ');
+	{
+	    int colspan = 1;
+	    if (present && present[HTML_TD_COLSPAN] &&
+		value[HTML_TD_COLSPAN] &&
+		isdigit((unsigned char)*value[HTML_TD_COLSPAN]))
+		colspan = atoi(value[HTML_TD_COLSPAN]);
+	    if (present && present[HTML_TD_ALIGN] && value[HTML_TD_ALIGN]) {
+		if (!strcasecomp(value[HTML_TD_ALIGN], "center")) {
+		    stbl_align = HT_CENTER;
+		} else if (!strcasecomp(value[HTML_TD_ALIGN], "right")) {
+		    stbl_align = HT_RIGHT;
+		} else if (!strcasecomp(value[HTML_TD_ALIGN], "left") ||
+			   !strcasecomp(value[HTML_TD_ALIGN], "justify")) {
+		    stbl_align = HT_LEFT;
+		}
+	    }
+	    HText_startStblTD(me->text, colspan, stbl_align,
+			      (ElementNumber == HTML_TH));
+	}
 	me->in_word = NO;
 	break;
 
@@ -5693,13 +6013,14 @@ PRIVATE void HTML_start_element ARGS6(
 
     } /* end switch */
 
-    if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY) {
+    if (ElementNumber >= HTML_ELEMENTS ||
+	HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY) {
 	if (me->skip_stack > 0) {
 	    CTRACE((tfp,
     "HTML:begin_element: internal call (level %d), leaving on stack - `%s'\n",
 			me->skip_stack, me->sp->style->name));
 	    me->skip_stack--;
-	    return;
+	    return status;
 	}
 	if (me->sp == me->stack) {
 	    if (me->stack_overrun == FALSE) {
@@ -5713,7 +6034,7 @@ PRIVATE void HTML_start_element ARGS6(
 		}
 		me->stack_overrun = TRUE;
 	    }
-	    return;
+	    return HT_ERROR;
 	}
 
 	CTRACE((tfp,"HTML:begin_element[%d]: adding style to stack - %s\n",
@@ -5738,10 +6059,8 @@ PRIVATE void HTML_start_element ARGS6(
 
 #if defined(USE_COLOR_STYLE)
 /* end really empty tags straight away */
-#define REALLY_EMPTY(e) ((HTML_dtd.tags[e].contents == SGML_EMPTY) && \
-			 !(HTML_dtd.tags[e].flags & Tgf_nreie))
 
-    if (REALLY_EMPTY(element_number))
+    if (ReallyEmptyTagNum(element_number))
     {
 	CTRACE((tfp, "STYLE:begin_element:ending EMPTY element style\n"));
 #if !defined(USE_HASH)
@@ -5763,6 +6082,7 @@ PRIVATE void HTML_start_element ARGS6(
 #endif
     }
 #endif /* USE_COLOR_STYLE */
+    return status;
 }
 
 /*		End Element
@@ -5779,12 +6099,13 @@ PRIVATE void HTML_start_element ARGS6(
 **	(internal code errors apart) good nesting.  The parser checks
 **	incoming code errors, not this module.
 */
-PRIVATE void HTML_end_element ARGS3(
+PRIVATE int HTML_end_element ARGS3(
 	HTStructured *,		me,
 	int,			element_number,
 	char **,		include)
 {
     int i = 0;
+    int status = HT_OK;
     char *temp = NULL, *cp = NULL;
     BOOL BreakFlag = FALSE;
     EMIT_IFDEF_EXP_JUSTIFY_ELTS(BOOL reached_awaited_stacked_elt=FALSE;)
@@ -5809,30 +6130,35 @@ PRIVATE void HTML_end_element ARGS3(
 	    PSRCSTOP(tag);
 	    PSRCSTART(abracket); PUTC('>'); PSRCSTOP(abracket);
 	    psrc_nested_call=FALSE;
-	    return;
+	    return HT_OK;
 	}
 	/*fall through*/
     }
 #endif
 
-#ifdef CAREFUL			/* parser assumed to produce good nesting */
-    if (element_number != me->sp[0].tag_number &&
+    if ((me->sp >= (me->stack + MAX_NESTING - 1) ||
+	 element_number != me->sp[0].tag_number) &&
 	HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
 	CTRACE((tfp,
-		"HTMLText: end of element %s when expecting end of %s\n",
+		"HTML: end of element %s when expecting end of %s\n",
 		HTML_dtd.tags[element_number].name,
+	       (me->sp == me->stack + MAX_NESTING - 1) ? "none" :
+	       (me->sp->tag_number < 0) ? "*invalid tag*" :
+	       (me->sp->tag_number >= HTML_ELEMENTS) ? "special tag" :
 		HTML_dtd.tags[me->sp->tag_number].name));
+#ifdef CAREFUL			/* parser assumed to produce good nesting */
 		/* panic */
-    }
 #endif /* CAREFUL */
+    }
 
     /*
      *	If we're seeking MAPs, skip everything that's
      *	not a MAP or AREA tag. - FM
      */
     if (LYMapsOnly) {
-	if (!(element_number == HTML_MAP || element_number == HTML_AREA)) {
-	    return;
+	if (!(element_number == HTML_MAP || element_number == HTML_AREA ||
+	      element_number == HTML_OBJECT)) {
+	    return HT_OK;
 	}
     }
 
@@ -5862,10 +6188,32 @@ PRIVATE void HTML_end_element ARGS3(
 	     */
 	    BreakFlag = TRUE;
 	}
+	if (me->skip_stack == 0 && element_number == HTML_OBJECT &&
+	    me->sp[0].tag_number == HTML_OBJECT_M &&
+	    (me->sp < (me->stack + MAX_NESTING - 1)))
+	    me->sp[0].tag_number = HTML_OBJECT;
 	if (me->skip_stack > 0) {
 	     CTRACE((tfp, "HTML:end_element: Internal call (level %d), leaving on stack - %s\n",
 			me->skip_stack, me->sp->style->name));
 	    me->skip_stack--;
+	} else if (element_number == HTML_OBJECT &&
+		   me->sp[0].tag_number != HTML_OBJECT &&
+		   me->sp[0].tag_number != HTML_OBJECT_M &&
+		   me->objects_mixed_open > 0 &&
+		   !(me->objects_figged_open > 0 &&
+		       me->sp[0].tag_number == HTML_FIG)) {
+	    /*
+	     *	Ignore non-corresponding OBJECT tags that we
+	     *	didn't push because the SGML parser was supposed
+	     *  to go on parsing the contents non-literally. - kw
+	     */
+	    CTRACE((tfp,
+		   "HTML:end_element[%d]: %s (level %d), %s - %s\n",
+		   (int) STACKLEVEL(me),
+		   "Special OBJECT handling", me->objects_mixed_open,
+		   "leaving on stack",
+		   me->sp->style->name));
+	    me->objects_mixed_open--;
 	} else if (me->stack_overrun == TRUE &&
 	    element_number != me->sp[0].tag_number) {
 	    /*
@@ -5879,7 +6227,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	offer reasonable protection against crashes
 	     *	if an overrun does occur. - FM
 	     */
-	    return;
+	    return HT_OK; /* let's pretend... */
 	} else if (element_number == HTML_SELECT &&
 	    me->sp[0].tag_number != HTML_SELECT) {
 	    /*
@@ -5888,7 +6236,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	to deal with markup which amounts to a nested
 	     *	SELECT, or an out of order FORM end tag. - FM
 	     */
-	    return;
+	    return HT_OK;
 	} else if ((element_number != me->sp[0].tag_number) &&
 	    HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY &&
 	    (me->sp[0].tag_number == HTML_UL ||
@@ -5907,12 +6255,30 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	an HTML_LH, which we've declared as
 	     *	SGML_EMPTY, so just return. - FM
 	     */
-	    return;
+	    return HT_OK;
 	} else if (me->sp < (me->stack + MAX_NESTING - 1)) {
 #ifdef EXP_JUSTIFY_ELTS
 	    if (wait_for_this_stacked_elt == me->stack - me->sp + MAX_NESTING)
 		reached_awaited_stacked_elt = TRUE;
 #endif
+	    if (element_number == HTML_OBJECT) {
+		if (me->sp[0].tag_number == HTML_FIG &&
+		    me->objects_figged_open > 0) {
+		    /*
+		     *  It's an OBJECT for which we substituted a FIG,
+		     *  so pop the FIG and pretend that's what we are
+		     *  being called for. - kw
+		     */
+		    CTRACE((tfp,
+		       "HTML:end_element[%d]: %s (level %d), %s - %s\n",
+			(int) STACKLEVEL(me),
+		       "Special OBJECT->FIG handling", me->objects_figged_open,
+		       "treating as end FIG",
+		       me->sp->style->name));
+		    me->objects_figged_open--;
+		    element_number = HTML_FIG;
+		}
+	    }
 	    (me->sp)++;
 	    CTRACE((tfp, "HTML:end_element[%d]: Popped style off stack - %s\n",
 			(int) STACKLEVEL(me),
@@ -5927,7 +6293,7 @@ PRIVATE void HTML_end_element ARGS3(
 	    if (reached_awaited_stacked_elt)
 		wait_for_this_stacked_elt=-1;
 #endif
-	return;
+	return HT_OK; /* let's pretend... */
     }
 
     /*
@@ -6003,6 +6369,8 @@ PRIVATE void HTML_end_element ARGS3(
 	    if ((LYMultiBookmarks == TRUE) ||
 		((bookmark_page && *bookmark_page) &&
 		 strcmp(me->node_anchor->bookmark, bookmark_page))) {
+		if (!include)
+		    include = &me->xinclude;
 		for (i = 0; i <= MBM_V_MAXFILES; i++) {
 		    if (MBM_A_subbookmark[i] &&
 			!strcmp(MBM_A_subbookmark[i],
@@ -6208,12 +6576,15 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_KBD:
     case HTML_SAMP:
     case HTML_SMALL:
-    case HTML_SUB:
     case HTML_SUP:
     case HTML_TT:
     case HTML_VAR:
 	break;
 
+    case HTML_SUB:
+	HText_appendCharacter(me->text, ']');
+	break;
+
     case HTML_DEL:
     case HTML_S:
     case HTML_STRIKE:
@@ -6362,19 +6733,11 @@ PRIVATE void HTML_end_element ARGS3(
 	break;
 
     case HTML_FIG:
-	if (me->inFIGwithP) {
-	    LYEnsureDoubleSpace(me);
-	} else {
-	    HTML_put_character(me, ' ');  /* space char may be ignored */
-	}
-	LYResetParagraphAlignment(me);
-	me->inFIGwithP = FALSE;
-	me->inFIG = FALSE;
-	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
-	if (me->List_Nesting_Level >= 0) {
-	    UPDATE_STYLE;
-	    HText_NegateLineOne(me->text);
-	}
+	LYHandleFIG(me, NULL, NULL,
+		    0,
+		    0,
+		    NULL,
+		    NULL, NO, FALSE);
 	break;
 
     case HTML_OBJECT:
@@ -6383,7 +6746,8 @@ PRIVATE void HTML_end_element ARGS3(
 	 */
 	{
 	    int s = 0, e = 0;
-	    char *start = NULL, *first_end = NULL;
+	    char *start = NULL, *first_end = NULL, *last_end = NULL;
+	    char *first_map = NULL, *last_map = NULL;
 	    BOOL have_param = FALSE;
 	    char *data = NULL;
 
@@ -6399,39 +6763,31 @@ PRIVATE void HTML_end_element ARGS3(
 		if (!strncmp(cp, "<!--", 4)) {
 		    data = LYFindEndOfComment(cp);
 		    cp = data;
-		} else if (s == 0 && !strncasecomp(cp, "<PARAM", 6)) {
+		} else if (s == 0 && !strncasecomp(cp, "<PARAM", 6) &&
+		    !IsNmChar(cp[6])) {
 		    have_param = TRUE;
-		} else if (!strncasecomp(cp, "<OBJECT", 7)) {
+		} else if (!strncasecomp(cp, "<OBJECT", 7) &&
+		    !IsNmChar(cp[7])) {
 		    if (s == 0)
 			start = cp;
 		    s++;
-		} else if (!strncasecomp(cp, "</OBJECT", 8)) {
+		} else if (!strncasecomp(cp, "</OBJECT", 8) &&
+		    !IsNmChar(cp[8])) {
 		    if (e == 0)
 			first_end = cp;
+		    last_end = cp;
 		    e++;
+		} else if (!strncasecomp(cp, "<MAP", 4) &&
+		    !IsNmChar(cp[4])) {
+		    if (!first_map)
+			first_map = cp;
+		    last_map = cp;
+		} else if (!strncasecomp(cp, "</MAP", 5) &&
+		    !IsNmChar(cp[5])) {
+		    last_map = cp;
 		}
 		data = ++cp;
 	    }
-	    if (s > e) {
-		/*
-		 *  We have nested OBJECT tags, and not yet all of the
-		 *  end tags, so restore an end tag to the content, and
-		 *  pass a dummy start tag to the SGML parser so that it
-		 *  will resume the accumulation of OBJECT content. - FM
-		 */
-		CTRACE((tfp, "HTML: Nested OBJECT tags.  Recycling.\n"));
-		if (*include == NULL) {
-		    StrAllocCopy(*include, "<OBJECT>");
-		} else {
-		    if (0 && strstr(*include, me->object.data) == NULL) {
-			StrAllocCat(*include, "<OBJECT>");
-		    }
-		}
-		me->object.size--;
-		HTChunkPuts(&me->object, "</OBJECT>");
-		change_paragraph_style(me, me->sp->style);
-		break;
-	    }
 	    if (s < e) {
 		/*
 		 *  We had more end tags than start tags, so
@@ -6447,6 +6803,60 @@ PRIVATE void HTML_end_element ARGS3(
 		}
 		goto End_Object;
 	    }
+	    if (s > e) {
+		if (!me->object_declare && !me->object_name &&
+		    !(me->object_shapes && !LYMapsOnly) &&
+		    !(me->object_usemap != NULL && !LYMapsOnly) &&
+		    !(clickable_images && !LYMapsOnly &&
+		      me->object_data != NULL &&
+		      !have_param &&
+		      me->object_classid == NULL &&
+		      me->object_codebase == NULL &&
+		      me->object_codetype == NULL)) {
+		    /*
+		     *  We have nested OBJECT tags, and not yet all of the
+		     *  end tags, but have a case where the content needs
+		     *  to be parsed again (not dropped) and where we don't
+		     *  want to output anything special at the point when we
+		     *  *do* have accumulated all the end tags.  So recycle
+		     *  the incomplete contents now, and signal the SGML
+		     *  parser that it should not regard the current OBJECT
+		     *  ended but should treat its contents as mixed.
+		     *  Normally these cases would have already handled
+		     *  in the real start_element call, so this block may
+		     *  not be necessary. - kw
+		     */
+		    CTRACE((tfp, "%s:\n%s\n",
+			   "HTML: Nested OBJECT tags.  Recycling incomplete contents",
+			   me->object.data));
+		    status = HT_PARSER_OTHER_CONTENT;
+		    me->object.size--;
+		    HTChunkPuts(&me->object, "</OBJECT>");
+		    if (!include)	/* error, should not happen */
+			include = &me->xinclude;
+		    StrnAllocCat(*include, me->object.data, me->object.size);
+		    clear_objectdata(me);
+		    /* an internal fake call to keep our stack happy: */
+		    HTML_start_element(me, HTML_OBJECT, NULL,NULL,
+				       me->tag_charset, include);
+		    break;
+		}
+		/*
+		 *  We have nested OBJECT tags, and not yet all of the
+		 *  end tags, and we want the end tags.  So restore an
+		 *  end tag to the content, and signal to the SGML parser
+		 *  that it should resume the accumulation of OBJECT content
+		 *  (after calling back to start_element) in a way that
+		 *  is equivalent to passing it a dummy start tag. - FM, kw
+		 */
+		CTRACE((tfp, "HTML: Nested OBJECT tags.  Recycling.\n"));
+		status = HT_PARSER_REOPEN_ELT;
+		me->object.size--;
+		HTChunkPuts(&me->object, "</OBJECT>");
+		if (!LYMapsOnly)
+		    change_paragraph_style(me, me->sp->style);
+		break;
+	    }
 
 	    /*
 	     *	OBJECT start and end tags are fully matched,
@@ -6464,7 +6874,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	the content (sigh 8-). - FM
 	     */
 	    if (me->object_declare == TRUE) {
-		if (me->object_id && *me->object_id)
+		if (me->object_id && *me->object_id && !LYMapsOnly)
 		    LYHandleID(me, me->object_id);
 		CTRACE((tfp, "HTML: DECLAREd OBJECT.  Ignoring!\n"));
 		goto End_Object;
@@ -6476,7 +6886,7 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	present, and discard the content until we
 	     *	have code to handle these. (sigh 8-). - FM
 	     */
-	    if (me->object_name != NULL) {
+	    if (me->object_name != NULL && !LYMapsOnly) {
 		if (me->object_id && *me->object_id)
 		    LYHandleID(me, me->object_id);
 		CTRACE((tfp, "HTML: NAMEd OBJECT.  Ignoring!\n"));
@@ -6495,20 +6905,36 @@ PRIVATE void HTML_end_element ARGS3(
 		     *	to have succeeded are met.  We'll hope that
 		     *	it did succeed. - FM
 		     */
-		    *first_end = '\0';
-		    data = NULL;
-		    StrAllocCopy(data, start);
-		    if (e > 1) {
-			for (i = e; i > 1; i--) {
-			    StrAllocCat(data, "</OBJECT><OBJECT>");
+		    if (LYMapsOnly) {
+			/*
+			 *  Well we don't need to do this any more,
+			 *  nested objects should either not get here
+			 *  any more at all or can be handled fine by
+			 *  other code below.  Leave in place for now
+			 *  as a special case for LYMapsOnly. - kw
+			 */
+			if (LYMapsOnly && (!last_map || last_map < first_end))
+			    *first_end = '\0';
+			else
+			    e = 0;
+			data = NULL;
+			if (LYMapsOnly && (!first_map || first_map > start))
+			    StrAllocCopy(data, start);
+			else
+			    StrAllocCopy(data, me->object.data);
+			if (e > 0) {
+			    for (i = e; i > 0; i--) {
+				StrAllocCat(data, "</OBJECT>");
+			    }
 			}
+			if (!include)	/* error, should not happen */
+			    include = &me->xinclude;
+			StrAllocCat(*include, data);
+			CTRACE((tfp, "HTML: Recycling nested OBJECT%s.\n",
+			       (s > 1) ? "s" : ""));
+			FREE(data);
+			goto End_Object;
 		    }
-		    StrAllocCat(data, "</OBJECT>");
-		    StrAllocCat(*include, data);
-		    CTRACE((tfp, "HTML: Recycling nested OBJECT%s.\n",
-					(e > 1) ? "s" : ""));
-		    FREE(data);
-		    goto End_Object;
 		} else {
 		    if (TRACE) {
 			fprintf(tfp,
@@ -6522,10 +6948,16 @@ PRIVATE void HTML_end_element ARGS3(
 	    }
 
 	    /*
-	     *	If it's content has SHAPES, convert it to FIG. - FM
+	     *	If its content has SHAPES, convert it to FIG. - FM
+	     *
+	     *  This is now handled in our start_element without using
+	     *  include if the SGML parser cooperates, so this block
+	     *  may be unnecessary. - kw
 	     */
-	    if (me->object_shapes == TRUE) {
+	    if (me->object_shapes == TRUE && !LYMapsOnly) {
 		CTRACE((tfp, "HTML: OBJECT has SHAPES.  Converting to FIG.\n"));
+		if (!include)	/* error, should not happen */
+		    include = &me->xinclude;
 		StrAllocCat(*include, "<FIG ISOBJECT IMAGEMAP");
 		if (me->object_ismap == TRUE)
 		    StrAllocCat(*include, " IMAGEMAP");
@@ -6552,9 +6984,11 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	If it has a USEMAP attribute and didn't have SHAPES,
 	     *	convert it to IMG. - FM
 	     */
-	    if (me->object_usemap != NULL) {
+	    if (me->object_usemap != NULL && !LYMapsOnly) {
 		CTRACE((tfp, "HTML: OBJECT has USEMAP.  Converting to IMG.\n"));
 
+		if (!include)	/* error, should not happen */
+		    include = &me->xinclude;
 		StrAllocCat(*include, "<IMG ISOBJECT");
 		if (me->object_id != NULL) {
 		    /*
@@ -6598,20 +7032,70 @@ PRIVATE void HTML_end_element ARGS3(
 		} else {
 		    StrAllocCat(*include, ">");
 		}
+		/*
+		 *  Add the content if it has <MAP, since that may
+		 *  be the MAP this usemap points to.  But if we have
+		 *  nested objects, try to eliminate portions that
+		 *  cannot contribute to the quest for MAP.  This is
+		 *  not perfect, we may get too much content; this seems
+		 *  preferable over losing too much. - kw
+		 */
+		if (first_map) {
+		    if (s == 0) {
+			StrAllocCat(*include, me->object.data);
+			CTRACE((tfp, "HTML: MAP found, recycling object contents.\n"));
+			goto End_Object;
+		    }
+		    /* s > 0 and s == e */
+		    data = NULL;
+		    if (last_map < start) {
+			*start = '\0';
+			i = 0;
+		    } else if (last_map < first_end) {
+			*first_end = '\0';
+			i = e;
+		    } else if (last_map < last_end) {
+			*last_end = '\0';
+			i = 1;
+		    } else {
+			i = 0;
+		    }
+		    if (first_map > last_end) {
+			/* fake empty object to keep stacks stack happy */
+			StrAllocCopy(data, "<OBJECT><");
+			StrAllocCat(data, last_end + 1);
+			i = 0;
+		    } else if (first_map > start) {
+			StrAllocCopy(data, start);
+		    } else {
+			StrAllocCopy(data, me->object.data);
+		    }
+		    for (; i > 0; i--) {
+			StrAllocCat(data, "</OBJECT>");
+		    }
+		    CTRACE((tfp, "%s:\n%s\n",
+			   "HTML: MAP and nested OBJECT tags.  Recycling parts",
+			   data));
+		    StrAllocCat(*include, data);
+		    FREE(data);
+		}
 		goto End_Object;
 	    }
 
 	    /*
 	     *	Add an ID link if needed. - FM
 	     */
-	    if (me->object_id && *me->object_id)
+	    if (me->object_id && *me->object_id && !LYMapsOnly)
 		LYHandleID(me, me->object_id);
 
 	    /*
 	     *	Add the OBJECTs content if not empty. - FM
 	     */
-	    if (me->object.size > 1)
+	    if (me->object.size > 1) {
+		if (!include)	/* error, should not happen */
+		    include = &me->xinclude;
 		StrAllocCat(*include, me->object.data);
+	    }
 
 	    /*
 	     *	Create a link to the DATA, if desired, and
@@ -6622,7 +7106,8 @@ PRIVATE void HTML_end_element ARGS3(
 	     *	it a try. - FM
 	     */
 	    if (clickable_images) {
-		if (me->object_data != NULL &&
+		if (!LYMapsOnly &&
+		    me->object_data != NULL &&
 		    !have_param &&
 		    me->object_classid == NULL &&
 		    me->object_codebase == NULL &&
@@ -6635,6 +7120,8 @@ PRIVATE void HTML_end_element ARGS3(
 		     *	an image or not, and set the link name
 		     *	accordingly. - FM
 		     */
+		    if (!include)	/* error, should not happen */
+			include = &me->xinclude;
 		    if (me->inA)
 			StrAllocCat(*include, "</A>");
 		    StrAllocCat(*include, " -<A HREF=\"");
@@ -6655,22 +7142,10 @@ PRIVATE void HTML_end_element ARGS3(
 	 *  Re-intialize all of the OBJECT elements. - FM
 	 */
 End_Object:
-	HTChunkClear(&me->object);
-	me->object_started = FALSE;
-	me->object_declare = FALSE;
-	me->object_shapes = FALSE;
-	me->object_ismap = FALSE;
-	FREE(me->object_usemap);
-	FREE(me->object_id);
-	FREE(me->object_title);
-	FREE(me->object_data);
-	FREE(me->object_type);
-	FREE(me->object_classid);
-	FREE(me->object_codebase);
-	FREE(me->object_codetype);
-	FREE(me->object_name);
+	clear_objectdata(me);
 
-	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
+	if (!LYMapsOnly)
+	    change_paragraph_style(me, me->sp->style);  /* Often won't really change */
 	break;
 
     case HTML_APPLET:
@@ -6827,7 +7302,6 @@ End_Object:
 	     *	Finish the data off.
 	     */
 	    HTChunkTerminate(&me->textarea);
-	    data = me->textarea.data;
 	    FREE(temp);
 
 	    I.type = "textarea";
@@ -6840,19 +7314,32 @@ End_Object:
 	    I.id = me->textarea_id;
 
 	    /*
-	     *	SGML unescape any character references in TEXTAREA
-	     *	content, then parse it into individual lines
-	     *	to be handled as a series of INPUT fields (ugh!).
+	     *	Transform the TEXTAREA content as needed, then parse
+	     *	it into individual lines to be handled as a series
+	     *  series of INPUT fields (ugh!).
 	     *	Any raw 8-bit or multibyte characters already have been
 	     *	handled in relation to the display character set
 	     *	in SGML_character().
+	     *
+	     *  If TEXTAREA is handled as SGML_LITTERAL (the old way),
+	     *	we need to SGML-unescape any character references and NCRs
+	     *  here.  Otherwise this will already have happened in the
+	     *  SGML.c parsing. - kw
 	     */
 	    me->UsePlainSpace = TRUE;
 
-	    TRANSLATE_AND_UNESCAPE_ENTITIES5(&me->textarea.data,
+	    if (HTML_dtd.tags[element_number].contents == SGML_LITTERAL) {
+		TRANSLATE_AND_UNESCAPE_ENTITIES5(&me->textarea.data,
 						    me->UCLYhndl,
 						    current_char_set,
 						    me->UsePlainSpace, me->HiddenValue);
+	    } else {
+		TRANSLATE_HTML5(&me->textarea.data,
+						    me->UCLYhndl,
+						    current_char_set,
+						    me->UsePlainSpace, me->HiddenValue);
+	    }
+	    data = me->textarea.data;
 
 	    /*
 	     *	Trim any trailing newlines and
@@ -7091,6 +7578,7 @@ End_Object:
 				me->DivisionAlignments[me->Division_Level];
 	change_paragraph_style(me, me->sp->style);
 	UPDATE_STYLE;
+	HText_endStblTABLE(me->text);
 	me->current_default_alignment = me->sp->style->alignment;
 	if (me->List_Nesting_Level >= 0)
 	    HText_NegateLineOne(me->text);
@@ -7098,6 +7586,7 @@ End_Object:
 
 /* These TABLE related elements may now not be SGML_EMPTY. - kw */
     case HTML_TR:
+	HText_endStblTR(me->text);
 	if (HText_LastLineSize(me->text, FALSE)) {
 	    HText_setLastChar(me->text, ' ');  /* absorb next white space */
 	    HText_appendCharacter(me->text, '\r');
@@ -7114,9 +7603,8 @@ End_Object:
 	break;
 
     case HTML_TH:
-	break;
-
     case HTML_TD:
+	HText_endStblTD(me->text);
 	break;
 
 /* More stuff that may now not be SGML_EMPTY any more: */
@@ -7161,6 +7649,13 @@ End_Object:
 	    if (reached_awaited_stacked_elt)
 		wait_for_this_stacked_elt=-1;
 #endif
+
+    if (me->xinclude) {
+	HText_appendText(me->text, " *** LYNX ERROR ***\rUnparsed data:\r");
+	HText_appendText(me->text, me->xinclude);
+	FREE(me->xinclude);
+    }
+
 #ifdef USE_COLOR_STYLE
 #if !OPT_SCN
     TrimColorClass(HTML_dtd.tags[element_number].name,
@@ -7174,7 +7669,7 @@ End_Object:
 #  endif
 #endif
 
-    if (!REALLY_EMPTY(element_number))
+    if (!ReallyEmptyTagNum(element_number))
     {
 	CTRACE((tfp, "STYLE:end_element: ending non-EMPTY style\n"));
 #if !defined(USE_HASH)
@@ -7184,6 +7679,7 @@ End_Object:
 #endif /* USE_HASH */
     }
 #endif /* USE_COLOR_STYLE */
+    return status;
 }
 
 /*		Expanding entities
@@ -7226,6 +7722,8 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me)
 	 */
 	FREE(me->base_href);
 	FREE(me->map_address);
+	clear_objectdata(me);
+	FREE(me->xinclude);
 	FREE(me);
 	return;
     }
@@ -7333,6 +7831,11 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me)
 	    HTML_put_character(me, ']');
 	    HTML_end_element(me, HTML_P, &include);
 	}
+	if (me->xinclude) {
+	    HText_appendText(me->text, " *** LYNX ERROR ***\rUnparsed data:\r");
+	    HText_appendText(me->text, me->xinclude);
+	    FREE(me->xinclude);
+	}
 
 	/*
 	 *  Now call the cleanup function. - FM
@@ -7404,6 +7907,7 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me)
     FREE(me->base_href);
     FREE(me->map_address);
     FREE(me->LastOptionValue);
+    clear_objectdata(me);
     FREE(me);
 }
 
@@ -7499,6 +8003,8 @@ PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e)
     FREE(me->textarea_cols);
     FREE(me->textarea_id);
     FREE(me->LastOptionValue);
+    FREE(me->xinclude);
+    clear_objectdata(me);
     FREE(me);
 }
 
@@ -8107,7 +8613,7 @@ PUBLIC HTStream* HTMLParsedPresent ARGS3(
 **	is commented out.
 **	This will convert from HTML to presentation or plain text.
 **
-**	It is registered in HTInit.c, but never actually used by lynx.
+**	It is registered in HTInit.c, but normally not used by lynx.
 **	- kw 1999-03-15
 */
 PUBLIC HTStream* HTMLToC ARGS3(
@@ -8116,12 +8622,18 @@ PUBLIC HTStream* HTMLToC ARGS3(
 	HTStream *,		sink)
 {
     HTStructured * html;
-
-    (*sink->isa->put_string)(sink, "/* ");	/* Before even title */
+#if 0
+    if (!sink)
+	sink = HTStreamStack(WWW_SOURCE, HTAtom_for("www/dump"),
+	HTOutputStream, anchor);
+#endif
+    if (sink)
+	(*sink->isa->put_string)(sink, "/* ");	/* Before even title */
     html = HTML_new(anchor, WWW_PLAINTEXT, sink);
     html->comment_start = "/* ";
     html->comment_end = " */\n";	/* Must start in col 1 for cpp */
-/*    HTML_put_string(html,html->comment_start); */
+    if (!sink)
+	HTML_put_string(html,html->comment_start);
 #ifdef SOURCE_CACHE
     return CacheThru_new(anchor,
 			 SGML_new(&HTML_dtd, anchor, html));
diff --git a/src/HTML.h b/src/HTML.h
index 69074324..04ea3f32 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -20,13 +20,19 @@
 #define ATTR_CS_IN me->tag_charset
 
 #define TRANSLATE_AND_UNESCAPE_ENTITIES(s, p, h) \
-	LYUCFullyTranslateString(s, ATTR_CS_IN, current_char_set, YES, p, h, st_HTML)
+	LYUCTranslateHTMLString(s, ATTR_CS_IN, current_char_set, YES, p, h, st_HTML)
 
 #define TRANSLATE_AND_UNESCAPE_ENTITIES5(s,cs_from,cs_to,p,h) \
-	LYUCFullyTranslateString(s, cs_from, cs_to, YES, p, h, st_HTML)
+	LYUCTranslateHTMLString(s, cs_from, cs_to, YES, p, h, st_HTML)
 
 #define TRANSLATE_AND_UNESCAPE_ENTITIES6(s,cs_from,cs_to,spcls,p,h) \
-	LYUCFullyTranslateString(s, cs_from, cs_to, spcls, p, h, st_HTML)
+	LYUCTranslateHTMLString(s, cs_from, cs_to, spcls, p, h, st_HTML)
+
+#define TRANSLATE_HTML(s,p,h) \
+	LYUCFullyTranslateString(s, me->UCLYhndl, current_char_set, NO, YES, p, h, NO, st_HTML)
+
+#define TRANSLATE_HTML5(s,cs_from,cs_to,p,h) \
+	LYUCFullyTranslateString(s, cs_from, cs_to, NO, YES, p, h, NO, st_HTML)
 
 /*
  *  Strings from attributes which should be converted to some kind
@@ -34,9 +40,9 @@
  *  esp. URLs (incl. #fragments) and HTML NAME and ID stuff.
  */
 #define TRANSLATE_AND_UNESCAPE_TO_STD(s) \
-	LYUCFullyTranslateString(s, ATTR_CS_IN, ATTR_CS_IN, NO, NO, YES, st_URL)
+	LYUCTranslateHTMLString(s, ATTR_CS_IN, ATTR_CS_IN, NO, NO, YES, st_URL)
 #define UNESCAPE_FIELDNAME_TO_STD(s) \
-	LYUCFullyTranslateString(s, ATTR_CS_IN, ATTR_CS_IN, NO, NO, YES, st_HTML)
+	LYUCTranslateHTMLString(s, ATTR_CS_IN, ATTR_CS_IN, NO, NO, YES, st_HTML)
 
 extern CONST HTStructuredClass HTMLPresentation;
 
@@ -84,6 +90,8 @@ struct _HTStructured {
     char *			object_codebase;
     char *			object_codetype;
     char *			object_name;
+    int				objects_mixed_open,
+    				objects_figged_open;
     HTChunk			option;		/* Grow by 128 */
     BOOL			first_option;	/* First OPTION in SELECT? */
     char *			LastOptionValue;
@@ -161,6 +169,7 @@ struct _HTStructured {
 
     BOOL		needBoldH;
 
+    char *		xinclude; /* if no include strin address passed */
     /*
     **  UCI and UCLYhndl give the UCInfo and charset registered for
     **  the HTML parser in the node_anchor's UCStages structure.  It
diff --git a/src/HTNestedList.h b/src/HTNestedList.h
index 32a3049b..f7c0411d 100644
--- a/src/HTNestedList.h
+++ b/src/HTNestedList.h
@@ -37,4 +37,9 @@
 #define HTML_DLEFT    HTML_ELEMENTS+29
 #define HTML_DRIGHT   HTML_ELEMENTS+30
 
+
+#define HTML_OBJECT_M HTML_ELEMENTS+31
+
+#define HTML_EXTRA_ELEMENTS 31
+
 #endif /* HTNESTEDLIST_H */
diff --git a/src/LYCharSets.c b/src/LYCharSets.c
index 6e775c27..62e1fdfc 100644
--- a/src/LYCharSets.c
+++ b/src/LYCharSets.c
@@ -621,7 +621,12 @@ PRIVATE void HTMLSetDisplayCharsetMatchLocale ARGS1(int,i)
 	match = TRUE; /* guess, but see below */
 
 #if !defined(LOCALE)
-	match = FALSE;
+	if (LYCharSet_UC[i].enc != UCT_ENC_UTF8)
+	    /*
+	     *  Leave true for utf-8 display - the code doesn't deal
+	     *  very well with this case. - kw
+	     */
+	    match = FALSE;
 #else
 	if (UCForce8bitTOUPPER) {
 	    /*
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index e0de8686..b4b54422 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -66,8 +66,8 @@ PUBLIC void LYEntify ARGS2(
     int amps = 0, lts = 0, gts = 0;
 #ifdef CJK_EX
     enum _state
-        { S_text, S_esc, S_dollar, S_paren,
-          S_nonascii_text, S_dollar_paren } state = S_text;
+	{ S_text, S_esc, S_dollar, S_paren,
+	  S_nonascii_text, S_dollar_paren } state = S_text;
     int in_sjis = 0;
 #endif
 
@@ -126,8 +126,8 @@ PUBLIC void LYEntify ARGS2(
 			state = S_esc;
 			*q++ = *p;
 			continue;
-                    }
-                    break;
+		    }
+		    break;
 
 		case S_esc:
 		    if (*p == '$') {
@@ -392,7 +392,7 @@ PUBLIC char *LYFindEndOfComment ARGS1(
 */
 PUBLIC void LYFillLocalFileURL ARGS2(
 	char **,	href,
-	CONST char *, 	base)
+	CONST char *,	base)
 {
     char * temp = NULL;
 
@@ -510,7 +510,7 @@ PUBLIC void LYFillLocalFileURL ARGS2(
 **								 - LP
 */
 PUBLIC void LYAddMETAcharsetToFD ARGS2(
-	FILE *, 	fd,
+	FILE *,		fd,
 	int,		disp_chndl)
 {
     if (disp_chndl == -1)
@@ -883,7 +883,7 @@ PUBLIC char *LYLowercaseI_OL_String ARGS1(
 **  This function initializes the Ordered List counter. - FM
 */
 PUBLIC void LYZero_OL_Counter ARGS1(
-	HTStructured *, 	me)
+	HTStructured *,		me)
 {
     int i;
 
@@ -905,7 +905,7 @@ PUBLIC void LYZero_OL_Counter ARGS1(
 **  This function is used by the HTML Structured object. - KW
 */
 PUBLIC void LYGetChartransInfo ARGS1(
-	HTStructured *, 	me)
+	HTStructured *,		me)
 {
     me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
 					UCT_STAGE_STRUCTURED);
@@ -944,7 +944,7 @@ PUBLIC void LYGetChartransInfo ARGS1(
 **  keep memory allocations at a minimum. - FM
 */
 PUBLIC void LYExpandString ARGS2(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	char **,		str)
 {
     char *p = *str;
@@ -1485,68 +1485,6 @@ PUBLIC void LYExpandString ARGS2(
 #endif /* NOTUSED_FOTEMODS */
 
 /*
-** Get UCS character code for one character from UTF-8 encoded string.
-**
-** On entry:
-**	*ppuni should point to beginning of UTF-8 encoding character
-** On exit:
-**	*ppuni is advanced to point to the last byte of UTF-8 sequence,
-**		if there was a valid one; otherwise unchanged.
-** returns the UCS value
-** returns negative value on error (invalid UTF-8 sequence)
-*/
-PRIVATE UCode_t UCGetUniFromUtf8String ARGS1(char **, ppuni)
-{
-    UCode_t uc_out = 0;
-    char * p = *ppuni;
-    int utf_count, i;
-    if (!(**ppuni&0x80))
-	return (UCode_t) **ppuni; /* ASCII range character */
-    else if (!(**ppuni&0x40))
-	return (-1);		/* not a valid UTF-8 start */
-    if ((*p & 0xe0) == 0xc0) {
-	utf_count = 1;
-    } else if ((*p & 0xf0) == 0xe0) {
-	utf_count = 2;
-    } else if ((*p & 0xf8) == 0xf0) {
-	utf_count = 3;
-    } else if ((*p & 0xfc) == 0xf8) {
-	utf_count = 4;
-    } else if ((*p & 0xfe) == 0xfc) {
-	utf_count = 5;
-    } else { /* garbage */
-	return (-1);
-    }
-    for (p = *ppuni, i = 0; i < utf_count ; i++) {
-	if ((*(++p) & 0xc0) != 0x80)
-	    return (-1);
-    }
-    p = *ppuni;
-    switch (utf_count) {
-    case 1:
-	uc_out = (((*p&0x1f) << 6) | (*(p+1)&0x3f));
-	break;
-    case 2:
-	uc_out = (((((*p&0x0f) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f));
-	break;
-    case 3:
-	uc_out = (((((((*p&0x07) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
-	    | (*(p+3)&0x3f));
-	break;
-    case 4:
-	uc_out = (((((((((*p&0x03) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
-		  | (*(p+3)&0x3f)) << 6) | (*(p+4)&0x3f));
-	break;
-    case 5:
-	uc_out = (((((((((((*p&0x01) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
-		  | (*(p+3)&0x3f)) << 6) | (*(p+4)&0x3f)) << 6) | (*(p+5)&0x3f));
-	break;
-    }
-    *ppuni = p + utf_count;
-    return uc_out;
-}
-
-/*
  *  Given an UCS character code, will fill buffer passed in as q with
  *  the code's UTF-8 encoding.
  *  If terminate = YES, terminates string on success and returns pointer
@@ -1682,7 +1620,7 @@ PRIVATE CONST char *hex = "0123456789ABCDEF";
 **		       BOOLEAN		       isURL));
 */
 
-PRIVATE char ** LYUCFullyTranslateString_1 ARGS9(
+PUBLIC char ** LYUCFullyTranslateString ARGS9(
 	char **,	str,
 	int,		cs_from,
 	int,		cs_to,
@@ -1832,7 +1770,7 @@ PRIVATE char ** LYUCFullyTranslateString_1 ARGS9(
 		    sjis_1st = '\0';
 		} else {
 		    if (0xA1 <= code && code <= 0xDF) {
-		        sjis_str[2] = '\0';
+			sjis_str[2] = '\0';
 			JISx0201TO0208_SJIS((unsigned char)code,
 						sjis_str, sjis_str + 1);
 			REPLACE_STRING(sjis_str);
@@ -2283,15 +2221,29 @@ PRIVATE char ** LYUCFullyTranslateString_1 ARGS9(
 		    **	otherwise use the Lynx special character. - FM
 		    */
 		if (code == 160) {
-		    if (hidden) {
-			;
-		    } else if (plain_space) {
+		    if (plain_space) {
 			code = ' ';
-		    } else {
+			state = S_got_outchar;
+			break;
+		    } else if (use_lynx_specials) {
 			code = HT_NON_BREAK_SPACE;
+			state = S_got_outchar;
+			break;
+		    } else if ((hidden && !Back) ||
+			       (LYCharSet_UC[cs_to].codepoints & UCT_CP_SUPERSETOF_LAT1) ||
+			       LYCharSet_UC[cs_to].enc == UCT_ENC_8859 ||
+			       (LYCharSet_UC[cs_to].like8859 &
+						UCT_R_8859SPECL)) {
+			state = S_got_outchar;
+			break;
+		    } else if (
+			(LYCharSet_UC[cs_to].repertoire & UCT_REP_SUPERSETOF_LAT1)) {
+			;	/* nothing, may be translated later */
+		    } else {
+			code = ' ';
+			state = S_got_outchar;
+			break;
 		    }
-		    state = S_got_outchar;
-		    break;
 		}
 		/*
 		    **	For 173 (shy), use that value if it's
@@ -2312,7 +2264,7 @@ PRIVATE char ** LYUCFullyTranslateString_1 ARGS9(
 		    } else if (hidden || Back) {
 			state = S_got_outchar;
 			break;
-		    } else {
+		    } else if (use_lynx_specials) {
 			code = LY_SOFT_HYPHEN;
 			state = S_got_outchar;
 			break;
@@ -2607,7 +2559,7 @@ PRIVATE char ** LYUCFullyTranslateString_1 ARGS9(
 #undef REPLACE_CHAR
 #undef REPLACE_STRING
 
-PUBLIC BOOL LYUCFullyTranslateString ARGS7(
+PUBLIC BOOL LYUCTranslateHTMLString ARGS7(
 	char **, str,
 	int,	cs_from,
 	int,	cs_to,
@@ -2618,7 +2570,7 @@ PUBLIC BOOL LYUCFullyTranslateString ARGS7(
 {
     BOOL ret = YES;
     /* May reallocate *str even if cs_to == 0 */
-    if (!LYUCFullyTranslateString_1(str, cs_from, cs_to, TRUE,
+    if (!LYUCFullyTranslateString(str, cs_from, cs_to, TRUE,
 				    use_lynx_specials, plain_space, hidden,
 				    NO, stype)) {
 	ret = NO;
@@ -2634,7 +2586,7 @@ PUBLIC BOOL LYUCTranslateBackFormData ARGS4(
 {
     char ** ret;
     /* May reallocate *str */
-    ret = (LYUCFullyTranslateString_1(str, cs_from, cs_to, FALSE,
+    ret = (LYUCFullyTranslateString(str, cs_from, cs_to, FALSE,
 				       NO, plain_space, YES,
 				       YES, st_HTML));
     return (BOOL) (ret != NULL);
@@ -2644,7 +2596,7 @@ PUBLIC BOOL LYUCTranslateBackFormData ARGS4(
 **  This function processes META tags in HTML streams. - FM
 */
 PUBLIC void LYHandleMETA ARGS4(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	CONST BOOL*,		present,
 	CONST char **,		value,
 	char **,		include GCC_UNUSED)
@@ -2664,7 +2616,7 @@ PUBLIC void LYHandleMETA ARGS4(
 	value[HTML_META_HTTP_EQUIV] && *value[HTML_META_HTTP_EQUIV]) {
 	StrAllocCopy(http_equiv, value[HTML_META_HTTP_EQUIV]);
 	convert_to_spaces(http_equiv, TRUE);
-	LYUCFullyTranslateString(&http_equiv, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&http_equiv, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_other);
 	LYTrimHead(http_equiv);
 	LYTrimTail(http_equiv);
@@ -2676,7 +2628,7 @@ PUBLIC void LYHandleMETA ARGS4(
 	value[HTML_META_NAME] && *value[HTML_META_NAME]) {
 	StrAllocCopy(name, value[HTML_META_NAME]);
 	convert_to_spaces(name, TRUE);
-	LYUCFullyTranslateString(&name, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&name, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_other);
 	LYTrimHead(name);
 	LYTrimTail(name);
@@ -2722,7 +2674,7 @@ PUBLIC void LYHandleMETA ARGS4(
      */
     if (!strcasecomp((http_equiv ? http_equiv : ""), "Pragma") ||
 	!strcasecomp((http_equiv ? http_equiv : ""), "Cache-Control")) {
-	LYUCFullyTranslateString(&content, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&content, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_other);
 	LYTrimHead(content);
 	LYTrimTail(content);
@@ -2796,7 +2748,7 @@ PUBLIC void LYHandleMETA ARGS4(
 	 *  Date header from a server when making the
 	 *  comparison. - FM
 	 */
-	LYUCFullyTranslateString(&content, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&content, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_other);
 	LYTrimHead(content);
 	LYTrimTail(content);
@@ -2839,7 +2791,7 @@ PUBLIC void LYHandleMETA ARGS4(
 	       !strcasecomp((http_equiv ? http_equiv : ""), "Content-Type")) {
 	LYUCcharset * p_in = NULL;
 	LYUCcharset * p_out = NULL;
-	LYUCFullyTranslateString(&content, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&content, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_other);
 	LYTrimHead(content);
 	LYTrimTail(content);
@@ -3085,11 +3037,15 @@ PUBLIC void LYHandleMETA ARGS4(
 	    /*
 	     *	Check for an anchor in http or https URLs. - FM
 	     */
+#ifndef DONT_TRACK_INTERNAL_LINKS
+	    /* id_string seems to be used wrong below if given.
+	       not that it matters much.  avoid setting it here. - kw */
 	    if ((strncmp(href, "http", 4) == 0) &&
 		(cp = strrchr(href, '#')) != NULL) {
 		StrAllocCopy(id_string, cp);
 		*cp = '\0';
 	    }
+#endif
 	    if (me->inA) {
 		/*
 		 *  Ugh!  The META tag, which is a HEAD element,
@@ -3213,7 +3169,7 @@ free_META_copies:
 **  end tag is present or not in the markup. - FM
 */
 PUBLIC void LYHandlePlike ARGS6(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	CONST BOOL*,		present,
 	CONST char **,		value,
 	char **,		include GCC_UNUSED,
@@ -3322,7 +3278,7 @@ PUBLIC void LYHandlePlike ARGS6(
 **  an end tag. - FM
 */
 PUBLIC void LYHandleSELECT ARGS5(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	CONST BOOL*,		present,
 	CONST char **,		value,
 	char **,		include GCC_UNUSED,
@@ -3553,7 +3509,7 @@ PUBLIC void LYHandleSELECT ARGS5(
 **  URLs. - FM
 */
 PUBLIC int LYLegitimizeHREF ARGS4(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	char **,		href,
 	BOOL,			force_slash,
 	BOOL,			strip_dots)
@@ -3586,7 +3542,7 @@ PUBLIC int LYLegitimizeHREF ARGS4(
     }
     if (*(*href) == '\0')
 	return(url_type);
-    LYUCFullyTranslateString(href, me->tag_charset, me->tag_charset,
+    LYUCTranslateHTMLString(href, me->tag_charset, me->tag_charset,
 			     NO, NO, YES, st_URL);
     url_type = is_url(*href);
     if (!url_type && force_slash &&
@@ -3679,7 +3635,7 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 **  any BASE tag in the HTML stream, itself. - FM
 */
 PUBLIC void LYCheckForContentBase ARGS1(
-	HTStructured *, 	me)
+	HTStructured *,		me)
 {
     char *cp = NULL;
     BOOL present[HTML_BASE_ATTRIBUTES];
@@ -3747,7 +3703,7 @@ PUBLIC void LYCheckForContentBase ARGS1(
 **  or ID attribute was present in the tag. - FM
 */
 PUBLIC void LYCheckForID ARGS4(
-	HTStructured *, 	me,
+	HTStructured *,		me,
 	CONST BOOL *,		present,
 	CONST char **,		value,
 	int,			attribute)
@@ -3764,7 +3720,7 @@ PUBLIC void LYCheckForID ARGS4(
 	 *  Translate any named or numeric character references. - FM
 	 */
 	StrAllocCopy(temp, value[attribute]);
-	LYUCFullyTranslateString(&temp, me->tag_charset, me->tag_charset,
+	LYUCTranslateHTMLString(&temp, me->tag_charset, me->tag_charset,
 				 NO, NO, YES, st_URL);
 
 	/*
@@ -3789,8 +3745,8 @@ PUBLIC void LYCheckForID ARGS4(
 **  does not need checking for character references. - FM
 */
 PUBLIC void LYHandleID ARGS2(
-	HTStructured *, 	me,
-	char *, 		id)
+	HTStructured *,		me,
+	CONST char *,		id)
 {
     HTChildAnchor *ID_A = NULL;
 
@@ -3987,7 +3943,7 @@ PUBLIC BOOLEAN LYCommentHacks ARGS2(
 	cp = comment + 17;
 	StrAllocCopy(messageid, cp);
 	/* This should be ok - message-id should only contain 7-bit ASCII */
-	if (!LYUCFullyTranslateString(&messageid, 0, 0, NO, NO, YES, st_URL))
+	if (!LYUCTranslateHTMLString(&messageid, 0, 0, NO, NO, YES, st_URL))
 	    return FALSE;
 	for (p = messageid; *p; p++) {
 	    if ((unsigned char)*p >= 127 || !isgraph((unsigned char)*p)) {
@@ -4039,7 +3995,7 @@ PUBLIC BOOLEAN LYCommentHacks ARGS2(
 	 * header in raw form, but don't have MIME encoding implemented.
 	 * Someone may want to do more about this...  - kw
 	 */
-	if (!LYUCFullyTranslateString(&subject, 0, 0, NO, YES, NO, st_HTML))
+	if (!LYUCTranslateHTMLString(&subject, 0, 0, NO, YES, NO, st_HTML))
 	    return FALSE;
 	for (p = subject; *p; p++) {
 	    if ((unsigned char)*p >= 127 || !isprint((unsigned char)*p)) {
diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h
index d518d3ae..97cba343 100644
--- a/src/LYCharUtils.h
+++ b/src/LYCharUtils.h
@@ -14,22 +14,32 @@ typedef enum {
     st_other
 } CharUtil_st;
 
-extern BOOL LYUCFullyTranslateString PARAMS((
-	char ** 	str,
+extern char** LYUCFullyTranslateString PARAMS((
+	char **		str,
 	int		cs_from,
 	int		cs_to,
+	BOOLEAN		do_ent,
 	BOOL		use_lynx_specials,
-	BOOLEAN 	plain_space,
-	BOOLEAN 	hidden,
+	BOOLEAN		plain_space,
+	BOOLEAN		hidden,
+	BOOL		Back,
+	CharUtil_st	stype));
+extern BOOL LYUCTranslateHTMLString PARAMS((
+	char **		str,
+	int		cs_from,
+	int		cs_to,
+	BOOL		use_lynx_specials,
+	BOOLEAN		plain_space,
+	BOOLEAN		hidden,
 	CharUtil_st	stype));
 extern BOOL LYUCTranslateBackFormData PARAMS((
-	char ** 	str,
+	char **		str,
 	int		cs_from,
 	int		cs_to,
-	BOOLEAN 	plain_space));
+	BOOLEAN		plain_space));
 extern void LYEntify PARAMS((
-	char ** 	str,
-	BOOLEAN 	isTITLE));
+	char **		str,
+	BOOLEAN		isTITLE));
 extern void LYTrimHead PARAMS((
 	char *		str));
 extern void LYTrimTail PARAMS((
@@ -37,14 +47,14 @@ extern void LYTrimTail PARAMS((
 extern char *LYFindEndOfComment PARAMS((
 	char *		str));
 extern void LYFillLocalFileURL PARAMS((
-	char ** 	href,
+	char **		href,
 	CONST char *	base));
 extern void LYAddMETAcharsetToFD PARAMS((
 	FILE *		fd,
 	int		disp_chndl));
 
 #ifdef Lynx_HTML_Handler
-extern int OL_CONTINUE; 	/* flag for whether CONTINUE is set */
+extern int OL_CONTINUE;		/* flag for whether CONTINUE is set */
 extern int OL_VOID;		/* flag for whether a count is set */
 extern void LYZero_OL_Counter PARAMS((
 	HTStructured *		me));
@@ -62,23 +72,23 @@ extern void LYHandleMETA PARAMS((
 	HTStructured *		me,
 	CONST BOOL*		present,
 	CONST char **		value,
-	char ** 		include));
+	char **			include));
 extern void LYHandlePlike PARAMS((
 	HTStructured *		me,
 	CONST BOOL*		present,
 	CONST char **		value,
-	char ** 		include,
+	char **			include,
 	int			align_idx,
 	BOOL			start));
 extern void LYHandleSELECT PARAMS((
 	HTStructured *		me,
 	CONST BOOL*		present,
 	CONST char **		value,
-	char ** 		include,
+	char **			include,
 	BOOL			start));
 extern int LYLegitimizeHREF PARAMS((
 	HTStructured *		me,
-	char ** 		href,
+	char **			href,
 	BOOL			force_slash,
 	BOOL			strip_dots));
 extern void LYCheckForContentBase PARAMS((
@@ -90,7 +100,7 @@ extern void LYCheckForID PARAMS((
 	int			attribute));
 extern void LYHandleID PARAMS((
 	HTStructured *		me,
-	char *			id));
+	CONST char *		id));
 extern BOOLEAN LYoverride_default_alignment PARAMS((
 	HTStructured *		me));
 extern void LYEnsureDoubleSpace PARAMS((
@@ -101,7 +111,10 @@ extern void LYResetParagraphAlignment PARAMS((
 	HTStructured *		me));
 extern BOOLEAN LYCheckForCSI PARAMS((
 	HTParentAnchor *	anchor,
-	char ** 		url));
+	char **			url));
+
 #endif /* Lynx_HTML_Handler */
 
+#define LYUCTranslateBackHeaderText LYUCTranslateBackFormData
+
 #endif /* LYCHARUTILS_H */
diff --git a/src/LYCurses.h b/src/LYCurses.h
index 58725ff3..9ff9a597 100644
--- a/src/LYCurses.h
+++ b/src/LYCurses.h
@@ -202,6 +202,7 @@ extern unsigned int Lynx_Color_Flags;
 #endif
 
 #ifdef USE_SLANG
+#define SHOW_WHEREIS_TARGETS 1
 
 #if !defined(VMS) && !defined(DJGPP)
 #define USE_SLANG_MOUSE		1
@@ -282,6 +283,7 @@ extern void VTHome NOPARAMS;
 #else /* Define curses functions: */
 
 #ifdef FANCY_CURSES
+#define SHOW_WHEREIS_TARGETS 1
 
 #ifdef VMS
 /*
diff --git a/src/LYDownload.c b/src/LYDownload.c
index eb74d163..2a985ad0 100644
--- a/src/LYDownload.c
+++ b/src/LYDownload.c
@@ -25,7 +25,7 @@ PUBLIC BOOLEAN LYDidRename = FALSE;
 PRIVATE char LYValidDownloadFile[LY_MAXPATH] = "\0";
 
 PUBLIC void LYDownload ARGS1(
-	char *, 	line)
+	char *,		line)
 {
     char *Line = NULL, *method, *file, *sug_file = NULL;
     int method_number;
@@ -61,25 +61,25 @@ PUBLIC void LYDownload ARGS1(
     StrAllocCopy(Line, line);
 
     /*
-     *	Parse out the sug_file, Method and the File.
+     *	Parse out the File, sug_file, and the Method.
      */
-    if ((sug_file = (char *)strstr(Line, "SugFile=")) != NULL) {
-	*(sug_file-1) = '\0';
+    if ((file = (char *)strstr(Line, "/File=")) == NULL)
+	goto failed;
+    *file = '\0';
+    /*
+     *	Go past "File=".
+     */
+    file += 6;
+
+    if ((sug_file = (char *)strstr(file + 1, "/SugFile=")) != NULL) {
+	*sug_file = '\0';
 	/*
 	 *  Go past "SugFile=".
 	 */
-	sug_file += 8;
+	sug_file += 9;
 	HTUnEscape(sug_file);
     }
 
-    if ((file = (char *)strstr(Line, "File=")) == NULL)
-	goto failed;
-    *(file-1) = '\0';
-    /*
-     *	Go past "File=".
-     */
-    file += 5;
-
     /*
      *	Make sure that the file string is the one from
      *	the last displayed download options menu. - FM
@@ -486,7 +486,7 @@ cancelled:
  */
 PUBLIC int LYdownload_options ARGS2(
 	char **,	newfile,
-	char *, 	data_file)
+	char *,		data_file)
 {
     static char tempfile[LY_MAXPATH] = "\0";
     char *downloaded_url = NULL;
@@ -524,12 +524,12 @@ PUBLIC int LYdownload_options ARGS2(
 
     fprintf(fp0, "<pre>\n");
     fprintf(fp0, "<em>%s</em> %s\n",
-    	    gettext("Downloaded link:"),
+	    gettext("Downloaded link:"),
 	    downloaded_url);
     FREE(downloaded_url);
 
     fprintf(fp0, "<em>%s</em> %s\n",
-    	    gettext("Suggested file name:"),
+	    gettext("Suggested file name:"),
 	    sug_filename);
 
     fprintf(fp0, "\n%s\n",
diff --git a/src/LYEditmap.c b/src/LYEditmap.c
index 7314e97b..4a23b319 100644
--- a/src/LYEditmap.c
+++ b/src/LYEditmap.c
@@ -284,7 +284,7 @@ LYE_NOP,        LYE_BOL,        LYE_BACK,       LYE_ABORT,
 LYE_DELN,       LYE_EOL,        LYE_FORW,       LYE_ABORT,
 /* ^D           ^E              ^F              ^G      */
 
-LYE_DELP,       LYE_ENTER,      LYE_ENTER,      LYE_DELNW, /* LYE_DELEL,*/
+LYE_DELP,       LYE_ENTER,      LYE_ENTER,      LYE_DELEL,
 /* bs           tab             nl              ^K      */
 
 LYE_NOP,        LYE_ENTER,      LYE_FORWW,      LYE_ABORT,
diff --git a/src/LYForms.c b/src/LYForms.c
index ac75a941..70f7486d 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -225,13 +225,29 @@ PUBLIC int change_form_link_ex ARGS8(
 	     *  If c indicates that line editing ended with Enter, we still
 	     *  defer to mainloop() for further checking if the submit
 	     *  action URL could require more checks than we do here.
-	     *  call HText_SubmitForm() directly before returning.
-	     *  Only in the remaining cases do we proceed directly. - kw
+	     *  Only in the remaining cases do we proceed to call
+	     *  HText_SubmitForm() directly before returning. - kw
 	     */
 	    if (immediate_submit ||
 		((c == '\r' || c == '\n' || c == LAC_TO_LKC0(LYK_SUBMIT)) &&
 		 peek_mouse_link() == -1)) {
 		form_link->hightext = form->value;
+#ifdef TEXT_SUBMIT_CONFIRM_WANTED
+		if (!immediate_submit && (c == '\r' || c == '\n') &&
+		    !HTConfirmDefault(
+	gettext("No submit button for this form, submit single text field?"),
+			YES)) {
+		    /* User was prompted and declined; if canceled with ^G
+		     * let mainloop stay on this field, otherwise move on to
+		     * the next field or link. - kw
+		     */
+		    if (HTLastConfirmCancelled())
+			c = DO_NOTHING;
+		    else
+			c = LAC_TO_LKC(LYK_NEXT_LINK);
+		    break;
+		}
+#endif
 		if (!form->submit_action || *form->submit_action == '\0') {
 		    HTUserMsg(NO_FORM_ACTION);
 		    c = DO_NOTHING;
@@ -965,6 +981,10 @@ PRIVATE int popup_options ARGS7(
      *  if it all fits.  Otherwise, set up the widest window possible. - FM
      */
 #ifdef USE_SLANG
+    if (width + 4 > SLtt_Screen_Cols) {
+	lx = 1;
+	width = LYcols - 5; /* avoids a crash? - kw */
+    }
     SLsmg_fill_region(top, lx - 1, bottom - top, width + 4, ' ');
 #else
     if (!(form_window = newwin(bottom - top, width + 4, top, lx - 1)) &&
@@ -979,7 +999,7 @@ PRIVATE int popup_options ARGS7(
 #if defined(NCURSES)
     LYsubwindow(form_window);
 #endif
-#if defined(HAVE_GETBKGD) && !defined(PDCURSES)/* not defined in ncurses 1.8.7 */
+#if defined(HAVE_GETBKGD) /* not defined in ncurses 1.8.7 */
     wbkgd(form_window, getbkgd(stdscr));
     wbkgdset(form_window, getbkgd(stdscr));
 #endif
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index f5713d68..9a80861c 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -14,7 +14,6 @@
 #include <LYGetFile.h>
 #include <LYPrint.h>
 #include <LYOptions.h>
-#include <LYHistory.h>
 #include <LYStrings.h>
 #include <LYClean.h>
 #include <LYDownload.h>
@@ -28,12 +27,13 @@
 #include <LYLocal.h>
 #endif /* DIRED_SUPPORT */
 #include <LYReadCFG.h>
+#include <LYHistory.h>
 
 #include <LYexit.h>
 #include <LYLeaks.h>
 
 PRIVATE int fix_httplike_urls PARAMS((document *doc, UrlTypes type));
-extern char * WWW_Download_File;
+
 #ifdef VMS
 extern BOOLEAN LYDidRename;
 #endif /* VMS */
@@ -317,6 +317,11 @@ Try_Redirected_URL:
 		    /* show compile-time settings */
 		    return(lynx_compile_opts(doc));
 #endif
+		} else if (url_type == LYNXMESSAGES_URL_TYPE) {
+			/* Uh! */
+			LYforce_no_cache = TRUE;
+			LYoverride_no_cache = FALSE;
+			/* continue */
 
 #ifndef DISABLE_NEWS
 		} else if (url_type == NEWSPOST_URL_TYPE ||
@@ -776,23 +781,9 @@ Try_Redirected_URL:
 			}
 			FREE(cp);
 		    }
-		    if (url_type == LYNXMESSAGES_URL_TYPE) {
-			int rv;
-		    /* show list of recent statusline messages */
-			if ((rv = LYshow_statusline_messages(doc)) != NORMAL) {
-			    return rv;
-			}
-			WWWDoc.address = doc->address;
-			WWWDoc.post_data = doc->post_data;
-			WWWDoc.post_content_type = doc->post_content_type;
-			WWWDoc.bookmark = doc->bookmark;
-			WWWDoc.isHEAD = doc->isHEAD;
-			WWWDoc.safe = doc->safe;
-		    } else {
+		    CTRACE_SLEEP(MessageSecs);
+		    user_message(WWW_WAIT_MESSAGE, doc->address);
 
-			CTRACE_SLEEP(MessageSecs);
-			user_message(WWW_WAIT_MESSAGE, doc->address);
-		    }
 		    if (TRACE) {
 #ifdef USE_SLANG
 			if (LYCursesON) {
@@ -851,6 +842,7 @@ Try_Redirected_URL:
 				url_type == LYNXCOMPILE_OPTS_URL_TYPE ||
 				url_type == LYNXHIST_URL_TYPE ||
 				url_type == LYNXCOOKIE_URL_TYPE ||
+			        url_type == LYNXMESSAGES_URL_TYPE ||
 				(LYValidate &&
 				 url_type != HTTP_URL_TYPE &&
 				 url_type != HTTPS_URL_TYPE) ||
diff --git a/src/LYGetFile.h b/src/LYGetFile.h
index 319efbb6..a9062318 100644
--- a/src/LYGetFile.h
+++ b/src/LYGetFile.h
@@ -16,6 +16,8 @@ extern int follow_link_number PARAMS((
 extern void add_trusted PARAMS((char *str, int type));
 extern BOOLEAN exec_ok PARAMS((CONST char *source, CONST char *linkpath, int type));
 
+extern char * WWW_Download_File;
+
 /* values for follow_link_number() */
 #define DO_LINK_STUFF		1
 #define DO_GOTOLINK_STUFF	2
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 586c5a7d..d0f8efbf 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -385,6 +385,7 @@ extern BOOLEAN LYPrependCharsetToSource;
 extern BOOLEAN LYQuitDefaultYes;
 extern BOOLEAN LYNonRestartingSIGWINCH;
 extern BOOLEAN LYReuseTempfiles;
+extern BOOLEAN LYUseBuiltinSuffixes;
 extern BOOLEAN dont_wrap_pre;
 
 #ifdef EXP_JUSTIFY_ELTS
@@ -412,6 +413,7 @@ extern BOOLEAN restore_sigpipe_for_children;
 #endif /* !VMS */
 
 extern int HTNoDataOK;		/* HT_NO_DATA-is-ok hack */
+extern BOOLEAN FileInitAlreadyDone;
 
 #ifdef WIN_EX
 /* LYMain.c */
diff --git a/src/LYHistory.c b/src/LYHistory.c
index 93ff53fc..de190ef1 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -14,7 +14,7 @@
 #include <LYShowInfo.h>
 #include <LYStrings.h>
 #include <LYCharUtils.h>
-#include <LYGetFile.h>
+#include <LYCharSets.h>
 
 #ifdef DIRED_SUPPORT
 #include <LYUpload.h>
@@ -687,73 +687,6 @@ PRIVATE void to_stack ARGS1(char *, str)
 
 
 /*
- *  Status line messages list, LYNXMESSAGES:/ internal page,
- *  called from getfile().
- */
-PUBLIC int LYshow_statusline_messages ARGS1(
-    document *,			      newdoc)
-{
-    static char tempfile[LY_MAXPATH] = "\0";
-    static char *info_url;
-    FILE *fp0;
-    int i;
-    char *temp = NULL;
-
-    if (LYReuseTempfiles) {
-	fp0 = LYOpenTempRewrite(tempfile, HTML_SUFFIX, "w");
-    } else {
-	LYRemoveTemp(tempfile);
-	fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w");
-    }
-    if (fp0 == NULL) {
-	HTAlert(CANNOT_OPEN_TEMP);
-	return(NOT_FOUND);
-    }
-    LYLocalFileToURL(&info_url, tempfile);
-
-    LYforce_no_cache = TRUE;  /* don't cache this doc */
-
-    BeginInternalPage (fp0, STATUSLINES_TITLE, NULL);
-    fprintf(fp0, "<pre>\n");
-    fprintf(fp0, "<ol>\n");
-
-    /* print messages in reverse order: */
-    i = topOfStack;
-    while (--i >= 0) {
-	if (buffstack[i] != NULL) {
-	    StrAllocCopy(temp, buffstack[i]);
-	    LYEntify(&temp, TRUE);
-	    fprintf(fp0,  "<li> <em>%s</em>\n",	 temp);
-	}
-    }
-    i = STATUSBUFSIZE;
-    while (--i >= topOfStack) {
-	if (buffstack[i] != NULL) {
-	    StrAllocCopy(temp, buffstack[i]);
-	    LYEntify(&temp, TRUE);
-	    fprintf(fp0,  "<li> <em>%s</em>\n",	 temp);
-	}
-    }
-
-    fprintf(fp0, "</ol>\n");
-    fprintf(fp0, "</pre>\n");
-    EndInternalPage(fp0);
-    LYCloseTempFP(fp0);
-
-
-    /* exit to getfile() cycle */
-    StrAllocCopy(newdoc->address, info_url);
-    FREE(newdoc->post_data);
-    FREE(newdoc->post_content_type);
-    FREE(newdoc->bookmark);
-    newdoc->isHEAD = FALSE;
-
-    /* Leave loading it to getfile - that has the advantage to make
-       this kind of link 'd'ownloadable. - kw */
-    return(NORMAL);
-}
-
-/*
  * Dump statusline messages into the buffer.
  * Called from mainloop() when exit immediately with an error:
  * can not access startfile (first_file) so a couple of alert messages
@@ -794,7 +727,6 @@ PUBLIC void LYstore_message2 ARGS2(
     if (message != NULL) {
 	char *temp = NULL;
 	HTSprintf(&temp, message, (argument == 0) ? "" : argument);
-	LYEntify(&temp, TRUE);
 	to_stack(temp);
     }
 }
@@ -805,7 +737,97 @@ PUBLIC void LYstore_message ARGS1(
     if (message != NULL) {
 	char *temp = NULL;
 	StrAllocCopy(temp, message);
-	LYEntify(&temp, TRUE);
 	to_stack(temp);
     }
 }
+
+/*     LYLoadMESSAGES
+**     --------------
+**     Create a text/html stream with a list of recent statusline messages.
+**     LYNXMESSAGES:/ internal page.
+**     [implementation based on LYLoadKeymap()].
+*/
+
+struct _HTStream
+{
+    HTStreamClass * isa;
+};
+
+PRIVATE int LYLoadMESSAGES ARGS4 (
+	CONST char *,		arg GCC_UNUSED,
+	HTParentAnchor *,	anAnchor,
+	HTFormat,		format_out,
+	HTStream*,		sink)
+{
+    HTFormat format_in = WWW_HTML;
+    HTStream *target = NULL;
+    char *buf = NULL;
+
+    int i;
+    char *temp = NULL;
+
+    /*
+     *  Set up the stream. - FM
+     */
+    target = HTStreamStack(format_in, format_out, sink, anAnchor);
+
+    if (!target || target == NULL) {
+	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
+			 HTAtom_name(format_in), HTAtom_name(format_out));
+	HTAlert(buf);
+	FREE(buf);
+	return(HT_NOT_LOADED);
+    }
+    anAnchor->no_cache = TRUE;
+
+#define PUTS(buf)    (*target->isa->put_block)(target, buf, strlen(buf))
+
+    HTSprintf0(&buf, "<html>\n<head>\n");
+    PUTS(buf);
+	/*
+	 *  This page is a list of messages in display character set.
+	 */
+    HTSprintf0(&buf, "<META %s content=\"text/html;charset=%s\">\n",
+	       "http-equiv=\"content-type\"",
+	       LYCharSet_UC[current_char_set].MIMEname);
+    PUTS(buf);
+    HTSprintf0(&buf, "<title>%s</title>\n", STATUSLINES_TITLE);
+    PUTS(buf);
+    HTSprintf0(&buf, "</head>\n<body>\n<pre>\n<ol>\n");
+    PUTS(buf);
+
+    /* print messages in reverse order: */
+    i = topOfStack;
+    while (--i >= 0) {
+	if (buffstack[i] != NULL) {
+	    StrAllocCopy(temp, buffstack[i]);
+	    LYEntify(&temp, TRUE);
+	    HTSprintf0(&buf, "<li> <em>%s</em>\n",  temp);
+	    PUTS(buf);
+	}
+    }
+    i = STATUSBUFSIZE;
+    while (--i >= topOfStack) {
+	if (buffstack[i] != NULL) {
+	    StrAllocCopy(temp, buffstack[i]);
+	    LYEntify(&temp, TRUE);
+	    HTSprintf0(&buf, "<li> <em>%s</em>\n",  temp);
+	    PUTS(buf);
+	}
+    }
+    FREE(temp);
+
+    HTSprintf0(&buf, "</ol>\n</pre>\n</body>\n</html>\n");
+    PUTS(buf);
+
+    (*target->isa->_free)(target);
+    FREE(buf);
+    return(HT_LOADED);
+}
+
+#ifdef GLOBALDEF_IS_MACRO
+#define _LYMESSAGES_C_GLOBALDEF_1_INIT { "LYNXMESSAGES", LYLoadMESSAGES, 0}
+GLOBALDEF (HTProtocol,LYLynxStatusMessages,_LYMESSAGES_C_GLOBALDEF_1_INIT);
+#else
+GLOBALDEF PUBLIC HTProtocol LYLynxStatusMessages = {"LYNXMESSAGES", LYLoadMESSAGES, 0};
+#endif /* GLOBALDEF_IS_MACRO */
diff --git a/src/LYHistory.h b/src/LYHistory.h
index ad25b250..f929e1d1 100644
--- a/src/LYHistory.h
+++ b/src/LYHistory.h
@@ -16,7 +16,6 @@ extern void LYpush PARAMS((document *doc, BOOLEAN force_push));
 
 extern void LYstore_message2 PARAMS((CONST char *message, CONST char *argument));
 extern void LYstore_message PARAMS((CONST char *message));
-extern int LYshow_statusline_messages PARAMS((document *newdoc));
 extern void LYstatusline_messages_on_exit PARAMS((char **buf));
 
 #endif /* LYHISTORY_H */
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index c381c081..148479f7 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -928,16 +928,18 @@ PRIVATE int LYLoadKeymap ARGS4 (
     }
     anAnchor->no_cache = TRUE;
 
+#define PUTS(buf)    (*target->isa->put_block)(target, buf, strlen(buf))
+
     HTSprintf0(&buf, "<head>\n<title>%s</title>\n</head>\n<body>\n",
 		     CURRENT_KEYMAP_TITLE);
-    (*target->isa->put_block)(target, buf, strlen(buf));
+    PUTS(buf);
     HTSprintf0(&buf, "<h1>%s (%s)%s<a href=\"%s%s\">%s</a></h1>\n",
 	LYNX_NAME, LYNX_VERSION,
 	HELP_ON_SEGMENT,
 	helpfilepath, CURRENT_KEYMAP_HELP, CURRENT_KEYMAP_TITLE);
-    (*target->isa->put_block)(target, buf, strlen(buf));
+    PUTS(buf);
     HTSprintf0(&buf, "<pre>\n");
-    (*target->isa->put_block)(target, buf, strlen(buf));
+    PUTS(buf);
 
     for (i = 'a'+1; i <= 'z'+1; i++) {
 	print_binding(target, i);
@@ -959,7 +961,7 @@ PRIVATE int LYLoadKeymap ARGS4 (
     }
 
     HTSprintf0(&buf,"</pre>\n</body>\n");
-    (*target->isa->put_block)(target, buf, strlen(buf));
+    PUTS(buf);
 
     (*target->isa->_free)(target);
     FREE(buf);
diff --git a/src/LYLocal.c b/src/LYLocal.c
index cbb7f62f..735fccdc 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -2324,7 +2324,7 @@ PRIVATE int LYExecv ARGS3(
 	char **,	argv,
 	char *, 	msg)
 {
-#if defined(VMS) || defined(SH_EX) || defined(_WINDOWS)
+#if defined(VMS) || defined(_WINDOWS)
     CTRACE((tfp, "LYExecv:  Called inappropriately!\n"));
     return(0);
 #else
diff --git a/src/LYMain.c b/src/LYMain.c
index 3960ade5..baeb89b8 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -87,7 +87,8 @@ PUBLIC char *LYCSwingPath = NULL;
 #endif /* VMS */
 
 #if HAVE_CUSERID && !defined(_XOPEN_SOURCE)
-extern char *cuserid();		/* workaround for Redhat 6.0 */
+/*extern char *cuserid();*/		/* workaround for Redhat 6.0 */
+		/* for the price of screwing up legitimate systems? Nah. */
 #endif
 
 #ifdef DIRED_SUPPORT
@@ -461,6 +462,7 @@ PUBLIC int partial_threshold = -1;  /* # of lines to be d/l'ed until we repaint
 
 PUBLIC BOOLEAN LYNonRestartingSIGWINCH = FALSE;
 PUBLIC BOOLEAN LYReuseTempfiles = FALSE;
+PUBLIC BOOLEAN LYUseBuiltinSuffixes = TRUE;
 
 /* These are declared in cutil.h for current freeWAIS libraries. - FM */
 #ifdef DECLARE_WAIS_LOGFILES
@@ -473,6 +475,8 @@ extern int HTNewsChunkSize; /* Number of news articles per chunk (HTNews.c) */
 extern int HTNewsMaxChunk;  /* Max news articles before chunking (HTNews.c) */
 #endif
 
+PUBLIC BOOLEAN FileInitAlreadyDone = FALSE;
+
 PRIVATE BOOLEAN stack_dump = FALSE;
 PRIVATE char *terminal = NULL;
 PRIVATE char *pgm;
@@ -545,9 +549,9 @@ PUBLIC int is_windows_nt(void)
 
     version = GetVersion();
     if ((version & 0x80000000) == 0)
-    	return 1;
+	return 1;
     else
-    	return 0;
+	return 0;
 }
 #endif
 
@@ -1664,8 +1668,16 @@ PUBLIC int main ARGS2(
      *	file, if they overlap.
      */
     HTFormatInit();
-    HTFileInit();
+    if (!FileInitAlreadyDone)
+	HTFileInit();
 
+    if (LYUserAgent && *LYUserAgent &&
+		   !strstr(LYUserAgent, "Lynx") &&
+		   !strstr(LYUserAgent, "lynx") &&
+		   !strstr(LYUserAgent, "L_y_n_x") &&
+		   !strstr(LYUserAgent, "l_y_n_x")) {
+	HTAlwaysAlert(gettext("Warning:"), UA_NO_LYNX_WARNING);
+    }
 #ifdef SH_EX
     if (show_cfg) {
 	cleanup();
@@ -1811,7 +1823,7 @@ PUBLIC int main ARGS2(
 	 */
 #ifndef DOSPATH
 	if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
-    	     restore_sigpipe_for_children = TRUE;
+	     restore_sigpipe_for_children = TRUE;
 #endif /* DOSPATH */
     }
 #endif /* !VMS */
@@ -2039,18 +2051,20 @@ PUBLIC int main ARGS2(
 /*
  *  Called by HTAccessInit to register any protocols supported by lynx.
  *  Protocols added by lynx:
- *    LYNXKEYMAP, lynxcgi, LYNXIMGMAP, LYNXCOOKIE
+ *    LYNXKEYMAP, lynxcgi, LYNXIMGMAP, LYNXCOOKIE, LYNXMESSAGES
  */
 #ifdef GLOBALREF_IS_MACRO
 extern GLOBALREF (HTProtocol, LYLynxKeymap);
 extern GLOBALREF (HTProtocol, LYLynxCGI);
 extern GLOBALREF (HTProtocol, LYLynxIMGmap);
 extern GLOBALREF (HTProtocol, LYLynxCookies);
+extern GLOBALREF (HTProtocol, LYLynxStatusMessages);
 #else
 GLOBALREF  HTProtocol LYLynxKeymap;
 GLOBALREF  HTProtocol LYLynxCGI;
 GLOBALREF  HTProtocol LYLynxIMGmap;
 GLOBALREF  HTProtocol LYLynxCookies;
+GLOBALREF  HTProtocol LYLynxStatusMessages;
 #endif /* GLOBALREF_IS_MACRO */
 
 PUBLIC void LYRegisterLynxProtocols NOARGS
@@ -2059,13 +2073,14 @@ PUBLIC void LYRegisterLynxProtocols NOARGS
     HTRegisterProtocol(&LYLynxCGI);
     HTRegisterProtocol(&LYLynxIMGmap);
     HTRegisterProtocol(&LYLynxCookies);
+    HTRegisterProtocol(&LYLynxStatusMessages);
 }
 
 #ifndef NO_CONFIG_INFO
 /*
  *  Some stuff to reload lynx.cfg without restarting new lynx session,
  *  also load options menu items and command-line options
- *  to make things consistent.  Not implemented yet.
+ *  to make things consistent.
  *  Warning: experimental, more main() reorganization required.
  *
  *  Called by user of interactive session by LYNXCFG://reload/ link.
@@ -2112,7 +2127,7 @@ PUBLIC void reload_read_cfg NOARGS
 	custom_display_charset = FALSE;
 	memset((char*)charset_subsets, 0, sizeof(charset_subset_t)*MAXCHARSETS);
 #endif
-	free_lynx_cfg(); /* free downloaders, printers, not always environments */
+	free_lynx_cfg(); /* free downloaders, printers, environments */
 	/*
 	 *  Process the configuration file.
 	 */
@@ -2396,6 +2411,49 @@ static int color_fun ARGS1(
 }
 #endif
 
+#ifdef MISC_EXP
+/* -convert_to */
+static int convert_to_fun ARGS1(
+	char *,			next_arg)
+{
+    if (next_arg != 0) {
+	char *outformat = NULL;
+	char *cp1, *cp2, *cp4;
+	int chndl;
+	StrAllocCopy(outformat, next_arg);
+	/* not lowercased, to allow for experimentation - kw */
+	/*LYLowerCase(outformat);*/
+	if ((cp1 = strchr(outformat, ';')) != NULL) {
+	    if ((cp2 = LYstrstr(cp1, "charset")) != NULL) {
+		cp2 += 7;
+		while (*cp2 == ' ' || *cp2 == '=' || *cp2 == '\"')
+		    cp2++;
+		for (cp4 = cp2; (*cp4 != '\0' && *cp4 != '\"' &&
+				 *cp4 != ';'  &&
+				 !WHITE(*cp4));	cp4++)
+		    ; /* do nothing */
+		*cp4 = '\0';
+		/* This is intentionally not the "safe" version,
+		   to allow for experimentation. */
+		chndl = UCGetLYhndl_byMIME(cp2);
+		if (chndl < 0) chndl = UCLYhndl_for_unrec;
+		if (chndl < 0) {
+		    fprintf(stderr,
+		    gettext("Lynx: ignoring unrecognized charset=%s\n"), cp2);
+		} else {
+		    current_char_set = chndl;
+		}
+		*cp1 = '\0';	/* truncate outformat */
+	    }
+	}
+	HTOutputFormat = HTAtom_for(outformat);
+    } else {
+	HTOutputFormat = NULL;
+    }
+    return 0;
+}
+#endif
+
 /* -crawl */
 static int crawl_fun ARGS1(
 	char *,			next_arg GCC_UNUSED)
@@ -2987,6 +3045,12 @@ static Parse_Args_Type Arg_Table [] =
       "force color mode on with standard bg colors"
    ),
 #endif
+#ifdef MISC_EXP
+   PARSE_SET(
+      "convert_to",	FUNCTION_ARG,		convert_to_fun,
+      "=FORMAT\nconvert input, FORMAT is in MIME type notation (experimental)"
+   ),
+#endif
    PARSE_SET(
       "cookies",	TOGGLE_ARG,		&LYSetCookies,
       "toggles handling of Set-Cookie headers"
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 78225419..1c8f18d8 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -241,6 +241,7 @@ PRIVATE void free_mainloop_variables NOARGS
 #ifdef DIRED_SUPPORT
     clear_tags();
 #endif /* DIRED_SUPPORT */
+    FREE(WWW_Download_File);	/* LYGetFile.c/HTFWriter.c */
 
     return;
 }
@@ -500,7 +501,7 @@ PRIVATE void do_check_goto_URL ARGS3(
 		   !strncmp(user_input_buffer, "LYNXPRINT:", 10)) {
 	    HTUserMsg(GOTO_SPECIAL_DISALLOWED);
 
-       } else {
+	} else {
 	    StrAllocCopy(newdoc.address, user_input_buffer);
 	    newdoc.isHEAD = FALSE;
 	    /*
@@ -1314,9 +1315,8 @@ gettext("Enctype multipart/form-data not yet supported!  Cannot submit."));
 }
 
 #ifdef EXP_ADDRLIST_PAGE
-PRIVATE BOOLEAN handle_LYK_ADDRLIST ARGS2(
-    int *,	cmd,
-    BOOLEAN *,	refresh_screen)
+PRIVATE BOOLEAN handle_LYK_ADDRLIST ARGS1(
+    int *,     cmd)
 {
     /*
      *	Don't do if already viewing list addresses page.
@@ -1343,7 +1343,6 @@ PRIVATE BOOLEAN handle_LYK_ADDRLIST ARGS2(
      *	a POST response. - kw
      */
 
-    refresh_screen = TRUE;  /* redisplay */
     if (LYValidate || check_realm) {
 	LYPermitURL = TRUE;
 	StrAllocCopy(lynxlistfile, newdoc.address);
@@ -2189,7 +2188,7 @@ PRIVATE int handle_LYK_DWIMEDIT ARGS3(
 	    HTUserMsg(ANYEDIT_DISABLED);
 	}
 	return 1;
-    } 
+    }
 #endif /* AUTOEXTEDIT */
     return 0;
 }
@@ -2991,8 +2990,7 @@ PRIVATE void handle_LYK_HISTORICAL NOARGS
     return;
 }
 
-PRIVATE BOOLEAN handle_LYK_HISTORY ARGS2(
-    BOOLEAN *,	refresh_screen,
+PRIVATE BOOLEAN handle_LYK_HISTORY ARGS1(
     BOOLEAN,	ForcePush)
 {
     if (curdoc.title && strcmp(curdoc.title, HISTORY_PAGE_TITLE)) {
@@ -3029,7 +3027,6 @@ PRIVATE BOOLEAN handle_LYK_HISTORY ARGS2(
 	newdoc.link = 1; /*@@@ bypass "recent statusline messages" link */
 	FREE(curdoc.address);  /* so it doesn't get pushed */
 
-	*refresh_screen = TRUE;
 	if (LYValidate || check_realm) {
 	    LYPermitURL = TRUE;
 	}
@@ -3090,10 +3087,9 @@ PRIVATE void handle_LYK_INDEX ARGS2(
     }  /* end if */
 }
 
-PRIVATE void handle_LYK_INDEX_SEARCH ARGS5(
+PRIVATE void handle_LYK_INDEX_SEARCH ARGS4(
     BOOLEAN *,	force_load,
     BOOLEAN,	ForcePush,
-    BOOLEAN *,	refresh_screen,
     int *,	old_c,
     int,	real_c)
 {
@@ -3132,7 +3128,6 @@ PRIVATE void handle_LYK_INDEX_SEARCH ARGS5(
 	    newdoc.internal_link = FALSE;
 	    curdoc.line = -1;
 	    Newline = 0;
-	    *refresh_screen = TRUE; /* redisplay it */
 	} else if (use_this_url_instead != NULL) {
 	    /*
 	     *	Got back a redirecting URL.  Check it out.
@@ -3411,9 +3406,8 @@ PRIVATE void handle_LYK_LEFT_LINK ARGS1(
     }
 }
 
-PRIVATE BOOLEAN handle_LYK_LIST ARGS2(
-    int *,	cmd,
-    BOOLEAN *,	refresh_screen)
+PRIVATE BOOLEAN handle_LYK_LIST ARGS1(
+    int *,     cmd)
 {
     /*
      *	Don't do if already viewing list page.
@@ -3440,7 +3434,6 @@ PRIVATE BOOLEAN handle_LYK_LIST ARGS2(
      *	a POST response. - kw
      */
 
-    *refresh_screen = TRUE;  /* redisplay */
     if (LYValidate || check_realm) {
 	LYPermitURL = TRUE;
 	StrAllocCopy(lynxlistfile, newdoc.address);
@@ -3776,7 +3769,7 @@ PRIVATE void handle_LYK_NEXT_PAGE ARGS3(
 	highlight(OFF, curdoc.link, prev_target);
 	curdoc.link = nlinks-1;  /* put on last link */
     } else if (*old_c != real_c) {
-        *old_c = real_c;
+	*old_c = real_c;
 	HTInfoMsg(ALREADY_AT_END);
     }
 }
@@ -3799,7 +3792,7 @@ PRIVATE BOOLEAN handle_LYK_NOCACHE ARGS2(
 	    LYforce_no_cache = TRUE;
 	    reloading = TRUE;
 	}
-    } 
+    }
     return TRUE;
 }
 
@@ -3976,8 +3969,7 @@ PRIVATE void handle_LYK_PREV_PAGE ARGS3(
     }
 }
 
-PRIVATE void handle_LYK_PRINT ARGS4(
-    BOOLEAN *,	refresh_screen,
+PRIVATE void handle_LYK_PRINT ARGS3(
     BOOLEAN *,	ForcePush,
     int *,	old_c,
     int,	real_c)
@@ -4005,7 +3997,6 @@ PRIVATE void handle_LYK_PRINT ARGS4(
 	*ForcePush = TRUE;  /* see LYpush() and print_options() */
 	if (check_realm)
 	    LYPermitURL = TRUE;
-	*refresh_screen = TRUE;	/* redisplay */
     }
 }
 
@@ -4071,8 +4062,8 @@ PRIVATE void handle_LYK_RELOAD ARGS1(
      */
 
     if (HTisDocumentSource()) {
-	force_old_UCLYhndl_on_reload = TRUE;
-	forced_UCLYhdnl = HTMainText_Get_UCLYhndl();
+	if ((forced_UCLYhdnl = HTMainText_Get_UCLYhndl()) >= 0)
+	    force_old_UCLYhndl_on_reload = TRUE;
 #ifndef USE_PSRC
 	HTOutputFormat = WWW_SOURCE;
 #else
@@ -4628,7 +4619,7 @@ PRIVATE void handle_LYK_VIEW_BOOKMARK ARGS3(
 	}
 #if defined(CJK_EX)	/* 1997/12/13 (Sat) 15:20:18 */
 	if (HTCJK == JAPANESE) {
-	    *last_kcode = NOKANJI;	/* AUTO */
+	    last_kcode = NOKANJI;	/* AUTO */
 	}
 #endif
 	LYforce_no_cache = TRUE;  /*force the document to be reloaded*/
@@ -4651,9 +4642,8 @@ PRIVATE void handle_LYK_VIEW_BOOKMARK ARGS3(
     }
 }
 
-PRIVATE BOOLEAN handle_LYK_VLINKS ARGS2(
-    int *,	cmd,
-    BOOLEAN *,	refresh_screen)
+PRIVATE BOOLEAN handle_LYK_VLINKS ARGS1(
+    int *,     cmd)
 {
     if (!strcmp((curdoc.title ? curdoc.title : ""),
 		VISITED_LINKS_TITLE)) {
@@ -4678,7 +4668,6 @@ PRIVATE BOOLEAN handle_LYK_VLINKS ARGS2(
     newdoc.isHEAD = FALSE;
     newdoc.safe = FALSE;
     newdoc.internal_link = FALSE;
-    *refresh_screen = TRUE;
     if (LYValidate || check_realm) {
 	LYPermitURL = TRUE;
 	StrAllocCopy(lynxlinksfile, newdoc.address);
@@ -6004,7 +5993,7 @@ try_again:
 	 */
 	if (HTdocument_settings_changed()) {
 	   if (HTcan_reparse_document()) {
-	       HTUserMsg(gettext("Reparsing document under current settings..."));
+	       HTInfoMsg(gettext("Reparsing document under current settings..."));
 	       if (HTreparse_document()) {}
 	   } else {
 		/*
@@ -6734,7 +6723,7 @@ new_cmd:  /*
 	    break;
 
 	case LYK_HISTORY:	/* show the history page */
-	    if (handle_LYK_HISTORY(&refresh_screen, ForcePush))
+	    if (handle_LYK_HISTORY(ForcePush))
 		break;
 
 	    /* FALLTHRU */
@@ -6790,7 +6779,7 @@ new_cmd:  /*
 	    handle_LYK_HELP(&cshelpfile);
 	    break;
 
-	case LYK_INDEX:  	/* index file */
+	case LYK_INDEX:		/* index file */
 	    handle_LYK_INDEX(&old_c, real_c);
 	    break;
 
@@ -6804,7 +6793,7 @@ new_cmd:  /*
 	    break;
 
 	case LYK_INDEX_SEARCH:	/* search for a user string */
-	    handle_LYK_INDEX_SEARCH(&force_load, ForcePush, &refresh_screen, &old_c, real_c);
+	    handle_LYK_INDEX_SEARCH(&force_load, ForcePush, &old_c, real_c);
 	    break;
 
 	case LYK_WHEREIS: /* search within the document */
@@ -6812,7 +6801,7 @@ new_cmd:  /*
 	    handle_LYK_WHEREIS(cmd, prev_target, &refresh_screen);
 	    break;
 
-	case LYK_COMMENT: 	/* reply by mail */
+	case LYK_COMMENT:	/* reply by mail */
 	    handle_LYK_COMMENT(&refresh_screen, owner_address, &old_c, real_c);
 	    break;
 
@@ -6821,11 +6810,11 @@ new_cmd:  /*
 	    handle_LYK_TAG_LINK(prev_target);
 	    break;
 
-	case LYK_MODIFY:  	/* rename a file or directory */
+	case LYK_MODIFY:	/* rename a file or directory */
 	    handle_LYK_MODIFY(&refresh_screen);
 	    break;
 
-	case LYK_CREATE:  	/* create a new file or directory */
+	case LYK_CREATE:	/* create a new file or directory */
 	    handle_LYK_CREATE();
 	    break;
 #endif /* DIRED_SUPPORT */
@@ -6877,23 +6866,23 @@ new_cmd:  /*
 	    break;
 
 	case LYK_PRINT:  /* print the file */
-	    handle_LYK_PRINT(&refresh_screen, &ForcePush, &old_c, real_c);
+	    handle_LYK_PRINT(&ForcePush, &old_c, real_c);
 	    break;
 
 	case LYK_LIST:	/* list links in the current document */
-	    if (handle_LYK_LIST(&cmd, &refresh_screen))
+	    if (handle_LYK_LIST(&cmd))
 		goto new_cmd;
 	    break;
 
 #ifdef EXP_ADDRLIST_PAGE
 	case LYK_ADDRLIST:   /* always list URL's (only) */
-	    if (handle_LYK_ADDRLIST(&cmd, &refresh_screen))
+	    if (handle_LYK_ADDRLIST(&cmd))
 		goto new_cmd;
 	    break;
 #endif /* EXP_ADDRLIST_PAGE */
 
 	case LYK_VLINKS:  /* list links visited during the current session */
-	    if (handle_LYK_VLINKS(&cmd, &refresh_screen))
+	    if (handle_LYK_VLINKS(&cmd))
 		goto new_cmd;
 	    break;
 
@@ -7109,14 +7098,13 @@ PRIVATE int are_different ARGS2(
     /*
      *	Are the base addresses different?
      */
-    if (strcmp(doc1->address, doc2->address))
-      {
+    if (strcmp(doc1->address, doc2->address)) {
 	if (cp1)
 	    *cp1 = '#';
 	if (cp2)
 	    *cp2 = '#';
 	return(TRUE);
-      }
+    }
     if (cp1)
 	*cp1 = '#';
     if (cp2)
@@ -7125,19 +7113,14 @@ PRIVATE int are_different ARGS2(
     /*
      *	Do the docs have different contents?
      */
-    if (doc1->post_data)
-      {
-	if (doc2->post_data)
-	  {
+    if (doc1->post_data) {
+	if (doc2->post_data) {
 	    if (strcmp(doc1->post_data, doc2->post_data))
 		return(TRUE);
-	  }
-	else
-	    return(TRUE);
-      }
-    else
-	if (doc2->post_data)
+	} else
 	    return(TRUE);
+    } else if (doc2->post_data)
+	return(TRUE);
 
     /*
      *	We'll assume the two documents in fact are the same.
@@ -7194,14 +7177,13 @@ PRIVATE int are_phys_different ARGS2(
     /*
      *	Are the base addresses different?
      */
-    if (strcmp(ap1, ap2))
-      {
+    if (strcmp(ap1, ap2)) {
 	if (cp1)
 	    *cp1 = '#';
 	if (cp2)
 	    *cp2 = '#';
 	return(TRUE);
-      }
+    }
     if (cp1)
 	*cp1 = '#';
     if (cp2)
@@ -7210,19 +7192,14 @@ PRIVATE int are_phys_different ARGS2(
     /*
      *	Do the docs have different contents?
      */
-    if (doc1->post_data)
-      {
-	if (doc2->post_data)
-	  {
+    if (doc1->post_data) {
+	if (doc2->post_data) {
 	    if (strcmp(doc1->post_data, doc2->post_data))
 		return(TRUE);
-	  }
-	else
-	    return(TRUE);
-      }
-    else
-	if (doc2->post_data)
+	} else
 	    return(TRUE);
+    } else if (doc2->post_data)
+	return(TRUE);
 
     /*
      *	We'll assume the two documents in fact are the same.
diff --git a/src/LYMap.c b/src/LYMap.c
index 05593910..b74c743d 100644
--- a/src/LYMap.c
+++ b/src/LYMap.c
@@ -124,8 +124,8 @@ PRIVATE void LYLynxMaps_free NOARGS
  *  MAP element content. - FM
  */
 PUBLIC BOOL LYAddImageMap ARGS3(
-	char *, 	address,
-	char *, 	title,
+	char *,		address,
+	char *,		title,
 	HTParentAnchor *, node_anchor)
 {
     LYImageMap *new = NULL;
@@ -173,7 +173,7 @@ PUBLIC BOOL LYAddImageMap ARGS3(
 	cur = theList;
 	while (NULL != (old = (LYImageMap *)HTList_nextObject(cur))) {
 	    if (old->address == 0)	/* shouldn't happen */
-	    	continue;
+		continue;
 	    if (!strcmp(old->address, address)) {
 		FREE(old->address);
 		FREE(old->title);
@@ -212,9 +212,9 @@ PUBLIC BOOL LYAddImageMap ARGS3(
  * in the appropriate list. - FM
  */
 PUBLIC BOOL LYAddMapElement ARGS5(
-	char *, 	map,
-	char *, 	address,
-	char *, 	title,
+	char *,		map,
+	char *,		address,
+	char *,		title,
 	HTParentAnchor *, node_anchor,
 	BOOL,		intern_flag)
 {
@@ -299,7 +299,7 @@ PUBLIC BOOL LYAddMapElement ARGS5(
  *  structure. - FM
  */
 PUBLIC BOOL LYHaveImageMap ARGS1(
-	char *, 	address)
+	char *,		address)
 {
     LYImageMap *Map;
     HTList *cur = LynxMaps;
@@ -470,6 +470,25 @@ PRIVATE int LYLoadIMGmap ARGS4 (
 	    break;
 	}
     }
+    if (theMap && HTList_count(theMap->elements) == 0) {
+	/*
+	 *  We found a MAP without any usable AREA.
+	 *  Fake a redirection to the address with fragment.
+	 *  We do this even for post data (internal link within
+	 *  a document with post data) if it will not result in
+	 *  an unwanted network request. - kw
+	 */
+	if (!anAnchor->post_data) {
+	    StrAllocCopy(redirecting_url, address);
+	    return(HT_REDIRECTING);
+	} else if (WWWDoc.safe ||
+		   (underlying->document && !anAnchor->document &&
+		    (LYinternal_flag || LYoverride_no_cache))) {
+	    StrAllocCopy(redirecting_url, address);
+	    redirect_post_content = TRUE;
+	    return(HT_REDIRECTING);
+	}
+    }
     if (!(theMap && theMap->elements)) {
 	if (anAnchor->post_data && !WWWDoc.safe &&
 	    ((underlying && underlying->document && !LYforce_no_cache) ||
diff --git a/src/LYNews.c b/src/LYNews.c
index 2425c365..85c5759e 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -118,6 +118,13 @@ PUBLIC char *LYNewsPost ARGS2(
 	return(postfile);
 
     /*
+     *  Return immediately if we do get called, maybe by some quirk
+     *  of HTNews.c, when we shouldn't. - kw
+     */
+    if (no_newspost)
+	return(postfile);
+
+    /*
      *  Open a temporary file for the headers
      *  and message body. - FM
      */
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 60fe6e4c..ba1e2973 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -1615,13 +1615,15 @@ draw_options:
 			HTInfoMsg("");
 		    } else if (LYUserAgent && *LYUserAgent &&
 			!strstr(LYUserAgent, "Lynx") &&
-			!strstr(LYUserAgent, "lynx")) {
-			_statusline(UA_COPYRIGHT_WARNING);
+			!strstr(LYUserAgent, "lynx") &&
+			!strstr(LYUserAgent, "L_y_n_x") &&
+			!strstr(LYUserAgent, "l_y_n_x")) {
+			_statusline(UA_PLEASE_USE_LYNX);
 		    } else {
 			_statusline(VALUE_ACCEPTED);
 		    }
 		} else { /* disallowed */
-		    _statusline(UA_COPYRIGHT_WARNING);
+		    _statusline(UA_CHANGE_DISABLED);
 		}
 		response = ' ';
 		break;
@@ -2425,7 +2427,7 @@ PUBLIC int popup_choice ARGS7(
 #ifdef NCURSES
     LYsubwindow(form_window);
 #endif
-#if defined(HAVE_GETBKGD) && !defined(PDCURSES)/* not defined in ncurses 1.8.7 */
+#if defined(HAVE_GETBKGD)/* not defined in ncurses 1.8.7 */
     wbkgd(form_window, getbkgd(stdscr));
     wbkgdset(form_window, getbkgd(stdscr));
 #endif
@@ -3405,19 +3407,26 @@ static char * user_agent_string		= "user_agent";
 #define PutLabel(fp, text) \
 	fprintf(fp,"  %-33s: ", text)
 
+#define PutLabelNotSaved(fp, text) \
+    if (!no_option_save) { \
+	int l=strlen(text); \
+	fprintf(fp,"  %s", text); \
+	fprintf(fp,"%s%-*s: ", (l<30)?" ":"", (l<30)?32-l:3, "(!)"); \
+    } else PutLabel(fp, text)
+
 #define PutTextInput(fp, Name, Value, Size, disable) \
 	fprintf(fp,\
 	"<input size=%d type=\"text\" name=\"%s\" value=\"%s\" %s>\n",\
-		(int) Size, Name, Value, disable)
+		(int) Size, Name, Value, disable_all?disabled_string:disable)
 
 #define PutOption(fp, flag, html, name) \
 	fprintf(fp,"<option value=\"%s\" %s>%s\n", html, SELECTED(flag), name)
 
 #define BeginSelect(fp, text) \
-	fprintf(fp,"<select name=\"%s\">\n", text)
+	fprintf(fp,"<select name=\"%s\" %s>\n", text, disable_all?disabled_string:"")
 
 #define MaybeSelect(fp, flag, text) \
-	fprintf(fp,"<select name=\"%s\" %s>\n", text, DISABLED(flag))
+	fprintf(fp,"<select name=\"%s\" %s>\n", text, disable_all?disabled_string:DISABLED(flag))
 
 #define EndSelect(fp)\
 	fprintf(fp,"</select>\n")
@@ -3928,8 +3937,10 @@ PUBLIC int postoptions ARGS1(
 		   : LYUserAgentDefault);
 		if (LYUserAgent && *LYUserAgent &&
 		   !strstr(LYUserAgent, "Lynx") &&
-		   !strstr(LYUserAgent, "lynx")) {
-		    HTAlert(UA_COPYRIGHT_WARNING);
+		   !strstr(LYUserAgent, "lynx") &&
+		   !strstr(LYUserAgent, "L_y_n_x") &&
+		   !strstr(LYUserAgent, "l_y_n_x")) {
+		    HTAlert(UA_PLEASE_USE_LYNX);
 		}
 	    }
 	}
@@ -4137,6 +4148,7 @@ PRIVATE int gen_options ARGS1(
     BOOLEAN can_do_colors;
 #endif
     static char tempfile[LY_MAXPATH] = "\0";
+    BOOLEAN disable_all = FALSE;
     FILE *fp0;
     size_t cset_len = 0;
     size_t text_len = COLS - 38;	/* cf: PutLabel */
@@ -4163,6 +4175,13 @@ PRIVATE int gen_options ARGS1(
        the flag. - kw 1999-05-24 */
     LYforce_no_cache = TRUE;
 
+    /*
+     * Without LYUseFormsOptions set we should maybe not even get here.
+     * However, it's possible we do; disable the form in that case. - kw
+     */
+    if (!LYUseFormsOptions)
+	disable_all = TRUE;
+
     BeginInternalPage(fp0, OPTIONS_TITLE, NULL); /* help link below */
 
     /*
@@ -4183,17 +4202,22 @@ PRIVATE int gen_options ARGS1(
 
     /* Submit/Reset/Help */
     fprintf(fp0,"<p align=center>\n");
-    fprintf(fp0,"<input type=\"submit\" value=\"%s\"> - \n", ACCEPT_CHANGES);
-    fprintf(fp0,"<input type=\"reset\" value=\"%s\">\n", RESET_CHANGES);
-    fprintf(fp0,"%s\n", CANCEL_CHANGES);
+    if (!disable_all) {
+	fprintf(fp0,"<input type=\"submit\" value=\"%s\"> - \n", ACCEPT_CHANGES);
+	fprintf(fp0,"<input type=\"reset\" value=\"%s\">\n", RESET_CHANGES);
+	fprintf(fp0,"%s\n", CANCEL_CHANGES);
+    }
     fprintf(fp0, "<a href=\"%s%s\">%s</a>\n",
 		 helpfilepath, OPTIONS_HELP, TO_HELP);
 
     /* Save options */
     if (!no_option_save) {
-	fprintf(fp0, "<p align=center>%s: ", SAVE_OPTIONS);
-	fprintf(fp0, "<input type=\"checkbox\" name=\"%s\">\n",
-		save_options_string);
+	if (!disable_all) {
+	    fprintf(fp0, "<p align=center>%s: ", SAVE_OPTIONS);
+	    fprintf(fp0, "<input type=\"checkbox\" name=\"%s\">\n",
+		    save_options_string);
+	}
+	fprintf(fp0, "<br>(options marked with (!) will not be saved)\n");
     }
 
     /*
@@ -4203,7 +4227,9 @@ PRIVATE int gen_options ARGS1(
     fprintf(fp0,"\n  <em>%s</em>\n", gettext("Personal Preferences"));
 
     /* Cookies: SELECT */
-    PutLabel(fp0, gettext("Cookies"));
+    /* @@@ This is inconsistent - LYAcceptAllCookies gets saved to RC file
+       but LYSetCookies doesn't! */
+    PutLabelNotSaved(fp0, gettext("Cookies"));
     BeginSelect(fp0, cookies_string);
     PutOption(fp0, !LYSetCookies,
 	      cookies_ignore_all_string,
@@ -4348,7 +4374,7 @@ PRIVATE int gen_options ARGS1(
     EndSelect(fp0);
 
     /* X Display: INPUT */
-    PutLabel(fp0, gettext("X Display"));
+    PutLabelNotSaved(fp0, gettext("X Display"));
     PutTextInput(fp0, x_display_string, NOTEMPTY(x_display), text_len, "");
 
     /*
@@ -4371,7 +4397,7 @@ PRIVATE int gen_options ARGS1(
 	    /* ok, LYRawMode, so use UCAssume_MIMEcharset */
 	    curval = safeUCGetLYhndl_byMIME(UCAssume_MIMEcharset);
 	}
-	PutLabel(fp0, gettext("Assumed document character set"));
+	PutLabelNotSaved(fp0, gettext("Assumed document character set"));
 	BeginSelect(fp0, assume_char_set_string);
 	for (i = 0; i < LYNumCharsets; i++) {
 #ifdef EXP_CHARSET_CHOICE
@@ -4385,15 +4411,16 @@ PRIVATE int gen_options ARGS1(
     }
 
     /* Raw Mode: ON/OFF */
-    if (LYHaveCJKCharacterSet)
+    if (LYHaveCJKCharacterSet) {
 	/*
 	 * Since CJK people hardly mixed with other world
 	 * we split the header to make it more readable:
 	 * "CJK mode" for CJK display charsets, and "Raw 8-bit" for others.
 	 */
-	PutLabel(fp0, gettext("CJK mode"));
-    else
-	PutLabel(fp0, gettext("Raw 8-bit"));
+	PutLabelNotSaved(fp0, gettext("CJK mode"));
+    } else {
+	PutLabelNotSaved(fp0, gettext("Raw 8-bit"));
+    }
 
     BeginSelect(fp0, raw_mode_string);
     PutOptValues(fp0, LYRawMode, bool_values);
@@ -4401,7 +4428,7 @@ PRIVATE int gen_options ARGS1(
 
 #ifndef SH_EX	/* 1999/01/19 (Tue) */
     /* HTML error recovery: SELECT */
-    PutLabel(fp0, gettext("HTML error recovery"));
+    PutLabelNotSaved(fp0, gettext("HTML error recovery"));
     BeginSelect(fp0, DTD_recovery_string);
     PutOptValues(fp0, Old_DTD, DTD_type_values);
     EndSelect(fp0);
@@ -4414,7 +4441,7 @@ PRIVATE int gen_options ARGS1(
     EndSelect(fp0);
 
     /* Show Images: SELECT */
-    PutLabel(fp0, gettext("Show images"));
+    PutLabelNotSaved(fp0, gettext("Show images"));
     BeginSelect(fp0, images_string);
     PutOption(fp0, !pseudo_inline_alts && !clickable_images,
        images_ignore_all_string,
@@ -4531,7 +4558,7 @@ PRIVATE int gen_options ARGS1(
 
     /* User Agent: INPUT */
     if (!no_useragent) {
-	PutLabel(fp0, gettext("User-Agent header"));
+	PutLabelNotSaved(fp0, gettext("User-Agent header"));
 	PutTextInput(fp0, user_agent_string,
 		     NOTEMPTY(LYUserAgent), text_len, "");
     }
@@ -4544,10 +4571,12 @@ PRIVATE int gen_options ARGS1(
     fprintf(fp0,"\n</pre>\n");
 
     /* Submit/Reset */
-    fprintf(fp0,"<p align=center>\n");
-    fprintf(fp0,"<input type=\"submit\" value=\"%s\">\n - ", ACCEPT_CHANGES);
-    fprintf(fp0,"<input type=\"reset\" value=\"%s\">\n", RESET_CHANGES);
-    fprintf(fp0,"%s\n", CANCEL_CHANGES);
+    if (!disable_all) {
+	fprintf(fp0,"<p align=center>\n");
+	fprintf(fp0,"<input type=\"submit\" value=\"%s\">\n - ", ACCEPT_CHANGES);
+	fprintf(fp0,"<input type=\"reset\" value=\"%s\">\n", RESET_CHANGES);
+	fprintf(fp0,"%s\n", CANCEL_CHANGES);
+    }
 
     /*
      * close HTML
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 817f5d04..03ea1b04 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -1232,38 +1232,27 @@ PRIVATE int remove_quotes ARGS1(
  *
  *  Always returns a new allocated string which has to be freed.
  */
+#include <LYCharUtils.h>
 PRIVATE char* subject_translate8bit ARGS1(char *, source)
 {
-    CONST char *p = source;
-    char temp[2];
     char *target = NULL;
 
     int charset_in, charset_out;
-    char replace_buf [10];
 
     int i = outgoing_mail_charset;  /* from lynx.cfg, -1 by default */
 
+    StrAllocCopy(target, source);
     if (i < 0
      || i == current_char_set
      || LYCharSet_UC[current_char_set].enc == UCT_ENC_CJK
      || LYCharSet_UC[i].enc == UCT_ENC_CJK) {
-	StrAllocCopy(target, source);
 	return(target); /* OK */
     } else {
 	charset_out = i;
 	charset_in  = current_char_set;
     }
 
-    for ( ; *p; p++) {
-	LYstrncpy(temp, p, sizeof(temp)-1);
-	if ((unsigned char)*temp <= 127) {
-	    StrAllocCat(target, temp);
-	} else {
-	    if (UCTransCharStr(replace_buf, sizeof(replace_buf), *temp,
-				charset_in, charset_out, YES) > 0)
-		StrAllocCat(target, replace_buf);
-	}
-    }
+    LYUCTranslateBackHeaderText(&target, charset_in, charset_out, YES);
 
     return(target);
 }
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index b2bfd81e..2d47628e 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -4,6 +4,7 @@
 #include <HTUtils.h>
 #endif
 #include <HTFile.h>
+#include <HTInit.h>
 #include <UCMap.h>
 
 #include <LYUtils.h>
@@ -822,29 +823,109 @@ static int source_cache_fun ARGS1(
 static int suffix_fun ARGS1(
 	char *,		value)
 {
-    char *mime_type;
+    char *mime_type, *p;
+    char *encoding = NULL, *sq = NULL, *description = NULL;
+    float q = 1.0;
 
     if ((strlen (value) < 3)
-    || (NULL == (mime_type = strchr (value, ':'))))
+    || (NULL == (mime_type = strchr (value, ':')))) {
+	CTRACE((tfp, "Invalid SUFFIX:%s ignored.\n", value));
 	return 0;
+    }
 
     *mime_type++ = '\0';
+    if (*mime_type) {
+	if ((encoding = strchr(mime_type, ':')) != NULL) {
+	    *encoding++ = '\0';
+	    if ((sq = strchr(encoding, ':')) != NULL) {
+		*sq++ = '\0';
+		if ((description = strchr(sq, ':')) != NULL) {
+		    *description++ = '\0';
+		    if ((p = strchr(sq, ':')) != NULL)
+			*p = '\0';
+		    LYTrimTail(description);
+		}
+		LYRemoveBlanks(sq);
+		if (!*sq)
+		    sq = NULL;
+	    }
+	    LYRemoveBlanks(encoding);
+	    LYLowerCase(encoding);
+	    if (!*encoding)
+		encoding = NULL;
+	}
+    }
 
     LYRemoveBlanks(mime_type);
-    LYLowerCase(mime_type);
+    /*
+     *  Not converted to lowercase on input, to make it possible to
+     *  reproduce the equivalent of some of the HTInit.c defaults
+     *  that use mixed case, although that is not recomended. - kw
+     */ /*LYLowerCase(mime_type);*/
+
+    if (!*mime_type) { /* that's ok now, with an encoding!  */
+	CTRACE((tfp, "SUFFIX:%s without MIME type for %s\n", value,
+	       encoding ? encoding : "what?"));
+	mime_type = NULL; /* that's ok now, with an encoding!  */
+	if (!encoding)
+	    return 0;
+    }
 
-    if (strstr(mime_type, "tex") != NULL ||
-	strstr(mime_type, "postscript") != NULL ||
-	strstr(mime_type, "sh") != NULL ||
-	strstr(mime_type, "troff") != NULL ||
-	strstr(mime_type, "rtf") != NULL)
-	HTSetSuffix(value, mime_type, "8bit", 1.0);
-    else
-	HTSetSuffix(value, mime_type, "binary", 1.0);
+    if (!encoding) {
+	if (strstr(mime_type, "tex") != NULL ||
+	    strstr(mime_type, "postscript") != NULL ||
+	    strstr(mime_type, "sh") != NULL ||
+	    strstr(mime_type, "troff") != NULL ||
+	    strstr(mime_type, "rtf") != NULL)
+	    encoding = "8bit";
+	else
+	    encoding = "binary";
+    }
+    if (!sq) {
+	q = 1.0;
+    } else {
+	double df = strtod(sq, &p);
+	if (p == sq && df == 0.0) {
+	    CTRACE((tfp, "Invalid q=%s for SUFFIX:%s, using -1.0\n",
+		   sq, value));
+	    q = -1.0;
+	} else {
+	    q = df;
+	}
+    }
+    HTSetSuffix5(value, mime_type, encoding, description, q);
 
     return 0;
 }
 
+static int suffix_order_fun ARGS1(
+	char *,		value)
+{
+    char *p = value;
+    char *optn;
+    BOOLEAN want_file_init_now = FALSE;
+
+    LYUseBuiltinSuffixes = TRUE;
+    while ((optn = HTNextTok(&p, ", ", "", NULL)) != NULL) {
+	if (!strcasecomp(optn, "NO_BUILTIN")) {
+	    LYUseBuiltinSuffixes = FALSE;
+	} else if (!strcasecomp(optn, "PRECEDENCE_HERE")) {
+	    want_file_init_now = TRUE;
+	} else if (!strcasecomp(optn, "PRECEDENCE_OTHER")) {
+	    want_file_init_now = FALSE;
+	} else {
+	    CTRACE((tfp, "Invalid SUFFIX_ORDER:%s\n", optn));
+	    break;
+	}
+    }
+
+    if (want_file_init_now && !FileInitAlreadyDone) {
+	HTFileInit();
+	FileInitAlreadyDone = TRUE;
+    }
+    return 0;
+}
+
 static int system_editor_fun ARGS1(
 	char *,		value)
 {
@@ -1329,6 +1410,7 @@ static Config_Type Config_Table [] =
      PARSE_SET("strip_dotdot_urls", CONF_BOOL, &LYStripDotDotURLs),
      PARSE_SET("substitute_underscores", CONF_BOOL, &use_underscore),
      PARSE_FUN("suffix", CONF_FUN, suffix_fun),
+     PARSE_FUN("suffix_order", CONF_FUN, suffix_order_fun),
      PARSE_FUN("system_editor", CONF_FUN, system_editor_fun),
      PARSE_STR("system_mail", CONF_STR, &system_mail),
      PARSE_STR("system_mail_flags", CONF_STR, &system_mail_flags),
diff --git a/src/LYStrings.c b/src/LYStrings.c
index 1806d0cc..a4a7fe29 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -315,6 +315,17 @@ PRIVATE int set_clicked_link ARGS4(
 	    return INSERT_KEY;
 	if (y >= h)
 	    return REMOVE_KEY;
+#ifdef DISP_PARTIAL			/* Newline is not defined otherwise */
+	if (clicks >= 2) {
+	    double frac = (1. * y)/(h - 1);
+	    int l = HText_getNumOfLines() + 1;	/* NOL() off by one? */
+
+	    l -= display_lines;
+	    if (l > 0)
+		Newline = frac * l + 1 + 0.5;
+	    return LYReverseKeymap(LYK_DO_NOTHING);
+	}
+#endif
 	if (y < LYsb_begin)
 	    return PGUP;
 	if (y >= LYsb_end)
@@ -418,7 +429,7 @@ PRIVATE int set_clicked_link ARGS4(
  *  Writes a null byte into the n+1 byte of dst.
  */
 PUBLIC char *LYstrncpy ARGS3(
-	char *, 	dst,
+	char *,		dst,
 	CONST char *,	src,
 	int,		n)
 {
@@ -451,7 +462,7 @@ PUBLIC char *LYstrncpy ARGS3(
  *  argument should be TRUE for UTF8. - KW & FM
  */
 PUBLIC char * LYmbcsstrncpy ARGS5(
-	char *, 	dst,
+	char *,		dst,
 	CONST char *,	src,
 	int,		n_bytes,
 	int,		n_glyphs,
@@ -485,7 +496,7 @@ PUBLIC char * LYmbcsstrncpy ARGS5(
  *  of UTF-8 encoded characters. - KW
  */
 PUBLIC char * LYmbcs_skip_glyphs ARGS3(
-	char *, 	data,
+	char *,		data,
 	int,		n_glyphs,
 	BOOL,		utf_flag)
 {
@@ -516,7 +527,7 @@ PUBLIC char * LYmbcs_skip_glyphs ARGS3(
  *  characters. - FM
  */
 PUBLIC int LYmbcsstrlen ARGS2(
-	char *, 	str,
+	char *,		str,
 	BOOL,		utf_flag)
 {
     int i, j, len = 0;
@@ -740,7 +751,7 @@ static Keysym_String_List Keysym_Strings [] =
     INTERN_KEY( "INSERT_KEY",	INSERT_KEY,	KEY_IC ),
     INTERN_KEY( "REMOVE_KEY",	REMOVE_KEY,	KEY_DC ),
     INTERN_KEY( "DO_NOTHING",	DO_NOTHING,	DO_NOTHING|LKC_ISLKC ),
-    INTERN_KEY( NULL, 		-1,		ERR )
+    INTERN_KEY( NULL,		-1,		ERR )
 };
 
 #ifdef NCURSES_VERSION
@@ -1141,7 +1152,7 @@ PRIVATE void setup_vtXXX_keymap NOARGS
     };
     size_t n;
     for (n = 0; n < TABLESIZE(table); n++)
-    	define_key(table[n].string, table[n].value);
+	define_key(table[n].string, table[n].value);
 }
 
 PUBLIC int lynx_initialize_keymaps NOARGS
@@ -1204,7 +1215,7 @@ PRIVATE int LYmouse_menu ARGS4(int, x, int, y, int, atlink, int, code)
 	"Page down",
 	"End of document",
 	"Bookmarks",
- 	"Cookie jar",
+	"Cookie jar",
 	"Search index",
 	"Set Options",
 	NULL
@@ -1238,7 +1249,7 @@ PRIVATE int LYmouse_menu ARGS4(int, x, int, y, int, atlink, int, code)
 	LYK_NEXT_PAGE,
 	LYK_END,
 	LYK_VIEW_BOOKMARK,
- 	LYK_COOKIE_JAR,
+	LYK_COOKIE_JAR,
 	LYK_INDEX_SEARCH,
 	LYK_OPTIONS
     };
@@ -1297,7 +1308,7 @@ PRIVATE int LYmouse_menu ARGS4(int, x, int, y, int, atlink, int, code)
 	    case LYK_NEXT_PAGE:
 	    case LYK_END:
 	    case LYK_VIEW_BOOKMARK:
- 	    case LYK_COOKIE_JAR:
+	    case LYK_COOKIE_JAR:
 	    case LYK_INDEX_SEARCH:
 	    case LYK_OPTIONS:
 		mouse_link = -3; /* so LYgetch_for() passes it on - kw */
@@ -1328,7 +1339,7 @@ PRIVATE int myGetChar NOARGS
 }
 
 PUBLIC int LYgetch_for ARGS1(
-	int, 	code)
+	int,	code)
 {
    SLang_Key_Type *key;
    int keysym;
@@ -1371,7 +1382,7 @@ PUBLIC int LYgetch_for ARGS1(
 #define found_CSI(first,second) ((second) == '[' || (first) == 155)
 
 PUBLIC int LYgetch_for ARGS1(
-	int, 	code)
+	int,	code)
 {
     int a, b, c, d = -1;
     int current_modifier = 0;
@@ -1644,7 +1655,7 @@ re_read:
 	case KEY_LEFT:
 	   c = LTARROW;
 	   break;
-	case KEY_RIGHT: 	   /* ... */
+	case KEY_RIGHT:		   /* ... */
 	   c = RTARROW;
 	   break;
 #if defined(SH_EX) && defined(DOSPATH)	/* for NEC PC-9800 1998/08/30 (Sun) 21:50:35 */
@@ -1660,23 +1671,23 @@ re_read:
 	case KEY_B3:
 	   c = RTARROW;
 	   break;
-	case PAD0:	 	   /* PC-9800 Ins */
+	case PAD0:		   /* PC-9800 Ins */
 	   c = INSERT_KEY;
 	   break;
-	case PADSTOP:	   	   /* PC-9800 DEL */
+	case PADSTOP:		   /* PC-9800 DEL */
 	   c = REMOVE_KEY;
 	   break;
 #endif /* SH_EX */
 	case KEY_HOME:		   /* Home key (upward+left arrow) */
 	   c = HOME;
 	   break;
-	case KEY_CLEAR: 	   /* Clear screen */
+	case KEY_CLEAR:		   /* Clear screen */
 	   c = 18; /* CTRL-R */
 	   break;
-	case KEY_NPAGE: 	   /* Next page */
+	case KEY_NPAGE:		   /* Next page */
 	   c = PGDOWN;
 	   break;
-	case KEY_PPAGE: 	   /* Previous page */
+	case KEY_PPAGE:		   /* Previous page */
 	   c = PGUP;
 	   break;
 	case KEY_LL:		   /* home down or bottom (lower left) */
@@ -2028,7 +2039,7 @@ re_read:
 	case K_ELeft:
 	   c = LTARROW;
 	   break;
-	case K_Right: 		   /* ... */
+	case K_Right:		   /* ... */
 	case K_ERight:
 	   c = RTARROW;
 	   break;
@@ -2036,11 +2047,11 @@ re_read:
 	case K_EHome:
 	   c = HOME;
 	   break;
-	case K_PageDown: 	   /* Next page */
+	case K_PageDown:	   /* Next page */
 	case K_EPageDown:
 	   c = PGDOWN;
 	   break;
-	case K_PageUp:	 	   /* Previous page */
+	case K_PageUp:		   /* Previous page */
 	case K_EPageUp:
 	   c = PGUP;
 	   break;
@@ -2086,18 +2097,18 @@ re_read:
 	case SL_KEY_LEFT:
 	   c = LTARROW;
 	   break;
-	case SL_KEY_RIGHT: 	   /* ... */
+	case SL_KEY_RIGHT:	   /* ... */
 	   c = RTARROW;
 	   break;
 	case SL_KEY_HOME:	   /* Home key (upward+left arrow) */
 	case SL_KEY_A1:		   /* upper left of keypad */
 	   c = HOME;
 	   break;
-	case SL_KEY_NPAGE: 	   /* Next page */
+	case SL_KEY_NPAGE:	   /* Next page */
 	case SL_KEY_C3:		   /* lower right of keypad */
 	   c = PGDOWN;
 	   break;
-	case SL_KEY_PPAGE: 	   /* Previous page */
+	case SL_KEY_PPAGE:	   /* Previous page */
 	case SL_KEY_A3:		   /* upper right of keypad */
 	   c = PGUP;
 	   break;
@@ -2193,7 +2204,7 @@ PUBLIC void LYUpperCase ARGS1(
  * Remove ALL whitespace from a string (including embedded blanks).
  */
 PUBLIC void LYRemoveBlanks ARGS1(
-	char *, 	buffer)
+	char *,		buffer)
 {
     if (buffer != 0) {
 	size_t i, j;
@@ -2208,7 +2219,7 @@ PUBLIC void LYRemoveBlanks ARGS1(
  * Skip whitespace
  */
 PUBLIC char * LYSkipBlanks ARGS1(
-	char *, 	buffer)
+	char *,		buffer)
 {
     while (isspace((unsigned char)(*buffer)))
 	buffer++;
@@ -2219,7 +2230,7 @@ PUBLIC char * LYSkipBlanks ARGS1(
  * Skip non-whitespace
  */
 PUBLIC char * LYSkipNonBlanks ARGS1(
-	char *, 	buffer)
+	char *,		buffer)
 {
     while (*buffer != 0 && !isspace((unsigned char)(*buffer)))
 	buffer++;
@@ -2252,7 +2263,7 @@ PUBLIC CONST char * LYSkipCNonBlanks ARGS1(
  * Trim leading blanks from a string
  */
 PUBLIC void LYTrimLeading ARGS1(
-	char *, 	buffer)
+	char *,		buffer)
 {
     char *skipped = LYSkipBlanks(buffer);
     while ((*buffer++ = *skipped++) != 0)
@@ -2263,7 +2274,7 @@ PUBLIC void LYTrimLeading ARGS1(
  * Trim trailing blanks from a string
  */
 PUBLIC void LYTrimTrailing ARGS1(
-	char *, 	buffer)
+	char *,		buffer)
 {
     size_t i = strlen(buffer);
     while (i != 0 && isspace((unsigned char)buffer[i-1]))
@@ -2320,7 +2331,7 @@ PRIVATE char killbuffer[1024] = "\0";
 
 PUBLIC void LYSetupEdit ARGS4(
 	EDREC *,	edit,
-	char *, 	old,
+	char *,		old,
 	int,		maxstr,
 	int,		maxdsp)
 {
@@ -3015,9 +3026,9 @@ PUBLIC void LYRefreshEdit ARGS1(
 #define CurModif MyEdit.current_modifiers
 
 PUBLIC int LYgetstr ARGS4(
-	char *, 	inputline,
+	char *,		inputline,
 	int,		hidden,
-	size_t, 	bufsize,
+	size_t,		bufsize,
 	int,		recall)
 {
     int x, y, MaxStringSize;
@@ -3280,8 +3291,8 @@ PUBLIC char *LYstrsep ARGS2(
  *  It is a case insensitive search.
  */
 PUBLIC char * LYstrstr ARGS2(
-	char *, 	chptr,
-	CONST char *, 	tarptr)
+	char *,		chptr,
+	CONST char *,	tarptr)
 {
     int len = strlen(tarptr);
 
@@ -3307,8 +3318,8 @@ PUBLIC char * LYstrstr ARGS2(
  *  It is a case insensitive search.
  */
 PUBLIC char * LYno_attr_char_case_strstr ARGS2(
-	char *, 	chptr,
-	char *, 	tarptr)
+	char *,		chptr,
+	char *,		tarptr)
 {
     register char *tmpchptr, *tmptarptr;
 
@@ -3418,8 +3429,8 @@ PRIVATE int LYAddToCloset ARGS1(char*, str)
  *  It is a case sensitive search.
  */
 PUBLIC char * LYno_attr_char_strstr ARGS2(
-	char *, 	chptr,
-	char *, 	tarptr)
+	char *,		chptr,
+	char *,		tarptr)
 {
     register char *tmpchptr, *tmptarptr;
 
@@ -3476,13 +3487,14 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(
  *  It is a case insensitive search. - KW & FM
  */
 PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
-	char *, 	chptr,
-	char *, 	tarptr,
+	char *,		chptr,
+	CONST char *,	tarptr,
 	BOOL,		utf_flag,
 	int *,		nstartp,
 	int *,		nendp)
 {
-    register char *tmpchptr, *tmptarptr;
+    char *tmpchptr;
+    CONST char *tmptarptr;
     int len = 0;
     int offset;
 
@@ -3518,9 +3530,9 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 		/*
 		 *  One char target.
 		 */
-		*nstartp = offset;
-		*nendp = len;
-		 return(chptr);
+		if (nstartp)	*nstartp = offset;
+		if (nendp)	*nendp = len;
+		return(chptr);
 	    }
 	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
 		 *chptr == *tarptr &&
@@ -3539,8 +3551,8 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 			/*
 			 *  One character match. - FM
 			 */
-			*nstartp = offset;
-			*nendp = len + tarlen;
+			if (nstartp)	*nstartp = offset;
+			if (nendp)	*nendp = len + tarlen;
 			return(chptr);
 		    }
 		    tarlen++;
@@ -3557,7 +3569,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 	     *	See if the rest of the target matches. - FM
 	     */
 	    while (1) {
-		 if (!IsSpecialAttrChar(*tmpchptr)) {
+		if (!IsSpecialAttrChar(*tmpchptr)) {
 		    if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) {
 			if (*tmpchptr == *tmptarptr &&
 			    *(tmpchptr + 1) == *(tmptarptr + 1) &&
@@ -3565,7 +3577,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 			    tmpchptr++;
 			    tmptarptr++;
 			} else {
-			break;
+			    break;
 			}
 		    } else if (0 != UPPER8(*tmpchptr, *tmptarptr)) {
 			break;
@@ -3577,18 +3589,17 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 		    tmpchptr++;
 		    tmptarptr++;
 
-		 } else {
+		} else {
 		    tmpchptr++;
-		 }
+		}
 
-		 if (*tmptarptr == '\0') {
-		    *nstartp = offset;
-		     *nendp = len + tarlen;
-		     return(chptr);
-		 }
-		if (*tmpchptr == '\0') {
-		     break;
-	    }
+		if (*tmptarptr == '\0') {
+		    if (nstartp)	*nstartp = offset;
+		    if (nendp)		*nendp = len + tarlen;
+		    return(chptr);
+		}
+		if (*tmpchptr == '\0')
+		    break;
 	    }
 	} else if (!(IS_UTF_EXTRA(*chptr) ||
 		      IsSpecialAttrChar(*chptr))) {
@@ -3615,19 +3626,20 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
  *			      LY_UNDERLINE_END_CHAR
  *			      LY_BOLD_START_CHAR
  *			      LY_BOLD_END_CHAR
- *				LY_SOFT_HYPHEN
+ *			      LY_SOFT_HYPHEN
  *			      if present in chptr.
  * It assumes UTF8 if utf_flag is set.
  *  It is a case sensitive search. - KW & FM
  */
 PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
-	char *, 	chptr,
-	char *, 	tarptr,
+	char *,		chptr,
+	CONST char *,	tarptr,
 	BOOL,		utf_flag,
 	int *,		nstartp,
 	int *,		nendp)
 {
-    register char *tmpchptr, *tmptarptr;
+    char *tmpchptr;
+    CONST char *tmptarptr;
     int len = 0;
     int offset;
 
@@ -3659,9 +3671,9 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 		/*
 		 *  One char target.
 		 */
-		*nstartp = offset;
-		*nendp = len + 1;
-		 return(chptr);
+		if (nstartp)	*nstartp = offset;
+		if (nendp)	*nendp = len + 1;
+		return(chptr);
 	    }
 	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
 		 *tmpchptr != '\0' &&
@@ -3679,8 +3691,8 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 			/*
 			 *  One character match. - FM
 			 */
-			*nstartp = offset;
-			*nendp = len + tarlen;
+			if (nstartp)	*nstartp = offset;
+			if (nendp)	*nendp = len + tarlen;
 			return(chptr);
 		    }
 		    tarlen++;
@@ -3721,14 +3733,13 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 		 }
 
 		 if (*tmptarptr == '\0') {
-		    *nstartp = offset;
-		     *nendp = len + tarlen;
+		     if (nstartp)	*nstartp = offset;
+		     if (nendp)		*nendp = len + tarlen;
 		     return(chptr);
 		 }
-		if (*tmpchptr == '\0') {
+		if (*tmpchptr == '\0')
 		     break;
 	    }
-	    }
 	} else if (!(IS_UTF_EXTRA(*chptr) ||
 		      IsSpecialAttrChar(*chptr))) {
 	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
@@ -3781,11 +3792,11 @@ PUBLIC char * SNACat ARGS3(
 	    strncpy(*dest + length, src, n);
 	    *(*dest + length + n) = '\0'; /* terminate */
 	} else {
-	    *dest = (char *)calloc(1, strlen(src) + 1);
+	    *dest = (char *)calloc(1, n + 1);
 	    if (*dest == NULL)
 		outofmem(__FILE__, "SNACat");
-	    strncpy(*dest, src, n);
-	    *dest[n] = '\0'; /* terminate */
+	    memcpy(*dest, src, n);
+	    (*dest)[n] = '\0'; /* terminate */
 	}
     }
     return *dest;
@@ -3845,6 +3856,13 @@ PRIVATE long UniToLowerCase ARGS1(long, upper)
 */
 PUBLIC int UPPER8 ARGS2(int,ch1, int,ch2)
 {
+    /* if they are the same or one is a null characters return immediately. */
+    if (ch1 == ch2)
+	return 0;
+    if (!ch2)
+	return (unsigned char)ch1;
+    else if (!ch1)
+	return -(unsigned char)ch2;
 
     /* case-insensitive match for us-ascii */
     if ((unsigned char)TOASCII(ch1) < 128 && (unsigned char)TOASCII(ch2) < 128)
@@ -3858,9 +3876,12 @@ PUBLIC int UPPER8 ARGS2(int,ch1, int,ch2)
 	   return(TOUPPER(ch1) - TOUPPER(ch2)); /* old-style */
 	else
 	{
-	long uni_ch1 = UCTransToUni(ch1, current_char_set);
-	long uni_ch2 = UCTransToUni(ch2, current_char_set);
-	return(UniToLowerCase(uni_ch1) - UniToLowerCase(uni_ch2));
+	    long uni_ch2 = UCTransToUni(ch2, current_char_set);
+	    long uni_ch1;
+	    if (uni_ch2 < 0)
+		return (unsigned char)ch1;
+	    uni_ch1 = UCTransToUni(ch1, current_char_set);
+	    return(UniToLowerCase(uni_ch1) - UniToLowerCase(uni_ch2));
 	}
     }
 
diff --git a/src/LYStrings.h b/src/LYStrings.h
index 550c4096..e836c6a4 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -47,13 +47,13 @@ extern int LYmbcsstrlen PARAMS((
 	BOOL		utf_flag));
 extern char * LYno_attr_mbcs_strstr PARAMS((
 	char *		chptr,
-	char *		tarptr,
+	CONST char *	tarptr,
 	BOOL		utf_flag,
 	int *		nstartp,
 	int *		nendp));
 extern char * LYno_attr_mbcs_case_strstr PARAMS((
 	char *		chptr,
-	char *		tarptr,
+	CONST char *	tarptr,
 	BOOL		utf_flag,
 	int *		nstartp,
 	int *		nendp));
diff --git a/src/LYUtils.c b/src/LYUtils.c
index a48994fa..4d30777d 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -127,15 +127,17 @@ PUBLIC void highlight ARGS3(
     char buffer[200];
     int i;
     char tmp[7];
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#ifdef SHOW_WHEREIS_TARGETS
     char *cp;
     char *theData = NULL;
     char *Data = NULL;
     int Offset, HitOffset, tLen;
     int LenNeeded;
     BOOL TargetEmphasisON = FALSE;
+    BOOL target1_drawn = NO;
 #endif
     BOOL utf_flag = (BOOL)(LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8);
+    BOOL hl1_drawn = NO;
 #if defined(USE_COLOR_STYLE) && !defined(NO_HILIT_FIX)
     BOOL hl2_drawn=FALSE;	/* whether links[cur].hightext2 is already drawn
 				   properly */
@@ -165,10 +167,22 @@ PUBLIC void highlight ARGS3(
 #define LXP (links[cur].lx)
 #define LYP (links[cur].ly)
 #endif
-	move(links[cur].ly, links[cur].lx);
 #ifndef USE_COLOR_STYLE
-	lynx_start_link_color (flag == ON, links[cur].inUnderline);
+	if (links[cur].type == WWW_FORM_LINK_TYPE ||
+	    !links[cur].hightext) {
+	    LYMoveToLink(cur, target, NULL,
+			 flag, links[cur].inUnderline, utf_flag);
+	    lynx_start_link_color (flag == ON, links[cur].inUnderline);
+	} else {
+	    LYMoveToLink(cur, target, links[cur].hightext,
+			 flag, links[cur].inUnderline, utf_flag);
+	    hl1_drawn = YES;
+#ifdef SHOW_WHEREIS_TARGETS
+	    target1_drawn = YES;
+#endif
+	}
 #else
+	move(links[cur].ly, links[cur].lx);
 	if (flag == ON) {
 	    LynxChangeStyle(s_alink, STACK_ON, 0);
 	} else {
@@ -227,18 +241,18 @@ PUBLIC void highlight ARGS3(
 		redraw_lines_of_link(cur);
 	    } else
 #endif
-	    {
+	    if (!hl1_drawn) {
 	    /*
 	     *	Copy into the buffer only what will fit
 	     *	within the width of the screen.
 	     */
-	    LYmbcsstrncpy(buffer,
-			  (links[cur].hightext ?
-			   links[cur].hightext : ""),
-			  (sizeof(buffer) - 1),
-			  ((LYcols - 1) - links[cur].lx),
-			  utf_flag);
-	    addstr(buffer);
+		LYmbcsstrncpy(buffer,
+			      (links[cur].hightext ?
+			       links[cur].hightext : ""),
+			      (sizeof(buffer) - 1),
+			      ((LYcols - 1) - links[cur].lx),
+			      utf_flag);
+		addstr(buffer);
 	    }
 	}
 
@@ -279,7 +293,8 @@ PUBLIC void highlight ARGS3(
 #endif
 	lynx_stop_link_color (flag == ON, links[cur].inUnderline);
 
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#ifdef SHOW_WHEREIS_TARGETS
+	if (!target1_drawn)
 	/*
 	 *  If we have an emphasized WHEREIS hit in the highlighted
 	 *  text, restore the emphasis.  Note that we never emphasize
@@ -1759,7 +1774,7 @@ highlight_search_done:
 	     */
 	    LYHideCursor();
 	else
-#endif /* FANCY CURSES || USE_SLANG */
+#endif /* SHOW_WHEREIS_TARGETS */
 	    /*
 	     *	Never hide the cursor if there's no FANCY CURSES or SLANG.
 	     */
@@ -1893,12 +1908,21 @@ PUBLIC void statusline ARGS1(
 	if (p)
 	    p= '\0';
     }
+#if 0
+    /* This is broken.  It shows a truncated name if the complete URL is
+       so long that it has already been shortened by the caller to fit.
+       Moreover it doesn't belong here.  This function should just display
+       what it's asked to and not second-guess its caller.  If you want
+       a different message displayed, pass it a different message.
+       Finally, I dislike the intended change anyway.  It shows less
+       information, it is a dumbed down interface. - kw */
     if (strncmp(text, "LYNXDOWNLOAD:", 13) == 0) {
 	p = strstr(text + 13, "SugFile=");
 	if (p != NULL) {
 	    strcpy(text_buff, p + 3);
 	}
     }
+#endif
 
     /*
      *	Deal with any CJK escape sequences and Kanji if we have a CJK
@@ -3240,7 +3264,13 @@ PUBLIC void size_change ARGS1(
     LYcols  = SLtt_Screen_Cols;
 #ifdef SLANG_MBCS_HACK
     PHYSICAL_SLtt_Screen_Cols = LYcols;
-    SLtt_Screen_Cols = (LYcols * 6);
+#ifdef SLANG_NO_LIMIT		/* define this if slang has been fixed */
+    SLtt_Screen_Cols = (LYcols-1) * 6;
+#else
+    /* Needs to be limited: fixed buffer bugs in slang can cause crash,
+       see slang's SLtt_smart_puts - kw */
+    SLtt_Screen_Cols = HTMIN((LYcols-1) * 6, 255);
+#endif
 #endif /* SLANG_MBCS_HACK */
     if (sig == 0)
 	/*
@@ -7617,9 +7647,9 @@ PUBLIC void LYSyslog ARGS1(
 	    CTRACE((tfp, "...alter %s\n", buf));
 	    FREE(buf);
 	    return;
-        }
+	}
     }
-    syslog (LOG_INFO|LOG_LOCAL5, arg);
+    syslog (LOG_INFO|LOG_LOCAL5, "%s", arg ? arg : "(null-URL)");
 }
 
 PUBLIC void LYCloselog NOARGS
diff --git a/src/TRSTable.c b/src/TRSTable.c
new file mode 100644
index 00000000..3545fdb8
--- /dev/null
+++ b/src/TRSTable.c
@@ -0,0 +1,1335 @@
+/*		Simple table object
+**		===================
+** Authors
+**	KW	Klaus Weide <kweide@enteract.com>
+** History:
+**   2 Jul 1999	KW	Created.
+*/
+
+#include <HTUtils.h>
+#include <HTStyle.h>		/* for HT_LEFT, HT_CENTER, HT_RIGHT */
+#include <LYCurses.h>
+#include <TRSTable.h>
+
+#include <LYLeaks.h>
+
+#define CELLS_GROWBY 2
+#define ROWS_GROWBY 2
+#define MAX_STBL_POS (LYcols-1)
+
+typedef enum {
+    CS_invalid = -1,
+    CS_new     =  0,
+    CS__0,			/* new, at BOL */
+    CS__0eb,			/* starts at BOL, empty, break */
+    CS__eb,			/* empty, break */
+    CS__0cb,			/* starts at BOL, content, break */
+    CS__cb,			/* content, break */
+    CS__0f,			/* starts at BOL, finished */
+    CS__ef,			/* empty, finished */
+    CS__0cf,			/* starts at BOL, content, finished */
+    CS__cf,			/* content, finished */
+    CS__ebc,			/* empty, break, more content */
+    CS__cbc			/* content, break, more content */
+} cellstate_t;
+
+typedef struct _STable_states {
+    cellstate_t	prev_state;
+    cellstate_t	state;
+    int		lineno;		/* last line no. looked at */
+    int		icell_core;	/* first/best 'core' cell in row so far */
+    int		x_td;		/* x pos of currently open cell or -1 */
+    int		pending_len;	/* if state is CS__0?[ec]b (??) */
+} STable_states;
+
+
+typedef struct _STable_cellinfo {
+	int	Line;		/* lineno in doc (zero-based) */
+	int	pos;		/* column where cell starts */
+	int	len;		/* number of character positions */
+	int	colspan;	/* number of columns to span */
+	short	alignment;	/* one of HT_LEFT, HT_CENTER, HT_RIGHT */
+} STable_cellinfo;
+
+typedef struct _STable_rowinfo {
+	int	Line;		/* lineno in doc (zero-based) */
+	int	ncells;		/* number of table cells */
+/*	int	pending_skip;*/	/* skip this many after finishing open cell */
+	BOOL	fixed_line;	/* if we have a 'core' line of cells */
+	int	allocated;	/* number of table cells allocated */
+	STable_cellinfo * cells;
+	short	alignment;	/* global align attribute for this row */
+} STable_rowinfo;
+
+struct _STable_info {
+	int	startline;	/* lineno where table starts (zero-based) */
+	int	nrows;		/* number of rows */
+	int	ncols;		/* number of rows */
+	int	maxlen;		/* sum of max. cell lengths of any row */
+	int	maxpos;		/* max. of max. cell pos's of any row */
+	int	allocated_rows; /* number of rows allocated */
+	int	allocated_sumcols;	/* number of sumcols allocated */
+	STable_cellinfo * sumcols; /* for summary (max len/pos) col info */
+	STable_rowinfo * rows;
+	short	alignment;	/* global align attribute for this table */
+	STable_states s;
+};
+
+/*
+**  Functions and structures in this source file keep track of positions.
+**  They don't know about the character data in those lines, or about
+**  the HText and HTLine structures.  GridText.c doesn't know about our
+**  structures.  It should stay that way.
+**
+**  The basic idea: we let the code in HTML.c/GridText.c produce and format
+**  output "as usual", i.e. as without Simple Table support.  We keep track
+**  of the positions in the generated output where cells and rows start (or
+**  end).  If all goes well, that preliminary output (stored in HText/HTLine
+**  structures) can be fixed up when the TABLE end tag is processed, by just
+**  inserting spaces in the right places (and possibly changing alignment).
+**  If all goes not well, we already have a safe fallback.
+**
+**  Note that positions passed to and from these functions should be
+**  in terms of screen positions, not just byte counts in a HTLine.data
+**  (cf. line->data vs. HText_TrueLineSize).
+**
+**  Memory is allocated dynamically, so we can have tables of arbitrary
+**  length.  On allocation error we just return and error indication
+**  instead of outofmem(), so caller can give up table tracking and maybe
+**  recover memory.
+**
+**  Implemented:
+**  - ALIGN={left,right,center,justify} applied to individual table cells
+**    ("justify" is treated as "left")
+**  - Inheritance of horizontal alignment according to HTML 4.0 (with the
+**    exception of COLGROUP/COL)
+**  - COLSPAN >1 (nearly untested)
+**  - Line breaks at start of first cell or at end of last cell are treated
+**    as if they were not part of the cell and row.  This allows us to
+**    cooperate with one way in which tables have been made friendly to
+**    browsers without any table support.
+**  Missing, but can be added:
+**  - Support for COLGROUP/COL
+**  - ROWSPAN >1 (reserving cells in following rows)
+**  - Tables wider than display.  The limitation is not here but in GridText.c
+**    etc.  If horizontal scrolling were implemented there, the mechanisms
+**    here coudl deal with wide tables (just change MAX_STBL_POS code).
+**  Missing, unlikely to add:
+**  - Support for non-LTR directionality.  A general problem, support is
+**    lacking throughout the lynx code.
+**  - Support for most other table-related attributes.  Most of them are
+**    for decorative purposes.
+**  Impossible or very unlikely (because it doesn't fit the model):
+**  - Any cell contents of more than one line, line breaks within cells.
+**    Anything that requires handling cell contents as paragraphs (block
+**    elements), like reflowing.  Vertical alignment.
+*/
+PRIVATE int Stbl_finishCellInRow PARAMS((
+    STable_rowinfo *	me,
+    STable_states *	s,
+    BOOL		certain,
+    int			lineno,
+    int			pos));
+PRIVATE int Stbl_finishRowInTable PARAMS((
+    STable_info *	me));
+
+
+PUBLIC struct _STable_info * Stbl_startTABLE ARGS1(
+    short,		alignment)
+{
+    STable_info *me = (STable_info *) calloc(1, sizeof(STable_info));
+    if (me) {
+	me->alignment = alignment;
+	me->s.x_td = -1;
+	me->s.icell_core = -1;
+    }
+    return me;
+}
+
+PRIVATE void free_rowinfo ARGS1(
+    STable_rowinfo *,	me)
+{
+    if (me && me->allocated) {
+	FREE(me->cells);
+    }
+}
+
+PUBLIC void Stbl_free ARGS1(
+    STable_info *,	me)
+{
+    if (me && me->allocated_rows && me->rows) {
+	int i;
+	for (i = 0; i <= me->nrows; i++)
+	    free_rowinfo(me->rows + i);
+	free(me->rows);
+    }
+    if (me)
+	FREE(me->sumcols);
+    FREE(me);
+}
+
+/*
+ * Returns -1 on error, otherwise index of just-added table cell.
+ */
+PRIVATE int Stbl_addCellToRow ARGS7(
+    STable_rowinfo *,	me,
+    STable_states *,	s,
+    int,		colspan,
+    short,		alignment,
+    BOOL,		isheader,
+    int,		lineno,
+    int *,		ppos)
+{
+    STable_cellinfo *cells;
+    int i;
+    int last_colspan = me->ncells ?
+	me->cells[me->ncells - 1].colspan : 1;
+    cellstate_t newstate;
+
+    if (me->ncells == 0)
+	s->prev_state = CS_invalid;
+    else if (s->prev_state == CS_invalid ||
+	     (/*s->state != CS_new && */ s->state != CS__0 &&
+	      s->state != CS__ef && s->state != CS__0f))
+	s->prev_state = s->state;
+
+    if (me->ncells == 0 || *ppos == 0)
+	newstate = CS__0;
+    else
+	newstate = CS_new;
+
+    if (me->ncells > 0 && s->pending_len > 0) {
+	if (s->prev_state != CS__cbc)
+	    me->cells[me->ncells - 1].len = s->pending_len;
+	s->pending_len = 0;
+    }
+    s->x_td = *ppos;
+
+    if (lineno != s->lineno) {
+	if (!me->fixed_line) {
+	    if (me->ncells == 0 || *ppos == 0) {
+		switch (s->prev_state) {
+		case CS_invalid:
+		case CS__0:
+		case CS__0eb:
+		case CS__0cb:
+		case CS__0f:
+		case CS__0cf:
+		    if (me->ncells > 0)
+			for (i = me->ncells + last_colspan - 2;
+			     i >= me->ncells - 1; i--) {
+			    me->cells[i].pos = *ppos;
+			    me->cells[i].Line = lineno;
+			}
+		    me->Line = lineno;
+		    /* s->lineno = lineno; */
+		    break;
+		case CS_new:
+		case CS__eb:
+		case CS__ef:
+		case CS__cf:
+		default:
+		    break;
+		case CS__cb:
+		    *ppos = me->cells[me->ncells - 1].pos +
+			me->cells[me->ncells - 1].len;
+		}
+	    } else {
+		switch (s->prev_state) {
+		case CS__0:
+		case CS__0eb:
+		case CS__0f:
+		    break;
+		case CS__cb:
+		    return -1;
+		case CS__cf:
+/*		    HTAlert("foo woo!!"); */
+		    return -1;
+		case CS__0cb:
+		case CS__0cf:
+		    if (*ppos > me->cells[0].pos)
+			me->Line = lineno;
+		    me->fixed_line = YES;
+		    break;
+		case CS_new:
+		case CS__eb:
+		case CS__ef:
+		default:
+		    me->fixed_line = YES;
+		    break;
+		case CS__cbc:
+		    return -1;
+		}
+	    }
+	}
+	if (me->fixed_line && lineno != me->Line) {
+	    switch (s->prev_state) {
+	    case CS__cb:
+	    case CS__cf:
+		if (*ppos > 0)
+		    return -1;
+		else
+		    *ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
+			me->cells[me->ncells - 1].len;
+		break;
+	    case CS__0cf:
+	    case CS__0cb:
+		if (*ppos == 0 || *ppos <= me->cells[0].pos)
+		    *ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
+			me->cells[me->ncells - 1].len;
+		break;
+	    case CS__0:
+	    case CS__0f:
+	    case CS__0eb:
+/*		me->Line = lineno; */
+		break;
+	    case CS_new:
+	    case CS__eb:
+	    case CS__ef:
+	    default:
+		*ppos = me->cells[me->ncells - 1].pos;	break;
+	    case CS__cbc:
+/*		*ppos = me->cells[me->ncells - 1].pos +
+		    me->cells[me->ncells - 1].len;
+		if (*ppos > 0)
+		    return -1; */
+		break;
+	    case CS_invalid:
+		break;
+	    }
+	}
+	s->lineno = lineno;
+    } else {			/* lineno == s->lineno: */
+	switch (s->prev_state) {
+	case CS_invalid:
+	case CS__0:
+	case CS__0eb:		/* cannot happen */
+	case CS__0cb:		/* cannot happen */
+	case CS__0f:
+	case CS__0cf:		/* ##302?? set icell_core? or only in finish? */
+	    break;
+	case CS__eb:		/* cannot happen */
+	case CS__cb:		/* cannot happen */
+	case CS__ef:
+	    break;
+	case CS__ebc:		/* should have done smth in finish */
+	case CS__cbc:		/* should have done smth in finish */
+	    break;
+	case CS_new:
+	case CS__cf:
+	    if (me->fixed_line && me->Line != lineno) {
+		return -1;
+	    } else {
+		me->fixed_line = YES;
+		me->Line = lineno;
+	    }
+	}
+    }
+
+#if 0				/* MEGA_COMMENTOUT */
+    if (lineno != me->Line) {
+	if (!me->fixed_line) {
+	    if (me->ncells == 0 ||
+		(*ppos == 0 && me->cells[me->ncells - 1].pos == 0)) {
+		if (me->ncells > 0)
+		    for (i = me->ncells + last_colspan - 2;
+			 i >= 0; i--) {
+			me->cells[i].pos = *ppos;
+			me->cells[i].Line = lineno;
+		    }
+		me->Line = lineno;
+		s->state = CS__0;
+	    }
+	    if (*ppos > 0 && me->ncells > 0 &&
+		(me->cells[me->ncells - 1].pos > 0 ||
+		 me->cells[me->ncells - 1].len > 0)) {
+		me->fixed_line = YES;
+
+	    }
+	}
+	if (me->fixed_line && lineno != me->Line) {
+	    if (me->cells[me->ncells - 1].pos > 0 &&
+		me->cells[me->ncells - 1].len > 0) {
+		return -1;
+	    } else if (me->cells[me->ncells - 1].pos == 0 &&
+		       me->cells[me->ncells - 1].len > 0) {
+		if (*ppos > 0 && *ppos > me->cells[0].pos)
+		    me->Line = lineno;
+		else
+		    *ppos = me->cells[me->ncells - 1].pos; /* == 0 */
+	    } else /* if (me->cells[me->ncells - 1].pos == 0 &&
+		       me->cells[me->ncells - 1].len <= 0) {
+		me->Line = lineno;
+	    } else */ {
+		*ppos = me->cells[me->ncells - 1].pos;
+	    }
+	}
+#if 0
+	for (i = 0; i < me->ncells; i++) {
+	    if (me->cells[i].Line == lineno) {
+		break;
+	    } else if (me->cells[i].len <= 0) {
+		me->cells[i].Line = lineno;
+		/* @@@ reset its pos too ?? */
+	    } else {
+		break;
+	    }
+	}
+	if (i < me->ncells && me->cells[i].Line != lineno)
+	    return -1;
+	me->Line = lineno;
+#endif
+    }
+#endif /* MEGA_COMMENTOUT */
+    s->state = newstate;
+
+    if (me->ncells > 0 && me->cells[me->ncells - 1].colspan > 1) {
+	me->ncells += me->cells[me->ncells-1].colspan - 1;
+    }
+    {
+	int growby = 0;
+	while (me->ncells + colspan + 1 > me->allocated + growby)
+	    growby += CELLS_GROWBY;
+	if (growby) {
+	    if (me->allocated == 0 && !me->cells) {
+		cells = calloc(growby, sizeof(STable_cellinfo));
+	    } else {
+		cells = realloc(me->cells,
+				  (me->allocated + growby)
+				  * sizeof(STable_cellinfo));
+	    }
+	    if (cells) {
+		me->allocated += growby;
+		me->cells = cells;
+	    } else {
+		return -1;
+	    }
+	}
+    }
+
+    me->cells[me->ncells].Line = lineno;
+    me->cells[me->ncells].pos = *ppos;
+    me->cells[me->ncells].len = -1;
+    me->cells[me->ncells].colspan = colspan;
+    me->cells[me->ncells].alignment =
+	(alignment==HT_ALIGN_NONE) ? me->alignment : alignment;
+    if (me->cells[me->ncells].alignment==HT_ALIGN_NONE)
+	me->cells[me->ncells].alignment = isheader ? HT_CENTER : HT_LEFT;
+    for (i = me->ncells + 1; i < me->ncells + colspan; i++) {
+	me->cells[i].Line = lineno;
+	me->cells[i].pos = *ppos;
+	me->cells[i].len = -1;
+	me->cells[i].colspan = 0;
+	me->cells[i].alignment = HT_LEFT;
+    }
+    me->cells[me->ncells + colspan].pos = -1; /* not yet used */
+    me->ncells++;
+    return (me->ncells - 1);
+}
+
+PRIVATE int Stbl_finishCellInRow ARGS5(
+    STable_rowinfo *,	me,
+    STable_states *,	s,
+    BOOL,		certain,
+    int,		lineno,
+    int,		pos)
+{
+    STable_cellinfo *lastcell;
+    cellstate_t newstate = CS_invalid;
+    BOOL broken = NO, empty;
+
+    if (me->ncells <= 0)
+	return -1;
+    lastcell = me->cells + (me->ncells - 1);
+    broken = (lineno != lastcell->Line || lineno != s->lineno);
+    empty = broken ? (pos == 0) : (pos <= s->x_td);
+    if (broken) {
+	if (!certain) {
+	    switch (s->state) {
+	    case CS_invalid:
+		newstate = empty ? CS_invalid : CS__cbc;
+		break;
+	    case CS__0:
+		newstate = empty ? CS__0eb : CS__0cb;
+		break;
+	    case CS__0eb:
+		newstate = empty ? CS__0eb : CS__ebc;
+		s->state = newstate;
+		if (me->fixed_line) {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		} else {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : 0;
+		}
+		newstate = empty ? CS__0eb : CS__ebc;
+		break;
+	    case CS__0cb:
+		if (!me->fixed_line) {
+		    if (empty) { /* ##462_return_0 */
+/*			if (s->icell_core == -1)
+			    s->icell_core = lastcell->Line; */ /* we don't know yet */
+			/* lastcell->Line = lineno; */
+		    } else {	/* !empty */
+			if (s->icell_core == -1)
+			    me->Line = -1;
+		    }
+		}
+		if (s->pending_len && empty) { /* ##470_why_that?? */
+		    if ((me->fixed_line && me->Line == lastcell->Line) ||
+			s->icell_core == me->ncells - 1)
+			lastcell->len = s->pending_len;
+		    s->pending_len = 0;
+		} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
+		newstate = empty ? CS__0cb : CS__cbc; /* ##474_needs_len!=-1? */
+		break;
+	    case CS__0f:
+	    case CS__0cf:
+		break;
+	    case CS_new:
+		newstate = empty ? CS__eb : CS__cb;
+		break;
+	    case CS__eb:	/* ##484_set_pending_ret_0_if_empty? */
+		newstate = empty ? CS__eb : CS__ebc;
+		s->state = newstate;
+		if (me->fixed_line) {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		} else {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		}
+		newstate = empty ? CS__eb : CS__ebc;
+		break;
+	    case CS__cb:
+		if (s->pending_len && empty) { /* ##496: */
+		    lastcell->len = s->pending_len;
+		    s->pending_len = 0;
+		} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
+		if (empty) {
+		    if (!me->fixed_line) {
+			me->fixed_line = YES;
+			me->Line = lastcell->Line; /* should've happened in break */
+		    } else {
+			if (me->Line != lastcell->Line)
+			    return -1;
+		    }
+		} else {
+		    if (!me->fixed_line) {
+			me->fixed_line = YES;
+			me->Line = lastcell->Line; /* should've happened in break */
+		    }
+		    s->state = CS__cbc;
+		    return -1;
+		}
+		newstate = empty ? CS__cb : CS__cbc;
+		break;
+	    case CS__ef:
+		return 0;
+	    case CS__cf:
+		return lastcell->len; /* ##523_change_state? */
+	    case CS__cbc:
+		if (!me->fixed_line) {
+		    if (empty) {
+			if (s->icell_core == -1) /* ##528??: */
+			    me->Line = lineno;
+			/* lastcell->Line = lineno; */
+		    } else {	/* !empty */
+			if (s->icell_core == -1)
+			    me->Line = -1;
+		    }
+		}
+		s->pending_len = 0;
+		newstate = empty ? CS_invalid : CS__cbc;
+		break;
+	    default:
+		break;
+	    }
+	} else {		/* broken, certain: */
+	    s->x_td = -1;
+	    switch (s->state) {
+	    case CS_invalid:
+		/* ##540_return_-1_for_invalid_if_len!: */
+		if (!empty && lastcell->len > 0) {
+		    newstate = CS__0cf;
+		    s->state = newstate;
+		    return -1;
+		}
+				/* ##541_set_len_0_Line_-1_sometimes: */
+		lastcell->len = 0;
+		lastcell->Line = -1;
+		 /* fall thru ##546 really fall thru??: */
+		newstate = empty ? CS_invalid : CS__cbc;	break;
+	    case CS__0:
+		newstate = empty ? CS__0f  : CS__0cf;	break;
+	    case CS__0eb:
+		newstate = empty ? CS__0f  : CS__0cf;		/* ebc?? */
+		s->state = newstate;
+		if (me->fixed_line) {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		} else {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : 0;
+		}
+		newstate = empty ? CS__0f  : CS__0cf;	break; /* ebc?? */
+	    case CS__0cb:
+		if (s->pending_len) {
+		    if (empty)
+			lastcell->len = s->pending_len;
+		    else
+			lastcell->len = 0;
+		    s->pending_len = 0;
+		}
+		if (!me->fixed_line) {
+		    if (empty) {
+			if (s->icell_core == -1)
+			    s->icell_core = me->ncells - 1;
+			/* lastcell->Line = lineno; */
+		    } else {	/* !empty */
+			if (s->icell_core == -1)
+			    me->Line = -1;
+		    }
+		}
+		if (s->pending_len && empty) {
+		    lastcell->len = s->pending_len;
+		    s->pending_len = 0;
+		} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
+		newstate = empty ? CS__0cf : CS__cbc;	break;
+	    case CS__0f:
+		newstate = CS__0f;
+	    case CS__0cf:
+		break;
+	    case CS_new:
+		newstate = empty ? CS__ef  : CS__cf;	break;
+	    case CS__eb:
+		newstate = empty ? CS__ef  : CS__ef; /* ##579??? !!!!! */
+		s->state = newstate;
+		if (me->fixed_line) {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		} else {
+		    if (empty)
+			return lastcell->len <= 0 ? 0 : lastcell->len;
+		    else
+			return lastcell->len <= 0 ? 0 : -1;
+		}
+		newstate = empty ? CS__ef  : CS__ef;	break;
+	    case CS__cb:
+		if (s->pending_len && empty) {
+		    lastcell->len = s->pending_len;
+		    s->pending_len = 0;
+		}
+		if (empty) {
+		    if (!me->fixed_line) {
+			me->fixed_line = YES;
+			me->Line = lastcell->Line; /* should've happened in break */
+		    } else {
+			if (me->Line != lastcell->Line)
+			    return -1;
+		    }
+		} else {
+		    return -1;
+		}
+		newstate = empty ? CS__cf  : CS__cbc;	break;
+	    case CS__ef:		/* ignored error */
+	    case CS__cf:		/* ignored error */
+		break;
+	    case CS__ebc:	/* ##540_handle_ebc: */
+		lastcell->len = 0;
+		if (!me->fixed_line) {
+		    if (!empty) {
+			if (s->icell_core == -1)
+			    lastcell->Line = -1;
+		    }
+		}
+		s->pending_len = 0;
+		newstate = empty ? CS_invalid : CS__cbc;	break;
+	    case CS__cbc:	/* ##586 */
+		lastcell->len = 0; /* ##613 */
+		if (me->fixed_line && me->Line == lastcell->Line)
+		    return -1;
+		if (!me->fixed_line) {
+		    if (empty) {
+			if (s->icell_core == -1)
+			    me->Line = lineno;
+			/* lastcell->Line = lineno; */
+#if 0	/* ?? */
+		    } else {	/* !empty */
+			if (s->icell_core == -1)
+			    me->Line = -1;
+#endif
+		    }
+		}
+		s->pending_len = 0; /* ##629 v */
+		newstate = empty ? CS_invalid : CS__cbc;	break;
+	    }
+	}
+    } else {			/* (!broken) */
+	if (!certain) {
+	    switch (s->state) {
+	    case CS_invalid:
+	    case CS__0:
+		s->pending_len = empty ? 0 : pos - lastcell->pos;
+		newstate = empty ? CS__0eb : CS__0cb;
+		s->state = newstate;
+		return 0; /* or 0 for xlen to s->pending_len?? */
+	    case CS__0eb:	/* cannot happen */
+		newstate = CS__eb;
+	    case CS__0cb:	/* cannot happen */
+		newstate = CS__cb;			break;
+	    case CS__0f:
+	    case CS__0cf:
+		break;
+	    case CS_new:
+		if (!empty && s->prev_state == CS__cbc)	/* ##609: */
+		    return -1;
+		if (!empty) {
+		    if (!me->fixed_line) {
+			me->fixed_line = YES;
+			me->Line = lineno;
+		    } else {
+			if (me->Line != lineno)
+			    return -1;
+		    }
+		}
+		newstate = empty ? CS__eb : CS__cb;
+		s->state = newstate;
+		if (!me->fixed_line) {
+		    s->pending_len = empty ? 0 : pos - lastcell->pos;
+		    return 0;
+		} else {
+		    s->pending_len = 0;
+		    lastcell->len = empty ? 0 : pos - lastcell->pos;
+		    return lastcell->len;
+		}
+	    case CS__eb:	/* cannot happen */
+		newstate = empty ? CS__eb : CS__ebc;	break;
+	    case CS__cb:	/* cannot happen */
+		newstate = empty ? CS__cb : CS__cbc;	break;
+	    case CS__ef:
+		return 0;
+	    case CS__cf:
+		return lastcell->len;
+	    case CS__cbc:	/* ??? */
+		break;
+	    default:
+		break;
+	    }
+	} else {		/* !broken, certain: */
+	    s->x_td = -1;
+	    switch (s->state) {
+	    case CS_invalid:	/* ##691_no_lastcell_len_for_invalid: */
+		if (!(me->fixed_line && me->Line == lastcell->Line))
+		    lastcell->len = 0;
+	    case CS__0:
+		newstate = empty ? CS__0f  : CS__0cf;	break; /* ##630 */
+	    case CS__0eb:
+		newstate = empty ? CS__0f : CS__0f;	break; /* ??? */
+	    case CS__0cb:
+		newstate = empty ? CS__0cf : CS__cbc;	break; /* ??? */
+	    case CS__0f:
+		newstate = CS__0f;			break; /* ??? */
+	    case CS__0cf:
+		break;		/* ??? */
+	    case CS_new:
+		if (!empty && s->prev_state == CS__cbc)
+		    return -1;
+		if (!empty) { /* ##642_set_fixed!: */
+		    if (!me->fixed_line) {
+			me->fixed_line = YES;
+			me->Line = lineno;
+		    } else {
+			if (me->Line != lineno)
+			    return -1;
+		    }
+		}
+		if (lastcell->len < 0)
+		    lastcell->len = empty ? 0 : pos - lastcell->pos;
+		newstate = empty ? CS__ef  : CS__cf;
+		s->state = newstate;
+		return (me->fixed_line && lineno != me->Line) ? -1 : lastcell->len;
+	    case CS__eb:
+		newstate = empty ? CS__ef  : CS__cf;	break; /* ??? */
+	    case CS__cb:
+		newstate = empty ? CS__cf  : CS__cf;	break; /* ??? */
+	    case CS__ef:		/* ignored error */
+	    case CS__cf:		/* ignored error */
+	    default:
+		break;
+	    }
+	    lastcell->len = pos - lastcell->pos;
+	} /* if (!certain) ... else */
+    } /* if (broken) ... else */
+
+#if 0				/* MEGA_COMMENTOUT */
+    if (lineno != me->cells[0].Line) {
+#if 0
+	int i;
+	for (i = ncells - 1; i >= 0; i--) {
+	    if (!(me->cells[i].len == 0 || me->cells[i].colspan == 0))
+		break;
+	}
+#endif
+	if (lineno >= lastcell->Line) {
+	    if (me->fixed_line) {
+		if (pos == 0) {
+		    if (lastcell->len <= 0) {
+			return 0;
+		    } else {
+			return lastcell->len;
+		    }
+		} else {	/* pos != 0 */
+		    if (lastcell->len <= 0 && lineno > lastcell->Line && lastcell->Line <= me->Line) {
+			return 0;
+		    } else {
+			return -1;
+		    }
+		}
+	    } else {	/* not me->fixed_line */
+		if (pos == 0) {
+		    if (lastcell->len <= 0) {
+			return 0;
+		    } else {
+			return lastcell->len;
+		    }
+		} else {	/* pos != 0 */
+		    if (lastcell->len <= 0) {
+			return 0;
+		    } else {
+			if (me->ncells == 1 || lastcell->pos == 0) {
+			    return 0;
+			} else
+			    return -1;
+		    }
+		}
+	    }
+	}
+    }
+#endif /* MEGA_COMMENTOUT */
+    s->state = newstate;
+/*    lastcell->len = pos - lastcell->pos; */
+    return (lastcell->len);
+}
+
+/*
+ * Returns -1 on error, otherwise index of just-added table row.
+ */
+PUBLIC int Stbl_addRowToTable ARGS3(
+    STable_info *,	me,
+    short,		alignment,
+    int,		lineno)
+{
+    STable_rowinfo *rows, *row;
+    STable_states * s = &me->s;
+    if (me->nrows > 0 && me->rows[me->nrows-1].ncells > 0) {
+	if (s->pending_len > 0)
+	    me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len = s->pending_len;
+	s->pending_len = 0;
+/*	if (me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len >= 0 &&
+	    me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].Line == lineno)
+	    Stbl_finishCellInTable(me, YES,
+				   lineno,
+		me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].pos +
+		me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len); */
+    }
+#if 0
+    s->prev_state = s->state = CS_invalid;
+    s->lineno = -1;
+    s->icell_core = -1;
+#endif
+    Stbl_finishRowInTable(me);
+    if (me->nrows > 0 && me->rows[me->nrows-1].Line == lineno)
+	me->rows[me->nrows-1].Line = -1;
+    s->pending_len = 0;
+    s->x_td = -1;
+
+    {
+	int i;
+	int growby = 0;
+	while (me->nrows + 2 > me->allocated_rows + growby)
+	    growby += ROWS_GROWBY;
+	if (growby) {
+	    if (me->allocated_rows == 0 && !me->rows) {
+		rows = calloc(growby, sizeof(STable_rowinfo));
+	    } else {
+		rows = realloc(me->rows,
+				  (me->allocated_rows + growby)
+				  * sizeof(STable_rowinfo));
+		for (i = 0; rows && i < growby; i++) {
+		    row = rows + me->allocated_rows + i;
+		    row->allocated = 0;
+		    row->ncells = 0;
+		    row->fixed_line = NO;
+		    row->cells = NULL;
+		    row->alignment = HT_ALIGN_NONE;
+		}
+	    }
+	    if (rows) {
+		me->allocated_rows += growby;
+		me->rows = rows;
+	    } else {
+		return -1;
+	    }
+	}
+    }
+
+    me->rows[me->nrows].Line = lineno;
+    if (me->nrows == 0)
+	me->startline = lineno;
+    me->rows[me->nrows].alignment =
+	(alignment==HT_ALIGN_NONE) ? me->alignment : alignment;
+    me->nrows++;
+    me->rows[me->nrows].Line = -1; /* not yet used */
+    return (me->nrows - 1);
+}
+
+/*
+ * Returns -1 on error, otherwise current number of rows.
+ */
+PRIVATE int Stbl_finishRowInTable ARGS1(
+    STable_info *,	me)
+{
+    STable_rowinfo *lastrow;
+    STable_states * s = &me->s;
+    int ncells;
+    if (!me->rows || !me->nrows)
+	return -1;		/* no row started! */
+    lastrow = me->rows + (me->nrows - 1);
+    ncells = lastrow->ncells;
+    if (lastrow->ncells > 0) {
+	if (s->pending_len > 0)
+	    lastrow->cells[lastrow->ncells - 1].len = s->pending_len;
+	s->pending_len = 0;
+    }
+    s->prev_state = s->state = CS_invalid;
+    s->lineno = -1;
+
+#if 0
+    if (lastrow->Line == -1 && s->icell_core >= 0)
+#endif
+    if (s->icell_core >= 0 && !lastrow->fixed_line &&
+	lastrow->cells[s->icell_core].Line >= 0)
+	lastrow->Line = lastrow->cells[s->icell_core].Line;
+    s->icell_core = -1;
+    return (me->nrows);
+}
+
+PRIVATE void update_sumcols0 ARGS7(
+    STable_cellinfo *,	sumcols,
+    STable_rowinfo *,	lastrow,
+    int,		pos,
+    int,		len,
+    int,		icell,
+    int,		ispan,
+    int,		allocated_sumcols)
+{
+    int i;
+    if (len > 0) {
+	int sumpos = pos;
+	int prevsumpos = sumcols[icell + ispan].pos;
+	int advance;
+	if (ispan > 0) {
+	    if (lastrow->cells[icell].pos + len > sumpos)
+		sumpos = lastrow->cells[icell].pos + len;
+	    if (sumcols[icell+ispan-1].pos + sumcols[icell+ispan-1].len > sumpos)
+		sumpos = sumcols[icell+ispan-1].pos + sumcols[icell+ispan-1].len;
+	}
+	advance = sumpos - prevsumpos;
+	if (advance > 0) {
+	    for (i = icell + ispan; i < allocated_sumcols; i++) {
+		if (ispan > 0 && sumcols[i].colspan < -1) {
+		    if (i + sumcols[i].colspan < icell + ispan) {
+			advance = sumpos - sumcols[i].pos;
+			if (i > 0)
+			    advance = HTMAX(advance,
+					    sumcols[i-1].pos + sumcols[i-1].len
+					    - (sumcols[i].pos));
+			if (advance <= 0)
+			    break;
+		    }
+		}
+		if (sumcols[i].pos >= 0)
+		    sumcols[i].pos += advance;
+		else {
+		    sumcols[i].pos = sumpos;
+		    break;
+		}
+	    }
+	}
+    }
+}
+
+/*
+ * Returns -1 on error, otherwise 0.
+ */
+PUBLIC int Stbl_addCellToTable ARGS6(
+    STable_info *,	me,
+    int,		colspan,
+    short,		alignment,
+    BOOL,		isheader,
+    int,		lineno,
+    int,		pos)
+{
+    STable_states * s = &me->s;
+    STable_rowinfo *lastrow;
+    STable_cellinfo *sumcols, *sumcol;
+    int i, icell, ncells, sumpos;
+#if 0
+    int prevsumpos, advance;
+#endif
+
+    if (!me->rows || !me->nrows)
+	return -1;		/* no row started! */
+				/* ##850_fail_if_fail?? */
+    Stbl_finishCellInTable(me, YES,
+			   lineno, pos);
+    lastrow = me->rows + (me->nrows - 1);
+    ncells = lastrow->ncells;	/* remember what it was before adding cell. */
+    icell = Stbl_addCellToRow(lastrow, s,
+			      colspan, alignment, isheader,
+			      lineno, &pos);
+    if (icell < 0)
+	return icell;
+    if (me->nrows == 1 && me->startline < lastrow->Line)
+	me->startline = lastrow->Line;
+
+    {
+	int growby = 0;
+	while (icell + colspan + 1 > me->allocated_sumcols + growby)
+	    growby += CELLS_GROWBY;
+	if (growby) {
+	    if (me->allocated_sumcols == 0 && !me->sumcols) {
+		sumcols = calloc(growby, sizeof(STable_cellinfo));
+	    } else {
+		sumcols = realloc(me->sumcols,
+				  (me->allocated_sumcols + growby)
+				  * sizeof(STable_cellinfo));
+		for (i = 0; sumcols && i < growby; i++) {
+		    sumcol = sumcols + me->allocated_sumcols + i;
+		    sumcol->pos = sumcols[me->allocated_sumcols-1].pos;
+		    sumcol->len = 0;
+		    sumcol->colspan = 0;
+		}
+	    }
+	    if (sumcols) {
+		me->allocated_sumcols += growby;
+		me->sumcols = sumcols;
+	    } else {
+		return -1;
+	    }
+	}
+    }
+#if 0
+    if (icell + colspan > me->ncols) {
+	me->sumcols[icell + colspan].pos = -1; /* not yet used @@@ ??? */
+    }
+#endif
+    if (icell + 1 > me->ncols) {
+	me->ncols = icell + 1;
+    }
+    if (colspan > 1 && colspan + me->sumcols[icell + colspan].colspan > 0)
+	me->sumcols[icell + colspan].colspan = -colspan;
+    sumpos = pos;
+    if (ncells > 0)
+	sumpos += me->sumcols[ncells-1].pos - lastrow->cells[ncells-1].pos;
+    update_sumcols0(me->sumcols, lastrow, sumpos,
+		    sumpos - (ncells > 0 ? me->sumcols[icell].pos : me->sumcols[icell].pos),
+		    icell, 0, me->allocated_sumcols);
+#if 0
+    prevsumpos = me->sumcols[icell].pos;
+    advance = sumpos - prevsumpos;
+    if (advance > 0) {
+	for (i = icell; i < me->allocated_sumcols; i++) {
+	    if (me->sumcols[i].pos >= 0)
+		me->sumcols[i].pos += advance;
+	    else {
+		me->sumcols[i].pos = sumpos;
+		break;
+	    }
+	}
+    }
+#endif
+
+
+#if 0
+	int prevopos = (ncells > 0 ? lastrow->cells[ncells-1].pos : 0);
+	int prevnpos = (ncells > 0 ? me->sumcols[ncells-1].pos : 0);
+#endif
+#if 0
+    if (pos > me->maxpos) {
+	me->maxpos = pos;
+	if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
+	    return -1;
+    }
+#endif
+    me->maxpos = me->sumcols[me->allocated_sumcols-1].pos;
+    if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
+	return -1;
+    return 0;
+}
+
+/*
+ * Returns -1 on error, otherwise 0.
+ */
+PUBLIC int Stbl_finishCellInTable ARGS4(
+    STable_info *,	me,
+    BOOL,		certain,
+    int,		lineno,
+    int,		pos)
+{
+    STable_states * s = &me->s;
+    STable_rowinfo *lastrow;
+    int len, xlen, icell;
+    int i;
+    if (me->nrows == 0)
+	return -1;
+    lastrow = me->rows + (me->nrows - 1);
+    icell = lastrow->ncells - 1;
+    if (icell < 0)
+	return icell;
+    if (s->x_td == -1)
+	return certain ? -1 : 0;
+    len = Stbl_finishCellInRow(lastrow, s, certain, lineno, pos);
+    if (len == -1)
+	return len;
+    xlen = (len > 0) ? len : s->pending_len; /* ##890 use xlen if fixed_line?: */
+    if (lastrow->fixed_line && lastrow->Line == lineno)
+	len = xlen;
+    if (lastrow->cells[icell].colspan > 1) {
+	/*
+	 * @@@ This is all a too-complicated mess; do we need
+	 * sumcols len at all, or is pos enough??
+	 * Answer: sumcols len is at least used for center/right
+	 * alignment, and should probably continue to be used there;
+	 * all other uses are probably not necessary.
+	 */
+	int spanlen = 0, spanlend = 0;
+	for (i = icell; i < icell + lastrow->cells[icell].colspan; i++) {
+	    if (me->sumcols[i].len > 0) {
+		spanlen += me->sumcols[i].len;
+		if (i > icell)
+		    spanlen++;
+	    }
+	    spanlend = HTMAX(spanlend,
+			     me->sumcols[i+1].pos - me->sumcols[icell].pos);
+	}
+	if (spanlend)
+	    spanlend--;
+	if (spanlend > spanlen)
+	    spanlen = spanlend;
+	/* @@@ could overcount? */
+	if (len > spanlen)
+	    me->maxlen += (len - spanlen);
+#if 0	/* this is all quite bogus! */
+	if (me->sumcols[icell].colspan > 1)
+	    me->sumcols[icell+me->sumcols[icell].colspan].pos =
+		HTMAX(me->sumcols[icell].pos + len,
+		      me->sumcols[icell+me->sumcols[icell].colspan].pos);
+	if (lastrow->cells[icell].colspan > me->sumcols[icell].colspan) {
+	    me->sumcols[icell].colspan = lastrow->cells[icell].colspan;
+	    if (me->sumcols[icell].colspan > 1)
+		me->sumcols[icell+me->sumcols[icell].colspan].pos =
+		    HTMAX(me->sumcols[icell].pos + len,
+			  me->sumcols[icell+me->sumcols[icell].colspan].pos);
+	}
+#endif
+    } else if (len > me->sumcols[icell].len) {
+	if (me->sumcols[icell + 1].colspan >= -1)
+	    me->maxlen += (len - me->sumcols[icell].len);
+	me->sumcols[icell].len = len;
+    }
+
+    if (len > 0) {
+	update_sumcols0(me->sumcols, lastrow, pos, len,
+			icell, lastrow->cells[icell].colspan,
+			me->allocated_sumcols);
+	me->maxpos = me->sumcols[me->allocated_sumcols-1].pos;
+    }
+#if 0
+    if (len > 0) {
+	int sumpos = pos;
+	int ispan = lastrow->cells[icell].colspan;
+	int prevsumpos = me->sumcols[icell + ispan].pos;
+	int advance;
+	if (lastrow->cells[icell].pos + len > sumpos)
+	    sumpos = lastrow->cells[icell].pos + len;
+	if (me->sumcols[icell+ispan-1].pos + me->sumcols[icell+ispan-1].len > sumpos)
+	    sumpos = me->sumcols[icell+ispan-1].pos + me->sumcols[icell+ispan-1].len;
+	advance = sumpos - prevsumpos;
+	if (advance > 0) {
+	    for (i = icell + ispan; i < me->allocated_sumcols; i++) {
+		if (me->sumcols[i].colspan < -1) {
+		    if (i + me->sumcols[i].colspan < icell + ispan) {
+			advance = sumpos - me->sumcols[i].pos;
+			if (i > 0)
+			    advance = HTMAX(advance,
+					    me->sumcols[i-1].pos + me->sumcols[i-1].len
+					    - (me->sumcols[i].pos));
+			if (advance <= 0)
+			    break;
+		    }
+		}
+		if (me->sumcols[i].pos >= 0)
+		    me->sumcols[i].pos += advance;
+		else {
+		    me->sumcols[i].pos = sumpos;
+		    break;
+		}
+	    }
+	}
+	me->maxpos = me->sumcols[me->allocated_sumcols-1].pos;
+    }
+#endif
+
+    if (me->maxlen + (xlen - len) > MAX_STBL_POS)
+	return -1;
+    if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
+	return -1;
+
+    if (lineno != lastrow->Line) {
+	/* @@@ Do something here?  Or is it taken care of in
+	   Stbl_finishCellInRow ? */
+    }
+
+    return 0;
+}
+
+PUBLIC int Stbl_finishTABLE ARGS1(
+    STable_info *,	me)
+{
+    STable_states * s = &me->s;
+    int i;
+    int curpos = 0;
+
+    if (!me || me->nrows <= 0 || me->ncols <= 0) {
+	return -1;
+    }
+    if (me->nrows > 0 && me->rows[me->nrows-1].ncells > 0) {
+	if (s->pending_len > 0)
+	    me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len = s->pending_len;
+	s->pending_len = 0;
+/*	if (me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len >= 0)
+	    Stbl_finishCellInTable(me, YES,
+		me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].Line,
+		me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].pos +
+		me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len); */
+    }
+    Stbl_finishRowInTable(me);
+    for (i = 0; i < me->ncols; i++) {
+	if (me->sumcols[i].pos < curpos) {
+	    me->sumcols[i].pos = curpos;
+	} else {
+	    curpos = me->sumcols[i].pos;
+	}
+	if (me->sumcols[i].len > 0) {
+	    curpos += me->sumcols[i].len;
+	}
+    }
+#if 0				/* ??? */
+    for (j = 0; j < me->nrows; j++) {
+	STable_rowinfo *row = me->rows + i;
+	for (i = 0; i < row->ncells; i++) {
+	}
+    }
+#endif
+    return me->ncols;
+}
+
+PUBLIC short Stbl_getAlignment ARGS1(
+    STable_info *,	me)
+{
+    return me ? me->alignment : HT_ALIGN_NONE;
+}
+
+PRIVATE int get_fixup_positions ARGS4(
+    STable_rowinfo *,	me,
+    int *,		oldpos,
+    int *,		newpos,
+    STable_cellinfo *,	sumcols)
+{
+    int i = 0, ip = 0;
+    int next_i, newlen;
+    int ninserts;
+
+    if (!me)
+	return -1;
+    while (i < me->ncells) {
+	next_i = i + me->cells[i].colspan;
+	if (me->cells[i].Line != me->Line) {
+	    if (me->cells[i].Line > me->Line)
+		break;
+	    i = next_i;
+	    continue;
+	}
+	oldpos[ip] = me->cells[i].pos;
+	newpos[ip] = sumcols[i].pos;
+	if ((me->cells[i].alignment == HT_CENTER ||
+	     me->cells[i].alignment == HT_RIGHT) &&
+	    me->cells[i].len > 0) {
+	    newlen = sumcols[next_i].pos - newpos[ip] - 1;
+	    newlen = HTMAX(newlen, sumcols[i].len);
+	    if (me->cells[i].len < newlen) {
+		if (me->cells[i].alignment == HT_RIGHT) {
+		    newpos[i] += newlen - me->cells[i].len;
+		} else {
+		    newpos[i] += (newlen - me->cells[i].len) / 2;
+		}
+	    }
+	}
+	ip++;
+	i = next_i;
+    }
+    ninserts = ip;
+    return ninserts;
+}
+
+/*
+ *  Returns -1 if we have no row for this lineno, or for other error,
+ *           0 or greater (number of oldpos/newpos pairs) if we have
+ *             a table row.
+ */
+PUBLIC int Stbl_getFixupPositions ARGS4(
+    STable_info *,	me,
+    int,		lineno,
+    int *,		oldpos,
+    int *,		newpos)
+{
+    STable_rowinfo * row;
+    int j;
+    int ninserts = -1;
+    if (!me || !me->nrows)
+	return -1;
+    for (j = 0; j < me->nrows; j++) {
+	row = me->rows + j;
+	if (row->Line == lineno) {
+	    ninserts = get_fixup_positions(row, oldpos, newpos,
+					   me->sumcols);
+	    break;
+	}
+    }
+    return ninserts;
+}
+
+PUBLIC int Stbl_getStartLine ARGS1(
+    STable_info *,	me)
+{
+    if (!me)
+	return -1;
+    else
+	return me->startline;
+}
diff --git a/src/TRSTable.h b/src/TRSTable.h
new file mode 100644
index 00000000..7ef88b45
--- /dev/null
+++ b/src/TRSTable.h
@@ -0,0 +1,15 @@
+typedef struct _STable_info STable_info;
+extern STable_info * Stbl_startTABLE PARAMS((short));
+extern int Stbl_finishTABLE PARAMS((STable_info *));
+extern void Stbl_free PARAMS((STable_info *));
+extern int Stbl_addRowToTable PARAMS((STable_info *, short, int));
+extern int Stbl_addCellToTable PARAMS((STable_info *, int, short, BOOL, int, int));
+extern int Stbl_finishCellInTable PARAMS((STable_info *, BOOL, int, int));
+#define Stbl_lineBreak(stbl,l,pos) Stbl_finishCellInTable(stbl, NO, l, pos)
+extern int Stbl_getStartLine PARAMS((STable_info *));
+extern int Stbl_getFixupPositions PARAMS((
+    STable_info *	me,
+    int			lineno,
+    int *		oldpos,
+    int *		newpos));
+extern short Stbl_getAlignment PARAMS((STable_info *));
diff --git a/src/UCAuto.c b/src/UCAuto.c
index 70c8972a..87bbd3c7 100644
--- a/src/UCAuto.c
+++ b/src/UCAuto.c
@@ -1,7 +1,7 @@
 /*
 **  This file contains code for changing the Linux console mode.
 **  Currently some names for font files are hardwired in here.
-**  You have to change this code if it needs accomodation for your
+**  You have to change this code if it needs accommodation for your
 **  system (or get the required files...).
 **
 **  Depending on the Display Character Set switched to, and the previous
@@ -168,7 +168,7 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(
 			    SETFONT, old_font, NOOUTPUT);
 		}
 		CTRACE((tfp, "Executing setfont to restore: '%s'\n", tmpbuf1));
-		LYSystem(tmpbuf1);
+		status = LYSystem(tmpbuf1);
 		FREE(tmpbuf1);
 	    }
 	}
@@ -181,6 +181,10 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(
 		LYRemoveTemp(old_umap);
 		FREE(old_umap);
 	    }
+	    if (status == 0) {
+		FREE(T_font_fn);
+		FREE(T_umap_fn);
+	    }
 	}
 	return;
     } else if (lastcs < 0 && old_umap == 0 && old_font == 0) {
@@ -370,6 +374,14 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(
 	name = "unknown-8bit";
     }
 
+    if (status == 1)
+	HasUmap = Is_Unset;
+    else if (status < 0) {
+	if (HasUmap == Is_Set)
+	    HasUmap = Dunno;
+	name = "unknown-8bit";
+    }
+
     if (TransT != lastTransT) {
 	if (TransT == GN_Blat1) {
 	    /*
diff --git a/src/UCAux.c b/src/UCAux.c
index eaab7522..d4701484 100644
--- a/src/UCAux.c
+++ b/src/UCAux.c
@@ -151,7 +151,7 @@ PUBLIC BOOL UCNeedNotTranslate ARGS2(
 **  up to the caller to do something about them. - KW
 */
 PUBLIC void UCSetTransParams ARGS5(
-    UCTransParams *, 	pT,
+    UCTransParams *,	pT,
     int,		cs_in,
     CONST LYUCcharset*,	p_in,
     int,		cs_out,
@@ -452,3 +452,65 @@ PUBLIC BOOL UCConvertUniToUtf8 ARGS2(
     }
     return YES;
 }
+
+/*
+** Get UCS character code for one character from UTF-8 encoded string.
+**
+** On entry:
+**	*ppuni should point to beginning of UTF-8 encoding character
+** On exit:
+**	*ppuni is advanced to point to the last byte of UTF-8 sequence,
+**		if there was a valid one; otherwise unchanged.
+** returns the UCS value
+** returns negative value on error (invalid UTF-8 sequence)
+*/
+PUBLIC UCode_t UCGetUniFromUtf8String ARGS1(char **, ppuni)
+{
+    UCode_t uc_out = 0;
+    char * p = *ppuni;
+    int utf_count, i;
+    if (!(**ppuni&0x80))
+	return (UCode_t) **ppuni; /* ASCII range character */
+    else if (!(**ppuni&0x40))
+	return (-1);		/* not a valid UTF-8 start */
+    if ((*p & 0xe0) == 0xc0) {
+	utf_count = 1;
+    } else if ((*p & 0xf0) == 0xe0) {
+	utf_count = 2;
+    } else if ((*p & 0xf8) == 0xf0) {
+	utf_count = 3;
+    } else if ((*p & 0xfc) == 0xf8) {
+	utf_count = 4;
+    } else if ((*p & 0xfe) == 0xfc) {
+	utf_count = 5;
+    } else { /* garbage */
+	return (-1);
+    }
+    for (p = *ppuni, i = 0; i < utf_count ; i++) {
+	if ((*(++p) & 0xc0) != 0x80)
+	    return (-1);
+    }
+    p = *ppuni;
+    switch (utf_count) {
+    case 1:
+	uc_out = (((*p&0x1f) << 6) | (*(p+1)&0x3f));
+	break;
+    case 2:
+	uc_out = (((((*p&0x0f) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f));
+	break;
+    case 3:
+	uc_out = (((((((*p&0x07) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
+	    | (*(p+3)&0x3f));
+	break;
+    case 4:
+	uc_out = (((((((((*p&0x03) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
+		  | (*(p+3)&0x3f)) << 6) | (*(p+4)&0x3f));
+	break;
+    case 5:
+	uc_out = (((((((((((*p&0x01) << 6) | (*(p+1)&0x3f)) << 6) | (*(p+2)&0x3f)) << 6)
+		  | (*(p+3)&0x3f)) << 6) | (*(p+4)&0x3f)) << 6) | (*(p+5)&0x3f));
+	break;
+    }
+    *ppuni = p + utf_count;
+    return uc_out;
+}
diff --git a/src/chrtrans/cp1250_uni.tbl b/src/chrtrans/cp1250_uni.tbl
index 207add88..64ad83c4 100644
--- a/src/chrtrans/cp1250_uni.tbl
+++ b/src/chrtrans/cp1250_uni.tbl
@@ -26,6 +26,8 @@ C1250
 #    The entries are in cp1250 order
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 0x20-0x7e       idem
 #
@@ -39,11 +41,11 @@ C1250
 0x87	U+2021	#DOUBLE DAGGER
 0x88	      	#UNDEFINED
 0x89	U+2030	#PER MILLE SIGN
-0x8A	U+0160	#LATIN CAPITAL LETTER S WITH CARON
+0x8A	U+0160	U+0428	#LATIN CAPITAL LETTER S WITH CARON
 0x8B	U+2039	#SINGLE LEFT-POINTING ANGLE QUOTATION MARK
 0x8C	U+015A	#LATIN CAPITAL LETTER S WITH ACUTE
 0x8D	U+0164	#LATIN CAPITAL LETTER T WITH CARON
-0x8E	U+017D	#LATIN CAPITAL LETTER Z WITH CARON
+0x8E	U+017D	U+0416	#LATIN CAPITAL LETTER Z WITH CARON
 0x8F	U+0179	#LATIN CAPITAL LETTER Z WITH ACUTE
 0x90	      	#UNDEFINED
 0x91	U+2018	#LEFT SINGLE QUOTATION MARK
@@ -55,21 +57,21 @@ C1250
 0x97	U+2014	#EM DASH
 0x98	      	#UNDEFINED
 0x99	U+2122	#TRADE MARK SIGN
-0x9A	U+0161	#LATIN SMALL LETTER S WITH CARON
+0x9A	U+0161	U+0448	#LATIN SMALL LETTER S WITH CARON
 0x9B	U+203A	#SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
 0x9C	U+015B	#LATIN SMALL LETTER S WITH ACUTE
 0x9D	U+0165	#LATIN SMALL LETTER T WITH CARON
-0x9E	U+017E	#LATIN SMALL LETTER Z WITH CARON
+0x9E	U+017E	U+0436	#LATIN SMALL LETTER Z WITH CARON
 0x9F	U+017A	#LATIN SMALL LETTER Z WITH ACUTE
 0xA0	U+00A0	#NO-BREAK SPACE
-0xA1	U+02C7	#CARON
-0xA2	U+02D8	#BREVE
+0xA1	U+02C7	U+030c	#CARON
+0xA2	U+02D8	U+0306	#BREVE
 0xA3	U+0141	#LATIN CAPITAL LETTER L WITH STROKE
 0xA4	U+00A4	#CURRENCY SIGN
 0xA5	U+0104	#LATIN CAPITAL LETTER A WITH OGONEK
 0xA6	U+00A6	#BROKEN BAR
 0xA7	U+00A7	#SECTION SIGN
-0xA8	U+00A8	#DIAERESIS
+0xA8	U+00A8	U+0308	#DIAERESIS
 0xA9	U+00A9	#COPYRIGHT SIGN
 0xAA	U+015E	#LATIN CAPITAL LETTER S WITH CEDILLA
 0xAB	U+00AB	#LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -77,20 +79,20 @@ C1250
 0xAD	U+00AD	#SOFT HYPHEN
 0xAE	U+00AE	#REGISTERED SIGN
 0xAF	U+017B	#LATIN CAPITAL LETTER Z WITH DOT ABOVE
-0xB0	U+00B0	#DEGREE SIGN
+0xB0	U+00B0	U+030a	#DEGREE SIGN
 0xB1	U+00B1	#PLUS-MINUS SIGN
-0xB2	U+02DB	#OGONEK
+0xB2	U+02DB	U+0328	#OGONEK
 0xB3	U+0142	#LATIN SMALL LETTER L WITH STROKE
 0xB4	U+00B4	#ACUTE ACCENT
-0xB5	U+00B5	#MICRO SIGN
+0xB5	U+00B5	U+03bc	#MICRO SIGN
 0xB6	U+00B6	#PILCROW SIGN
 0xB7	U+00B7	#MIDDLE DOT
-0xB8	U+00B8	#CEDILLA
+0xB8	U+00B8	U+0327	#CEDILLA
 0xB9	U+0105	#LATIN SMALL LETTER A WITH OGONEK
 0xBA	U+015F	#LATIN SMALL LETTER S WITH CEDILLA
 0xBB	U+00BB	#RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
 0xBC	U+013D	#LATIN CAPITAL LETTER L WITH CARON
-0xBD	U+02DD	#DOUBLE ACUTE ACCENT
+0xBD	U+02DD	U+030b	#DOUBLE ACUTE ACCENT
 0xBE	U+013E	#LATIN SMALL LETTER L WITH CARON
 0xBF	U+017C	#LATIN SMALL LETTER Z WITH DOT ABOVE
 0xC0	U+0154	#LATIN CAPITAL LETTER R WITH ACUTE
@@ -101,7 +103,7 @@ C1250
 0xC5	U+0139	#LATIN CAPITAL LETTER L WITH ACUTE
 0xC6	U+0106	#LATIN CAPITAL LETTER C WITH ACUTE
 0xC7	U+00C7	#LATIN CAPITAL LETTER C WITH CEDILLA
-0xC8	U+010C	#LATIN CAPITAL LETTER C WITH CARON
+0xC8	U+010C	U+0427	#	LATIN CAPITAL LETTER C WITH CARON
 0xC9	U+00C9	#LATIN CAPITAL LETTER E WITH ACUTE
 0xCA	U+0118	#LATIN CAPITAL LETTER E WITH OGONEK
 0xCB	U+00CB	#LATIN CAPITAL LETTER E WITH DIAERESIS
@@ -133,7 +135,7 @@ C1250
 0xE5	U+013A	#LATIN SMALL LETTER L WITH ACUTE
 0xE6	U+0107	#LATIN SMALL LETTER C WITH ACUTE
 0xE7	U+00E7	#LATIN SMALL LETTER C WITH CEDILLA
-0xE8	U+010D	#LATIN SMALL LETTER C WITH CARON
+0xE8	U+010D	U+02a7	U+0447	#	LATIN SMALL LETTER C WITH CARON
 0xE9	U+00E9	#LATIN SMALL LETTER E WITH ACUTE
 0xEA	U+0119	#LATIN SMALL LETTER E WITH OGONEK
 0xEB	U+00EB	#LATIN SMALL LETTER E WITH DIAERESIS
@@ -156,4 +158,13 @@ C1250
 0xFC	U+00FC	#LATIN SMALL LETTER U WITH DIAERESIS
 0xFD	U+00FD	#LATIN SMALL LETTER Y WITH ACUTE
 0xFE	U+0163	#LATIN SMALL LETTER T WITH CEDILLA
-0xFF	U+02D9	#DOT ABOVE
+0xFF	U+02D9	U+0307	U+0387	#DOT ABOVE
+
+U+2218 " \260 "		# RING OPERATOR
+U+2219 " \225 "		# BULLET OPERATOR
+U+2297 "(\327)"		# CIRCLED TIMES
+U+2299 "(\267)"		# CIRCLED DOT OPERATOR
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+22A0 "[\327]"		# SQUARED TIMES
+U+22A1 "[\267]"		# SQUARED DOT OPERATOR
+U+22C5 " \267 "		# DOT OPERATOR
diff --git a/src/chrtrans/cp1252_uni.tbl b/src/chrtrans/cp1252_uni.tbl
index 7a9e149f..2365c9c5 100644
--- a/src/chrtrans/cp1252_uni.tbl
+++ b/src/chrtrans/cp1252_uni.tbl
@@ -30,6 +30,8 @@ C1252
 #    The entries are in cp1252 order
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 0x20-0x7e       idem
 #
@@ -41,7 +43,7 @@ C1252
 0x85	U+2026	#HORIZONTAL ELLIPSIS
 0x86	U+2020	#DAGGER
 0x87	U+2021	#DOUBLE DAGGER
-0x88	U+02C6	#MODIFIER LETTER CIRCUMFLEX ACCENT
+0x88	U+02C6	U+0302	#MODIFIER LETTER CIRCUMFLEX ACCENT
 0x89	U+2030	#PER MILLE SIGN
 0x8A	U+0160	#LATIN CAPITAL LETTER S WITH CARON
 0x8B	U+2039	#SINGLE LEFT-POINTING ANGLE QUOTATION MARK
@@ -53,7 +55,7 @@ C1252
 0x91	U+2018	#LEFT SINGLE QUOTATION MARK
 0x92	U+2019	#RIGHT SINGLE QUOTATION MARK
 0x93	U+201C	#LEFT DOUBLE QUOTATION MARK
-0x94	U+201D	#RIGHT DOUBLE QUOTATION MARK
+0x94	U+201D	U+02dd	U+030b	#RIGHT DOUBLE QUOTATION MARK
 0x95	U+2022	#BULLET
 0x96	U+2013	#EN DASH
 0x97	U+2014	#EM DASH
@@ -73,23 +75,23 @@ C1252
 0xA5	U+00A5	#YEN SIGN
 0xA6	U+00A6	#BROKEN BAR
 0xA7	U+00A7	#SECTION SIGN
-0xA8	U+00A8	#DIAERESIS
+0xA8	U+00A8	U+0308	#DIAERESIS
 0xA9	U+00A9	#COPYRIGHT SIGN
 0xAA	U+00AA	#FEMININE ORDINAL INDICATOR
 0xAB	U+00AB	#LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
 0xAC	U+00AC	#NOT SIGN
 0xAD	U+00AD	#SOFT HYPHEN
 0xAE	U+00AE	#REGISTERED SIGN
-0xAF	U+00AF	#MACRON
-0xB0	U+00B0	#DEGREE SIGN
+0xAF	U+00AF	U+0304	#MACRON
+0xB0	U+00B0	U+030a	#DEGREE SIGN
 0xB1	U+00B1	#PLUS-MINUS SIGN
 0xB2	U+00B2	#SUPERSCRIPT TWO
 0xB3	U+00B3	#SUPERSCRIPT THREE
 0xB4	U+00B4	#ACUTE ACCENT
-0xB5	U+00B5	#MICRO SIGN
+0xB5	U+00B5	U+03bc	#MICRO SIGN
 0xB6	U+00B6	#PILCROW SIGN
-0xB7	U+00B7	#MIDDLE DOT
-0xB8	U+00B8	#CEDILLA
+0xB7	U+00B7	U+0307	U+0387	U+2027	#MIDDLE DOT
+0xB8	U+00B8	U+0327	#CEDILLA
 0xB9	U+00B9	#SUPERSCRIPT ONE
 0xBA	U+00BA	#MASCULINE ORDINAL INDICATOR
 0xBB	U+00BB	#RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -161,3 +163,13 @@ C1252
 0xFD	U+00FD	#LATIN SMALL LETTER Y WITH ACUTE
 0xFE	U+00FE	#LATIN SMALL LETTER THORN
 0xFF	U+00FF	#LATIN SMALL LETTER Y WITH DIAERESIS
+
+U+2218 " \260 "		# RING OPERATOR
+U+2219 " \225 "		# BULLET OPERATOR
+U+221b " ROOT\263 "
+U+2297 "(\327)"		# CIRCLED TIMES
+U+2299 "(\267)"		# CIRCLED DOT OPERATOR
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+22A0 "[\327]"		# SQUARED TIMES
+U+22A1 "[\267]"		# SQUARED DOT OPERATOR
+U+22C5 " \267 "		# DOT OPERATOR
diff --git a/src/chrtrans/cp437_uni.tbl b/src/chrtrans/cp437_uni.tbl
index 818cbab3..95755693 100644
--- a/src/chrtrans/cp437_uni.tbl
+++ b/src/chrtrans/cp437_uni.tbl
@@ -28,8 +28,8 @@ C437
 #
 #    The entries are in cp437_DosLatinUS order
 #
-# some mapppings of greek letters to latin letters added,
-#  just for fun.. - KW
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 #
 #######################################
 
@@ -51,7 +51,7 @@ C437
 0x8d	U+00ec	#LATIN SMALL LETTER I WITH GRAVE
 0x8e	U+00c4	#LATIN CAPITAL LETTER A WITH DIAERESIS
 0x8f	U+00c5	#LATIN CAPITAL LETTER A WITH RING ABOVE
-0x90	U+00c9	#LATIN CAPITAL LETTER E WITH ACUTE
+0x90	U+00c9	U+0388	#LATIN CAPITAL LETTER E WITH ACUTE
 0x91	U+00e6	#LATIN SMALL LIGATURE AE
 0x92	U+00c6	#LATIN CAPITAL LIGATURE AE
 0x93	U+00f4	#LATIN SMALL LETTER O WITH CIRCUMFLEX
@@ -61,7 +61,7 @@ C437
 0x97	U+00f9	#LATIN SMALL LETTER U WITH GRAVE
 0x98	U+00ff	#LATIN SMALL LETTER Y WITH DIAERESIS
 0x99	U+00d6	#LATIN CAPITAL LETTER O WITH DIAERESIS
-0x9a	U+00dc	#LATIN CAPITAL LETTER U WITH DIAERESIS
+0x9a	U+00dc	U+03ab	#LATIN CAPITAL LETTER U WITH DIAERESIS
 0x9b	U+00a2	#CENT SIGN
 0x9c	U+00a3	#POUND SIGN
 0x9d	U+00a5	#YEN SIGN
@@ -135,40 +135,45 @@ C437
 0xe1	U+00df	U+03b2	#LATIN SMALL LETTER SHARP S
 0xe2	U+0393	#GREEK CAPITAL LETTER GAMMA
 0xe3	U+03c0	#GREEK SMALL LETTER PI
-0xe4	U+03a3	#GREEK CAPITAL LETTER SIGMA
+0xe4	U+03a3	U+2211	#GREEK CAPITAL LETTER SIGMA
 0xe5	U+03c3	#GREEK SMALL LETTER SIGMA
 0xe6	U+00b5	U+03bc	#MICRO SIGN
 0xe7	U+03c4	#GREEK SMALL LETTER TAU
 0xe8	U+03a6	#GREEK CAPITAL LETTER PHI
 0xe9	U+0398	U+03b8	#GREEK CAPITAL LETTER THETA
-0xea	U+03a9	#GREEK CAPITAL LETTER OMEGA
+0xea	U+03a9	U+2126	#GREEK CAPITAL LETTER OMEGA
 0xeb	U+03b4	#GREEK SMALL LETTER DELTA
 0xec	U+221e	#INFINITY
-0xed	U+03c6	#GREEK SMALL LETTER PHI
-0xee	U+03b5	#GREEK SMALL LETTER EPSILON
+0xed	U+03c6	U+00f8	#GREEK SMALL LETTER PHI
+0xee	U+03b5	U+2208	U+220a	#GREEK SMALL LETTER EPSILON
 0xef	U+2229	#INTERSECTION
 0xf0	U+2261	#IDENTICAL TO
 0xf1	U+00b1	#PLUS-MINUS SIGN
-0xf2	U+2265	#GREATER-THAN OR EQUAL TO
-0xf3	U+2264	#LESS-THAN OR EQUAL TO
-0xf4	U+2320	#TOP HALF INTEGRAL
+0xf2	U+2265	U+2267	#GREATER-THAN OR EQUAL TO
+0xf3	U+2264	U+2266	#LESS-THAN OR EQUAL TO
+0xf4	U+2320	U+0283	#TOP HALF INTEGRAL
 0xf5	U+2321	#BOTTOM HALF INTEGRAL
 0xf6	U+00f7	#DIVISION SIGN
 0xf7	U+2248	#ALMOST EQUAL TO
-0xf8	U+00b0	#DEGREE SIGN
-0xf9	U+2219	#BULLET OPERATOR
-0xfa	U+00b7	#MIDDLE DOT
+0xf8	U+00b0	U+030a	#DEGREE SIGN
+0xf9	U+2219	U+0307	U+0387	#BULLET OPERATOR
+0xfa	U+00b7	U+2027	#MIDDLE DOT
 0xfb	U+221a	#SQUARE ROOT
 0xfc	U+207f	#SUPERSCRIPT LATIN SMALL LETTER N
 0xfd	U+00b2	#SUPERSCRIPT TWO
 0xfe	U+25a0	#BLACK SQUARE
 0xff	U+00a0	#NO-BREAK SPACE
 
-U+03ac:a'
 U+03ad "\356'"	#:î'
 U+03ae:h'
-U+03af:i'
-U+03cc:o'
 U+03cd:u'
 U+03ce:w'
 
+U+2209 " !\356 "
+U+221b " 3\373"
+U+221c " 4\373"
+U+2262 " !\360"
+U+2299 "(\372)"
+U+229a "(\370)"
+U+22a1 "[\372]"
+U+02a7 "t\364"
diff --git a/src/chrtrans/cp737_uni.tbl b/src/chrtrans/cp737_uni.tbl
index 6beee2c4..710bd288 100644
--- a/src/chrtrans/cp737_uni.tbl
+++ b/src/chrtrans/cp737_uni.tbl
@@ -25,6 +25,8 @@ C737
 #    The entries are in cp737_DOSGreek order
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 0x20-0x7f       idem
 #
@@ -54,16 +56,16 @@ C737
 0x97	U+03a9	#GREEK CAPITAL LETTER OMEGA
 0x98	U+03b1	#GREEK SMALL LETTER ALPHA
 0x99	U+03b2	#GREEK SMALL LETTER BETA
-0x9a	U+03b3	#GREEK SMALL LETTER GAMMA
+0x9a	U+03b3	U+0263	#GREEK SMALL LETTER GAMMA
 0x9b	U+03b4	#GREEK SMALL LETTER DELTA
 0x9c	U+03b5	#GREEK SMALL LETTER EPSILON
 0x9d	U+03b6	#GREEK SMALL LETTER ZETA
 0x9e	U+03b7	#GREEK SMALL LETTER ETA
 0x9f	U+03b8	#GREEK SMALL LETTER THETA
-0xa0	U+03b9	#GREEK SMALL LETTER IOTA
+0xa0	U+03b9	U+0131	#GREEK SMALL LETTER IOTA
 0xa1	U+03ba	#GREEK SMALL LETTER KAPPA
 0xa2	U+03bb	#GREEK SMALL LETTER LAMDA
-0xa3	U+03bc	#GREEK SMALL LETTER MU
+0xa3	U+03bc	U+00b5	#GREEK SMALL LETTER MU
 0xa4	U+03bd	#GREEK SMALL LETTER NU
 0xa5	U+03be	#GREEK SMALL LETTER XI
 0xa6	U+03bf	#GREEK SMALL LETTER OMICRON
@@ -72,7 +74,7 @@ C737
 0xa9	U+03c3	#GREEK SMALL LETTER SIGMA
 0xaa	U+03c2	#GREEK SMALL LETTER FINAL SIGMA
 0xab	U+03c4	#GREEK SMALL LETTER TAU
-0xac	U+03c5	#GREEK SMALL LETTER UPSILON
+0xac	U+03c5	U+028a	#GREEK SMALL LETTER UPSILON
 0xad	U+03c6	#GREEK SMALL LETTER PHI
 0xae	U+03c7	#GREEK SMALL LETTER CHI
 0xaf	U+03c8	#GREEK SMALL LETTER PSI
@@ -132,7 +134,7 @@ C737
 0xe5	U+03af	#GREEK SMALL LETTER IOTA WITH TONOS
 0xe6	U+03cc	#GREEK SMALL LETTER OMICRON WITH TONOS
 0xe7	U+03cd	#GREEK SMALL LETTER UPSILON WITH TONOS
-0xe8	U+03cb	#GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+0xe8	U+03cb	U+00fc	#GREEK SMALL LETTER UPSILON WITH DIALYTIKA
 0xe9	U+03ce	#GREEK SMALL LETTER OMEGA WITH TONOS
 0xea	U+0386	#GREEK CAPITAL LETTER ALPHA WITH TONOS
 0xeb	U+0388	#GREEK CAPITAL LETTER EPSILON WITH TONOS
@@ -149,10 +151,20 @@ C737
 0xf6	U+00f7	#DIVISION SIGN
 0xf7	U+2248	#ALMOST EQUAL TO
 0xf8	U+00b0	#DEGREE SIGN
-0xf9	U+2219	#BULLET OPERATOR
+0xf9	U+2219	U+0307	U+0387	#BULLET OPERATOR
 0xfa	U+00b7	#MIDDLE DOT
 0xfb	U+221a	#SQUARE ROOT
 0xfc	U+207f	#SUPERSCRIPT LATIN SMALL LETTER N
 0xfd	U+00b2	#SUPERSCRIPT TWO
 0xfe	U+25a0	#BLACK SQUARE
 0xff	U+00a0	#NO-BREAK SPACE
+
+U+2209 " !\234 "
+U+2218 " \370 "		# RING OPERATOR
+U+221b " 3\373"
+U+221c " 4\373"
+U+2299 "(\372)"
+U+229a "(\370)"
+U+22a1 "[\372]"
+U+02a4 "d\235"
+U+2249 "!\367"
diff --git a/src/chrtrans/cp850_uni.tbl b/src/chrtrans/cp850_uni.tbl
index bc44cde8..91fe44ee 100644
--- a/src/chrtrans/cp850_uni.tbl
+++ b/src/chrtrans/cp850_uni.tbl
@@ -31,12 +31,14 @@ C850
 #    The entries are in cp850_DOSLatin1 order
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 0x20-0x7e       idem
 #
 0x80	U+00c7	#LATIN CAPITAL LETTER C WITH CEDILLA
-0x81	U+00fc	#LATIN SMALL LETTER U WITH DIAERESIS
-0x82	U+00e9	#LATIN SMALL LETTER E WITH ACUTE
+0x81	U+00fc	U+03cb	#LATIN SMALL LETTER U WITH DIAERESIS
+0x82	U+00e9	U+03ad	#LATIN SMALL LETTER E WITH ACUTE
 0x83	U+00e2	#LATIN SMALL LETTER A WITH CIRCUMFLEX
 0x84	U+00e4	#LATIN SMALL LETTER A WITH DIAERESIS
 0x85	U+00e0	#LATIN SMALL LETTER A WITH GRAVE
@@ -45,12 +47,12 @@ C850
 0x88	U+00ea	#LATIN SMALL LETTER E WITH CIRCUMFLEX
 0x89	U+00eb	#LATIN SMALL LETTER E WITH DIAERESIS
 0x8a	U+00e8	#LATIN SMALL LETTER E WITH GRAVE
-0x8b	U+00ef	#LATIN SMALL LETTER I WITH DIAERESIS
+0x8b	U+00ef	U+03ca	#LATIN SMALL LETTER I WITH DIAERESIS
 0x8c	U+00ee	#LATIN SMALL LETTER I WITH CIRCUMFLEX
 0x8d	U+00ec	#LATIN SMALL LETTER I WITH GRAVE
 0x8e	U+00c4	#LATIN CAPITAL LETTER A WITH DIAERESIS
 0x8f	U+00c5	#LATIN CAPITAL LETTER A WITH RING ABOVE
-0x90	U+00c9	#LATIN CAPITAL LETTER E WITH ACUTE
+0x90	U+00c9	U+0388	#LATIN CAPITAL LETTER E WITH ACUTE
 0x91	U+00e6	#LATIN SMALL LIGATURE AE
 0x92	U+00c6	#LATIN CAPITAL LIGATURE AE
 0x93	U+00f4	#LATIN SMALL LETTER O WITH CIRCUMFLEX
@@ -60,16 +62,16 @@ C850
 0x97	U+00f9	#LATIN SMALL LETTER U WITH GRAVE
 0x98	U+00ff	#LATIN SMALL LETTER Y WITH DIAERESIS
 0x99	U+00d6	#LATIN CAPITAL LETTER O WITH DIAERESIS
-0x9a	U+00dc	#LATIN CAPITAL LETTER U WITH DIAERESIS
+0x9a	U+00dc	U+03ab	#LATIN CAPITAL LETTER U WITH DIAERESIS
 0x9b	U+00f8	#LATIN SMALL LETTER O WITH STROKE
 0x9c	U+00a3	#POUND SIGN
 0x9d	U+00d8	#LATIN CAPITAL LETTER O WITH STROKE
 0x9e	U+00d7	#MULTIPLICATION SIGN
 0x9f	U+0192	#LATIN SMALL LETTER F WITH HOOK
-0xa0	U+00e1	#LATIN SMALL LETTER A WITH ACUTE
-0xa1	U+00ed	#LATIN SMALL LETTER I WITH ACUTE
-0xa2	U+00f3	#LATIN SMALL LETTER O WITH ACUTE
-0xa3	U+00fa	#LATIN SMALL LETTER U WITH ACUTE
+0xa0	U+00e1	U+03ac	#LATIN SMALL LETTER A WITH ACUTE
+0xa1	U+00ed	U+03af	#LATIN SMALL LETTER I WITH ACUTE
+0xa2	U+00f3	U+03cc	#LATIN SMALL LETTER O WITH ACUTE
+0xa3	U+00fa	U+03cd	#LATIN SMALL LETTER U WITH ACUTE
 0xa4	U+00f1	#LATIN SMALL LETTER N WITH TILDE
 0xa5	U+00d1	#LATIN CAPITAL LETTER N WITH TILDE
 0xa6	U+00aa	#FEMININE ORDINAL INDICATOR
@@ -87,7 +89,7 @@ C850
 0xb2	U+2593	#DARK SHADE
 0xb3	U+2502	#BOX DRAWINGS LIGHT VERTICAL
 0xb4	U+2524	#BOX DRAWINGS LIGHT VERTICAL AND LEFT
-0xb5	U+00c1	#LATIN CAPITAL LETTER A WITH ACUTE
+0xb5	U+00c1	U+0386	#LATIN CAPITAL LETTER A WITH ACUTE
 0xb6	U+00c2	#LATIN CAPITAL LETTER A WITH CIRCUMFLEX
 0xb7	U+00c0	#LATIN CAPITAL LETTER A WITH GRAVE
 0xb8	U+00a9	#COPYRIGHT SIGN
@@ -119,10 +121,10 @@ C850
 0xd2	U+00ca	#LATIN CAPITAL LETTER E WITH CIRCUMFLEX
 0xd3	U+00cb	#LATIN CAPITAL LETTER E WITH DIAERESIS
 0xd4	U+00c8	#LATIN CAPITAL LETTER E WITH GRAVE
-0xd5	U+0131	#LATIN SMALL LETTER DOTLESS I
-0xd6	U+00cd	#LATIN CAPITAL LETTER I WITH ACUTE
+0xd5	U+0131	U+03b9	#LATIN SMALL LETTER DOTLESS I
+0xd6	U+00cd	U+038a	#LATIN CAPITAL LETTER I WITH ACUTE
 0xd7	U+00ce	#LATIN CAPITAL LETTER I WITH CIRCUMFLEX
-0xd8	U+00cf	#LATIN CAPITAL LETTER I WITH DIAERESIS
+0xd8	U+00cf	U+03aa	#LATIN CAPITAL LETTER I WITH DIAERESIS
 0xd9	U+2518	#BOX DRAWINGS LIGHT UP AND LEFT
 0xda	U+250c	#BOX DRAWINGS LIGHT DOWN AND RIGHT
 0xdb	U+2588	#FULL BLOCK
@@ -130,13 +132,13 @@ C850
 0xdd	U+00a6	#BROKEN BAR
 0xde	U+00cc	#LATIN CAPITAL LETTER I WITH GRAVE
 0xdf	U+2580	#UPPER HALF BLOCK
-0xe0	U+00d3	#LATIN CAPITAL LETTER O WITH ACUTE
+0xe0	U+00d3	U+038c	#LATIN CAPITAL LETTER O WITH ACUTE
 0xe1	U+00df	#LATIN SMALL LETTER SHARP S
 0xe2	U+00d4	#LATIN CAPITAL LETTER O WITH CIRCUMFLEX
 0xe3	U+00d2	#LATIN CAPITAL LETTER O WITH GRAVE
 0xe4	U+00f5	#LATIN SMALL LETTER O WITH TILDE
 0xe5	U+00d5	#LATIN CAPITAL LETTER O WITH TILDE
-0xe6	U+00b5	#MICRO SIGN
+0xe6	U+00b5	U+03bc	#MICRO SIGN
 0xe7	U+00fe	#LATIN SMALL LETTER THORN
 0xe8	U+00de	#LATIN CAPITAL LETTER THORN
 0xe9	U+00da	#LATIN CAPITAL LETTER U WITH ACUTE
@@ -144,22 +146,30 @@ C850
 0xeb	U+00d9	#LATIN CAPITAL LETTER U WITH GRAVE
 0xec	U+00fd	#LATIN SMALL LETTER Y WITH ACUTE
 0xed	U+00dd	#LATIN CAPITAL LETTER Y WITH ACUTE
-0xee	U+00af	#MACRON
-0xef	U+00b4	#ACUTE ACCENT
+0xee	U+00af	U+0304	#MACRON
+0xef	U+00b4	U+0301	#ACUTE ACCENT
 0xf0	U+00ad	#SOFT HYPHEN
 0xf1	U+00b1	#PLUS-MINUS SIGN
-0xf2	U+2017	#DOUBLE LOW LINE
+0xf2	U+2017	U+0333	#DOUBLE LOW LINE
 0xf3	U+00be	#VULGAR FRACTION THREE QUARTERS
 0xf4	U+00b6	#PILCROW SIGN
 0xf5	U+00a7	#SECTION SIGN
 0xf6	U+00f7	#DIVISION SIGN
-0xf7	U+00b8	#CEDILLA
-0xf8	U+00b0	#DEGREE SIGN
-0xf9	U+00a8	#DIAERESIS
-0xfa	U+00b7	#MIDDLE DOT
+0xf7	U+00b8	U+0327	#CEDILLA
+0xf8	U+00b0	U+030a	#DEGREE SIGN
+0xf9	U+00a8	U+0308	#DIAERESIS
+0xfa	U+00b7	U+0307	U+0387	U+2027	#MIDDLE DOT
 0xfb	U+00b9	#SUPERSCRIPT ONE
 0xfc	U+00b3	#SUPERSCRIPT THREE
 0xfd	U+00b2	#SUPERSCRIPT TWO
 0xfe	U+25a0	#BLACK SQUARE
 0xff	U+00a0	#NO-BREAK SPACE
 
+U+2218 " \370 "		# RING OPERATOR
+U+221b " ROOT\374 "
+U+2297 "(\236)"		# CIRCLED TIMES
+U+2299 "(\372)"		# CIRCLED DOT OPERATOR
+U+229A "(\370)"		# CIRCLED RING OPERATOR
+U+22A0 "[\236]"		# SQUARED TIMES
+U+22A1 "[\372]"		# SQUARED DOT OPERATOR
+U+22C5 " \372 "		# DOT OPERATOR
diff --git a/src/chrtrans/cp852_uni.tbl b/src/chrtrans/cp852_uni.tbl
index fec2ecf4..c4ac349b 100644
--- a/src/chrtrans/cp852_uni.tbl
+++ b/src/chrtrans/cp852_uni.tbl
@@ -25,12 +25,14 @@ C852
 #    The entries are in cp852_DOSLatin2 order
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 0x20-0x7e       idem
 #
 0x80	U+00c7	#LATIN CAPITAL LETTER C WITH CEDILLA
-0x81	U+00fc	#LATIN SMALL LETTER U WITH DIAERESIS
-0x82	U+00e9	#LATIN SMALL LETTER E WITH ACUTE
+0x81	U+00fc	U+03cb	#LATIN SMALL LETTER U WITH DIAERESIS
+0x82	U+00e9	U+03ad	#LATIN SMALL LETTER E WITH ACUTE
 0x83	U+00e2	#LATIN SMALL LETTER A WITH CIRCUMFLEX
 0x84	U+00e4	#LATIN SMALL LETTER A WITH DIAERESIS
 0x85	U+016f	#LATIN SMALL LETTER U WITH RING ABOVE
@@ -44,7 +46,7 @@ C852
 0x8d	U+0179	#LATIN CAPITAL LETTER Z WITH ACUTE
 0x8e	U+00c4	#LATIN CAPITAL LETTER A WITH DIAERESIS
 0x8f	U+0106	#LATIN CAPITAL LETTER C WITH ACUTE
-0x90	U+00c9	#LATIN CAPITAL LETTER E WITH ACUTE
+0x90	U+00c9	U+0388	#LATIN CAPITAL LETTER E WITH ACUTE
 0x91	U+0139	#LATIN CAPITAL LETTER L WITH ACUTE
 0x92	U+013a	#LATIN SMALL LETTER L WITH ACUTE
 0x93	U+00f4	#LATIN SMALL LETTER O WITH CIRCUMFLEX
@@ -54,25 +56,25 @@ C852
 0x97	U+015a	#LATIN CAPITAL LETTER S WITH ACUTE
 0x98	U+015b	#LATIN SMALL LETTER S WITH ACUTE
 0x99	U+00d6	#LATIN CAPITAL LETTER O WITH DIAERESIS
-0x9a	U+00dc	#LATIN CAPITAL LETTER U WITH DIAERESIS
+0x9a	U+00dc	U+03ab	#LATIN CAPITAL LETTER U WITH DIAERESIS
 0x9b	U+0164	#LATIN CAPITAL LETTER T WITH CARON
 0x9c	U+0165	#LATIN SMALL LETTER T WITH CARON
 0x9d	U+0141	#LATIN CAPITAL LETTER L WITH STROKE
 0x9e	U+00d7	#MULTIPLICATION SIGN
-0x9f	U+010d	#LATIN SMALL LETTER C WITH CARON
-0xa0	U+00e1	#LATIN SMALL LETTER A WITH ACUTE
-0xa1	U+00ed	#LATIN SMALL LETTER I WITH ACUTE
-0xa2	U+00f3	#LATIN SMALL LETTER O WITH ACUTE
-0xa3	U+00fa	#LATIN SMALL LETTER U WITH ACUTE
+0x9f	U+010d	U+02a7	U+0447	#LATIN SMALL LETTER C WITH CARON
+0xa0	U+00e1	U+03ac	#LATIN SMALL LETTER A WITH ACUTE
+0xa1	U+00ed	U+03af	#LATIN SMALL LETTER I WITH ACUTE
+0xa2	U+00f3	U+03cc	#LATIN SMALL LETTER O WITH ACUTE
+0xa3	U+00fa	U+03cd	#LATIN SMALL LETTER U WITH ACUTE
 0xa4	U+0104	#LATIN CAPITAL LETTER A WITH OGONEK
 0xa5	U+0105	#LATIN SMALL LETTER A WITH OGONEK
-0xa6	U+017d	#LATIN CAPITAL LETTER Z WITH CARON
-0xa7	U+017e	#LATIN SMALL LETTER Z WITH CARON
+0xa6	U+017d	U+0416	#LATIN CAPITAL LETTER Z WITH CARON
+0xa7	U+017e	U+0436	#LATIN SMALL LETTER Z WITH CARON
 0xa8	U+0118	#LATIN CAPITAL LETTER E WITH OGONEK
 0xa9	U+0119	#LATIN SMALL LETTER E WITH OGONEK
 0xaa	U+00ac	#NOT SIGN
 0xab	U+017a	#LATIN SMALL LETTER Z WITH ACUTE
-0xac	U+010c	#LATIN CAPITAL LETTER C WITH CARON
+0xac	U+010c	U+0427	#LATIN CAPITAL LETTER C WITH CARON
 0xad	U+015f	#LATIN SMALL LETTER S WITH CEDILLA
 0xae	U+00ab	#LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
 0xaf	U+00bb	#RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -81,7 +83,7 @@ C852
 0xb2	U+2593	#DARK SHADE
 0xb3	U+2502	#BOX DRAWINGS LIGHT VERTICAL
 0xb4	U+2524	#BOX DRAWINGS LIGHT VERTICAL AND LEFT
-0xb5	U+00c1	#LATIN CAPITAL LETTER A WITH ACUTE
+0xb5	U+00c1	U+0386	#LATIN CAPITAL LETTER A WITH ACUTE
 0xb6	U+00c2	#LATIN CAPITAL LETTER A WITH CIRCUMFLEX
 0xb7	U+011a	#LATIN CAPITAL LETTER E WITH CARON
 0xb8	U+015e	#LATIN CAPITAL LETTER S WITH CEDILLA
@@ -114,7 +116,7 @@ C852
 0xd3	U+00cb	#LATIN CAPITAL LETTER E WITH DIAERESIS
 0xd4	U+010f	#LATIN SMALL LETTER D WITH CARON
 0xd5	U+0147	#LATIN CAPITAL LETTER N WITH CARON
-0xd6	U+00cd	#LATIN CAPITAL LETTER I WITH ACUTE
+0xd6	U+00cd	U+038a	#LATIN CAPITAL LETTER I WITH ACUTE
 0xd7	U+00ce	#LATIN CAPITAL LETTER I WITH CIRCUMFLEX
 0xd8	U+011b	#LATIN SMALL LETTER E WITH CARON
 0xd9	U+2518	#BOX DRAWINGS LIGHT UP AND LEFT
@@ -124,14 +126,14 @@ C852
 0xdd	U+0162	#LATIN CAPITAL LETTER T WITH CEDILLA
 0xde	U+016e	#LATIN CAPITAL LETTER U WITH RING ABOVE
 0xdf	U+2580	#UPPER HALF BLOCK
-0xe0	U+00d3	#LATIN CAPITAL LETTER O WITH ACUTE
+0xe0	U+00d3	U+038c	#LATIN CAPITAL LETTER O WITH ACUTE
 0xe1	U+00df	#LATIN SMALL LETTER SHARP S
 0xe2	U+00d4	#LATIN CAPITAL LETTER O WITH CIRCUMFLEX
 0xe3	U+0143	#LATIN CAPITAL LETTER N WITH ACUTE
 0xe4	U+0144	#LATIN SMALL LETTER N WITH ACUTE
 0xe5	U+0148	#LATIN SMALL LETTER N WITH CARON
-0xe6	U+0160	#LATIN CAPITAL LETTER S WITH CARON
-0xe7	U+0161	#LATIN SMALL LETTER S WITH CARON
+0xe6	U+0160	U+0428	#LATIN CAPITAL LETTER S WITH CARON
+0xe7	U+0161	U+0448	#LATIN SMALL LETTER S WITH CARON
 0xe8	U+0154	#LATIN CAPITAL LETTER R WITH ACUTE
 0xe9	U+00da	#LATIN CAPITAL LETTER U WITH ACUTE
 0xea	U+0155	#LATIN SMALL LETTER R WITH ACUTE
@@ -139,21 +141,28 @@ C852
 0xec	U+00fd	#LATIN SMALL LETTER Y WITH ACUTE
 0xed	U+00dd	#LATIN CAPITAL LETTER Y WITH ACUTE
 0xee	U+0163	#LATIN SMALL LETTER T WITH CEDILLA
-0xef	U+00b4	#ACUTE ACCENT
+0xef	U+00b4	U+0301	#ACUTE ACCENT
 0xf0	U+00ad	#SOFT HYPHEN
-0xf1	U+02dd	#DOUBLE ACUTE ACCENT
-0xf2	U+02db	#OGONEK
-0xf3	U+02c7	#CARON
-0xf4	U+02d8	#BREVE
+0xf1	U+02dd	U+030b	#DOUBLE ACUTE ACCENT
+0xf2	U+02db	U+0328	#OGONEK
+0xf3	U+02c7	U+030c	#CARON
+0xf4	U+02d8	U+0306	#BREVE
 0xf5	U+00a7	#SECTION SIGN
 0xf6	U+00f7	#DIVISION SIGN
-0xf7	U+00b8	#CEDILLA
-0xf8	U+00b0	#DEGREE SIGN
-0xf9	U+00a8	#DIAERESIS
-0xfa	U+02d9	#DOT ABOVE
+0xf7	U+00b8	U+0327	#CEDILLA
+0xf8	U+00b0	U+030a	#DEGREE SIGN
+0xf9	U+00a8	U+0308	#DIAERESIS
+0xfa	U+02d9	U+0307	U+0387	#DOT ABOVE
 0xfb	U+0171	#LATIN SMALL LETTER U WITH DOUBLE ACUTE
 0xfc	U+0158	#LATIN CAPITAL LETTER R WITH CARON
 0xfd	U+0159	#LATIN SMALL LETTER R WITH CARON
 0xfe	U+25a0	#BLACK SQUARE
 0xff	U+00a0	#NO-BREAK SPACE
 
+U+2218 " \370 "		# RING OPERATOR
+U+2297 "(\236)"		# CIRCLED TIMES
+U+2299 "(\372)"		# CIRCLED DOT OPERATOR
+U+229A "(\370)"		# CIRCLED RING OPERATOR
+U+22A0 "[\236]"		# SQUARED TIMES
+U+22A1 "[\372]"		# SQUARED DOT OPERATOR
+U+22C5 " \372 "		# DOT OPERATOR
diff --git a/src/chrtrans/def7_uni.tbl b/src/chrtrans/def7_uni.tbl
index 39dc165d..ffc217fe 100644
--- a/src/chrtrans/def7_uni.tbl
+++ b/src/chrtrans/def7_uni.tbl
@@ -67,7 +67,7 @@ U+00bd: 1/2
 U+00be: 3/4
 U+00bf:?
 0x41	U+00c0-U+00c3
-U+00c4:A:
+U+00c4 "Ae"		# &Auml;, not the best choice for some languages.
 U+00c5:AA
 U+00c6:AE
 U+00c7:C,
@@ -76,17 +76,17 @@ U+00c7:C,
 U+00d0:D-
 0x4e	U+00d1
 0x4f	U+00d2-U+00d5
-U+00d6:O:
+U+00d6 "Oe"		# &Ouml;, not the best choice for some languages.
 U+00d7: *
 U+00d8:O/
 0x55	U+00d9-U+00db
-U+00dc:U:
+U+00dc "Ue"		# &Uuml;, not the best choice for some languages.
 0x59	U+00dd
 U+00de:TH
 U+00df:ss
 U+00e0:`a
 0x61	U+00e1-U+00e3
-U+00e4:a:
+U+00e4 "ae"		# &auml;, not the best choice for some languages.
 U+00e5:aa
 U+00e6:ae
 U+00e7:c,
@@ -96,11 +96,11 @@ U+00ec:`i
 U+00f0:d-
 0x6e	U+00f1
 0x6f	U+00f2-U+00f5
-U+00f6:o:
+U+00f6 "oe"		# &ouml;, not the best choice for some languages.
 U+00f7:-:
 U+00f8:o/
 0x75	U+00f9-U+00fb
-U+00fc:u:
+U+00fc "ue"		# &uuml;, not the best choice for some languages.
 0x79	U+00fd
 U+00fe:th
 0x79	U+00ff
@@ -165,7 +165,7 @@ U+0171:u"
 0x77	U+0175
 0x59	U+0176	U+0178
 0x79	U+0177
-0x5a	U+0179	U+017b	U+017d
+0x5a	U+0179	U+017b	U+017d	U+021d
 0x7a	U+017a	U+017c	U+017e
 U+017f:s1
 U+0187:C2
@@ -314,7 +314,7 @@ U+028d:w<vls>
 U+028e:l^
 U+028f:I.
 U+0290:z.
-U+0292:ed
+U+0292:Z
 0x3f	U+0294 #	LATIN SMALL LETTER GLOTTAL STOP	-> ?
 U+0295:H<vcd>
 U+0296:l!
@@ -326,6 +326,9 @@ U+029b:G`
 U+029e:k!
 0x4c	U+029F #	LATIN LETTER SMALL CAPITAL L
 U+02a0:q`
+U+02a4:d3
+U+02a6:ts
+U+02a7:tS
 U+02b0:<h>
 U+02b1:<?>
 0x3b	U+02b2 U+0321
@@ -335,23 +338,50 @@ U+02bb:;S
 0x60	U+02bc
 U+02c6:^
 U+02c7:'<
+U+02c8:|
 U+02c9:1-
 U+02cb:1!
 0x3a	U+02d0
+U+02d1 ":\\"
+0x2b	U+02d6
+0x2d	U+02d7
 U+02d8:'(
 U+02d9:'.
 U+02da:'0
 U+02db:';
 U+02dc:~
 U+02dd:'"
+U+02e5:_T
+U+02e6:_H
+U+02e7:_M
+U+02e8:_L
+U+02e9:_B
+U+02ec:_v
+U+02ee:''
+0x60	U+0300
+0x27	U+0301
+0x5e	U+0302
 0x7e	U+0303	U+0334
+U+030b:''
+0x7c	U+030d
+U+030e:||
+U+030f:``
 0x2e	U+0322	U+0323
 U+0324:<?>
 U+0325:<o>
+0x2c	U+0326	U+0327
 0x2d	U+0329
 0x5b	U+032a
 U+032b:<w>
 U+0334:<H>
+0x2f	U+0337	U+0338
+U+0340:`
+U+0341:'
+U+0342:~
+U+0344:'%
+U+0345:j3
+U+0347:=
+U+0360:~~
 U+0374:'
 U+0375:,
 U+037a:j3
@@ -359,12 +389,12 @@ U+037e:?%
 U+0384:'*
 U+0385:'%
 # Greek letters
-U+0386:A%
+U+0386:A'
 U+0387:.*
-U+0388:E%
+U+0388:E'
 U+0389:Y%
-U+038a:I%
-U+038c:O%
+U+038a:I'
+U+038c:O'
 U+038e:U%
 U+038f:W%
 U+0390:i3
@@ -391,13 +421,13 @@ U+03a5:U
 U+03a6:F
 U+03a7:X
 U+03a8:Q
-U+03a9:W
+U+03a9:W*
 U+03aa:J
 U+03ab:V*
-U+03ac:a%
-U+03ad:e%
+U+03ac:a'
+U+03ad:e'
 U+03ae:y%
-U+03af:i%
+U+03af:i'
 U+03b0:u3
 U+03b1:a
 U+03b2:b
@@ -426,7 +456,7 @@ U+03c8:q
 U+03c9:w
 U+03ca:j
 U+03cb:v*
-U+03cc:o%
+U+03cc:o'
 U+03cd:u%
 U+03ce:w%
 # Greek symbols
@@ -435,6 +465,7 @@ U+03d1 "theta "
 U+03d2 "upsi "
 U+03d5 "phi "
 U+03d6 "pi "
+U+03d7:k.
 U+03da:T3
 U+03db:t3
 U+03dc:M3
@@ -445,6 +476,7 @@ U+03e0:P3
 U+03e1:p3
 U+03f0 "kappa "
 U+03f1 "rho "
+U+03f3:J
 U+03f4:'%
 U+03f5:j3
 # Cyrillic capital letters
@@ -555,7 +587,8 @@ U+0480:C3
 U+0481:c3
 U+0490:G3
 U+0491:g3
-
+U+04d4:AE
+U+04d5:ae
 # These may make Yiddish slightly more readable, until we have
 # something better.
 
@@ -1272,14 +1305,30 @@ U+1ef6:Y2
 U+1ef7:y2
 U+1ef8:Y?
 U+1ef9:y?
-U+1f00:;'
-U+1f01:,'
-U+1f02:;!
-U+1f03:,!
-U+1f04:?;
-U+1f05:?,
-U+1f06:!:
-U+1f07:?:
+0x61	U+1f00
+U+1f01:ha
+U+1f02:`a
+U+1f03:h`a
+U+1f04:a'
+U+1f05:ha'
+U+1f06:a~
+U+1f07:ha~
+0x41	U+1f08
+U+1f09:hA
+U+1f0a:`A
+U+1f0b:h`A
+U+1f0c:A'
+U+1f0d:hA'
+U+1f0e:A~
+U+1f0f:hA~
+U+1f11:he
+U+1f19:hE
+U+1f31:hi
+U+1f39:hI
+U+1f41:ho
+U+1f49:hO
+U+1f51:hu
+U+1f59:hU
 U+1fbf:,,
 U+1fc0:?*
 U+1fc1:?:
@@ -1289,6 +1338,8 @@ U+1fcf:?,
 U+1fdd:;!
 U+1fde:;'
 U+1fdf:?;
+U+1fe5:rh
+U+1fec:Rh
 U+1fed:!:
 U+1fef:!*
 U+1ffe:;;
@@ -1299,7 +1350,7 @@ U+2003 "  "
 U+200e:(->)
 U+200f:(<-)
 U+200a:
-0x2d	U+2010	U+2013 U+2015	# hyphen-like
+0x2d	U+2010 U+2011 U+2013 U+2015	# hyphen-like
 U+2014 "--"
 U+2016:||
 U+2017:=2
@@ -1309,8 +1360,12 @@ U+2017:=2
 U+2020:/-
 U+2021:/=
 U+2022 " o "
+0x2e	U+2024
 U+2025:..
 U+2026:...
+U+2027:.
+U+2028 "\015"
+U+2029 "\015\012"
 
 # Dont wanna see these:
 # POP DIRECTIONAL FORMATTING      202C
@@ -1318,6 +1373,7 @@ U+202c:
 # LEFT-TO-RIGHT OVERRIDE  202D
 U+202d:
 
+U+202f ""
 U+2030: 0/00
 U+2032:'
 U+2033:''
@@ -1333,6 +1389,8 @@ U+203c:!!
 U+203e:'-
 0x2d   U+2043  # HYPHEN BULLET ?
 U+2044:/
+U+2048:?!
+U+2049:!?
 # end of General punctuation.
 U+2070:^0
 U+2074:^4
@@ -1370,22 +1428,31 @@ U+20a7:Pt
 U+20a9:W=
 # New euro currency sign glyph:
 U+20AC:EUR
+U+2100:a/c
+U+2101:a/s
 U+2103:oC
 U+2105:c/o
+U+2106:c/u
 U+2109:oF
+0x67	U+210a
+0x68	U+210e
+U+210f "\134hbar "
 U+2111:Im
+U+2113:l
 U+2116:No.
 U+2117:PO
 U+2118:P
 U+211C:Re
 U+211e:Rx
 U+2120:(SM)
+U+2121:TEL
 # TRADE MARK SIGN:
 U+2122:(TM)
 U+2126:Ohm
 0x4b	U+212A	# Kelvin sign - K
 U+212b:Ang.
 U+212E:est.
+0x6f	U+2134
 U+2135 "Aleph "
 U+2136 "Bet "
 U+2137 "Gimel "
@@ -1402,6 +1469,7 @@ U+215b: 1/8
 U+215c: 3/8
 U+215d: 5/8
 U+215e: 7/8
+U+215f: 1/
 U+2160:I
 U+2161:II
 U+2162:III
@@ -1459,25 +1527,34 @@ U+2200:FA
 U+2202:\partial
 U+2203:TE
 U+2205:{}
-U+2206:decr.
+U+2206:Delta
 U+2207:Nabla
 U+2208:(-
 U+2209:!(-
+U+220a:(-
 U+220b:-)
+U+220c:!-)
+U+220d:-)
+U+220e " qed"
 U+220f:\prod
 U+2211:\sum
 U+2212: -
 U+2213:-/+
 U+2214:.+
+0x2f	U+2215
+U+2216 " - "
 U+2217:*
 U+2218:Ob
 U+2219:sb
 U+221a " SQRT "
+U+221b " ROOT3 "
+U+221c " ROOT4 "
 U+221d:0(
 U+221e:infty
 U+221f:-L
 U+2220:-V
 U+2225:PP
+U+2226 " !PP "
 U+2227:AND
 U+2228:OR
 U+2229:(U
@@ -1495,30 +1572,69 @@ U+2243:?-
 U+2245:?=
 # ALMOST EQUAL TO:
 U+2248:~=
+U+2249 " !~= "
 U+224c:=?
 U+2253:HI
+U+2254::=
+U+2255:=:
 U+2260:!=
 U+2261:=3
+U+2262 " !=3 "
 U+2264:=<
 U+2265:>=
+U+2266:.LE.
+U+2267:.GE.
+U+2268:.LT.NOT.EQ.
+U+2269:.GT.NOT.EQ.
 U+226a:<<
 U+226b:>>
 U+226e:!<
 U+226f:!>
+U+2276 " <> "
+U+2277 " >< "
 U+2282:(C
 U+2283:)C
-U+2282:!(C
+U+2284 " !(C "
+U+2285 " !)C "
 U+2286:(_
 U+2287:)_
-U+2295:(+)
-U+2297:(x)
-U+2299:0.
-U+229a:02
+U+2295 "(+)"		# CIRCLED PLUS
+U+2296 "(-)"		# CIRCLED MINUS
+U+2297 "(x)"		# CIRCLED TIMES
+U+2298 "(/)"		# CIRCLED DIVISION SLASH
+U+2299 "(.)"		# CIRCLED DOT OPERATOR
+U+229A "(o)"		# CIRCLED RING OPERATOR
+U+229B "(*)"		# CIRCLED ASTERISK OPERATOR
+U+229C "(=)"		# CIRCLED EQUALS
+U+229D "(-)"		# CIRCLED DASH
+U+229E "[+]"		# SQUARED PLUS
+U+229F "[-]"		# SQUARED MINUS
+U+22A0 "[x]"		# SQUARED TIMES
+U+22A1 "[.]"		# SQUARED DOT OPERATOR
 U+22a5:-T
-U+22c5:.P
+U+22A7 " MODELS "		# MODELS
+U+22A8 " TRUE "		# TRUE
+U+22A9 " FORCES "		# FORCES
+U+22AC " !PROVES "		# DOES NOT PROVE
+U+22AD " NOT TRUE "		# NOT TRUE
+U+22AE " !FORCES "		# DOES NOT FORCE
+U+22B2 " NORMAL SUBGROUP OF "
+U+22B3 " CONTAINS AS NORMAL SUBGROUP "
+U+22B4 " NORMAL SUBGROUP OF OR EQUAL TO "
+U+22B5 " CONTAINS AS NORMAL SUBGROUP OR EQUAL TO "
+U+22B8 " MULTIMAP "		# MULTIMAP
+U+22BA " INTERCALATE "		# INTERCALATE
+U+22BB " XOR "		# XOR
+U+22BC " NAND "		# NAND
+U+22C5 " DOT "		# DOT OPERATOR
+U+22d6:<.
+U+22d7:>.
+U+22d8:<<<
+U+22d9:>>>
 U+22ee::3
 U+22ef:.3
 U+2302:Eh
+U+2307:~~
 U+2308:<7
 U+2309:>7
 U+230a:7<
@@ -1529,7 +1645,10 @@ U+2315:TR
 U+2318:88
 U+2320:Iu
 U+2321:Il
+U+2322::(
 U+2323::)
+U+2324:|^|
+U+2327:[X]
 U+2329:</
 U+232a:/>
 U+2423:Vs
@@ -1716,16 +1835,16 @@ U+25a9:RX
 U+25aa:sB
 U+25ac:SR
 U+25ad:Or
-U+25b2:UT
+U+25b2:^
 U+25b3:uT
-U+25b6:PR
+U+25b6:|>
 U+25b7:Tr
-U+25ba:PR
-U+25bc:Dt
+U+25ba:|>
+U+25bc:v
 U+25bd:dT
-U+25c0:PL
+U+25c0:<|
 U+25c1:Tl
-U+25c4:PL
+U+25c4:<|
 U+25c6:Db
 U+25c7:Dw
 U+25ca:LZ
@@ -1745,6 +1864,9 @@ U+260e:TEL
 U+260f:tel
 U+261c:<--
 U+261e:-->
+U+2621 "CAUTION "
+U+2627:XP
+U+2639::-(
 U+263a::-)
 U+263b:(-:
 U+263c:SU
@@ -1792,6 +1914,7 @@ U+3016:(I
 U+3017:)I
 U+301c:-?
 U+3020:=T:)
+0x20	U+303f
 U+3041:A5
 U+3042:a5
 U+3043:I5
@@ -2163,6 +2286,11 @@ U+fefa:lh.
 U+fefb:la-
 U+fefc:la.
 
+0x21-0x7e	U+ff01-U+ff5e
+0x2e	U+ff61
+0x22	U+ff62	U+ff63
+0x2c	U+ff64
+
 # Symbols for C0 and C1 control characters, in case they get through...
 U+0000:NUL
 U+0001:SH
@@ -2207,6 +2335,7 @@ U+007f:DT
 #U+0083:NH
 #U+0084:IN
 #U+0085:NL
+U+0085 "\012"
 #U+0086:SA
 #U+0087:ES
 #U+0088:HS
@@ -2236,5 +2365,5 @@ U+007f:DT
 
 # Let's try to show a question mark for character that cannot
 # be shown.  U+fffd is used for invalid characters.
-# It works, but let's stick with UHHH representatiion. - FM
-#U+fffd:?
+# It works, but let's stick with UHHH representation. - FM
+#U+fffd "?"
diff --git a/src/chrtrans/iso01_uni.tbl b/src/chrtrans/iso01_uni.tbl
index 2d138ec2..5a47e2f8 100644
--- a/src/chrtrans/iso01_uni.tbl
+++ b/src/chrtrans/iso01_uni.tbl
@@ -52,6 +52,9 @@ C819
 #
 #	Any comments or problems, contact <John_Jenkins@taligent.com>
 #
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
+#
 0x20-0x7e idem
 0xa0-0xff idem  #  iso 8859-1 special: trivial mapping to Unicode
 #
@@ -150,7 +153,7 @@ C819
 #0x7C	U+007C	#	VERTICAL LINE
 #0x7D	U+007D	#	RIGHT CURLY BRACKET
 #0x7E	U+007E	#	TILDE
-#0xA0	U+00A0	#	NO-BREAK SPACE
+0xA0	U+00A0	U+2007	#	NO-BREAK SPACE
 #0xA1	U+00A1	#	INVERTED EXCLAMATION MARK
 #0xA2	U+00A2	#	CENT SIGN
 #0xA3	U+00A3	#	POUND SIGN
@@ -158,23 +161,23 @@ C819
 #0xA5	U+00A5	#	YEN SIGN
 #0xA6	U+00A6	#	BROKEN BAR
 #0xA7	U+00A7	#	SECTION SIGN
-#0xA8	U+00A8	#	DIAERESIS
+0xA8	U+00A8	U+0308	#	DIAERESIS
 #0xA9	U+00A9	#	COPYRIGHT SIGN
 #0xAA	U+00AA	#	FEMININE ORDINAL INDICATOR
 #0xAB	U+00AB	#	LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
 #0xAC	U+00AC	#	NOT SIGN
 #0xAD	U+00AD	#	SOFT HYPHEN
 #0xAE	U+00AE	#	REGISTERED SIGN
-#0xAF	U+00AF	#	MACRON
-#0xB0	U+00B0	#	DEGREE SIGN
+0xAF	U+00AF	U+0304	#	MACRON
+0xB0	U+00B0	U+030a	#	DEGREE SIGN
 #0xB1	U+00B1	#	PLUS-MINUS SIGN
 #0xB2	U+00B2	#	SUPERSCRIPT TWO
 #0xB3	U+00B3	#	SUPERSCRIPT THREE
 #0xB4	U+00B4	#	ACUTE ACCENT
-#0xB5	U+00B5	#	MICRO SIGN
+0xB5	U+00B5	U+03bc	#	MICRO SIGN
 #0xB6	U+00B6	#	PILCROW SIGN
-#0xB7	U+00B7	#	MIDDLE DOT
-#0xB8	U+00B8	#	CEDILLA
+0xB7	U+00B7	U+0307	U+0387	U+2027	#	MIDDLE DOT
+0xB8	U+00B8	U+0327	#	CEDILLA
 #0xB9	U+00B9	#	SUPERSCRIPT ONE
 #0xBA	U+00BA	#	MASCULINE ORDINAL INDICATOR
 #0xBB	U+00BB	#	RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -250,4 +253,11 @@ C819
 
 0xd0	U+0110	# Dstrok and ETH are nearly the same...
 
-U+2297 "(\327)"
+U+2218 " \260 "		# RING OPERATOR
+U+221b " ROOT\263 "
+U+2297 "(\327)"		# CIRCLED TIMES
+U+2299 "(\267)"		# CIRCLED DOT OPERATOR
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+22A0 "[\327]"		# SQUARED TIMES
+U+22A1 "[\267]"		# SQUARED DOT OPERATOR
+U+22C5 " \267 "		# DOT OPERATOR
diff --git a/src/chrtrans/iso02_uni.tbl b/src/chrtrans/iso02_uni.tbl
index 383b4674..b245be55 100644
--- a/src/chrtrans/iso02_uni.tbl
+++ b/src/chrtrans/iso02_uni.tbl
@@ -46,6 +46,9 @@ C912
 #
 #	Any comments or problems, contact <John_Jenkins@taligent.com>
 #
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
+#
 0x20-0x7e idem
 #
 #0x20	U+0020	#	SPACE
@@ -145,35 +148,35 @@ C912
 #0x7E	U+007E	#	TILDE
 0xA0	U+00A0	#	NO-BREAK SPACE
 0xA1	U+0104	#	LATIN CAPITAL LETTER A WITH OGONEK
-0xA2	U+02D8	#	BREVE
+0xA2	U+02D8	U+0306	#	BREVE
 0xA3	U+0141	#	LATIN CAPITAL LETTER L WITH STROKE
 0xA4	U+00A4	#	CURRENCY SIGN
 0xA5	U+013D	#	LATIN CAPITAL LETTER L WITH CARON
 0xA6	U+015A	#	LATIN CAPITAL LETTER S WITH ACUTE
 0xA7	U+00A7	#	SECTION SIGN
-0xA8	U+00A8	#	DIAERESIS
-0xA9	U+0160	#	LATIN CAPITAL LETTER S WITH CARON
+0xA8	U+00A8	U+0308	#	DIAERESIS
+0xA9	U+0160	U+0428	#	LATIN CAPITAL LETTER S WITH CARON
 0xAA	U+015E	#	LATIN CAPITAL LETTER S WITH CEDILLA
 0xAB	U+0164	#	LATIN CAPITAL LETTER T WITH CARON
 0xAC	U+0179	#	LATIN CAPITAL LETTER Z WITH ACUTE
 0xAD	U+00AD	#	SOFT HYPHEN
-0xAE	U+017D	#	LATIN CAPITAL LETTER Z WITH CARON
+0xAE	U+017D	U+0416	#	LATIN CAPITAL LETTER Z WITH CARON
 0xAF	U+017B	#	LATIN CAPITAL LETTER Z WITH DOT ABOVE
-0xB0	U+00B0	#	DEGREE SIGN
+0xB0	U+00B0	U+030a	#	DEGREE SIGN
 0xB1	U+0105	#	LATIN SMALL LETTER A WITH OGONEK
-0xB2	U+02DB	#	OGONEK
+0xB2	U+02DB	U+0328	#	OGONEK
 0xB3	U+0142	#	LATIN SMALL LETTER L WITH STROKE
 0xB4	U+00B4	#	ACUTE ACCENT
 0xB5	U+013E	#	LATIN SMALL LETTER L WITH CARON
 0xB6	U+015B	#	LATIN SMALL LETTER S WITH ACUTE
-0xB7	U+02C7	#	CARON
-0xB8	U+00B8	#	CEDILLA
-0xB9	U+0161	#	LATIN SMALL LETTER S WITH CARON
+0xB7	U+02C7	U+030c	#	CARON
+0xB8	U+00B8	U+0327	#	CEDILLA
+0xB9	U+0161	U+0448	#	LATIN SMALL LETTER S WITH CARON
 0xBA	U+015F	#	LATIN SMALL LETTER S WITH CEDILLA
 0xBB	U+0165	#	LATIN SMALL LETTER T WITH CARON
 0xBC	U+017A	#	LATIN SMALL LETTER Z WITH ACUTE
-0xBD	U+02DD	#	DOUBLE ACUTE ACCENT
-0xBE	U+017E	#	LATIN SMALL LETTER Z WITH CARON
+0xBD	U+02DD	U+030b	#	DOUBLE ACUTE ACCENT
+0xBE	U+017E	U+0436	#	LATIN SMALL LETTER Z WITH CARON
 0xBF	U+017C	#	LATIN SMALL LETTER Z WITH DOT ABOVE
 0xC0	U+0154	#	LATIN CAPITAL LETTER R WITH ACUTE
 0xC1	U+00C1	#	LATIN CAPITAL LETTER A WITH ACUTE
@@ -183,7 +186,7 @@ C912
 0xC5	U+0139	#	LATIN CAPITAL LETTER L WITH ACUTE
 0xC6	U+0106	#	LATIN CAPITAL LETTER C WITH ACUTE
 0xC7	U+00C7	#	LATIN CAPITAL LETTER C WITH CEDILLA
-0xC8	U+010C	#	LATIN CAPITAL LETTER C WITH CARON
+0xC8	U+010C	U+0427	#	LATIN CAPITAL LETTER C WITH CARON
 0xC9	U+00C9	#	LATIN CAPITAL LETTER E WITH ACUTE
 0xCA	U+0118	#	LATIN CAPITAL LETTER E WITH OGONEK
 0xCB	U+00CB	#	LATIN CAPITAL LETTER E WITH DIAERESIS
@@ -198,7 +201,7 @@ C912
 0xD4	U+00D4	#	LATIN CAPITAL LETTER O WITH CIRCUMFLEX
 0xD5	U+0150	#	LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
 0xD6	U+00D6	#	LATIN CAPITAL LETTER O WITH DIAERESIS
-0xD7	U+00D7	#	MULTIPLICATION SIGN
+0xD7	U+00D7	U+00b7	#	MULTIPLICATION SIGN
 0xD8	U+0158	#	LATIN CAPITAL LETTER R WITH CARON
 0xD9	U+016E	#	LATIN CAPITAL LETTER U WITH RING ABOVE
 0xDA	U+00DA	#	LATIN CAPITAL LETTER U WITH ACUTE
@@ -215,7 +218,7 @@ C912
 0xE5	U+013A	#	LATIN SMALL LETTER L WITH ACUTE
 0xE6	U+0107	#	LATIN SMALL LETTER C WITH ACUTE
 0xE7	U+00E7	#	LATIN SMALL LETTER C WITH CEDILLA
-0xE8	U+010D	#	LATIN SMALL LETTER C WITH CARON
+0xE8	U+010D	U+02a7	U+0447	#	LATIN SMALL LETTER C WITH CARON
 0xE9	U+00E9	#	LATIN SMALL LETTER E WITH ACUTE
 0xEA	U+0119	#	LATIN SMALL LETTER E WITH OGONEK
 0xEB	U+00EB	#	LATIN SMALL LETTER E WITH DIAERESIS
@@ -238,8 +241,15 @@ C912
 0xFC	U+00FC	#	LATIN SMALL LETTER U WITH DIAERESIS
 0xFD	U+00FD	#	LATIN SMALL LETTER Y WITH ACUTE
 0xFE	U+0163	#	LATIN SMALL LETTER T WITH CEDILLA
-0xFF	U+02D9	#	DOT ABOVE
+0xFF	U+02D9	U+0307	U+0387	#	DOT ABOVE
 
 
 0xd0	U+00d0	# Dstrok and ETH are nearly the same...
 
+U+2218 " \260 "		# RING OPERATOR
+U+2297 "(\327)"		# CIRCLED TIMES
+U+2299 "(\377)"		# CIRCLED DOT OPERATOR
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+22A0 "[\327]"		# SQUARED TIMES
+U+22A1 "[\377]"		# SQUARED DOT OPERATOR
+U+22C5 " \377 "		# DOT OPERATOR
diff --git a/src/chrtrans/iso05_uni.tbl b/src/chrtrans/iso05_uni.tbl
index 1436a687..7eeba113 100644
--- a/src/chrtrans/iso05_uni.tbl
+++ b/src/chrtrans/iso05_uni.tbl
@@ -46,6 +46,9 @@ C915
 #
 #	Any comments or problems, contact <John_Jenkins@taligent.com>
 #
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
+#
 0x20-0x7e idem
 #
 #0x20	U+0020	#	SPACE
@@ -149,8 +152,8 @@ C915
 0xA3	U+0403	#	CYRILLIC CAPITAL LETTER GJE
 0xA4	U+0404	#	CYRILLIC CAPITAL LETTER UKRAINIAN IE
 0xA5	U+0405	#	CYRILLIC CAPITAL LETTER DZE
-0xA6	U+0406	#	CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
-0xA7	U+0407	#	CYRILLIC CAPITAL LETTER YI
+0xA6	U+0406	U+0130	#	CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0xA7	U+0407	U+03AA	#	CYRILLIC CAPITAL LETTER YI
 0xA8	U+0408	#	CYRILLIC CAPITAL LETTER JE
 0xA9	U+0409	#	CYRILLIC CAPITAL LETTER LJE
 0xAA	U+040A	#	CYRILLIC CAPITAL LETTER NJE
@@ -162,28 +165,28 @@ C915
 0xB0	U+0410	#	CYRILLIC CAPITAL LETTER A
 0xB1	U+0411	#	CYRILLIC CAPITAL LETTER BE
 0xB2	U+0412	#	CYRILLIC CAPITAL LETTER VE
-0xB3	U+0413	#	CYRILLIC CAPITAL LETTER GHE
+0xB3	U+0413	U+0393	#	CYRILLIC CAPITAL LETTER GHE
 0xB4	U+0414	#	CYRILLIC CAPITAL LETTER DE
 0xB5	U+0415	#	CYRILLIC CAPITAL LETTER IE
-0xB6	U+0416	#	CYRILLIC CAPITAL LETTER ZHE
+0xB6	U+0416	U+017d	#	CYRILLIC CAPITAL LETTER ZHE
 0xB7	U+0417	#	CYRILLIC CAPITAL LETTER ZE
 0xB8	U+0418	#	CYRILLIC CAPITAL LETTER I
 0xB9	U+0419	#	CYRILLIC CAPITAL LETTER SHORT I
 0xBA	U+041A	#	CYRILLIC CAPITAL LETTER KA
-0xBB	U+041B	#	CYRILLIC CAPITAL LETTER EL
+0xBB	U+041B	U+039b	#	CYRILLIC CAPITAL LETTER EL
 0xBC	U+041C	#	CYRILLIC CAPITAL LETTER EM
 0xBD	U+041D	#	CYRILLIC CAPITAL LETTER EN
 0xBE	U+041E	#	CYRILLIC CAPITAL LETTER O
-0xBF	U+041F	#	CYRILLIC CAPITAL LETTER PE
+0xBF	U+041F	U+03a0	#	CYRILLIC CAPITAL LETTER PE
 0xC0	U+0420	#	CYRILLIC CAPITAL LETTER ER
 0xC1	U+0421	#	CYRILLIC CAPITAL LETTER ES
 0xC2	U+0422	#	CYRILLIC CAPITAL LETTER TE
 0xC3	U+0423	#	CYRILLIC CAPITAL LETTER U
-0xC4	U+0424	#	CYRILLIC CAPITAL LETTER EF
+0xC4	U+0424	U+03a6	#	CYRILLIC CAPITAL LETTER EF
 0xC5	U+0425	#	CYRILLIC CAPITAL LETTER HA
 0xC6	U+0426	#	CYRILLIC CAPITAL LETTER TSE
-0xC7	U+0427	#	CYRILLIC CAPITAL LETTER CHE
-0xC8	U+0428	#	CYRILLIC CAPITAL LETTER SHA
+0xC7	U+0427	U+010c	#	CYRILLIC CAPITAL LETTER CHE
+0xC8	U+0428	U+0160	#	CYRILLIC CAPITAL LETTER SHA
 0xC9	U+0429	#	CYRILLIC CAPITAL LETTER SHCHA
 0xCA	U+042A	#	CYRILLIC CAPITAL LETTER HARD SIGN
 0xCB	U+042B	#	CYRILLIC CAPITAL LETTER YERU
@@ -197,28 +200,28 @@ C915
 0xD3	U+0433	#	CYRILLIC SMALL LETTER GHE
 0xD4	U+0434	#	CYRILLIC SMALL LETTER DE
 0xD5	U+0435	#	CYRILLIC SMALL LETTER IE
-0xD6	U+0436	#	CYRILLIC SMALL LETTER ZHE
+0xD6	U+0436	U+017e	#	CYRILLIC SMALL LETTER ZHE
 0xD7	U+0437	#	CYRILLIC SMALL LETTER ZE
 0xD8	U+0438	#	CYRILLIC SMALL LETTER I
 0xD9	U+0439	#	CYRILLIC SMALL LETTER SHORT I
 0xDA	U+043A	#	CYRILLIC SMALL LETTER KA
-0xDB	U+043B	#	CYRILLIC SMALL LETTER EL
+0xDB	U+043B	U+03bb	#	CYRILLIC SMALL LETTER EL
 0xDC	U+043C	#	CYRILLIC SMALL LETTER EM
 0xDD	U+043D	#	CYRILLIC SMALL LETTER EN
 0xDE	U+043E	#	CYRILLIC SMALL LETTER O
-0xDF	U+043F	#	CYRILLIC SMALL LETTER PE
+0xDF	U+043F	U+03c0	#	CYRILLIC SMALL LETTER PE
 0xE0	U+0440	#	CYRILLIC SMALL LETTER ER
 0xE1	U+0441	#	CYRILLIC SMALL LETTER ES
 0xE2	U+0442	#	CYRILLIC SMALL LETTER TE
 0xE3	U+0443	#	CYRILLIC SMALL LETTER U
-0xE4	U+0444	#	CYRILLIC SMALL LETTER EF
+0xE4	U+0444	U+03c6	#	CYRILLIC SMALL LETTER EF
 0xE5	U+0445	#	CYRILLIC SMALL LETTER HA
 0xE6	U+0446	#	CYRILLIC SMALL LETTER TSE
-0xE7	U+0447	#	CYRILLIC SMALL LETTER CHE
-0xE8	U+0448	#	CYRILLIC SMALL LETTER SHA
+0xE7	U+0447	U+010d	#	CYRILLIC SMALL LETTER CHE
+0xE8	U+0448	U+0161	#	CYRILLIC SMALL LETTER SHA
 0xE9	U+0449	#	CYRILLIC SMALL LETTER SHCHA
 0xEA	U+044A	#	CYRILLIC SMALL LETTER HARD SIGN
-0xEB	U+044B	#	CYRILLIC SMALL LETTER YERU
+0xEB	U+044B	U+0131	#	CYRILLIC SMALL LETTER YERU
 0xEC	U+044C	#	CYRILLIC SMALL LETTER SOFT SIGN
 0xED	U+044D	#	CYRILLIC SMALL LETTER E
 0xEE	U+044E	#	CYRILLIC SMALL LETTER YU
@@ -230,7 +233,7 @@ C915
 0xF4	U+0454	#	CYRILLIC SMALL LETTER UKRAINIAN IE
 0xF5	U+0455	#	CYRILLIC SMALL LETTER DZE
 0xF6	U+0456	#	CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
-0xF7	U+0457	#	CYRILLIC SMALL LETTER YI
+0xF7	U+0457	U+03CA	#	CYRILLIC SMALL LETTER YI
 0xF8	U+0458	#	CYRILLIC SMALL LETTER JE
 0xF9	U+0459	#	CYRILLIC SMALL LETTER LJE
 0xFA	U+045A	#	CYRILLIC SMALL LETTER NJE
@@ -240,3 +243,7 @@ C915
 0xFE	U+045E	#	CYRILLIC SMALL LETTER SHORT U
 0xFF	U+045F	#	CYRILLIC SMALL LETTER DZHE
 
+U+0400 "`\265"
+U+040d "`\270"
+U+0450 "`\325"
+U+045d "`\330"
diff --git a/src/chrtrans/iso07_uni.tbl b/src/chrtrans/iso07_uni.tbl
index 7e9063ec..458c2389 100644
--- a/src/chrtrans/iso07_uni.tbl
+++ b/src/chrtrans/iso07_uni.tbl
@@ -46,6 +46,9 @@ C813
 #
 #	Any comments or problems, contact <John_Jenkins@taligent.com>
 #
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
+#
 0x20-0x7e idem
 #
 #0x20	U+0020	#	SPACE
@@ -161,20 +164,20 @@ C813
 0xB3	U+00B3	#	SUPERSCRIPT THREE
 0xB4	U+0384	#	GREEK TONOS
 0xB5	U+0385	#	GREEK DIALYTIKA TONOS
-0xB6	U+0386	#	GREEK CAPITAL LETTER ALPHA WITH TONOS
-0xB7	U+00B7	#	MIDDLE DOT
-0xB8	U+0388	#	GREEK CAPITAL LETTER EPSILON WITH TONOS
-0xB9	U+0389	#	GREEK CAPITAL LETTER ETA WITH TONOS
-0xBA	U+038A	#	GREEK CAPITAL LETTER IOTA WITH TONOS
+0xB6	U+0386	U+1fbb	#	GREEK CAPITAL LETTER ALPHA WITH TONOS
+0xB7	U+00B7	U+0307	U+0387	U+2027	#	MIDDLE DOT
+0xB8	U+0388	U+1fc9	#	GREEK CAPITAL LETTER EPSILON WITH TONOS
+0xB9	U+0389	U+1fcb	#	GREEK CAPITAL LETTER ETA WITH TONOS
+0xBA	U+038A	U+1fdb	#	GREEK CAPITAL LETTER IOTA WITH TONOS
 0xBB	U+00BB	#	RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
-0xBC	U+038C	#	GREEK CAPITAL LETTER OMICRON WITH TONOS
+0xBC	U+038C	U+1ff9	#	GREEK CAPITAL LETTER OMICRON WITH TONOS
 0xBD	U+00BD	#	VULGAR FRACTION ONE HALF
-0xBE	U+038E	#	GREEK CAPITAL LETTER UPSILON WITH TONOS
-0xBF	U+038F	#	GREEK CAPITAL LETTER OMEGA WITH TONOS
+0xBE	U+038E	U+1feb	#	GREEK CAPITAL LETTER UPSILON WITH TONOS
+0xBF	U+038F	U+1ffb	#	GREEK CAPITAL LETTER OMEGA WITH TONOS
 0xC0	U+0390	#	GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
 0xC1	U+0391	#	GREEK CAPITAL LETTER ALPHA
 0xC2	U+0392	#	GREEK CAPITAL LETTER BETA
-0xC3	U+0393	#	GREEK CAPITAL LETTER GAMMA
+0xC3	U+0393	U+0413	#	GREEK CAPITAL LETTER GAMMA
 0xC4	U+0394	#	GREEK CAPITAL LETTER DELTA
 0xC5	U+0395	#	GREEK CAPITAL LETTER EPSILON
 0xC6	U+0396	#	GREEK CAPITAL LETTER ZETA
@@ -182,39 +185,39 @@ C813
 0xC8	U+0398	#	GREEK CAPITAL LETTER THETA
 0xC9	U+0399	#	GREEK CAPITAL LETTER IOTA
 0xCA	U+039A	#	GREEK CAPITAL LETTER KAPPA
-0xCB	U+039B	#	GREEK CAPITAL LETTER LAMDA
+0xCB	U+039B	U+041b	#	GREEK CAPITAL LETTER LAMDA
 0xCC	U+039C	#	GREEK CAPITAL LETTER MU
 0xCD	U+039D	#	GREEK CAPITAL LETTER NU
 0xCE	U+039E	#	GREEK CAPITAL LETTER XI
 0xCF	U+039F	#	GREEK CAPITAL LETTER OMICRON
-0xD0	U+03A0	#	GREEK CAPITAL LETTER PI
+0xD0	U+03A0	U+041f	#	GREEK CAPITAL LETTER PI
 0xD1	U+03A1	#	GREEK CAPITAL LETTER RHO
 0xD3	U+03A3	#	GREEK CAPITAL LETTER SIGMA
 0xD4	U+03A4	#	GREEK CAPITAL LETTER TAU
 0xD5	U+03A5	#	GREEK CAPITAL LETTER UPSILON
-0xD6	U+03A6	#	GREEK CAPITAL LETTER PHI
-0xD7	U+03A7	#	GREEK CAPITAL LETTER CHI
+0xD6	U+03A6	U+0424	#	GREEK CAPITAL LETTER PHI
+0xD7	U+03A7	U+0425	#	GREEK CAPITAL LETTER CHI
 0xD8	U+03A8	#	GREEK CAPITAL LETTER PSI
 0xD9	U+03A9	#	GREEK CAPITAL LETTER OMEGA
 0xDA	U+03AA	#	GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
 0xDB	U+03AB	#	GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
-0xDC	U+03AC	#	GREEK SMALL LETTER ALPHA WITH TONOS
-0xDD	U+03AD	#	GREEK SMALL LETTER EPSILON WITH TONOS
-0xDE	U+03AE	#	GREEK SMALL LETTER ETA WITH TONOS
-0xDF	U+03AF	#	GREEK SMALL LETTER IOTA WITH TONOS
+0xDC	U+03AC	U+1f71	#	GREEK SMALL LETTER ALPHA WITH TONOS
+0xDD	U+03AD	U+1f73	#	GREEK SMALL LETTER EPSILON WITH TONOS
+0xDE	U+03AE	U+1f75	#	GREEK SMALL LETTER ETA WITH TONOS
+0xDF	U+03AF	U+1f77	#	GREEK SMALL LETTER IOTA WITH TONOS
 0xE0	U+03B0	#	GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
 0xE1	U+03B1	#	GREEK SMALL LETTER ALPHA
 0xE2	U+03B2	#	GREEK SMALL LETTER BETA
-0xE3	U+03B3	#	GREEK SMALL LETTER GAMMA
-0xE4	U+03B4	#	GREEK SMALL LETTER DELTA
+0xE3	U+03B3	U+0263	#	GREEK SMALL LETTER GAMMA
+0xE4	U+03B4	U+00f0	#	GREEK SMALL LETTER DELTA
 0xE5	U+03B5	#	GREEK SMALL LETTER EPSILON
 0xE6	U+03B6	#	GREEK SMALL LETTER ZETA
 0xE7	U+03B7	#	GREEK SMALL LETTER ETA
 0xE8	U+03B8	#	GREEK SMALL LETTER THETA
-0xE9	U+03B9	#	GREEK SMALL LETTER IOTA
+0xE9	U+03B9	U+0131	#	GREEK SMALL LETTER IOTA
 0xEA	U+03BA	#	GREEK SMALL LETTER KAPPA
 0xEB	U+03BB	#	GREEK SMALL LETTER LAMDA
-0xEC	U+03BC	#	GREEK SMALL LETTER MU
+0xEC	U+03BC	U+00b5	#	GREEK SMALL LETTER MU
 0xED	U+03BD	#	GREEK SMALL LETTER NU
 0xEE	U+03BE	#	GREEK SMALL LETTER XI
 0xEF	U+03BF	#	GREEK SMALL LETTER OMICRON
@@ -223,14 +226,20 @@ C813
 0xF2	U+03C2	#	GREEK SMALL LETTER FINAL SIGMA
 0xF3	U+03C3	#	GREEK SMALL LETTER SIGMA
 0xF4	U+03C4	#	GREEK SMALL LETTER TAU
-0xF5	U+03C5	#	GREEK SMALL LETTER UPSILON
+0xF5	U+03C5	U+028a	#	GREEK SMALL LETTER UPSILON
 0xF6	U+03C6	#	GREEK SMALL LETTER PHI
 0xF7	U+03C7	#	GREEK SMALL LETTER CHI
 0xF8	U+03C8	#	GREEK SMALL LETTER PSI
 0xF9	U+03C9	#	GREEK SMALL LETTER OMEGA
 0xFA	U+03CA	#	GREEK SMALL LETTER IOTA WITH DIALYTIKA
-0xFB	U+03CB	#	GREEK SMALL LETTER UPSILON WITH DIALYTIKA
-0xFC	U+03CC	#	GREEK SMALL LETTER OMICRON WITH TONOS
-0xFD	U+03CD	#	GREEK SMALL LETTER UPSILON WITH TONOS
-0xFE	U+03CE	#	GREEK SMALL LETTER OMEGA WITH TONOS
+0xFB	U+03CB	U+00fc	#	GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+0xFC	U+03CC	U+1f79	#	GREEK SMALL LETTER OMICRON WITH TONOS
+0xFD	U+03CD	U+1f7b	#	GREEK SMALL LETTER UPSILON WITH TONOS
+0xFE	U+03CE	U+1f7d	#	GREEK SMALL LETTER OMEGA WITH TONOS
 
+U+2218 " \260 "		# RING OPERATOR
+U+2209 " !\345 "
+U+221b " ROOT\263 "
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+02a4 "d\346"
+U+20af "\304\361\367"
diff --git a/src/chrtrans/iso09_uni.tbl b/src/chrtrans/iso09_uni.tbl
index 0b93209c..5dc9660c 100644
--- a/src/chrtrans/iso09_uni.tbl
+++ b/src/chrtrans/iso09_uni.tbl
@@ -46,7 +46,11 @@ C920
 #
 #	Any comments or problems, contact <John_Jenkins@taligent.com>
 #
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
+#
 0x20-0x7e idem
+0x49	U+042b
 #
 #0x20	U+0020	#	SPACE
 #0x21	U+0021	#	EXCLAMATION MARK
@@ -151,23 +155,23 @@ C920
 0xA5	U+00A5	#	YEN SIGN
 0xA6	U+00A6	#	BROKEN BAR
 0xA7	U+00A7	#	SECTION SIGN
-0xA8	U+00A8	#	DIAERESIS
+0xA8	U+00A8	U+0308	#	DIAERESIS
 0xA9	U+00A9	#	COPYRIGHT SIGN
 0xAA	U+00AA	#	FEMININE ORDINAL INDICATOR
 0xAB	U+00AB	#	LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
 0xAC	U+00AC	#	NOT SIGN
 0xAD	U+00AD	#	SOFT HYPHEN
 0xAE	U+00AE	#	REGISTERED SIGN
-0xAF	U+00AF	#	MACRON
-0xB0	U+00B0	#	DEGREE SIGN
+0xAF	U+00AF	U+0304	#	MACRON
+0xB0	U+00B0	U+030a	#	DEGREE SIGN
 0xB1	U+00B1	#	PLUS-MINUS SIGN
 0xB2	U+00B2	#	SUPERSCRIPT TWO
 0xB3	U+00B3	#	SUPERSCRIPT THREE
 0xB4	U+00B4	#	ACUTE ACCENT
-0xB5	U+00B5	#	MICRO SIGN
+0xB5	U+00B5	U+03bc	#	MICRO SIGN
 0xB6	U+00B6	#	PILCROW SIGN
-0xB7	U+00B7	#	MIDDLE DOT
-0xB8	U+00B8	#	CEDILLA
+0xB7	U+00B7	U+0307	U+0387	#	MIDDLE DOT
+0xB8	U+00B8	U+0327	#	CEDILLA
 0xB9	U+00B9	#	SUPERSCRIPT ONE
 0xBA	U+00BA	#	MASCULINE ORDINAL INDICATOR
 0xBB	U+00BB	#	RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -204,8 +208,8 @@ C920
 0xDA	U+00DA	#	LATIN CAPITAL LETTER U WITH ACUTE
 0xDB	U+00DB	#	LATIN CAPITAL LETTER U WITH CIRCUMFLEX
 0xDC	U+00DC	#	LATIN CAPITAL LETTER U WITH DIAERESIS
-0xDD	U+0130	#	LATIN CAPITAL LETTER I WITH DOT ABOVE
-0xDE	U+015E	#	LATIN CAPITAL LETTER S WITH CEDILLA
+0xDD	U+0130	U+0418	U+0406	#	LATIN CAPITAL LETTER I WITH DOT ABOVE
+0xDE	U+015E	U+0428	#	LATIN CAPITAL LETTER S WITH CEDILLA
 0xDF	U+00DF	#	LATIN SMALL LETTER SHARP S
 0xE0	U+00E0	#	LATIN SMALL LETTER A WITH GRAVE
 0xE1	U+00E1	#	LATIN SMALL LETTER A WITH ACUTE
@@ -236,7 +240,15 @@ C920
 0xFA	U+00FA	#	LATIN SMALL LETTER U WITH ACUTE
 0xFB	U+00FB	#	LATIN SMALL LETTER U WITH CIRCUMFLEX
 0xFC	U+00FC	#	LATIN SMALL LETTER U WITH DIAERESIS
-0xFD	U+0131	#	LATIN SMALL LETTER DOTLESS I
-0xFE	U+015F	#	LATIN SMALL LETTER S WITH CEDILLA
+0xFD	U+0131	U+03b9	U+044b	#	LATIN SMALL LETTER DOTLESS I
+0xFE	U+015F	U+0448	#	LATIN SMALL LETTER S WITH CEDILLA
 0xFF	U+00FF	#	LATIN SMALL LETTER Y WITH DIAERESIS
 
+U+2218 " \260 "		# RING OPERATOR
+U+221b " ROOT\263 "
+U+2297 "(\327)"		# CIRCLED TIMES
+U+2299 "(\267)"		# CIRCLED DOT OPERATOR
+U+229A "(\260)"		# CIRCLED RING OPERATOR
+U+22A0 "[\327]"		# SQUARED TIMES
+U+22A1 "[\267]"		# SQUARED DOT OPERATOR
+U+22C5 " \267 "		# DOT OPERATOR
diff --git a/src/chrtrans/koi8r_uni.tbl b/src/chrtrans/koi8r_uni.tbl
index 1378eed9..8bf4001a 100644
--- a/src/chrtrans/koi8r_uni.tbl
+++ b/src/chrtrans/koi8r_uni.tbl
@@ -11,6 +11,9 @@ C878
 # Based on a table received from "Glenn E. Thobe" <thobe@lafn.org>
 # (verified against RFC1489).
 #
+#   Lines with more than one Unicode (U+XXXX) value contain additional
+#   replacement mappings added for lynx. - kw
+#
 #hex unicode # description
 #--- U+---- # ---------------
 0x80 U+2500 # FORMS LIGHT HORIZONTAL
@@ -43,7 +46,7 @@ C878
 0x9B U+2321 # BOTTOM HALF INTEGRAL
 0x9C U+00B0 # DEGREE SIGN
 0x9D U+00B2 # SUPERSCRIPT DIGIT TWO
-0x9E U+00B7 # MIDDLE DOT
+0x9E U+00B7 U+2027	# MIDDLE DOT
 0x9F U+00F7 # DIVISION SIGN
 0xA0 U+2550 # FORMS DOUBLE HORIZONTAL
 0xA1 U+2551 # FORMS DOUBLE VERTICAL
@@ -83,31 +86,31 @@ C878
 0xC3 U+0446 # SMA TSE
 0xC4 U+0434 # SMA DE
 0xC5 U+0435 # SMA IE
-0xC6 U+0444 # SMA EF
+0xC6 U+0444 U+03c6	# SMA EF
 0xC7 U+0433 # SMA GE
 0xC8 U+0445 # SMA KHA
 0xC9 U+0438 # SMA II
 0xCA U+0439 # SMA SHORT II
 0xCB U+043A # SMA KA
-0xCC U+043B # SMA EL
+0xCC U+043B U+03bb	# SMA EL
 0xCD U+043C # SMA EM
 0xCE U+043D # SMA EN
 0xCF U+043E # SMA O
-0xD0 U+043F # SMA PE
+0xD0 U+043F U+03c0	# SMA PE
 0xD1 U+044F # SMA IA
 0xD2 U+0440 # SMA ER
 0xD3 U+0441 # SMA ES
 0xD4 U+0442 # SMA TE
 0xD5 U+0443 # SMA U
-0xD6 U+0436 # SMA ZHE
+0xD6 U+0436 U+017e	# SMA ZHE
 0xD7 U+0432 # SMA VE
 0xD8 U+044C # SMA SOFT SIGN
-0xD9 U+044B # SMA YERI
+0xD9 U+044B U+0131	# SMA YERI
 0xDA U+0437 # SMA ZE
-0xDB U+0448 # SMA SHA
+0xDB U+0448 U+0161	# SMA SHA
 0xDC U+044D # SMA REVERSED E
 0xDD U+0449 # SMA SHCHA
-0xDE U+0447 # SMA CHE
+0xDE U+0447 U+010d	# SMA CHE
 0xDF U+044A # SMA HARD SIGN
 0xE0 U+042E # CAP IU
 0xE1 U+0410 # CAP A
@@ -115,30 +118,30 @@ C878
 0xE3 U+0426 # CAP TSE
 0xE4 U+0414 # CAP DE
 0xE5 U+0415 # CAP IE
-0xE6 U+0424 # CAP EF
-0xE7 U+0413 # CAP GE
+0xE6 U+0424 U+03a6	# CAP EF
+0xE7 U+0413 U+0393	# CAP GE
 0xE8 U+0425 # CAP KHA
 0xE9 U+0418 # CAP II
 0xEA U+0419 # CAP SHORT II
 0xEB U+041A # CAP KA
-0xEC U+041B # CAP EL
+0xEC U+041B U+039b	# CAP EL
 0xED U+041C # CAP EM
 0xEE U+041D # CAP EN
 0xEF U+041E # CAP O
-0xF0 U+041F # CAP PE
+0xF0 U+041F U+03a0	# CAP PE
 0xF1 U+042F # CAP IA
 0xF2 U+0420 # CAP ER
 0xF3 U+0421 # CAP ES
 0xF4 U+0422 # CAP TE
 0xF5 U+0423 # CAP U
-0xF6 U+0416 # CAP ZHE
+0xF6 U+0416 U+017d	# CAP ZHE
 0xF7 U+0412 # CAP VE
 0xF8 U+042C # CAP SOFT SIGN
 0xF9 U+042B # CAP YERI
 0xFA U+0417 # CAP ZE
-0xFB U+0428 # CAP SHA
+0xFB U+0428 U+0160	# CAP SHA
 0xFC U+042D # CAP REVERSED E
 0xFD U+0429 # CAP SHCHA
-0xFE U+0427 # CAP CHE
+0xFE U+0427 U+010c	# CAP CHE
 0xFF U+042A # CAP HARD SIGN
 
diff --git a/src/chrtrans/mac_uni.tbl b/src/chrtrans/mac_uni.tbl
index ea76d078..c2457e7b 100644
--- a/src/chrtrans/mac_uni.tbl
+++ b/src/chrtrans/mac_uni.tbl
@@ -80,6 +80,8 @@ OMacintosh (8 bit)
 #   interpreted (if at all) as the control codes DC1-DC4.
 #
 ##################
+# Lines with more than one Unicode (U+XXXX) value contain additional
+# replacement mappings added for lynx. - kw
 
 #0x20    U+0020  # SPACE
 #0x21    U+0021  # EXCLAMATION MARK
@@ -276,7 +278,7 @@ OMacintosh (8 bit)
 0xDE    U+FB01  # LATIN SMALL LIGATURE FI
 0xDF    U+FB02  # LATIN SMALL LIGATURE FL
 0xE0    U+2021  # DOUBLE DAGGER
-0xE1    U+00B7  # MIDDLE DOT
+0xE1    U+00B7  U+0307	U+0387	U+2027	# MIDDLE DOT
 0xE2    U+201A  # SINGLE LOW-9 QUOTATION MARK
 0xE3    U+201E  # DOUBLE LOW-9 QUOTATION MARK
 0xE4    U+2030  # PER MILLE SIGN
diff --git a/src/chrtrans/makeuctb.c b/src/chrtrans/makeuctb.c
index 8c333d90..9ad80ecb 100644
--- a/src/chrtrans/makeuctb.c
+++ b/src/chrtrans/makeuctb.c
@@ -89,7 +89,7 @@ PUBLIC int strncasecomp ARGS3(
     CONST char *q = b;
 
     for (p = a, q = b; ; p++, q++) {
-        int diff;
+	int diff;
 	if (p == (a+n))
 	    return 0;	/*   Match up to n characters */
 	if (!(*p && *q))
@@ -136,6 +136,8 @@ PRIVATE int Raw_found = 0;		/* whether explicit R directive found */
 PRIVATE int CodePage = 0;
 PRIVATE int CodePage_found = 0;		/* whether explicit C directive found */
 
+#define MAX_UNIPAIRS 2500
+
 PRIVATE void addpair_str ARGS2(
 	char *,		str,
 	int,		un)
@@ -147,8 +149,8 @@ PRIVATE void addpair_str ARGS2(
 	    /*
 	     *  Initialize the map for replacement strings.
 	     */
-	    themap_str.entries =
-	  (struct unipair_str *) malloc (2000 * sizeof (struct unipair_str));
+	    themap_str.entries = (struct unipair_str *) malloc (MAX_UNIPAIRS
+				* sizeof (struct unipair_str));
 	    if (!themap_str.entries) {
 		fprintf(stderr,
 			"%s: Out of memory\n", tblname);
@@ -169,9 +171,10 @@ PRIVATE void addpair_str ARGS2(
 	/*
 	 *  Add to list.
 	 */
-	if (themap_str.entry_ct > 1999) {
+	if (themap_str.entry_ct > MAX_UNIPAIRS-1) {
 	    fprintf(stderr,
-		"ERROR: Only 2000 unicode replacement strings permitted!\n");
+		    "ERROR: Only %d unicode replacement strings permitted!\n",
+		    MAX_UNIPAIRS);
 	    done(EX_DATAERR);
 	}
 	themap_str.entries[themap_str.entry_ct].unicode = un;
@@ -187,7 +190,7 @@ PRIVATE void addpair ARGS2(
 {
     int i;
 
-    if (!Raw_found) {       /* enc not (yet) explicitly given with 'R' */
+    if (!Raw_found) {	/* enc not (yet) explicitly given with 'R' */
 	if (fp >= 128) {
 	    if (RawOrEnc != UCT_ENC_8BIT && RawOrEnc <= UCT_ENC_8859) {
 		if (fp < 160) {	/* cannot be 8859 */
@@ -391,7 +394,7 @@ PUBLIC int main ARGS2(
 		}
 		p++;
 		while (*p == ' ' || *p == '\t') {
-	  	    p++;
+		    p++;
 		}
 		RawOrEnc = strtol(p,0,10);
 		Raw_found = 1;
@@ -400,7 +403,7 @@ PUBLIC int main ARGS2(
 	    /*
 	     *  Is this the default table?
 	     */
- 	    case 'D':
+	    case 'D':
 		if (p[1] == 'e' || p[1] == 'E') {
 		    buffer[sizeof(buffer) - 1] = '\0';
 		    if (!strncasecomp(p, "Default", 7)) {
@@ -417,7 +420,7 @@ PUBLIC int main ARGS2(
 	    /*
 	     *  Is this the default table?
 	     */
- 	    case 'F':
+	    case 'F':
 		if (p[1] == 'a' || p[1] == 'A') {
 		    buffer[sizeof(buffer) - 1] = '\0';
 		    if (!strncasecomp(p, "FallBack", 8)) {
@@ -477,7 +480,7 @@ PUBLIC int main ARGS2(
 		}
 		p++;
 		while (*p == ' ' || *p == '\t') {
-	  	    p++;
+		    p++;
 		}
 		CodePage = strtol(p,0,10);
 		CodePage_found = 1;
@@ -587,7 +590,7 @@ PUBLIC int main ARGS2(
 	if (p1 == p) {
 	    fprintf(stderr, "Bad input line: %s\n", buffer);
 	    done(EX_DATAERR);
-        }
+	}
 	p = p1;
 
 	while (*p == ' ' || *p == '\t') {
@@ -601,7 +604,7 @@ PUBLIC int main ARGS2(
 		done(EX_DATAERR);
 	    }
 	    p = p1;
-        } else {
+	} else {
 	    fp1 = 0;
 	}
 
@@ -643,7 +646,7 @@ PUBLIC int main ARGS2(
 		    fprintf(stderr,
 			    " there should be a Unicode range.\n");
 		    done(EX_DATAERR);
-	        }
+		}
 		p++;
 		un1 = getunicode(&p);
 		if (un0 < 0 || un1 < 0) {
@@ -651,7 +654,7 @@ PUBLIC int main ARGS2(
      "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
 			    tblname, fp0, fp1);
 		    done(EX_DATAERR);
-	        }
+		}
 		if (un1 - un0 != fp1 - fp0) {
 		    fprintf(stderr,
 			"%s: Unicode range U+%x-U+%x not of the same length",
@@ -660,7 +663,7 @@ PUBLIC int main ARGS2(
 			    " as font position range 0x%x-0x%x\n",
 			    fp0, fp1);
 		    done(EX_DATAERR);
-	        }
+		}
 		for (i = fp0; i <= fp1; i++) {
 		    addpair(i,un0-fp0+i);
 		}
@@ -752,8 +755,8 @@ PUBLIC int main ARGS2(
 	this_isDefaultMap = !strncmp(this_MIMEcharset,"iso-8859-1", 10);
     }
     fprintf(stderr,
-    	    "makeuctb: %s: %stranslation map",
- 	    this_MIMEcharset, (this_isDefaultMap ? "default " : ""));
+	    "makeuctb: %s: %stranslation map",
+	    this_MIMEcharset, (this_isDefaultMap ? "default " : ""));
     if (this_isDefaultMap == 1) {
 	*id_append = '\0';
     } else {
@@ -808,7 +811,7 @@ static CONST u8 dfont_unicount%s[%d] = \n\
 
     if (nuni) {
 	fprintf(chdr, "\nstatic CONST u16 dfont_unitable%s[%d] = \n{\n\t",
-	       id_append, nuni);
+		id_append, nuni);
     } else {
 	fprintf(chdr, "\nstatic CONST u16 dfont_unitable%s[1]; /* dummy */\n", id_append);
     }
@@ -841,8 +844,8 @@ static struct unipair_str repl_map%s[%d] = \n\
 
     for (i = 0; i < themap_str.entry_ct; i++) {
 	fprintf(chdr, "{0x%x,\"%s\"}",
-	       themap_str.entries[i].unicode,
-	       themap_str.entries[i].replace_str);
+		themap_str.entries[i].unicode,
+		themap_str.entries[i].replace_str);
 	if (i == (themap_str.entry_ct - 1)) {
 	    fprintf(chdr, "\n};\n");
 	} else if ((i % 4) == 3) {
diff --git a/src/makefile.dos b/src/makefile.dos
index a10c0b2d..98b57662 100644
--- a/src/makefile.dos
+++ b/src/makefile.dos
@@ -7,7 +7,7 @@ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
 HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \
 LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
 LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \
-LYStyle.o LYHash.o LYPrettySrc.o
+LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o
 
 CFLAGS= $(MCFLAGS) -I. -I.. $(SLANGINC)
 
diff --git a/src/makefile.dsl b/src/makefile.dsl
index 9eb56338..093bcb0c 100644
--- a/src/makefile.dsl
+++ b/src/makefile.dsl
@@ -7,7 +7,7 @@ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
 HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \
 LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
 LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \
-LYStyle.o LYHash.o LYPrettySrc.o
+LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o
 
 CFLAGS= $(MCFLAGS) $(INTLFLAGS) -I. -I.. $(SLANGINC)
 
diff --git a/src/makefile.in b/src/makefile.in
index 67dc920b..89e8ef71 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -67,7 +67,7 @@ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
 HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \
 LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
 LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \
-LYStyle.o LYHash.o LYPrettySrc.o $(CHARTRANS_OBJS) @LIBOBJS@
+LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o $(CHARTRANS_OBJS) @LIBOBJS@
 
 C_SRC	= $(OBJS:.o=.c)
 
diff --git a/src/makefile.wsl b/src/makefile.wsl
index a97b51bf..97f488d9 100644
--- a/src/makefile.wsl
+++ b/src/makefile.wsl
@@ -7,7 +7,7 @@ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
 HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \
 LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
 LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \
-LYStyle.o LYHash.o LYPrettySrc.o
+LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o
 
 CFLAGS= $(MCFLAGS) -I. -I.. $(SLANGINC)