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.c630
-rw-r--r--src/GridText.h5
-rw-r--r--src/HTAlert.c37
-rw-r--r--src/HTML.c175
-rw-r--r--src/HTML.h3
-rw-r--r--src/HTNestedList.h2
-rw-r--r--src/LYCharUtils.c29
-rw-r--r--src/LYCurses.c13
-rw-r--r--src/LYForms.c2
-rw-r--r--src/LYGlobalDefs.h2
-rw-r--r--src/LYHistory.c6
-rw-r--r--src/LYKeymap.c10
-rw-r--r--src/LYKeymap.h4
-rw-r--r--src/LYLeaks.c348
-rw-r--r--src/LYLocal.c20
-rw-r--r--src/LYMain.c27
-rw-r--r--src/LYMainLoop.c164
-rw-r--r--src/LYMap.c2
-rw-r--r--src/LYOptions.c2
-rw-r--r--src/LYPrettySrc.c112
-rw-r--r--src/LYPrettySrc.h21
-rw-r--r--src/LYPrint.c7
-rw-r--r--src/LYReadCFG.c27
-rw-r--r--src/LYStrings.c154
-rw-r--r--src/LYStrings.h5
-rw-r--r--src/LYUtils.c100
-rw-r--r--src/TRSTable.c229
-rw-r--r--src/TRSTable.h10
-rw-r--r--src/UCAuto.c8
-rw-r--r--src/UCdomap.c2
-rw-r--r--src/chrtrans/cp1253_uni.tbl4
-rw-r--r--src/chrtrans/cp869_uni.tbl4
-rw-r--r--src/chrtrans/iso07_uni.tbl13
-rw-r--r--src/makefile.dos16
-rw-r--r--src/makefile.in5
35 files changed, 1725 insertions, 473 deletions
diff --git a/src/GridText.c b/src/GridText.c
index 6b89dc21..8aae54af 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -92,6 +92,7 @@ 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)
+/* a test in compact form: how many extra UTF-8 chars after initial? - kw */
 #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)))
 
@@ -144,12 +145,22 @@ PUBLIC int LYsb_end = -1;
 #if defined(USE_COLOR_STYLE)
 #define MAX_STYLES_ON_LINE 64
 
+#ifdef OLD_HTSTYLECHANGE
 typedef struct _stylechange {
 	int	horizpos;	/* horizontal position of this change */
 	int	style;		/* which style to change to */
 	int	direction;	/* on or off */
 	int	previous;	/* previous style */
 } HTStyleChange;
