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.c1673
-rw-r--r--src/HTFWriter.c12
-rw-r--r--src/HTML.c4
-rw-r--r--src/LYBookmark.c2
-rw-r--r--src/LYCharUtils.c13
-rw-r--r--src/LYCookie.c6
-rw-r--r--src/LYCurses.c113
-rw-r--r--src/LYCurses.h9
-rw-r--r--src/LYDownload.c14
-rw-r--r--src/LYEdit.c2
-rw-r--r--src/LYExtern.c425
-rw-r--r--src/LYForms.c4
-rw-r--r--src/LYGlobalDefs.h4
-rw-r--r--src/LYHash.h1
-rw-r--r--src/LYHistory.c2
-rw-r--r--src/LYHistory.h2
-rw-r--r--src/LYJump.c4
-rw-r--r--src/LYKeymap.c26
-rw-r--r--src/LYKeymap.h7
-rw-r--r--src/LYLeaks.c38
-rw-r--r--src/LYLocal.c79
-rw-r--r--src/LYMain.c18
-rw-r--r--src/LYMainLoop.c19
-rw-r--r--src/LYNews.c10
-rw-r--r--src/LYOptions.c2
-rw-r--r--src/LYPrint.c12
-rw-r--r--src/LYReadCFG.c250
-rw-r--r--src/LYReadCFG.h3
-rw-r--r--src/LYStrings.c132
-rw-r--r--src/LYStrings.h4
-rw-r--r--src/LYStructs.h32
-rw-r--r--src/LYStyle.c28
-rw-r--r--src/LYUpload.c8
-rw-r--r--src/LYUtils.c43
-rw-r--r--src/LYUtils.h6
-rw-r--r--src/TRSTable.c55
-rw-r--r--src/TRSTable.h11
-rw-r--r--src/UCAuto.c30
-rw-r--r--src/Xsystem.c4
-rw-r--r--src/chrtrans/makefile.in13
-rw-r--r--src/makefile.dos4
-rw-r--r--src/makefile.in67
42 files changed, 1452 insertions, 1739 deletions
diff --git a/src/GridText.c b/src/GridText.c
index ad5abbfe..e61ddbd9 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -33,6 +33,7 @@
 #include <LYPrint.h>
 #include <LYPrettySrc.h>
 #include <TRSTable.h>
+#include <LYHistory.h>
 #ifdef EXP_CHARTRANS_AUTOSWITCH
 #include <UCAuto.h>
 #endif /* EXP_CHARTRANS_AUTOSWITCH */
@@ -60,7 +61,6 @@ unsigned int cached_styles[CACHEH][CACHEW];
 
 #include <LYJustify.h>
 