+#else
+    /*try to fit in 2 shorts*/
+typedef struct _stylechange {
+	unsigned int	direction:2;	/* on or off */
+	unsigned int	horizpos: (sizeof(short)*CHAR_BIT-2);
+	    /* horizontal position of this change */
+	unsigned short	style;		/* which style to change to */
+} HTStyleChange;
+#endif
 #endif
 
 typedef struct _line {
@@ -161,12 +172,134 @@ typedef struct _line {
 	BOOL	bullet;			/* Do we bullet? */
 	BOOL	expansion_line;		/* TEXTAREA edit new line flag */
 #if defined(USE_COLOR_STYLE)
+#ifdef OLD_HTSTYLECHANGE
 	HTStyleChange	styles[MAX_STYLES_ON_LINE];
+#else
+	HTStyleChange* styles;
+#endif
 	int	numstyles;
 #endif
 	char	data[1];		/* Space for terminator at least! */
 } HTLine;
 
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+typedef struct _HTStyleChangePool {
+	HTStyleChange	data[4092];
+	struct _HTStyleChangePool* next;
+	int free_items;
+} HTStyleChangePool;
+
+/*these are used when current line is being aggregated. */
+HTStyleChange stylechanges_buffers[2][MAX_STYLES_ON_LINE];
+int stylechanges_buffers_free;/*this is an index of the free buffer.
+    Can be 0 or 1*/
+
+/* These are generic macors for any pools (provided those structures have the
+same members as HTStyleChangePool).  Pools are used for allocation of groups of
+objects of the same type T.  Pools are represented as a list of structures of
+type P (called pool chunks here).  Structure P has an array of N objects of
+type T named 'data' (the number N in the array can be chosen arbitrary),
+pointer to the next pool chunk named 'pool', and the number of free items in
+that pool chunk named 'free_items'.  Here is a definition of the structure P:
+	struct P
+	{
+	    T data[N];
+	    struct P* next;
+	    int free_items;
+	};
+ It's recommended that sizeof(P) be memory page size minus 32 in order malloc'd
+chunks to fit in machine page size.
+ Allocation of 'n' items in the pool is implemented by decrementing member
+'free_items' by 'n' if 'free_items' >= 'n', or allocating a new pool chunk and
+allocating 'n' items in that new chunk.  It's the task of the programmer to
+assert that 'n' is <= N.  Only entire pool may be freed - this limitation makes
+allocation algorithms trivial and fast - so the use of pools is limited to
+objects that are freed in batch, that are not deallocated not in the batch, and
+not reallocated.
+ Pools greatly reduce memory fragmentation and memory allocation/deallocation
+speed due to the simple algorithms used.  Due to the fact that memory is
+'allocated' in array, alignment overhead is minimal.  Allocating strings in a
+pool provided their length will never exceed N and is much smaller than N seems
+to be very efficient.
+
+ Pool are referenced by pointer to the chunk that contains free slots. Macros
+that allocate memory in pools update that pointer if needed.
+ There are 3 macros that deal with pools - POOL_NEW, POOL_FREE and
+ALLOC_IN_POOL.
+ Here is a description of those macros as C++ functions (with names mentioned
+above and with use of C++ references)
+
+void ALLOC_IN_POOL( P*& pool, pool_type, int toalloc, T*& ptr)
+    - allocates 'toalloc' items in the pool of type 'pool_type' pointed by
+    'pool', sets the pointer 'ptr' to the "allocated" memory and updates 'pool'
+    if necessary. Sets 'ptr' to NULL if fails.
+
+void POOL_NEW( pool_type  , P*& ptr)
+    Initializes a pool of type 'pool_type' pointed by 'ptr', updating 'ptr'.
+    Sets 'ptr' to NULL if fails.
+
+void POOL_FREE( pool_type , P* ptr)
+    Frees a pool of type 'pool_type' pointed by ptr.
+
+      - VH */
+
+/*
+void ALLOC_IN_POOL( P*& pool, pool_type, int toalloc, T*& ptr)
+    - allocates 'toalloc' items in the pool of type 'pool_type' pointed by
+    'pool', sets the pointer 'ptr' to the "allocated" memory and updates 'pool'
+    if necessary. Sets 'ptr' to NULL if fails.
+*/
+#define ALLOC_IN_POOL(pool,pool_type,toalloc,ptr)     \
+if (!pool)  \
+    ptr = NULL; \
+else { \
+    if ((pool)->free_items > toalloc) { \
+	(pool)->free_items -= toalloc; \
+	ptr = (pool)->data + (pool)->free_items; \
+    } else { \
+	pool_type* newpool = (pool_type*)malloc(sizeof(pool_type)); \
+	if (!newpool) { \
+	    ptr = NULL; \
+	} else { \
+	    newpool->next = pool; \
+	    newpool->free_items = sizeof newpool->data/ \
+		    sizeof newpool->data[0] - toalloc; \
+	    pool = newpool; \
+	    ptr = newpool->data + sizeof newpool->data/sizeof newpool->data[0] - toalloc; \
+	} \
+    } \
+}
+/*
+void POOL_NEW( pool_type  , P*& ptr)
+    Initializes a pool of type 'pool_type' pointed by 'ptr', updating 'ptr'.
+    Sets 'ptr' to NULL if fails.
+*/
+#define POOL_NEW(pool_type,ptr) \
+    { \
+	pool_type* newpool = (pool_type*)malloc(sizeof(pool_type)); \
+	if (!newpool) { \
+	    ptr = NULL; \
+	} else { \
+	    newpool->next = NULL; \
+	    newpool->free_items = sizeof newpool->data/sizeof newpool->data[0]; \
+	    ptr = newpool; \
+	} \
+    }
+/*
+void POOL_FREE( pool_type , P* ptr)
+    Frees a pool of type 'pool_type' pointed by ptr.
+*/
+#define POOL_FREE(pool_type,xptr) \
+    { \
+	pool_type* ptr = xptr; \
+	do { \
+	    pool_type* prevpool = ptr; \
+	    ptr = ptr->next; \
+	    FREE(prevpool); \
+	} while (ptr); \
+    }
+#endif
+
 #define LINE_SIZE(l) (sizeof(HTLine)+(l))	/* Allow for terminator */
 
 typedef struct _TextAnchor {
@@ -245,6 +378,7 @@ struct _HText {
 	BOOL			stale;			/* Must refresh */
 	BOOL			page_has_target; /* has target on screen */
 	BOOL			has_utf8; /* has utf-8 on screen or line */
+	BOOL			had_utf8; /* had utf-8 when last displayed */
 #ifdef DISP_PARTIAL
 	int			first_lineno_last_disp_partial;
 	int			last_lineno_last_disp_partial;
@@ -267,6 +401,9 @@ struct _HText {
 
 	HTStream *		target;			/* Output stream */
 	HTStreamClass		targetClass;		/* Output routines */
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+	HTStyleChangePool*	styles_pool;
+#endif
 };
 
 PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor));
@@ -552,6 +689,22 @@ PUBLIC HText *	HText_new ARGS1(
     CTRACE((tfp, "GridText: VMTotal = %d\n", VMTotal));
 #endif /* VMS && VAXC && !__DECC */
 
+    /*
+     *  If the previously shown text had UTF-8 characters on screen,
+     *  remember this in the newly created object.  Do this now, before
+     *  the previous object may become invalid. - kw
+     */
+    if (HTMainText) {
+	if (HText_hasUTF8OutputSet(HTMainText) &&
+	    HTLoadedDocumentEightbit() &&
+	    LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
+	    self->had_utf8 = HTMainText->has_utf8;
+	} else {
+	    self->had_utf8 = HTMainText->has_utf8;
+	}
+	HTMainText->has_utf8 = NO;
+    }
+
     if (!loaded_texts)	{
 	loaded_texts = HTList_new();
 #ifdef LY_FIND_LEAKS
@@ -597,6 +750,13 @@ PUBLIC HText *	HText_new ARGS1(
     line->offset = line->size = 0;
 #ifdef USE_COLOR_STYLE
     line->numstyles = 0;
+#ifndef  OLD_HTSTYLECHANGE
+    POOL_NEW(HTStyleChangePool,self->styles_pool);
+    if (!self->styles_pool)
+	outofmem(__FILE__, "HText_New");
+    stylechanges_buffers_free = 0;
+    line->styles = stylechanges_buffers[0];
+#endif
 #endif
     self->Lines = self->chars = 0;
     self->first_anchor = self->last_anchor = NULL;
@@ -757,7 +917,9 @@ PUBLIC void HText_free ARGS1(
 	return;
 
     HTAnchor_setDocument(self->node_anchor, (HyperDoc *)0);
-
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+    POOL_FREE(HTStyleChangePool,self->styles_pool);
+#endif
     while (YES) {	/* Free off line array */
 	HTLine * l = self->last_line;
 	if (l) {
@@ -967,13 +1129,13 @@ PRIVATE int display_line ARGS4(
 	if (case_sensitive)
 	    cp_tgt = LYno_attr_mbcs_strstr(data,
 					   target,
-					   text->T.output_utf8,
+					   text->T.output_utf8, YES,
 					   &HitOffset,
 					   &LenNeeded);
 	else
 	    cp_tgt = LYno_attr_mbcs_case_strstr(data,
 						target,
-						text->T.output_utf8,
+						text->T.output_utf8, YES,
 						&HitOffset,
 						&LenNeeded);
 	if (cp_tgt) {
@@ -1001,13 +1163,13 @@ PRIVATE int display_line ARGS4(
 		if (case_sensitive)
 		    cp_tgt = LYno_attr_mbcs_strstr(data,
 						target,
-						text->T.output_utf8,
+						text->T.output_utf8, YES,
 						&HitOffset,
 						&LenNeeded);
 		else
 		    cp_tgt = LYno_attr_mbcs_case_strstr(data,
 						     target,
-						text->T.output_utf8,
+						text->T.output_utf8, YES,
 						&HitOffset,
 						&LenNeeded);
 		if (cp_tgt) {
@@ -1135,7 +1297,7 @@ PRIVATE int display_line ARGS4(
 #endif /* SHOW_WHEREIS_TARGETS */
 #endif /* USE_COLOR_STYLE */
 		i++;
-		if (text->T.output_utf8 && !isascii(buffer[0])) {
+		if (text->T.output_utf8 && !isascii((unsigned char)buffer[0])) {
 		    text->has_utf8 = YES;
 		    if ((*buffer & 0xe0) == 0xc0) {
 			utf_extra = 1;
@@ -1168,7 +1330,7 @@ PRIVATE int display_line ARGS4(
 		    buffer[1] = '\0';
 		    data += utf_extra;
 		    utf_extra = 0;
-		} else if (HTCJK != NOCJK && !isascii(buffer[0])) {
+		} else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) {
 		    /*
 		     *  For CJK strings, by Masanobu Kimura.
 		     */
@@ -1677,7 +1839,14 @@ PRIVATE void display_page ARGS3(
     if (line) {
 #if defined(USE_COLOR_STYLE) && defined(SHOW_WHEREIS_TARGETS)
 	char *data;
-	int offset, HitOffset, LenNeeded;
+	int offset, LenNeeded;
+#endif
+#ifdef DISP_PARTIAL
+	if (display_partial ||
+	    line_number != text->first_lineno_last_disp_partial)
+	    text->has_utf8 = NO;
+#else
+	text->has_utf8 = NO;
 #endif
 	for (i = 0; i < (display_lines); i++)  {
 	    /*
@@ -1722,13 +1891,13 @@ PRIVATE void display_page ARGS3(
 		   (case_sensitive ?
 		    (cp = LYno_attr_mbcs_strstr(data,
 						target,
-						text->T.output_utf8,
-						&HitOffset,
+						text->T.output_utf8, YES,
+						NULL,
 						&LenNeeded)) != NULL :
 		    (cp = LYno_attr_mbcs_case_strstr(data,
 						     target,
-						text->T.output_utf8,
-						&HitOffset,
+						text->T.output_utf8, YES,
+						NULL,
 						&LenNeeded)) != NULL) &&
 		   ((int)line->offset + LenNeeded) < LYcols) {
 		int itmp = 0;
@@ -1767,7 +1936,7 @@ PRIVATE void display_page ARGS3(
 			/*
 			 *  Output all the printable target chars.
 			 */
-			if (text->T.output_utf8 && !isascii(tmp[0])) {
+			if (text->T.output_utf8 && !isascii((unsigned char)tmp[0])) {
 			    if ((*tmp & 0xe0) == 0xc0) {
 				utf_extra = 1;
 			    } else if ((*tmp & 0xf0) == 0xe0) {
@@ -1799,7 +1968,7 @@ PRIVATE void display_page ARGS3(
 			    tmp[1] = '\0';
 			    written += (utf_extra + 1);
 			    utf_extra = 0;
-			} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			} else if (HTCJK != NOCJK && !isascii((unsigned char)tmp[0])) {
 			    /*
 			     *  For CJK strings, by Masanobu Kimura.
 			     */
@@ -2072,11 +2241,12 @@ PRIVATE void display_page ARGS3(
     }
 #endif /* DISP_PARTIAL */
 
-    if (text->has_utf8) {
+    if (text->has_utf8 || text->had_utf8) {
 	/*
 	 *  For other than ncurses, repainting is taken care of
 	 *  by touching lines in display_line and highlight. - kw 1999-10-07
 	 */
+	text->had_utf8 = text->has_utf8;
 	clearok(curscr, TRUE);
     } else if (HTCJK != NOCJK) {
 	/*
@@ -2087,7 +2257,6 @@ PRIVATE void display_page ARGS3(
 	/*clearok(curscr, TRUE);*/
     }
     refresh();
-
 }
 
 
@@ -2107,13 +2276,18 @@ 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 */
+   difference via SLANG_MBCS_HACK.  Checks of the line length (as the
+   non-UTF-8-aware display library would see it) against LYcols_cu are
+   is used to try to prevent that lines with UTF-8 chars get wrapped
+   by the library when they shouldn't.
+   If there is no display library involved, i.e. dump_output_immediately,
+   no such limit should be imposed.  LYcols*6 should be just as good
+   as any other large value.  (But don't use INT_MAX or something close
+   to it to, avoid over/underflow.) - kw */
 #ifdef USE_SLANG
-#define LYcols_cu SLtt_Screen_Cols
+#define LYcols_cu (dump_output_immediately ? LYcols*6 : SLtt_Screen_Cols)
 #else
-#define LYcols_cu LYcols
+#define LYcols_cu (dump_output_immediately ? LYcols*6 : LYcols)
 #endif
 
 /*	Add a new line of text
@@ -2147,6 +2321,7 @@ PRIVATE void split_line ARGS2(
 #endif
     int indent = text->in_line_1 ?
 	  text->style->indent1st : text->style->leftIndent;
+    short alignment;
     TextAnchor * a;
     int CurLine = text->Lines;
     int HeadTrim = 0;
@@ -2166,7 +2341,9 @@ PRIVATE void split_line ARGS2(
     HTLine * line = (HTLine *)LY_CALLOC(1, LINE_SIZE(MAX_LINE)+2);
     if (line == NULL)
 	outofmem(__FILE__, "split_line_1");
-
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+    line->styles = stylechanges_buffers[stylechanges_buffers_free = (stylechanges_buffers_free + 1) &1];
+#endif
     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 = ' ';
@@ -2219,6 +2396,7 @@ PRIVATE void split_line ARGS2(
 	ctrl_chars_on_this_line++;
     }
 
+    alignment = style->alignment;
     /*
      *  Split at required point
      */
@@ -2251,9 +2429,9 @@ PRIVATE void split_line ARGS2(
 
 		(HeadTrim || text->first_anchor ||
 		 underline_on || bold_on ||
-		 text->style->alignment != HT_LEFT ||
-		 text->style->wordWrap || text->style->freeFormat ||
-		 text->style->spaceBefore || text->style->spaceAfter)) ||
+		 alignment != HT_LEFT ||
+		 style->wordWrap || style->freeFormat ||
+		 style->spaceBefore || style->spaceAfter)) ||
 	       *p == LY_SOFT_HYPHEN) {
 	    p++;
 	    HeadTrim++;
@@ -2383,9 +2561,9 @@ PRIVATE void split_line ARGS2(
 #endif
 	   (ctrl_chars_on_this_line || HeadTrim || text->first_anchor ||
 	    underline_on || bold_on ||
-	    text->style->alignment != HT_LEFT ||
-	    text->style->wordWrap || text->style->freeFormat ||
-	    text->style->spaceBefore || text->style->spaceAfter)) {
+	    alignment != HT_LEFT ||
+	    style->wordWrap || style->freeFormat ||
+	    style->spaceBefore || style->spaceAfter)) {
 	/*
 	 *  Strip trailers.
 	 */
@@ -2562,6 +2740,12 @@ PRIVATE void split_line ARGS2(
     if (temp == NULL)
 	outofmem(__FILE__, "split_line_2");
     memcpy(temp, previous, LINE_SIZE(previous->size));
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+    ALLOC_IN_POOL((text->styles_pool),HTStyleChangePool,previous->numstyles,temp->styles);
+    memcpy(temp->styles, previous->styles, sizeof(HTStyleChange)*previous->numstyles);
+    if (!temp->styles)
+	outofmem(__FILE__, "split_line_2");
+#endif
     FREE(previous);
     previous = temp;
 
@@ -2581,8 +2765,8 @@ PRIVATE void split_line ARGS2(
 #ifdef EXP_JUSTIFY_ELTS
 	this_line_was_splitted ||
 #endif
-	(style->alignment == HT_CENTER ||
-	 style->alignment == HT_RIGHT) || text->stbl) {
+	(alignment == HT_CENTER ||
+	 alignment == HT_RIGHT) || text->stbl) {
 	/* Calculate spare character positions if needed */
 	for (cp = previous->data; *cp; cp++) {
 	    if (*cp == LY_UNDERLINE_START_CHAR ||
@@ -2600,7 +2784,9 @@ PRIVATE void split_line ARGS2(
 	spare =  (LYcols-1) -
 	    (int)style->rightIndent - indent +
 	    ctrl_chars_on_previous_line - previous->size;
-	if (spare > 0 && text->T.output_utf8 && ctrl_chars_on_previous_line) {
+
+	if (spare > 0 && !dump_output_immediately &&
+	    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) -
@@ -2611,13 +2797,30 @@ PRIVATE void split_line ARGS2(
 		     *  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).
+		     *  having them split by curses.  (Curses cursor movement
+		     *  optimization may still cause wrong positioning within
+		     *  the line, in particular after a sequence of spaces).
 		     * - kw
 		     */
 		if (spare_cu < spare) {
 		    if (spare_cu >= 0) {
-			spare = spare_cu;
+			if (alignment == HT_CENTER &&
+			    (int)(previous->offset + indent + spare/2 +
+				  previous->size)
+			    - ctrl_chars_on_previous_line
+			    + utfxtra_on_previous_line <= (LYcols_cu - 1))
+			    /* do nothing - it still fits - kw */;
+			else {
+			    spare = spare_cu;
+			    if (alignment == HT_CENTER) {
+				/*
+				 *  Can't move towars center all the way,
+				 *  but at least make line contents appear
+				 *  as far right as possible. - kw
+				 */
+				alignment = HT_RIGHT;
+			    }
+			}
 		    } else if (indent + (int)previous->offset + spare_cu >= 0)
 		    { /* subtract overdraft from effective indentation */
 			indent += (int)previous->offset + spare_cu;
@@ -2636,7 +2839,10 @@ PRIVATE void split_line ARGS2(
 	 *  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
+	 *  errors here.
+	 *  This call is down here because we need the
+	 *  ctrl_chars_on_previous_line, which have just been re-
+	 *  counted above. - kw
 	 */
 	Stbl_lineBreak(text->stbl,
 		       text->Lines - 1,
@@ -2848,7 +3054,7 @@ PRIVATE void split_line ARGS2(
 		*jp = ' ';	/* substitute it */
 		continue;
 	    }
-	    if (text->T.output_utf8 && !isascii(c)) {
+	    if (text->T.output_utf8 && !isascii((unsigned char)c)) {
 		int utf_extra = 0;
 		if ((c & 0xe0) == 0xc0) {
 		    utf_extra = 1;
@@ -2877,7 +3083,9 @@ PRIVATE void split_line ARGS2(
 	    jline = (HTLine *)LY_CALLOC(1, LINE_SIZE(previous->size+spare));
 	    if (jline == NULL)
 		outofmem(__FILE__, "split_line_1");
-
+#if defined(USE_COLOR_STYLE) && !defined(OLD_HTSTYLECHANGE)
+	    jline->styles = previous->styles;
+#endif
 	    jdata = jline->data;
 
 	    /*
@@ -2943,8 +3151,9 @@ PRIVATE void split_line ARGS2(
 
 		jline->styles[i].style = previous->styles[i].style;
 		jline->styles[i].direction = previous->styles[i].direction;
+#ifdef OLD_HTSTYLECHANGE
 		jline->styles[i].previous = previous->styles[i].previous;
-
+#endif
 		/*there are stylechanges with hpos > line length */
 		jline->styles[i].horizpos = (hpos > previous->size)
 			? previous->size + spare
@@ -3539,10 +3748,15 @@ PUBLIC void HText_appendCharacter ARGS2(
     }
 
     if (text->T.output_utf8) {
+	/*
+	 *  Some extra checks for UTF-8 output here to make sure
+	 *  memory is not overrun.  For a non-first char, append
+	 *  to the line here and return. - kw
+	 */
 	if (IS_UTF_EXTRA(ch)) {
 	    if ((line->size > (MAX_LINE-1))
 		|| (indent + (int)(line->offset + line->size) +
-		    utfx - ctrl_chars_on_this_line +
+		    utfxtra_on_this_line - ctrl_chars_on_this_line +
 		    ((line->size > 0) &&
 		     (int)(line->data[line->size-1] ==
 				LY_SOFT_HYPHEN ?
@@ -3570,11 +3784,11 @@ PUBLIC void HText_appendCharacter ARGS2(
 	    utfxtra_on_this_line++;
 	    ctrl_chars_on_this_line++;
 	    return;
-	} else if (ch & 0x80) {
+	} else if (ch & 0x80) {	/* a first char of UTF-8 sequence - kw */
 	    if ((line->size > (MAX_LINE-7))
-#if 0	/* the equivalent should already happen below */
+#if 0	/* the equivalent check should already happen below */
 		|| (indent + (int)(line->offset + line->size) +
-		    utfx - ctrl_chars_on_this_line +
+		    utfxtra_on_this_line - ctrl_chars_on_this_line +
 		    ((line->size > 0) &&
 		     (int)(line->data[line->size-1] ==
 				LY_SOFT_HYPHEN ?
@@ -3722,7 +3936,7 @@ PUBLIC void HText_appendCharacter ARGS2(
 	}
 	return;
     } /* if tab */
-    else if (text->source && text == HTMainText) {
+    else if ( (text->source || dont_wrap_pre) && text == HTMainText) {
 	/*
 	 * If we're displaying document source, wrap long lines to keep all of
 	 * the source visible.
@@ -4440,6 +4654,7 @@ PUBLIC void HText_cancelStbl ARGS1(
     Stbl_free(me->stbl);
     me->stbl = NULL;
 }
+
 /*	Start simple table handling
 */
 PUBLIC void HText_startStblTABLE ARGS2(
@@ -4458,6 +4673,7 @@ PUBLIC void HText_startStblTABLE ARGS2(
 	CTRACE((tfp, "startStblTABLE: failed.\n"));
     }
 }
+
 /*	Finish simple table handling
 */
 PUBLIC void HText_endStblTABLE ARGS1(
@@ -4478,6 +4694,7 @@ PUBLIC void HText_endStblTABLE ARGS1(
     Stbl_free(me->stbl);
     me->stbl = NULL;
 }
+
 /*	Start simple table row
 */
 PUBLIC void HText_startStblTR ARGS2(
@@ -4489,6 +4706,7 @@ PUBLIC void HText_startStblTR ARGS2(
     if (Stbl_addRowToTable(me->stbl, alignment, me->Lines) < 0)
 	HText_cancelStbl(me);	/* give up */
 }
+
 /*	Finish simple table row
 */
 PUBLIC void HText_endStblTR ARGS1(
@@ -4498,11 +4716,13 @@ PUBLIC void HText_endStblTR ARGS1(
 	return;
     /* should this do something?? */
 }
-/*	Finish simple table cell
+
+/*	Start simple table cell
 */
-PUBLIC void HText_startStblTD ARGS4(
+PUBLIC void HText_startStblTD ARGS5(
 	HText *,	me,
 	int,		colspan,
+	int,		rowspan,
 	short,		alignment,
 	BOOL,		isheader)
 {
@@ -4510,10 +4730,11 @@ PUBLIC void HText_startStblTD ARGS4(
 	return;
     if (colspan <= 0)
 	colspan = 1;
-    if (Stbl_addCellToTable(me->stbl, colspan, alignment, isheader,
+    if (Stbl_addCellToTable(me->stbl, colspan, rowspan, alignment, isheader,
 			    me->Lines, HText_LastLineSize(me,FALSE)) < 0)
 	HText_cancelStbl(me);	/* give up */
 }
+
 /*	Finish simple table cell
 */
 PUBLIC void HText_endStblTD ARGS1(
@@ -4526,6 +4747,45 @@ PUBLIC void HText_endStblTD ARGS1(
 	HText_cancelStbl(me);	/* give up */
 }
 
+/*	Remember COL info / Start a COLGROUP and remember info
+*/
+PUBLIC void HText_startStblCOL ARGS4(
+	HText *,	me,
+	int,		span,
+	short,		alignment,
+	BOOL,		isgroup)
+{
+    if (!me || !me->stbl)
+	return;
+    if (span <= 0)
+	span = 1;
+    if (Stbl_addColInfo(me->stbl, span, alignment, isgroup) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+
+/*	Finish a COLGROUP
+*/
+PUBLIC void HText_endStblCOLGROUP ARGS1(
+	HText *,	me)
+{
+    if (!me || !me->stbl)
+	return;
+    if (Stbl_finishColGroup(me->stbl) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+
+/*	Start a THEAD / TFOOT / TBODY - remember its alignment info
+*/
+PUBLIC void HText_startStblRowGroup ARGS2(
+	HText *,	me,
+	short,		alignment)
+{
+    if (!me || !me->stbl)
+	return;
+    if (Stbl_addRowGroup(me->stbl, alignment) < 0)
+	HText_cancelStbl(me);	/* give up */
+}
+
 /*		Anchor handling
 **		---------------
 */
@@ -6091,12 +6351,12 @@ PUBLIC BOOL HText_getFirstTargetInLine ARGS7(
     if ((case_sensitive ?
 	 (cp = LYno_attr_mbcs_strstr(LineData,
 				     target,
-				     utf_flag,
+				     utf_flag, YES,
 				     &HitOffset,
 				     &LenNeeded)) != NULL :
 	 (cp = LYno_attr_mbcs_case_strstr(LineData,
 				     target,
-				     utf_flag,
+				     utf_flag, YES,
 				     &HitOffset,
 				     &LenNeeded)) != NULL) &&
 	(LineOffset + LenNeeded) < LYcols) {
@@ -6560,9 +6820,6 @@ PUBLIC BOOL HText_select ARGS1(
 	HText *,	text)
 {
     if (text != HTMainText) {
-	HTMainText = text;
-	HTMainAnchor = text->node_anchor;
-
 	/*
 	 *  Reset flag for whereis search string - cannot be true here
 	 *  since text is not our HTMainText. - kw
@@ -6580,6 +6837,21 @@ PUBLIC BOOL HText_select ARGS1(
 	}
 #endif /* DISP_PARTIAL */
 
+	if (HTMainText) {
+	    if (HText_hasUTF8OutputSet(HTMainText) &&
+		HTLoadedDocumentEightbit() &&
+		LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
+		text->had_utf8 = HTMainText->has_utf8;
+	    } else {
+		text->had_utf8 = NO;
+	    }
+	    HTMainText->has_utf8 = NO;
+	    text->has_utf8 = NO;
+	}
+
+	HTMainText = text;
+	HTMainAnchor = text->node_anchor;
+
 	/*
 	 *  Make this text the most current in the loaded texts list. - FM
 	 */
@@ -7094,17 +7366,18 @@ PUBLIC void print_wwwfile_to_fd ARGS2(
     line = HTMainText->last_line->next;
     for (;; line = line->next) {
 	if (!first
-	 && line->data[0] != LY_SOFT_NEWLINE)
+	 && line->data[0] != LY_SOFT_NEWLINE && line->data[1] != LY_SOFT_NEWLINE) {
+	    /* data[0] can be LY_*START_CHAR, so LY_SOFT_NEWLINE can be in [1] - VH */
 	    fputc('\n',fp);
-	first = FALSE;
-
-	/*
-	 *  Add news-style quotation if requested. - FM
-	 */
-	if (is_reply) {
-	    fputc('>',fp);
+	    /*
+	     *  Add news-style quotation if requested. - FM
+	     */
+	    if (is_reply) {
+		fputc('>',fp);
+	    }
 	}
 
+	first = FALSE;
 	/*
 	 *  Add offset.
 	 */
@@ -7218,7 +7491,8 @@ PUBLIC void print_crawl_to_fd ARGS3(
 
     for (;; line = line->next) {
 	if (!first
-	 && line->data[0] != LY_SOFT_NEWLINE)
+	 && line->data[0] != LY_SOFT_NEWLINE && line->data[1] != LY_SOFT_NEWLINE)
+	    /* data[0] can be LY_*START_CHAR, so LY_SOFT_NEWLINE can be in [1] - VH */
 	    fputc('\n',fp);
 	first = FALSE;
 	/*
@@ -7611,7 +7885,7 @@ PUBLIC void user_message ARGS2(
 	return;
     }
 
-    HTSprintf(&temp, message, (argument == 0) ? "" : argument);
+    HTSprintf0(&temp, message, (argument == 0) ? "" : argument);
 
     statusline(temp);
 
@@ -9492,6 +9766,7 @@ PUBLIC int HText_SubmitForm ARGS4(
     BOOLEAN SemiColon = FALSE;
     char *Boundary = NULL;
     char *MultipartContentType = NULL;
+    char *content_type_out = NULL;
     int target_cs = -1;
     CONST char *out_csname;
     CONST char *target_csname = NULL;
@@ -9731,20 +10006,21 @@ PUBLIC int HText_SubmitForm ARGS4(
     } else {
 	/*
 	 *  We are submitting POST content to a server,
-	 *  so load the post_content_type element. - FM
+	 *  so load content_type_out.  This will be put in
+	 *  the post_content_type element if all goes well. - FM, kw
 	 */
 	if (SemiColon == TRUE) {
-	    StrAllocCopy(doc->post_content_type,
+	    StrAllocCopy(content_type_out,
 			 "application/sgml-form-urlencoded");
 	} else if (PlainText == TRUE) {
-	    StrAllocCopy(doc->post_content_type,
+	    StrAllocCopy(content_type_out,
 			 "text/plain");
 	} else if (Boundary != NULL) {
-	    StrAllocCopy(doc->post_content_type,
+	    StrAllocCopy(content_type_out,
 			 "multipart/form-data; boundary=");
-	    StrAllocCat(doc->post_content_type, Boundary);
+	    StrAllocCat(content_type_out, Boundary);
 	} else {
-	    StrAllocCopy(doc->post_content_type,
+	    StrAllocCopy(content_type_out,
 			 "application/x-www-form-urlencoded");
 	}
 
@@ -9775,8 +10051,8 @@ PUBLIC int HText_SubmitForm ARGS4(
 			  strcmp(target_csname, "iso-8859-1"))) ||
 			(!HTMainText->node_anchor->charset &&
 			 target_cs != UCLYhndl_for_unspec)) {
-			StrAllocCat(doc->post_content_type, "; charset=");
-			StrAllocCat(doc->post_content_type, target_csname);
+			StrAllocCat(content_type_out, "; charset=");
+			StrAllocCat(content_type_out, target_csname);
 		    }
 		}
 	    } else {
@@ -10097,7 +10373,7 @@ PUBLIC int HText_SubmitForm ARGS4(
 		    if ((fd = fopen(val_used, "rb")) == 0) {
 			/* We can't open the file, what do we do? */
 			HTAlert("Can't open file for uploading");
-			return 0;
+			goto exit_disgracefully;
 		    }
 		    StrAllocCopy(escaped2, "");
 		    while ((bytes = fread(buffer, sizeof(char), 45, fd)) != 0) {
@@ -10109,12 +10385,12 @@ PUBLIC int HText_SubmitForm ARGS4(
 			/* We got an error reading the file, what do we do? */
 			HTAlert("Short read from file, problem?");
 			fclose(fd);
-			return 0;
+			goto exit_disgracefully;
 		    }
 		    fclose(fd);
-		    /* we need to modify the mime-type here */
-		    /* could use LYGetFileInfo for that and for other
-		       headers that should be transmitted - kw */
+		    /* we need to modify the mime-type here - rp */
+		    /* Note: could use LYGetFileInfo for that and for
+		       other headers that should be transmitted - kw */
 
 		    HTSprintf(&query,
 				   "%s%s%s%s%s",
@@ -10486,9 +10762,9 @@ PUBLIC int HText_SubmitForm ARGS4(
 			     (HText_getTitle() ?
 			      HText_getTitle() : "")),
 		 query,
-		 doc->post_content_type);
+		 content_type_out);
 	FREE(query);
-	FREE(doc->post_content_type);
+	FREE(content_type_out);
 	return 0;
     } else {
 	_statusline(SUBMITTING_FORM);
@@ -10496,6 +10772,8 @@ PUBLIC int HText_SubmitForm ARGS4(
 
     if (submit_item->submit_method == URL_POST_METHOD || Boundary) {
 	StrAllocCopy(doc->post_data, query);
+	FREE(doc->post_content_type);
+	doc->post_content_type = content_type_out; /* don't free c_t_out */
 	CTRACE((tfp,"GridText - post_data: %s\n",doc->post_data));
 	StrAllocCopy(doc->address, submit_item->submit_action);
 	FREE(query);
@@ -10504,9 +10782,22 @@ PUBLIC int HText_SubmitForm ARGS4(
 	StrAllocCopy(doc->address, query);
 	FREE(doc->post_data);
 	FREE(doc->post_content_type);
+	FREE(content_type_out);
 	FREE(query);
 	return 1;
     }
+#ifdef EXP_FILE_UPLOAD
+exit_disgracefully:
+    FREE(escaped1);
+    FREE(escaped2);
+    FREE(previous_blanks);
+    FREE(copied_name_used);
+    FREE(copied_val_used);
+    FREE(MultipartContentType);
+    FREE(query);
+    FREE(content_type_out);
+    return 0;
+#endif
 }
 
 PUBLIC void HText_DisableCurrentForm NOARGS
@@ -11640,6 +11931,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
     TextAnchor *start_anchor  = NULL;
     TextAnchor *end_anchor    = NULL;
     BOOLEAN	firstanchor   = TRUE;
+    BOOLEAN wrapalert = FALSE;
 
     char	ed_offset[10];
     int		start_line    = 0;
@@ -11661,7 +11953,10 @@ PUBLIC int HText_ExtEditForm ARGS1(
     char       *cp;
     int         match_tag = 0;
     int		newlines  = 0;
-    int		len;
+    int		len, len0, len_in;
+    int		wanted_fieldlen_wrap = -1; /* not yet asked; 0 means don't. */
+    char       *skip_at = NULL;
+    int		skip_num = 0, i;
 
     CTRACE((tfp, "GridText: entered HText_ExtEditForm()\n"));
 
@@ -11780,15 +12075,27 @@ PUBLIC int HText_ExtEditForm ARGS1(
 	((size = stat_info.st_size) == 0)) {
 	size = 0;
 	ebuf = (char *) calloc (1, 1);
+	if (!ebuf)
+	    outofmem(__FILE__, "HText_ExtEditForm");
     } else {
 	ebuf = (char *) calloc (size + 1, (sizeof(char)));
+	if (!ebuf) {
+	    /*
+	     *  This could be huge - don't exit if we don't have enough
+	     *  memory for it.  With some luck, the user may be even able
+	     *  to recover the file manually from the temp space while
+	     *  the lynx session is not over. - kw
+	     */
+	    free(ed_temp);
+	    HTAlwaysAlert(NULL, MEMORY_EXHAUSTED_FILE);
+	    return 0;
+	}
 
 	fp = fopen (ed_temp, "r");
 	size = fread (ebuf, 1, size, fp);
 	fclose (fp);
+	ebuf[size] = '\0';	/* Terminate! - kw */
     }
-    if (ebuf == 0)
-	outofmem(__FILE__, "HText_ExtEditForm");
 
     /*
      *	Nuke any blank lines from the end of the edited data.
@@ -11805,24 +12112,111 @@ PUBLIC int HText_ExtEditForm ARGS1(
 	outofmem(__FILE__, "HText_ExtEditForm");
 
     anchor_ptr = start_anchor;
+    if (anchor_ptr->input_field->size <= 4 ||
+	anchor_ptr->input_field->size >= MAX_LINE)
+	wanted_fieldlen_wrap = 0;
 
-    len = 0;
+    len = len_in = 0;
     lp  = ebuf;
 
     while ((line_cnt <= orig_cnt) || (*lp) || ((len != 0) && (*lp == '\0'))) {
 
+	if (skip_at) {
+	    len0 = skip_at - lp;
+	    strncpy(line, lp, len0);
+	    line[len0] = '\0';
+	    lp = skip_at + skip_num;
+	    skip_at = NULL;
+	    skip_num = 0;
+	} else {
+	    len0 = 0;
+	}
+	line[len0] = '\0';
+
 	if ((cp = strchr (lp, '\n')) != 0)
-	   len = cp - lp;
+	   len = len_in = cp - lp;
 	else
-	   len = strlen (lp);
+	   len = len_in = strlen (lp);
+
+
+	if (wanted_fieldlen_wrap < 0 && !wrapalert &&
+	    len0+len >= anchor_ptr->input_field->size &&
+	    (cp = strchr(lp, ' ')) != NULL &&
+	    (cp-lp) < anchor_ptr->input_field->size - 1) {
+	    LYFixCursesOn("ask for confirmation:");
+	    erase();		/* don't show previous state */
+	    if (HTConfirmDefault(gettext("Wrap lines to fit displayed area?"),
+				 NO)) {
+		wanted_fieldlen_wrap = anchor_ptr->input_field->size - 1;
+	    } else {
+		wanted_fieldlen_wrap = 0;
+	    }
+	}
+	if (wanted_fieldlen_wrap > 0 && len0+len > wanted_fieldlen_wrap) {
+	    for (i = wanted_fieldlen_wrap-len0;
+		 i+len0 >= wanted_fieldlen_wrap/4; i--) {
+		if (isspace((unsigned char)lp[i])) {
+		    len = i + 1;
+		    cp = lp + i;
+		    if (cp[1] != '\n' &&
+			isspace((unsigned char)cp[1]) &&
+			!isspace((unsigned char)cp[2])) {
+			len++;
+			cp++;
+		    }
+		    if (!isspace((unsigned char)cp[1])) {
+			while (*cp && *cp != '\r' && *cp != '\n' &&
+			       (cp - lp) <= len + (3 * wanted_fieldlen_wrap/4))
+			    cp++;	/* search for next line break */
+			if (*cp == '\r' && cp[1] == '\n')
+			    cp++;
+			if (*cp == '\n' &&
+			    (cp[1] == '\r' || cp[1] == '\n' ||
+			     !isspace((unsigned char)cp[1]))) {
+			    *cp = ' ';
+			    while (isspace((unsigned char)*(cp-1))) {
+				skip_num++;
+				cp--;
+			    }
+			    skip_at = cp;
+			}
+		    }
+		    break;
+		}
+	    }
+	}
+	if (wanted_fieldlen_wrap > 0 && len0+len > wanted_fieldlen_wrap) {
+	    i = len-1;
+	    while (len0+i+1 > wanted_fieldlen_wrap &&
+		   isspace((unsigned char)lp[i]))
+		i--;
+	    if (len0+i+1 > wanted_fieldlen_wrap)
+		len = wanted_fieldlen_wrap - len0;
+	}
 
-	if (len >= MAX_LINE - 1)
-	    len = MAX_LINE - 1;
+	if (len0+len >= MAX_LINE) {
+	    if (!wrapalert) {
+		LYFixCursesOn("show alert:");
+		HTAlert(gettext("Very long lines have been wrapped!"));
+		wrapalert = TRUE;
+	    }
+	    /*
+	     *  First try to find a space character for wrapping - kw
+	     */
+	    for (i = MAX_LINE - len0 - 1; i > 0; i--) {
+		if (isspace((unsigned char)lp[i])) {
+		    len = i;
+		    break;
+		}
+	    }
+	    if (len0+len >= MAX_LINE)
+		len = MAX_LINE - len0 - 1;
+	}
 
-	strncpy (line, lp, len);
-	*(line + len) = '\0';
+	strncat (line, lp, len);
+	*(line + len0+len) = '\0';
 
-	cleanup_line_for_textarea (line, len);
+	cleanup_line_for_textarea (line, len0+len);
 
 	/*
 	 *  If there are more lines in the edit buffer than were in the
@@ -11844,7 +12238,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
 	 *  Keep track of 1st blank line in any trailing blank lines, for
 	 *  later cursor repositioning.
 	 */
-	if (len > 0)
+	if (len0+len > 0)
 	    exit_line = 0;
 	else if (exit_line == 0)
 	    exit_line = anchor_ptr->line_num;
@@ -11853,7 +12247,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
 	 *  And do the next line of edited text, for the next anchor ...
 	 */
 	lp += len;
-	if (*lp) lp++;
+	if (*lp && isspace((unsigned char)*lp)) lp++;
 
 	end_anchor = anchor_ptr;
 	anchor_ptr = anchor_ptr->next;
@@ -12013,6 +12407,7 @@ PUBLIC int HText_InsertFile ARGS1(
     TextAnchor *prev_anchor = NULL;
     TextAnchor *end_anchor  = NULL;
     BOOLEAN	firstanchor = TRUE;
+    BOOLEAN truncalert = FALSE;
 
     FormInfo   *form	 = form_link->form;
     char       *areaname = form->name;
@@ -12096,6 +12491,7 @@ PUBLIC int HText_InsertFile ARGS1(
 	size = fread (fbuf, 1, size, fp);
 	fclose (fp);
 	FREE(fn);
+	fbuf[size] = '\0';	/* Terminate! - kw */
     }
 
 
@@ -12248,6 +12644,15 @@ PUBLIC int HText_InsertFile ARGS1(
 	else
 	   len = strlen (lp);
 
+	if (len >= MAX_LINE) {
+	    if (!truncalert) {
+		HTAlert(gettext("Very long lines have been truncated!"));
+		truncalert = TRUE;
+	    }
+	    len = MAX_LINE - 1;
+	    if (lp[len])
+		lp[len+1] = '\0'; /* prevent next iteration */
+	}
 	strncpy (line, lp, len);
 	*(line + len) = '\0';
 
@@ -12422,7 +12827,7 @@ PRIVATE void redraw_part_of_line ARGS4(
 
 	    default:
 		i++;
-		if (text->T.output_utf8 && !isascii(buffer[0])) {
+		if (text->T.output_utf8 && !isascii((unsigned char)buffer[0])) {
 		    if ((*buffer & 0xe0) == 0xc0) {
 			utf_extra = 1;
 		    } else if ((*buffer & 0xf0) == 0xe0) {
@@ -12454,7 +12859,7 @@ PRIVATE void redraw_part_of_line ARGS4(
 		    buffer[1] = '\0';
 		    data += utf_extra;
 		    utf_extra = 0;
-		} else if (HTCJK != NOCJK && !isascii(buffer[0])) {
+		} else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) {
 		    /*
 		     *  For CJK strings, by Masanobu Kimura.
 		     */
@@ -12574,7 +12979,7 @@ PRIVATE void move_to_glyph ARGS10(
     if (i > (int)LYcols - 1)
 	i = (int)LYcols - 1;
 
-    linkvlen = hightext ? LYmbcsstrlen(hightext, utf_flag) : 0;
+    linkvlen = hightext ? LYmbcsstrlen(hightext, utf_flag, YES) : 0;
 
     /*
      *  Scan through the data, making sure that we do not
@@ -12593,13 +12998,13 @@ PRIVATE void move_to_glyph ARGS10(
 	if (case_sensitive)
 	    cp_tgt = LYno_attr_mbcs_strstr(sdata,
 					   target,
-					   utf_flag,
+					   utf_flag, YES,
 					   &HitOffset,
 					   &LenNeeded);
 	else
 	    cp_tgt = LYno_attr_mbcs_case_strstr(sdata,
 						target,
-						utf_flag,
+						utf_flag, YES,
 						&HitOffset,
 						&LenNeeded);
 	if (cp_tgt) {
@@ -12629,9 +13034,9 @@ PRIVATE void move_to_glyph ARGS10(
 	if (data && hightext && i >= XP && !incurlink) {
 
 	/*
-	 *  We reached the position of link itself, and highlight is
+	 *  We reached the position of link itself, and hightext is
 	 *  non-NULL.  We switch data from being a pointer into the HTLine
-	 *  to be a pointer into hightext.  Normally (as long as this
+	 *  to being 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
@@ -12648,7 +13053,7 @@ PRIVATE void move_to_glyph ARGS10(
 	    data = hightext;
 	    len = strlen(hightext);
 	    end_of_data = hightext + len;
-	    XP += linkvlen;
+	    XP += linkvlen;	/* from now on XP includes hightext chars */
 	    incurlink = YES;
 	    if (cp_tgt) {
 		if (flag && i_after_tgt >= XP)
@@ -12725,13 +13130,13 @@ PRIVATE void move_to_glyph ARGS10(
 		else if (case_sensitive)
 		    cp_tgt = LYno_attr_mbcs_strstr(sdata,
 						   target,
-						   utf_flag,
+						   utf_flag, YES,
 						   &HitOffset,
 						   &LenNeeded);
 		else
 		    cp_tgt = LYno_attr_mbcs_case_strstr(sdata,
 							target,
-							utf_flag,
+							utf_flag, YES,
 							&HitOffset,
 							&LenNeeded);
 		if (cp_tgt) {
@@ -12852,10 +13257,21 @@ PRIVATE void move_to_glyph ARGS10(
 		 *  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)
+		if (incurlink && intarget && flag && i_after_tgt > i) {
+		    if (i == XP - 1) {
+			i_after_tgt = i;
+		    } else if (i == XP - 2 && HTCJK != NOCJK &&
+			       !isascii((unsigned char)buffer[0])) {
 			i_after_tgt = i;
+			cp_tgt = NULL;
+			if (drawing) {
+			    if (drawingtarget) {
+				LYstopTargetEmphasis();
+				drawingtarget = NO;
+				lynx_start_link_color (flag, inU);
+			    }
+			}
+		    }
 		}
 		if (cp_tgt && i >= i_start_tgt && sdata > cp_tgt) {
 		    if (!intarget ||
@@ -12952,7 +13368,7 @@ PRIVATE void move_to_glyph ARGS10(
 		    buffer[1] = '\0';
 		    sdata += utf_extra; data += utf_extra;
 		    utf_extra = 0;
-		} else if (HTCJK != NOCJK && !isascii(buffer[0])) {
+		} else if (HTCJK != NOCJK && !isascii((unsigned char)buffer[0])) {
 		    /*
 		     *  For CJK strings, by Masanobu Kimura.
 		     */
@@ -13006,10 +13422,12 @@ PRIVATE void move_to_glyph ARGS10(
 	if (hadutf8) {
 #ifdef USE_SLANG
 	    SLsmg_touch_lines(YP, 1);
-#elif defined(NCURSES_VERSION)
-	    touchline(stdscr, YP, 1);
 #else
-	    touchwin(stdscr);
+#if defined(NCURSES_VERSION)
+	    wredrawln(stdscr, YP, 1);
+#else
+	    touchline(stdscr, YP, 1); /* or something else? */
+#endif
 #endif
 	}
     }
diff --git a/src/GridText.h b/src/GridText.h
index 190d97fa..1f82ec73 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -202,8 +202,11 @@ 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_startStblTD PARAMS((HText *, int, int, short, BOOL));
 extern void HText_endStblTD PARAMS((HText *));
+extern void HText_startStblCOL PARAMS((HText *, int, short, BOOL));
+extern void HText_endStblCOLGROUP PARAMS((HText *));
+extern void HText_startStblRowGroup PARAMS((HText *, short));
 
 /* forms stuff */
 extern void HText_beginForm PARAMS((
diff --git a/src/HTAlert.c b/src/HTAlert.c
index 5a86f666..99d8ad43 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -440,6 +440,32 @@ PUBLIC BOOL HTLastConfirmCancelled NOARGS
 */
 PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft)
 {
+/* Meta-note: don't move the following note from its place right
+   in front of the first gettext().  As it is now, it should
+   automatically appear in generated lynx.pot files. - kw
+ */
+
+/*  NOTE TO TRANSLATORS:  If you provide a translation for "yes", lynx
+ *  will take the first byte of the translation as a positive response
+ *  to Yes/No questions.  If you provide a translation for "no", lynx
+ *  will take the first byte of the translation as a negative response
+ *  to Yes/No questions.  For both, lynx will also try to show the
+ *  first byte in the prompt as a character, instead of (y) or (n),
+ *  respectively.  This will not work right for multibyte charsets!
+ *  Don't translate "yes" and "no" for CJK character sets (or translate
+ *  them to "yes" and "no").  For a translation using UTF-8, don't
+ *  translate if the translation would begin with anything but a 7-bit
+ *  (US_ASCII) character.  That also means do not translate if the
+ *  translation would begin with anything but a 7-bit character, if
+ *  you use a single-byte character encoding (a charset like ISO-8859-n)
+ *  but anticipate that the message catalog may be used re-encoded in
+ *  UTF-8 form.
+ *  For translations using other character sets, you may also wish to
+ *  leave "yes" and "no" untranslated, if using (y) and (n) is the
+ *  preferred behavior.
+ *  Lynx will also accept y Y n N as responses unless there is a conflict
+ *  with the first letter of the "yes" or "no" translation.
+ */
     char *msg_yes = gettext("yes");
     char *msg_no  = gettext("no");
     int result = -1;
@@ -455,6 +481,13 @@ PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft)
 	result = NO;
     } else {
 	char *msg = NULL;
+	char fallback_y = 'y';	/* English letter response as fallback */
+	char fallback_n = 'n';	/* English letter response as fallback */
+
+	if (fallback_y == *msg_yes || fallback_y == *msg_no)
+	    fallback_y = '\0';	/* conflict or duplication, don't use */
+	if (fallback_n == *msg_yes || fallback_n == *msg_no)
+	    fallback_n = '\0';	/* conflict or duplication, don't use */
 
 	if (Dft == DFT_CONFIRM)
 	    HTSprintf0(&msg, "%s (%c/%c) ", Msg, *msg_yes, *msg_no);
@@ -481,6 +514,10 @@ PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft)
 		result = YES;
 	    } else if (TOUPPER(c) == TOUPPER(*msg_no)) {
 		result = NO;
+	    } else if (fallback_y && TOLOWER(c) == fallback_y) {
+		result = YES;
+	    } else if (fallback_n && TOLOWER(c) == fallback_n) {
+		result = NO;
 	    } else if (Dft != DFT_CONFIRM) {
 		result = Dft;
 		break;
diff --git a/src/HTML.c b/src/HTML.c
index 464a05b1..f9374c96 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -109,7 +109,7 @@ PRIVATE HTStyleSheet * styleSheet = NULL;	/* Application-wide */
 
 /*	Module-wide style cache
 */
-PRIVATE HTStyle *styles[HTML_ELEMENTS+HTML_EXTRA_ELEMENTS];
+PRIVATE HTStyle *styles[HTML_ELEMENTS+LYNX_HTML_EXTRA_ELEMENTS];
 					   /* adding 24 nested list styles  */
 					   /* and 3 header alignment styles */
 					   /* and 3 div alignment styles    */
@@ -682,7 +682,7 @@ PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
    string (resolution of relative URLs etc.).  This variable only used
    locally here, don't confuse with LYinternal_flag which is for
    overriding non-caching similar to LYoverride_no_cache. - kw */
-#define CHECK_FOR_INTERN(s) intern_flag = (s && (*s=='#' || *s=='\0')) ? TRUE : FALSE;
+#define CHECK_FOR_INTERN(flag,s) flag = (s && (*s=='#' || *s=='\0')) ? TRUE : FALSE
 
 /* Last argument to pass to HTAnchor_findChildAndLink() calls,
    just an abbreviation. - kw */
@@ -690,7 +690,7 @@ PUBLIC void HTML_write ARGS3(HTStructured *, me, CONST char*, s, int, l)
 
 #else  /* !DONT_TRACK_INTERNAL_LINKS */
 
-#define CHECK_FOR_INTERN(s)  /* do nothing */ ;
+#define CHECK_FOR_INTERN(flag,s)  /* do nothing */ ;
 #define INTERN_LT (HTLinkType *)NULL
 
 #endif /* DONT_TRACK_INTERNAL_LINKS */
@@ -712,11 +712,11 @@ static int hcode;
 
 PRIVATE void HTMLSRC_apply_markup ARGS4(
 	    HTStructured *,   context,
-	    HTlexem,	      lexem,
+	    HTlexeme,	      lexeme,
 	    BOOL,	      start,
 	    int,	      tag_charset)
 {
-    HT_tagspec* ts = *( ( start ? lexem_start : lexem_end ) + lexem);
+    HT_tagspec* ts = *( ( start ? lexeme_start : lexeme_end ) + lexeme);
 
     while (ts) {
 #ifdef USE_COLOR_STYLE
@@ -727,7 +727,7 @@ PRIVATE void HTMLSRC_apply_markup ARGS4(
 	    force_classname = TRUE;
 	}
 #endif
-	CTRACE((tfp,ts->start ? "SRCSTART %d\n" : "SRCSTOP %d\n",(int)lexem));
+	CTRACE((tfp,ts->start ? "SRCSTART %d\n" : "SRCSTOP %d\n",(int)lexeme));
 	if (ts->start)
 	    HTML_start_element(
 		context,
@@ -791,7 +791,7 @@ PRIVATE void LYStartArea ARGS5(
 			       tag_charset, 0);
 }
 
-PRIVATE void LYHandleFIG ARGS9(
+PRIVATE void LYHandleFIG ARGS10(
 	HTStructured *,		me,
 	CONST BOOL*,		present,
 	CONST char **,		value,
@@ -800,7 +800,8 @@ PRIVATE void LYHandleFIG ARGS9(
 	CONST char *,		id,
 	CONST char *,		src,
 	BOOL,			convert,
-	BOOL,			start)
+	BOOL,			start,
+	BOOL *,			intern_flag GCC_UNUSED)
 {
     if (start == TRUE) {
 	me->inFIG = TRUE;
@@ -828,7 +829,7 @@ PRIVATE void LYHandleFIG ARGS9(
 	if (clickable_images && src && src != '\0') {
 	    char *href = NULL;
 	    StrAllocCopy(href, src);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(*intern_flag,href);
 	    LYLegitimizeHREF(me, &href, TRUE, TRUE);
 	    if (*href) {
 		char *temp = NULL;
@@ -933,7 +934,7 @@ PRIVATE int HTML_start_element ARGS6(
     int dest_char_set = UCLYhndl_for_unrec;
     HTParentAnchor *dest = NULL;	     /* An anchor's destination */
     BOOL dest_ismap = FALSE;		     /* Is dest an image map script? */
-    BOOL UseBASE = TRUE;		     /* Resoved vs. BASE if present? */
+    BOOL UseBASE = TRUE;		     /* Resolved vs. BASE if present? */
     HTChildAnchor *ID_A = NULL;		     /* HTML_foo_ID anchor */
     int url_type = 0, i = 0;
     char *cp = NULL;
@@ -1310,7 +1311,7 @@ PRIVATE int HTML_start_element ARGS6(
 	intern_flag = FALSE;
 #endif
 	if (present && present[HTML_LINK_HREF]) {
-	    CHECK_FOR_INTERN(value[HTML_LINK_HREF]);
+	    CHECK_FOR_INTERN(intern_flag,value[HTML_LINK_HREF]);
 	    /*
 	     *	Prepare to do housekeeping on the reference. - FM
 	     */
@@ -1762,7 +1763,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (present && present[HTML_FRAME_SRC] &&
 	    value[HTML_FRAME_SRC] && *value[HTML_FRAME_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_FRAME_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 
 	    /*
@@ -1837,7 +1838,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (present && present[HTML_IFRAME_SRC] &&
 	    value[HTML_IFRAME_SRC] && *value[HTML_IFRAME_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_IFRAME_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 
 	    /*
@@ -3031,7 +3032,7 @@ PRIVATE int HTML_start_element ARGS6(
 	    if (present[HTML_A_ISMAP])
 		intern_flag = FALSE;
 	    else
-		CHECK_FOR_INTERN(value[HTML_A_HREF]);
+		CHECK_FOR_INTERN(intern_flag,value[HTML_A_HREF]);
 #endif
 	    /*
 	     *	Prepare to do housekeeping on the reference. - FM
@@ -3175,20 +3176,24 @@ PRIVATE int HTML_start_element ARGS6(
 					    me->inUnderline, me->CurrentA);
 	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
 	    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-#if defined(NOTUSED_FOTEMODS) || !defined(NO_EMPTY_HREFLESS_A)
+#if defined(NOTUSED_FOTEMODS)
 	/*
 	 *  Close an HREF-less NAMED-ed now if we aren't making their
 	 *  content bold, and let the check in HTML_end_element() deal
 	 *  with any dangling end tag this creates. - FM
 	 */
-# ifndef NO_EMPTY_HREFLESS_A
-	if (force_empty_hrefless_a)
-# endif
-	    if (href == NULL && me->inBoldA == FALSE) {
-		SET_SKIP_STACK(HTML_A);
-		HTML_end_element(me, HTML_A, include);
-	    }
-#endif /* NOTUSED_FOTEMODS || !defined(NO_EMPTY_HREFLESS_A)*/
+	if (href == NULL && me->inBoldA == FALSE) {
+	    SET_SKIP_STACK(HTML_A);
+	    HTML_end_element(me, HTML_A, include);
+	}
+#else
+	/*Close an HREF-less NAMED-ed now if force_empty_hrefless_a was
+	    requested - VH*/
+	if (href == NULL) {
+	    SET_SKIP_STACK(HTML_A);
+	    HTML_end_element(me, HTML_A, include);
+	}
+#endif
 	FREE(href);
 	break;
 
@@ -3225,7 +3230,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (present && present[HTML_IMG_USEMAP] &&
 	    value[HTML_IMG_USEMAP] && *value[HTML_IMG_USEMAP]) {
 	    StrAllocCopy(map_href, value[HTML_IMG_USEMAP]);
-	    CHECK_FOR_INTERN(map_href);
+	    CHECK_FOR_INTERN(intern_flag,map_href);
 	    url_type = LYLegitimizeHREF(me, &map_href, TRUE, TRUE);
 	    /*
 	     *	If map_href ended up zero-length or otherwise doesn't
@@ -3778,7 +3783,7 @@ PRIVATE int HTML_start_element ARGS6(
 	     *	Resolve the HREF. - FM
 	     */
 	    StrAllocCopy(href, value[HTML_AREA_HREF]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 
 	    /*
@@ -3888,13 +3893,13 @@ PRIVATE int HTML_start_element ARGS6(
 			present[HTML_FIG_IMAGEMAP],
 			present[HTML_FIG_ID] ? value[HTML_FIG_ID] : NULL,
 			present[HTML_FIG_SRC] ? value[HTML_FIG_SRC] : NULL,
-			YES, TRUE);
+			YES, TRUE, &intern_flag);
 	else
 	    LYHandleFIG(me, NULL, NULL,
 			0,
 			0,
 			NULL,
-			NULL, YES, TRUE);
+			NULL, YES, TRUE, &intern_flag);
 #if 0
 	me->inFIG = TRUE;
 	if (me->inA) {
@@ -3917,7 +3922,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (clickable_images && present && present[HTML_FIG_SRC] &&
 	    value[HTML_FIG_SRC] && *value[HTML_FIG_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_FIG_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 	    if (*href) {
 		/*
@@ -4130,7 +4135,7 @@ PRIVATE int HTML_start_element ARGS6(
 		    1 || me->object_ismap,
 		    me->object_id,
 		    (me->object_data && !me->object_classid) ? value[HTML_OBJECT_DATA] : NULL,
-		    NO, TRUE);
+		    NO, TRUE, &intern_flag);
 		clear_objectdata(me);
 		status = HT_PARSER_OTHER_CONTENT;
 		me->objects_figged_open++;
@@ -4150,7 +4155,7 @@ PRIVATE int HTML_start_element ARGS6(
 	    present && present[HTML_OVERLAY_SRC] &&
 	    value[HTML_OVERLAY_SRC] && *value[HTML_OVERLAY_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_OVERLAY_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 	    if (*href) {
 		/*
@@ -4355,7 +4360,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (clickable_images && present && present[HTML_BGSOUND_SRC] &&
 	    value[HTML_BGSOUND_SRC] && *value[HTML_BGSOUND_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_BGSOUND_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 	    if (*href == '\0') {
 		FREE(href);
@@ -4469,7 +4474,7 @@ PRIVATE int HTML_start_element ARGS6(
 	if (clickable_images && present && present[HTML_EMBED_SRC] &&
 	    value[HTML_EMBED_SRC] && *value[HTML_EMBED_SRC] != '\0') {
 	    StrAllocCopy(href, value[HTML_EMBED_SRC]);
-	    CHECK_FOR_INTERN(href);
+	    CHECK_FOR_INTERN(intern_flag,href);
 	    url_type = LYLegitimizeHREF(me, &href, TRUE, TRUE);
 	    if (*href != '\0') {
 		/*
@@ -5928,7 +5933,7 @@ PRIVATE int HTML_start_element ARGS6(
     case HTML_TBODY:
 	HText_endStblTR(me->text);
 	/*
-	 *  Not yet implemented.  Just check for an ID link. - FM
+	 *  Not fully implemented.  Just check for an ID link. - FM
 	 */
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
@@ -5939,13 +5944,26 @@ PRIVATE int HTML_start_element ARGS6(
 	    HTML_end_element(me, HTML_U, include);
 	}
 	UPDATE_STYLE;
+	if (me->inTABLE) {
+	    if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) {
+		if (!strcasecomp(value[HTML_TR_ALIGN], "center")) {
+		    stbl_align = HT_CENTER;
+		} else if (!strcasecomp(value[HTML_TR_ALIGN], "right")) {
+		    stbl_align = HT_RIGHT;
+		} else if (!strcasecomp(value[HTML_TR_ALIGN], "left") ||
+			   !strcasecomp(value[HTML_TR_ALIGN], "justify")) {
+		    stbl_align = HT_LEFT;
+		}
+	    }
+	    HText_startStblRowGroup(me->text, stbl_align);
+	}
 	CHECK_ID(HTML_TR_ID);
 	break;
 
     case HTML_COL:
     case HTML_COLGROUP:
 	/*
-	 *  Not yet implemented.  Just check for an ID link. - FM
+	 *  Not fully implemented.  Just check for an ID link. - FM
 	 */
 	if (me->inA) {
 	    SET_SKIP_STACK(HTML_A);
@@ -5955,8 +5973,26 @@ PRIVATE int 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;
+	if (me->inTABLE) {
+	    int span = 1;
+	    if (present && present[HTML_COL_SPAN] &&
+		value[HTML_COL_SPAN] &&
+		isdigit((unsigned char)*value[HTML_COL_SPAN]))
+		span = atoi(value[HTML_COL_SPAN]);
+	    if (present && present[HTML_COL_ALIGN] && value[HTML_COL_ALIGN]) {
+		if (!strcasecomp(value[HTML_COL_ALIGN], "center")) {
+		    stbl_align = HT_CENTER;
+		} else if (!strcasecomp(value[HTML_COL_ALIGN], "right")) {
+		    stbl_align = HT_RIGHT;
+		} else if (!strcasecomp(value[HTML_COL_ALIGN], "left") ||
+			   !strcasecomp(value[HTML_COL_ALIGN], "justify")) {
+		    stbl_align = HT_LEFT;
+		}
+	    }
+	    HText_startStblCOL(me->text, span, stbl_align,
+			       (ElementNumber == HTML_COLGROUP));
+	}
 	CHECK_ID(HTML_COL_ID);
 	break;
 
@@ -5978,11 +6014,15 @@ PRIVATE int HTML_start_element ARGS6(
 	 */
 	HTML_put_character(me, ' ');
 	{
-	    int colspan = 1;
+	    int colspan = 1, rowspan = 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_ROWSPAN] &&
+		value[HTML_TD_ROWSPAN] &&
+		isdigit((unsigned char)*value[HTML_TD_ROWSPAN]))
+		rowspan = atoi(value[HTML_TD_ROWSPAN]);
 	    if (present && present[HTML_TD_ALIGN] && value[HTML_TD_ALIGN]) {
 		if (!strcasecomp(value[HTML_TD_ALIGN], "center")) {
 		    stbl_align = HT_CENTER;
@@ -5993,7 +6033,7 @@ PRIVATE int HTML_start_element ARGS6(
 		    stbl_align = HT_LEFT;
 		}
 	    }
-	    HText_startStblTD(me->text, colspan, stbl_align,
+	    HText_startStblTD(me->text, colspan, rowspan, stbl_align,
 			      (ElementNumber == HTML_TH));
 	}
 	me->in_word = NO;
@@ -6108,6 +6148,8 @@ PRIVATE int HTML_end_element ARGS3(
     int status = HT_OK;
     char *temp = NULL, *cp = NULL;
     BOOL BreakFlag = FALSE;
+    BOOL intern_flag = FALSE;
+    BOOL skip_stack_requested = FALSE;
     EMIT_IFDEF_EXP_JUSTIFY_ELTS(BOOL reached_awaited_stacked_elt=FALSE;)
 
 #ifdef USE_PSRC
@@ -6167,6 +6209,7 @@ PRIVATE int HTML_end_element ARGS3(
      *	SGML_EMPTY in HTMLDTD.c. - FM & KW
      */
     if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
+	skip_stack_requested = me->skip_stack > 0;
 	if ((element_number != me->sp[0].tag_number) &&
 	    me->skip_stack <= 0 &&
 	    HTML_dtd.tags[HTML_LH].contents != SGML_EMPTY &&
@@ -6737,7 +6780,7 @@ PRIVATE int HTML_end_element ARGS3(
 		    0,
 		    0,
 		    NULL,
-		    NULL, NO, FALSE);
+		    NULL, NO, FALSE, &intern_flag);
 	break;
 
     case HTML_OBJECT:
@@ -7329,15 +7372,33 @@ End_Object:
 	    me->UsePlainSpace = TRUE;
 
 	    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);
+		TRANSLATE_AND_UNESCAPE_ENTITIES6(&me->textarea.data,
+						 me->UCLYhndl,
+						 current_char_set,
+						 NO,
+						 me->UsePlainSpace, me->HiddenValue);
 	    } else {
-		TRANSLATE_HTML5(&me->textarea.data,
+		/*
+		 *  This shouldn't have anything to do, normally, but
+		 *  just in case...
+		 *  There shouldn't be lynx special character codes in
+		 *  the chunk ("DTD" flag Tgf_nolyspcl tells SGML.c not
+		 *  to generate them).  If there were, we could set the
+		 *  last parameter ('Back') below to YES, which would
+		 *  take them out of the data.
+		 *  The data may however contain non break space, soft
+		 *  hyphen, or en space etc., in the me->UCLYhndl character
+		 *  encoding.  If that's a problem, perhaps for the (line
+		 *  or other) editor, setting 'Back' to YES should also
+		 *  help to always convert them to plain spaces (or drop
+		 *  them). - kw
+		 */
+		TRANSLATE_HTML7(&me->textarea.data,
 						    me->UCLYhndl,
 						    current_char_set,
-						    me->UsePlainSpace, me->HiddenValue);
+						    NO,
+						    me->UsePlainSpace, me->HiddenValue,
+						    NO);
 	    }
 	    data = me->textarea.data;
 
@@ -7600,6 +7661,8 @@ End_Object:
 	break;
 
     case HTML_COLGROUP:
+	if (me->inTABLE)
+	    HText_endStblCOLGROUP(me->text);
 	break;
 
     case HTML_TH:
@@ -7657,26 +7720,28 @@ End_Object:
     }
 
 #ifdef USE_COLOR_STYLE
+    if (!skip_stack_requested) { /*don't emit stylechanges if skipped stack element - VH*/
 #if !OPT_SCN
-    TrimColorClass(HTML_dtd.tags[element_number].name,
-		   Style_className, &hcode);
+	TrimColorClass(HTML_dtd.tags[element_number].name,
+		       Style_className, &hcode);
 #else
 # if !OMIT_SCN_KEEPING
-    FastTrimColorClass(HTML_dtd.tags[element_number].name,
-		       HTML_dtd.tags[element_number].name_len,
-		       Style_className,
-		       &Style_className_end, &hcode);
+	FastTrimColorClass(HTML_dtd.tags[element_number].name,
+			   HTML_dtd.tags[element_number].name_len,
+			   Style_className,
+			   &Style_className_end, &hcode);
 #  endif
 #endif
 
-    if (!ReallyEmptyTagNum(element_number))
-    {
-	CTRACE((tfp, "STYLE:end_element: ending non-EMPTY style\n"));
+	if (!ReallyEmptyTagNum(element_number))
+	{
+	    CTRACE((tfp, "STYLE:end_element: ending non-EMPTY style\n"));
 #if !defined(USE_HASH)
-	HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF);
+	    HText_characterStyle(me->text, element_number+STARTAT, STACK_OFF);
 #else
-	HText_characterStyle(me->text, HCODE_TO_STACK_OFF(hcode), STACK_OFF);
+	    HText_characterStyle(me->text, HCODE_TO_STACK_OFF(hcode), STACK_OFF);
 #endif /* USE_HASH */
+	}
     }
 #endif /* USE_COLOR_STYLE */
     return status;
diff --git a/src/HTML.h b/src/HTML.h
index 04ea3f32..95bd74f1 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -34,6 +34,9 @@
 #define TRANSLATE_HTML5(s,cs_from,cs_to,p,h) \
 	LYUCFullyTranslateString(s, cs_from, cs_to, NO, YES, p, h, NO, st_HTML)
 
+#define TRANSLATE_HTML7(s,cs_from,cs_to,spcls,p,h,Back) \
+	LYUCFullyTranslateString(s, cs_from, cs_to, NO, spcls, p, h, Back, st_HTML)
+
 /*
  *  Strings from attributes which should be converted to some kind
  *  of "standard" representation (character encoding), was Latin-1,
diff --git a/src/HTNestedList.h b/src/HTNestedList.h
index f7c0411d..75d83a70 100644
--- a/src/HTNestedList.h
+++ b/src/HTNestedList.h
@@ -40,6 +40,6 @@
 
 #define HTML_OBJECT_M HTML_ELEMENTS+31
 
-#define HTML_EXTRA_ELEMENTS 31
+#define LYNX_HTML_EXTRA_ELEMENTS 31
 
 #endif /* HTNESTEDLIST_H */
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index b4b54422..e48aaf8b 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -1678,17 +1678,18 @@ PUBLIC char ** LYUCFullyTranslateString ARGS9(
     /*
     **	Don't do byte translation
     **	if original AND target character sets
-    **	are both iso-8859-1,
+    **	are both iso-8859-1 (and we are not called to back-translate),
     **	or if we are in CJK mode.
     */
-    no_bytetrans = (BOOL) ((cs_to <= 0 && cs_from == cs_to) ||
-		    HTCJK != NOCJK);
-
+    if (HTCJK != NOCJK) {
+	no_bytetrans = TRUE;
+    } else if (cs_to <= 0 && cs_from == cs_to && (!Back || cs_to < 0)) {
+	no_bytetrans = TRUE;
+    } else {
     /* No need to translate or examine the string any further */
-    if (!no_bytetrans)
 	no_bytetrans = (BOOL) (!use_lynx_specials && !Back &&
-			UCNeedNotTranslate(cs_from, cs_to));
-
+			       UCNeedNotTranslate(cs_from, cs_to));
+    }
     /*
     **	Save malloc/calloc overhead in simple case - kw
     */
@@ -1898,21 +1899,31 @@ PUBLIC char ** LYUCFullyTranslateString ARGS9(
 			state = S_got_outchar;
 			break;
 		    } else {
-			*(unsigned char *)p = (unsigned char)160;
 			code = 160;
 			if (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_from].enc == UCT_ENC_8859
+			||(LYCharSet_UC[cs_from].like8859 & UCT_R_8859SPECL))) {
+			    state = S_check_uni;
+			    break;
+			} else {
+			    *(unsigned char *)p = (unsigned char)160;
 			}
 		    }
 		} else if ((*p) == LY_SOFT_HYPHEN) {
-		    *(unsigned char *)p = (unsigned char)173;
 		    code = 173;
 		    if (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_from].enc == UCT_ENC_8859
+			||(LYCharSet_UC[cs_from].like8859 & UCT_R_8859SPECL))) {
+			state = S_check_uni;
+			break;
+		    } else {
+			*(unsigned char *)p = (unsigned char)173;
 		    }
 		} else if (code < 127 || T.transp) {
 		    state = S_got_outchar;
diff --git a/src/LYCurses.c b/src/LYCurses.c
index 07b2d8d9..e804da1e 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -520,14 +520,17 @@ PRIVATE void LYsetWAttr ARGS1(WINDOW *, win)
 	attr = lynx_color_cfg[code].attr;
 
 	/*
-	 * no_color_video isn't implemented (97/4/14) in ncurses 4.1, but may
-	 * be in SVr4 (which would make this redundant for the latter).
+	 * no_color_video is implemented in ncurses 4.2, but not in other
+	 * flavors of curses.  So we check before adding video attributes that
+	 * might conflict with colors.  For A_BOLD, check for both the bold and
+	 * standout mask items because standout often uses bold in conjunction
+	 * with another attribute.  -TD
 	 */
 	if ((Current_Attr & A_BOLD) && !(NoColorVideo & 33)) {
 		attr |= A_BOLD;
 	}
 
-	if ((Current_Attr == A_UNDERLINE) && !(NoColorVideo & 2)) {
+	if ((Current_Attr & A_UNDERLINE) && !(NoColorVideo & 2)) {
 		attr |= A_UNDERLINE;
 	}
 
@@ -837,7 +840,11 @@ PUBLIC void start_curses NOARGS
 #endif /* USE_COLOR_TABLE */
     }
 #ifdef __DJGPP__
+#ifdef WATT32
+    _eth_init();
+#else
     else sock_init();
+#endif /* WATT32 */
 #endif /* __DJGPP__ */
 #endif /* not VMS */
 
diff --git a/src/LYForms.c b/src/LYForms.c
index 70f7486d..6e10025b 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -1134,7 +1134,7 @@ redraw:
 	    cmd = LYK_QUIT;
 #ifndef USE_SLANG
 	} else if (c == MOUSE_KEY) {
-	    if ((cmd = fancy_mouse(form_window, i + 1 + window_offset, &cur_selection)) < 0)
+	    if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_selection)) < 0)
 		goto redraw;
 	    if  (cmd == LYK_ACTIVATE)
 		break;
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index d0f8efbf..dc41af94 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -396,9 +396,7 @@ extern BOOL ok_justify;
 extern BOOLEAN with_backspaces;
 #endif
 
-#ifndef NO_EMPTY_HREFLESS_A
 extern BOOL force_empty_hrefless_a;
-#endif
 
 #ifndef NO_NONSTICKY_INPUTS
 extern BOOL sticky_inputs;
diff --git a/src/LYHistory.c b/src/LYHistory.c
index de190ef1..9f7a8cca 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -148,6 +148,10 @@ PUBLIC BOOLEAN LYwouldPush ARGS2(
 	if (strncmp(docurl, "file://localhost/", 17) != 0 ||
 	    (ulen = strlen(docurl)) <= strlen(HTML_SUFFIX) ||
 	    strcmp(docurl + ulen - strlen(HTML_SUFFIX), HTML_SUFFIX) != 0)
+	    /*
+	     *  If it is not a local HTML file, it may be a Web page that
+	     *  accidentally has the same title.  So return TRUE now. - kw
+	     */
 	    return TRUE;
     }
 
@@ -726,7 +730,7 @@ PUBLIC void LYstore_message2 ARGS2(
 
     if (message != NULL) {
 	char *temp = NULL;
-	HTSprintf(&temp, message, (argument == 0) ? "" : argument);
+	HTSprintf0(&temp, message, (argument == 0) ? "" : argument);
 	to_stack(temp);
     }
 }
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 148479f7..bd5783b5 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -1167,18 +1167,18 @@ PUBLIC char *key_for_func ARGS1 (
 
 /*
  *  This function returns TRUE if the ch is non-alphanumeric
- *  and maps to key_name (LYK_foo in the keymap[] array). - FM
+ *  and maps to KeyName (LYK_foo in the keymap[] array). - FM
  */
 PUBLIC BOOL LYisNonAlnumKeyname ARGS2(
 	int,	ch,
-	int,	key_name)
+	int,	KeyName)
 {
     if ((ch >= '0' && ch <= '9') ||
         (ch >= 'A' && ch <= 'z') ||
 	ch < 0 || ch >= KEYMAP_SIZE)
 	return (FALSE);
 
-    return (BOOL) (keymap[ch+1] == key_name);
+    return (BOOL) (keymap[ch+1] == KeyName);
 }
 
 /*
@@ -1186,12 +1186,12 @@ PUBLIC BOOL LYisNonAlnumKeyname ARGS2(
  *  LYK_foo value passed to it as an argument. - FM
  */
 PUBLIC int LYReverseKeymap ARGS1(
-	int,	key_name)
+	int,	KeyName)
 {
     int i;
 
     for (i = 1; i < KEYMAP_SIZE; i++) {
-	if (keymap[i] == key_name) {
+	if (keymap[i] == KeyName) {
 	    return(i - 1);
 	}
     }
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index 518864fe..85ffb087 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -5,9 +5,9 @@
 #include <HTUtils.h>
 #endif
 
-extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int key_name));
+extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int KeyName));
 extern char *key_for_func PARAMS((int func));
-extern int LYReverseKeymap PARAMS((int key_name));
+extern int LYReverseKeymap PARAMS((int KeyName));
 extern int lookup_keymap PARAMS((int code));
 extern int lacname_to_lac PARAMS((CONST char *func));
 extern int lkcstring_to_lkc PARAMS((CONST char *src));
diff --git a/src/LYLeaks.c b/src/LYLeaks.c
index f4a5954c..d0f7acab 100644
--- a/src/LYLeaks.c
+++ b/src/LYLeaks.c
@@ -235,6 +235,75 @@ PUBLIC void *LYLeakMalloc ARGS3(
 }
 
 /*
+**  Purpose:	Add information about new allocation to the list,
+**		after a call to malloc or calloc or an equivalent
+**		function which may or may not have already created
+**		a list entry.
+**  Arguments:	vp_malloc	The pointer to newly allocate memory.
+**  Arguments:	st_bytes	The size of the allocation requested
+**				in bytes.
+**		cp_File 	The file from which the request for
+**				allocation came from.
+**		ssi_Line	The line number in cp_File where the
+**				allocation request came from.
+**  Return Value:	void *	A pointer to the allocated memory or NULL on
+**				failure.
+**  Remarks/Portability/Dependencies/Restrictions:
+**		If no memory is allocated, then no entry is added to the
+**		allocation list.
+**  Revision History:
+**	1999-02-08	created, modelled after LYLeakMalloc - kw
+*/
+PUBLIC AllocationList *LYLeak_mark_malloced ARGS4(
+	void *,		vp_malloced,
+	size_t, 	st_bytes,
+	CONST char *,	cp_File,
+	CONST short,	ssi_Line)
+{
+    AllocationList *ALp_new = NULL;
+    /*
+     *	The actual allocation has already been done!
+     *
+     *	Only on successful allocation do we track any information.
+     */
+    if (vp_malloced != NULL) {
+	/*
+	 *  See if there is already an entry.  If so, just
+	 *  update the source location info.
+	 */
+	ALp_new = FindInList(vp_malloced);
+	if (ALp_new) {
+	    ALp_new->SL_memory.cp_FileName = cp_File;
+	    ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
+	    return(ALp_new);
+	}	    
+	/*
+	 *  Further allocate memory to store the information.
+	 *  Just return on failure to allocate more.
+	 */
+	ALp_new = (AllocationList *)calloc(1, sizeof(AllocationList));
+
+	if (ALp_new == NULL) {
+	    return(NULL);
+	}
+	/*
+	 *  Copy over the relevant information.
+	 */
+	ALp_new->vp_Alloced = vp_malloced;
+	ALp_new->st_Bytes = st_bytes;
+	ALp_new->SL_memory.cp_FileName = cp_File;
+	ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
+
+	/*
+	 *  Add the new item to the allocation list.
+	 */
+	AddToList(ALp_new);
+    }
+
+    return(ALp_new);
+}
+
+/*
 **  Purpose:	Capture allocations by calloc (stdlib.h) and
 **		save relevant information in a list.
 **  Arguments:	st_number	The number of items to allocate.
@@ -390,6 +459,61 @@ PUBLIC void *LYLeakRealloc ARGS4(
 }
 
 /*
+**  Purpose:	Add information about reallocated memory to the list,
+**		after a call to realloc or an equivalent
+**		function which has not already created or updated
+**		a list entry.
+**  Arguments:	ALp_old   	List entry for previously allocated
+**				block of memory to resize.  If NULL,
+**				mark_realloced works just like
+**				mark_malloced.
+**		vp_realloced	The new pointer, after resizing.
+**		st_newBytes	The new size of the chunk of memory.
+**		cp_File 	The file to record.
+**		ssi_Line	The line to record.
+**  Return Value:	      	Pointer to new or updated list entry
+**				for this memory block.
+**				NULL on allocation error.
+**  Revision History:
+**	1999-02-11	created kw
+*/
+#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
+PRIVATE AllocationList *mark_realloced ARGS5(
+	AllocationList *, ALp_old,
+	void *, 	vp_realloced,
+	size_t, 	st_newBytes,
+	CONST char *,	cp_File,
+	CONST short,	ssi_Line)
+{
+    /*
+     *	If there is no list entry for the old allocation, treat this
+     *	as if a new allocation had happened.
+     */
+    if (ALp_old == NULL) {
+	return(LYLeak_mark_malloced(
+	    vp_realloced, st_newBytes, cp_File, ssi_Line));
+    }
+
+    /*
+     *	ALp_old represents the memory block before reallocation.
+     *  Assume that if we get here, there isn't yet a list entry
+     *  for the new, possibly different, address after realloc,
+     *  that is our list hasn't been updated - so we're going to
+     *  do that now.
+     */
+
+    if (vp_realloced != NULL) {
+	ALp_old->vp_Alloced = vp_realloced;
+	ALp_old->st_Bytes = st_newBytes;
+	ALp_old->SL_realloc.cp_FileName = cp_File;
+	ALp_old->SL_realloc.ssi_LineNumber = ssi_Line;
+    }
+
+    return(ALp_old);
+}
+#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
+
+/*
 **  Purpose:	Capture all requests to free information and also
 **		remove items from the allocation list.
 **  Arguments:	vp_Alloced	The memory to free.
@@ -524,6 +648,230 @@ PUBLIC char * LYLeakSACat ARGS4(
     return *dest;
 }
 
+#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
+PUBLIC CONST char * leak_cp_File_hack = __FILE__;
+PUBLIC short leak_ssi_Line_hack = __LINE__;
+
+/*
+** Purpose:	A wrapper around StrAllocVsprintf (the workhorse of
+**		HTSprintf/HTSprintf0, implemented in HTString.c) that
+**		tries to make sure that our allocation list is always
+**		properly updated, whether StrAllocVsprintf itself was
+**		compiled with memory tracking or not (or even a mixture,
+**		like tracking the freeing but not the new allocation).
+**		Some source files can be compiled with LY_FIND_LEAKS_EXTENDED
+**		in effect while others only have LY_FIND_LEAKS in effect,
+**		and as long as HTString.c is complied with memory tracking
+**		(of either kind) string objects allocated by HTSprintf/
+**		HTSprintf0 (or otherwise) can be passed around among them and
+**		manipulated both ways.
+**  Arguments:	dest		As for StrAllocVsprintf.
+**		cp_File		The source file of the caller (i.e. the
+**				caller of HTSprintf/HTSprintf0, hopefully).
+**		ssi_Line	The line of cp_File calling.
+**		inuse,fmt,ap	As for StrAllocVsprintf.
+**  Return Value:	The char pointer to resulting string, as set
+**			by StrAllocVsprintf, or
+**			NULL if dest==0 (wrong use!).
+**  Remarks/Portability/Dependencies/Restrictions:
+**		The price for generality is severe inefficiency: several
+**		list lookups are done to be on the safe side.
+**		We don't get he real allocation size, only a minimum based
+**		on the string length of the result.  So the amount of memory
+**		leakage may get underestimated.
+**		If *dest is an invalid pointer value on entry (i.e. was not
+**		tracked), the program will exit after one last entry is added
+**		to the allocation list.
+**		If StrAllocVsprintf fails to return a valid string via the
+**		indirect string pointer (its first parameter), invalid memory
+**		access will result and the program will probably terminate
+**		with a signal.  This can happen if, on entry, *dest is NULL
+**		and fmt is empty or NULL, so just Don't Do That.
+**  Revision History:
+**	1999-02-11	created kw
+**	1999-10-15	added comments kw
+*/
+PRIVATE char * LYLeakSAVsprintf ARGS6(
+	char **,	dest,
+	CONST char *,	cp_File,
+	CONST short,	ssi_Line,
+	size_t,		inuse,
+	CONST char *,	fmt,
+	va_list,	ap)
+{
+    AllocationList *ALp_old;
+    void *vp_oldAlloced;
+    
+    CONST char * old_cp_File = __FILE__;
+    short old_ssi_Line = __LINE__;
+
+    if (!dest)
+	return NULL;
+
+    vp_oldAlloced = *dest;
+    if (!vp_oldAlloced) {
+	StrAllocVsprintf(dest, inuse, fmt, ap);
+	LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
+	return(*dest);
+    } else {
+	void * vp_realloced;
+	ALp_old = FindInList(vp_oldAlloced);
+	if (ALp_old == NULL) {
+	    /*
+	     *  Track the invalid pointer value and then exit.
+	     *  If unable to allocate, just exit.
+	     */
+	    auto AllocationList *ALp_new =
+		(AllocationList *)calloc(1,
+					 sizeof(AllocationList));
+
+	    if (ALp_new == NULL) {
+		exit(-1);
+	    }
+
+	    /*
+	     *  Set the information up; no need to allocate file name
+	     *  since it is a static string.
+	     */
+	    ALp_new->vp_Alloced = NULL;
+	    ALp_new->vp_BadRequest = vp_oldAlloced;
+	    ALp_new->SL_realloc.cp_FileName = cp_File;
+	    ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
+
+	    /*
+	     *  Add the item to the list.
+	     *  Exit.
+	     */
+	    AddToList(ALp_new);
+	    exit(-1);
+	}
+
+	old_cp_File = ALp_old->SL_memory.cp_FileName;
+	old_ssi_Line = ALp_old->SL_memory.ssi_LineNumber;
+	/*
+	 *	DO THE REAL WORK, by calling StrAllocVsprintf.
+	 *	If result is not NULL, record the information.
+	 */
+	StrAllocVsprintf(dest, inuse, fmt, ap);
+	vp_realloced = (void *)*dest;
+	if (vp_realloced != NULL) {
+	    AllocationList *ALp_new = FindInList(vp_realloced);
+	    if (!ALp_new) {
+		/* Look up again, list may have changed! - kw */
+		ALp_old = FindInList(vp_oldAlloced);
+		if (ALp_old == NULL) {
+		    LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
+		    return(*dest);
+		}
+		mark_realloced(ALp_old, *dest, strlen(*dest) + 1, cp_File, ssi_Line);
+		return(*dest);
+	    }
+	    if (vp_realloced == vp_oldAlloced) {
+		ALp_new->SL_memory.cp_FileName = old_cp_File;
+		ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
+		ALp_new->SL_realloc.cp_FileName = cp_File;
+		ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
+		return(*dest);
+	    }
+	    /* Look up again, list may have changed! - kw */
+	    ALp_old = FindInList(vp_oldAlloced);
+	    if (ALp_old == NULL) {
+		ALp_new->SL_memory.cp_FileName = old_cp_File;
+		ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
+		ALp_new->SL_realloc.cp_FileName = cp_File;
+		ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
+	    } else {
+		ALp_new->SL_memory.cp_FileName = old_cp_File;
+		ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
+		ALp_new->SL_realloc.cp_FileName = cp_File;
+		ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
+	    }
+	}
+	return(*dest);
+    }
+}
+
+/* Note: the following may need updating if HTSprintf in HTString.c
+ * is changed. - kw */
+#if ANSI_VARARGS
+PRIVATE char * LYLeakHTSprintf (char **pstr, CONST char *fmt, ...)
+#else
+PRIVATE char * LYLeakHTSprintf (va_alist)
+    va_dcl
+#endif
+{
+    char *str;
+    size_t inuse = 0;
+    va_list ap;
+    LYva_start(ap,fmt);
+    {
+#if !ANSI_VARARGS
+	char **		pstr = va_arg(ap, char **);
+	CONST char *	fmt  = va_arg(ap, CONST char *);
+#endif
+	if (pstr != 0 && *pstr != 0)
+	    inuse = strlen(*pstr);
+	str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
+			       inuse, fmt, &ap);
+    }
+    va_end(ap);
+    return str;
+}
+
+/* Note: the following may need updating if HTSprintf0 in HTString.c
+ * is changed. - kw */
+#if ANSI_VARARGS
+PRIVATE char * LYLeakHTSprintf0 (char **pstr, CONST char *fmt, ...)
+#else
+PRIVATE char * LYLeakHTSprintf0 (va_alist)
+    va_dcl
+#endif
+{
+    char *str;
+    va_list ap;
+    LYva_start(ap,fmt);
+    {
+#if !ANSI_VARARGS
+	char **		pstr = va_arg(ap, char **);
+	CONST char *	fmt  = va_arg(ap, CONST char *);
+#endif
+	str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
+			       0, fmt, &ap);
+    }
+    va_end(ap);
+    return str;
+}
+
+/*
+ *  HTSprintf and HTSprintf0 will be defined such that they effectively
+ *  call one of the following two functions that store away a copy to
+ *  the File & Line info in temporary hack variables, and then call
+ *  the real function (which is returned here as a function pointer)
+ *  to the regular HTSprintf/HTSprintf0 arguments.
+ *  It's probably a bit inefficient, but that shouldn't be noticeable
+ *  compared to all the time that memory tracking takes up for list
+ *  traversal. - kw
+ */
+PUBLIC HTSprintflike *Get_htsprintf_fn ARGS2(
+	CONST char *,	cp_File,
+	CONST short,	ssi_Line)
+{
+    leak_cp_File_hack = cp_File;
+    leak_ssi_Line_hack = ssi_Line;
+    return &LYLeakHTSprintf;
+}
+
+PUBLIC HTSprintflike *Get_htsprintf0_fn ARGS2(
+	CONST char *,	cp_File,
+	CONST short,	ssi_Line)
+{
+    leak_cp_File_hack = cp_File;
+    leak_ssi_Line_hack = ssi_Line;
+    return &LYLeakHTSprintf0;
+}
+
+#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
+
 /*
 **  Purpose:	Add a new allocation item to the list.
 **  Arguments:		ALp_new The new item to add.
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 735fccdc..25ce7699 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -287,7 +287,7 @@ struct dired_menu {
 PRIVATE BOOLEAN cannot_stat ARGS1(CONST char *, name)
 {
     char *tmpbuf = 0;
-    HTSprintf(&tmpbuf, gettext("Unable to get status of '%s'."), name);
+    HTSprintf0(&tmpbuf, gettext("Unable to get status of '%s'."), name);
     HTAlert(tmpbuf);
     FREE(tmpbuf);
     return FALSE;
@@ -356,7 +356,7 @@ PRIVATE int move_file ARGS2(char *, source, char *, target)
     char *msg = 0;
     char *args[5];
 
-    HTSprintf(&msg, gettext("move %s to %s"), source, target);
+    HTSprintf0(&msg, gettext("move %s to %s"), source, target);
     args[0] = "mv";
     args[1] = source;
     args[2] = target;
@@ -869,7 +869,7 @@ PRIVATE BOOLEAN create_file ARGS1(
 	 */
 	if (not_already_exists(testpath)) {
 	    char *msg = 0;
-	    HTSprintf(&msg,gettext("create %s"),testpath);
+	    HTSprintf0(&msg,gettext("create %s"),testpath);
 	    args[0] = "touch";
 	    args[1] = testpath;
 	    args[2] = (char *) 0;
@@ -914,7 +914,7 @@ PRIVATE BOOLEAN create_directory ARGS1(
 	 */
 	if (not_already_exists(testpath)) {
 	    char *msg = 0;
-	    HTSprintf(&msg,"make directory %s",testpath);
+	    HTSprintf0(&msg,"make directory %s",testpath);
 	    args[0] = "mkdir";
 	    args[1] = testpath;
 	    args[2] = (char *) 0;
@@ -1322,7 +1322,7 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	/*
 	 *  Call chmod().
 	 */
-	HTSprintf(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath);
+	HTSprintf0(&tmpbuf, "chmod %.4o %s", (unsigned int)new_mode, destpath);
 	sprintf(amode, "%.4o", (unsigned int)new_mode);
 	args[0] = "chmod";
 	args[1] = amode;
@@ -2090,7 +2090,7 @@ PUBLIC BOOLEAN local_install ARGS3(
 	    return 0;		/* don't do it */
 	}
 	args[src] = savepath;
-	HTSprintf(&tmpbuf, "install %s in %s", savepath, destpath);
+	HTSprintf0(&tmpbuf, "install %s in %s", savepath, destpath);
 	if (LYExecv(INSTALL_PATH, args, tmpbuf) <= 0) {
 	    FREE(tmpbuf);
 	    FREE(tmpdest);
@@ -2099,7 +2099,7 @@ PUBLIC BOOLEAN local_install ARGS3(
 	count++;
     } else {
 	char *name;
-	HTSprintf(&tmpbuf, "install in %s", destpath);
+	HTSprintf0(&tmpbuf, "install in %s", destpath);
 	while ((name = (char *)HTList_nextObject(tag))) {
 	    int err;
 	    args[src] = HTfullURL_toFile(name);
@@ -2333,7 +2333,7 @@ PRIVATE int LYExecv ARGS3(
     char *tmpbuf = 0;
 #ifdef __DJGPP__
     stop_curses();
-    HTSprintf(&tmpbuf, "%s", path);
+    HTSprintf0(&tmpbuf, "%s", path);
     for (n = 1; argv[n] != 0; n++)
 	HTSprintf(&tmpbuf, " %s", argv[n]);
     HTSprintf(&tmpbuf, "\n");
@@ -2357,7 +2357,7 @@ PRIVATE int LYExecv ARGS3(
     pid = fork();	/* fork and execute command */
     switch (pid) {
 	case -1:
-	    HTSprintf(&tmpbuf, gettext("Unable to %s due to system error!"), msg);
+	    HTSprintf0(&tmpbuf, gettext("Unable to %s due to system error!"), msg);
 	    rc = 0;
 	    break;	/* don't fall thru! - KW */
 	case 0:  /* child */
@@ -2386,7 +2386,7 @@ PRIVATE int LYExecv ARGS3(
 #endif /* !HAVE_WAITPID */
 	    if (WEXITSTATUS(wstatus) != 0 ||
 		WTERMSIG(wstatus) > 0)	{ /* error return */
-		HTSprintf(&tmpbuf, gettext("Probable failure to %s due to system error!"),
+		HTSprintf0(&tmpbuf, gettext("Probable failure to %s due to system error!"),
 				   msg);
 		rc = 0;
 	    }
diff --git a/src/LYMain.c b/src/LYMain.c
index baeb89b8..8c06d910 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -86,11 +86,6 @@ PUBLIC char *syslog_txt = NULL;		/* syslog arb text for session */
 PUBLIC char *LYCSwingPath = NULL;
 #endif /* VMS */
 
-#if HAVE_CUSERID && !defined(_XOPEN_SOURCE)
-/*extern char *cuserid();*/		/* workaround for Redhat 6.0 */
-		/* for the price of screwing up legitimate systems? Nah. */
-#endif
-
 #ifdef DIRED_SUPPORT
 PUBLIC BOOLEAN lynx_edit_mode = FALSE;
 PUBLIC BOOLEAN no_dired_support = FALSE;
@@ -444,15 +439,13 @@ PUBLIC BOOL ok_justify = TRUE;
 PUBLIC BOOLEAN with_backspaces = FALSE;
 #endif
 
-#ifndef NO_EMPTY_HREFLESS_A
 PUBLIC BOOL force_empty_hrefless_a = FALSE;
-#endif
 
 #ifndef NO_NONSTICKY_INPUTS
 PUBLIC BOOL sticky_inputs = TRUE;
+PUBLIC BOOL textfield_stop_at_left_edge=FALSE;
 #endif
 
-PUBLIC BOOL textfield_stop_at_left_edge=TRUE;
 
 #ifdef DISP_PARTIAL
 PUBLIC BOOLEAN display_partial_flag = TRUE; /* Display document during download */
@@ -1872,8 +1865,12 @@ PUBLIC int main ARGS2(
      *  interruptible (terminal is in raw mode, select() works).  -BL
      */
 #ifdef USE_PSRC
-    if (!dump_output_immediately)
-	HTMLSRC_init_caches(); /* do it before terminal is initialized*/
+    if (!dump_output_immediately) {
+	HTMLSRC_init_caches(FALSE); /* do it before terminal is initialized*/
+#ifdef LY_FIND_LEAKS
+	atexit(html_src_clean_data);
+#endif
+    }
 #endif
 
     if (!dump_output_immediately) {
@@ -2127,6 +2124,10 @@ PUBLIC void reload_read_cfg NOARGS
 	custom_display_charset = FALSE;
 	memset((char*)charset_subsets, 0, sizeof(charset_subset_t)*MAXCHARSETS);
 #endif
+
+#ifdef USE_PSRC
+	html_src_on_lynxcfg_reload();
+#endif
 	free_lynx_cfg(); /* free downloaders, printers, environments */
 	/*
 	 *  Process the configuration file.
@@ -2447,6 +2448,7 @@ static int convert_to_fun ARGS1(
 	    }
 	}
 	HTOutputFormat = HTAtom_for(outformat);
+	FREE(outformat);
     } else {
 	HTOutputFormat = NULL;
     }
@@ -3090,7 +3092,8 @@ with -dump, format output as with -traversal, but to stdout"
    ),
    PARSE_SET(
       "dont_wrap_pre",	SET_ARG,		&dont_wrap_pre,
-      "inhibit wrapping of text in <pre> when -dump'ing and -crawl'ing"
+      "inhibit wrapping of text in <pre> when -dump'ing and \n"
+      "-crawl'ing, mark wrapped lines in interactive session"
    ),
    PARSE_FUN(
       "dump",		FUNCTION_ARG,		dump_output_fun,
@@ -3147,12 +3150,10 @@ keys (may be incompatible with some curses packages)"
       "from",		TOGGLE_ARG,		&LYNoFromHeader,
       "toggle transmissions of From headers"
    ),
-#ifndef NO_EMPTY_HREFLESS_A
    PARSE_SET(
       "force_empty_hrefless_a",	SET_ARG,	&force_empty_hrefless_a,
       "force HREF-less 'A' elements to be empy (close them as soon as they are seen)"
    ),
-#endif
 #if !defined(NO_OPTION_FORMS) && !defined(NO_OPTION_MENU)
    PARSE_SET(
       "forms_options",	TOGGLE_ARG,		&LYUseFormsOptions,
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 1c8f18d8..157fe2a7 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -209,6 +209,8 @@ PRIVATE document newdoc;
 PRIVATE document curdoc;
 PRIVATE char *traversal_host = NULL;
 PRIVATE char *traversal_link_to_add = NULL;
+PRIVATE char *owner_address = NULL;  /* Holds the responsible owner's address     */
+PRIVATE char *ownerS_address = NULL; /* Holds owner's address during source fetch */
 
 #ifndef NO_NONSTICKY_INPUTS
 PRIVATE BOOL textinput_activated = FALSE;
@@ -238,6 +240,8 @@ PRIVATE void free_mainloop_variables NOARGS
 #endif
     FREE(traversal_host);
     FREE(traversal_link_to_add);
+    FREE(owner_address);
+    FREE(ownerS_address);
 #ifdef DIRED_SUPPORT
     clear_tags();
 #endif /* DIRED_SUPPORT */
@@ -530,7 +534,8 @@ PRIVATE void do_check_goto_URL ARGS3(
     }
 }
 
-PRIVATE void do_check_recall ARGS7(
+/* returns FALSE if user cancelled input or URL was invalid, TRUE otherwise */
+PRIVATE BOOL do_check_recall ARGS7(
     int,	ch,
     char *,	user_input_buffer,
     char **,	old_user_input,
@@ -540,6 +545,7 @@ PRIVATE void do_check_recall ARGS7(
     BOOLEAN *,	FirstURLRecall)
 {
     char *cp;
+    BOOL ret = FALSE;
 
     if (*old_user_input == 0)
 	StrAllocCopy(*old_user_input, "");
@@ -565,6 +571,7 @@ PRIVATE void do_check_recall ARGS7(
 		HTUserMsg2(WWW_ILLEGAL_URL_MESSAGE, user_input_buffer);
 		strcpy(user_input_buffer, *old_user_input);
 		FREE(*old_user_input);
+		ret = FALSE;
 		break;
 	    }
 	}
@@ -580,6 +587,7 @@ PRIVATE void do_check_recall ARGS7(
 	    strcpy(user_input_buffer, *old_user_input);
 	    FREE(*old_user_input);
 	    HTInfoMsg(CANCELLED);
+	    ret = FALSE;
 	    break;
 	}
 	if (recall && ch == UPARROW) {
@@ -623,6 +631,7 @@ PRIVATE void do_check_recall ARGS7(
 		    strcpy(user_input_buffer, *old_user_input);
 		    FREE(*old_user_input);
 		    HTInfoMsg(CANCELLED);
+		    ret = FALSE;
 		    break;
 		}
 		continue;
@@ -666,14 +675,17 @@ PRIVATE void do_check_recall ARGS7(
 		    strcpy(user_input_buffer, *old_user_input);
 		    FREE(*old_user_input);
 		    HTInfoMsg(CANCELLED);
+		    ret = FALSE;
 		    break;
 		}
 		continue;
 	    }
 	} else {
+	    ret = TRUE;
 	    break;
 	}
     }
+    return ret;
 }
 
 PRIVATE void do_cleanup_after_delete NOARGS
@@ -809,6 +821,44 @@ PRIVATE int DoTraversal ARGS2(
     return c;
 }
 
+#ifndef DONT_TRACK_INTERNAL_LINKS
+PRIVATE BOOLEAN check_history NOARGS
+{
+    CONST char *base;
+
+    if (!curdoc.post_data)
+	/*
+	 *  Normal case - List Page is not associated
+	 *  with post data. - kw
+	 */
+	return TRUE;
+
+    if (nhist > 0
+     && !LYresubmit_posts
+     && curdoc.post_data
+     && history[nhist - 1].post_data
+     && !strcmp(curdoc.post_data, history[nhist - 1].post_data)
+     && (base = HText_getContentBase()) != 0) {
+	 char *text = strncmp(history[nhist - 1].address, "LYNXIMGMAP:", 11)
+		     ? history[nhist - 1].address
+		     : history[nhist - 1].address + 11;
+	if (!strncmp(base, text, strlen(base))) {
+	    /*
+	     * Normal case - as best as we can check, the document at the top
+	     * of the history stack seems to be the document the List Page is
+	     * about (or a LYNXIMGMAP derived from it), and LYresubmit_posts is
+	     * not set, so don't prompt here.  If we actually have to repeat a
+	     * POST because, against expectations, the underlying document
+	     * isn't cached any more, HTAccess will prompt for confirmation,
+	     * unless we had LYK_NOCACHE -kw
+	     */
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+#endif
+
 PRIVATE int handle_LYK_ACTIVATE ARGS7(
     int *,	c,
     int,	cmd GCC_UNUSED,
@@ -1173,34 +1223,7 @@ gettext("Enctype multipart/form-data not yet supported!  Cannot submit."));
 		 */
 		if ( 0==strcmp(curdoc.address, LYlist_temp_url()) &&
 		    (LYIsListpageTitle(curdoc.title ? curdoc.title : ""))) {
-		    if (!curdoc.post_data ||
-			/*
-			 *  Normal case - List Page is not associated
-			 *  with post data. - kw
-			 */
-			(!LYresubmit_posts && curdoc.post_data &&
-			history[nhist - 1].post_data &&
-			!strcmp(curdoc.post_data,
-				 history[nhist - 1].post_data) &&
-			HText_getContentBase() &&
-			!strncmp(HText_getContentBase(),
-				 strncmp(history[nhist - 1].address,
-					 "LYNXIMGMAP:", 11) ?
-				 history[nhist - 1].address :
-				 history[nhist - 1].address + 11,
-				 strlen(HText_getContentBase())))) {
-			/*
-			 *  Normal case - as best as we can check, the
-			 *  document at the top of the history stack
-			 *  seems to be the document the List Page is
-			 *  about (or a LYNXIMGMAP derived from it),
-			 *  and LYresubmit_posts is not set, so don't
-			 *  prompt here.  If we actually have to repeat
-			 *  a POST because, against expectations, the
-			 *  underlying document isn't cached any more,
-			 *  HTAccess will prompt for confirmation,
-			 *  unless we had LYK_NOCACHE. - kw
-			 */
+		    if (check_history()) {
 			LYinternal_flag = TRUE;
 		    } else {
 			HTLastConfirmCancelled(); /* reset flag */
@@ -1532,13 +1555,13 @@ PRIVATE void handle_LYK_CLEAR_AUTH ARGS2(
 
 PRIVATE void handle_LYK_COMMENT ARGS4(
     BOOLEAN *,	refresh_screen,
-    char *,	owner_address,
+    char **,	owner_address_p,
     int *,	old_c,
     int,	real_c)
 {
     int	c;
 
-    if (!owner_address &&
+    if (!*owner_address_p &&
 	strncasecomp(curdoc.address, "http", 4)) {
 	if (*old_c != real_c)	{
 	    *old_c = real_c;
@@ -1551,7 +1574,7 @@ PRIVATE void handle_LYK_COMMENT ARGS4(
 	}
     } else {
 	if (HTConfirmDefault(CONFIRM_COMMENT, NO)) {
-	    if (!owner_address) {
+	    if (!*owner_address_p) {
 		/*
 		 *  No owner defined, so make a guess and
 		 *  and offer it to the user. - FM
@@ -1585,18 +1608,18 @@ PRIVATE void handle_LYK_COMMENT ARGS4(
 		c = HTConfirmDefault(temp, NO);
 		FREE(temp);
 		if (c == YES) {
-		    StrAllocCopy(owner_address, address);
+		    StrAllocCopy(*owner_address_p, address);
 		    FREE(address);
 		} else {
 		    FREE(address);
 		    return;
 		}
 	    }
-	    if (is_url(owner_address) != MAILTO_URL_TYPE) {
+	    if (is_url(*owner_address_p) != MAILTO_URL_TYPE) {
 		/*
 		 *  The address is a URL.  Just follow the link.
 		 */
-		StrAllocCopy(newdoc.address, owner_address);
+		StrAllocCopy(newdoc.address, *owner_address_p);
 		newdoc.internal_link = FALSE;
 	    } else {
 		/*
@@ -1616,15 +1639,15 @@ PRIVATE void handle_LYK_COMMENT ARGS4(
 		    }
 		}
 
-		if (strchr(owner_address,':')!=NULL)
+		if (strchr(*owner_address_p,':')!=NULL)
 		     /*
 		      *  Send a reply.	The address is after the colon.
 		      */
-		     reply_by_mail(strchr(owner_address,':')+1,
+		     reply_by_mail(strchr(*owner_address_p,':')+1,
 				   curdoc.address,
 				   (kp ? kp : ""), id);
 		else
-		    reply_by_mail(owner_address, curdoc.address,
+		    reply_by_mail(*owner_address_p, curdoc.address,
 				  (kp ? kp : ""), id);
 
 		FREE(tmptitle);
@@ -2368,7 +2391,7 @@ PRIVATE void handle_LYK_DWIMHELP ARGS1(
     CONST char **,	cshelpfile)
 {
     /*
-     *  Currently a different help file form the main
+     *  Currently a help file different from the main
      *  'helpfile' is shown only if current link is a
      *  text input form field. - kw
      */
@@ -3166,9 +3189,8 @@ PRIVATE void handle_LYK_INDEX_SEARCH ARGS4(
     }
 }
 
-PRIVATE BOOLEAN handle_LYK_INFO ARGS3(
+PRIVATE BOOLEAN handle_LYK_INFO ARGS2(
     char *,	prev_target,
-    char *,	owner_address,
     int *,	cmd)
 {
     /*
@@ -4194,7 +4216,7 @@ PRIVATE void handle_LYK_SOFT_DQUOTES NOARGS
  * seek confirmation if the safe element is not set.  - FM
  */
 PRIVATE void handle_LYK_SOURCE ARGS1(
-    char **,	ownerS_address)
+    char **,	ownerS_address_p)
 {
     if ((curdoc.post_data != NULL &&
 	 curdoc.safe != TRUE) &&
@@ -4211,7 +4233,7 @@ PRIVATE void handle_LYK_SOURCE ARGS1(
 #endif
     } else {
 	if (HText_getOwner())
-	    StrAllocCopy(*ownerS_address, HText_getOwner());
+	    StrAllocCopy(*ownerS_address_p, HText_getOwner());
 	LYUCPushAssumed(HTMainAnchor);
 #ifdef USE_PSRC
 	if (LYpsrc)
@@ -4236,7 +4258,7 @@ PRIVATE void handle_LYK_SOURCE ARGS1(
 	    HTMark_asSource();
 	psrc_view = FALSE;
 #endif
-	FREE(*ownerS_address);  /* not used with source_cache */
+	FREE(*ownerS_address_p);  /* not used with source_cache */
 	LYUCPopAssumed();	/* probably a right place here */
 	HTMLSetCharacterHandling(current_char_set);  /* restore now */
 
@@ -4716,7 +4738,7 @@ PRIVATE void handle_LYK_WHEREIS ARGS3(
     /*
      *	Force a redraw to ensure highlighting of hits
      *	even when found on the same page, or clearing
-     *	of highlighting is the default search string
+     *	of highlighting if the default search string
      *	was erased without replacement. - FM
      */
     /*
@@ -4783,34 +4805,7 @@ PRIVATE void handle_LYK_digit ARGS7(
 	    newdoc.internal_link = TRUE;
 	    if (LYIsListpageTitle(curdoc.title ? curdoc.title : "") &&
 		0==strcmp(HTLoadedDocumentURL(), LYlist_temp_url())) {
-		if (!curdoc.post_data ||
-		    /*
-		     *	Normal case - List Page is not associated
-		     *	with post data. - kw
-		     */
-		    (!LYresubmit_posts && curdoc.post_data &&
-		     history[nhist - 1].post_data &&
-		     !strcmp(curdoc.post_data,
-			     history[nhist - 1].post_data) &&
-		     HText_getContentBase() &&
-		     !strncmp(HText_getContentBase(),
-			      strncmp(history[nhist - 1].address,
-				      "LYNXIMGMAP:", 11) ?
-			      history[nhist - 1].address :
-			      history[nhist - 1].address + 11,
-			      strlen(HText_getContentBase())))) {
-		    /*
-		     *	Normal case - as best as we can check, the
-		     *	document at the top of the history stack
-		     *	seems to be the document the List Page is
-		     *	about (or a LYNXIMGMAP derived from it),
-		     *	and LYresubmit_posts is not set, so don't
-		     *	prompt here.  If we actually have to repeat
-		     *	a POST because, against expectations, the
-		     *	underlying document isn't cached any more,
-		     *	HTAccess will prompt for confirmation,
-		     *	unless we had LYK_NOCACHE. - kw
-		     */
+		if (check_history()) {
 		    LYinternal_flag = TRUE;
 		} else {
 		    HTLastConfirmCancelled(); /* reset flag */
@@ -4984,8 +4979,6 @@ int mainloop NOARGS
     int arrowup = FALSE, show_help = FALSE;
     char prev_target[512];
     char user_input_buffer[MAX_LINE];
-    char *owner_address = NULL;  /* Holds the responsible owner's address     */
-    char *ownerS_address = NULL; /* Holds owner's address during source fetch */
     CONST char *cshelpfile = NULL;
     BOOLEAN first_file = TRUE;
     BOOLEAN popped_doc = FALSE;
@@ -6037,6 +6030,7 @@ try_again:
 #ifndef NO_NONSTICKY_INPUTS
 	    textinput_drawn = FALSE;
 #endif
+
 	    refresh_screen = FALSE;
 
 	    HText_pageDisplay(Newline, prev_target);
@@ -6621,7 +6615,7 @@ new_cmd:  /*
 	case LYK_TO_CLIPBOARD:	/* ^S */
 	    {
 		if (put_clip(links[curdoc.link].lname) == 0) {
-		    HTInfoMsg("URL to Clip Borad.");
+		    HTInfoMsg("URL to Clip Board.");
 		} else {
 		    HTInfoMsg("Current URL is empty.");
 		}
@@ -6765,9 +6759,9 @@ new_cmd:  /*
 	    if (handle_LYK_GOTO(&ch, user_input_buffer, &temp, &recall,
 				&URLTotal, &URLNum, &FirstURLRecall, &old_c,
 				real_c)) {
-		do_check_recall (ch, user_input_buffer, &temp, URLTotal,
-				 &URLNum, recall, &FirstURLRecall);
-		do_check_goto_URL(user_input_buffer, &temp, &force_load);
+		if (do_check_recall (ch, user_input_buffer, &temp, URLTotal,
+				 &URLNum, recall, &FirstURLRecall))
+		    do_check_goto_URL(user_input_buffer, &temp, &force_load);
 	    }
 	    break;
 
@@ -6801,8 +6795,8 @@ new_cmd:  /*
 	    handle_LYK_WHEREIS(cmd, prev_target, &refresh_screen);
 	    break;
 
-	case LYK_COMMENT:	/* reply by mail */
-	    handle_LYK_COMMENT(&refresh_screen, owner_address, &old_c, real_c);
+	case LYK_COMMENT: 	/* reply by mail */
+	    handle_LYK_COMMENT(&refresh_screen, &owner_address, &old_c, real_c);
 	    break;
 
 #ifdef DIRED_SUPPORT
@@ -6849,7 +6843,7 @@ new_cmd:  /*
 #endif /* DIRED_SUPPORT && OK_INSTALL */
 
 	case LYK_INFO:		/* show document info */
-	    if (handle_LYK_INFO(prev_target, owner_address, &cmd))
+	    if (handle_LYK_INFO(prev_target, &cmd))
 		goto new_cmd;
 	    break;
 
@@ -6969,9 +6963,9 @@ new_cmd:  /*
 	    if (handle_LYK_JUMP(c, user_input_buffer, &temp, &recall,
 				    &FirstURLRecall, &URLNum, &URLTotal, &ch,
 				    &old_c, real_c)) {
-		do_check_recall (ch, user_input_buffer, &temp, URLTotal,
-				 &URLNum, recall, &FirstURLRecall);
-		do_check_goto_URL(user_input_buffer, &temp, &force_load);
+		if (do_check_recall (ch, user_input_buffer, &temp, URLTotal,
+				 &URLNum, recall, &FirstURLRecall))
+		    do_check_goto_URL(user_input_buffer, &temp, &force_load);
 	    }
 	    break;
 
diff --git a/src/LYMap.c b/src/LYMap.c
index b74c743d..04cc663e 100644
--- a/src/LYMap.c
+++ b/src/LYMap.c
@@ -533,7 +533,7 @@ PRIVATE int LYLoadIMGmap ARGS4 (
 			   sink, anAnchor);
 
     if (!target || target == NULL) {
-	HTSprintf(&buf, CANNOT_CONVERT_I_TO_O,
+	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
 		HTAtom_name(format_in), HTAtom_name(format_out));
 	HTAlert(buf);
 	FREE(buf);
diff --git a/src/LYOptions.c b/src/LYOptions.c
index ba1e2973..ab88556a 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -2592,7 +2592,7 @@ redraw:
 	    cmd = LYK_QUIT;
 #ifndef USE_SLANG
 	} else if (c == MOUSE_KEY) {
-	    if ((cmd = fancy_mouse(form_window, i + 1 + window_offset, &cur_choice)) < 0)
+	    if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_choice)) < 0)
 		goto redraw;
 	    if  (cmd == LYK_ACTIVATE)
 		break;
diff --git a/src/LYPrettySrc.c b/src/LYPrettySrc.c
index f7e5538c..3b279c8b 100644
--- a/src/LYPrettySrc.c
+++ b/src/LYPrettySrc.c
@@ -6,6 +6,10 @@
 #include <LYHash.h>
 #include <LYPrettySrc.h>
 
+ /* This file creates too many "leak detected" entries in Lynx.leaks. */
+#define NO_MEMORY_TRACKING
+#include <LYLeaks.h>
+
 #ifdef USE_PSRC
 BOOL psrc_convert_string = FALSE;
 PUBLIC BOOL psrc_view = FALSE;/* this is read by SGML_put_character - TRUE
@@ -21,7 +25,7 @@ PUBLIC BOOL mark_htext_as_source=FALSE;
      support), the style cache and markup are created before entering the
      mainloop. */
 PUBLIC BOOL psrcview_no_anchor_numbering = FALSE;
-PUBLIC char* HTL_tagspecs[HTL_num_lexems] = {
+PRIVATE char* HTL_tagspecs_defaults[HTL_num_lexemes] = {
  /* these values are defaults. They are also listed in comments of distibution's
      lynx.cfg.*/
 #ifdef USE_COLOR_STYLE
@@ -38,26 +42,27 @@ PUBLIC char* HTL_tagspecs[HTL_num_lexems] = {
     "span.htmlsrc_badattr:!span",
     "span.htmlsrc_sgmlspecial:!span"
 #else
-    "b:!b",
-    "b:!b",
-    ":",
-    "!b:b",
-    "b:!b",
-    "b:!b",
-    ":",
-    ":",
-    "b:!b",
-    ":",
-    "!b:b",
-    "b:!b"
+    "b:!b",	/*	comment	*/
+    "b:!b",	/*	tag	*/
+    "b:!b",	/*	attrib	*/
+    ":",	/*	attrval	*/
+    "b:!b",	/*	abracket*/
+    "b:!b",	/*	entity	*/
+    ":",	/*	href	*/
+    ":",	/*	entire	*/
+    "b:!b",	/*	badseq	*/
+    ":",	/*	badtag	*/
+    ":",	/*	badattr	*/
+    "b:!b"	/*	sgmlspec*/
 #endif
 };
 
+PUBLIC char* HTL_tagspecs[HTL_num_lexemes];
 
  /* these are pointers since tagspec can be empty (the pointer will be NULL
     in that case) */
-PUBLIC HT_tagspec* lexem_start[HTL_num_lexems];
-PUBLIC HT_tagspec* lexem_end[HTL_num_lexems];
+PUBLIC HT_tagspec* lexeme_start[HTL_num_lexemes];
+PUBLIC HT_tagspec* lexeme_end[HTL_num_lexemes];
 
 PUBLIC int tagname_transform = 2;
 PUBLIC int attrname_transform = 2;
@@ -102,6 +107,9 @@ PRIVATE void append_close_tag ARGS3(
     subj->present = (BOOL*)calloc( nattr*sizeof (BOOL), 1);
     subj->value = (char**)calloc( nattr*sizeof (char*), 1);
     subj->start = FALSE;
+#ifdef USE_COLOR_STYLE
+    subj->class_name = NULL;
+#endif
 
     if (!*head) {
 	*head = subj; *tail = subj;
@@ -150,17 +158,16 @@ PRIVATE void append_open_tag ARGS4(
 	hcode = hash_code_aggregate_lower_str(classname, hcode);
 	StrAllocCopy(subj->class_name, classname);
     } else {
-	subj->class_name = "";
+	StrAllocCopy(subj->class_name,"");
     }
     subj->style = hcode;
 #endif
 }
 
-
 /* returns 1 if incorrect */
 PUBLIC int html_src_parse_tagspec ARGS4(
 	char*,		ts,
-	HTlexem,	lexem,
+	HTlexeme,	lexeme,
 	BOOL,		checkonly,
 	BOOL,		isstart)
 {
@@ -172,7 +179,7 @@ PUBLIC int html_src_parse_tagspec ARGS4(
     char stop = FALSE, after_excl = FALSE;
     html_src_check_state state = HTSRC_CK_normal;
     HT_tagspec* head = NULL, *tail = NULL;
-    HT_tagspec** slot = ( isstart ? lexem_start : lexem_end ) +lexem;
+    HT_tagspec** slot = ( isstart ? lexeme_start : lexeme_end ) +lexeme;
 
     while (!stop) {
 	switch (state) {
@@ -190,7 +197,7 @@ PUBLIC int html_src_parse_tagspec ARGS4(
 		    default:
 			if (isalpha(*p) || *p == '_') {
 			    tagstart = p;
-			    while (*p && ( isalpha(*p) || *p == '_') )
+			    while (*p && ( isalnum(*p) || *p == '_') )
 				 ++p;
 			    tagend = p;
 			    state = HTSRC_CK_after_tagname;
@@ -243,7 +250,7 @@ PUBLIC int html_src_parse_tagspec ARGS4(
 			char save, save1;
 			if ( isalpha(*p) || *p == '_' ) {
 			    classstart = p;
-			    while (*p && ( isalpha(*p) || *p == '_') ) ++p;
+			    while (*p && ( isalnum(*p) || *p == '_') ) ++p;
 			    classend = p;
 			    save = *classend;
 			    *classend = '\0';
@@ -274,26 +281,67 @@ PUBLIC int html_src_parse_tagspec ARGS4(
     return 0;
 }
 
-/*it shouldn't fail anyway - since everything is checked before it's called. */
-PUBLIC void HTMLSRC_init_caches NOARGS
+/*this will clean the data associated with lexeme 'l' */
+PUBLIC void html_src_clean_item ARGS1(
+	HTlexeme, l)
+{
+    int i;
+    if (HTL_tagspecs[l])
+	FREE(HTL_tagspecs[l]);
+    for(i = 0; i < 2; ++i) {
+	HT_tagspec* cur,** pts = ( i ? lexeme_start : lexeme_end)+l,*ts = *pts;
+	*pts = NULL;
+	while (ts) {
+	    FREE(ts->present);
+	    FREE(ts->value);
+#ifdef USE_COLOR_STYLE
+	    if (ts->start) {
+		FREE(ts->class_name);
+	    }
+#endif
+	    cur = ts;
+	    ts = ts->next;
+	    FREE(cur);
+	}
+    }
+}
+
+/*this will be registered with atexit*/
+PUBLIC void html_src_clean_data NOARGS
+{
+    int i;
+    for (i = 0; i < HTL_num_lexemes; ++i)
+	html_src_clean_item(i);
+}
+
+PUBLIC void html_src_on_lynxcfg_reload NOARGS
+{
+    html_src_clean_data();
+    HTMLSRC_init_caches(TRUE);
+}
+
+PUBLIC void HTMLSRC_init_caches ARGS1(
+	BOOL,	dont_exit)
 {
     int i;
     char* p;
     char buf[1000];
 
-    for (i = 0; i < HTL_num_lexems; ++i) {
-	if (HTL_tagspecs[i])
-	    strcpy(buf, HTL_tagspecs[i]);
-	else
-	    buf[0] = '\0';
+    for (i = 0; i < HTL_num_lexemes; ++i) {
+
+	strcpy(buf, HTL_tagspecs_defaults[i]);
+	p = HTL_tagspecs_defaults[i];
+	HTL_tagspecs[i] = NULL;
+	StrAllocCopy(HTL_tagspecs[i],p);
+
 	if ((p = strchr(buf, ':')) != 0)
 	    *p = '\0';
-	if (html_src_parse_tagspec(buf, i, FALSE, TRUE) ) {
-	    fprintf(stderr, "internal error while caching 1st tagspec of %d lexem", i);
+	if (html_src_parse_tagspec(buf, i, FALSE, TRUE) && !dont_exit ) {
+	    fprintf(stderr, "internal error while caching 1st tagspec of %d lexeme", i);
 	    exit_immediately(-1);
 	}
-	if (html_src_parse_tagspec( p ? p+1 : NULL , i, FALSE, FALSE) )	 {
-	    fprintf(stderr, "internal error while caching 2nd tagspec of %d lexem", i);
+	if (html_src_parse_tagspec( p ? p+1 : NULL , i, FALSE, FALSE) && !dont_exit) {
+	    fprintf(stderr, "internal error while caching 2nd tagspec of %d lexeme", i);
 	    exit_immediately(-1);
 	}
     }
diff --git a/src/LYPrettySrc.h b/src/LYPrettySrc.h
index e49b3fd8..02a8f75f 100644
--- a/src/LYPrettySrc.h
+++ b/src/LYPrettySrc.h
@@ -23,8 +23,8 @@ extern BOOL psrc_first_tag; /* this is also used in HTML.c to trigger the
 
 extern BOOL mark_htext_as_source;
 
-/* here is a list of lexem codes. */
-typedef enum _HTlexem {
+/* here is a list of lexeme codes. */
+typedef enum _HTlexeme {
   HTL_comm=0,
   HTL_tag,
   HTL_attrib,
@@ -37,8 +37,8 @@ typedef enum _HTlexem {
   HTL_badtag,
   HTL_badattr,
   HTL_sgmlspecial,
-  HTL_num_lexems
-} HTlexem;
+  HTL_num_lexemes
+} HTlexeme;
 
 typedef struct _HT_tagspec
 {
@@ -55,13 +55,16 @@ typedef struct _HT_tagspec
     BOOL start; /* if true, then this starts element, otherwise - ends */    
 } HT_tagspec;
 
-extern char* HTL_tagspecs[HTL_num_lexems];
-extern HT_tagspec* lexem_start[HTL_num_lexems];
-extern HT_tagspec* lexem_end[HTL_num_lexems];
+extern char* HTL_tagspecs[HTL_num_lexemes];
+extern HT_tagspec* lexeme_start[HTL_num_lexemes];
+extern HT_tagspec* lexeme_end[HTL_num_lexemes];
 
-extern int html_src_parse_tagspec PARAMS((char* ts, HTlexem lexem,
+extern int html_src_parse_tagspec PARAMS((char* ts, HTlexeme lexeme,
                      BOOL checkonly,BOOL isstart));
-extern void HTMLSRC_init_caches NOPARAMS;
+extern void HTMLSRC_init_caches PARAMS((BOOL dont_exit));
+extern void html_src_clean_item PARAMS((HTlexeme l));
+extern void html_src_clean_data NOPARAMS;
+extern void html_src_on_lynxcfg_reload NOPARAMS;
 
 /* these 2 vars tell what kind of transform should be appiled to tag names
   and attribute names. 0 - lowercase, 1 - as is, 2 uppercase. */
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 03ea1b04..6f660812 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -770,12 +770,13 @@ PRIVATE void send_file_to_mail ARGS3(
     if (keypad_mode)
 	printlist(outfile_fp, FALSE);
 
+#if defined(WIN_EX) || defined(__DJGPP__)
 #if defined(WIN_EX)	/* 1998/08/17 (Mon) 16:29:49 */
-    buffer = NULL;
     if (mail_is_blat)
 	HTSprintf0(&buffer, "%s %s -t \"%s\"",
 		system_mail, my_temp, user_response);
     else
+#endif /* WIN_EX */
 	HTSprintf0(&buffer, "%s -t \"%s\" -F %s",
 			system_mail, user_response, my_temp);
     LYCloseTempFP(outfile_fp);	/* Close the tmpfile. */
@@ -789,9 +790,9 @@ PRIVATE void send_file_to_mail ARGS3(
     SetOutputMode( O_BINARY );
 
     LYRemoveTemp(my_temp); /* Delete the tmpfile. */
-#else /* !WIN_EX */
+#else /* !WIN_EX && !__DJGPP__ */
     pclose(outfile_fp);
-#endif
+#endif /* WIN_EX || __DJGPP__ */
 #endif /* VMS */
 
 done:	/* send_file_to_mail() */
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 2d47628e..e3adb938 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -659,6 +659,20 @@ static int keymap_fun ARGS1(
 		BOOLEAN success = FALSE;
 		int lkc = lkcstring_to_lkc(key);
 		int lec = -1;
+		/*
+		 *  PASS! tries to enter the key into the LYLineEditors
+		 *  bindings in a different way from PASS, namely as
+		 *  binding that maps to the specific lynx actioncode
+		 *  (rather than to LYE_FORM_PASS).  That only works
+		 *  for lynx keycodes with modifier bit set, and we
+		 *  have no documented/official way to specify this
+		 *  in the KEYMAP directive, although it can be made
+		 *  to work e.g. by specifying a hex value that has the
+		 *  modifier bit set.  But knowledge about the bit
+		 *  pattern of modifiers should remain in internal
+		 *  matter subject to change...  At any rate, if
+		 *  PASS! fails try it the same way as for PASS. - kw
+		 */
 		if (strcasecomp(efunc, "PASS!") == 0) {
 		    if (func) {
 			lec = LYE_FORM_LAC|lacname_to_lac(func);
@@ -1090,7 +1104,7 @@ static void html_src_bad_syntax ARGS2(
 
 
 static int parse_html_src_spec ARGS3(
-	    HTlexem, lexem_code,
+	    HTlexeme, lexeme_code,
 	    char*, value,
 	    char*, option_name)
 {
@@ -1109,16 +1123,17 @@ static int parse_html_src_spec ARGS3(
 	BS();
     *ts2 = '\0';
 
-    if ( html_src_parse_tagspec(value, lexem_code, TRUE, TRUE)
-	|| html_src_parse_tagspec(ts2, lexem_code, TRUE, TRUE) )
+    CTRACE((tfp,"ReadCFG - parsing tagspec '%s:%s' for option '%s'\n",value,ts2,option_name));
+    html_src_clean_item(lexeme_code);
+    if ( html_src_parse_tagspec(value, lexeme_code, FALSE, TRUE)
+	|| html_src_parse_tagspec(ts2, lexeme_code, FALSE, FALSE) )
     {
 	*ts2 = ':';
 	BS();
     }
 
     *ts2 = ':';
-    HTL_tagspecs[lexem_code] = NULL;
-    StrAllocCopy(HTL_tagspecs[lexem_code],value);
+    StrAllocCopy(HTL_tagspecs[lexeme_code],value);
 #undef BS
     return 0;
 }
@@ -1253,9 +1268,7 @@ static Config_Type Config_Table [] =
      PARSE_SET("focus_window", CONF_BOOL, &focus_window),
 #endif
      PARSE_SET("force_8bit_toupper", CONF_BOOL, &UCForce8bitTOUPPER),
-#ifndef NO_EMPTY_HREFLESS_A
      PARSE_SET("force_empty_hrefless_a", CONF_BOOL, &force_empty_hrefless_a),
-#endif
      PARSE_SET("force_ssl_cookies_secure", CONF_BOOL, &LYForceSSLCookiesSecure),
 #if !defined(NO_OPTION_FORMS) && !defined(NO_OPTION_MENU)
      PARSE_SET("forms_options", CONF_BOOL, &LYUseFormsOptions),
diff --git a/src/LYStrings.c b/src/LYStrings.c
index a4a7fe29..dd55c262 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -263,17 +263,32 @@ PRIVATE int XYdist ARGS5(
     int,	y2,
     int,	dx2)
 {
-    int xerr = x2 - x1, yerr = y2 - y1;
+    int xerr = 3 * (x2 - x1), yerr = 9 * (y2 - y1);
 
     if (xerr < 0)
-	xerr = x1 - x2 - dx2;
+	xerr = 3 * (x1 - x2 - dx2) + 1;	/* pos after string not really in it */
     if (xerr < 0)
 	xerr = 0;
     if (yerr < 0)
 	yerr = -yerr;
-    if (xerr < 3 && yerr)	/* x-distance of 3 better than y-dist of 1 */
-	return yerr + 1;
-    return (xerr + 2)/3 + yerr;	/* Subjective factor of distance */
+    if (!yerr)			/* same line is good */
+	return (xerr > 0) ? (xerr*2 - 1) : 0;
+    if (xerr < 9 && yerr)   /* x-dist of 3 cell better than y-dist of 1 cell */
+	yerr += (9 - xerr);
+    return 2 * xerr + yerr; /* Subjective factor; ratio -> approx. 6 / 9 */
+/*
+old: (IZ 1999-07-30)
+ 3  2  2  2  1  1  1 XX XX XX XX XX  0  1  1  1  2  2  2  3  3
+ 4\ 3  3  3  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3/ 4  4
+ 5  4  4  4\ 3  3  3  3  3  3  3  3  3  3  3  3/ 4  4  4  5  5
+ 6  5  5  5  4  4  4  4  4  4  4  4  4  4  4  4  5  5  5  6  5
+now: (kw 1999-10-23)
+41 35 29|23 17 11  5 XX XX XX XX XX  1  7 13 19 25|31 37 43 49
+   45 39 33\27 24 21 18 18 18 18 18 19 22 25 28/34 40 46 50
+      48 42 36 33 30\27 27 27 27 27 28/31 34 37 43 49
+         51 45 42 39 36 36 36 36 36 37 40 43 46 49
+               51 48 45 45 45 45 45 46 49 52
+*/
 }
 
 /* Given X and Y coordinates of a mouse event, set mouse_link to the
@@ -312,9 +327,9 @@ PRIVATE int set_clicked_link ARGS4(
 	mouse_link = -2;
 	y -= 1 + (LYsb_arrow != 0);
 	if (y < 0)
-	    return INSERT_KEY;
+	    return LAC_TO_LKC0(LYK_UP_TWO);
 	if (y >= h)
-	    return REMOVE_KEY;
+	    return LAC_TO_LKC0(LYK_DOWN_TWO);
 #ifdef DISP_PARTIAL			/* Newline is not defined otherwise */
 	if (clicks >= 2) {
 	    double frac = (1. * y)/(h - 1);
@@ -327,13 +342,13 @@ PRIVATE int set_clicked_link ARGS4(
 	}
 #endif
 	if (y < LYsb_begin)
-	    return PGUP;
+	    return LAC_TO_LKC0(LYK_PREV_PAGE);
 	if (y >= LYsb_end)
-	    return PGDOWN;
+	    return LAC_TO_LKC0(LYK_NEXT_PAGE);
 	mouse_link = -1;		/* No action in edit fields */
 #endif
     } else {
-	int mouse_err = 4, /* subjctv-dist better than this for approx stuff */
+	int mouse_err = 29, /* subjctv-dist better than this for approx stuff */
 	    cur_err;
 
 	/* Loop over the links and see if we can get a match */
@@ -355,6 +370,18 @@ PRIVATE int set_clicked_link ARGS4(
 	    /* Check the first line of the link */
 	    if ( links[i].hightext != NULL) {
 		cur_err = XYdist(x, y, links[i].lx, links[i].ly, len);
+		/* Check the second line */
+		if (cur_err > 0 && links[i].hightext2 != NULL) {
+		    /* Note that there is never hightext2 if is_text */
+		    int cur_err_2 = XYdist(x, y,
+					   links[i].hightext2_offset,
+					   links[i].ly+1,
+					   strlen(links[i].hightext2));
+		    cur_err = HTMIN(cur_err, cur_err_2);
+		}
+		if (cur_err > 0 && is_text)
+		    cur_err--;	/* a bit of preference for text fields,
+				   enter field if hit exactly at end - kw */
 		if (cur_err == 0) {
 		    int cury, curx;
 
@@ -390,6 +417,7 @@ PRIVATE int set_clicked_link ARGS4(
 		    mouse_link = i;
 		}
 	    }
+#if 0	/* should not have second line if no first - kw */
 	    /* Check the second line */
 	    if (links[i].hightext2 != NULL) {
 		cur_err = XYdist(x, y,
@@ -405,6 +433,7 @@ PRIVATE int set_clicked_link ARGS4(
 		    mouse_link = i;
 		}
 	    }
+#endif
 	}
 	/*
 	 * If a link was hit, we must look for a key which will activate
@@ -525,10 +554,13 @@ PUBLIC char * LYmbcs_skip_glyphs ARGS3(
  *  LYmbcsstrlen() returns the printable length of a string
  *  that might contain IsSpecial or multibyte (CJK or UTF8)
  *  characters. - FM
+ *  Counts glyph cells if count_gcells is set. (Full-width
+ *  characters in CJK mode count as two.)
  */
-PUBLIC int LYmbcsstrlen ARGS2(
-	char *,		str,
-	BOOL,		utf_flag)
+PUBLIC int LYmbcsstrlen ARGS3(
+	char *, 	str,
+	BOOL,		utf_flag,
+	BOOL,		count_gcells)
 {
     int i, j, len = 0;
 
@@ -550,10 +582,6 @@ PUBLIC int LYmbcsstrlen ARGS2(
 		i++;
 		j++;
 	    }
-	} else if (!utf_flag && HTCJK != NOCJK && !isascii(str[i]) &&
-		    str[(i + 1)] != '\0' &&
-		    !IsSpecialAttrChar(str[(i + 1)])) {
-	    i++;
 	}
     }
 
@@ -1129,26 +1157,43 @@ PRIVATE int read_keymap_file NOARGS
 PRIVATE void setup_vtXXX_keymap NOARGS
 {
     static Keysym_String_List table[] = {
-	EXTERN_KEY( "\033[A",	"^(ku)", UPARROW,	KEY_UP ),
-	EXTERN_KEY( "\033OA",	"^(ku)", UPARROW,	KEY_UP ),
-	EXTERN_KEY( "\033[B",	"^(kd)", DNARROW,	KEY_DOWN ),
-	EXTERN_KEY( "\033OB",	"^(kd)", DNARROW,	KEY_DOWN ),
-	EXTERN_KEY( "\033[C",	"^(kr)", RTARROW,	KEY_RIGHT ),
-	EXTERN_KEY( "\033OC",	"^(kr)", RTARROW,	KEY_RIGHT ),
-	EXTERN_KEY( "\033[D",	"^(kl)", LTARROW,	KEY_LEFT ),
-	EXTERN_KEY( "\033OD",	"^(kl)", LTARROW,	KEY_LEFT ),
-	EXTERN_KEY( "\033[1~",	"^(@0)", FIND_KEY,	KEY_FIND ),
-	EXTERN_KEY( "\033[2~",	"^(kI)", INSERT_KEY,	KEY_IC ),
-	EXTERN_KEY( "\033[3~",	"^(kD)", REMOVE_KEY,	KEY_DC ),
-	EXTERN_KEY( "\033[4~",	"^(*6)", SELECT_KEY,	KEY_SELECT ),
-	EXTERN_KEY( "\033[5~",	"^(kP)", PGUP,		KEY_PPAGE ),
-	EXTERN_KEY( "\033[6~",	"^(kN)", PGDOWN,	KEY_NPAGE ),
-	EXTERN_KEY( "\033[8~",	"^(@7)", END_KEY,	KEY_END ),
-	EXTERN_KEY( "\033[7~",	"^(kh)", HOME,		KEY_HOME),
-	EXTERN_KEY( "\033[28~",	"^(k1)", F1,		KEY_F(1) ),
-	EXTERN_KEY( "\033OP",	"^(k1)", F1,		KEY_F(1) ),
-	EXTERN_KEY( "\033[OP",	"^(k1)", F1,		KEY_F(1) ),
-	EXTERN_KEY( "\033[29~",	"^(F6)", DO_KEY,	KEY_F(16) ),
+	INTERN_KEY( "\033[A",	UPARROW,	KEY_UP ),
+	INTERN_KEY( "\033OA",	UPARROW,	KEY_UP ),
+	INTERN_KEY( "\033[B",	DNARROW,	KEY_DOWN ),
+	INTERN_KEY( "\033OB",	DNARROW,	KEY_DOWN ),
+	INTERN_KEY( "\033[C",	RTARROW,	KEY_RIGHT ),
+	INTERN_KEY( "\033OC",	RTARROW,	KEY_RIGHT ),
+	INTERN_KEY( "\033[D",	LTARROW,	KEY_LEFT ),
+	INTERN_KEY( "\033OD",	LTARROW,	KEY_LEFT ),
+	INTERN_KEY( "\033[1~",	FIND_KEY,	KEY_FIND ),
+	INTERN_KEY( "\033[2~",	INSERT_KEY,	KEY_IC ),
+	INTERN_KEY( "\033[3~",	REMOVE_KEY,	KEY_DC ),
+	INTERN_KEY( "\033[4~",	SELECT_KEY,	KEY_SELECT ),
+	INTERN_KEY( "\033[5~",	PGUP,		KEY_PPAGE ),
+	INTERN_KEY( "\033[6~",	PGDOWN,		KEY_NPAGE ),
+	INTERN_KEY( "\033[7~",	HOME,		KEY_HOME),
+	INTERN_KEY( "\033[8~",	END_KEY,	KEY_END ),
+	INTERN_KEY( "\033[11~",	F1,		KEY_F(1) ),
+	INTERN_KEY( "\033[28~",	F1,		KEY_F(1) ),
+	INTERN_KEY( "\033OP",	F1,		KEY_F(1) ),
+	INTERN_KEY( "\033[OP",	F1,		KEY_F(1) ),
+	INTERN_KEY( "\033[29~",	DO_KEY,		KEY_F(16) ),
+#if defined(USE_SLANG) && !defined(VMS)
+	INTERN_KEY(	"^(ku)", UPARROW,	KEY_UP ),
+	INTERN_KEY(	"^(kd)", DNARROW,	KEY_DOWN ),
+	INTERN_KEY(	"^(kr)", RTARROW,	KEY_RIGHT ),
+	INTERN_KEY(	"^(kl)", LTARROW,	KEY_LEFT ),
+	INTERN_KEY(	"^(@0)", FIND_KEY,	KEY_FIND ),
+	INTERN_KEY(	"^(kI)", INSERT_KEY,	KEY_IC ),
+	INTERN_KEY(	"^(kD)", REMOVE_KEY,	KEY_DC ),
+	INTERN_KEY(	"^(*6)", SELECT_KEY,	KEY_SELECT ),
+	INTERN_KEY(	"^(kP)", PGUP,		KEY_PPAGE ),
+	INTERN_KEY(	"^(kN)", PGDOWN,	KEY_NPAGE ),
+	INTERN_KEY(	"^(@7)", END_KEY,	KEY_END ),
+	INTERN_KEY(	"^(kh)", HOME,		KEY_HOME),
+	INTERN_KEY(	"^(k1)", F1,		KEY_F(1) ),
+	INTERN_KEY(	"^(F6)", DO_KEY,	KEY_F(16) ),
+#endif /* SLANG && !VMS */
     };
     size_t n;
     for (n = 0; n < TABLESIZE(table); n++)
@@ -3475,8 +3520,13 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(
  * LYno_attr_mbcs_case_strstr will find the first occurrence of the string
  * pointed to by tarptr in the string pointed to by chptr.
  * It takes account of MultiByte Character Sequences (UTF8).
- * The physical length of the displayed string up to the end of the target
- * string is returned in *nendp if the search is successful.
+ * The physical lengths of the displayed string up to the start and
+ * end (= next position after) of the target string are returned in *nstartp
+ * and *nendp if the search is successful.
+ *   These lengths count glyph cells if count_gcells is set. (Full-width
+ *   characters in CJK mode count as two.)  Normally that's what we want.
+ *   They count actual glyphs if count_gcells is unset. (Full-width
+ *   characters in CJK mode count as one.)
  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  *			      LY_UNDERLINE_END_CHAR
  *			      LY_BOLD_START_CHAR
@@ -3486,10 +3536,11 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(
  * It assumes UTF8 if utf_flag is set.
  *  It is a case insensitive search. - KW & FM
  */
-PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
+PUBLIC char * LYno_attr_mbcs_case_strstr ARGS6(
 	char *,		chptr,
 	CONST char *,	tarptr,
 	BOOL,		utf_flag,
+	BOOL,		count_gcells,
 	int *,		nstartp,
 	int *,		nendp)
 {
@@ -3547,6 +3598,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 		     */
 		    tmpchptr++;
 		    tmptarptr++;
+		    if (count_gcells) tarlen++;
 		    if (*tmptarptr == '\0') {
 			/*
 			 *  One character match. - FM
@@ -3555,13 +3607,13 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 			if (nendp)	*nendp = len + tarlen;
 			return(chptr);
 		    }
-		    tarlen++;
 		} else {
 		    /*
 		     *	It's not a match, so go back to
 		     *	seeking a first target match. - FM
 		     */
 		    chptr++;
+		    if (count_gcells) len++;
 		    continue;
 		}
 	    }
@@ -3576,6 +3628,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 			    !IsSpecialAttrChar(*(tmpchptr + 1))) {
 			    tmpchptr++;
 			    tmptarptr++;
+			    if (count_gcells) tarlen++;
 			} else {
 			    break;
 			}
@@ -3607,6 +3660,7 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
 		*(chptr + 1) != '\0' &&
 		!IsSpecialAttrChar(*(chptr + 1))) {
 		chptr++;
+		if (count_gcells) len++;
 	    }
 	    len++;
 	}
@@ -3620,8 +3674,12 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
  * pointed to by tarptr in the string pointed to by chptr.
  *  It takes account of CJK and MultiByte Character Sequences (UTF8).
  *  The physical lengths of the displayed string up to the start and
- *  end of the target string are returned in *nstartp and *nendp if
- *  the search is successful.
+ *  end (= next position after) the target string are returned in *nstartp
+ *  and *nendp if the search is successful.
+ *    These lengths count glyph cells if count_gcells is set. (Full-width
+ *    characters in CJK mode count as two.)  Normally that's what we want.
+ *    They count actual glyphs if count_gcells is unset. (Full-width
+ *    characters in CJK mode count as one.)
  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  *			      LY_UNDERLINE_END_CHAR
  *			      LY_BOLD_START_CHAR
@@ -3631,10 +3689,11 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
  * It assumes UTF8 if utf_flag is set.
  *  It is a case sensitive search. - KW & FM
  */
-PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
+PUBLIC char * LYno_attr_mbcs_strstr ARGS6(
 	char *,		chptr,
 	CONST char *,	tarptr,
 	BOOL,		utf_flag,
+	BOOL,		count_gcells,
 	int *,		nstartp,
 	int *,		nendp)
 {
@@ -3672,7 +3731,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 		 *  One char target.
 		 */
 		if (nstartp)	*nstartp = offset;
-		if (nendp)	*nendp = len + 1;
+		if (nendp)	*nendp = len;
 		return(chptr);
 	    }
 	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
@@ -3687,6 +3746,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 		     */
 		    tmpchptr++;
 		    tmptarptr++;
+		    if (count_gcells) tarlen++;
 		    if (*tmptarptr == '\0') {
 			/*
 			 *  One character match. - FM
@@ -3695,13 +3755,13 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 			if (nendp)	*nendp = len + tarlen;
 			return(chptr);
 		    }
-		    tarlen++;
 		} else {
 		    /*
 		     *	It's not a match, so go back to
 		     *	seeking a first target match. - FM
 		     */
 		    chptr++;
+		    if (count_gcells) len++;
 		    continue;
 		}
 	    }
@@ -3716,6 +3776,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 			    !IsSpecialAttrChar(*(tmpchptr + 1))) {
 			    tmpchptr++;
 			    tmptarptr++;
+			    if (count_gcells) tarlen++;
 			} else {
 			    break;
 			}
@@ -3746,6 +3807,7 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
 		*(chptr + 1) != '\0' &&
 		!IsSpecialAttrChar(*(chptr + 1))) {
 		chptr++;
+		if (count_gcells) len++;
 	    }
 	    len++;
 	}
diff --git a/src/LYStrings.h b/src/LYStrings.h
index e836c6a4..ac85f315 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -44,17 +44,20 @@ extern char * LYmbcs_skip_glyphs PARAMS((
 	BOOL		utf_flag));
 extern int LYmbcsstrlen PARAMS((
 	char *		str,
-	BOOL		utf_flag));
+	BOOL		utf_flag,
+	BOOL		count_gcells));
 extern char * LYno_attr_mbcs_strstr PARAMS((
 	char *		chptr,
 	CONST char *	tarptr,
 	BOOL		utf_flag,
+	BOOL		count_gcells,
 	int *		nstartp,
 	int *		nendp));
 extern char * LYno_attr_mbcs_case_strstr PARAMS((
 	char *		chptr,
 	CONST char *	tarptr,
 	BOOL		utf_flag,
+	BOOL		count_gcells,
 	int *		nstartp,
 	int *		nendp));
 extern char * LYno_attr_char_strstr PARAMS((
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 4d30777d..de1c7112 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -337,7 +337,7 @@ PUBLIC void highlight ARGS3(
 			  utf_flag);
 	    hlen = strlen(buffer);
 	    hLen = ((HTCJK != NOCJK || utf_flag) ?
-		  LYmbcsstrlen(buffer, utf_flag) : hlen);
+		  LYmbcsstrlen(buffer, utf_flag, YES) : hlen);
 
 	    /*
 	     *	Break out if the first hit in the line
@@ -359,12 +359,12 @@ PUBLIC void highlight ARGS3(
 		if ((case_sensitive ?
 		     (cp = LYno_attr_mbcs_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL :
 		     (cp = LYno_attr_mbcs_case_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL) &&
 		    (offset + LenNeeded) < LYcols) {
@@ -607,12 +607,12 @@ PUBLIC void highlight ARGS3(
 		if ((case_sensitive ?
 		     (cp = LYno_attr_mbcs_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL :
 		     (cp = LYno_attr_mbcs_case_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL) &&
 		    (offset + LenNeeded) < LYcols) {
@@ -886,12 +886,12 @@ highlight_hit_within_hightext:
 	    if ((case_sensitive ?
 		 (cp = LYno_attr_mbcs_strstr(data,
 					     target,
-					     utf_flag,
+					     utf_flag, YES,
 					     &HitOffset,
 					     &LenNeeded)) != NULL :
 		 (cp = LYno_attr_mbcs_case_strstr(data,
 					     target,
-					     utf_flag,
+					     utf_flag, YES,
 					     &HitOffset,
 					     &LenNeeded)) != NULL) &&
 		(offset + LenNeeded) < LYcols) {
@@ -1067,7 +1067,7 @@ highlight_search_hightext2:
 			  utf_flag);
 	    hlen = strlen(buffer);
 	    hLen = ((HTCJK != NOCJK || utf_flag) ?
-		  LYmbcsstrlen(buffer, utf_flag) : hlen);
+		  LYmbcsstrlen(buffer, utf_flag, YES) : hlen);
 
 	    /*
 	     *	Break out if the first hit in the line
@@ -1089,12 +1089,12 @@ highlight_search_hightext2:
 		if ((case_sensitive ?
 		     (cp = LYno_attr_mbcs_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL :
 		     (cp = LYno_attr_mbcs_case_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL) &&
 		    (offset + LenNeeded) < LYcols) {
@@ -1336,12 +1336,12 @@ highlight_search_hightext2:
 		if ((case_sensitive ?
 		     (cp = LYno_attr_mbcs_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL :
 		     (cp = LYno_attr_mbcs_case_strstr(data,
 						 target,
-						 utf_flag,
+						 utf_flag, YES,
 						 &HitOffset,
 						 &LenNeeded)) != NULL) &&
 		    (offset + LenNeeded) < LYcols) {
@@ -1615,12 +1615,12 @@ highlight_hit_within_hightext2:
 	    if ((case_sensitive ?
 		 (cp = LYno_attr_mbcs_strstr(data,
 					     target,
-					     utf_flag,
+					     utf_flag, YES,
 					     &HitOffset,
 					     &LenNeeded)) != NULL :
 		 (cp = LYno_attr_mbcs_case_strstr(data,
 					     target,
-					     utf_flag,
+					     utf_flag, YES,
 					     &HitOffset,
 					     &LenNeeded)) != NULL) &&
 		(offset + LenNeeded) < LYcols) {
@@ -4665,6 +4665,9 @@ have_VMS_URL:
 		} else if (fixit) {
 		  /* RW 1998Mar16  Restore AllocatedString to 'old_string' */
 		    StrAllocCopy(*AllocatedString, old_string);
+		} else {
+		    /* Return file URL for the file that does not exist */
+		    StrAllocCat(*AllocatedString, temp);
 		}
 #ifdef WIN_EX
 	Retry:
@@ -6478,10 +6481,10 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3(
     if (registered) {
 #ifndef NO_GROUPS
 	writable_exists = HTEditable(fname); /* existing, can write */
-#define CTRACE_EXISTS "exists and is writable"
+#define CTRACE_EXISTS "exists and is writable, "
 #else
 	writable_exists = (BOOL) (stat(fname, &stat_buf) == 0); /* existing, assume can write */
-#define CTRACE_EXISTS "exists"
+#define CTRACE_EXISTS "exists, "
 #endif
 
 	if (writable_exists) {
@@ -6508,46 +6511,25 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3(
 	 * This should probably not happen.  Make a new one.
 	 */
 	return (LYOpenTemp(fname, suffix, mode));
-    } else if (is_ours) {
+    } else if (!registered) {
 	/*
-	 *  Yes, it exists, is writable if we checked, and everything
-	 *  looks ok so far.  This should be the most regular case.
-	 *  We truncate and then append, this avoids having a small
-	 *  window in which the file doesn't exist. - kw
+	 *  Not registered.  It should have been registered at one point
+	 *  though, otherwise we wouldn't be called like this.
 	 */
-#if HAVE_TRUNCATE
-	if (truncate(fname, 0) != 0) {
-	    CTRACE((tfp, "... truncate(%s,0) failed: %s\n",
-		   fname, LYStrerror(errno)));
-	    return (LYOpenTemp(fname, suffix, mode));
-	}
-#endif
-	return (LYReopenTemp(fname));
-    } else if (writable_exists) {
+	return (LYOpenTemp(fname, suffix, mode));
+    } else if (writable_exists && !is_ours) {
 	/*
 	 *  File exists, writable if we checked, but something is wrong
 	 *  with it.
 	 */
 	return (LYOpenTemp(fname, suffix, mode));
 #ifndef NO_GROUPS
-    } else if (registered && (lstat(fname, &stat_buf) == 0)) {
+    } else if (!is_ours && (lstat(fname, &stat_buf) == 0)) {
 	/*
 	 *  Exists but not writable, and something is wrong with it.
 	 */
 	return (LYOpenTemp(fname, suffix, mode));
 #endif
-    } else if (!registered) {
-	/*
-	 *  Not registered.  It should have been registered at one point
-	 *  though, otherwise we wouldn't be called like this.
-	 */
-	return (LYOpenTemp(fname, suffix, mode));
-    } else {
-	/*
-	 *  File does not exist, but is registered as a temp file.
-	 *  It must have been removed by some means other than
-	 *  LYRemoveTemp.  Reuse the name!
-	 */
     }
 
     while (*mode != '\0') {
@@ -6561,6 +6543,38 @@ PUBLIC FILE *LYOpenTempRewrite ARGS3(
 	}
     }
 
+    if (is_ours) {
+	/*
+	 *  Yes, it exists, is writable if we checked, and everything
+	 *  looks ok so far.  This should be the most regular case. - kw
+	 */
+#if HAVE_TRUNCATE
+	if (txt == TRUE) {	/* limitation of LYReopenTemp.  shrug */
+	    /*
+	     *  We truncate and then append, this avoids having a small
+	     *  window in which the file doesn't exist. - kw
+	     */
+	    if (truncate(fname, 0) != 0) {
+		CTRACE((tfp, "... truncate(%s,0) failed: %s\n",
+			fname, LYStrerror(errno)));
+		return (LYOpenTemp(fname, suffix, mode));
+	    } else {
+		return (LYReopenTemp(fname));
+	    }
+	}
+#endif
+	remove(fname);
+
+    }
+
+	/*  We come here in two cases: either the file existed and was
+	 *  ours and we just got rid of it.
+	 *  Or the file did and does not exist, but is registered as a
+	 *  temp file.  It must have been removed by some means other than
+	 *  LYRemoveTemp.
+	 *  In both cases, reuse the name! - kw
+	 */
+
     if (txt) {
 	switch (wrt) {
 	case 'w':
diff --git a/src/TRSTable.c b/src/TRSTable.c
index 3545fdb8..7e65fc2f 100644
--- a/src/TRSTable.c
+++ b/src/TRSTable.c
@@ -17,6 +17,9 @@
 #define ROWS_GROWBY 2
 #define MAX_STBL_POS (LYcols-1)
 
+/* must be different from HT_ALIGN_NONE and HT_LEFT, HT_CENTER etc.: */
+#define RESERVEDCELL (-2)  /* cell's alignment field is overloaded, this
+			      value means cell was reserved by ROWSPAN */
 typedef enum {
     CS_invalid = -1,
     CS_new     =  0,
@@ -48,7 +51,8 @@ typedef struct _STable_cellinfo {
 	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 */
+	short	alignment;	/* one of HT_LEFT, HT_CENTER, HT_RIGHT,
+				   or RESERVEDCELL */
 } STable_cellinfo;
 
 typedef struct _STable_rowinfo {
@@ -69,9 +73,13 @@ struct _STable_info {
 	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 */
+	int	ncolinfo;		/* number of COL info collected */
 	STable_cellinfo * sumcols; /* for summary (max len/pos) col info */
 	STable_rowinfo * rows;
 	short	alignment;	/* global align attribute for this table */
+	short	rowgroup_align;	/* align default for current group of rows */
+	short	pending_colgroup_align;
+	int	pending_colgroup_next;
 	STable_states s;
 };
 
@@ -103,14 +111,14 @@ struct _STable_info {
 **    ("justify" is treated as "left")
 **  - Inheritance of horizontal alignment according to HTML 4.0 (with the
 **    exception of COLGROUP/COL)
-**  - COLSPAN >1 (nearly untested)
+**  - COLSPAN >1 (may work incorrectly for some tables?)
+**  - ROWSPAN >1 (reserving cells in following rows)
 **  - 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).
@@ -140,6 +148,8 @@ PUBLIC struct _STable_info * Stbl_startTABLE ARGS1(
     STable_info *me = (STable_info *) calloc(1, sizeof(STable_info));
     if (me) {
 	me->alignment = alignment;
+	me->rowgroup_align = HT_ALIGN_NONE;
+	me->pending_colgroup_align = HT_ALIGN_NONE;
 	me->s.x_td = -1;
 	me->s.icell_core = -1;
     }
@@ -159,9 +169,9 @@ PUBLIC void Stbl_free ARGS1(
 {
     if (me && me->allocated_rows && me->rows) {
 	int i;
-	for (i = 0; i <= me->nrows; i++)
+	for (i = 0; i < me->allocated_rows; i++)
 	    free_rowinfo(me->rows + i);
-	free(me->rows);
+	FREE(me->rows);
     }
     if (me)
 	FREE(me->sumcols);
@@ -171,8 +181,10 @@ PUBLIC void Stbl_free ARGS1(
 /*
  * Returns -1 on error, otherwise index of just-added table cell.
  */
-PRIVATE int Stbl_addCellToRow ARGS7(
+PRIVATE int Stbl_addCellToRow ARGS9(
     STable_rowinfo *,	me,
+    STable_cellinfo *,	colinfo,
+    int,		ncolinfo,
     STable_states *,	s,
     int,		colspan,
     short,		alignment,
@@ -386,6 +398,10 @@ PRIVATE int Stbl_addCellToRow ARGS7(
     if (me->ncells > 0 && me->cells[me->ncells - 1].colspan > 1) {
 	me->ncells += me->cells[me->ncells-1].colspan - 1;
     }
+    while (me->ncells < me->allocated &&
+	   me->cells[me->ncells].alignment == RESERVEDCELL) {
+	me->ncells++;
+    }
     {
 	int growby = 0;
 	while (me->ncells + colspan + 1 > me->allocated + growby)
@@ -413,8 +429,17 @@ PRIVATE int Stbl_addCellToRow ARGS7(
     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;
+
+    if (alignment != HT_ALIGN_NONE)
+	    me->cells[me->ncells].alignment = alignment;
+    else {
+	if (ncolinfo >= me->ncells + 1) 
+	    me->cells[me->ncells].alignment = colinfo[me->ncells].alignment;
+	if (me->cells[me->ncells].alignment==HT_ALIGN_NONE)
+	    me->cells[me->ncells].alignment = me->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;
@@ -427,6 +452,38 @@ PRIVATE int Stbl_addCellToRow ARGS7(
     return (me->ncells - 1);
 }
 
+/* returns -1 on error, 0 otherwise */
+/* assumes cells have already been allocated (but may need more) */
+PRIVATE int Stbl_reserveCellsInRow ARGS3(
+    STable_rowinfo *,	me,
+    int,		icell,
+    int,		colspan)
+{
+    STable_cellinfo *cells;
+    int i;
+    int growby = icell + colspan - me->allocated;
+    if (growby > 0) {
+	cells = realloc(me->cells,
+			(me->allocated + growby)
+			* sizeof(STable_cellinfo));
+	if (cells) {
+	    me->allocated += growby;
+	    me->cells = cells;
+	} else {
+	    return -1;
+	}
+    }
+    for (i = icell; i < icell + colspan; i++) {
+	me->cells[i].Line = -1;
+	me->cells[i].pos = -1;
+	me->cells[i].len = -1;
+	me->cells[i].colspan = 0;
+	me->cells[i].alignment = RESERVEDCELL;
+    }
+    me->cells[icell].colspan = colspan;
+    return 0;
+}
+
 PRIVATE int Stbl_finishCellInRow ARGS5(
     STable_rowinfo *,	me,
     STable_states *,	s,
@@ -827,6 +884,52 @@ PRIVATE int Stbl_finishCellInRow ARGS5(
 }
 
 /*
+ *  Reserve cells, of colspan=spolspan each, in (rowspan-1) rows after
+ *  the current row.
+ */
+PRIVATE int Stbl_reserveCellsInTable ARGS4(
+    STable_info *,	me,
+    int,		icell,
+    int,		colspan,
+    int,		rowspan)
+{
+    STable_rowinfo *rows, *row;
+    int growby;
+    int i;
+    if (me->nrows <= 0)
+	return -1;		/* must already have at least one row */
+    growby = me->nrows + rowspan - 1 - me->allocated_rows;
+    if (growby > 0) {
+	rows = realloc(me->rows,
+		       (me->allocated_rows + growby)
+		       * sizeof(STable_rowinfo));
+	if (!rows)
+	    return 0; /* ignore silently, maybe someone said ROWSPAN=9999999 */
+	for (i = 0; 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;
+	}
+	me->allocated_rows += growby;
+	me->rows = rows;
+    }
+    for (i = me->nrows; i < me->nrows + rowspan - 1; i++) {
+	if (!me->rows[i].allocated) {
+	    me->rows[i].cells = calloc(icell + colspan, sizeof(STable_cellinfo));
+	    if (!me->rows[i].cells)
+		return 0;	/* fail silently */
+	    else
+		me->rows[i].allocated = icell + colspan;
+	}
+	Stbl_reserveCellsInRow(me->rows + i, icell, colspan);
+    }
+    return 0;
+}
+
+/*
  * Returns -1 on error, otherwise index of just-added table row.
  */
 PUBLIC int Stbl_addRowToTable ARGS3(
@@ -891,9 +994,17 @@ PUBLIC int Stbl_addRowToTable ARGS3(
     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;
+    if (alignment != HT_ALIGN_NONE)
+	me->rows[me->nrows].alignment = alignment;
+    else
+	me->rows[me->nrows].alignment =
+	    (me->rowgroup_align==HT_ALIGN_NONE) ?
+				  me->alignment : me->rowgroup_align;
     me->nrows++;
+    if (me->pending_colgroup_next > me->ncolinfo) {
+	me->ncolinfo = me->pending_colgroup_next;
+	me->pending_colgroup_next = 0;
+    }
     me->rows[me->nrows].Line = -1; /* not yet used */
     return (me->nrows - 1);
 }
@@ -977,9 +1088,10 @@ PRIVATE void update_sumcols0 ARGS7(
 /*
  * Returns -1 on error, otherwise 0.
  */
-PUBLIC int Stbl_addCellToTable ARGS6(
+PUBLIC int Stbl_addCellToTable ARGS7(
     STable_info *,	me,
     int,		colspan,
+    int,		rowspan,
     short,		alignment,
     BOOL,		isheader,
     int,		lineno,
@@ -1000,7 +1112,7 @@ PUBLIC int Stbl_addCellToTable ARGS6(
 			   lineno, pos);
     lastrow = me->rows + (me->nrows - 1);
     ncells = lastrow->ncells;	/* remember what it was before adding cell. */
-    icell = Stbl_addCellToRow(lastrow, s,
+    icell = Stbl_addCellToRow(lastrow, me->sumcols, me->ncolinfo, s,
 			      colspan, alignment, isheader,
 			      lineno, &pos);
     if (icell < 0)
@@ -1008,6 +1120,12 @@ PUBLIC int Stbl_addCellToTable ARGS6(
     if (me->nrows == 1 && me->startline < lastrow->Line)
 	me->startline = lastrow->Line;
 
+    if (rowspan > 1) {
+	Stbl_reserveCellsInTable(me, icell, colspan, rowspan);
+	/* me->rows may now have been realloc'd, make lastrow valid pointer */
+	lastrow = me->rows + (me->nrows - 1);
+    }
+
     {
 	int growby = 0;
 	while (icell + colspan + 1 > me->allocated_sumcols + growby)
@@ -1209,6 +1327,89 @@ PUBLIC int Stbl_finishCellInTable ARGS4(
     return 0;
 }
 
+/*
+ * Returns -1 on error, otherwise 0.
+ */
+PUBLIC int Stbl_addColInfo ARGS4(
+    STable_info *,	me,
+    int,		colspan,
+    short,		alignment,
+    BOOL,		isgroup)
+{
+    STable_cellinfo *sumcols, *sumcol;
+    int i, icolinfo;
+
+    if (isgroup) {
+	if (me->pending_colgroup_next > me->ncolinfo)
+	    me->ncolinfo = me->pending_colgroup_next;
+	me->pending_colgroup_next = me->ncolinfo + colspan;
+	me->pending_colgroup_align = alignment;
+    } else {
+	for (i = me->pending_colgroup_next - 1;
+	     i >= me->ncolinfo + colspan; i--)
+	    me->sumcols[i].alignment = HT_ALIGN_NONE;
+	me->pending_colgroup_next = me->ncolinfo + colspan;
+    }
+    icolinfo = me->ncolinfo;
+    if (!isgroup)
+	me->ncolinfo += colspan;
+
+    {
+	int growby = 0;
+	while (icolinfo + colspan + 1 > me->allocated_sumcols + growby)
+	    growby += CELLS_GROWBY;
+	if (growby) {
+	    if (me->allocated_sumcols == 0) {
+		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 (alignment==HT_ALIGN_NONE)
+	alignment = me->pending_colgroup_align;
+    for (i = icolinfo; i < icolinfo + colspan; i++) {
+	me->sumcols[i].alignment = alignment;
+    }
+    return 0;
+}
+
+/*
+ * Returns -1 on error, otherwise 0.
+ */
+PUBLIC int Stbl_finishColGroup ARGS1(
+    STable_info *,	me)
+{
+    if (me->pending_colgroup_next > me->ncolinfo)
+	me->ncolinfo = me->pending_colgroup_next;
+    me->pending_colgroup_next = 0;
+    me->pending_colgroup_align = HT_ALIGN_NONE;
+    return 0;
+}
+
+PUBLIC int Stbl_addRowGroup ARGS2(
+    STable_info *,	me,
+    short,		alignment)
+{
+    me->rowgroup_align = alignment;
+    return 0;			/* that's all! */
+}
+
 PUBLIC int Stbl_finishTABLE ARGS1(
     STable_info *,	me)
 {
@@ -1285,9 +1486,9 @@ PRIVATE int get_fixup_positions ARGS4(
 	    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;
+		    newpos[ip] += newlen - me->cells[i].len;
 		} else {
-		    newpos[i] += (newlen - me->cells[i].len) / 2;
+		    newpos[ip] += (newlen - me->cells[i].len) / 2;
 		}
 	    }
 	}
diff --git a/src/TRSTable.h b/src/TRSTable.h
index 7ef88b45..a1791151 100644
--- a/src/TRSTable.h
+++ b/src/TRSTable.h
@@ -1,10 +1,16 @@
+#ifndef TRSTABLE_H
+#define TRSTABLE_H
+
 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_addCellToTable PARAMS((STable_info *, int, int, short, BOOL, int, int));
 extern int Stbl_finishCellInTable PARAMS((STable_info *, BOOL, int, int));
+extern int Stbl_addColInfo PARAMS((STable_info *, int, short, BOOL));
+extern int Stbl_finishColGroup PARAMS((STable_info *));
+extern int Stbl_addRowGroup PARAMS((STable_info *, short));
 #define Stbl_lineBreak(stbl,l,pos) Stbl_finishCellInTable(stbl, NO, l, pos)
 extern int Stbl_getStartLine PARAMS((STable_info *));
 extern int Stbl_getFixupPositions PARAMS((
@@ -13,3 +19,5 @@ extern int Stbl_getFixupPositions PARAMS((
     int *		oldpos,
     int *		newpos));
 extern short Stbl_getAlignment PARAMS((STable_info *));
+
+#endif /* TRSTABLE_H */
diff --git a/src/UCAuto.c b/src/UCAuto.c
index 87bbd3c7..86e48f22 100644
--- a/src/UCAuto.c
+++ b/src/UCAuto.c
@@ -374,14 +374,6 @@ 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/UCdomap.c b/src/UCdomap.c
index d451b167..2fd0d885 100644
--- a/src/UCdomap.c
+++ b/src/UCdomap.c
@@ -1332,7 +1332,7 @@ PUBLIC int UCReverseTransChar ARGS3(
 
 #ifndef UC_NO_SHORTCUTS
     if (charset_in == charset_out)
-	return ch_out;
+	return (unsigned char)ch_out;
 #endif /* UC_NO_SHORTCUTS */
     if (charset_in < 0)
 	return -11;
diff --git a/src/chrtrans/cp1253_uni.tbl b/src/chrtrans/cp1253_uni.tbl
index 6a08baef..8d3116d8 100644
--- a/src/chrtrans/cp1253_uni.tbl
+++ b/src/chrtrans/cp1253_uni.tbl
@@ -46,8 +46,8 @@ C1253
 0x8E		#UNDEFINED
 0x8F		#UNDEFINED
 0x90		#UNDEFINED
-0x91	U+2018	#LEFT SINGLE QUOTATION MARK
-0x92	U+2019	#RIGHT SINGLE QUOTATION MARK
+0x91	U+2018	U+02bd	#LEFT SINGLE QUOTATION MARK
+0x92	U+2019	U+02bc	#RIGHT SINGLE QUOTATION MARK
 0x93	U+201C	#LEFT DOUBLE QUOTATION MARK
 0x94	U+201D	#RIGHT DOUBLE QUOTATION MARK
 0x95	U+2022	#BULLET
diff --git a/src/chrtrans/cp869_uni.tbl b/src/chrtrans/cp869_uni.tbl
index a706d2a8..e8941b41 100644
--- a/src/chrtrans/cp869_uni.tbl
+++ b/src/chrtrans/cp869_uni.tbl
@@ -38,8 +38,8 @@ C869
 0x88	U+00b7	#MIDDLE DOT
 0x89	U+00ac	#NOT SIGN
 0x8a	U+00a6	#BROKEN BAR
-0x8b	U+2018	#LEFT SINGLE QUOTATION MARK
-0x8c	U+2019	#RIGHT SINGLE QUOTATION MARK
+0x8b	U+2018	U+02bd	#LEFT SINGLE QUOTATION MARK
+0x8c	U+2019	U+02bc	#RIGHT SINGLE QUOTATION MARK
 0x8d	U+0388	#GREEK CAPITAL LETTER EPSILON WITH TONOS
 0x8e	U+2015	#HORIZONTAL BAR
 0x8f	U+0389	#GREEK CAPITAL LETTER ETA WITH TONOS
diff --git a/src/chrtrans/iso07_uni.tbl b/src/chrtrans/iso07_uni.tbl
index 458c2389..3eb3aeb7 100644
--- a/src/chrtrans/iso07_uni.tbl
+++ b/src/chrtrans/iso07_uni.tbl
@@ -147,8 +147,17 @@ C813
 #0x7D	U+007D	#	RIGHT CURLY BRACKET
 #0x7E	U+007E	#	TILDE
 0xA0	U+00A0	#	NO-BREAK SPACE
-0xA1	U+02BD	#	MODIFIER LETTER REVERSED COMMA
-0xA2	U+02BC	#	MODIFIER LETTER APOSTROPHE
+#
+# The following two changed in ISO 8859:1999
+#
+#   Remap 0xA1 to U+2018 (instead of U+02BD)
+#   Remap 0xA2 to U+2019 (instead of U+02BC)
+#
+# Keep the old ones as primary for now.  Also added old U+037[12]
+# found in existing linux kbd files and in RFC 1345 for compatibility.
+# - kw 1999-10-29
+0xA1	U+02BD	U+2018	U+0371	#	MODIFIER LETTER REVERSED COMMA
+0xA2	U+02BC	U+2019	U+0372	#	MODIFIER LETTER APOSTROPHE
 0xA3	U+00A3	#	POUND SIGN
 0xA6	U+00A6	#	BROKEN BAR
 0xA7	U+00A7	#	SECTION SIGN
diff --git a/src/makefile.dos b/src/makefile.dos
index 98b57662..6c715a54 100644
--- a/src/makefile.dos
+++ b/src/makefile.dos
@@ -11,15 +11,23 @@ LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o
 
 CFLAGS= $(MCFLAGS) -I. -I.. $(SLANGINC)
 
+# comment this line to suppress DIRED support
+DIRED_DEFS = -DDIRED_SUPPORT -DOK_UUDECODE -DOK_TAR -DOK_GZIP -DOK_ZIP
+
 CC = gcc
 MCFLAGS = -O2 -DHAVE_GETBKGD -DDISP_PARTIAL -DUSE_ZLIB \
  -DSOURCE_CACHE -DUSE_PSRC \
  -DUSE_EXTERNALS -DCOLOR_CURSES -DNCURSES -DFANCY_CURSES \
  -DACCESS_AUTH -DNO_CUSERID -DNOUSERS -DDOSPATH -DNO_TTYTYPE -DNO_UTMP \
- -Ichrtrans -I../WWW/library/implementation \
- -I../curses  -I../djgpp/tcplib/include -I../djgpp/tcplib/include/tcp
-WWWLIB = ../WWW/library/djgpp/libwww.a ../curses/pdcurses.a ../djgpp/tcplib/obj/libtcp.a
-LIBS=-lz
+ -DEXP_PERSISTENT_COOKIES -DEXP_ADDRLIST_PAGE -DEXP_ALT_BINDINGS \
+ -DEXP_FILE_UPLOAD \
+ -DWATT32 \
+ $(DIRED_DEFS) \
+ -I./chrtrans -I../WWW/Library/Implementation \
+ -I../curses -I../djgpp/watt32/inc -I../djgpp/watt32/inc/sys
+WWWLIB = ../WWW/Library/djgpp/libwww.a ../curses/pdcurses.a ../djgpp/watt32/lib/libwatt.a
+LIBS= -lz # -lintl
+#INTLFLAGS = -DHAVE_GETTEXT -DHAVE_LIBINTL_H
 
 all: lynx
 
diff --git a/src/makefile.in b/src/makefile.in
index 89e8ef71..d655a462 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -110,6 +110,8 @@ clean:
 
 distclean: clean
 
+CMN=$(top_srcdir)/WWW/Library/Implementation/
+
 HTFWriter.o:	$(top_srcdir)/userdefs.h
 HTInit.o:	$(top_srcdir)/userdefs.h
 LYCharSets.o:	$(top_srcdir)/userdefs.h
@@ -124,6 +126,7 @@ LYShowInfo.o:	$(top_builddir)/cfg_defs.h
 LYTraversal.o:	$(top_srcdir)/userdefs.h
 LYUtils.o:	$(top_srcdir)/userdefs.h
 LYrcFile.o:	$(top_srcdir)/userdefs.h
+LYLeaks.o:	$(CMN)LYLeaks.h $(CMN)HTString.h
 
 CHRTR= chrtrans/
 
@@ -167,8 +170,6 @@ TABLES= \
  $(CHRTR)utf8_uni.h \
  $(CHRTR)viscii_uni.h
 
-CMN=$(top_srcdir)/WWW/Library/Implementation/
-
 $(TABLES):
 	-cd chrtrans && $(MAKE) tables