-
 #ifdef USE_COLOR_STYLE_UNUSED
 void LynxClearScreenCache NOARGS
 {
@@ -128,8 +128,8 @@ PUBLIC char * unchecked_box = "[ ]";
 PUBLIC char * checked_radio = "(*)";
 PUBLIC char * unchecked_radio = "( )";
 
-PUBLIC BOOLEAN underline_on = OFF;
-PUBLIC BOOLEAN bold_on      = OFF;
+PRIVATE BOOLEAN underline_on = OFF;
+PRIVATE BOOLEAN bold_on      = OFF;
 
 #ifdef SOURCE_CACHE
 PUBLIC int LYCacheSource = SOURCE_CACHE_NONE;
@@ -160,9 +160,6 @@ typedef struct _line {
 	struct _line	*prev;
 	unsigned	offset;		/* Implicit initial spaces */
 	unsigned	size;		/* Number of characters */
-	BOOL	split_after;		/* Can we split after? */
-	BOOL	bullet;			/* Do we bullet? */
-	BOOL	expansion_line;		/* TEXTAREA edit new line flag */
 #if defined(USE_COLOR_STYLE)
 	HTStyleChange* styles;
 	int	numstyles;
@@ -294,9 +291,8 @@ void POOL_FREE( pool_type , P* ptr)
 typedef struct _TextAnchor {
 	struct _TextAnchor *	next;
 	int			number;		/* For user interface */
-	int			start;		/* Characters */
-	int			line_pos;	/* Position in text */
-	int			extent;		/* Characters */
+	int			line_pos;	/* Bytes/chars - extent too */
+	int			extent;		/* (see HText_trimHightext) */
 	int			line_num;	/* Place in document */
 	char *			hightext;	/* The link text */
 	char *			hightext2;	/* A second line*/
@@ -336,11 +332,10 @@ struct _HText {
 	BOOLEAN			old_dtd;
 	int			keypad_mode;
 	int			disp_lines;	/* Screen size */
-	int			disp_cols;
+	int			disp_cols;	/* Used for reports only */
 #endif
 	HTLine *		last_line;
 	int			Lines;		/* Number of them */
-	int			chars;		/* Number of them */
 	TextAnchor *		first_anchor;	/* Singly linked list */
 	TextAnchor *		last_anchor;
 	TextAnchor *		last_anchor_before_stbl;
@@ -406,7 +401,6 @@ struct _HText {
 
 PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor));
 
-
 #ifdef EXP_JUSTIFY_ELTS
 PUBLIC BOOL can_justify_here;
 PUBLIC BOOL can_justify_here_saved;
@@ -436,10 +430,6 @@ static int ht_num_runs;/*the number of runs filled*/
 static ht_run_info ht_runs[MAX_LINE];
 static BOOL this_line_was_split;
 static TextAnchor* last_anchor_of_previous_line;
-static int justified_text_map[MAX_LINE]; /* this is a map - for each index i
-    it tells to which position j=justified_text_map[i] in justified text
-    i-th character is mapped - it's used for anchor positions fixup and for
-    color style's positions adjustment. */
 static BOOL have_raw_nbsps = FALSE;
 
 PUBLIC void ht_justify_cleanup NOARGS
@@ -472,6 +462,8 @@ PUBLIC void mark_justify_start_position ARGS1(void*,text)
 	HTCJK == NOCJK && !in_DT && \
 	can_justify_here && can_justify_this_line && !form_in_htext )
 
+#else
+#define last_anchor_of_previous_line (TextAnchor*)0
 #endif /* EXP_JUSTIFY_ELTS */
 
 
@@ -588,7 +580,7 @@ PRIVATE void * LY_check_calloc ARGS2(
 	if (t == HTMainText)
 	    t = NULL;		/* shouldn't happen */
 	{
-	CTRACE((tfp, "\r *** Emergency freeing document %d/%d for '%s'%s!\n",
+	CTRACE((tfp, "\nBUG *** Emergency freeing document %d/%d for '%s'%s!\n",
 		    i + 1, n,
 		    ((t && t->node_anchor &&
 		      t->node_anchor->address) ?
@@ -754,7 +746,7 @@ PUBLIC HText *	HText_new ARGS1(
     stylechanges_buffers_free = 0;
     line->styles = stylechanges_buffers[0];
 #endif
-    self->Lines = self->chars = 0;
+    self->Lines = 0;
     self->first_anchor = self->last_anchor = NULL;
     self->style = &default_style;
     self->top_of_screen = 0;
@@ -1430,7 +1422,7 @@ PRIVATE void display_title ARGS1(
     char percent[20];
     char *cp = NULL;
     unsigned char *tmp = NULL;
-    int i = 0, j = 0;
+    int i = 0, j = 0, toolbar = 0;
     int limit;
 
     /*
@@ -1530,9 +1522,26 @@ PRIVATE void display_title ARGS1(
 #if defined(SH_EX) && defined(KANJI_CODE_OVERRIDE)
     LYaddstr(str_kcode(last_kcode));
 #endif
-    if (text->top_of_screen > 0 && HText_hasToolbar(text)) {
+    if (HText_hasToolbar(text)) {
 	LYaddch('#');
+	toolbar = 1;
     }
+#ifdef USE_COLOR_STYLE
+    if (s_forw_backw != NOSTYLE && (nhist || nhist_extra > 1)) {
+	int c = nhist ? ACS_LARROW : ' ';
+
+	/* turn the FORWBACKW.ARROW style on */
+	LynxChangeStyle(s_forw_backw, STACK_ON);
+	if (nhist) {
+	    LYaddch(c); LYaddch(c); LYaddch(c);
+	} else
+	    LYmove(0, 3 + toolbar);
+	if (nhist_extra > 1) {
+	    LYaddch(ACS_RARROW); LYaddch(ACS_RARROW); LYaddch(ACS_RARROW);
+	}
+	LynxChangeStyle(s_forw_backw, STACK_OFF);
+    }
+#endif /* USE_COLOR_STYLE */
     i = (limit - 1) - strlen(percent) - strlen(title);
     if (i >= CHAR_WIDTH) {
 	LYmove(0, i);
@@ -1844,7 +1853,7 @@ PRIVATE void display_page ARGS3(
 
 #ifdef DISP_PARTIAL
     if (display_partial && text->stbl) {
-	stop_before_for_anchors = Stbl_getStartLine(text->stbl);
+	stop_before_for_anchors = Stbl_getStartLineDeep(text->stbl);
 	if (stop_before_for_anchors > line_number+(display_lines))
 	    stop_before_for_anchors = line_number+(display_lines);
     } else
@@ -2337,6 +2346,232 @@ PUBLIC void HText_beginAppend ARGS1(
 #define CTRACE_SPLITLINE(p)	/*nothing*/
 #endif
 
+PRIVATE int set_style_by_embedded_chars ARGS4(
+	char *,		s,
+	char *,		e,
+	unsigned char,	start_c,
+	unsigned char,	end_c)
+{
+    int ret = NO;
+
+    while (--e >= s) {
+	if (*e == end_c)
+	    break;
+	if (*e == start_c) {
+	    ret = YES;
+	    break;
+	}
+    }
+    return ret;
+}
+
+PRIVATE void move_anchors_in_region ARGS7(
+    HTLine *,		line,
+    int,		line_number,
+    TextAnchor **,	prev_anchor,
+    int *,		prev_head_processed,
+    int,		sbyte,
+    int,		ebyte,
+    int,		shift)		/* Likewise */
+{
+    /*
+     *  Update anchor positions for anchors that start on this line.
+     *  Note: we rely on a->line_pos counting bytes, not
+     *  characters.  That's one reason why HText_trimHightext
+     *  has to be prevented from acting on these anchors in
+     *  partial display mode before we get a chance to
+     *  deal with them here.
+     */
+    TextAnchor *a;
+    int head_processed = *prev_head_processed;
+
+    /* We need to know whether (*prev_anchor)->line_pos is "in new
+       coordinates" or in old ones.  If prev_anchor' head was touched
+       on the previous iteraction, we set head_processed.  The tail
+       may need to be treated now. */
+    for (a = *prev_anchor;
+	 a && a->line_num <= line_number;
+	 a = a->next, head_processed = 0) {
+	/* extent==0 needs to be special-cased; happens if no text for
+	   the anchor was processed yet.  */
+	/* Subtract one so that the space is not inserted at the end
+	   of the anchor... */
+	int last = a->line_pos + (a->extent ? a->extent - 1 : 0);
+
+	/* Include the anchors started on the previous line */
+	if (a->line_num < line_number - 1)
+	    continue;
+	if (a->line_num == line_number - 1)
+	    last -= line->prev->size + 1; /* Fake "\n" "between" lines counted too */
+	if (last < sbyte)		/* Completely before the start */
+	    continue;
+
+	if ( !head_processed		/* a->line_pos is not edited yet */
+	     && a->line_num == line_number
+	     && a->line_pos >= ebyte)	/* Completely after the end */
+	    break;
+	/* Now we know that the anchor context intersects the chunk */
+
+	/* Fix the start */
+	if ( !head_processed && a->line_num == line_number
+	     && a->line_pos >= sbyte ) {
+	    a->line_pos += shift;
+	    a->extent -= shift;
+	    head_processed = 1;
+	}
+	/* Fix the end */
+	if ( last < ebyte )
+	    a->extent += shift;
+	else
+	    break;			/* Keep this `a' for the next step */
+    }
+    *prev_anchor = a;
+    *prev_head_processed = head_processed;
+}
+
+/*
+ *  Given a line and two int arrays of old/now position, this function
+ *  creates a new line where spaces have been inserted/removed
+ *  in appropriate places - so that characters at/after the old
+ *  position end up at/after the new position, for each pair, if possible.
+ *  Some necessary changes for anchors starting on this line are also done
+ *  here if needed.
+ *  Returns a newly allocated HTLine* if changes were made
+ *    (caller has to free the old one).
+ *  Returns NULL if no changes needed.  (Remove-spaces code may be buggy...)
+ * - kw
+ */
+PRIVATE HTLine * insert_blanks_in_line ARGS7(
+    HTLine *,		line,
+    int,		line_number,
+    HText *,		text,
+    TextAnchor *,	prev_anchor,
+    int,		ninserts,
+    int *,		oldpos,		/* Measured in cells */
+    int *,		newpos)		/* Likewise */
+{
+    int ioldc = 0;			/* count visible characters */
+    int ip;				/* count insertion pairs */
+#if defined(USE_COLOR_STYLE)
+    int istyle = 0;
+#endif
+    int added_chars = 0;
+    int shift = 0;
+    int head_processed;
+    HTLine * mod_line;
+    char *newdata;
+    char *s = line->data;
+    char *copied = line->data, *t;
+
+    if (!(line && line->size && ninserts))
+	return NULL;
+    for (ip = 0; ip < ninserts; ip++)
+	if (newpos[ip] > oldpos[ip] &&
+	    (newpos[ip] - oldpos[ip]) > added_chars)
+	    added_chars = newpos[ip] - oldpos[ip];
+    if (line->size + added_chars > MAX_LINE - 2)
+	return NULL;
+    if (line == text->last_line)
+	mod_line = allocHTLine(MAX_LINE);
+    else
+	mod_line = allocHTLine(line->size + added_chars);
+    if (!mod_line)
+	return NULL;
+    if (!prev_anchor)
+	prev_anchor = text->first_anchor;
+    head_processed = (prev_anchor && prev_anchor->line_num < line_number);
+    memcpy(mod_line, line, LINE_SIZE(1));
+    t = newdata = mod_line->data;
+    ip = 0;
+    while (ip <= ninserts) {
+	/* line->size is in bytes, so it may be larger than needed... */
+	int curlim = (ip < ninserts
+		      ? oldpos[ip]
+		      /* Include'em all! */
+		      : (line->size <= MAX_LINE ? MAX_LINE+1 : line->size+1));
+	char *pre = s;
+
+	/* Fast forward to char==curlim or EOL.  Stop *before* the
+	   style-change chars. */
+	while (*s) {
+	    if ( text && text->T.output_utf8
+		 && UCH(*s) >= 0x80 && UCH(*s) <  0xC0 )
+		pre = s + 1;
+	    else if (!IsSpecialAttrChar(*s)) {	/* At a "displayed" char */
+		if (ioldc >= curlim)
+		    break;
+		ioldc++;
+		pre = s + 1;
+	    }
+	    s++;
+	}
+
+	/* Now s is at the "displayed" char, pre is before the style change */
+	if (ip)				/* Fix anchor positions */
+	    move_anchors_in_region(line, line_number, &prev_anchor,
+				   &head_processed,
+				   copied - line->data, pre - line->data,
+				   shift);
+#if defined(USE_COLOR_STYLE)		/* Move styles too */
+#define NStyle mod_line->styles[istyle]
+	for (; istyle < line->numstyles && NStyle.horizpos < curlim ; istyle++)
+	    /* Should not we include OFF-styles at curlim? */
+	    NStyle.horizpos += shift;
+#endif
+	while (copied < pre)	/* Copy verbatim to byte == pre */
+	    *t++ = *copied++;
+	if (ip < ninserts) {		/* Insert spaces */
+	    int delta = newpos[ip] - oldpos[ip] - shift;
+
+	    if (delta < 0) {		/* Not used yet? */
+		while (delta++ < 0 && t > newdata && t[-1] == ' ')
+		    t--, shift--;
+	    } else
+		shift = newpos[ip] - oldpos[ip];
+	    while (delta-- > 0)
+		*t++ = ' ';
+	}
+	ip++;
+    }
+    /* Check whether the last anchor continues on the next line */
+    if (head_processed && prev_anchor && prev_anchor->line_num == line_number)
+	prev_anchor->extent += shift;
+    *t = '\0';
+    mod_line->size = t - newdata;
+    return mod_line;
+}
+
+#if defined(USE_COLOR_STYLE)
+PRIVATE HTStyleChange * skip_matched_and_correct_offsets ARGS3(
+	HTStyleChange *,	end,
+	HTStyleChange *,	start,
+	unsigned,		split_pos)
+{ /* Found an OFF change not part of an adjacent matched pair.
+   * Walk backward looking for the corresponding ON change.
+   * Move everything after split_pos to be at split_pos.
+   * This can only work correctly if all changes are correctly
+   * nested!  If this fails, assume it is safer to leave whatever
+   * comes before the OFF on the previous line alone. */
+    int level = 0;
+    HTStyleChange *tmp = end;
+
+    for (; tmp >= start; tmp--) {
+	if (tmp->style == end->style) {
+	    if (tmp->direction == STACK_OFF)
+		level--;
+	    else if (tmp->direction == STACK_ON) {
+		if (++level == 0)
+		    return tmp;
+	    } else
+		return 0;
+	}
+	if (tmp->horizpos > split_pos)
+	    tmp->horizpos = split_pos;
+    }
+    return 0;
+}
+#endif /* USE_COLOR_STYLE */
+
 PRIVATE void split_line ARGS2(
 	HText *,	text,
 	unsigned,	split)
@@ -2344,9 +2579,6 @@ PRIVATE void split_line ARGS2(
     HTStyle * style = text->style;
     HTLine * temp;
     int spare;
-#if defined(USE_COLOR_STYLE)
-    int inew;
-#endif
     int indent = text->in_line_1 ?
 	  text->style->indent1st : text->style->leftIndent;
     short alignment;
@@ -2355,22 +2587,20 @@ PRIVATE void split_line ARGS2(
     int HeadTrim = 0;
     int SpecialAttrChars = 0;
     int TailTrim = 0;
-    int s;
-
-    /*
-     *  Make new line.
-     */
+    int s, s_post, s_pre, t_underline = underline_on, t_bold = bold_on;
+    char *p;
     HTLine * previous = text->last_line;
     int ctrl_chars_on_previous_line = 0;
     int utfxtra_on_previous_line = utfxtra_on_this_line;
     char * cp;
     /* can't wrap in middle of multibyte sequences, so allocate 2 extra */
     HTLine * line = (HTLine *)LY_CALLOC(1, LINE_SIZE(MAX_LINE)+2);
+
+    /*
+     *  Make new line.
+     */
     if (line == NULL)
 	outofmem(__FILE__, "split_line_1");
-#if defined(USE_COLOR_STYLE)
-    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 = ' ';
@@ -2381,6 +2611,7 @@ PRIVATE void split_line ARGS2(
 #endif
 
     cp = previous->data;
+    /* Float LY_SOFT_NEWLINE to the start */
     if (cp[0] == LY_BOLD_START_CHAR
      || cp[0] == LY_UNDERLINE_START_CHAR) {
 	switch (cp[1]) {
@@ -2423,36 +2654,42 @@ PRIVATE void split_line ARGS2(
     text->permissible_split = 0;  /* 12/13/93 */
     line->data[0] = '\0';
 
-    /*
-     *  If we are not splitting and need an underline char, add it now. - FM
-     */
-    if ((split < 1) &&
-	!(dump_output_immediately && use_underscore) && underline_on) {
+    alignment = style->alignment;
+
+    if (split > 0) { /* Restore flags to the value at the splitting point */
+	if (!(dump_output_immediately && use_underscore))
+	    t_underline = set_style_by_embedded_chars(
+		previous->data, previous->data + split,
+		LY_UNDERLINE_START_CHAR, LY_UNDERLINE_END_CHAR);
+
+	t_bold = set_style_by_embedded_chars(
+	    previous->data, previous->data + split,
+	    LY_BOLD_START_CHAR, LY_BOLD_END_CHAR);
+
+    }
+
+    if (!(dump_output_immediately && use_underscore) && t_underline) {
 	line->data[line->size++] = LY_UNDERLINE_START_CHAR;
 	line->data[line->size] = '\0';
 	ctrl_chars_on_this_line++;
+	SpecialAttrChars++;
     }
-    /*
-     *  If we are not splitting and need a bold char, add it now. - FM
-     */
-    if ((split < 1) && bold_on) {
+    if (t_bold) {
 	line->data[line->size++] = LY_BOLD_START_CHAR;
 	line->data[line->size] = '\0';
 	ctrl_chars_on_this_line++;
+	SpecialAttrChars++;
     }
 
-    alignment = style->alignment;
     /*
      *  Split at required point
      */
     if (split > 0) {	/* Delete space at "split" splitting line */
-	char *p, *prevdata = previous->data, *linedata = line->data;
+	char *prevdata = previous->data, *linedata = line->data;
 	unsigned plen;
 	int i;
 
-	/*
-	 *  Split the line. - FM
-	 */
+	/* Split the line. - FM */
 	prevdata[previous->size] = '\0';
 	previous->size = split;
 
@@ -2462,160 +2699,76 @@ PRIVATE void split_line ARGS2(
 	 */
 	p = prevdata + split;
 	while ((
+		(*p == ' '
 #ifdef EXP_JUSTIFY_ELTS
 		/* if justification is allowed for prev line, then raw
 		 * HT_NON_BREAK_SPACE are still present in data[] (they'll be
 		 * substituted at the end of this function with ' ') - VH
 		 */
-		(*p == ' ' || *p == HT_NON_BREAK_SPACE ) &&
-#else
-		(*p == ' ') &&
-#endif
-
-		(HeadTrim || text->first_anchor ||
-		 underline_on || bold_on ||
-		 alignment != HT_LEFT ||
-		 style->wordWrap || style->freeFormat ||
-		 style->spaceBefore || style->spaceAfter)) ||
+		 || *p == HT_NON_BREAK_SPACE
+#endif
+		)
+		&& (HeadTrim || text->first_anchor ||
+		    underline_on || bold_on ||
+		    alignment != HT_LEFT ||
+		    style->wordWrap || style->freeFormat ||
+		    style->spaceBefore || style->spaceAfter)) ||
 		*p == LY_SOFT_HYPHEN) {
 	    p++;
 	    HeadTrim++;
 	}
-	plen = strlen(p);
 
-	/*
-	 *  Add underline char if needed. - FM
-	 */
-	if (!(dump_output_immediately && use_underscore)) {
-	    /*
-	     * Make sure our global flag is correct. - FM
-	     */
-	    underline_on = NO;
-	    for (i = (split-1); i >= 0; i--) {
-		if (prevdata[i] == LY_UNDERLINE_END_CHAR) {
-		    break;
-		}
-		if (prevdata[i] == LY_UNDERLINE_START_CHAR) {
-		    underline_on = YES;
-		    break;
-		}
-	    }
-	    /*
-	     *  Act on the global flag if set above. - FM
-	     */
-	    if (underline_on && *p != LY_UNDERLINE_END_CHAR) {
-		linedata[line->size++] = LY_UNDERLINE_START_CHAR;
-		linedata[line->size] = '\0';
-		ctrl_chars_on_this_line++;
-		SpecialAttrChars++;
-	    }
-	    if (plen) {
-		for (i = (plen - 1); i >= 0; i--) {
-		    if (p[i] == LY_UNDERLINE_START_CHAR) {
-			underline_on = YES;
-			break;
-		    }
-		    if (p[i] == LY_UNDERLINE_END_CHAR) {
-			underline_on = NO;
-			break;
-		    }
-		}
-		for (i = (plen - 1); i >= 0; i--) {
-		    if (p[i] == LY_UNDERLINE_START_CHAR ||
-			p[i] == LY_UNDERLINE_END_CHAR) {
-			ctrl_chars_on_this_line++;
-		    }
-		}
-	    }
-	}
-
-	/*
-	 *  Add bold char if needed, first making
-	 *  sure that our global flag is correct. - FM
-	 */
-	bold_on = NO;
-	for (i = (split - 1); i >= 0; i--) {
-	    if (prevdata[i] == LY_BOLD_END_CHAR) {
-		break;
-	    }
-	    if (prevdata[i] == LY_BOLD_START_CHAR) {
-		bold_on = YES;
-		break;
-	    }
-	}
-	/*
-	 *  Act on the global flag if set above. - FM
-	 */
-	if (bold_on && *p != LY_BOLD_END_CHAR) {
-	    linedata[line->size++] = LY_BOLD_START_CHAR;
-	    linedata[line->size] = '\0';
-	    ctrl_chars_on_this_line++;
-	    SpecialAttrChars++;
-	}
-	if (plen) {
-	    for (i = (plen - 1); i >= 0; i--) {
-		if (p[i] == LY_BOLD_START_CHAR) {
-		    bold_on = YES;
-		    break;
-		}
-		if (p[i] == LY_BOLD_END_CHAR) {
-		    bold_on = NO;
-		    break;
-		}
-	    }
+	plen = strlen(p);
+	if (plen) {			/* Count funny characters */
 	    for (i = (plen - 1); i >= 0; i--) {
-		if (p[i] == LY_BOLD_START_CHAR ||
+		if (p[i] == LY_UNDERLINE_START_CHAR ||
+		    p[i] == LY_UNDERLINE_END_CHAR ||
+		    p[i] == LY_BOLD_START_CHAR ||
 		    p[i] == LY_BOLD_END_CHAR ||
-		    p[i] == LY_SOFT_HYPHEN) {
+		    p[i] == LY_SOFT_HYPHEN)
 		    ctrl_chars_on_this_line++;
-		} else if (IS_UTF_EXTRA(p[i])) {
+		else if (IS_UTF_EXTRA(p[i]))
 		    utfxtra_on_this_line++;
-		}
-		if (p[i] == LY_SOFT_HYPHEN && (int)text->permissible_split < i) {
+		if (p[i] == LY_SOFT_HYPHEN && (int)text->permissible_split < i)
 		    text->permissible_split = i + 1;
-		}
 	    }
 	    ctrl_chars_on_this_line += utfxtra_on_this_line;
-	}
 
-	/*
-	 *  Add the data to the new line. - FM
-	 */
-	strcat(linedata, p);
-	line->size += plen;
+	    /* Add the data to the new line. - FM */
+	    strcat(linedata, p);
+	    line->size += plen;
+	}
     }
 
     /*
      *  Economize on space.
      */
-    while ((previous->size > 0) &&
+    p = previous->data + previous->size - 1;
+    while (p >= previous->data
+	   && (*p == ' '
 #ifdef EXP_JUSTIFY_ELTS
 	    /* if justification is allowed for prev line, then raw
 	     * HT_NON_BREAK_SPACE are still present in data[] (they'll be
 	     * substituted at the end of this function with ' ') - VH
 	     */
-	   ((previous->data[previous->size-1] == ' ') ||
-	    (previous->data[previous->size-1] == HT_NON_BREAK_SPACE)) &&
-#else
-	   (previous->data[previous->size-1] == ' ') &&
+	       || *p == HT_NON_BREAK_SPACE
 #endif
+	      )
 #ifdef USE_PRETTYSRC
-	    !psrc_view && /*don't strip trailing whites - since next line can
+	   && !psrc_view /*don't strip trailing whites - since next line can
 		start with LY_SOFT_NEWLINE - so we don't lose spaces when
 		'p'rinting this text to file -VH */
 #endif
-	   (ctrl_chars_on_this_line || HeadTrim || text->first_anchor ||
-	    underline_on || bold_on ||
-	    alignment != HT_LEFT ||
-	    style->wordWrap || style->freeFormat ||
-	    style->spaceBefore || style->spaceAfter)) {
-	/*
-	 *  Strip trailers.
-	 */
-	previous->data[previous->size-1] = '\0';
-	previous->size--;
-	TailTrim++;
-    }
+	   && (ctrl_chars_on_this_line || HeadTrim || text->first_anchor ||
+	       underline_on || bold_on ||
+	       alignment != HT_LEFT ||
+	       style->wordWrap || style->freeFormat ||
+	       style->spaceBefore || style->spaceAfter))
+	p--;	/*  Strip trailers. */
+    TailTrim = previous->data + previous->size - 1 - p;	/*  Strip trailers. */
+    previous->size -= TailTrim;
+    p[1] = '\0';
+
     /*
      *  s is the effective split position, given by either a non-zero
      *  value of split or by the size of the previous line before
@@ -2626,6 +2779,9 @@ PRIVATE void split_line ARGS2(
     } else {
 	s = split;
     }
+    s_post = s + HeadTrim;
+    s_pre  = s - TailTrim;
+
 #ifdef DEBUG_SPLITLINE
 #ifdef DEBUG_APPCH
     if (s != (int)split)
@@ -2634,150 +2790,98 @@ PRIVATE void split_line ARGS2(
 #endif
 
 #if defined(USE_COLOR_STYLE)
-#define LastStyle (previous->numstyles-1)
+    line->styles = stylechanges_buffers[stylechanges_buffers_free = (stylechanges_buffers_free + 1) &1];
     line->numstyles = 0;
-    inew = MAX_STYLES_ON_LINE - 1;
-    /*
-     *  Color style changes after the split position + possible trimmed
-     *  head characters are transferred to the new line.  Ditto for changes
-     *  within the trimming region, but we stop when we reach an OFF change.
-     *  The second while loop below may then handle remaining changes. - kw
-     */
-    while (previous->numstyles && inew >= 0) {
-	if (previous->styles[LastStyle].horizpos > s + HeadTrim) {
-	    line->styles[inew].horizpos =
-		previous->styles[LastStyle].horizpos
-		- (s + HeadTrim) + SpecialAttrChars;
-	    line->styles[inew].direction = previous->styles[LastStyle].direction;
-	    line->styles[inew].style = previous->styles[LastStyle].style;
-	    inew --;
-	    line->numstyles ++;
-	    previous->numstyles --;
-	} else if (previous->styles[LastStyle].horizpos > s - TailTrim &&
-		   (previous->styles[LastStyle].direction == STACK_ON ||
-		    previous->styles[LastStyle].direction == ABS_ON)) {
-	    line->styles[inew].horizpos =
-		(previous->styles[LastStyle].horizpos < s) ?
-		0 : SpecialAttrChars;
-	    line->styles[inew].direction = previous->styles[LastStyle].direction;
-	    line->styles[inew].style = previous->styles[LastStyle].style;
-	    inew --;
-	    line->numstyles ++;
-	    previous->numstyles --;
-	} else
-	    break;
-    }
-    spare = previous->numstyles;
-    while (previous->numstyles && inew >= 0) {
-	if (previous->numstyles >= 2 &&
-	    previous->styles[LastStyle].style
-	    == previous->styles[previous->numstyles-2].style &&
-	    previous->styles[LastStyle].horizpos
-	    == previous->styles[previous->numstyles-2].horizpos &&
-	    ((previous->styles[LastStyle].direction == STACK_OFF &&
-	      previous->styles[previous->numstyles-2].direction == STACK_ON) ||
-	     (previous->styles[LastStyle].direction == ABS_OFF &&
-	      previous->styles[previous->numstyles-2].direction == ABS_ON) ||
-	     (previous->styles[LastStyle].direction == ABS_ON &&
-	      previous->styles[previous->numstyles-2].direction == ABS_OFF)
-		)) {
-	    /*
-	     *  Discard pairs of ON/OFF for the same color style, but only
-	     *  if they appear at the same position. - kw
-	     */
-	    previous->numstyles -= 2;
-	    if (spare > previous->numstyles)
-		spare = previous->numstyles;
-	} else if (spare > 0 && previous->styles[spare - 1].direction &&
-		   previous->numstyles < MAX_STYLES_ON_LINE) {
-	    /*
-	     *  The index variable spare walks backwards through the
-	     *  list of color style changes on the previous line, trying
-	     *  to find an ON change which isn't followed by a
-	     *  corresponding OFF.  When it finds one, the missing OFF
-	     *  change is appended to the end, and an ON change is added
-	     *  at the beginning of the current line.  The OFF change
-	     *  appended to the previous line may get removed again in
-	     *  the next iteration. - kw
-	     */
-	    line->styles[inew].horizpos = 0;
-	    line->styles[inew].direction = ON;
-	    line->styles[inew].style = previous->styles[spare - 1].style;
-	    inew --;
-	    line->numstyles ++;
-	    previous->styles[previous->numstyles].style = line->styles[inew + 1].style;
-
-	    previous->styles[previous->numstyles].direction = ABS_OFF;
-	    previous->styles[previous->numstyles].horizpos = previous->size;
-	    previous->numstyles++;
-	    spare --;
-	} else if (spare >= 2 &&
-		   previous->styles[spare - 1].style == previous->styles[spare - 2].style &&
-		   ((previous->styles[spare - 1].direction == STACK_OFF &&
-		     previous->styles[spare - 2].direction == STACK_ON) ||
-		    (previous->styles[spare - 1].direction == ABS_OFF &&
-		     previous->styles[spare - 2].direction == ABS_ON) ||
-		    (previous->styles[spare - 1].direction == STACK_ON &&
-		     previous->styles[spare - 2].direction == STACK_OFF) ||
-		    (previous->styles[spare - 1].direction == ABS_ON &&
-		     previous->styles[spare - 2].direction == ABS_OFF)
-		       )) {
-		/*
-		 *  Skip pairs of adjacent ON/OFF or OFF/ON changes.
-		 */
-	    spare -= 2;
-	} else if (spare && !previous->styles[spare - 1].direction) {
-	    /*
-	     *  Found an OFF change not part of an adjacent matched pair.
-	     *  Walk backward looking for the corresponding ON change.
-	     *  If we find it, skip the ON/OFF and everything in between.
-	     *  This can only work correctly if all changes are correctly
-	     *  nested!  If this fails, assume it is safer to leave whatever
-	     *  comes before the OFF on the previous line alone.  Setting
-	     *  spare to 0 ensures that it won't be used in a following
-	     *  iteration. - kw
+    {
+	HTStyleChange *from = previous->styles + previous->numstyles - 1;
+	HTStyleChange *to = line->styles + MAX_STYLES_ON_LINE - 1;
+	HTStyleChange *scan, *at_end;
+
+	/*  Color style changes after the split position
+	 *  are transferred to the new line.  Ditto for changes
+	 *  in the trimming region, but we stop when we reach an OFF change.
+	 *  The second loop below may then handle remaining changes. - kw */
+	while (from >= previous->styles && to >= line->styles) {
+	    *to = *from;
+	    if (to->horizpos > s_post)
+		to->horizpos += - s_post + SpecialAttrChars;
+	    else if (to->horizpos > s_pre &&
+		     (to->direction == STACK_ON ||
+		      to->direction == ABS_ON))
+		to->horizpos = (to->horizpos < s) ? 0 : SpecialAttrChars;
+	    else
+		break;
+	    to--;
+	    from--;
+	}
+	/* FROM may be invalid, otherwise it is either an ON change at or
+	   before s_pre, or is an OFF change at or before s_post.  */
+
+	scan = from;
+	at_end = from;
+	/* Now on the previous line we have a correctly nested but
+	   possibly non-terminated sequence of style changes.
+	   Terminate it, and duplicate unterminated changes at the
+	   beginning of the new line. */
+	while (scan >= previous->styles && at_end >= previous->styles) {
+	    /* The algorithm: scan back though the styles on the previous line.
+	       a) If OFF, skip the matched group.
+	          Report a bug on failure.
+	       b) If ON, (try to) cancel the corresponding ON at at_end,
+		  and the corresponding OFF at to;
+		  If not, put the corresponding OFF at at_end, and copy to to;
 	     */
-	    int level=-1;
-	    int itmp;
-	    for (itmp = spare-1; itmp > 0; itmp--) {
-		if (previous->styles[itmp - 1].style
-		    == previous->styles[spare - 1].style) {
-		    if (previous->styles[itmp - 1].direction == STACK_OFF) {
-			level--;
-		    } else if (previous->styles[itmp - 1].direction == STACK_ON) {
-			if (++level == 0)
-			    break;
-		    } else
-			break;
+	    if (scan->direction == STACK_OFF) {
+		scan = skip_matched_and_correct_offsets(scan, previous->styles,
+							s_pre);
+		if (!scan) {
+		    CTRACE((tfp, "BUG: styles improperly nested.\n"));
+		    break;
+		}
+	    } else if (scan->direction == STACK_ON) {
+		if ( at_end->direction == STACK_ON
+		     && at_end->style == scan->style
+		     && at_end->horizpos >= s_pre )
+		    at_end--;
+		else if (at_end >= previous->styles + MAX_STYLES_ON_LINE - 1) {
+		    CTRACE((tfp, "BUG: style overflow before split_line.\n"));
+		    break;
+		} else {
+		    at_end++;
+		    at_end->direction = STACK_OFF;
+		    at_end->style = scan->style;
+		    at_end->horizpos = s_pre;
+		}
+		if ( to < line->styles + MAX_STYLES_ON_LINE - 1
+		     && to[1].direction == STACK_OFF
+		     && to[1].horizpos <= SpecialAttrChars
+		     && to[1].style == scan->style )
+		    to++;
+		else if (to >= line->styles) {
+		    *to = *scan;
+		    to->horizpos = SpecialAttrChars;
+		    to--;
+		} else {
+		    CTRACE((tfp, "BUG: style overflow after split_line.\n"));
+		    break;
 		}
 	    }
-	    if (level == 0)
-		spare = itmp - 1;
-	    else
-		spare = 0;
-	} else {
-	    /*
-	     *  Nothing applied, so we are done with the loop. - kw
-	     */
-	    break;
+	    if (scan->horizpos > s_pre)
+		scan->horizpos = s_pre;
+	    scan--;
 	}
-    }
-    if (previous->numstyles > 0 && previous->styles[LastStyle].direction) {
+	line->numstyles = line->styles + MAX_STYLES_ON_LINE - 1 - to;
+	if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) {
+	    int n;
 
-	CTRACE((tfp, "%s\n%s%s\n",
-		    "........... Too many character styles on line:",
-		    "........... ", previous->data));
-    }
-    if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) {
-	int n;
-	inew ++;
-	for (n = 0; n < line->numstyles; n++)
-		line->styles[n] = line->styles[n + inew];
-    } else if (line->numstyles == 0) {
-	line->styles[0].horizpos = ~0;
+	    for (n = 0; n < line->numstyles; n++)
+		line->styles[n] = to[n + 1];
+	} else if (line->numstyles == 0)
+	    line->styles[0].horizpos = ~0; /* ?!!! */
+	previous->numstyles = at_end - previous->styles + 1;
+	if (previous->numstyles == 0)
+	    previous->styles[0].horizpos = ~0;	/* ?!!! */
     }
-    if (previous->numstyles == 0)
-	previous->styles[0].horizpos = ~0;
 #endif /*USE_COLOR_STYLE*/
 
     temp = (HTLine *)LY_CALLOC(1, LINE_SIZE(previous->size));
@@ -2907,7 +3011,6 @@ PRIVATE void split_line ARGS2(
 	    break;
     } /* switch */
 
-    text->chars = text->chars + previous->size + 1;	/* 1 for the line */
     text->in_line_1 = NO;		/* unless caller sets it otherwise */
 
     /*
@@ -2915,126 +3018,73 @@ PRIVATE void split_line ARGS2(
      *  structure values for the new line. - FM
      */
 
-    if (split > 0 || s > 0) {		/* if not completely empty */
+    if (s > 0) {			/* if not completely empty */
 	TextAnchor * prev_a = NULL;
+	int moved = 0;
+
+	/* In the algorithm below we move or not move anchors between
+	   lines using some heuristic criteria.  However, it is
+	   desirable not to have two consequent anchors on different
+	   lines *in a wrong order*!  (How can this happen?)
+	   So when the "reasonable choice" is not unique, we use the
+	   MOVED flag to choose one.
+	 */
+	/* Our operations can make a non-empty all-whitespace link
+	   empty.  So what? */
 	for (a = text->first_anchor; a; prev_a = a, a = a->next) {
 	    if (a->line_num == CurLine) {
-		int old_e = a->extent;
-		int a0 = a->line_pos, a1 = a->line_pos + a->extent;
-		int S, d, new_pos, new_ext;
-		if (a->link_type == INPUT_ANCHOR) {
-		    if (a->line_pos >= s) {
-			a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
-			a->line_pos -= (s - SpecialAttrChars + HeadTrim);
-			a->line_num = text->Lines;
+		int len = a->extent, n = a->number, start = a->line_pos;
+		int end = start + len;
+
+		/* Which anchors do we leave on the previous line?
+		   a) empty finished (We need a cut-off value.
+		      "Just because": those before s;
+		      this is the only case when we use s, not s_pre/s_post);
+		   b) Those which start before s_pre;
+		 */
+		if (start < s_pre) {
+		    if (end <= s_pre)
+			continue;	/* No problem */
+
+		    CTRACE_SPLITLINE((tfp, "anchor %d: no relocation", n));
+		    if (end > s_post) {
+			CTRACE_SPLITLINE((tfp, " of the start.\n"));
+			a->extent += -(TailTrim + HeadTrim) - SpecialAttrChars;
+		    } else {
+			CTRACE_SPLITLINE((tfp, ", cut the end.\n"));
+			a->extent = s_pre - start;
 		    }
 		    continue;
+		} else if (start < s && !len
+			   && (!n || (a->show_anchor && !moved))) {
+		    CTRACE_SPLITLINE((tfp, "anchor %d: no relocation, empty-finished",
+				      n));
+		    a->line_pos = s_pre; /* Leave at the end of line */
+		    continue;
 		}
-		if (a0 < s - TailTrim && a1 <= s - TailTrim) {
-		    continue;	/* unaffected, leave it where it is. */
-		}
-		S = s + a->start - a->line_pos;
-		d = S - s;	/* == a->start - a->line_pos */
-		new_ext = old_e = a->extent;
-
-		if (!old_e &&
-		    (!a->number || a->show_anchor) &&
-		    a0 <= s + HeadTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,1));
-		    /*
-		     *  It is meant to be empty, and/or endAnchor
-		     *  has seen it and recognized it as empty.
-		     */
-		    new_pos = (a0 <= s) ? s - TailTrim :
-			s - TailTrim + 1;
-		    if (prev_a && new_pos + d < prev_a->start) {
-			if (prev_a->start <= S - TailTrim + 1 + SpecialAttrChars)
-			    new_pos = prev_a->start - d;
-			else
-			    new_pos = s - TailTrim + 1 + SpecialAttrChars;
-		    }
-		} else if (old_e &&
-		     a0 >= s - TailTrim && a0 <= s + HeadTrim &&
-		     a1 <= s + HeadTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,2));
-		    /*
-		     *  endAnchor has seen it, it is effectively empty
-		     *  after our trimming, but endAnchor has for some
-		     *  reason not recognized this.  In other words,
-		     *  this should not happen.
-		     *  Should we not adjust the extent and let it "leak"
-		     *  into the new line?
-		     */
-		    new_pos = (a0 < s) ? s - TailTrim :
-			s - TailTrim + 1;
-		    if (prev_a && new_pos + d < prev_a->start) {
-			if (prev_a->start <= S - TailTrim + 1 + SpecialAttrChars)
-			    new_pos = prev_a->start - d;
-			else
-			    new_pos = s - TailTrim + 1 + SpecialAttrChars;
-		    }
-		    new_ext = 0;
-		} else if (a0 >= s + HeadTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,3));
-		    /*
-		     *  Completely after split, just shift.
-		     */
-		    new_pos = a0 - TailTrim + 1 - HeadTrim + SpecialAttrChars;
-		} else if (!old_e) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,4));
-		    /*
-		     *  No extent set, we may still be growing it.
-		     */
-		    new_pos = s - TailTrim + 1 + SpecialAttrChars;
 
-		    /*
-		     *  Ok, it's neither empty, nor is it completely
-		     *  before or after the split region (including trimmed
-		     *  stuff).  So the anchor is either being split in
-		     *  the middle, with stuff remaining on both lines,
-		     *  or something is being nibbled off, either at
-		     *  the end (anchor stays on previous line) or at
-		     *  the beginning (anchor is on new line).  Let's
-		     *  try in that order.
-		     */
-		} else if (a0 < s - TailTrim &&
-			   a1 > s + HeadTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,5));
-		    new_pos = a0;
-		    new_ext = old_e - TailTrim - HeadTrim + SpecialAttrChars;
-		} else if (a0 < s - TailTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,6));
-		    new_pos = a0;
-		    new_ext = s - TailTrim - a0;
-		} else if (a1 > s + HeadTrim) {
-		    CTRACE_SPLITLINE((tfp, "anchor %d case %d: ", a->number,7));
-		    new_pos = s - TailTrim + 1 + SpecialAttrChars;
-		    new_ext = old_e - (s + HeadTrim - a0);
-		} else {
-		    CTRACE((tfp, "split_line anchor %d line %d: This should not happen!\n",
-			   a->number, a->line_num));
-		    CTRACE((tfp,
-			   "anchor %d: (T,H,S)=(%d,%d,%d); (line,start,pos,ext):(%d,%d,%d,%d)!\n",
-			   a->number,
-			   TailTrim,HeadTrim,SpecialAttrChars,
-			   a->line_num,a->start,a->line_pos,a->extent));
-		    continue;
+		/* The rest we relocate */
+		moved = 1;
+		a->line_num++;
+		CTRACE_SPLITLINE((tfp, "anchor %d: (T,H,S)=(%d,%d,%d); (line,pos,ext):(%d,%d,%d), ",
+		       n, TailTrim,HeadTrim,SpecialAttrChars,
+		       a->line_num,a->line_pos,a->extent));
+		if (end < s_post) {	/* Move the end to s_post */
+		    CTRACE_SPLITLINE((tfp, "Move end +%d, ", s_post - end));
+		    len += s_post - end;
 		}
-		CTRACE_SPLITLINE((tfp, "(T,H,S)=(%d,%d,%d); (line,start,pos,ext):(%d,%d,%d,%d",
-		       TailTrim,HeadTrim,SpecialAttrChars,
-		       a->line_num,a->start,a->line_pos,a->extent));
-		if (new_pos != a->line_pos)
-		    a->start = new_pos + d;
-		if (new_pos > s - TailTrim) {
-		    new_pos -= s - TailTrim + 1;
-		    a->line_num = text->Lines;
+		if (start < s_post) {	/* Move the start to s_post */
+		    CTRACE_SPLITLINE((tfp, "Move start +%d, ", s_post - start));
+		    len -= s_post - start;
+		    start = s_post;
 		}
-		a->line_pos = new_pos;
-		a->extent = new_ext;
+		a->line_pos = start - s_post + SpecialAttrChars;
+		a->extent = len;
 
-		CTRACE_SPLITLINE((tfp, "))->(%d,%d,%d,%d)\n",
-		       a->line_num,a->start,a->line_pos,a->extent));
-	    }
+		CTRACE_SPLITLINE((tfp, "->(%d,%d,%d)\n",
+		       a->line_num,a->line_pos,a->extent));
+	    } else if (a->line_num > CurLine)
+		break;
 	}
     }
 
@@ -3043,6 +3093,7 @@ PRIVATE void split_line ARGS2(
 
     if (this_line_was_split
      && spare
+     && !text->stbl	/* We don't inform TRST on the cell width change yet */
      && justify_max_void_percent > 0
      && justify_max_void_percent <= 100
      && justify_max_void_percent >= ((100*spare)
@@ -3055,10 +3106,8 @@ PRIVATE void split_line ARGS2(
 	ht_run_info* r = ht_runs;
 	char c;
 	int total_byte_len = 0, total_cell_len = 0;
-	int d_, r_, i, j, cur_byte_num, *m;
+	int d_, r_;
 	HTLine * jline;
-	char *jdata;
-	char *prevdata = previous->data;
 
 	ht_num_runs = 0;
 	r->byte_len = r->cell_len = 0;
@@ -3106,183 +3155,46 @@ PRIVATE void split_line ARGS2(
 	++ht_num_runs;
 
 	if (ht_num_runs != 1) {
+	    int *oldpos = (int*)malloc(sizeof(int)*2*(ht_num_runs - 1));
+	    int *newpos = oldpos + ht_num_runs - 1;
+	    int i = 1;
 
-	    jline = allocHTLine(previous->size+spare);
-	    if (jline == NULL)
-		outofmem(__FILE__, "split_line_1");
-#if defined(USE_COLOR_STYLE)
-	    jline->styles = previous->styles;
-#endif
-	    jdata = jline->data;
+	    if (oldpos == NULL)
+		outofmem(__FILE__, "split_line_3");
 
-	    /*
-	     * we have to spread num_spaces among (ht_num_runs-1) runs - we
-	     * fill justified_text_map in order to apply changes caused by
-	     * justification to anchor data and color styles, and justify
-	     * original string on the fly
-	     */
 	    d_ = spare/(ht_num_runs-1);
 	    r_ = spare % (ht_num_runs-1);
 
-	    m = justified_text_map;
-	    for(jp = previous->data, i = 0; i < justify_start_position; ++i) {
-		*m++ = i;
-		*jdata++ = ( *prevdata == HT_NON_BREAK_SPACE ? ' ' : *prevdata);
-		++prevdata;
-	    }
-
-	    cur_byte_num = i;
-
-	    for (r = ht_runs; r < ht_runs + ht_num_runs; ++r ) {
+	    /* The first run is not moved, proceed to the second one */
+	    oldpos[0] = justify_start_position + ht_runs[0].cell_len + 1;
+	    newpos[0] = oldpos[0] + ( d_ + ( r_--  > 0 ) );
+	    while (i < ht_num_runs - 1) {
+		int delta = ht_runs[i].cell_len + 1;
 
-		/* copy the reference to run content */
-		for(i=0; i < r->byte_len;  ++i) {
-		    *m++ = cur_byte_num++;
-		    *jdata++ = *prevdata++;
-		}
-		if ( r - ht_runs  == ht_num_runs - 1 ) { /* nop on last run */
-		    *jdata++ = '\0';
-		    break;
-		}
-
-		/* the space that was in original string */
-		*m++ = cur_byte_num++;
-		*jdata++ = ' ';
-		prevdata++;/* skip that space */
-
-		cur_byte_num += j=( d_ + ( r_--  > 0 ) );
-		for (i=0; i<j; ++i)
-		    *jdata++ = ' ';
+		oldpos[i] = oldpos[i-1] + delta;
+		newpos[i] = newpos[i-1] + delta + ( d_ + ( r_--  > 0 ) );
+		i++;
 	    }
-	    *m++ = previous->size + spare; /*map the end */
-
-	    text->chars += spare;
-
-	    jline->offset = previous->offset;
-	    jline->size = previous->size + spare;
-	    jline->split_after = previous->split_after;
-	    jline->bullet = previous->bullet;
-	    jline->expansion_line = previous->expansion_line;
-
-	    jline->prev = previous->prev;
-	    jline->next = previous->next;
+	    jline = insert_blanks_in_line(previous, CurLine, text,
+					  last_anchor_of_previous_line,
+					  ht_num_runs - 1, oldpos, newpos);
+	    free((char*)oldpos);
+	    if (jline == NULL)
+		outofmem(__FILE__, "split_line_4");
 	    previous->next->prev = jline;
 	    previous->prev->next = jline;
 
-#if defined(USE_COLOR_STYLE)
-	    jline->numstyles = previous->numstyles;
-
-	    /* now copy and fix colorstyles */
-	    for(i = 0; i < jline->numstyles; ++i) {
-		int hpos = previous->styles[i].horizpos;
-
-		jline->styles[i].style = previous->styles[i].style;
-		jline->styles[i].direction = previous->styles[i].direction;
-		/*there are stylechanges with hpos > line length */
-		jline->styles[i].horizpos = (hpos > previous->size)
-			? previous->size + spare
-			: justified_text_map[hpos];
-	    }
-#endif
-	    /* we have to fix anchors*/
-	    {
-		/*a2 is the last anchor on the line preceding 'previous'*/
-		TextAnchor* a2 = last_anchor_of_previous_line;
-
-		if (!a2)
-		    a2 = text->first_anchor;
-		else if (a2 == text->last_anchor)
-		    a2 = NULL;
-		else
-		    a2 = a2->next; /*1st anchor on line we justify */
-
-		if (a2) {
-		    for (; a2 /*&& a2->line_num == text->Lines-1*/;
-			    last_anchor_of_previous_line = a2, a2 = a2->next) {
-			int oldpos = a2->line_pos,
-			    newpos = justified_text_map[a2->line_pos],
-			    shift = newpos - oldpos;
-
-			if (a2->line_num == text->Lines)
-			    break;/*new line not yet completed*/
-
-			if (a2->line_num == text->Lines-1) {
-			    a2->line_pos = newpos;
-			    a2->start += shift;
-
-			    if (!a2->extent && a2->number &&
-				(a2->link_type & HYPERTEXT_ANCHOR) &&
-				!a2->show_anchor &&
-				a2->number == text->last_anchor_number)
-				/* seems endAnchor wasn't called for it */ {
-				a2 = a2->next; /*don't allow .start to be incremented
-				    by 'spare' once more */
-				break;
-			    }
-
-			    if ( a2->extent + oldpos > (int) previous->size)
-				/*anchor content wrapped to new line */
-				a2->extent += (jline->size - newpos) -
-				    (previous->size - oldpos);
-			    else
-				a2->extent = justified_text_map[oldpos+a2->extent]
-				    - newpos;
-
-			} else {
-			    /* This is the anchor that was started on previous
-			     * line.  Its .line_pos and .start were updated.
-			     * So we have to update only extent.  If anchor
-			     * text is longer than two lines, we don't bother
-			     * setting it to correct value.
-			     */
-			    if (a2->line_num != text->Lines-2)
-				continue; /* don't bother */
-			    if (!a2->extent && a2->number &&
-				(a2->link_type & HYPERTEXT_ANCHOR) &&
-				!a2->show_anchor &&
-				a2->number == text->last_anchor_number)
-				/* seems endAnchor wasn't called for it */
-				continue;
-			    /* anchor is started at text->Lines-2, and there
-			     * are two cases - either it was wrapped to newline
-			     * or it ended in previous text->Lines-1.
-			     */
-			    {
-				int p2sz = previous->prev->size,
-				    p1sz = previous->size,
-				    onp2sz = p2sz - a2->line_pos,
-				    onp1sz = a2->extent - 1 - onp2sz;
-
-				if (onp1sz >= p1sz)
-				    /* this anchor will be skipped at the next
-				     * split_line here, since its line_num will
-				     * be text->Lines-3
-				     */
-				    a2->extent += spare;
-				else if (onp2sz < a2->extent)
-				    a2->extent += justified_text_map[onp1sz-1]
-					 - onp1sz + 1;
-			    }
-
-			}
-
-		    }
-
-		    /* iterate on anchors in the last line */
-		    for (; a2; a2 = a2->next)
-			a2->start += spare;
-		}
-	    }
-
 	    FREE(previous);
 
-	} else { /* (ht_num_runs==1) */
+	    previous = jline;
+	}
+	{ /* (ht_num_runs==1) */
 	    /* keep maintaining 'last_anchor_of_previous_line' */
 	    TextAnchor* a2 = last_anchor_of_previous_line;
 	    if (justify_start_position) {
-		char* p = previous->data;
-		for( ; p < previous->data + justify_start_position; ++p)
-		    *p = (*p == HT_NON_BREAK_SPACE ? ' ' : *p);
+		char* p2 = previous->data;
+		for( ; p2 < previous->data + justify_start_position; ++p2)
+		    *p2 = (*p2 == HT_NON_BREAK_SPACE ? ' ' : *p2);
 	    }
 
 	    if (!a2)
@@ -3298,23 +3210,23 @@ PRIVATE void split_line ARGS2(
 	}
     } else {
 	if (REALLY_CAN_JUSTIFY(text) ) {
-	    char* p;
+	    char* p2;
 
 	    /* it was permitted to justify line, but this function was called
 	     * to end paragraph - we must substitute HT_NON_BREAK_SPACEs with
 	     * spaces in previous line
 	     */
-	    if (line->size) {
-		  CTRACE((tfp,"justification: shouldn't happen - new line is not empty!\n"));
+	    if (line->size && !text->stbl) {
+		  CTRACE((tfp,"BUG: justification: shouldn't happen - new line is not empty!\n"));
 	    }
 
-	    for (p=previous->data;*p;++p)
-		if (*p == HT_NON_BREAK_SPACE)
-		    *p = ' ';
+	    for (p2=previous->data;*p2;++p2)
+		if (*p2 == HT_NON_BREAK_SPACE)
+		    *p2 = ' ';
 	} else if (have_raw_nbsps) {
 	    /* this is very rare case, that can happen in forms placed in
 	       table cells*/
-	    int i;
+	    unsigned i;
 
 	    for (i = 0; i< previous->size; ++i)
 		if (previous->data[i] == HT_NON_BREAK_SPACE)
@@ -3349,6 +3261,13 @@ PRIVATE void blank_lines ARGS2(
 
     if (!HText_LastLineSize(text, IgnoreSpaces)) { /* No text on current line */
 	HTLine * line = text->last_line->prev;
+
+#ifdef USE_COLOR_STYLE
+	/* Style-change petty requests at the start of the document: */
+	if (line == text->last_line && newlines == 1)
+	    return;			/* Do not add a blank line at start */
+#endif
+
 	while ((line != text->last_line) &&
 	       (HText_TrueLineSize(line, text, IgnoreSpaces) == 0)) {
 	    if (newlines == 0)
@@ -4411,9 +4330,9 @@ PUBLIC void _internal_HTC ARGS3(HText *,text, int,style, int,dir)
 	line = text->last_line;
 
 	if (line->numstyles > 0 && dir == 0 &&
-	    line->styles[line->numstyles].direction &&
-	    line->styles[line->numstyles].style == style &&
-	    (int) line->styles[line->numstyles].horizpos
+	    line->styles[line->numstyles-1].direction &&
+	    line->styles[line->numstyles-1].style == style &&
+	    (int) line->styles[line->numstyles-1].horizpos
 	    == (int)line->size - ctrl_chars_on_this_line) {
 	    /*
 	     *  If this is an OFF change directly preceded by an
@@ -4483,138 +4402,6 @@ PUBLIC void HText_setIgnoreExcess ARGS2(
 */
 
 /*
- *  Given a line and two int arrays of old/now position, this function
- *  does the actual work of creating a new line where spaces have been
- *  inserted in appropriate places - so that characters at/after the old
- *  position end up at/after the new position, for each pair, if possible.
- *  Some necessary changes for anchors starting on this line are also done
- *  here if needed.
- *  Returns a newly allocated HTLine* if changes were made
- *    (caller has to free the old one).
- *  Returns NULL if no changes needed.
- * - kw
- */
-PRIVATE HTLine * insert_blanks_in_line ARGS6(
-    HTLine *,		line,
-    int,		line_number,
-    HText *,		text,
-    int,		ninserts,
-    int *,		oldpos,
-    int *,		newpos)
-{
-    int i;
-    int ioldb, inewb;		/* count bytes */
-    int ioldc = 0, inewc = 0;	/* count visible characters (positions) */
-    int ip = 0;			/* count oldpos,newpos insertion pairs */
-    int acurshift, ashift = 0;	/* for shifting of anchors in this line */
-#if defined(USE_COLOR_STYLE)
-    int stcurshift, stshift = 0; /* for shifting of styles in this line */
-    int istyle;
-#endif
-    int added_chars = 0;
-    HTLine * mod_line;
-    char * newdata;
-    TextAnchor * a;
-    if (!(line && line->size && ninserts))
-	return NULL;
-    for (i = 0; i < ninserts; i++)
-	if (newpos[i] > oldpos[i] &&
-	    (newpos[i] - oldpos[i]) > added_chars)
-	    added_chars = newpos[i] - oldpos[i];
-    if (line->size + added_chars > MAX_LINE - 2)
-	return NULL;
-    if (line == text->last_line)
-	mod_line = allocHTLine(MAX_LINE);
-    else
-	mod_line = allocHTLine(line->size + added_chars);
-    if (!mod_line)
-	return NULL;
-    memcpy(mod_line, line, LINE_SIZE(1));
-    newdata = mod_line->data;
-    for (ioldb = 0, inewb = 0; ioldb < (int)line->size; ioldb++) {
-	if ((line->data[ioldb] == LY_BOLD_START_CHAR ||
-	     line->data[ioldb] == LY_UNDERLINE_START_CHAR ||
-	     !IsSpecialAttrChar(line->data[ioldb])) &&
-	    (!(text && text->T.output_utf8) ||
-	     UCH(line->data[ioldb]) < 128 ||
-	     (UCH((line->data[ioldb] & 0xc0)) == 0xc0))) {
-	    /*
-	     *  A new displayable character starts here.  Time to check
-	     *  whether this is a position to insert spaces.
-	     */
-	    while (ip < ninserts && oldpos[ip] <= ioldc) {
-		if (inewc < newpos[ip]) {
-		    /*
-		     *  Yup, spaces to insert.  We also have to update
-		     *  anchor positions for anchors that start on the
-		     *  same line, this is a pain.  Let's do it first.
-		     *  Note: we rely on a->line_pos counting bytes, not
-		     *  characters.  That's one reason why HText_trimHightext
-		     *  has to be prevented from acting on these anchors in
-		     *  partial display mode before we get a chance to
-		     *  deal with them here.
-		     */
-		    acurshift = 0;
-		    for (a = text->last_anchor_before_stbl ?
-			     text->last_anchor_before_stbl->next :
-			     text->first_anchor;
-			 a && a->line_num <= line_number; a = a->next) {
-			if (a->line_num == line_number)
-			    if (a->line_pos - ashift >= ioldb) {
-				acurshift = newpos[ip] - inewc;
-				a->line_pos += acurshift;
-				a->start += acurshift;
-			    }
-		    }
-		    ashift += acurshift;
-
-		    /*  doing something for color styles here.
-		     *  we rely on horizpos counting characters
-		     *  (display positions), not bytes. */
-#if defined(USE_COLOR_STYLE)
-#define NStyle mod_line->styles[istyle]
-		    stcurshift = 0;
-		    for (istyle = 0; istyle < line->numstyles;
-			 istyle++) {
-			if (NStyle.horizpos - stshift >= ioldc) {
-			    stcurshift = newpos[ip] - inewc;
-			    NStyle.horizpos += stcurshift;
-			}
-		    }
-		    stshift += stcurshift;
-#endif
-		    /*
-		     *  Now insert the spaces.
-		     */
-		    for (; inewc < newpos[ip]; inewc++) {
-			newdata[inewb++] = ' ';
-		    }
-		}
-		ip++;	/* done with this oldpos[ip],newpos[ip] pair. */
-	    }
-	    /*
-	     *  Copy character data over, advance position pointers.
-	     */
-	    newdata[inewb++] = line->data[ioldb];
-	    if (!(line->data[ioldb] == LY_BOLD_START_CHAR ||
-		  line->data[ioldb] == LY_UNDERLINE_START_CHAR)) {
-		ioldc++;
-		inewc++;
-	    }
-	} else {
-	    /*
-	     *  Just copy special attribute chars and utf-8 additional
-	     *  bytes over, don't advance position pointers.
-	     */
-	    newdata[inewb++] = line->data[ioldb];
-	}
-    }
-    newdata[inewb] = '\0';
-    mod_line->size = inewb;
-    return mod_line;
-}
-
-/*
  *  HText_insertBlanksInStblLines fixes up table lines when simple table
  *  processing is closed, by calling insert_blanks_in_line for lines
  *  that need fixup.  Also recalculates alignment for those lines,
@@ -4636,7 +4423,6 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
     int		last_nonempty = -1;
 #endif
     int		added_chars_before = 0;
-    TextAnchor * a;
     int lines_changed = 0;
     int max_width = 0, indent, spare, table_offset;
     HTStyle *style;
@@ -4662,14 +4448,6 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
     }
     first_lineno_pass2 = last_lineno = me->Lines;
     for (; line && lineno <= last_lineno; line = line->next, lineno++) {
-	if (added_chars_before) {
-	    for (a = me->last_anchor_before_stbl ?
-		     me->last_anchor_before_stbl->next : me->first_anchor;
-		 a && a->line_num <= lineno; a = a->next) {
-		if (a->line_num == lineno)
-		    a->start += added_chars_before;
-	    }
-	}
 	ninserts = Stbl_getFixupPositions(me->stbl, lineno, oldpos, newpos);
 	if (ninserts < 0)
 	    continue;
@@ -4712,12 +4490,12 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
 	    continue;
 	}
 	mod_line = insert_blanks_in_line(line, lineno, me,
+					 me->last_anchor_before_stbl,
 					 ninserts, oldpos, newpos);
 	if (mod_line) {
 	    if (line == me->last_line) {
 		me->last_line = mod_line;
 	    } else {
-		me->chars += (mod_line->size - line->size);
 		added_chars_before += (mod_line->size - line->size);
 	    }
 	    line->prev->next = mod_line;
@@ -4807,7 +4585,7 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
 	 *  Still not enough.  Something went wrong.  Try the best we
 	 *  can do.
 	 */
-	CTRACE((tfp, "insertBlanks: resulting table too wide by %d positions!",
+	CTRACE((tfp, "BUG: insertBlanks: resulting table too wide by %d positions!\n",
 	       -spare));
 	indent = spare = 0;
     }
@@ -4848,11 +4626,11 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
 	    CTRACE((tfp, " %d:%d", lineno, table_offset - line->offset));
 	    line->offset = table_offset;
 	}
+    }
 #ifdef EXP_NESTED_TABLES
-	if (max_width)
-	    Stbl_update_enclosing(me->stbl, max_width, last_nonempty);
+    if (max_width)
+	Stbl_update_enclosing(me->stbl, max_width, last_nonempty);
 #endif
-    }
     CTRACE((tfp, " %d:done\n", lineno));
     free(oldpos);
     return lines_changed;
@@ -4867,20 +4645,20 @@ PRIVATE int HText_insertBlanksInStblLines ARGS2(
 PUBLIC void HText_cancelStbl ARGS1(
 	HText *,	me)
 {
-    STable_info *stbl;
-
     if (!me || !me->stbl) {
 	CTRACE((tfp, "cancelStbl: ignored.\n"));
 	return;
     }
     CTRACE((tfp, "cancelStbl: ok, will do.\n"));
 #ifdef EXP_NESTED_TABLES
-    stbl = me->stbl;
+    {
+    STable_info *stbl = me->stbl;
     while (stbl) {
 	STable_info *enclosing = Stbl_get_enclosing(stbl);
 	Stbl_free(stbl);
 	stbl = enclosing;
     }
+    }
 #else
     Stbl_free(me->stbl);
 #endif
@@ -5012,7 +4790,7 @@ PUBLIC void HText_endStblTD ARGS1(
 {
     if (!me || !me->stbl)
 	return;
-    if (Stbl_finishCellInTable(me->stbl, YES,
+    if (Stbl_finishCellInTable(me->stbl, TRST_ENDCELL_ENDTD,
 			       me->Lines, HText_LastLineSize(me,FALSE)) < 0)
 	HText_cancelStbl(me);	/* give up */
 }
@@ -5079,7 +4857,6 @@ PUBLIC int HText_beginAnchor ARGS3(
 	outofmem(__FILE__, "HText_beginAnchor");
     a->hightext  = NULL;
     a->hightext2 = NULL;
-    a->start = text->chars + text->last_line->size;
     a->inUnderline = underline;
 
     a->line_num = text->Lines;
@@ -5122,7 +4899,6 @@ PUBLIC int HText_beginAnchor ARGS3(
 	HText_appendText(text, marker);
 	if (saved_linenum && text->Lines && saved_lastchar != ' ')
 	    text->LastChar = ']'; /* if marker not after space caused split */
-	a->start = text->chars + text->last_line->size;
 	a->line_num = text->Lines;
 	a->line_pos = text->last_line->size;
     }
@@ -5130,15 +4906,11 @@ PUBLIC int HText_beginAnchor ARGS3(
     return(a->number);
 }
 
-/*
-    This returns whether the given anchor has blank content. Shamelessly copied
-    from HText_endAnchor. The values returned are meaningful only for "normal"
-    links - like ones produced by <a href=".">foo</a>, no inputs, etc. - VH
-*/
-#ifdef MARK_HIDDEN_LINKS
-PUBLIC BOOL HText_isAnchorBlank ARGS2(
+/* If !really, report whether the anchor is empty. */
+PRIVATE int HText_endAnchor0 ARGS3(
 	HText *,	text,
-	int,		number)
+	int,		number,
+	int,		really)
 {
     TextAnchor *a;
 
@@ -5170,7 +4942,7 @@ PUBLIC BOOL HText_isAnchorBlank ARGS2(
 	}
     }
 
-    CTRACE((tfp, "GridText:HText_isAnchorBlank: number:%d link_type:%d\n",
+    CTRACE((tfp, "GridText:HText_endAnchor0: number:%d link_type:%d\n",
 			a->number, a->link_type));
     if (a->link_type == INPUT_ANCHOR) {
 	/*
@@ -5178,188 +4950,8 @@ PUBLIC BOOL HText_isAnchorBlank ARGS2(
 	 */
 
 	CTRACE((tfp,
-	   "HText_isAnchorBlank: internal error: last anchor was input field!\n"));
-	return 0;
-    }
-    if (a->number) {
-	/*
-	 *  If it goes somewhere...
-	 */
-	int i, j, k;
-	HTLine *last = text->last_line;
-	HTLine *prev = text->last_line->prev;
-	HTLine *start = last;
-	int CurBlankExtent = 0;
-	int BlankExtent = 0;
-
-	int extent_adjust = (text->chars + last->size) - a->start -
-		     (text->Lines - a->line_num);
-
-	/*
-	 *  Check if the anchor content has only
-	 *  white and special characters, starting
-	 *  with the content on the last line. - FM
-	 */
-	a->extent += extent_adjust;
-	if (a->extent > (int)last->size) {
-	    /*
-	     *  The anchor extends over more than one line,
-	     *  so set up to check the entire last line. - FM
-	     */
-	    i = last->size;
-	} else {
-	    /*
-	     *  The anchor is restricted to the last line,
-	     *  so check from the start of the anchor. - FM
-	     */
-	    i = a->extent;
-	}
-	k = j = (last->size - i);
-	while (j < (int)last->size) {
-	    if (!IsSpecialAttrChar(last->data[j]) &&
-		!isspace(UCH(last->data[j])) &&
-		last->data[j] != HT_NON_BREAK_SPACE &&
-		last->data[j] != HT_EN_SPACE)
-		break;
-	    i--;
-	    j++;
-	}
-	if (i == 0) {
-	    if (a->extent > (int)last->size) {
-		/*
-		 *  The anchor starts on a preceding line, and
-		 *  the last line has only white and special
-		 *  characters, so declare the entire extent
-		 *  of the last line as blank. - FM
-		 */
-		CurBlankExtent = BlankExtent = last->size;
-	    } else {
-		/*
-		 *  The anchor starts on the last line, and
-		 *  has only white or special characters, so
-		 *  declare the anchor's extent as blank. - FM
-		 */
-		CurBlankExtent = BlankExtent = a->extent;
-	    }
-	}
-	/*
-	 *  While the anchor starts on a line preceding
-	 *  the one we just checked, and the one we just
-	 *  checked has only white and special characters,
-	 *  check whether the anchor's content on the
-	 *  immediately preceding line also has only
-	 *  white and special characters. - FM
-	 */
-	while (i == 0 &&
-	       (a->extent > CurBlankExtent ||
-		(a->extent == CurBlankExtent &&
-		 k == 0 &&
-		 prev != text->last_line &&
-		 (prev->size == 0 ||
-		  prev->data[prev->size - 1] == ']')))) {
-	    start = prev;
-	    k = j = prev->size - a->extent + CurBlankExtent;
-	    if (j < 0) {
-		/*
-		 *  The anchor starts on a preceding line,
-		 *  so check all of this line. - FM
-		 */
-		j = 0;
-		i = prev->size;
-	    } else {
-		/*
-		 *  The anchor starts on this line. - FM
-		 */
-		i = a->extent - CurBlankExtent;
-	    }
-	    while (j < (int)prev->size) {
-		if (!IsSpecialAttrChar(prev->data[j]) &&
-		    !isspace(UCH(prev->data[j])) &&
-		    prev->data[j] != HT_NON_BREAK_SPACE &&
-		    prev->data[j] != HT_EN_SPACE)
-		    break;
-		i--;
-		j++;
-	    }
-	    if (i == 0) {
-		if (a->extent > (CurBlankExtent + (int)prev->size) ||
-		    (a->extent == CurBlankExtent + (int)prev->size &&
-		     k == 0 &&
-		     prev->prev != text->last_line &&
-		     (prev->prev->size == 0 ||
-		      prev->prev->data[prev->prev->size - 1] == ']'))) {
-		    /*
-		     *  This line has only white and special
-		     *  characters, so treat its entire extent
-		     *  as blank, and decrement the pointer for
-		     *  the line to be analyzed. - FM
-		     */
-		    CurBlankExtent += prev->size;
-		    BlankExtent = CurBlankExtent;
-		    prev = prev->prev;
-		} else {
-		    /*
-		     *  The anchor starts on this line, and it
-		     *  has only white or special characters, so
-		     *  declare the anchor's extent as blank. - FM
-		     */
-		    BlankExtent = a->extent;
-		    break;
-		}
-	    }
-	}
-	a->extent -= extent_adjust;
-	return i==0;
-    } else
+	   "BUG: HText_endAnchor0: internal error: last anchor was input field!\n"));
 	return 0;
-}
-#endif /* MARK_HIDDEN_LINKS */
-
-
-PUBLIC void HText_endAnchor ARGS2(
-	HText *,	text,
-	int,		number)
-{
-    TextAnchor *a;
-
-    /*
-     *  The number argument is set to 0 in HTML.c and
-     *  LYCharUtils.c when we want to end the anchor
-     *  for the immediately preceding HText_beginAnchor()
-     *  call.  If it's greater than 0, we want to handle
-     *  a particular anchor.  This allows us to set links
-     *  for positions indicated by NAME or ID attributes,
-     *  without needing to close any anchor with an HREF
-     *  within which that link might be embedded. - FM
-     */
-    if (number <= 0 || number == text->last_anchor->number) {
-	a = text->last_anchor;
-    } else {
-	for (a = text->first_anchor; a; a = a->next) {
-	    if (a->number == number) {
-		break;
-	    }
-	}
-	if (a == NULL) {
-	    /*
-	     *  There's no anchor with that number,
-	     *  so we'll default to the last anchor,
-	     *  and cross our fingers. - FM
-	     */
-	    a = text->last_anchor;
-	}
-    }
-
-    CTRACE((tfp, "GridText:HText_endAnchor: number:%d link_type:%d\n",
-			a->number, a->link_type));
-    if (a->link_type == INPUT_ANCHOR) {
-	/*
-	 *  Shouldn't happen, but put test here anyway to be safe. - LE
-	 */
-
-	CTRACE((tfp,
-	   "HText_endAnchor: internal error: last anchor was input field!\n"));
-	return;
     }
     if (a->number) {
 	/*
@@ -5379,14 +4971,25 @@ PUBLIC void HText_endAnchor ARGS2(
 	HTLine *start = last;
 	int CurBlankExtent = 0;
 	int BlankExtent = 0;
+	int extent_adjust = 0;
+
+	/* Find the length taken by the anchor */
+	l = text->Lines;		/* lineno of last */
+	while (l > a->line_num) {
+	    extent_adjust += start->size;
+	    start = start->prev;
+	    l--;
+	}
+	/* Now start is the start line of the anchor */
+	extent_adjust += start->size - a->line_pos;
+	start = last;			/* Used later */
 
 	/*
 	 *  Check if the anchor content has only
 	 *  white and special characters, starting
 	 *  with the content on the last line. - FM
 	 */
-	a->extent += (text->chars + last->size) - a->start -
-		     (text->Lines - a->line_num);
+	a->extent += extent_adjust;
 	if (a->extent > (int)last->size) {
 	    /*
 	     *  The anchor extends over more than one line,
@@ -5494,6 +5097,10 @@ PUBLIC void HText_endAnchor ARGS2(
 		}
 	    }
 	}
+	if (!really) {			/* Just report whether it is empty */
+	    a->extent -= extent_adjust;
+	    return i==0;
+	}
 	if (i == 0) {
 	    /*
 	     *  It's an invisible anchor probably from an ALT=""
@@ -5503,8 +5110,8 @@ PUBLIC void HText_endAnchor ARGS2(
 	    a->show_anchor = NO;
 
 	    CTRACE((tfp,
-		   "HText_endAnchor: hidden (line,start,pos,ext,BlankExtent):(%d,%d,%d,%d,%d)",
-		   a->line_num,a->start,a->line_pos,a->extent,
+		   "HText_endAnchor0: hidden (line,pos,ext,BlankExtent):(%d,%d,%d,%d)",
+		   a->line_num,a->line_pos,a->extent,
 		   BlankExtent));
 
 	    /*
@@ -5579,10 +5186,7 @@ PUBLIC void HText_endAnchor ARGS2(
 			k = j + NumSize;
 			while (k < (int)start->size)
 			    start->data[j++] = start->data[k++];
-			if (start != last)
-			    text->chars -= NumSize;
 			for (anc = a; anc; anc = anc->next) {
-			    anc->start -= NumSize;
 			    if (anc->line_num == a->line_num &&
 				anc->line_pos >= NumSize) {
 			    anc->line_pos -= NumSize;
@@ -5617,10 +5221,6 @@ PUBLIC void HText_endAnchor ARGS2(
 			    l = (i - j);
 			    while (i < (int)prev->size)
 				prev->data[j++] = prev->data[i++];
-			    text->chars -= l;
-			    for (anc = a; anc; anc = anc->next) {
-				anc->start -= l;
-			    }
 			    prev->size = j;
 			    prev->data[j] = '\0';
 			    while (j < i)
@@ -5635,10 +5235,7 @@ PUBLIC void HText_endAnchor ARGS2(
 			    i = k;
 			    while (k < (int)start->size)
 				start->data[j++] = start->data[k++];
-			    if (start != last)
-				text->chars -= i;
 			    for (anc = a; anc; anc = anc->next) {
-				anc->start -= i;
 				if (anc->line_num == a->line_num &&
 				    anc->line_pos >= i) {
 				    anc->line_pos -= i;
@@ -5694,10 +5291,6 @@ PUBLIC void HText_endAnchor ARGS2(
 			    k = j + NumSize;
 			    while (k < (int)prev->size)
 				prev->data[j++] = prev->data[k++];
-			    text->chars -= NumSize;
-			    for (anc = a; anc; anc = anc->next) {
-				anc->start -= NumSize;
-			    }
 			    prev->size = j;
 			    prev->data[j++] = '\0';
 			    while (j < k)
@@ -5733,8 +5326,8 @@ PUBLIC void HText_endAnchor ARGS2(
 	    a->show_anchor = YES;
 	    if (BlankExtent) {
 		CTRACE((tfp,
-		   "HText_endAnchor: blanks (line,start,pos,ext,BlankExtent):(%d,%d,%d,%d,%d)",
-		   a->line_num,a->start,a->line_pos,a->extent,
+		   "HText_endAnchor0: blanks (line,pos,ext,BlankExtent):(%d,%d,%d,%d)",
+		   a->line_num,a->line_pos,a->extent,
 		   BlankExtent));
 	    }
 	}
@@ -5764,12 +5357,14 @@ PUBLIC void HText_endAnchor ARGS2(
 	}
 	if (BlankExtent || a->extent <= 0 || a->number <= 0) {
 	    CTRACE((tfp,
-		   "->[%d](%d,%d,%d,%d,%d)\n",
+		   "->[%d](%d,%d,%d,%d)\n",
 		   a->number,
-		   a->line_num,a->start,a->line_pos,a->extent,
+		   a->line_num,a->line_pos,a->extent,
 		   BlankExtent));
 	}
     } else {
+	if (!really)			/* Just report whether it is empty */
+	    return 0;
 	/*
 	 *  It's a named anchor without an HREF, so it
 	 *  should be registered but not shown as a
@@ -5778,8 +5373,29 @@ PUBLIC void HText_endAnchor ARGS2(
 	a->show_anchor = NO;
 	a->extent = 0;
     }
+    return 0;
+}
+
+PUBLIC void HText_endAnchor ARGS2(
+	HText *,	text,
+	int,		number)
+{
+    HText_endAnchor0(text, number, 1);
 }
 
+/*
+    This returns whether the given anchor has blank content. Shamelessly copied
+    from HText_endAnchor. The values returned are meaningful only for "normal"
+    links - like ones produced by <a href=".">foo</a>, no inputs, etc. - VH
+*/
+#ifdef MARK_HIDDEN_LINKS
+PUBLIC BOOL HText_isAnchorBlank ARGS2(
+	HText *,	text,
+	int,		number)
+{
+    return HText_endAnchor0(text, number, 0);
+}
+#endif /* MARK_HIDDEN_LINKS */
 
 PUBLIC void HText_appendText ARGS2(
 	HText *,	text,
@@ -5921,7 +5537,7 @@ PUBLIC void HText_trimHightext ARGS3(
 	BOOLEAN,	final,
 	int,		stop_before)
 {
-    int cur_line, cur_char, cur_shift;
+    int cur_line, cur_shift;
     TextAnchor *anchor_ptr;
     TextAnchor *prev_a = NULL;
     HTLine *line_ptr;
@@ -5944,7 +5560,6 @@ PUBLIC void HText_trimHightext ARGS3(
      *  Get the first line.
      */
     line_ptr = text->last_line->next;
-    cur_char = line_ptr->size;
     cur_line = 0;
 
     /*
@@ -5959,10 +5574,8 @@ re_parse:
 	/*
 	 *  Find the right line.
 	 */
-	for (; anchor_ptr->start > cur_char;
-	       line_ptr = line_ptr->next,
-	       cur_char += line_ptr->size+1,
-	       cur_line++) {
+	for (; anchor_ptr->line_num > cur_line;
+	       line_ptr = line_ptr->next, cur_line++) {
 	    ; /* null body */
 	}
 
@@ -5974,7 +5587,8 @@ re_parse:
 	     */
 	    if (cur_line >= stop_before)
 		break;
-	    if (anchor_ptr->start >= text->chars - 1)
+	    if ( anchor_ptr->line_num >= text->Lines - 1
+		 && anchor_ptr->line_pos >= (int) text->last_line->prev->size )
 		break;
 	    /*
 	     *  Also skip this anchor if it looks like HText_endAnchor
@@ -5995,14 +5609,10 @@ re_parse:
 	if (anchor_ptr->hightext)
 	    continue;
 
-	if (anchor_ptr->start == cur_char) {
+	if (anchor_ptr->line_pos > (int) line_ptr->size) {
 	    anchor_ptr->line_pos = line_ptr->size;
-	} else {
-	    anchor_ptr->line_pos = anchor_ptr->start -
-				   (cur_char - line_ptr->size);
 	}
 	if (anchor_ptr->line_pos < 0) {
-	    anchor_ptr->start -= anchor_ptr->line_pos;
 	    anchor_ptr->line_pos = 0;
 	    anchor_ptr->line_num = cur_line;
 	}
@@ -6029,7 +5639,6 @@ re_parse:
 	if (anchor_ptr->extent < 0) {
 	    anchor_ptr->extent = 0;
 	}
-	anchor_ptr->start += cur_shift;
 
 	CTRACE((tfp, "anchor text: '%s'\n", line_ptr->data));
 	/*
@@ -6043,8 +5652,10 @@ re_parse:
 	    if (cur_line < text->Lines &&
 		(anchor_ptr->extent ||
 		 anchor_ptr->line_pos != (int)line_ptr->size ||
-		 (prev_a && prev_a->start > anchor_ptr->start))) {
-		anchor_ptr->start++;
+		 (prev_a && /* How could this happen? */
+		  (prev_a->line_num > anchor_ptr->line_num)))) {
+		anchor_ptr->line_num++;
+		anchor_ptr->line_pos = 0;
 		CTRACE((tfp, "found anchor at end of line\n"));
 		goto re_parse;
 	    } else {
@@ -6369,8 +5980,8 @@ PUBLIC int HTGetLinkInfo ARGS6(
 	 *  and don't count towards nlinks. - KW
 	 */
 	if ((a->show_anchor) &&
-	    (a->link_type != INPUT_ANCHOR ||
-	     a->input_field->type != F_HIDDEN_TYPE)) {
+	    !(a->link_type == INPUT_ANCHOR
+	      && a->input_field->type == F_HIDDEN_TYPE)) {
 	    if (a->line_num == prev_anchor_line) {
 		anchors_this_line++;
 	    } else {
@@ -6645,8 +6256,8 @@ PUBLIC int HTGetLinkOrFieldStart ARGS5(
 	 *  and don't count towards nlinks. - KW
 	 */
 	if ((a->show_anchor) &&
-	    (a->link_type != INPUT_ANCHOR ||
-	     a->input_field->type != F_HIDDEN_TYPE)) {
+	    !(a->link_type == INPUT_ANCHOR
+	      && a->input_field->type == F_HIDDEN_TYPE)) {
 	    if (a->line_num == prev_anchor_line) {
 		anchors_this_line++;
 	    } else {
@@ -7141,7 +6752,7 @@ PUBLIC void HText_pageDisplay ARGS2(
 	**  Multiple calls of HText_trimHightext works without problem now.
 	*/
 	if (HTMainText && HTMainText->stbl)
-	    stop_before = Stbl_getStartLine(HTMainText->stbl);
+	    stop_before = Stbl_getStartLineDeep(HTMainText->stbl);
 	HText_trimHightext(HTMainText, FALSE, stop_before);
     }
 #endif
@@ -7197,8 +6808,8 @@ PUBLIC int HText_LinksInLines ARGS3(
 	if (Anchor_ptr->line_num >= start &&
 	    Anchor_ptr->line_num < end &&
 	    Anchor_ptr->show_anchor &&
-	    (Anchor_ptr->link_type != INPUT_ANCHOR ||
-	     Anchor_ptr->input_field->type != F_HIDDEN_TYPE))
+	    !(Anchor_ptr->link_type == INPUT_ANCHOR
+	      && Anchor_ptr->input_field->type == F_HIDDEN_TYPE))
 	    ++total;
 	if (Anchor_ptr == text->last_anchor)
 	    break;
@@ -7273,22 +6884,6 @@ PUBLIC void HText_scrollBottom ARGS1(
 
 /* Bring to front and highlight it
 */
-PRIVATE int line_for_char ARGS2(
-	HText *,	text,
-	int,		char_num)
-{
-    int line_number = 0;
-    int characters = 0;
-    HTLine * line = text->last_line->next;
-    for (;;) {
-	if (line == text->last_line) return 0;	/* Invalid */
-	characters = characters + line->size + 1;
-	if (characters > char_num) return line_number;
-	line_number ++;
-	line = line->next;
-    }
-}
-
 PUBLIC BOOL HText_select ARGS1(
 	HText *,	text)
 {
@@ -7400,8 +6995,8 @@ PUBLIC BOOL HTFindPoundSelector ARGS1(
 		www_search_result = a->line_num+1;
 
 		CTRACE((tfp,
-		       "HText: Selecting anchor [%d] at character %d, line %d\n",
-				     a->number, a->start, www_search_result));
+		       "HText: Selecting anchor [%d] at line %d\n",
+				     a->number, www_search_result));
 		if (!strcmp(selector, LYToolbarName)) {
 		    --www_search_result;
 		}
@@ -7440,10 +7035,10 @@ PUBLIC BOOL HText_selectAnchor ARGS2(
     }
 
     {
-	 int l = line_for_char(text, a->start);
+	 int l = a->line_num;
 	 CTRACE((tfp,
-	    "HText: Selecting anchor [%d] at character %d, line %d\n",
-	    a->number, a->start, l));
+	    "HText: Selecting anchor [%d] at line %d\n",
+	    a->number, l));
 
 	if ( !text->stale &&
 	     (l >= text->top_of_screen) &&
@@ -8119,8 +7714,8 @@ PRIVATE int www_user_search_internals ARGS8(
     for (;;) {
 	while ((a != NULL) && a->line_num == (*count - 1)) {
 	    if (a->show_anchor &&
-		(a->link_type != INPUT_ANCHOR ||
-		 a->input_field->type != F_HIDDEN_TYPE)) {
+		!(a->link_type == INPUT_ANCHOR
+		  && a->input_field->type == F_HIDDEN_TYPE)) {
 		if (((a->hightext != NULL && case_sensitive == TRUE) &&
 		     LYno_attr_char_strstr(a->hightext, target)) ||
 		    ((a->hightext != NULL && case_sensitive == FALSE) &&
@@ -8491,7 +8086,7 @@ PUBLIC BOOLEAN HTreparse_document NOARGS
 	}
 	CTRACE((tfp, "  Content type is \"%s\"\n", format->name));
 
-	fp = fopen(HTMainAnchor->source_cache_file, "r");
+	fp = fopen(HTMainAnchor->source_cache_file, TXT_R);
 	if (!fp) {
 	    CTRACE((tfp, "  Cannot read file %s\n", HTMainAnchor->source_cache_file));
 	    LYRemoveTemp(HTMainAnchor->source_cache_file);
@@ -8873,8 +8468,6 @@ PUBLIC void HText_RemovePreviousLine ARGS1(
     previous = line->prev;
     previous->next = text->last_line;
     text->last_line->prev = previous;
-    text->chars -= ((data && *data == '\0') ?
-					  1 : strlen(line->data) + 1);
     text->Lines--;
     FREE(line);
 }
@@ -9486,7 +9079,7 @@ PUBLIC char * HText_setLastOptionValue ARGS7(
 	cp[j] = '\0';
 	if (HTCJK != NOCJK) {
 	    if (cp &&
-		(tmp = (unsigned char *)calloc(1, strlen(cp)+1))) {
+		(tmp = typecallocn(unsigned char, strlen(cp)+1)) != 0) {
 #ifdef SH_EX
 		if (tmp == NULL)
 		    outofmem(__FILE__, "HText_setLastOptionValue");
@@ -9608,27 +9201,6 @@ PUBLIC char * HText_setLastOptionValue ARGS7(
 }
 
 /*
- * Count the number of anchors on the current line so we can allow for the
- * length of numbered fields.
- */
-PRIVATE int AnchorsOnThisLine ARGS2(
-	HText *,	txt,
-	TextAnchor *,	ank)
-{
-    TextAnchor *chk = txt->first_anchor;
-    int count = 1;
-
-    while (chk != 0
-    	&& chk != txt->last_anchor
-	&& chk != ank) {
-	if (chk->line_num == ank->line_num)
-	    count++;
-	chk = chk->next;
-    }
-    return count;
-}
-
-/*
  *  Assign a form input anchor.
  *  Returns the number of characters to leave
  *  blank so that the input field can fit.
@@ -9650,7 +9222,6 @@ PUBLIC int HText_beginInput ARGS3(
     if (a == NULL || f == NULL)
 	outofmem(__FILE__, "HText_beginInput");
 
-    a->start = text->chars + text->last_line->size;
     a->inUnderline = underline;
     a->line_num = text->Lines;
     a->line_pos = text->last_line->size;
@@ -9728,11 +9299,7 @@ PUBLIC int HText_beginInput ARGS3(
     if (I->value)
 	StrAllocCopy(IValue, I->value);
     if (IValue && HTCJK != NOCJK) {
-	if ((tmp = (unsigned char *)calloc(1, (strlen(IValue) + 1)))) {
-#ifdef SH_EX
-	    if (tmp == NULL)
-		outofmem(__FILE__, "HText_beginInput");
-#endif
+	if ((tmp = typecallocn(unsigned char, strlen(IValue) + 1)) != 0) {
 	    if (kanji_code == EUC) {
 		TO_EUC((unsigned char *)IValue, tmp);
 		I->value_cs = current_char_set;
@@ -10018,7 +9585,6 @@ PUBLIC int HText_beginInput ARGS3(
 	     *  Add option list designation char.
 	     */
 	    HText_appendCharacter(text, '[');
-	a->start = text->chars + text->last_line->size;
 	a->line_num = text->Lines;
 	a->line_pos = text->last_line->size;
     }
@@ -10047,12 +9613,14 @@ PUBLIC int HText_beginInput ARGS3(
 			  (int)text->style->leftIndent -
 			  (int)text->style->rightIndent;
 
-	    /*
-	     *  If we are numbering form links, take that into
-	     *  account as well. - FM
-	     */
+	    /*  If we are numbering form links, place is taken by [nn]  */
 	    if (keypad_mode == LINKS_AND_FIELDS_ARE_NUMBERED)
-		MaximumSize -= AnchorsOnThisLine(text, a) / 10 + 3;
+		MaximumSize -= (a->number >= 10	/*Buggy if 1e6 links, sowhat?*/
+				? (a->number >= 100
+				   ? (a->number >= 1000
+				      ? (a->number >= 10000
+					 ? (a->number >= 100000
+					    ? 6 : 5) : 4) : 3) : 2) : 1) + 2;
 	    if (f->size > MaximumSize)
 		f->size = MaximumSize;
 
@@ -10858,7 +10426,7 @@ PUBLIC int HText_SubmitForm ARGS4(
 			escaped1 = HTEscapeSP(name_used, URL_XALPHAS);
 		    }
 
-		    if ((fd = fopen(val_used, "rb")) == 0) {
+		    if ((fd = fopen(val_used, BIN_R)) == 0) {
 			/* We can't open the file, what do we do? */
 			HTAlert(gettext("Can't open file for uploading"));
 			goto exit_disgracefully;
@@ -12189,7 +11757,6 @@ PRIVATE void insert_new_textarea_anchor ARGS2(
     /*  [anything "special" needed based on ->show_anchor value ?] */
     a->next	       = anchor->next;
     a->number	       = anchor->number;
-    a->start	       = anchor->start + anchor->input_field->size + 1;
     a->line_pos	       = anchor->line_pos;
     a->extent	       = anchor->extent;
     a->line_num	       = anchor->line_num + 1;
@@ -12220,9 +11787,6 @@ PRIVATE void insert_new_textarea_anchor ARGS2(
     l->prev	       = htline;
     l->offset	       = htline->offset;
     l->size	       = htline->size;
-    l->split_after     = htline->split_after;
-    l->bullet	       = htline->bullet;
-    l->expansion_line  = TRUE;
 #if defined(USE_COLOR_STYLE)
     /* dup styles[] if needed [no need in TEXTAREA (?); leave 0's] */
     l->numstyles       = htline->numstyles;
@@ -12276,13 +11840,12 @@ PRIVATE void insert_new_textarea_anchor ARGS2(
 PRIVATE void update_subsequent_anchors ARGS4(
 	int,		 n,
 	TextAnchor *,	 start_anchor,
-	HTLine *,        start_htline,
+	HTLine *,	 start_htline,
 	int,		 start_tag)
 {
     TextAnchor *anchor;
     HTLine     *htline = start_htline;
 
-    int form_chars_added = (start_anchor->input_field->size + 1) * n;
     int		line_adj = 0;
     int		tag_adj	 = 0;
     int		lx	 = 0;
@@ -12306,7 +11869,6 @@ PRIVATE void update_subsequent_anchors ARGS4(
 	    (anchor->number != 0))
 	    anchor->number += n;
 	anchor->line_num  += n;
-	anchor->start	  += form_chars_added;
 	anchor = anchor->next;
     }
 
@@ -12395,7 +11957,6 @@ finish:
     nlinks                         += n;
     HTMainText->Lines              += n;
     HTMainText->last_anchor_number += n;
-    HTMainText->chars              += (form_chars_added + tag_adj);
 
     more = HText_canScrollDown();
 
@@ -12456,7 +12017,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
     char       *line;
     char       *lp;
     char       *cp;
-    int         match_tag = 0;
+    int		match_tag = 0;
     int		newlines  = 0;
     int		len, len0, len_in;
     int		wanted_fieldlen_wrap = -1; /* not yet asked; 0 means don't. */
@@ -12596,7 +12157,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
 	    return 0;
 	}
 
-	fp = fopen (ed_temp, "r");
+	fp = fopen (ed_temp, TXT_R);
 	size = fread (ebuf, 1, size, fp);
 	LYCloseInput (fp);
 	ebuf[size] = '\0';	/* Terminate! - kw */
@@ -12801,7 +12362,7 @@ PUBLIC int HText_ExtEditForm ARGS1(
  */
 PUBLIC void HText_ExpandTextarea ARGS2(
 	    struct link *,  form_link,
-	    int,            newlines)
+	    int,	    newlines)
 {
     TextAnchor *anchor_ptr;
     TextAnchor *end_anchor    = NULL;
@@ -12986,7 +12547,7 @@ PUBLIC int HText_InsertFile ARGS1(
 	 */
 	LYGetFileInfo(fn, 0, 0, 0, 0, 0, &file_cs);
 
-	fp   = fopen (fn, "r");
+	fp   = fopen (fn, TXT_R);
 	if (!fp) {
 	    free(fbuf);
 	    free(fn);
@@ -13059,7 +12620,6 @@ PUBLIC int HText_InsertFile ARGS1(
     /*  [anything "special" needed based on ->show_anchor value ?] */
     a->next	       = anchor_ptr;
     a->number	       = anchor_ptr->number;
-    a->start	       = anchor_ptr->start;
     a->line_pos	       = anchor_ptr->line_pos;
     a->extent	       = anchor_ptr->extent;
     a->line_num	       = anchor_ptr->line_num;
@@ -13088,9 +12648,6 @@ PUBLIC int HText_InsertFile ARGS1(
     /*  Init all the fields in the new HTLine (but see the #if).   */
     l->offset	       = htline->offset;
     l->size	       = htline->size;
-    l->split_after     = htline->split_after;
-    l->bullet	       = htline->bullet;
-    l->expansion_line  = TRUE;
 #if defined(USE_COLOR_STYLE)
     /* dup styles[] if needed [no need in TEXTAREA (?); leave 0's] */
     l->numstyles       = htline->numstyles;
@@ -13112,11 +12669,11 @@ PUBLIC int HText_InsertFile ARGS1(
     if (prev_anchor)
 	prev_anchor->next = a;
 
-    htline             = htline->prev;
-    l->next	       = htline->next;
-    l->prev	       = htline;
-    htline->next->prev = l;
-    htline->next       = l;
+    htline		= htline->prev;
+    l->next		= htline->next;
+    l->prev		= htline;
+    htline->next->prev	= l;
+    htline->next	= l;
 
     /*
      *  update_subsequent_anchors() expects htline to point to 1st potential
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index ff75c6e0..3afa76db 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -570,7 +570,7 @@ PRIVATE char *mailcap_substitute ARGS3(
 	    }
 	}
 	if (pass == 0) {
-	    if ((result = malloc(need)) == 0)
+	    if ((result = malloc(need + 1)) == 0)
 		outofmem(__FILE__, "mailcap_substitute");
 	    *result = 0;
 	}
@@ -667,7 +667,7 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3(
 	 *  not being able to find the fp.  The ".bin" suffix is expected
 	 *  to not be used, it's only for fallback in unusual error cases. - kw
 	 */
-	me->fp = LYOpenTempRewrite(fnam, ".bin", "wb");
+	me->fp = LYOpenTempRewrite(fnam, ".bin", BIN_W);
     } else {
 #if defined(WIN_EX) && !defined(__CYGWIN__)	/* 1998/01/04 (Sun) */
 	if (!strncmp(anchor->address,"file://localhost",16)) {
@@ -730,7 +730,7 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3(
 	{
 	    suffix = HTML_SUFFIX;
 	}
-	me->fp = LYOpenTemp(fnam, suffix, "wb");
+	me->fp = LYOpenTemp(fnam, suffix, BIN_W);
     }
 
     if (!me->fp) {
@@ -862,7 +862,7 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
 	 *  not being able to find the fp.  The ".bin" suffix is expected
 	 *  to not be used, it's only for fallback in unusual error cases. - kw
 	 */
-	ret_obj->fp = LYOpenTempRewrite(fnam, ".bin", "wb");
+	ret_obj->fp = LYOpenTempRewrite(fnam, ".bin", BIN_W);
     } else {
 	/*
 	 *  Check for a suffix.
@@ -880,7 +880,7 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
 		    || *suffix != '.') {
 	    suffix = HTML_SUFFIX;
 	}
-	ret_obj->fp = LYOpenTemp(fnam, suffix, "wb");
+	ret_obj->fp = LYOpenTemp(fnam, suffix, BIN_W);
     }
 
     if (!ret_obj->fp) {
@@ -1173,7 +1173,7 @@ PUBLIC HTStream* HTCompressed ARGS3(
     /*
      *	Open the file for receiving the compressed input stream. - FM
      */
-    me->fp = LYOpenTemp (fnam, temp, "wb");
+    me->fp = LYOpenTemp (fnam, temp, BIN_W);
     if (!me->fp) {
 	HTAlert(CANNOT_OPEN_TEMP);
 	FREE(uncompress_mask);
diff --git a/src/HTML.c b/src/HTML.c
index 8973cab0..4175b026 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -8178,7 +8178,7 @@ PUBLIC HTStructured* HTML_new ARGS3(
 	exit_immediately (EXIT_FAILURE);
     }
 
-    me = (HTStructured*) calloc(sizeof(*me),1);
+    me = typecalloc(HTStructured);
     if (me == NULL)
 	outofmem(__FILE__, "HTML_new");
 
@@ -8631,7 +8631,7 @@ PRIVATE HTStream* CacheThru_new ARGS2(
 	 * don't get munged; this way, the file should (knock on wood)
 	 * contain exactly what came in from the network.
 	 */
-	if (!(stream->fp = LYOpenTemp(filename, HTML_SUFFIX, "wb"))) {
+	if (!(stream->fp = LYOpenTemp(filename, HTML_SUFFIX, BIN_W))) {
 	    CTRACE((tfp, "SourceCacheWriter: Cannot open source cache file for URL %s\n",
 		   HTAnchor_address((HTAnchor *)anchor)));
 	    FREE(stream);
diff --git a/src/LYBookmark.c b/src/LYBookmark.c
index db2e0271..cfe8c837 100644
--- a/src/LYBookmark.c
+++ b/src/LYBookmark.c
@@ -328,7 +328,7 @@ PUBLIC void save_bookmark_link ARGS2(
     }
     CTRACE((tfp, "\nsave_bookmark_link: SEEKING %s\n   AS %s\n\n",
 		BookmarkPage, filename_buffer));
-    if ((fp = fopen(filename_buffer, (first_time ? "w" : "a+"))) == NULL) {
+    if ((fp = fopen(filename_buffer, (first_time ? TXT_W : TXT_A))) == NULL) {
 	LYMBM_statusline(BOOKMARK_OPEN_FAILED);
 	LYSleepAlert();
 	FREE(Title);
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index 6bb34184..3a15f269 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -111,8 +111,8 @@ PUBLIC void LYEntify ARGS2(
     /*
      *	Allocate space and convert. - FM
      */
-    q = (char *)calloc(1,
-		     (strlen(*str) + (4 * amps) + (3 * lts) + (3 * gts) + 1));
+    q = typecallocn(char,
+		    (strlen(*str) + (4 * amps) + (3 * lts) + (3 * gts) + 1));
     if ((cp = q) == NULL)
 	outofmem(__FILE__, "LYEntify");
     for (p = *str; *p; p++) {
@@ -3623,11 +3623,10 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 		   : me->node_anchor->address[4]) == 's') {
 		    str = "s";
 		}
-		if (TRACE) {
-		    CTRACE((tfp, "LYLegitimizeHREF: Bad value '%s' for http%s URL.\n",
-				 *href, str);)
-		    CTRACE((tfp, "                  Stripping lead dots.\n"));
-		} else if (!me->inBadHREF) {
+		CTRACE((tfp, "LYLegitimizeHREF: Bad value '%s' for http%s URL.\n",
+			*href, str));
+		CTRACE((tfp, "                  Stripping lead dots.\n"));
+		if (!me->inBadHREF) {
 		    HTUserMsg(BAD_PARTIAL_REFERENCE);
 		    me->inBadHREF = TRUE;
 		}
diff --git a/src/LYCookie.c b/src/LYCookie.c
index ec9ab39d..df847365 100644
--- a/src/LYCookie.c
+++ b/src/LYCookie.c
@@ -132,7 +132,7 @@ PRIVATE void MemAllocCopy ARGS3(
 	return;
     }
 
-    temp = (char *)calloc(1, ((end - start) + 1));
+    temp = typecallocn(char, (end - start) + 1);
     if (temp == NULL)
 	outofmem(__FILE__, "MemAllocCopy");
     LYstrncpy(temp, start, (end - start));
@@ -1031,7 +1031,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		if (value_len > max_cookies_buffer) {
 		    value_len = max_cookies_buffer;
 		}
-		value = (char *)calloc(1, value_len + 1);
+		value = typecallocn(char, value_len + 1);
 		if (value == NULL)
 		    outofmem(__FILE__, "LYProcessSetCookies");
 		LYstrncpy(value, value_start, value_len);
@@ -1551,7 +1551,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		if (value_len > max_cookies_buffer) {
 		    value_len = max_cookies_buffer;
 		}
-		value = (char *)calloc(1, value_len + 1);
+		value = typecallocn(char, value_len + 1);
 		if (value == NULL)
 		    outofmem(__FILE__, "LYProcessSetCookies");
 		LYstrncpy(value, value_start, value_len);
diff --git a/src/LYCurses.c b/src/LYCurses.c
index fe9642b6..49d48567 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -769,7 +769,6 @@ static WINDOW *LYscreen = NULL;
 
 PUBLIC void start_curses NOARGS
 {
-    int keypad_on = 0;
 #ifdef USE_SLANG
     static int slinit;
 
@@ -882,10 +881,10 @@ PUBLIC void start_curses NOARGS
     signal(SIGINT, cleanup_sig);
 #endif /* !VMS */
 
-   lynx_enable_mouse (1);
+    lynx_enable_mouse (1);
 
 #else /* USE_SLANG; Now using curses: */
-
+    int keypad_on = 0;
 
 #ifdef VMS
     /*
@@ -1152,6 +1151,56 @@ PUBLIC void lynx_enable_mouse ARGS1(int,state)
 #endif /* USE_MOUSE */
 }
 
+/*
+ * SVr4 curses (and ncurses) initialize the terminal I/O to raw mode, and
+ * simulate other modes in the library.  This means that when running, it
+ * simulates the OCRNL setting.  Normally that is not a problem.  However, when
+ * spawning a subprocess (e.g., xli), the subprocess may write to the screen. 
+ * Fine so far - curses resets the terminal I/O to the normal state on exit. 
+ * But the subprocess's messages can still be coming to the screen when lynx
+ * returns to the screen mode.  This function delays restoring OCRNL until
+ * after the first getch() call.
+ *
+ * The OCRNL setting is controlled by nl()/nonl() of course - but we do not
+ * want to give up that optimization since it would be a bit slower.  (Note -
+ * slang does not use this optimization; if it did, the same screen glitch
+ * would occur).
+ *
+ * FIXME:  for simplicity, only ncurses is implemented here - the TTY and
+ * SET_TTY definitions are ncurses-specific.  The same effect could be done for
+ * other curses implementations, since the "cur_term->Nttyb" part is common to
+ * SVr4 curses.
+ */
+PUBLIC void lynx_nl2crlf ARGS1(int, normal GCC_UNUSED)
+{
+    
+#if defined(NCURSES_VERSION) && defined(SET_TTY) && defined(TERMIOS) && defined(ONLCR)
+    static TTY saved_tty;
+    static int did_save = FALSE;
+    static int waiting = FALSE;
+
+    if (!did_save) {
+	saved_tty = cur_term->Nttyb;
+	did_save = TRUE;
+    }
+    if (normal) {
+	if (!waiting) {
+	    cur_term->Nttyb.c_oflag |= ONLCR;
+	    waiting = TRUE;
+	    nonl();
+	}
+    } else {
+	if (waiting) {
+	    cur_term->Nttyb = saved_tty;
+	    SET_TTY(fileno(stdout), &saved_tty);
+	    waiting = FALSE;
+	    nl();
+	    LYrefresh();
+	}
+    }
+#endif
+}
+
 PUBLIC void stop_curses NOARGS
 {
     if (LYCursesON)
@@ -1172,6 +1221,7 @@ PUBLIC void stop_curses NOARGS
      *	05-28-94 Lynx 2-3-1 Garrett Arch Blythe
      */
     if(LYCursesON == TRUE)	{
+	lynx_nl2crlf(TRUE);
 	lynx_enable_mouse (0);
 #if (!defined(WIN_EX) || defined(__CYGWIN__))	/* @@@ */
 	if(LYscreen) {
@@ -1293,10 +1343,10 @@ PUBLIC BOOLEAN setup ARGS1(
     char *buffer = NULL;
     char *cp;
 
-   /*
-    *  If the display was not set by a command line option then
-    *  see if it is available from the environment .
-    */
+    /*
+     *  If the display was not set by a command line option then
+     *  see if it is available from the environment .
+     */
     if ((cp = LYgetXDisplay()) != NULL) {
 	StrAllocCopy(x_display, cp);
     } else {
@@ -1350,7 +1400,7 @@ PUBLIC BOOLEAN setup ARGS1(
      *  the current link is indistinguishable from all other links.
      *  The workaround here is to disable the 'rev' capability.
      */
-    if ((strncmp(ttytype, "sun", 3) == 0)) {
+    if ((strncmp((CONST char *)ttytype, "sun", 3) == 0)) {
 	LYnoVideo(2);
     }
 #endif /* HAVE_TTYTYPE */
@@ -2090,6 +2140,19 @@ PUBLIC void LYrefresh NOARGS
 {
 #ifdef USE_CURSES_PADS
     if (LYwin != stdscr) {
+	/*
+	 * Workaround for special case where lynx is prompting for a mailto,
+	 * and has a subject line that is wider than the screen.  The 
+	 * wnoutrefresh() call resets newscr's position to match stdscr's,
+	 * which happens to be the window's origin because we were not updating
+	 * that, and other stray wmove's in lynx fail because the coordinate
+	 * is on/after the right margin.  Force things to look ok here.
+	 */
+	int y, x;
+	getyx(LYwin, y, x);
+	if (x >= LYcols) x = LYcols-1;
+	wmove(stdscr, y, x);
+
 	wnoutrefresh(stdscr);
 	pnoutrefresh(LYwin, 0, LYshiftWin, 0, 0, LYlines, LYscreenWidth()-1);
 	doupdate();
@@ -2199,16 +2262,16 @@ PUBLIC void lynx_stop_link_color ARGS2(
 
 PUBLIC void lynx_stop_target_color NOARGS
 {
-   stop_underline();
-   stop_reverse();
-   stop_bold();
+    stop_underline();
+    stop_reverse();
+    stop_bold();
 }
 
 PUBLIC void lynx_start_target_color NOARGS
 {
-   start_bold();
-   start_reverse();
-   start_underline();
+    start_bold();
+    start_reverse();
+    start_underline();
 }
 
 
@@ -2234,41 +2297,41 @@ PUBLIC void lynx_stop_status_color NOARGS
 
 PUBLIC void lynx_start_h1_color NOARGS
 {
-   if (bold_H1 || bold_headers)
-     start_bold();
+    if (bold_H1 || bold_headers)
+	start_bold();
 }
 
 PUBLIC void lynx_stop_h1_color NOARGS
 {
-   if (bold_H1 || bold_headers)
-     stop_bold();
+    if (bold_H1 || bold_headers)
+	stop_bold();
 }
 
 PUBLIC void lynx_start_prompt_color NOARGS
 {
-   start_reverse ();
+    start_reverse ();
 }
 
 PUBLIC void lynx_stop_prompt_color NOARGS
 {
-   stop_reverse ();
+    stop_reverse ();
 }
 
 PUBLIC void lynx_start_radio_color NOARGS
 {
-   start_bold ();
+    start_bold ();
 }
 
 PUBLIC void lynx_stop_radio_color NOARGS
 {
-   stop_bold ();
+    stop_bold ();
 }
 
 PUBLIC void lynx_stop_all_colors NOARGS
 {
-   stop_underline ();
-   stop_reverse ();
-   stop_bold ();
+    stop_underline ();
+    stop_reverse ();
+    stop_bold ();
 }
 
 /*
diff --git a/src/LYCurses.h b/src/LYCurses.h
index c872758e..f4be459f 100644
--- a/src/LYCurses.h
+++ b/src/LYCurses.h
@@ -66,6 +66,14 @@ typedef struct {
 #define ACS_DARROW  SLSMG_DARROW_CHAR
 #endif
 
+#ifndef ACS_LARROW
+#define ACS_LARROW  SLSMG_LARROW_CHAR
+#endif
+
+#ifndef ACS_RARROW
+#define ACS_RARROW  SLSMG_RARROW_CHAR
+#endif
+
 #ifndef ACS_CKBOARD
 #define ACS_CKBOARD SLSMG_CKBRD_CHAR
 #endif
@@ -542,6 +550,7 @@ FANCY_CURSES.  Check your config.log to see why the FANCY_CURSES test failed.
 
 extern void lynx_enable_mouse PARAMS((int));
 extern void lynx_force_repaint NOPARAMS;
+extern void lynx_nl2crlf PARAMS((int normal));
 extern void lynx_start_title_color NOPARAMS;
 extern void lynx_stop_title_color NOPARAMS;
 extern void lynx_start_link_color PARAMS((int flag, int pending));
diff --git a/src/LYDownload.c b/src/LYDownload.c
index 839af32b..03a9ea5f 100644
--- a/src/LYDownload.c
+++ b/src/LYDownload.c
@@ -34,7 +34,7 @@ PUBLIC void LYDownload ARGS1(
     char buffer[LY_MAXPATH];
     char command[LY_MAXPATH];
     char *cp;
-    lynx_html_item_type *download_command = 0;
+    lynx_list_item_type *download_command = 0;
     int ch, recall;
     int FnameTotal;
     int FnameNum;
@@ -62,7 +62,7 @@ PUBLIC void LYDownload ARGS1(
     /*
      *	Parse out the File, sug_file, and the Method.
      */
-    if ((file = (char *)strstr(Line, "/File=")) == NULL)
+    if ((file = strstr(Line, "/File=")) == NULL)
 	goto failed;
     *file = '\0';
     /*
@@ -70,7 +70,7 @@ PUBLIC void LYDownload ARGS1(
      */
     file += 6;
 
-    if ((sug_file = (char *)strstr(file + 1, "/SugFile=")) != NULL) {
+    if ((sug_file = strstr(file + 1, "/SugFile=")) != NULL) {
 	*sug_file = '\0';
 	/*
 	 *  Go past "SugFile=".
@@ -110,7 +110,7 @@ PUBLIC void LYDownload ARGS1(
 #endif /* _WINDOWS */
 #endif /* DIRED_SUPPORT */
 
-    if ((method = (char *)strstr(Line, "Method=")) == NULL)
+    if ((method = strstr(Line, "Method=")) == NULL)
 	goto failed;
     /*
      *	Go past "Method=".
@@ -485,7 +485,7 @@ PUBLIC int LYdownload_options ARGS2(
     char *downloaded_url = NULL;
     char *sug_filename = NULL;
     FILE *fp0;
-    lynx_html_item_type *cur_download;
+    lynx_list_item_type *cur_download;
     int count;
 
     /*
@@ -495,10 +495,10 @@ PUBLIC int LYdownload_options ARGS2(
     change_sug_filename(sug_filename);
 
     if (LYReuseTempfiles) {
-	fp0 = LYOpenTempRewrite(tempfile, HTML_SUFFIX, "wb");
+	fp0 = LYOpenTempRewrite(tempfile, HTML_SUFFIX, BIN_W);
     } else {
 	LYRemoveTemp(tempfile);
-	fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "wb");
+	fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, BIN_W);
     }
     if (fp0 == NULL) {
 	HTAlert(CANNOT_OPEN_TEMP);
diff --git a/src/LYEdit.c b/src/LYEdit.c
index 37b182db..453cab0b 100644
--- a/src/LYEdit.c
+++ b/src/LYEdit.c
@@ -129,7 +129,7 @@ PUBLIC int edit_current_file ARGS3(
     /*
      *  Don't allow editing if user lacks append access.
      */
-    if ((fp = fopen(filename, "a")) == NULL)
+    if ((fp = fopen(filename, TXT_A)) == NULL)
     {
 	HTUserMsg(NOAUTH_TO_EDIT_FILE);
 	goto done;
diff --git a/src/LYExtern.c b/src/LYExtern.c
index 8cecb422..4f341bb7 100644
--- a/src/LYExtern.c
+++ b/src/LYExtern.c
@@ -24,9 +24,9 @@
 #include <LYExtern.h>
 #include <LYLeaks.h>
 #include <LYCurses.h>
+#include <LYReadCFG.h>
 #include <LYStrings.h>
 
-
 #ifdef WIN_EX
 /* 1997/10/15 (Wed) 17:39:50 */
 
@@ -126,254 +126,297 @@ PUBLIC char * quote_pathname ARGS1(
 }
 #endif /* WIN_EX */
 
-#if 0	/* old version */
-void run_external_ ARGS1(char *, cmd)
+
+PRIVATE void format ARGS3(
+    char **,	result,
+    char *,	fmt,
+    char *,	parm)
 {
-    char *the_command = 0;
-    lynx_html_item_type *ext = 0;
+    *result = NULL;
+    HTAddParam(result, fmt, 1, parm);
+    HTEndParam(result, fmt, 1);
+}
 
-    for (ext = externals; ext != NULL; ext = ext->next) {
+/*
+ * Format the given command into a buffer, returning the resulting string.
+ *
+ * It is too dangerous to leave any URL that may come along unquoted.  They
+ * often contain '&', ';', and '?' chars, and who knows what else may occur. 
+ * Prevent spoofing of the shell.  Dunno how this needs to be modified for VMS
+ * or DOS.  - kw
+ */
+PRIVATE char *format_command ARGS2(
+    char *,	command,
+    char *,	param)
+{
+#ifdef WIN_EX
+    char pram_string[PATH_MAX];
+#endif
+    char *cmdbuf = NULL;
 
-	if (ext->command != 0
-	&& !strncasecomp(ext->name, cmd, strlen(ext->name))) {
+#if (defined(VMS) || defined(DOSPATH) || defined(__EMX__)) && !defined(WIN_EX)
+    format(&cmdbuf, command, param);
+#else	/* Unix or DOS/Win: */
+#if defined(WIN_EX)
+    if (*param != '\"' && strchr(param, ' ') != NULL) {
+	char *cp = quote_pathname(param);
+	format(&cmdbuf, command, cp);
+	FREE(cp);
+    } else {
+	LYstrncpy(pram_string, param, sizeof(pram_string)-1);
+	decode_string(pram_string);
+	param = pram_string;
+
+	if (strnicmp("mailto:", param, 7) == 0) {
+	    format(&cmdbuf, command, param + 7);
+	} else if (strnicmp("telnet://", param, 9) == 0) {
+	    char host[sizeof(pram_string)];
+	    int last_pos;
+
+	    strcpy(host, param + 9);
+	    last_pos = strlen(host) - 1;
+	    if (last_pos > 1 && host[last_pos] == '/')
+		host[last_pos] = '\0';
+
+	    format(&cmdbuf, command, host);
+	} else if (strnicmp("file://localhost/", param, 17) == 0) {
+	    char e_buff[PATH_MAX], *p;
+
+	    p = param + 17;
+	    *e_buff = 0;
+	    if (strchr(p, ':') == NULL) {
+		sprintf(e_buff, "%.3s/", windows_drive);
+	    }
+	    strncat(e_buff, p, sizeof(e_buff) - strlen(e_buff) - 1);
+	    p = strrchr(e_buff, '.');
+	    if (p) {
+		p = strchr(p, '#');
+		if (p) {
+		    *p = '\0';
+		}
+	    }
+	    if (*e_buff != '\"' && strchr(e_buff, ' ') != NULL) {
+		p = quote_pathname(e_buff);
+		LYstrncpy(e_buff, p, sizeof(e_buff)-1);
+		FREE(p);
+	    }
 
-	    if (no_externals && !ext->always_enabled) {
-		HTUserMsg(EXTERNALS_DISABLED);
+	    /* Less ==> short filename,
+	     * less ==> long filename
+	     */
+	    if (isupper(command[0])) {
+		format(&cmdbuf,
+			command, HTDOS_short_name(e_buff));
 	    } else {
-
-		HTAddParam(&the_command, ext->command, 1, cmd);
-		HTEndParam(&the_command, ext->command, 1);
-
-		HTUserMsg(the_command);
-
-		stop_curses();
-		LYSystem(the_command);
-		FREE(the_command);
-		start_curses();
+		format(&cmdbuf, command, e_buff);
 	    }
-
-	    break;
+	} else {
+	    format(&cmdbuf, command, param);
 	}
     }
-
-    return;
-}
+#else	/* Unix */
+    {
+	format(&cmdbuf, command, param);
+    }
 #endif
+#endif	/* VMS */
+    return cmdbuf;
+}
 
-PRIVATE void format ARGS3(
-    char **,	result,
-    char *,	fmt,
-    char *,	parm)
+/*
+ * Find the EXTERNAL command which matches the given name 'param'.  If there is
+ * more than one possibility, make a popup menu of the matching commands and
+ * allow the user to select one.  Return the selected command.
+ */
+PRIVATE char *lookup_external ARGS2(
+    char *, 	param,
+    BOOL,	only_overriders)
 {
-    *result = NULL;
-    HTAddParam(result, fmt, 1, parm);
-    HTEndParam(result, fmt, 1);
+    int pass, num_disabled, num_matched, num_choices, cur_choice;
+    int length = 0;
+    char *cmdbuf = NULL;
+    char **choices = 0;
+    lynx_list_item_type *ptr = 0;
+
+    for (pass = 0; pass < 2; pass++) {
+	num_disabled = 0;
+	num_matched = 0;
+	num_choices = 0;
+	for (ptr = externals; ptr != 0; ptr = ptr->next) {
+
+	    if (match_item_by_name(ptr, param, only_overriders)) {
+		++num_matched;
+		CTRACE((tfp, "EXTERNAL: '%s' <==> '%s'\n", ptr->name, param));
+		if (no_externals && !ptr->always_enabled && !only_overriders) {
+		    ++num_disabled;
+		} else {
+		    if (pass == 0) {
+			length++;
+		    } else if (pass != 0) {
+			cmdbuf = format_command(ptr->command, param);
+			if (length > 1)
+			    choices[num_choices] = cmdbuf;
+		    }
+		    num_choices++;
+		}
+	    }
+	}
+	if (length > 1) {
+	    if (pass == 0) {
+		choices = typecallocn(char *, length + 1);
+	    } else {
+		choices[num_choices] = 0;
+	    }
+	}
+    }
+
+    if (num_disabled != 0
+     && num_disabled == num_matched) {
+	HTUserMsg(EXTERNALS_DISABLED);
+    } else if (num_choices > 1) {
+	int old_y, old_x;
+#ifdef USE_SLANG
+	old_y = SLsmg_get_row();
+	old_x = SLsmg_get_column();
+#else
+	getyx(LYwin, old_y, old_x);
+#endif
+	cur_choice = LYhandlePopupList(
+			-1,
+			0,
+			old_x,
+			(CONST char **)choices,
+			-1,
+			-1,
+			FALSE,
+			TRUE,
+			FALSE);
+#ifdef USE_SLANG
+	SLsmg_gotorc(old_y, old_x);
+#else
+	wmove(LYwin, old_y, old_x);
+#endif
+	CTRACE((tfp, "selected choice %d of %d\n", cur_choice, num_choices));
+	if (cur_choice < 0) {
+	    HTInfoMsg(CANCELLED);
+	    cmdbuf = 0;
+	}
+	for (pass = 0; choices[pass] != 0; pass++) {
+	    if (pass == cur_choice) {
+		cmdbuf = choices[pass];
+	    } else {
+		FREE(choices[pass]);
+	    }
+	}
+	FREE(choices);
+    }
+    return cmdbuf;
 }
 
 BOOL run_external ARGS2(
-    char *, 	c,
+    char *, 	param,
     BOOL,	only_overriders)
 {
 #ifdef WIN_EX
-    HANDLE handle;
     int status;
-    int confirmed;
-    char pram_string[PATH_MAX];
-    int redraw_flag;
     extern int xsystem(char *cmd);
 #endif
+    int redraw_flag = TRUE;
     char *cmdbuf = NULL;
-    lynx_html_item_type *externals2 = 0;
     int found = 0;
+    int confirmed = TRUE;
 
     if (externals == NULL)
 	return 0;
 
 #ifdef WIN_EX			/* 1998/01/26 (Mon) 09:16:13 */
-    if (c == NULL) {
+    if (param == NULL) {
 	HTInfoMsg("External command is null");
 	return 0;
     }
 #endif
 
-    for (externals2 = externals; externals2 != NULL;
-	 externals2 = externals2->next) {
-
-#ifdef WIN_EX
-	handle = GetForegroundWindow();
-	CTRACE((tfp, "EXTERNAL: '%s' <==> '%s'\n", externals2->name, c));
-#endif
-	if (externals2->command != 0
-	  && !strncasecomp(externals2->name, c, strlen(externals2->name))
-	  && (only_overriders ? externals2->override_primary_action : 1))
-	{
-	    if (no_externals && !externals2->always_enabled && !only_overriders) {
-		HTUserMsg(EXTERNALS_DISABLED);
-		break;
-	    }
-	    ++found;
-	    /*  Too dangerous to leave any URL that may come along unquoted.
-	     *  They often contain '&', ';', and '?' chars, and who knows
-	     *  what else may occur.
-	     *  Prevent spoofing of the shell.
-	     *  Dunno how this needs to be modified for VMS or DOS. - kw
-	     */
-#if (defined(VMS) || defined(DOSPATH) || defined(__EMX__)) && !defined(WIN_EX)
-	    format(&cmdbuf, externals2->command, c);
-#else	/* Unix or DOS/Win: */
-#if defined(WIN_EX)
-	    if (*c != '\"' && strchr(c, ' ') != NULL) {
-		char *cp = quote_pathname(c);
-		format(&cmdbuf, externals2->command, cp);
-		FREE(cp);
-	    } else {
-		LYstrncpy(pram_string, c, sizeof(pram_string)-1);
-		decode_string(pram_string);
-		c = pram_string;
-
-		if (strnicmp("mailto:", c, 7) == 0) {
-		    format(&cmdbuf, externals2->command, c + 7);
-		} else if (strnicmp("telnet://", c, 9) == 0) {
-		    char host[sizeof(pram_string)];
-		    int last_pos;
-
-		    strcpy(host, c + 9);
-		    last_pos = strlen(host) - 1;
-		    if (last_pos > 1 && host[last_pos] == '/')
-			host[last_pos] = '\0';
-
-		    format(&cmdbuf, externals2->command, host);
-		} else if (strnicmp("file://localhost/", c, 17) == 0) {
-		    char e_buff[PATH_MAX], *p;
-
-		    p = c + 17;
-		    *e_buff = 0;
-		    if (strchr(p, ':') == NULL) {
-			sprintf(e_buff, "%.3s/", windows_drive);
-		    }
-		    strncat(e_buff, p, sizeof(e_buff) - strlen(e_buff) - 1);
-		    p = strrchr(e_buff, '.');
-		    if (p) {
-			p = strchr(p, '#');
-			if (p) {
-			    *p = '\0';
-			}
-		    }
-		    if (*e_buff != '\"' && strchr(e_buff, ' ') != NULL) {
-			p = quote_pathname(e_buff);
-			LYstrncpy(e_buff, p, sizeof(e_buff)-1);
-			FREE(p);
-		    }
-
-		    /* Less ==> short filename,
-		     * less ==> long filename
-		     */
-		    if (isupper(externals2->command[0])) {
-			format(&cmdbuf,
-				externals2->command, HTDOS_short_name(e_buff));
-		    } else {
-			format(&cmdbuf, externals2->command, e_buff);
-		    }
-		} else {
-		    format(&cmdbuf, externals2->command, c);
-		}
-	    }
-#else	/* Unix */
-	    {
-		format(&cmdbuf, externals2->command, c);
-	    }
-#endif
-#endif	/* VMS */
-
-	    if (cmdbuf != 0 && *cmdbuf != '\0') {
+    cmdbuf = lookup_external(param, only_overriders);
+    if (cmdbuf != 0 && *cmdbuf != '\0') {
 #ifdef WIN_EX			/* 1997/10/17 (Fri) 14:07:50 */
-		int len;
-		char buff[PATH_MAX];
+	int len;
+	char buff[PATH_MAX];
 
-		CTRACE((tfp, "Lynx EXTERNAL: '%s'\n", cmdbuf));
+	CTRACE((tfp, "Lynx EXTERNAL: '%s'\n", cmdbuf));
 #ifdef WIN_GUI			/* 1997/11/06 (Thu) 14:17:15 */
-		confirmed = MessageBox(handle, cmdbuf,
-				  "Lynx (EXTERNAL COMMAND EXEC)",
-		       MB_ICONQUESTION | MB_SETFOREGROUND | MB_OKCANCEL)
-			    == IDCANCEL;
+	confirmed = MessageBox(GetForegroundWindow(), cmdbuf,
+			       "Lynx (EXTERNAL COMMAND EXEC)",
+			       MB_ICONQUESTION | MB_SETFOREGROUND | MB_OKCANCEL)
+		    != IDCANCEL;
 #else
-		confirmed = HTConfirm(string_short(cmdbuf, 40)) == NO;
+	confirmed = HTConfirm(string_short(cmdbuf, 40)) != NO;
 #endif
-		if (confirmed)
-		    break;
-
-		len = strlen(cmdbuf);
-		if (len > 255) {
-		    sprintf(buff, "Lynx: command line too long (%d > 255)", len);
+	if (confirmed) {
+	    len = strlen(cmdbuf);
+	    if (len > 255) {
+		sprintf(buff, "Lynx: command line too long (%d > 255)", len);
 #ifdef WIN_GUI			/* 1997/11/06 (Thu) 14:17:02 */
-		    MessageBox(handle, buff,
-			       "Lynx (EXTERNAL COMMAND EXEC)",
-			  MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK);
-		    SetConsoleTitle("Lynx for Win32");
+		MessageBox(GetForegroundWindow(), buff,
+			   "Lynx (EXTERNAL COMMAND EXEC)",
+			   MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK);
+		SetConsoleTitle("Lynx for Win32");
 #else
-		    HTConfirm(string_short(buff, 40));
+		HTConfirm(string_short(buff, 40));
 #endif
-		    break;
-		} else {
-		    SetConsoleTitle(cmdbuf);
-		}
-
-		if (strnicmp(cmdbuf, "start ", 6) == 0)
-		    redraw_flag = FALSE;
-		else
-		    redraw_flag = TRUE;
+		confirmed = FALSE;
+	    } else {
+		SetConsoleTitle(cmdbuf);
+	    }
+	}
 
-		if (redraw_flag) {
-		    stop_curses();
-		    fflush(stdout);
-		}
+	if (strnicmp(cmdbuf, "start ", 6) == 0)
+	    redraw_flag = FALSE;
+	else
+	    redraw_flag = TRUE;
 #else
-		HTUserMsg(cmdbuf);
-		stop_curses();
+	HTUserMsg(cmdbuf);
 #endif
+	found = TRUE;
+	if (confirmed) {
+	    if (redraw_flag) {
+		stop_curses();
+		fflush(stdout);
+	    }
 
-		/* command running. */
+	    /* command running. */
 #ifdef WIN_EX			/* 1997/10/17 (Fri) 14:07:50 */
 #ifdef __CYGWIN__
-		status = system(cmdbuf);
+	    status = system(cmdbuf);
 #else
-		status = xsystem(cmdbuf);
+	    status = xsystem(cmdbuf);
 #endif
-		if (status != 0) {
-		    sprintf(buff,
-			    "EXEC code = %04x (%2d, %2d)\r\n"
-			    "'%s'",
-			    status, (status / 256), (status & 0xff),
-			    cmdbuf);
+	    if (status != 0) {
+		sprintf(buff,
+			"EXEC code = %04x (%2d, %2d)\r\n"
+			"'%s'",
+			status, (status / 256), (status & 0xff),
+			cmdbuf);
 #ifdef SH_EX	/* WIN_GUI for ERROR only */
-		    MessageBox(handle, buff,
-			       "Lynx (EXTERNAL COMMAND EXEC)",
-			       MB_ICONSTOP | MB_SETFOREGROUND | MB_OK);
+		MessageBox(GetForegroundWindow(), buff,
+			   "Lynx (EXTERNAL COMMAND EXEC)",
+			   MB_ICONSTOP | MB_SETFOREGROUND | MB_OK);
 #else
-		    HTConfirm(string_short(buff, 40));
-#endif		/* 1 */
-		}
+		HTConfirm(string_short(buff, 40));
+#endif /* 1 */
+	    }
 #else	/* Not WIN_EX */
-		LYSystem(cmdbuf);
+	    LYSystem(cmdbuf);
 #endif	/* WIN_EX */
 
 #if defined(WIN_EX)
-		SetConsoleTitle("Lynx for Win32");
+	    SetConsoleTitle("Lynx for Win32");
 #endif
-
-#ifdef WIN_EX
-		if (redraw_flag) {
-		    fflush(stdout);
-		    start_curses();
-		}
-#else
+	    if (redraw_flag) {
 		fflush(stdout);
 		start_curses();
-#endif
 	    }
-	    break;
-	} /* end if */
-    } /* end-for */
+	}
+    }
 
     FREE(cmdbuf);
     return found;
diff --git a/src/LYForms.c b/src/LYForms.c
index cc5ccf1e..cdf84fc6 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -232,9 +232,9 @@ PUBLIC int change_form_link_ex ARGS8(
 	    if (form->disabled == YES &&
 		(c == '\r' || c == '\n' || immediate_submit)) {
 		if (peek_mouse_link() >= 0)
-		    c = lookup_keymap(LYK_ACTIVATE);
+		    c = LAC_TO_LKC0(LYK_ACTIVATE);
 		else
-		c = '\t';
+		    c = '\t';
 		break;
 	    }
 	    /*
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 3f754c7c..c7cdd705 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -15,7 +15,7 @@
    be removed (at least):
    CURRENT_KEYMAP_HELP
 */
-#ifdef HAVE_CONFIG_H
+#if defined(HAVE_CONFIG_H) && defined(HAVE_LYHELP_H)
 #include <LYHelp.h>
 #else
 #define ALT_EDIT_HELP		"keystrokes/alt_edit_help.html"
@@ -446,10 +446,10 @@ extern BOOLEAN with_backspaces;
 #endif
 
 #ifndef NO_LYNX_TRACE
-extern BOOLEAN LYUseTraceLog;		/* Use a TRACE log?		 */
 extern FILE *LYTraceLogFP;		/* Pointer for TRACE log	 */
 extern char *LYTraceLogPath;		/* Path for TRACE log		 */
 #endif
+extern BOOLEAN LYUseTraceLog;		/* Use a TRACE log?		 */
 
 extern BOOL force_empty_hrefless_a;
 extern int connect_timeout;
diff --git a/src/LYHash.h b/src/LYHash.h
index b6453fc8..72039a04 100644
--- a/src/LYHash.h
+++ b/src/LYHash.h
@@ -41,6 +41,7 @@ extern int	s_aedit_sel;
 extern int	s_alert;
 extern int	s_alink;
 extern int	s_curedit;
+extern int	s_forw_backw;
 extern int	s_normal;
 extern int	s_prompt_edit;
 extern int	s_prompt_edit_arr;
diff --git a/src/LYHistory.c b/src/LYHistory.c
index 31d39c92..26ac340b 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -38,7 +38,7 @@ PRIVATE VisitedLink *Latest_tree;
 PRIVATE VisitedLink *First_tree;
 PRIVATE VisitedLink *Last_by_first;
 
-PRIVATE int nhist_extra;
+int nhist_extra;
 
 #ifdef LY_FIND_LEAKS
 /*
diff --git a/src/LYHistory.h b/src/LYHistory.h
index fecb67f9..5d061a24 100644
--- a/src/LYHistory.h
+++ b/src/LYHistory.h
@@ -20,4 +20,6 @@ extern void LYstatusline_messages_on_exit PARAMS((char **buf));
 extern void LYstore_message PARAMS((CONST char *message));
 extern void LYstore_message2 PARAMS((CONST char *message, CONST char *argument));
 
+extern int nhist_extra;
+
 #endif /* LYHISTORY_H */
diff --git a/src/LYJump.c b/src/LYJump.c
index b198f3df..6f426153 100644
--- a/src/LYJump.c
+++ b/src/LYJump.c
@@ -378,7 +378,7 @@ PRIVATE unsigned LYRead_Jumpfile ARGS1(struct JumpTable *,jtp)
     }
 
     /* allocate storage to read entire file */
-    if ((mp=(char *)calloc(1, st.st_size + 1)) == NULL) {
+    if ((mp= typecallocn(char, st.st_size + 1)) == NULL) {
 	HTAlert(OUTOF_MEM_FOR_JUMP_FILE);
 	return 0;
     }
@@ -387,7 +387,7 @@ PRIVATE unsigned LYRead_Jumpfile ARGS1(struct JumpTable *,jtp)
     if (st.st_fab_rfm != (char)FAB$C_STMLF) {
 	/** It's a record-oriented file. **/
 	IsStream_LF = FALSE;
-	if ((fp = fopen(jtp->file, "r", "mbc=32")) == NULL) {
+	if ((fp = fopen(jtp->file, TXT_R, "mbc=32")) == NULL) {
 	    HTAlert(CANNOT_OPEN_JUMP_FILE);
 	    FREE(mp);
 	    return 0;
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 75549f98..8f20e7e3 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -104,7 +104,7 @@ LYK_LAST_LINK,          0,              0,          LYK_HISTORICAL,
 LYK_UP_HALF,      LYK_DOWN_HALF, LYK_IMAGE_TOGGLE,  LYK_NEXT_PAGE,
 /* ( */              /* ) */         /* * */        /* + */
 
-LYK_NEXT_PAGE,    LYK_PREV_PAGE, LYK_EXTERN,        LYK_WHEREIS,
+LYK_EXTERN_PAGE,  LYK_PREV_PAGE, LYK_EXTERN_LINK,   LYK_WHEREIS,
 /* , */              /* - */         /* . */        /* / */
 
 LYK_F_LINK_NUM,      LYK_1,          LYK_2,         LYK_3,
@@ -898,8 +898,11 @@ PRIVATE Kcmd revmap[] = {
 #endif
 #ifdef USE_EXTERNALS
     DATA(
-	LYK_EXTERN, "EXTERN",
-	"run external program with url" ),
+	LYK_EXTERN_LINK, "EXTERN_LINK",
+	"run external program with current link" ),
+    DATA(
+	LYK_EXTERN_PAGE, "EXTERN_PAGE",
+	"run external program with current page" ),
 #endif
 #ifdef VMS
     DATA(
@@ -1319,7 +1322,7 @@ PUBLIC int lacname_to_lac ARGS1(
 {
        Kcmd *mp = LYStringToKcmd(func);
 
-       return (mp != 0) ? mp->code : -1;
+       return (mp != 0) ? (int) mp->code : -1;
 }
 
 /*
@@ -1488,7 +1491,7 @@ PUBLIC int remap ARGS3(
 	else
 #endif
 	    keymap[c+1] = mp->code;
-	return (c ? c : LAC_TO_LKC0(mp->code)); /* don't return 0, successful */
+	return (c ? c : (int) LAC_TO_LKC0(mp->code)); /* don't return 0, successful */
     }
     return 0;
 }
@@ -1614,19 +1617,6 @@ PUBLIC void reset_numbers_as_arrows NOARGS
     did_number_keys = FALSE;
 }
 
-PUBLIC int lookup_keymap ARGS1(
-	int,	func)
-{
-    size_t i;
-
-    for (i = 1; i < KEYMAP_SIZE; i++) {
-	if (LYisNonAlnumKeyname(i, func)) {
-	    return i;
-	}
-    }
-    return -1;
-}
-
 PUBLIC char *key_for_func ARGS1 (
 	int,	func)
 {
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index 8d783f7f..166df535 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -16,7 +16,6 @@ extern int LYStringToKeycode PARAMS((char *src));
 extern int lacname_to_lac PARAMS((CONST char *func));
 extern int lecname_to_lec PARAMS((CONST char *func));
 extern int lkcstring_to_lkc PARAMS((CONST char *src));
-extern int lookup_keymap PARAMS((int code));
 extern int remap PARAMS((char *key, char *func, BOOLEAN for_dired));
 extern void print_keymap PARAMS((char **newfile));
 extern void reset_emacs_keys NOPARAMS;
@@ -213,9 +212,11 @@ typedef enum {
 #endif
 
 #ifdef USE_EXTERNALS
-  , LYK_EXTERN
+  , LYK_EXTERN_LINK
+  , LYK_EXTERN_PAGE
 #else
-#define LYK_EXTERN        LYK_UNKNOWN
+#define LYK_EXTERN_LINK   LYK_UNKNOWN
+#define LYK_EXTERN_PAGE   LYK_UNKNOWN
 #endif /* !defined(USE_EXTERNALS) */
 
 #if defined(VMS) || defined(DIRED_SUPPORT)
diff --git a/src/LYLeaks.c b/src/LYLeaks.c
index 87a11666..6f188ebe 100644
--- a/src/LYLeaks.c
+++ b/src/LYLeaks.c
@@ -209,8 +209,7 @@ PUBLIC void *LYLeakMalloc ARGS3(
 	 *  Further allocate memory to store the information.
 	 *  Just return on failure to allocate more.
 	 */
-	AllocationList *ALp_new =
-			(AllocationList *)calloc(1, sizeof(AllocationList));
+	AllocationList *ALp_new = typecalloc(AllocationList);
 
 	if (ALp_new == NULL) {
 	    return(vp_malloc);
@@ -242,7 +241,7 @@ PUBLIC void *LYLeakMalloc ARGS3(
 **  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
+**		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.
@@ -256,7 +255,7 @@ PUBLIC void *LYLeakMalloc ARGS3(
 */
 PUBLIC AllocationList *LYLeak_mark_malloced ARGS4(
 	void *,		vp_malloced,
-	size_t, 	st_bytes,
+	size_t,		st_bytes,
 	CONST char *,	cp_File,
 	CONST short,	ssi_Line)
 {
@@ -276,12 +275,12 @@ PUBLIC AllocationList *LYLeak_mark_malloced ARGS4(
 	    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));
+	ALp_new = typecalloc(AllocationList);
 
 	if (ALp_new == NULL) {
 	    return(NULL);
@@ -338,8 +337,7 @@ PUBLIC void *LYLeakCalloc ARGS4(
 	 *  Allocate memory for the item to be in the list.
 	 *  If unable, just return.
 	 */
-	AllocationList *ALp_new =
-			(AllocationList *)calloc(1, sizeof(AllocationList));
+	AllocationList *ALp_new = typecalloc(AllocationList);
 
 	if (ALp_new == NULL) {
 		return(vp_calloc);
@@ -413,9 +411,7 @@ PUBLIC void *LYLeakRealloc ARGS4(
 	 *  Track the invalid pointer value and then exit.
 	 *  If unable to allocate, just exit.
 	 */
-	auto AllocationList *ALp_new =
-			     (AllocationList *)calloc(1,
-						      sizeof(AllocationList));
+	auto AllocationList *ALp_new = typecalloc(AllocationList);
 
 	if (ALp_new == NULL) {
 	    exit(EXIT_FAILURE);
@@ -463,15 +459,15 @@ PUBLIC void *LYLeakRealloc ARGS4(
 **		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
+**  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.
+**		cp_File		The file to record.
 **		ssi_Line	The line to record.
-**  Return Value:	      	Pointer to new or updated list entry
+**  Return Value:		Pointer to new or updated list entry
 **				for this memory block.
 **				NULL on allocation error.
 **  Revision History:
@@ -480,8 +476,8 @@ PUBLIC void *LYLeakRealloc ARGS4(
 #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,
+	void *,		vp_realloced,
+	size_t,		st_newBytes,
 	CONST char *,	cp_File,
 	CONST short,	ssi_Line)
 {
@@ -546,9 +542,7 @@ PUBLIC void LYLeakFree ARGS3(
 	 *  Create the final entry before exiting marking this error.
 	 *  If unable to allocate more memory just exit.
 	 */
-	AllocationList *ALp_new =
-			(AllocationList *)calloc(1,
-						 sizeof(AllocationList));
+	AllocationList *ALp_new = typecalloc(AllocationList);
 
 	if (ALp_new == NULL) {
 	    exit(EXIT_FAILURE);
@@ -701,7 +695,7 @@ PRIVATE char * LYLeakSAVsprintf ARGS6(
 {
     AllocationList *ALp_old;
     void *vp_oldAlloced;
-    
+
     CONST char * old_cp_File = __FILE__;
     short old_ssi_Line = __LINE__;
 
@@ -721,9 +715,7 @@ PRIVATE char * LYLeakSAVsprintf ARGS6(
 	     *  Track the invalid pointer value and then exit.
 	     *  If unable to allocate, just exit.
 	     */
-	    auto AllocationList *ALp_new =
-		(AllocationList *)calloc(1,
-					 sizeof(AllocationList));
+	    auto AllocationList *ALp_new = typecalloc(AllocationList);
 
 	    if (ALp_new == NULL) {
 		exit(EXIT_FAILURE);
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 175c8ef9..ae5e5701 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -69,7 +69,7 @@
 
 PRIVATE int LYExecv PARAMS((
 	char *		path,
-	char ** 	argv,
+	char **		argv,
 	char *		msg));
 
 #ifdef DIRED_SUPPORT
@@ -91,7 +91,7 @@ PRIVATE char *get_filename PARAMS((
 PRIVATE BOOLEAN permit_location PARAMS((
 	char *		destpath,
 	char *		srcpath,
-	char ** 	newpath));
+	char **		newpath));
 #endif /* OK_PERMIT */
 
 PRIVATE char *render_item PARAMS((
@@ -100,7 +100,7 @@ PRIVATE char *render_item PARAMS((
 	CONST char *	dir,
 	char *		buf,
 	int		bufsize,
-	BOOLEAN 	url_syntax));
+	BOOLEAN		url_syntax));
 
 PRIVATE struct dired_menu *menu_head = NULL;
 struct dired_menu {
@@ -240,7 +240,7 @@ struct dired_menu {
 
 #ifdef OK_GZIP
 { DE_FILE,	      "", "Compress",
-	  "(using gzip)", "LYNXDIRED://GZIP%p", 		NULL },
+	  "(using gzip)", "LYNXDIRED://GZIP%p",			NULL },
 #endif /* OK_GZIP */
 
 #ifdef OK_ZIP
@@ -263,7 +263,7 @@ struct dired_menu {
 		      "", "LYNXDIRED://CLEAR_TAGGED",		NULL },
 
 { 0,		    NULL, NULL,
-		    NULL, NULL, 				NULL }
+		    NULL, NULL,					NULL }
 };
 
 PRIVATE BOOLEAN cannot_stat ARGS1(CONST char *, name)
@@ -451,7 +451,7 @@ PRIVATE BOOLEAN remove_tagged NOARGS
  *   uid with Lynx & dired can do the same thing.
  */
 PRIVATE BOOLEAN modify_tagged ARGS1(
-	char *, 	testpath)
+	char *,		testpath)
 {
     char *cp;
     dev_t dev;
@@ -607,7 +607,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
  *  Modify the name of the specified item.
  */
 PRIVATE BOOLEAN modify_name ARGS1(
-	char *, 	testpath)
+	char *,		testpath)
 {
     char *cp;
     char tmpbuf[DIRED_MAXBUF];
@@ -662,7 +662,7 @@ PRIVATE BOOLEAN modify_name ARGS1(
  *  Change the location of a file or directory.
  */
 PRIVATE BOOLEAN modify_location ARGS1(
-	char *, 	testpath)
+	char *,		testpath)
 {
     char *cp;
     dev_t dev;
@@ -822,7 +822,7 @@ PUBLIC BOOLEAN local_modify ARGS2(
  *  Create a new empty file in the current directory.
  */
 PRIVATE BOOLEAN create_file ARGS1(
-	char *, 	current_location)
+	char *,		current_location)
 {
     int code = FALSE;
     char tmpbuf[DIRED_MAXBUF];
@@ -871,7 +871,7 @@ PRIVATE BOOLEAN create_file ARGS1(
  *  Create a new directory in the current directory.
  */
 PRIVATE BOOLEAN create_directory ARGS1(
-	char *, 	current_location)
+	char *,		current_location)
 {
     int code = FALSE;
     char tmpbuf[DIRED_MAXBUF];
@@ -947,7 +947,7 @@ PUBLIC BOOLEAN local_create ARGS1(
  *  Remove a single file or directory.
  */
 PRIVATE BOOLEAN remove_single ARGS1(
-	char *, 	testpath)
+	char *,		testpath)
 {
     int code = 0;
     char *cp;
@@ -1079,8 +1079,8 @@ PRIVATE char LYValidPermitFile[LY_MAXPATH] = "\0";
  *  Handle DIRED permissions.
  */
 PRIVATE BOOLEAN permit_location ARGS3(
-	char *, 	destpath,
-	char *, 	srcpath,
+	char *,		destpath,
+	char *,		srcpath,
 	char **,	newpath)
 {
 #ifndef UNIX
@@ -1479,7 +1479,7 @@ PUBLIC int local_dired ARGS1(
     StrAllocCopy(line, line_url);
     HTUnEscape(line);	/* _file_ (not URL) syntax, for those functions
 			   that need it.  Don't forget to FREE it. */
-    if ((arg = match_op("CHDIR", line)) != 0) {    
+    if ((arg = match_op("CHDIR", line)) != 0) {
 #ifdef SUPPORT_CHDIR
 	handle_LYK_CHDIR();
 	do_pop_doc = FALSE;
@@ -1717,7 +1717,7 @@ PUBLIC int dired_options ARGS2(
     static char tempfile[LY_MAXPATH];
     char *path;
     char *dir;
-    lynx_html_item_type *nxt;
+    lynx_list_item_type *nxt;
     struct stat dir_info;
     FILE *fp0;
     char *dir_url;
@@ -1870,9 +1870,9 @@ PUBLIC int dired_options ARGS2(
  *  Check DIRED filename.
  */
 PRIVATE char *get_filename ARGS3(
-	char *, 	prompt,
-	char *, 	buf,
-	size_t, 	bufsize)
+	char *,		prompt,
+	char *,		buf,
+	size_t,		bufsize)
 {
     char *cp;
 
@@ -1904,7 +1904,7 @@ PRIVATE char *get_filename ARGS3(
 #define LYEXECV_MAX_ARGC 15
 /* these are quasi-constant once they have been allocated: */
 static char ** install_argp = NULL;	/* args for execv install */
-static char * install_path = NULL; 	/* auxiliary */
+static char * install_path = NULL;	/* auxiliary */
 #ifdef LY_FIND_LEAKS
 PRIVATE void clear_install_path NOARGS
 {
@@ -1936,7 +1936,7 @@ PRIVATE int fill_argv_for_execv ARGS5(
     char **args;
     char *cp;
     if (*argvp == NULL) {
-	*argvp = (char **)calloc(LYEXECV_MAX_ARGC+1, sizeof(char *));
+	*argvp = typecallocn(char *, LYEXECV_MAX_ARGC+1);
 	if (!*argvp)
 	    return(-1);
 #ifdef LY_FIND_LEAKS
@@ -1969,8 +1969,8 @@ PRIVATE int fill_argv_for_execv ARGS5(
  *  Install the specified file or directory.
  */
 PUBLIC BOOLEAN local_install ARGS3(
-	char *, 	destpath,
-	char *, 	srcpath,
+	char *,		destpath,
+	char *,		srcpath,
 	char **,	newpath)
 {
     char *tmpbuf = NULL;
@@ -2159,7 +2159,7 @@ PUBLIC void clear_tags NOARGS
  *  Handle DIRED menu item.
  */
 PUBLIC void add_menu_item ARGS1(
-	char *, 	str)
+	char *,		str)
 {
     struct dired_menu *new, *mp;
     char *cp;
@@ -2171,7 +2171,7 @@ PUBLIC void add_menu_item ARGS1(
     if (menu_head == defmenu)
 	menu_head = NULL;
 
-    new = (struct dired_menu *)calloc(1, sizeof(*new));
+    new = typecalloc(struct dired_menu);
     if (new == NULL)
 	outofmem(__FILE__, "add_menu_item");
 
@@ -2240,10 +2240,10 @@ PUBLIC void reset_dired_menu NOARGS
  *  Create URL for DIRED HREF value.
  */
 PRIVATE char * render_item ARGS6(
-	CONST char *, 	s,
-	CONST char *, 	path,
-	CONST char *, 	dir,
-	char *, 	buf,
+	CONST char *,	s,
+	CONST char *,	path,
+	CONST char *,	dir,
+	char *,		buf,
 	int,		bufsize,
 	BOOLEAN,	url_syntax)
 {
@@ -2338,18 +2338,18 @@ PRIVATE char * render_item ARGS6(
  *  Execute DIRED command, return -1 or 0 on failure, 1 success.
  */
 PRIVATE int LYExecv ARGS3(
-	char *, 	path,
+	char *,		path,
 	char **,	argv,
-	char *, 	msg)
+	char *,		msg)
 {
+    int rc = 0;
 #if defined(VMS)
     CTRACE((tfp, "LYExecv:  Called inappropriately!\n"));
-    return(0);
 #else
 #if defined(_WINDOWS)
     if (!strcmp(path, TOUCH_PATH)) {
-#if defined(__BORLANDC__) || defined(__MINGW32__) 
-	int fd = _creat(argv[1], S_IREAD | S_IWRITE); 
+#if defined(__BORLANDC__) || defined(__MINGW32__)
+	int fd = _creat(argv[1], S_IREAD | S_IWRITE);
 #else /* Visual C++ */
 	int fd = _creat(argv[1], _S_IREAD | _S_IWRITE);
 #endif
@@ -2358,12 +2358,11 @@ PRIVATE int LYExecv ARGS3(
 	    return(1);
 	}
     } else if (!strcmp(path, RM_PATH)) {
-	return remove(argv[2]);
+	rc = remove(argv[2]);
+    } else {
+	CTRACE((tfp, "LYExecv:  Called inappropriately! (path=%s)\n", path));
     }
-    CTRACE((tfp, "LYExecv:  Called inappropriately! (path=%s)\n", path));
-    return(0);
 #else
-    int rc;
     int n;
     char *tmpbuf = 0;
 #ifdef __DJGPP__
@@ -2390,11 +2389,13 @@ PRIVATE int LYExecv ARGS3(
     rc = 1;		/* It will work */
     stop_curses();
     pid = fork();	/* fork and execute command */
+
     switch (pid) {
 	case -1:
 	    HTSprintf0(&tmpbuf, gettext("Unable to %s due to system error!"), msg);
 	    rc = 0;
 	    break;	/* don't fall thru! - KW */
+
 	case 0:  /* child */
 #ifdef USE_EXECVP
 	    execvp(path, argv);	/* this uses our $PATH */
@@ -2402,6 +2403,8 @@ PRIVATE int LYExecv ARGS3(
 	    execv(path, argv);
 #endif
 	    exit(EXIT_FAILURE);	/* execv failed, give wait() something to look at */
+	    /*NOTREACHED*/
+
 	default:  /* parent */
 #if !HAVE_WAITPID
 	    while (wait(&wstatus) != pid)
@@ -2442,7 +2445,7 @@ PRIVATE int LYExecv ARGS3(
 	FREE(tmpbuf);
     }
 
-    return(rc);
 #endif /* _WINDOWS */
 #endif /* VMS */
+    return(rc);
 }
diff --git a/src/LYMain.c b/src/LYMain.c
index 371bc591..bf63a8ed 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -146,15 +146,15 @@ PUBLIC char *empty_string = "\0";
 PUBLIC int display_lines;  /* number of lines in display */
 PUBLIC int www_search_result= -1;
 			       /* linked list of printers */
-PUBLIC lynx_printer_item_type *printers = NULL;
+PUBLIC lynx_list_item_type *printers = NULL;
 			    /* linked list of download options */
-PUBLIC lynx_html_item_type *downloaders = NULL;
+PUBLIC lynx_list_item_type *downloaders = NULL;
 			    /* linked list of upload options */
 #ifdef USE_EXTERNALS
-PUBLIC lynx_html_item_type *externals = NULL;
+PUBLIC lynx_list_item_type *externals = NULL;
 			    /* linked list of external options */
 #endif
-PUBLIC lynx_html_item_type *uploaders = NULL;
+PUBLIC lynx_list_item_type *uploaders = NULL;
 PUBLIC int port_syntax = 1;
 PUBLIC int LYShowColor = SHOW_COLOR_UNKNOWN; /* to show or not to show */
 PUBLIC int LYChosenShowColor = SHOW_COLOR_UNKNOWN; /* whether to show and save */
@@ -436,18 +436,22 @@ BOOLEAN persistent_cookies = FALSE;	/* disabled by default! */
 PUBLIC char *LYCookieFile = NULL;	/* cookie read file */
 PUBLIC char *LYCookieSaveFile = NULL;	/* cookie save file */
 #endif /* EXP_PERSISTENT_COOKIES */
+
 PUBLIC int LYTransferRate = rateEtaKB_maybe;
 PUBLIC char *XLoadImageCommand = NULL;	/* Default image viewer for X */
 PUBLIC BOOLEAN LYNoISMAPifUSEMAP = FALSE; /* Omit ISMAP link if MAP present? */
 PUBLIC int LYHiddenLinks = HIDDENLINKS_SEPARATE; /* Show hidden links? */
 
 PUBLIC BOOL Old_DTD = NO;
+
+#ifndef NO_LYNX_TRACE
 PUBLIC FILE *LYTraceLogFP = NULL;		/* Pointer for TRACE log  */
+#endif
 PUBLIC char *LYTraceLogPath = NULL;		/* Path for TRACE log	   */
 PUBLIC BOOLEAN LYUseTraceLog = USE_TRACE_LOG;	/* Use a TRACE log?	   */
+
 PUBLIC BOOLEAN LYSeekFragMAPinCur = TRUE;
 PUBLIC BOOLEAN LYSeekFragAREAinCur = TRUE;
-
 PUBLIC BOOLEAN LYStripDotDotURLs = TRUE;	/* Try to fix ../ in some URLs? */
 PUBLIC BOOLEAN LYForceSSLCookiesSecure = FALSE;
 PUBLIC BOOLEAN LYNoCc = FALSE;
@@ -2139,7 +2143,7 @@ PUBLIC void reload_read_cfg NOARGS
      *  no_option_save restriction may thus be unnecessarily restrictive,
      *  but the check is currently still left in place. - kw
      */
-    tempfile = calloc(1, LY_MAXPATH);
+    tempfile = typecallocn(char, LY_MAXPATH);
     if (!tempfile) {
 	HTAlwaysAlert(NULL, NOT_ENOUGH_MEMORY);
 	return;
@@ -2196,7 +2200,7 @@ PUBLIC void reload_read_cfg NOARGS
 	/*
 	 *  Process the temporary RC file.
 	 */
-	rcfp = fopen(tempfile, "r");
+	rcfp = fopen(tempfile, TXT_R);
 	read_rc(rcfp);
 	LYRemoveTemp(tempfile);
 	FREE(tempfile);		/* done with it - kw */
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 434d804d..fd5ae994 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -2683,7 +2683,7 @@ PRIVATE int handle_LYK_ELGOTO ARGS5(
 }
 
 #ifdef USE_EXTERNALS
-PRIVATE void handle_LYK_EXTERN ARGS1(
+PRIVATE void handle_LYK_EXTERN_LINK ARGS1(
     BOOLEAN *,	refresh_screen)
 {
     if ((nlinks > 0) && (links[curdoc.link].lname != NULL))
@@ -2692,6 +2692,16 @@ PRIVATE void handle_LYK_EXTERN ARGS1(
 	*refresh_screen = TRUE;
     }
 }
+
+PRIVATE void handle_LYK_EXTERN_PAGE ARGS1(
+    BOOLEAN *,	refresh_screen)
+{
+    if (curdoc.address != NULL)
+    {
+	run_external(curdoc.address, FALSE);
+	*refresh_screen = TRUE;
+    }
+}
 #endif
 
 PRIVATE BOOLEAN handle_LYK_FASTBACKW_LINK ARGS3(
@@ -7300,8 +7310,11 @@ new_cmd:  /*
 #endif /* DIRED_SUPPORT || VMS*/
 
 #ifdef USE_EXTERNALS
-	case LYK_EXTERN:	/* use external program on url */
-	    handle_LYK_EXTERN(&refresh_screen);
+	case LYK_EXTERN_LINK:	/* use external program on url */
+	    handle_LYK_EXTERN_LINK(&refresh_screen);
+	    break;
+	case LYK_EXTERN_PAGE:	/* use external program on current page */
+	    handle_LYK_EXTERN_PAGE(&refresh_screen);
 	    break;
 #endif /* USE_EXTERNALS */
 
diff --git a/src/LYNews.c b/src/LYNews.c
index c9b13506..72309078 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -35,7 +35,7 @@ PRIVATE BOOLEAN message_has_content ARGS2(
 
     *nonspaces = FALSE;
 
-    if (!filename || (fp = fopen(filename, "r")) == NULL) {
+    if (!filename || (fp = fopen(filename, TXT_R)) == NULL) {
 	CTRACE((tfp, "Failed to open file %s for reading!\n",
 	       NONNULL(filename)));
 	return FALSE;
@@ -136,7 +136,7 @@ PUBLIC char *LYNewsPost ARGS2(
      *  and message body. - FM
      */
 #ifdef __DJGPP__
-    if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, "wb")) == NULL)
+    if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, BIN_W)) == NULL)
 #else
     if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, "w")) == NULL)
 #endif /* __DJGPP__ */
@@ -240,11 +240,11 @@ PUBLIC char *LYNewsPost ARGS2(
 	    CJKinput[0] = '\0';
 	    switch(kanji_code) {
 	    case EUC:
-		TO_EUC((CONST unsigned char *)kp, CJKinput);
+		TO_EUC((CONST unsigned char *)kp, (unsigned char *)CJKinput);
 		kp = CJKinput;
 		break;
 	    case SJIS:
-		TO_SJIS((CONST unsigned char *)kp, CJKinput);
+		TO_SJIS((CONST unsigned char *)kp, (unsigned char *)CJKinput);
 		kp = CJKinput;
 		break;
 	    default:
@@ -280,7 +280,7 @@ PUBLIC char *LYNewsPost ARGS2(
 	StrAllocCat(cp, org);
     }
 #ifdef UNIX
-    else if ((fp = fopen("/etc/organization", "r")) != NULL) {
+    else if ((fp = fopen("/etc/organization", TXT_R)) != NULL) {
 	char *buffer = 0;
 	if (LYSafeGets(&buffer, fp) != NULL) {
 	    if ((org = strchr(buffer, '\n')) != NULL) {
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 0ef88dec..230d380c 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -2438,7 +2438,7 @@ PRIVATE PostPair * break_data ARGS1(
 
     CTRACE((tfp, "break_data %s\n", data));
 
-    q = calloc(sizeof(PostPair), 1);
+    q = typecalloc(PostPair);
     if (q==NULL)
 	outofmem(__FILE__, "break_data(calloc)");
 
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 6a95f962..12bf6605 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -805,7 +805,7 @@ PRIVATE void send_file_to_printer ARGS4(
     char my_file[LY_MAXPATH];
     char my_temp[LY_MAXPATH];
     int FnameTotal, FnameNum = -1;
-    lynx_printer_item_type *cur_printer;
+    lynx_list_item_type *cur_printer;
 
     outfile_fp = LYOpenTemp(my_temp,
 			    (HTisDocumentSource())
@@ -1115,7 +1115,7 @@ PUBLIC int printfile ARGS1(
     /*
      *	Get the number of lines in the file.
      */
-    if ((cp = (char *)strstr(link_info, "lines=")) != NULL) {
+    if ((cp = strstr(link_info, "lines=")) != NULL) {
 	/*
 	 *  Terminate prev string here.
 	 */
@@ -1143,12 +1143,12 @@ PUBLIC int printfile ARGS1(
     } else if (strstr(link_info, "PRINTER")) {
 	type = PRINTER;
 
-	if ((cp = (char *)strstr(link_info, "number=")) != NULL) {
+	if ((cp = strstr(link_info, "number=")) != NULL) {
 	    /* number of characters in "number=" */
 	    cp += 7;
 	    printer_number = atoi(cp);
 	}
-	if ((cp = (char *)strstr(link_info, "pagelen=")) != NULL) {
+	if ((cp = strstr(link_info, "pagelen=")) != NULL) {
 	    /* number of characters in "pagelen=" */
 	    cp += 8;
 	    pagelen = atoi(cp);
@@ -1271,7 +1271,7 @@ PUBLIC int print_options ARGS3(
     int count;
     int pages;
     FILE *fp0;
-    lynx_printer_item_type *cur_printer;
+    lynx_list_item_type *cur_printer;
 
     if (LYReuseTempfiles) {
 	fp0 = LYOpenTempRewrite(my_temp, HTML_SUFFIX, "w");
@@ -1464,7 +1464,7 @@ check_recall:
      *   "invalid pointer" reported in the Lynx.leaks file (if compiled
      *   with  --enable-find-leaks  turned on.  Dumb.]
      */
-    if ((fn = (char *) calloc (1, (strlen (tbuf) + 1))) == NULL)
+    if ((fn = typecallocn(char, strlen (tbuf) + 1)) == NULL)
 	outofmem(__FILE__, "GetFileName");
     return (strcpy (fn, tbuf));
 
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 1369a8df..5ba10be4 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -78,15 +78,12 @@ PRIVATE char *find_colon ARGS1(
     return NULL;
 }
 
-/*
- *  Function for freeing the DOWNLOADER and UPLOADER menus list. - FM
- */
-PRIVATE void free_item_list NOARGS
+PRIVATE void free_item_list ARGS1(
+    lynx_list_item_type **,	ptr)
 {
-    lynx_html_item_type *cur;
-    lynx_html_item_type *next;
+    lynx_list_item_type *cur = *ptr;
+    lynx_list_item_type *next;
 
-    cur = downloaders;
     while (cur) {
 	next = cur->next;
 	FREE(cur->name);
@@ -94,30 +91,22 @@ PRIVATE void free_item_list NOARGS
 	FREE(cur);
 	cur = next;
     }
-    downloaders = NULL;
+    *ptr = NULL;
+}
 
+/*
+ *  Function for freeing the DOWNLOADER and UPLOADER menus list. - FM
+ */
+PRIVATE void free_all_item_lists NOARGS
+{
+    free_item_list(&printers);
+    free_item_list(&downloaders);
 #ifdef DIRED_SUPPORT
-    cur = uploaders;
-    while (cur) {
-	next = cur->next;
-	FREE(cur->name);
-	FREE(cur->command);
-	FREE(cur);
-	cur = next;
-    }
-    uploaders = NULL;
+    free_item_list(&uploaders);
 #endif /* DIRED_SUPPORT */
 
 #ifdef USE_EXTERNALS
-    cur = externals;
-    while (cur) {
-	next = cur->next;
-	FREE(cur->name);
-	FREE(cur->command);
-	FREE(cur);
-	cur = next;
-    }
-    externals = NULL;
+    free_item_list(&externals);
 #endif /* USE_EXTERNALS */
 
     return;
@@ -126,12 +115,13 @@ PRIVATE void free_item_list NOARGS
 /*
  *  Process string buffer fields for DOWNLOADER or UPLOADER menus.
  */
-PRIVATE void add_item_to_list ARGS2(
+PRIVATE void add_item_to_list ARGS3(
 	char *,			buffer,
-	lynx_html_item_type **, list_ptr)
+	lynx_list_item_type **, list_ptr,
+	int,			special)
 {
     char *colon, *next_colon;
-    lynx_html_item_type *cur_item, *prev_item;
+    lynx_list_item_type *cur_item, *prev_item;
 
     /*
      *	Make a linked list
@@ -140,12 +130,12 @@ PRIVATE void add_item_to_list ARGS2(
 	/*
 	 *  First item.
 	 */
-	cur_item = typecalloc(lynx_html_item_type);
+	cur_item = typecalloc(lynx_list_item_type);
 	if (cur_item == NULL)
 	    outofmem(__FILE__, "read_cfg");
 	*list_ptr = cur_item;
 #ifdef LY_FIND_LEAKS
-	atexit(free_item_list);
+	atexit(free_all_item_lists);
 #endif
     } else {
 	/*
@@ -155,7 +145,7 @@ PRIVATE void add_item_to_list ARGS2(
 	     prev_item->next != NULL;
 	     prev_item = prev_item->next)
 	    ;  /* null body */
-	cur_item = typecalloc(lynx_html_item_type);
+	cur_item = typecalloc(lynx_list_item_type);
 	if (cur_item == NULL)
 	    outofmem(__FILE__, "read_cfg");
 	else
@@ -166,6 +156,7 @@ PRIVATE void add_item_to_list ARGS2(
     cur_item->command = NULL;
     cur_item->always_enabled = FALSE;
     cur_item->override_primary_action = FALSE;
+    cur_item->pagelen = 66;
 
     /*
      *	Find first unescaped colon and process fields
@@ -174,7 +165,7 @@ PRIVATE void add_item_to_list ARGS2(
 	/*
 	 *  Process name field
 	 */
-	cur_item->name = typecallocn(char,colon-buffer+1);
+	cur_item->name = typecallocn(char, colon-buffer+1);
 	if (cur_item->name == NULL)
 	    outofmem(__FILE__, "read_cfg");
 	LYstrncpy(cur_item->name, buffer, (int)(colon-buffer));
@@ -202,113 +193,36 @@ PRIVATE void add_item_to_list ARGS2(
 		*next_colon++ = '\0';
 	    cur_item->always_enabled = is_true(colon);
 	    if (next_colon) {
-		cur_item->override_primary_action = is_true(next_colon);
+		if (special) {
+		    cur_item->pagelen = atoi(next_colon);
+		} else {
+		    cur_item->override_primary_action = is_true(next_colon);
+		}
 	    }
 	}
     }
 }
 
-
-/*
- *  Function for freeing the PRINTER menus list. - FM
- */
-PRIVATE void free_printer_item_list NOARGS
+PUBLIC lynx_list_item_type *find_item_by_number ARGS2(
+	lynx_list_item_type *,	list_ptr,
+	char *,			number)
 {
-    lynx_printer_item_type *cur = printers;
-    lynx_printer_item_type *next;
-
-    while (cur) {
-	next = cur->next;
-	FREE(cur->name);
-	FREE(cur->command);
-	FREE(cur);
-	cur = next;
+    int value = atoi(number);
+    while (value-- >= 0 && list_ptr != 0) {
+	list_ptr = list_ptr->next;
     }
-    printers = NULL;
-
-    return;
+    return list_ptr;
 }
 
-/*
- *  Process string buffer fields for PRINTER menus.
- */
-PRIVATE void add_printer_to_list ARGS2(
-	char *,				buffer,
-	lynx_printer_item_type **,	list_ptr)
+PUBLIC int match_item_by_name ARGS3(
+    lynx_list_item_type *,	ptr,
+    char *,			name,
+    BOOLEAN,			only_overriders)
 {
-    char *colon, *next_colon;
-    lynx_printer_item_type *cur_item, *prev_item;
-
-    /*
-     *	Make a linked list.
-     */
-    if (*list_ptr == NULL) {
-	/*
-	 *  First item.
-	 */
-	cur_item = typecalloc(lynx_printer_item_type);
-	if (cur_item == NULL)
-	    outofmem(__FILE__, "read_cfg");
-	*list_ptr = cur_item;
-#ifdef LY_FIND_LEAKS
-	atexit(free_printer_item_list);
-#endif
-    } else {
-	/*
-	 *  Find the last item.
-	 */
-	for (prev_item = *list_ptr;
-	     prev_item->next != NULL;
-	     prev_item = prev_item->next)
-	    ;  /* null body */
-
-	cur_item = typecalloc(lynx_printer_item_type);
-	if (cur_item == NULL)
-	    outofmem(__FILE__, "read_cfg");
-	else
-	    prev_item->next = cur_item;
-    }
-    cur_item->next = NULL;
-    cur_item->name = NULL;
-    cur_item->command = NULL;
-    cur_item->always_enabled = FALSE;
-
-    /*
-     *	Find first unescaped colon and process fields.
-     */
-    if ((colon = find_colon(buffer)) != NULL) {
-	/*
-	 *  Process name field.
-	 */
-	cur_item->name = typecallocn(char, colon-buffer+1);
-	if (cur_item->name == NULL)
-	    outofmem(__FILE__, "read_cfg");
-	LYstrncpy(cur_item->name, buffer, (int)(colon-buffer));
-	remove_backslashes(cur_item->name);
-
-	/*
-	 *  Process TRUE/FALSE field.
-	 */
-	if ((next_colon = find_colon(colon+1)) != NULL) {
-	    cur_item->command = typecallocn(char, next_colon-colon);
-	    if (cur_item->command == NULL)
-		outofmem(__FILE__, "read_cfg");
-	    LYstrncpy(cur_item->command, colon+1, (int)(next_colon-(colon+1)));
-	    remove_backslashes(cur_item->command);
-	    cur_item->always_enabled = is_true(next_colon+1);
-	}
-
-	/*
-	 *  Process pagelen field.
-	 */
-	if (next_colon != NULL
-	 && (next_colon = find_colon(next_colon+1)) != NULL) {
-	    cur_item->pagelen = atoi(next_colon+1);
-	} else {
-	    /* default to 66 lines */
-	    cur_item->pagelen = 66;
-	}
-    }
+    return
+	(ptr->command != 0
+	&& !strncasecomp(ptr->name, name, strlen(ptr->name))
+	&& (only_overriders ? ptr->override_primary_action : 1));
 }
 
 #if defined(USE_COLOR_STYLE) || defined(USE_COLOR_TABLE)
@@ -483,7 +397,7 @@ PRIVATE void parse_color ARGS1(
 typedef int (*ParseFunc) PARAMS((char *));
 
 typedef union {
-	lynx_html_item_type ** add_value;
+	lynx_list_item_type ** add_value;
 	BOOLEAN * set_value;
 	int *	  int_value;
 	char **   str_value;
@@ -493,7 +407,7 @@ typedef union {
 
 #ifdef	PARSE_DEBUG
 #define ParseData \
-	lynx_html_item_type** add_value; \
+	lynx_list_item_type** add_value; \
 	BOOLEAN *set_value; \
 	int *int_value; \
 	char **str_value; \
@@ -971,7 +885,7 @@ static int cern_rulesfile_fun ARGS1(
 static int printer_fun ARGS1(
 	char *,		value)
 {
-    add_printer_to_list(value, &printers);
+    add_item_to_list(value, &printers, TRUE);
     return 0;
 }
 
@@ -1710,8 +1624,7 @@ PUBLIC void free_lynx_cfg NOARGS
 	    break;
 	}
     }
-    free_item_list();
-    free_printer_item_list();
+    free_all_item_lists();
 #ifdef DIRED_SUPPORT
     reset_dired_menu();		/* frees and resets dired menu items - kw */
 #endif
@@ -1739,6 +1652,60 @@ PRIVATE Config_Type *lookup_config ARGS1(
     return tbl;
 }
 
+/*
+ * If the given value is an absolute path (by syntax), or we can read it, use
+ * the value as given.  Otherwise, assume it must be in the same place we read
+ * the parent configuration file from.
+ *
+ * Note:  only read files from the current directory if there's no parent
+ * filename, otherwise it leads to user surprise.
+ */
+PRIVATE char *actual_filename ARGS3(
+    char *,	cfg_filename,
+    char *,	parent_filename,
+    char *,	dft_filename)
+{
+    static char *my_filename;
+
+    if (my_filename != 0) {
+	FREE(my_filename);
+    }
+    if (!LYisAbsPath(cfg_filename)
+     && !(parent_filename == 0 && LYCanReadFile(cfg_filename))) {
+	if (!strncmp(cfg_filename, "~/", 2)) {
+	    HTSprintf0(&my_filename, "%s%s", Home_Dir(), cfg_filename+1);
+	    cfg_filename = my_filename;
+	} else {
+	    if (parent_filename != 0) {
+		StrAllocCopy(my_filename, parent_filename);
+		*LYPathLeaf (my_filename) = '\0';
+		StrAllocCat(my_filename, cfg_filename);
+	    }
+	    if (my_filename != 0 && LYCanReadFile(my_filename)) {
+		cfg_filename = my_filename;
+	    } else {
+		StrAllocCopy(my_filename, dft_filename);
+		*LYPathLeaf (my_filename) = '\0';
+		StrAllocCat(my_filename, cfg_filename);
+		if (LYCanReadFile(my_filename)) {
+		    cfg_filename = my_filename;
+		}
+	    }
+	}
+    }
+    return cfg_filename;
+}
+
+PUBLIC FILE *LYOpenCFG ARGS3(
+    char *,	cfg_filename,
+    char *,	parent_filename,
+    char *,	dft_filename)
+{
+    cfg_filename = actual_filename(cfg_filename, parent_filename, dft_filename);
+    CTRACE((tfp, "opening config file %s\n", cfg_filename));
+    return fopen(cfg_filename, TXT_R);
+}
+
 #define NOPTS_ ( TABLESIZE(Config_Table) - 1 )
 typedef BOOL (optidx_set_t) [ NOPTS_ ];
  /* if element is FALSE, then it's allowed in the current file*/
@@ -1765,7 +1732,6 @@ PRIVATE void do_read_cfg ARGS5(
 	FILE *,	fp0,
 	optidx_set_t*, allowed)
 {
-    static char *mypath = NULL;
     FILE *fp;
     char *buffer = 0;
 
@@ -1790,11 +1756,7 @@ PRIVATE void do_read_cfg ARGS5(
 	CTRACE((tfp,"No filename following -cfg switch!\n"));
 	return;
     }
-    if (!strncmp(cfg_filename, "~/", 2)) {
-	HTSprintf0(&mypath, "%s%s", Home_Dir(), cfg_filename+1);
-	cfg_filename = mypath;
-    }
-    if ((fp = fopen(cfg_filename, TXT_R)) == 0) {
+    if ((fp = LYOpenCFG(cfg_filename, parent_filename, LYNX_CFG_FILE)) == 0) {
 	CTRACE((tfp, "lynx.cfg file not found as '%s'\n", cfg_filename));
 	return;
     }
@@ -1954,7 +1916,7 @@ PRIVATE void do_read_cfg ARGS5(
 
 #ifndef NO_CONFIG_INFO
 	    if (fp0 != 0  &&  !no_lynxcfg_xinfo) {
-		LYLocalFileToURL(&url, value);
+		LYLocalFileToURL(&url, actual_filename(value, cfg_filename, LYNX_CFG_FILE));
 		StrAllocCopy(cp1, value);
 		if (strchr(value, '&') || strchr(value, '<')) {
 		    LYEntify(&cp1, TRUE);
@@ -2043,7 +2005,7 @@ PRIVATE void do_read_cfg ARGS5(
 
 	case CONF_ADD_ITEM:
 	    if (q->add_value != 0)
-		add_item_to_list (value, q->add_value);
+		add_item_to_list (value, q->add_value, FALSE);
 	    break;
 
 #if defined(EXEC_LINKS) || defined(LYNXCGI_LINKS)
@@ -2076,7 +2038,7 @@ PRIVATE void do_read_cfg ARGS5(
      *	with those always_enabled options still available. - FM
      */
     if (downloaders != 0) {
-	lynx_html_item_type *cur_download;
+	lynx_list_item_type *cur_download;
 
 	cur_download = downloaders;
 	while (cur_download != 0) {
diff --git a/src/LYReadCFG.h b/src/LYReadCFG.h
index 2fc893ad..b6349cc0 100644
--- a/src/LYReadCFG.h
+++ b/src/LYReadCFG.h
@@ -53,8 +53,11 @@ extern void read_cfg PARAMS((char *cfg_filename, char *parent_filename, int nest
 extern void free_lynx_cfg NOPARAMS;
 extern BOOLEAN have_read_cfg;
 
+extern FILE *LYOpenCFG PARAMS((char *cfg_filename, char *parent_filename, char *dft_filename));
 extern int lynx_cfg_infopage PARAMS((document *newdoc));
 extern int lynx_compile_opts PARAMS((document *newdoc));
+extern int match_item_by_name PARAMS((lynx_list_item_type * ptr, char * name, BOOLEAN only_overriders));
+extern lynx_list_item_type *find_item_by_number PARAMS((lynx_list_item_type * list_ptr, char * number));
 extern void reload_read_cfg NOPARAMS; /* implemented in LYMain.c */
 
 #endif /* LYREADCFG_H */
diff --git a/src/LYStrings.c b/src/LYStrings.c
index 7ea81384..0f6685de 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -364,16 +364,45 @@ PRIVATE int set_clicked_link ARGS4(
     int i;
     int c = -1;
 
-    if (y == (LYlines-1)) {
-	mouse_link = -2;
-	if (x < left)	    c = (code==FOR_PROMPT) ? LTARROW : LTARROW;
-	else if (x > right) c = (code==FOR_PROMPT) ? RTARROW : '\b';
-	else c = PGDOWN;
-    } else if (y == 0) {
+    if (y == (LYlines-1) || y == 0) {	/* First or last row */
+	/* XXXX In fact # is not always at x==0?  KANJI_CODE_OVERRIDE? */
+	int toolbar = (y == 0 && HText_hasToolbar(HTMainText));
+
 	mouse_link = -2;
-	if (x < left) c = LTARROW;
-	else if (x > right) c = '\b';
-	else c = PGUP;
+	if (x == 0 && toolbar)		/* On '#' */
+	    c = LAC_TO_LKC0(LYK_TOOLBAR);
+	else if (clicks > 1) {
+	    if (x < left + toolbar)
+		c = (code==FOR_PROMPT && y)
+		    ? HOME : LAC_TO_LKC0(LYK_MAIN_MENU);
+	    else if (x > right)
+		c = (code==FOR_PROMPT && y)
+		    ? END_KEY : LAC_TO_LKC0(LYK_VLINKS);
+	    else if (y)			/* Last row */
+		c = LAC_TO_LKC0(LYK_END);
+	    else			/* First row */
+		c = LAC_TO_LKC0(LYK_HOME);
+	} else {
+	    if (x < left + toolbar)
+		c = (code==FOR_PROMPT && y)
+		    ? LTARROW
+		    : (
+#ifdef USE_COLOR_STYLE
+			(s_forw_backw != NOSTYLE && x - toolbar >= 3)
+			? LAC_TO_LKC0(LYK_NEXT_DOC)
+			: LAC_TO_LKC0(LYK_PREV_DOC)
+#else
+			LAC_TO_LKC0(LYK_NEXT_DOC)
+#endif
+			);
+	    else if (x > right)
+		c = (code==FOR_PROMPT && y)
+		    ? RTARROW : LAC_TO_LKC0(LYK_HISTORY);
+	    else if (y)			/* Last row */
+		c = LAC_TO_LKC0(LYK_NEXT_PAGE);
+	    else			/* First row */
+		c = LAC_TO_LKC0(LYK_PREV_PAGE);
+	}
 #ifdef USE_SCROLLBAR
     } else if (x == LYcols - 1 && LYsb && LYsb_begin >= 0) {
 	int h = display_lines - 2*(LYsb_arrow != 0);
@@ -499,9 +528,9 @@ PRIVATE int set_clicked_link ARGS4(
 	if (mouse_link >= 0) {
 	    if (mouse_err == 0) {
 		if (c == -1)
-		    c = lookup_keymap(LYK_ACTIVATE);
+		    c = LAC_TO_LKC0(LYK_ACTIVATE);
 	    } else if (mouse_err >= 0)
-		c = lookup_keymap(LYK_CHANGE_LINK);
+		c = LAC_TO_LKC0(LYK_CHANGE_LINK);
 	}
     }
     return c;
@@ -1213,18 +1242,16 @@ PRIVATE int read_keymap_file NOARGS
     char *line = NULL;
     FILE *fp;
     char file[LY_MAXPATH];
-    int ret;
     int linenum;
     size_t n;
 
     LYAddPathToHome(file, sizeof(file), FNAME_LYNX_KEYMAPS);
 
-    if ((fp = fopen (file, "r")) == 0)
+    if ((fp = fopen (file, TXT_R)) == 0)
 	return 0;
 
     linenum = 0;
-    ret = 0;
-    while (LYSafeGets(&line, fp) != 0 && (ret == 0)) {
+    while (LYSafeGets(&line, fp) != 0) {
 	char *s = LYSkipBlanks(line);
 
 	linenum++;
@@ -1234,23 +1261,15 @@ PRIVATE int read_keymap_file NOARGS
 
 	for (n = 0; n < TABLESIZE(table); n++) {
 	    size_t len = strlen(table[n].name);
-	    if (strlen(s) > len
-	     && !strncmp(s, table[n].name, len)) {
-		if ((*(table[n].func))(LYSkipBlanks(s+len)) < 0) {
-		    ret = -1;
-		    break;
-		}
-	    }
+
+	    if ( strlen(s) > len && !strncmp(s, table[n].name, len)
+		 && (*(table[n].func))(LYSkipBlanks(s+len)) < 0 )
+		fprintf (stderr, FAILED_READING_KEYMAP, linenum, file);
 	}
     }
     FREE(line);
-
     LYCloseInput (fp);
-
-    if (ret == -1)
-	fprintf (stderr, FAILED_READING_KEYMAP, linenum, file);
-
-    return ret;
+    return 0;
 }
 
 PRIVATE void setup_vtXXX_keymap NOARGS
@@ -1547,9 +1566,11 @@ re_read:
 #endif /* !USE_SLANG */
 #if !defined(USE_SLANG) || defined(VMS) || defined(DJGPP_KEYHANDLER)
     c = GetChar();
+    lynx_nl2crlf(FALSE);
 #else
     if (LYCursesON) {
 	c = GetChar();
+	lynx_nl2crlf(FALSE);
     } else {
 	c = getchar();
 	if (c == EOF && errno == EINTR) /* Ctrl-Z causes EINTR in getchar() */
@@ -1595,7 +1616,7 @@ re_read:
 	    if (new_fd >= 0) {
 		FILE *frp;
 		close(new_fd);
-		freopen(term_name, "r", stdin);
+		freopen(term_name, TXT_R, stdin);
 		CTRACE((tfp,
 		"nozap: freopen(%s,\"r\",stdin) returned %p, stdin is now %p with fd %d.\n",
 			term_name, frp, stdin, fileno(stdin)));
@@ -2077,23 +2098,7 @@ re_read:
 		    c = set_clicked_link(event.x, event.y, code, 1);
 		} else if (event.bstate & BUTTON1_DOUBLE_CLICKED) {
 		    c = set_clicked_link(event.x, event.y, code, 2);
-		    if (c == PGDOWN)
-			c = END_KEY;
-		    else if (c == PGUP)
-			c = HOME;
-		    else if (c == REMOVE_KEY)
-			c = END_KEY;
-		    else if (c == INSERT_KEY)
-			c = HOME;
-		    else if (c == RTARROW)
-			c = END_KEY;
-		    else if (c == LTARROW && code == FOR_PROMPT)
-			c = HOME;
-		    else if (c == LTARROW)
-			c = LYReverseKeymap(LYK_MAIN_MENU);
-		    else if (c == '\b' && (code == FOR_PANEL || code == FOR_INPUT))
-			c = LAC_TO_LKC0(LYK_VLINKS);
-		    else if (c == LAC_TO_LKC0(LYK_SUBMIT) && code == FOR_INPUT)
+		    if (c == LAC_TO_LKC0(LYK_SUBMIT) && code == FOR_INPUT)
 			lac = LYK_SUBMIT;
 		} else if (event.bstate & BUTTON3_CLICKED) {
 		    c = LAC_TO_LKC0(LYK_PREV_DOC);
@@ -2110,7 +2115,7 @@ re_read:
 		    int atlink;
 
 		    c = set_clicked_link(event.x, event.y, code, 1);
-		    atlink = (c == LYReverseKeymap(LYK_ACTIVATE));
+		    atlink = (c == LAC_TO_LKC0(LYK_ACTIVATE));
 		    if (!atlink)
 			mouse_link = -1; /* Forget about approx stuff. */
 
@@ -2695,7 +2700,8 @@ PUBLIC int LYEditInsert ARGS5(
     if (map < 0)
 	map = map_active;
     if (map && LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
-	unsigned char *e = s + len, *t = Buf + Pos;
+	int off = Pos;
+	unsigned char *e = s + len;
 	char *tail = 0;
 
 	while (s < e) {
@@ -2712,30 +2718,30 @@ PUBLIC int LYEditInsert ARGS5(
 			remains -= l - 1;
 			if (remains < 0) {
 			    if (tail)
-				strcpy(t, tail);
+				strcpy(Buf + off, tail);
 			    FREE(tail);
-			    len = (char*)t - Buf;
+			    len = off;
 			    overflow = 1;
 			    goto finish;
 			}
 			if (l > 1 && !tail)
-			    StrAllocCopy((char*)tail, Buf + Pos + len);
+			    StrAllocCopy(tail, Buf + Pos + len);
 		    } else
 			utfbuf[0] = '?';
 		} else
 		    utfbuf[0] = UCH(ucode);
 	    }
-	    strncpy(t, utfbuf, l);
+	    strncpy(Buf + off, utfbuf, l);
 	    edited = 1;
-	    t += l;
+	    off += l;
 	    s++;
 	}
 	if (tail)
-	    strcpy(t, tail);
-	len = (char*)t - (Buf + Pos);
+	    strcpy(Buf + off, tail);
+	len = off - Pos;
 	FREE(tail);
     } else if (map) {
-	unsigned char *e = s + len, *t = Buf + Pos;
+	unsigned char *e = s + len, *t = (unsigned char *)Buf + Pos;
 
 	while (s < e) {
 	    int ch;
@@ -3556,7 +3562,7 @@ PRIVATE char **sortedList ARGS2(
     unsigned count = HTList_count(list);
     unsigned j = 0;
     unsigned k, jk;
-    char **result = calloc(count + 1, sizeof(char *));
+    char **result = typecallocn(char *, count + 1);
 
     if (result == 0)
 	outofmem(__FILE__, "sortedList");
@@ -3695,7 +3701,7 @@ PUBLIC int LYhandlePopupList ARGS9(
 	BOOLEAN,	numbered)
 {
     int c = 0, cmd = 0, i = 0, j = 0, rel = 0;
-    int orig_choice = cur_choice;
+    int orig_choice;
     WINDOW * form_window;
     int num_choices = 0;
     int max_choices = 0;
@@ -3719,6 +3725,10 @@ PUBLIC int LYhandlePopupList ARGS9(
     char *popup_status_msg = NULL;
     CONST char **Cptr = NULL;
 
+    orig_choice = cur_choice;
+    if (cur_choice < 0)
+	cur_choice = 0;
+
     /*
      * Initialize the search string buffer. - FM
      */
@@ -5341,7 +5351,7 @@ PUBLIC char * SNACopy ARGS3(
 {
     FREE(*dest);
     if (src) {
-	*dest = (char *)calloc(1, n + 1);
+	*dest = typecallocn(char, n + 1);
 	if (*dest == NULL) {
 	    CTRACE((tfp, "Tried to calloc %d bytes\n", n));
 	    outofmem(__FILE__, "SNACopy");
@@ -5369,7 +5379,7 @@ PUBLIC char * SNACat ARGS3(
 	    strncpy(*dest + length, src, n);
 	    *(*dest + length + n) = '\0'; /* terminate */
 	} else {
-	    *dest = (char *)calloc(1, n + 1);
+	    *dest = typecallocn(char, n + 1);
 	    if (*dest == NULL)
 		outofmem(__FILE__, "SNACat");
 	    memcpy(*dest, src, n);
@@ -5692,7 +5702,7 @@ PUBLIC BOOL LYHaveCmdScript NOARGS
 PUBLIC void LYOpenCmdScript NOARGS
 {
     if (lynx_cmd_script != 0) {
-	cmd_script = fopen(lynx_cmd_script, "r");
+	cmd_script = fopen(lynx_cmd_script, TXT_R);
 	CTRACE((tfp, "LYOpenCmdScript(%s) %s\n",
 		lynx_cmd_script,
 		cmd_script != 0 ? "SUCCESS" : "FAIL"));
diff --git a/src/LYStrings.h b/src/LYStrings.h
index 3c1f0898..af6e4fb2 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -139,10 +139,10 @@ extern void base64_encode PARAMS((char * dest, char * src, int len));
       have to be changed/reviewed, AS WELL AS the lineedit binding
       tables in LYEditmap.c !
     - KEYMAP_SIZE, defined in LYKeymap.h, may need to be changed !
-    - See also table funckey[] in LYKeymap.c for 'pretty' strings
+    - See also table named_keys[] in LYKeymap.c for 'pretty' strings
       for the keys with codes >= 256 (to appear on the 'K'eymap page).
       New keycodes should probably be assigned consecutively, so their
-      key names can be easily added to funckey[] (but see next point).
+      key names can be easily added to named_keys[] (but see next point).
       They should also be documented in lynx.cfg.
     - The DOS port uses its own native codes for some keys, unless
       they are remapped by the code in LYgetch().  See *.key files
diff --git a/src/LYStructs.h b/src/LYStructs.h
index 2471c59c..90020afd 100644
--- a/src/LYStructs.h
+++ b/src/LYStructs.h
@@ -80,14 +80,15 @@ typedef struct _VisitedLink {
 extern histstruct history[MAXHIST];
 extern int nhist;
 
-typedef struct _lynx_html_item_type {
-    struct _lynx_html_item_type *next;  /* the next item in the linked list */
+typedef struct _lynx_list_item_type {
+    struct _lynx_list_item_type *next;  /* the next item in the linked list */
     char *name; 			/* a description of the item */
     char *command;			/* the command to execute */
     int  always_enabled;		/* a constant to tell whether or
 					* not to disable the printer
 					* when the no_print option is on
 					*/
+    /* HTML lists: */
     BOOL override_primary_action;	/* whether primary action will be
 					* overridden by this - e.g. this allows
 					* invoking user's MUA when mailto: link
@@ -95,32 +96,23 @@ typedef struct _lynx_html_item_type {
 					* command. This field is only examined
 					* by code that handles EXTERNAL command.
 					*/
-} lynx_html_item_type;
+    /* PRINTER lists: */
+    int pagelen;			/* an integer to store the printer's
+					* page length
+					*/
+} lynx_list_item_type;
 
-/* for printer commands */
-typedef struct _lynx_printer_item_type {
-    struct _lynx_printer_item_type *next; /* next item in the linked list */
-    char *name; 			  /* a description of the item	  */
-    char *command;			  /* the command to execute	  */
-    int  always_enabled;		  /* a constant to tell whether or
-					   * not to disable the printer
-					   * when the no_print option is on
-					   */
-    int pagelen;			  /* an integer to store the printer's
-					   * page length
-					   */
-} lynx_printer_item_type;
-extern lynx_printer_item_type *printers;
+extern lynx_list_item_type *printers;
 
 /* for download commands */
-extern lynx_html_item_type *downloaders;
+extern lynx_list_item_type *downloaders;
 
 /* for upload commands */
-extern lynx_html_item_type *uploaders;
+extern lynx_list_item_type *uploaders;
 
 #ifdef USE_EXTERNALS
 /* for external commands */
-extern lynx_html_item_type *externals;
+extern lynx_list_item_type *externals;
 #endif
 
 #endif /* LYSTRUCTS_H */
diff --git a/src/LYStyle.c b/src/LYStyle.c
index b2b40e69..6477b42f 100644
--- a/src/LYStyle.c
+++ b/src/LYStyle.c
@@ -1,6 +1,6 @@
 /* character level styles for Lynx
  * (c) 1996 Rob Partington -- donated to the Lyncei (if they want it :-)
- * @Id: LYStyle.c 1.43 Mon, 26 Feb 2001 18:41:57 -0800 dickey @
+ * @Id: LYStyle.c 1.44 Sun, 01 Apr 2001 17:51:46 -0700 dickey @
  */
 #include <HTUtils.h>
 #include <HTML.h>
@@ -58,6 +58,7 @@ PUBLIC int s_aedit_sel		= NOSTYLE;
 PUBLIC int s_alert		= NOSTYLE;
 PUBLIC int s_alink		= NOSTYLE;
 PUBLIC int s_curedit		= NOSTYLE;
+PUBLIC int s_forw_backw		= NOSTYLE;
 PUBLIC int s_normal		= NOSTYLE;
 PUBLIC int s_prompt_edit	= NOSTYLE;
 PUBLIC int s_prompt_edit_arr	= NOSTYLE;
@@ -207,6 +208,7 @@ PRIVATE void parse_style ARGS1(char*,buffer)
 	{ "edit.prompt.arrow",	DSTYLE_ELEMENTS,	&s_prompt_edit_arr },
 	{ "edit.prompt.marked",	DSTYLE_ELEMENTS,	&s_prompt_sel },
 	{ "edit.prompt",	DSTYLE_ELEMENTS,	&s_prompt_edit },
+	{ "forwbackw.arrow",	DSTYLE_ELEMENTS,	&s_forw_backw },
     };
     unsigned n;
     BOOL found = FALSE;
@@ -434,24 +436,24 @@ PUBLIC void style_deleteStyleList NOARGS
     lss_styles = NULL;
 }
 
-PRIVATE int style_readFromFileREC ARGS2(char*, file, int, toplevel)
+PRIVATE int style_readFromFileREC ARGS2(
+    char *,	lss_filename,
+    char *,	parent_filename)
 {
     FILE *fh;
     char *buffer = NULL;
     int len;
 
-    CTRACE2(TRACE_STYLE, (tfp, "CSS:Reading styles from file: %s\n", file ? file : "?!? empty ?!?"));
-    if (file == NULL || *file == '\0')
+    CTRACE2(TRACE_STYLE, (tfp, "CSS:Reading styles from file: %s\n", lss_filename ? lss_filename : "?!? empty ?!?"));
+    if (lss_filename == NULL || *lss_filename == '\0')
 	return -1;
-    fh = fopen(file, TXT_R);
-    if (!fh)
-    {
+    if ((fh = LYOpenCFG(lss_filename, parent_filename, LYNX_LSS_FILE)) == 0) {
 	/* this should probably be an alert or something */
-	CTRACE2(TRACE_STYLE, (tfp, "CSS:Can't open style file '%s', using defaults\n", file));
+	CTRACE2(TRACE_STYLE, (tfp, "CSS:Can't open style file '%s', using defaults\n", lss_filename));
 	return -1;
     }
 
-    if (toplevel) {
+    if (parent_filename == 0) {
 	style_initialiseHashTable();
 	style_deleteStyleList();
     }
@@ -461,20 +463,20 @@ PRIVATE int style_readFromFileREC ARGS2(char*, file, int, toplevel)
 	LYTrimTail(buffer);
 	LYTrimHead(buffer);
 	if (!strncasecomp(buffer,"include:",8))
-	    style_readFromFileREC(buffer+8, 0);
+	    style_readFromFileREC(buffer+8, lss_filename);
 	else if (buffer[0] != '#' && (len = strlen(buffer)) > 0)
 	    HStyle_addStyle(buffer);
     }
 
     LYCloseInput (fh);
-    if (toplevel && LYCursesON)
+    if ((parent_filename == 0) && LYCursesON)
 	parse_userstyles();
     return 0;
 }
 
-PUBLIC int style_readFromFile ARGS1(char*, file)
+PUBLIC int style_readFromFile ARGS1(char*, filename)
 {
-    return style_readFromFileREC(file, 1);
+    return style_readFromFileREC(filename, (char *)0);
 }
 
 /* Used in HTStructured methods: - kw */
diff --git a/src/LYUpload.c b/src/LYUpload.c
index 63ab40d4..a78018fa 100644
--- a/src/LYUpload.c
+++ b/src/LYUpload.c
@@ -47,19 +47,19 @@ PUBLIC int LYUpload ARGS1(
     char *the_upload = 0;
     char tmpbuf[LY_MAXPATH];
     char *filename = NULL;
-    lynx_html_item_type *upload_command = 0;
+    lynx_list_item_type *upload_command = 0;
     char *the_command = 0;
 
     /*
      *	Use configured upload commands.
      */
-    if((directory = (char *)strstr(line, "TO=")) == NULL)
+    if((directory = strstr(line, "TO=")) == NULL)
 	goto failed;
     *(directory - 1) = '\0';
     /* go past "Directory=" */
     directory += 3;
 
-    if((method = (char *)strstr(line, "UPLOAD=")) == NULL)
+    if((method = strstr(line, "UPLOAD=")) == NULL)
 	goto failed;
     /*
      *	Go past "Method=".
@@ -180,7 +180,7 @@ PUBLIC int LYUpload_options ARGS2(
 {
     static char tempfile[LY_MAXPATH];
     FILE *fp0;
-    lynx_html_item_type *cur_upload;
+    lynx_list_item_type *cur_upload;
     int count;
     static char curloc[LY_MAXPATH];
     char *cp;
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 5b754ddf..24494fc2 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -2514,7 +2514,7 @@ PUBLIC int HTCheckForInterrupt NOARGS
  * references a directory.
  */
 PUBLIC BOOLEAN LYisAbsPath ARGS1(
-	char *,		path)
+	CONST char *,	path)
 {
 #ifdef VMS
     return TRUE;
@@ -3231,7 +3231,7 @@ PUBLIC BOOLEAN LYCloseOutput ARGS1(
 PUBLIC BOOLEAN LYCanWriteFile ARGS1(
 	CONST char*,	filename)
 {
-    if (LYCloseOutput(fopen(filename, "w"))) {
+    if (LYCloseOutput(fopen(filename, TXT_W))) {
 	remove(filename);
 	return TRUE;
     } else {
@@ -3248,7 +3248,7 @@ PUBLIC BOOLEAN LYCanReadFile ARGS1(
 {
     FILE *fp;
 
-    if ((fp = fopen(filename, "r")) != 0) {
+    if ((fp = fopen(filename, TXT_R)) != 0) {
 	return LYCloseInput(fp);
     }
     return FALSE;
@@ -3293,7 +3293,7 @@ PUBLIC BOOLEAN inlocaldomain NOARGS
     if ((cp = ttyname(0)))
 	mytty = strrchr(cp, '/');
 
-    if (mytty && (fp = fopen(UTMP_FILE, "r")) != NULL) {
+    if (mytty && (fp = fopen(UTMP_FILE, TXT_R)) != NULL) {
 	mytty++;
 	do {
 	    n = fread((char *) &me, sizeof(struct utmp), 1, fp);
@@ -3506,6 +3506,15 @@ PUBLIC void size_change ARGS1(
 	recent_sizechange = TRUE;
 	CTRACE((tfp, "Window size changed from (%d,%d) to (%d,%d)\n",
 		old_lines, old_cols, LYlines, LYcols));
+#if defined(CAN_SWITCH_DISPLAY_CHARSET) && defined(CAN_AUTODETECT_DISPLAY_CHARSET)
+	/* May need to reload the font due to different char-box size */
+	if (current_char_set != auto_display_charset) {
+	    int old = current_char_set;
+
+	    Switch_Display_Charset(auto_display_charset, 1);
+	    Switch_Display_Charset(old, 1);
+	}
+#endif
     }
 #ifdef SIGWINCH
     LYExtSignal (SIGWINCH, size_change);
@@ -6388,6 +6397,7 @@ PRIVATE FILE *OpenHiddenFile ARGS2(char *, name, char *, mode)
 {
     FILE *fp = 0;
     struct stat data;
+    BOOLEAN binary = strchr(mode, 'b') != 0;
 
 #if defined(O_CREAT) && defined(O_EXCL) /* we have fcntl.h or kindred? */
     /*
@@ -6405,7 +6415,7 @@ PRIVATE FILE *OpenHiddenFile ARGS2(char *, name, char *, mode)
 	}
 	if (fd >= 0) {
 #if defined(O_BINARY) && defined(__CYGWIN__)
-	    if (mode[1] == 'b')
+	    if (binary)
 		setmode(fd, O_BINARY);
 #endif
 	    fp = fdopen(fd, mode);
@@ -6418,7 +6428,7 @@ PRIVATE FILE *OpenHiddenFile ARGS2(char *, name, char *, mode)
 	 && chmod(name, HIDE_CHMOD) == 0)
 	    fp = fopen(name, mode);
 	else if (lstat(name, &data) != 0)
-	    fp = OpenHiddenFile(name, "w");
+	    fp = OpenHiddenFile(name, binary ? BIN_W : TXT_W);
     /*
      * This is less stringent, but reasonably portable.  For new files, the
      * umask will suffice; however if the file already exists we'll change
@@ -6445,10 +6455,10 @@ PRIVATE FILE *OpenHiddenFile ARGS2(char *, name, char *, mode)
 PUBLIC FILE *LYNewBinFile ARGS1(char *, name)
 {
 #ifdef VMS
-    FILE *fp = fopen (name, "wb", "mbc=32");
+    FILE *fp = fopen (name, BIN_W, "mbc=32");
     chmod(name, HIDE_CHMOD);
 #else
-    FILE *fp = OpenHiddenFile(name, "wb");
+    FILE *fp = OpenHiddenFile(name, BIN_W);
 #endif
     return fp;
 }
@@ -6458,12 +6468,12 @@ PUBLIC FILE *LYNewTxtFile ARGS1(char *, name)
     FILE *fp;
 
 #ifdef VMS
-    fp = fopen (name, "w", "shr=get");
+    fp = fopen (name, TXT_W, "shr=get");
     chmod(name, HIDE_CHMOD);
 #else
     SetDefaultMode(O_TEXT);
 
-    fp = OpenHiddenFile(name, "w");
+    fp = OpenHiddenFile(name, TXT_W);
 
     SetDefaultMode(O_BINARY);
 #endif
@@ -6476,12 +6486,12 @@ PUBLIC FILE *LYAppendToTxtFile ARGS1(char *, name)
     FILE *fp;
 
 #ifdef VMS
-    fp = fopen (name, "a+", "shr=get");
+    fp = fopen (name, TXT_A, "shr=get");
     chmod(name, HIDE_CHMOD);
 #else
     SetDefaultMode(O_TEXT);
 
-    fp = OpenHiddenFile(name, "a+");
+    fp = OpenHiddenFile(name, TXT_A);
 
     SetDefaultMode(O_BINARY);
 #endif
@@ -7321,6 +7331,11 @@ PUBLIC void LYLocalFileToURL ARGS2(
 
     leaf = wwwName(source);
 
+    if (!LYisAbsPath(source)) {
+	char temp[LY_MAXPATH];
+	Current_Dir(temp);
+	StrAllocCat(*target, temp);
+    }
     if (!LYIsHtmlSep(*leaf))
 	LYAddHtmlSep(target);
     StrAllocCat(*target, leaf);
@@ -7529,8 +7544,8 @@ PUBLIC int LYCopyFile ARGS2(
     int len;
 
     code = EOF;
-    if ((fin = fopen(src, "rb")) != 0) {
-	if ((fout = fopen(dst, "wb")) != 0) {
+    if ((fin = fopen(src, BIN_R)) != 0) {
+	if ((fout = fopen(dst, BIN_W)) != 0) {
 	    code = 0;
 	    while ((len = fread(buff, 1, BUF_SIZE, fin)) > 0) {
 		fwrite(buff, 1, len, fout);
diff --git a/src/LYUtils.h b/src/LYUtils.h
index bc6ee44d..a9b990e5 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -75,7 +75,7 @@ extern BOOLEAN LYExpandHostForURL PARAMS((char **AllocatedString, char *prefix_l
 extern BOOLEAN LYFixCursesOnForAccess PARAMS((CONST char* addr, CONST char* physical));
 extern BOOLEAN LYPathOffHomeOK PARAMS((char *fbuffer, size_t fbuffer_size));
 extern BOOLEAN LYValidateFilename PARAMS((char * result, char * given));
-extern BOOLEAN LYisAbsPath PARAMS((char *path));
+extern BOOLEAN LYisAbsPath PARAMS((CONST char *path));
 extern BOOLEAN LYisLocalAlias PARAMS((char *filename));
 extern BOOLEAN LYisLocalFile PARAMS((char *filename));
 extern BOOLEAN LYisLocalHost PARAMS((char *filename));
@@ -312,4 +312,8 @@ extern void LYCloselog NOPARAMS;
 #define TXT_A	"a+"
 #endif
 
+#define BIN_R	"rb"
+#define BIN_W	"wb"
+#define BIN_A	"ab+"
+
 #endif /* LYUTILS_H */
diff --git a/src/TRSTable.c b/src/TRSTable.c
index 8b752135..cb3980dc 100644
--- a/src/TRSTable.c
+++ b/src/TRSTable.c
@@ -74,6 +74,12 @@ typedef struct _STable_cellinfo {
 				   or RESERVEDCELL */
 } STable_cellinfo;
 
+enum ended_state {
+	ROW_not_ended,
+	ROW_ended_by_endtr,
+	ROW_ended_by_splitline
+};
+
 typedef struct _STable_rowinfo {
     /* Each row may be displayed on many display lines, but we fix up
        positions of cells on this display line only: */
@@ -103,6 +109,7 @@ typedef struct _STable_rowinfo {
        reset to the line of icell_core.
      */
 	BOOL	fixed_line;	/* if we have a 'core' line of cells */
+	BOOL	ended;		/* if we saw </tr> */
 	int	allocated;	/* number of table cells allocated */
 	STable_cellinfo * cells;
 	short	alignment;	/* global align attribute for this row */
@@ -620,7 +627,7 @@ PRIVATE int Stbl_finishCellInRow ARGS5(
 		  cellstate_s(s->prev_state), cellstate_s(s->state)));
 
     if (multiline) {
-	if (!end_td) {			/* processing line-break */
+	if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
 	    switch (s->state) {
 	    case CS_invalid:
 		newstate = empty ? CS_invalid : CS__cbc;
@@ -862,7 +869,7 @@ PRIVATE int Stbl_finishCellInRow ARGS5(
 	    }
 	}
     } else {				/* (!multiline) */
-	if (!end_td) {			/* processing line-break */
+	if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
 	    switch (s->state) {
 	    case CS_invalid:
 	    case CS__0new:
@@ -1218,6 +1225,7 @@ PUBLIC int Stbl_addRowToTable ARGS3(
 	me->pending_colgroup_next = 0;
     }
     me->rows[me->nrows].Line = -1; /* not yet used */
+    me->rows[me->nrows].ended = ROW_not_ended; /* No </tr> yet */
     return (me->nrows - 1);
 }
 
@@ -1236,6 +1244,7 @@ PRIVATE int Stbl_finishRowInTable ARGS1(
 	return -1;		/* no row started! */
     lastrow = me->rows + (me->nrows - 1);
     ncells = lastrow->ncells;
+    lastrow->ended = ROW_ended_by_endtr;
     if (lastrow->ncells > 0) {
 	if (s->pending_len > 0)
 	    lastrow->cells[lastrow->ncells - 1].len = s->pending_len;
@@ -1366,7 +1375,7 @@ PRIVATE int Stbl_fakeFinishCellInTable ARGS4(
 	int cs = lastrow->cells[lastrow->ncells - 1].colspan;
 	int rs = 1;			/* XXXX How to find rowspan? */
 	int ih = 0;			/* XXXX How to find is_header? */
-	int end_td = 1;
+	int end_td = (TRST_ENDCELL_ENDTD | TRST_FAKING_CELLS);
 	int need_reserved = 0;
 	int prev_reserved_last = -1;
 	STable_rowinfo *prev_row;
@@ -1421,6 +1430,7 @@ PRIVATE int Stbl_fakeFinishCellInTable ARGS4(
 					   (me->allocated_rows + 1)
 					   * sizeof(STable_rowinfo));
 	    int need_cells = prev_reserved_last + 1;
+	    int n;
 
 	    if (!rows)
 		return -1; /* ignore silently, no free memory, may be recoverable */
@@ -1433,8 +1443,8 @@ PRIVATE int Stbl_fakeFinishCellInTable ARGS4(
 	    me->allocated_rows++;
 
 	    /* Insert a duplicate row after lastrow */
-	    memmove(lastrow+1, lastrow,
-		    sizeof(STable_rowinfo)*(me->allocated_rows - me->nrows));
+	    for (n = me->allocated_rows - me->nrows - 1; n >= 0; --n)
+		lastrow[n + 1] = lastrow[n];
 
 	    /* Ignore cells, they belong to the next row now */
 	    lastrow->allocated = 0;
@@ -1515,7 +1525,9 @@ PUBLIC int Stbl_addCellToTable ARGS7(
     if (!me->rows || !me->nrows)
 	return -1;		/* no row started! */
 				/* ##850_fail_if_fail?? */
-    Stbl_finishCellInTable(me, YES, lineno, pos);
+    if (me->rows[me->nrows - 1].ended)
+	Stbl_addRowToTable(me, alignment, lineno);
+    Stbl_finishCellInTable(me, TRST_ENDCELL_ENDTD, lineno, pos);
     lastrow = me->rows + (me->nrows - 1);
 
 #ifdef EXP_NESTED_TABLES
@@ -1650,12 +1662,14 @@ PUBLIC int Stbl_finishCellInTable ARGS4(
     icell = lastrow->ncells - 1;
     if (icell < 0)
 	return icell;
-    if (s->x_td == -1)
-	return end_td ? -1 : 0;
+    if (s->x_td == -1) {	/* Stray </TD> or safety-call */
+	if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK)
+	    lastrow->ended = ROW_ended_by_splitline;
+	return 0;
+    }
 
 #ifdef EXP_NESTED_TABLES
-    /* This check for pos saves us from infinite recursion... */
-    if (!NO_AGGRESSIVE_NEWROW && pos) {
+    if (!NO_AGGRESSIVE_NEWROW && !(end_td & TRST_FAKING_CELLS)) {
 	int rc = Stbl_fakeFinishCellInTable(me, lastrow, lineno, 1);
 
 	if (rc) {
@@ -1670,7 +1684,7 @@ PUBLIC int Stbl_finishCellInTable ARGS4(
     if (len == -1)
 	return len;
     xlen = (len > 0) ? len : s->pending_len; /* ##890 use xlen if fixed_line?: */
-    if (lastrow->fixed_line && lastrow->Line == lineno)
+    if (lastrow->Line == lineno)
 	len = xlen;
     if (lastrow->cells[icell].colspan > 1) {
 	/*
@@ -1758,7 +1772,12 @@ PUBLIC int Stbl_finishCellInTable ARGS4(
     }
 #endif
 
-#ifndef EXP_NESTED_TABLES /* maxlen may already include contribution of a cell in this column */
+    if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK)
+	lastrow->ended = ROW_ended_by_splitline;
+#ifdef EXP_NESTED_TABLES /* maxlen may already include contribution of a cell in this column */
+    if (me->maxlen > MAX_STBL_POS)
+	return -1;
+#else
     if (me->maxlen + (xlen - len) > MAX_STBL_POS)
 	return -1;
 #endif
@@ -1996,6 +2015,16 @@ PUBLIC int Stbl_getStartLine ARGS1(
 
 #ifdef EXP_NESTED_TABLES
 
+PUBLIC int Stbl_getStartLineDeep ARGS1(
+    STable_info *,	me)
+{
+    if (!me)
+	return -1;
+    while (me->enclosing)
+	me = me->enclosing;
+    return me->startline;
+}
+
 PUBLIC void Stbl_update_enclosing ARGS3(
     STable_info *,	me,
     int,		max_width,
@@ -2009,7 +2038,7 @@ PUBLIC void Stbl_update_enclosing ARGS3(
 	    max_width, me->startline, last_lineno));
     for (l = me->startline; l <= last_lineno; l++) {
 	/* Fake <BR> in appropriate positions */
-	if (Stbl_finishCellInTable(me->enclosing, 0, l, max_width) < 0) {
+	if (Stbl_finishCellInTable(me->enclosing, TRST_ENDCELL_LINEBREAK, l, max_width) < 0) {
 	    /* It is not handy to let the caller delete me->enclosing,
 	       and it does not buy us anything.  Do it directly. */
 	    STable_info *stbl = me->enclosing;
diff --git a/src/TRSTable.h b/src/TRSTable.h
index 5eb48ce5..02463640 100644
--- a/src/TRSTable.h
+++ b/src/TRSTable.h
@@ -15,7 +15,13 @@ 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)
+
+#define TRST_ENDCELL_ENDTD	1
+#define TRST_ENDCELL_LINEBREAK	0
+#define TRST_ENDCELL_MASK	1
+#define TRST_FAKING_CELLS	2
+#define Stbl_lineBreak(stbl,l,pos) Stbl_finishCellInTable(stbl, TRST_ENDCELL_LINEBREAK, l, pos)
+
 extern int Stbl_getStartLine PARAMS((STable_info *));
 extern int Stbl_getFixupPositions PARAMS((
     STable_info *	me,
@@ -35,6 +41,9 @@ extern void Stbl_set_enclosing PARAMS(( STable_info *me,
 					struct _TextAnchor *last_anchor));
 extern STable_info * Stbl_get_enclosing PARAMS((STable_info *	me));
 extern struct _TextAnchor * Stbl_get_last_anchor_before PARAMS((STable_info *	me));
+extern int Stbl_getStartLineDeep PARAMS((STable_info *));
+#else
+#define Stbl_getStartLineDeep(t) Stbl_getStartLine(t)
 #endif
 
 #endif /* TRSTABLE_H */
diff --git a/src/UCAuto.c b/src/UCAuto.c
index e37944ff..fec1b052 100644
--- a/src/UCAuto.c
+++ b/src/UCAuto.c
@@ -210,10 +210,10 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(
     } else if (lastcs < 0 && old_umap == 0 && old_font == 0) {
 	FILE * fp1;
 	FILE * fp2 = NULL;
-	if ((old_font = calloc(1, LY_MAXPATH)))
-	    old_umap = calloc(1, LY_MAXPATH);
-	if ((fp1 = LYOpenTemp(old_font, ".fnt", "wb")))
-	    fp2 = LYOpenTemp(old_umap, ".uni", "wb");
+	if ((old_font = typecallocn(char, LY_MAXPATH)))
+	    old_umap = typecallocn(char, LY_MAXPATH);
+	if ((fp1 = LYOpenTemp(old_font, ".fnt", BIN_W)))
+	    fp2 = LYOpenTemp(old_umap, ".uni", BIN_W);
 	if (fp1 && fp2) {
 	    size_t nlen;
 	    char *rp;
@@ -543,7 +543,7 @@ PRIVATE int _Switch_Display_Charset ARGS2 (int, ord, int, really)
 {
     CONST char *name;
     unsigned short cp;
-    static int font_loaded_for = -1;
+    static int font_loaded_for = -1, old_h, old_w;
     int rc, ord1;
     UCHAR msgbuf[MAXPATHLEN + 80];
 
@@ -581,10 +581,7 @@ PRIVATE int _Switch_Display_Charset ARGS2 (int, ord, int, really)
     }
 
     /* Not a "prepared" codepage.  Need to load the user font. */
-    if (ord1 == font_loaded_for) {	/* The same as the previous font */
-	if ((rc = VioSetCp(0, -1, 0)))	/* -1: User font */
-	    goto err;
-    } else if (charsets_directory) {
+    if (charsets_directory) {
 	TIB *tib;			/* Can't load font in a windowed-VIO */
 	PIB *pib;
 	VIOFONTINFO f[2];
@@ -597,7 +594,8 @@ PRIVATE int _Switch_Display_Charset ARGS2 (int, ord, int, really)
 	long i, j;
 
 	/* 0 means a FS protected-mode session */
-	if (DosGetInfoBlocks(&tib, &pib) || pib->pib_ultype != 0) {
+	if ( font_loaded_for == -1		/* Did not try it yet */
+	     && (DosGetInfoBlocks(&tib, &pib) || pib->pib_ultype != 0) ) {
 	    ord = ord1 = auto_display_charset;
 	    goto retry;
 	}
@@ -619,9 +617,16 @@ PRIVATE int _Switch_Display_Charset ARGS2 (int, ord, int, really)
 	    ord = ord1 = auto_display_charset;
 	    goto retry;
 	}
+	if ( ord1 == font_loaded_for
+	     && old_h == font->cyCell && old_w == font->cxCell ) {
+	    /* The same as the previous font */
+	    if ((rc = VioSetCp(0, -1, 0)))	/* -1: User font */
+		goto err;
+	    goto report;
+	}
 	sprintf(fnamebuf, "%s/%dx%d/%s.fnt",
 		charsets_directory, font->cyCell, font->cxCell, name);
-	file = fopen(fnamebuf,"rb");
+	file = fopen(fnamebuf, BIN_R);
 	if (!file) {
 	    sprintf(msgbuf, "Can't open font file '%s'", fnamebuf);
 	    HTInfoMsg(msgbuf);
@@ -645,9 +650,12 @@ PRIVATE int _Switch_Display_Charset ARGS2 (int, ord, int, really)
 	    sprintf(msgbuf, "Can't set font: err=%#lx=%ld", rc, rc);
 	    HTInfoMsg(msgbuf);
 	    ord = ord1 = auto_display_charset;
+	    font_loaded_for = -1;
 	    goto retry;
 	}
 	font_loaded_for = ord1;
+	old_h = font->cyCell;
+	old_w = font->cxCell;
     }
   report:
     CTRACE((tfp, "Display font set to '%s'.\n", name));
diff --git a/src/Xsystem.c b/src/Xsystem.c
index 56cac70d..969f90d5 100644
--- a/src/Xsystem.c
+++ b/src/Xsystem.c
@@ -1,4 +1,4 @@
-/* @Id: Xsystem.c 1.9 Mon, 26 Feb 2001 18:41:57 -0800 dickey @
+/* @Id: Xsystem.c 1.10 Sun, 01 Apr 2001 17:51:46 -0700 dickey @
  *	like system("cmd") but return with exit code of "cmd"
  *	for Turbo-C/MS-C/LSI-C
  *  This code is in the public domain.
@@ -86,7 +86,7 @@ xmalloc(size_t n)
 {
     char *bp;
 
-    if ((bp = calloc(1, n)) == (char *) 0) {
+    if ((bp = typecallocn(char, n)) == 0) {
 	write(2, "xsystem: Out of memory.!\n", 25);
 	exit(1);
     }
diff --git a/src/chrtrans/makefile.in b/src/chrtrans/makefile.in
index 52cf5524..d399a0e5 100644
--- a/src/chrtrans/makefile.in
+++ b/src/chrtrans/makefile.in
@@ -29,6 +29,7 @@ SITE_DEFS	= # FIXME: set in parent makefile
 CC		= @CC@
 CPP		= @CPP@
 CFLAGS		= @CFLAGS@
+_O		= .o
 
 CPP_OPTS	= @DEFS@ @CPPFLAGS@ \
 		-I$(top_builddir) \
@@ -93,14 +94,14 @@ default: $(FONTMAP_INC)
 
 tables: $(TABLES)
 
-makeuctb$x: makeuctb.o
-	$(CC) $(CC_OPTS) $(LDFLAGS) -o $@ makeuctb.o $(INTLLIB) $(LIBS)
+makeuctb$x: makeuctb$(_O)
+	$(CC) $(CC_OPTS) $(LDFLAGS) -o $@ makeuctb$(_O) $(INTLLIB) $(LIBS)
 
-makeuctb.o: $(srcdir)/UCkd.h $(srcdir)/makeuctb.c
+makeuctb$(_O): $(srcdir)/UCkd.h $(srcdir)/makeuctb.c
 
-.SUFFIXES : .tbl .i
+.SUFFIXES : $(_O) .tbl .i
 
-.c.o:
+.c$(_O):
 @RULE_CC@
 	@ECHO_CC@$(CC) $(CC_OPTS) -c $(srcdir)/$*.c
 
@@ -155,7 +156,7 @@ utf8_uni.h:		$(srcdir)/utf8_uni.tbl		makeuctb$x
 viscii_uni.h:		$(srcdir)/viscii_uni.tbl	makeuctb$x
 
 clean:
-	rm -f makeuctb$x *.o *uni.h *uni2.h
+	rm -f makeuctb$x *$(_O) *uni.h *uni2.h
 
 distclean: clean
 	-rm -rf obsolete
diff --git a/src/makefile.dos b/src/makefile.dos
index 7c29b2c2..880c151a 100644
--- a/src/makefile.dos
+++ b/src/makefile.dos
@@ -22,9 +22,7 @@ DIRED_DEFS = \
 
 # Use this option to enable optional and *experimental* color style.
 #ENABLE_COLOR_STYLE = \
- -DUSE_COLOR_STYLE \
- -DUSE_HASH \
- -DLINKEDSTYLES
+ -DUSE_COLOR_STYLE
 
 CC = gcc
 
diff --git a/src/makefile.in b/src/makefile.in
index f76c6bef..36bdb424 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -24,6 +24,7 @@ CFLAGS		= @CFLAGS@
 DEFS		= @DEFS@
 CHARSET_DEFS	= @CHARSET_DEFS@
 CPPFLAGS	= @CPPFLAGS@
+_O		= .o
 
 LIBS		= @LIBS@ $(RESOLVLIB) $(WAISLIB) $(SITE_LIBS)
 LDFLAGS		= @LDFLAGS@
@@ -58,24 +59,26 @@ LINTOPTS	=
 COMPRESS_PROG	=@COMPRESS_PROG@
 COMPRESS_EXT	=@COMPRESS_EXT@
 
-CHARTRANS_OBJS=UCdomap.o UCAux.o UCAuto.o
-OBJS=  LYClean.o LYShowInfo.o LYEdit.o LYStrings.o \
-LYMail.o HTAlert.o GridText.o LYGetFile.o \
-LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYUtils.o \
-LYOptions.o LYReadCFG.o LYSearch.o LYHistory.o \
-LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \
-HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYUpload.o \
-LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \
-LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o \
-LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o $(CHARTRANS_OBJS) @LIBOBJS@
-
-C_SRC	= $(OBJS:.o=.c)
+CHARTRANS_OBJS	= UCdomap$(_O) UCAux$(_O) UCAuto$(_O)
+OBJS	= \
+	LYClean$(_O) LYShowInfo$(_O) LYEdit$(_O) LYStrings$(_O) LYMail$(_O) \
+	HTAlert$(_O) GridText$(_O) LYGetFile$(_O) LYMain$(_O) LYMainLoop$(_O) \
+	LYCurses$(_O) LYBookmark$(_O) LYUtils$(_O) LYOptions$(_O) \
+	LYReadCFG$(_O) LYSearch$(_O) LYHistory$(_O) LYForms$(_O) LYPrint$(_O) \
+	LYrcFile$(_O) LYDownload$(_O) LYNews$(_O) LYKeymap$(_O) HTML$(_O) \
+	HTFWriter$(_O) HTInit$(_O) DefaultStyle$(_O) LYUpload$(_O) \
+	LYLeaks$(_O) LYexit$(_O) LYJump$(_O) LYList$(_O) LYCgi$(_O) \
+	LYTraversal$(_O) LYEditmap$(_O) LYCharSets$(_O) LYCharUtils$(_O) \
+	LYMap$(_O) LYCookie$(_O) LYStyle$(_O) LYHash$(_O) LYPrettySrc$(_O) \
+	TRSTable$(_O) $(CHARTRANS_OBJS) @LIBOBJS@
+
+C_SRC	= $(OBJS:$(_O)=.c)
 
 all: lynx$x
 
-.SUFFIXES : .i
+.SUFFIXES : $(_O) .i
 
-.c.o:
+.c$(_O):
 @RULE_CC@
 	@ECHO_CC@$(CC) $(CC_OPTS) -c $(srcdir)/$*.c
 
@@ -112,21 +115,21 @@ 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
-LYGetFile.o:	$(top_srcdir)/userdefs.h
-LYKeymap.o:	$(top_srcdir)/userdefs.h
-LYMail.o:	$(top_srcdir)/userdefs.h
-LYMain.o:	$(top_srcdir)/userdefs.h $(top_builddir)/lynx_cfg.h
-LYMainLoop.o:	$(top_srcdir)/userdefs.h
-LYOptions.o:	$(top_srcdir)/userdefs.h
-LYReadCFG.o:	$(top_srcdir)/userdefs.h
-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
+HTFWriter$(_O):		$(top_srcdir)/userdefs.h
+HTInit$(_O):		$(top_srcdir)/userdefs.h
+LYCharSets$(_O):	$(top_srcdir)/userdefs.h
+LYGetFile$(_O):		$(top_srcdir)/userdefs.h
+LYKeymap$(_O):		$(top_srcdir)/userdefs.h
+LYMail$(_O):		$(top_srcdir)/userdefs.h
+LYMain$(_O):		$(top_srcdir)/userdefs.h $(top_builddir)/lynx_cfg.h
+LYMainLoop$(_O):	$(top_srcdir)/userdefs.h
+LYOptions$(_O):		$(top_srcdir)/userdefs.h
+LYReadCFG$(_O):		$(top_srcdir)/userdefs.h
+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/
 
@@ -173,14 +176,14 @@ TABLES= \
 $(TABLES):
 	-cd chrtrans && $(MAKE) tables
 
-UCdomap.o: UCdomap.c chrtrans/UCkd.h chrtrans/makeuctb$x chrtrans/makeuctb.c \
+UCdomap$(_O): UCdomap.c chrtrans/UCkd.h chrtrans/makeuctb$x chrtrans/makeuctb.c \
 	UCdomap.h $(CMN)UCMap.h $(TABLES) $(top_srcdir)/userdefs.h
 
 chrtrans/makeuctb$x:
 	cd chrtrans; make makeuctb$x
 
-UCAux.o : UCAux.c $(CMN)UCAux.h $(CMN)UCDefs.h
-LYCookie.o: $(top_srcdir)/userdefs.h
+UCAux$(_O) : UCAux.c $(CMN)UCAux.h $(CMN)UCDefs.h
+LYCookie$(_O): $(top_srcdir)/userdefs.h
 
 depend : $(TABLES)
 	makedepend -fmakefile -- $(CC_OPTS) -- $(C_SRC)