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.c1935
-rw-r--r--src/GridText.h21
-rw-r--r--src/HTAlert.c112
-rw-r--r--src/HTAlert.h5
-rw-r--r--src/HTFWriter.c36
-rw-r--r--src/HTML.c1135
-rw-r--r--src/HTML.h1
-rw-r--r--src/LYBookmark.c2
-rw-r--r--src/LYCharSets.c104
-rw-r--r--src/LYCharUtils.c822
-rw-r--r--src/LYCharUtils.h24
-rw-r--r--src/LYCookie.c1472
-rw-r--r--src/LYCookie.h3
-rw-r--r--src/LYCurses.c163
-rw-r--r--src/LYCurses.h168
-rw-r--r--src/LYDownload.c200
-rw-r--r--src/LYEdit.c181
-rw-r--r--src/LYExtern.c2
-rw-r--r--src/LYExtern.h10
-rw-r--r--src/LYForms.c848
-rw-r--r--src/LYGetFile.c90
-rw-r--r--src/LYGlobalDefs.h10
-rw-r--r--src/LYHash.c17
-rw-r--r--src/LYHash.h2
-rw-r--r--src/LYHistory.c62
-rw-r--r--src/LYLeaks.c1
-rw-r--r--src/LYList.c121
-rw-r--r--src/LYLocal.c2439
-rw-r--r--src/LYMail.c36
-rw-r--r--src/LYMain.c463
-rw-r--r--src/LYMainLoop.c365
-rw-r--r--src/LYMap.c12
-rw-r--r--src/LYNews.c141
-rw-r--r--src/LYOptions.c1896
-rw-r--r--src/LYOptions.h15
-rw-r--r--src/LYPrint.c120
-rw-r--r--src/LYReadCFG.c9
-rw-r--r--src/LYSearch.c14
-rw-r--r--src/LYShowInfo.c42
-rw-r--r--src/LYStrings.c586
-rw-r--r--src/LYStrings.h18
-rw-r--r--src/LYStructs.h8
-rw-r--r--src/LYTraversal.c5
-rw-r--r--src/LYUpload.c1
-rw-r--r--src/LYUtils.c2136
-rw-r--r--src/LYUtils.h4
-rw-r--r--src/LYrcFile.c59
-rw-r--r--src/UCAuto.c236
-rw-r--r--src/UCAuto.h8
-rw-r--r--src/UCAux.c163
-rw-r--r--src/UCdomap.c808
-rw-r--r--src/UCdomap.h33
-rw-r--r--src/chrtrans/README.tables20
-rw-r--r--src/chrtrans/UCkd.h21
-rw-r--r--src/chrtrans/build-chrtrans.com125
-rw-r--r--src/chrtrans/build-header.com37
-rw-r--r--src/chrtrans/makeuctb.c883
-rw-r--r--src/chrtrans/mnemonic_suni.tbl2
-rw-r--r--src/descrip.mms6
59 files changed, 13173 insertions, 5085 deletions
diff --git a/src/GridText.c b/src/GridText.c
index 179cbeed..f7b46419 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -4,13 +4,7 @@
 
 #include "HTUtils.h"
 #include "tcp.h"
-
-#include "LYCurses.h" /* lynx defined curses */
-
-#include <assert.h>
-#include <ctype.h>
 #include "HTString.h"
-#include "GridText.h"
 #include "HTFont.h"
 #include "HTAccess.h"
 #include "HTAnchor.h"
@@ -18,8 +12,19 @@
 #include "HTTP.h"
 #include "HTAlert.h"
 #include "HTCJK.h"
+#include "UCDefs.h"
+#include "UCAux.h"
+
+#include <assert.h>
+#include <ctype.h>
+#ifndef VMS
+#ifdef SYSLOG_REQUESTED_URLS
+#include <syslog.h>
+#endif /* SYSLOG_REQUESTED_URLS */
+#endif /* !VMS */
 
-/* lynx specific defines */
+#include "GridText.h"
+#include "LYCurses.h"
 #include "LYUtils.h"
 #include "LYStrings.h"
 #include "LYStructs.h"
@@ -39,17 +44,12 @@
 
 #include "LYexit.h"
 #include "LYLeaks.h"
-#ifndef VMS
-#ifdef SYSLOG_REQUESTED_URLS
-#include <syslog.h>
-#endif /* SYSLOG_REQUESTED_URLS */
-#endif /* !VMS */
 
 #ifdef USE_COLOR_STYLE
 #include "AttrList.h"
 #include "LYHash.h"
 
-unsigned cached_styles[CACHEH][CACHEW];
+unsigned int cached_styles[CACHEH][CACHEW];
 
 #endif
 
@@ -71,6 +71,8 @@ struct _HTStream {                      /* only know it as object */
 };
 
 #define TITLE_LINES  1
+#define IS_UTF_EXTRA(ch) (text->T.output_utf8 && \
+			  ((unsigned char)(ch)&0xc0) == 0x80)
 
 #define FREE(x) if (x) {free(x); x = NULL;}
 
@@ -147,6 +149,7 @@ typedef struct _TextAnchor {
 	int			link_type;	/* Normal, internal, or form? */
 	FormInfo *		input_field;	/* Info for form links */
 	BOOL			show_anchor;	/* Show the anchor? */
+	BOOL			inUnderline;	/* context is underlined */
 	HTChildAnchor *		anchor;
 } TextAnchor;
 
@@ -196,14 +199,15 @@ struct _HText {
 	char			kanji_buf;		/* Lead multibyte */
 	int			in_sjis;		/* SJIS flag */
 
-	HTStream*		target; 		/* Output stream */
-	HTStreamClass		targetClass;		/* Output routines */
 #ifdef EXP_CHARTRANS
-	LYUCcharset	* UCI;	/* pointer to node_anchor's UCInfo */
-	int	UCLYhndl;	/* tells us what charset we are fed */
-	UCTransParams T;
-	BOOL 	have_8bit_chars;	/* Any non-ASCII characters? */
+	BOOL			have_8bit_chars;   /* Any non-ASCII chars? */
+	LYUCcharset *		UCI;		   /* node_anchor UCInfo */
+	int			UCLYhndl;	   /* charset we are fed */
+	UCTransParams		T;
 #endif
+
+        HTStream *		target;                 /* Output stream */
+        HTStreamClass		targetClass;            /* Output routines */
 };
 
 PRIVATE void HText_AddHiddenLink PARAMS((HText *text, TextAnchor *textanchor));
@@ -235,20 +239,24 @@ PRIVATE HTStyle default_style =
 PRIVATE HTList * loaded_texts = NULL;	 /* A list of all those in memory */
 PUBLIC  HTList * search_queries = NULL;  /* isindex and whereis queries   */
 PRIVATE void free_all_texts NOARGS;
-PRIVATE int HText_TrueLineSize PARAMS((HTLine *line, HText *text));
+PRIVATE int HText_TrueLineSize PARAMS((
+	HTLine *	line,
+	HText *		text,
+	BOOL		IgnoreSpaces));
 
 #ifdef EXP_CHARTRANS
-PRIVATE void htext_get_chartrans_info ARGS1(HText *, me)
+PRIVATE void HText_getChartransInfo ARGS1(
+	HText *,	me)
 {
-    me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_HTEXT);
+    me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT);
     if (me->UCLYhndl < 0) {
 	int chndl = current_char_set;
-	HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_HTEXT,
-				UCT_SETBY_STRUCTURED);
+	HTAnchor_setUCInfoStage(me->node_anchor, chndl,
+				UCT_STAGE_HTEXT, UCT_SETBY_STRUCTURED);
 	me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
 					    UCT_STAGE_HTEXT);
     }
-    me->UCI = HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_HTEXT);
+    me->UCI = HTAnchor_getUCInfoStage(me->node_anchor, UCT_STAGE_HTEXT);
 }
 #endif /* EXP_CHARTRANS */
 
@@ -348,10 +356,9 @@ PUBLIC HText *	HText_new ARGS1(
     self->kanji_buf = '\0';
     self->in_sjis = 0;
     self->have_8bit_chars = NO;
-
 #ifdef EXP_CHARTRANS
-	htext_get_chartrans_info(self);
-	UCSetTransParams(&self->T,
+    HText_getChartransInfo(self);
+    UCSetTransParams(&self->T,
 		     self->UCLYhndl, self->UCI,
 		     current_char_set,
 		     &LYCharSet_UC[current_char_set]);
@@ -529,7 +536,8 @@ PUBLIC void HText_free ARGS1(
 #endif /* EXP_CHARTRANS */
         if (HTAnchor_delete(self->node_anchor))
 	    /*
-	     * Make sure HTMainAnchor won't point to an invalid structure. - kw
+	     *  Make sure HTMainAnchor won't point
+	     *  to an invalid structure. - KW
 	     */
 	    HTMainAnchor = NULL;
     }
@@ -549,7 +557,7 @@ PRIVATE int display_line ARGS2(
 	HTLine *,	line,
 	HText *,	text)
 {
-    register int i,j;
+    register int i, j;
     char buffer[7];
     char *data;
 #ifdef EXP_CHARTRANS
@@ -557,14 +565,21 @@ PRIVATE int display_line ARGS2(
 #endif
 #ifdef USE_COLOR_STYLE
     int current_style = 0;
-    int real_position = 0;
 #endif
+    char LastDisplayChar = ' ';
 
+    /*
+     *  Set up the multibyte character buffer,
+     *  and clear the line to which we will be
+     *  writing.
+     */
     buffer[0] = buffer[1] = buffer[2] = '\0';
     clrtoeol();
-    /* make sure that we don't go over the COLS limit on the display! */
 
-    /* add offset */
+    /*
+     *  Add offset, making sure that we do not
+     *  go over the COLS limit on the display.
+     */
     j = (int)line->offset;
     if (j > (int)LYcols - 1)
         j = (int)LYcols - 1;
@@ -572,16 +587,21 @@ PRIVATE int display_line ARGS2(
     SLsmg_forward (j);
     i = j;
 #else
+#ifdef USE_COLOR_STYLE
+    if (line->size == 0)
+	i = j;
+    else
+#endif
     for (i = 0; i < j; i++)
         addch (' ');
 #endif /* USE_SLANG */
 
-    /* add data */
+    /*
+     *  Add the data, making sure that we do not
+     *  go over the COLS limit on the display.
+     */
     data = line->data;
     i++;
-#ifdef USE_COLOR_STYLE
-    real_position = i;
-#endif
     while ((i < LYcols) && ((buffer[0] = *data) != '\0')) {
 	data++;
 
@@ -600,7 +620,7 @@ PRIVATE int display_line ARGS2(
 #ifndef USE_COLOR_STYLE
 	    case LY_UNDERLINE_START_CHAR:
 	        if (dump_output_immediately && use_underscore) {
-		    addch ('_');
+		    addch('_');
 		    i++;
 		} else {
 		    lynx_start_underline_color ();
@@ -609,7 +629,7 @@ PRIVATE int display_line ARGS2(
 
 	    case LY_UNDERLINE_END_CHAR:
 	        if (dump_output_immediately && use_underscore) {
-		    addch ('_');
+		    addch('_');
 		    i++;
 		} else {
 		    lynx_stop_underline_color ();
@@ -626,10 +646,18 @@ PRIVATE int display_line ARGS2(
 #endif
 
 	    case LY_SOFT_HYPHEN:
-	        if (*data != '\0') {
+	        if (*data != '\0' ||
+		    isspace((unsigned char)LastDisplayChar) ||
+		    LastDisplayChar == '-') {
 		    /*
-		     *  Ignore the soft hyphen if it is not
-		     *  the last character in the line. - FM
+		     *  Ignore the soft hyphen if it is not the last
+		     *  character in the line.  Also ignore it if it
+		     *  first character following the margin, or if it
+		     *  is preceded by a white character (we loaded 'M'
+		     *  into LastDisplayChar if it was a multibyte
+		     *  character) or hyphen, though it should have
+		     *  been excluded by HText_appendCharacter() or by
+		     *  split_line() in those cases. - FM
 		     */
 		    break;
 		} else {
@@ -643,46 +671,70 @@ PRIVATE int display_line ARGS2(
 	    default:
 		    i++;
 #ifdef EXP_CHARTRANS
-		    if (text->T.output_utf8 && !isascii(buffer[0])) {
-			if ((*buffer & 0xe0) == 0xc0) {
-			    utf_extra = 1;
-			} else if ((*buffer & 0xf0) == 0xe0) {
-			    utf_extra = 2;
-			} else if ((*buffer & 0xf8) == 0xf0) {
-			    utf_extra = 3;
-			} else if ((*buffer & 0xfc) == 0xf8) {
-			    utf_extra = 4;
-			} else if ((*buffer & 0xfe) == 0xfc) {
-			    utf_extra = 5;
-			} else { /* garbage */
-			    utf_extra = 0;
-			}
-			if (strlen(data) < utf_extra)
-			    utf_extra = 0; /* shouldn't happen */
+		if (text->T.output_utf8 && !isascii(buffer[0])) {
+		    if ((*buffer & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*buffer & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*buffer & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*buffer & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*buffer & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			 /*
+			  *  Garbage.
+			  */
+			utf_extra = 0;
 		    }
-		    if (utf_extra) {
-			strncpy(&buffer[1], data, utf_extra);
-			buffer[utf_extra+1] = '\0';
-			addstr(buffer);
-			buffer[1] = '\0';
-			data += utf_extra;
+		    if (strlen(data) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
 			utf_extra = 0;
-		    } else
+		    }
+		    LastDisplayChar = 'M';
+		}
+		if (utf_extra) {
+		    strncpy(&buffer[1], data, utf_extra);
+		    buffer[utf_extra+1] = '\0';
+		    addstr(buffer);
+		    buffer[1] = '\0';
+		    data += utf_extra;
+		    utf_extra = 0;
+		} else
 #endif /* EXP_CHARTRANS */
-		/* For CJK strings, by Masanobu Kimura */
-		if (HTCJK != NOCJK && !isascii(buffer[0])) { 
+		    if (HTCJK != NOCJK && !isascii(buffer[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
 		    buffer[1] = *data;
 		    data++;
-		    i++;
 		    addstr(buffer);
 		    buffer[1] = '\0';
+		    /*
+		     *  For now, load 'M' into LastDisplayChar,
+		     *  but we should check whether it's white
+		     *  and if so, use ' '.  I don't know if
+		     *  there actually are white CJK characters,
+		     *  and we're loading ' ' for multibyte
+		     *  spacing characters in this code set,
+		     *  but this will become an issue when
+		     *  the development code set's multibyte
+		     *  character handling is used. - FM
+		     */
+		    LastDisplayChar = 'M';
 		} else {
 		    addstr(buffer);
+		    LastDisplayChar = buffer[0];
 		}
 	} /* end of switch */
     } /* end of while */
 
-    /* add the return */
+    /*
+     *  Add the return.
+     */
     addch('\n');
 
 #ifndef USE_COLOR_STYLE
@@ -707,9 +759,6 @@ PRIVATE void display_title ARGS1(
 {
     char *title = NULL;
     char percent[20];
-#ifdef NOTDEFINED
-    char format[20];
-#endif
     char *cp = NULL;
     unsigned char *tmp = NULL;
     int i = 0, j = 0;
@@ -721,6 +770,10 @@ PRIVATE void display_title ARGS1(
         return;
 
     lynx_start_title_color ();
+#ifdef USE_COLOR_STYLE 
+/* turn the TITLE style on */
+    LynxChangeStyle(s_title, ABS_ON, 0);
+#endif /* USE_COLOR_STYLE */
 
     /*
      *  Load the title field. - FM
@@ -731,10 +784,14 @@ PRIVATE void display_title ARGS1(
 
     /*
      *  There shouldn't be any \n in the title field,
-     *  but if there is, lets kill it now!
+     *  but if there is, lets kill it now.  Also trim
+     *  any trailing spaces. - FM
      */
     if ((cp = strchr(title,'\n')) != NULL)
 	*cp = '\0';
+    i = (*title ? (strlen(title) - 1) : 0);
+    while ((i >= 0) && title[i] == ' ')
+	title[i--] = '\0';
 
     /*
      *  Generate the page indicator (percent) string.
@@ -759,31 +816,14 @@ PRIVATE void display_title ARGS1(
 	            ((text->top_of_screen + display_lines)/(display_lines))),
 		total_pages);
     } else {
-	strcpy(percent, "");	/* Null string */
+	percent[0] = '\0';	/* Null string */
     }
 
     /*
-     *  Generate format string.
+     *  Generate and display the title string, with page indictator
+     *  if appropriate, preceded by the toolbar token if appropriate,
+     *  and truncated if necessary. - FM & KW
      */
-#ifdef NOTDEFINED
-    /* Using this kind of format string, sprintf() didn't always get it
-       right at least on solaris if the title string contained some 8-bit 
-       characters.  - kw
-       */
-    sprintf(format, "%s%%%d.%ds%%s\n",
-    		    ((text->top_of_screen > 0 &&
-		      HText_hasToolbar(text)) ?
-		      			  "#" : " "),
-		    (LYcols-2)-strlen(percent),
-		    (LYcols-2)-strlen(percent));
-#endif /* NOTDEFINED */
-
-    /*
-     *  Generate and display the complete title string.
-     */
-    cp = (char *)calloc(1, (LYcols * 2));
-    if (cp == NULL)
-        outofmem(__FILE__, "display_title");
     if (HTCJK != NOCJK) {
         if (*title &&
 	    (tmp = (unsigned char *)calloc(1, (strlen(title) + 1)))) {
@@ -797,44 +837,44 @@ PRIVATE void display_title ARGS1(
 		        tmp[j++] = title[i];
 		    }
 		}
+		tmp[j] = '\0';
 	    }
 	    FREE(title);
-	    title = tmp;
+	    title = (char *)tmp;
         }
     }
-
-    move(0,0);
+    move(0, 0);
     clrtoeol();
     if (text->top_of_screen > 0 && HText_hasToolbar(text)) {
 	addch('#');
     }
-
-    i = (LYcols-2)-strlen(percent);
-    if ((i = (LYcols-1) - strlen(percent) - strlen(title)) > 0) {
-	move(0,i);
+    i = (LYcols - 1) - strlen(percent) - strlen(title);
+    if (i > 0) {
+	move(0, i);
     } else {
-	title[LYcols - 2 - strlen(percent)] = '\0';
-	move(0,1);
+        /*
+	 *  Note that this truncation is not taking into
+	 *  account the possibility that multibyte
+	 *  characters might be present. - FM
+	 */
+	title[((LYcols - 2) - strlen(percent))] = '\0';
+	move(0, 1);
     }
-    sprintf(cp, "%s%s\n", title, percent);
-#ifdef USE_COLOR_STYLE 
-/* turn the TITLE style on */
-    LynxChangeStyle(s_title, ABS_ON, 0);
-    addstr(cp);
-/* turn the TITLE style off */
-    LynxChangeStyle(s_title, ABS_OFF, 0);
-#else
-    addstr(cp);
-#endif
-    FREE(cp);
+    addstr(title);
+    if (percent[0] != '\0')
+        addstr(percent);
+    addch('\n');
     FREE(title);
    
+#ifdef USE_COLOR_STYLE
+/* turn the TITLE style off */
+    LynxChangeStyle(s_title, ABS_OFF, 0);
+#endif /* USE_COLOR_STYLE */
     lynx_stop_title_color ();
 
     return;
 }
 
-
 /*	Output a page
 **	-------------
 */
@@ -853,12 +893,7 @@ PRIVATE void display_page ARGS3(
     HTAnchor *link_dest, *link_dest_intl = NULL;
     static int last_nlinks = 0;
 #ifdef EXP_CHARTRANS
-    int utf_found = 0;
-#ifdef EXP_CHARTRANS_AUTOSWITCH
-#ifdef LINUX
     static int charset_last_displayed = -1;
-#endif
-#endif
 #endif /* EXP_CHARTRANS */
 
     lynx_mode = NORMAL_LYNX_MODE;
@@ -882,7 +917,7 @@ PRIVATE void display_page ARGS3(
 
     tmp[0] = tmp[1] = tmp[2] = '\0';
     text->page_has_target = NO;
-    last_screen = text->Lines - (display_lines-2);
+    last_screen = text->Lines - (display_lines - 2);
     line = text->last_line->prev;
 
     /*
@@ -901,21 +936,26 @@ PRIVATE void display_page ARGS3(
 	assert(line->next != NULL);
 
 #ifdef EXP_CHARTRANS
-#ifdef EXP_CHARTRANS_AUTOSWITCH
-#ifdef LINUX
     if (LYlowest_eightbit[current_char_set] <= 255 &&
 	(current_char_set != charset_last_displayed) &&
-	/* current_char_set has changed since last invocation,
-	   and it's not just 7-bit.
-	   Also we don't want to do this for -dump and -source etc. */
+	/*
+	 *  current_char_set has changed since last invocation,
+	 *  and it's not just 7-bit.
+	 *  Also we don't want to do this for -dump and -source etc.
+	 */
 	LYCursesON) {
 	charset_last_displayed = current_char_set;
+#ifdef EXP_CHARTRANS_AUTOSWITCH
+#ifdef LINUX
+	/*
+	 *  Currently implemented only for LINUX
+	 */
 	stop_curses();
 	if (LYTraceLogFP)
 	    /*
 	     *  Set stderr back to its original value,
 	     *  because the current UCChangeTerminalCodepage()
-	     *  writes escape sequences to stderr. - kw
+	     *  writes escape sequences to stderr. - KW
 	     */
 	    *stderr = LYOrigStderr;
 	UCChangeTerminalCodepage(current_char_set,
@@ -926,9 +966,10 @@ PRIVATE void display_page ARGS3(
 	     */
 	    *stderr = *LYTraceLogFP;
 	start_curses();
-    }
 #endif /* LINUX */
 #endif /* EXP_CHARTRANS_AUTOSWITCH */
+    }
+
 #endif /* EXP_CHARTRANS */
 
     /*
@@ -947,163 +988,216 @@ PRIVATE void display_page ARGS3(
     display_flag=TRUE;
     
     /*
-     *  Print it.
+     *  Output the page.
      */
     if (line) {
-      for (i = 0; i < (display_lines); i++)  {
+	char *data;
+	int offset, LineOffset, HitOffset, LenNeeded;
+	for (i = 0; i < (display_lines); i++)  {
+	    /*
+	     *  Verify and display each line.
+	     */
+	    assert(line != NULL);
+	    display_line(line, text);
+
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+	    /*
+	     *  If the target is on this line, recursively
+	     *  seek and emphasize it. - FM
+	     */
+	    data = (char *)line->data;
+	    offset = (int)line->offset;
+	    while ((target && *target) &&
+		   (case_sensitive ?
+		    (cp = LYno_attr_mbcs_strstr(data,
+						target,
 #ifdef EXP_CHARTRANS
-	  int len_needed;
+						text->T.output_utf8,
+#else
+						NO,
 #endif /* EXP_CHARTRANS */
-
-        assert(line != NULL);
-        display_line(line, text);
-
-        /*
-	 *  If the target is on this line, underline it.
-	 */
-        if (strlen(target) > 0 &&
+						&HitOffset,
+						&LenNeeded)) != NULL :
+		    (cp = LYno_attr_mbcs_case_strstr(data,
+						     target,
 #ifdef EXP_CHARTRANS
-	    (case_sensitive ?  
-	     (cp = LYno_attr_mbcs_strstr(line->data, target,
-					 text->T.output_utf8,
-					 &len_needed)) != NULL : 
-	     (cp = LYno_attr_mbcs_case_strstr(line->data, target,
-					      text->T.output_utf8,
-					      &len_needed)) != NULL) &&
-            ((int)line->offset + len_needed) < LYcols
+						text->T.output_utf8,
 #else
-	    (case_sensitive ?  
-	    (cp = LYno_attr_char_strstr(line->data, target)) != NULL : 
-	    (cp = LYno_attr_char_case_strstr(line->data, target)) != NULL) &&
-            ((int)(cp - (char *)line->data) +
-	     (int)line->offset + strlen(target)) < LYcols
+						NO,
 #endif /* EXP_CHARTRANS */
-	    ) {
-
-	    int itmp = 0;
-	    int written = 0;
-	    int x_pos=(int)line->offset + (int)(cp - line->data);
-	    int len = strlen(target);
+						&HitOffset,
+						&LenNeeded)) != NULL) &&
+		   ((int)line->offset + LenNeeded) < LYcols) {
+		int itmp = 0;
+		int written = 0;
+		int x_pos = offset + (int)(cp - data);
+		int len = strlen(target);
 #ifdef EXP_CHARTRANS
-	    size_t utf_extra = 0;
+		size_t utf_extra = 0;
 #endif /* EXP_CHARTRANS */
+		int y;
 
-	    text->page_has_target = YES;
+		text->page_has_target = YES;
 
-	    lynx_start_target_color ();
-		/* underline string */
-	    for (; written < len && (tmp[0] = line->data[itmp]) != '\0';
-		   itmp++)  {
-		if (IsSpecialAttrChar(tmp[0])) {
-		   /* ignore special characters */
-		   x_pos--;
+		/*
+		 *  Start the emphasis.
+		 */
+		LYstartTargetEmphasis();
 
-		} else if (cp == &line->data[itmp]) {
-		    /* first character of target */
-            	    move(i+1, x_pos);
+		/*
+		 *  Output the target characters.
+		 */
+		for (;
+		     written < len && (tmp[0] = data[itmp]) != '\0';
+		     itmp++)  {
+		    if (IsSpecialAttrChar(tmp[0])) {
+			/*
+			 *  Ignore special characters.
+			 */
+			x_pos--;
+
+		    } else if (cp == &data[itmp]) {
+			/*
+			 *  First printable character of target.
+			 */
+            		move((i + 1), x_pos);
 #ifdef EXP_CHARTRANS
-		    if (text->T.output_utf8 && !isascii(tmp[0])) {
-			if ((*tmp & 0xe0) == 0xc0) {
-			    utf_extra = 1;
-			} else if ((*tmp & 0xf0) == 0xe0) {
-			    utf_extra = 2;
-			} else if ((*tmp & 0xf8) == 0xf0) {
-			    utf_extra = 3;
-			} else if ((*tmp & 0xfc) == 0xf8) {
-			    utf_extra = 4;
-			} else if ((*tmp & 0xfe) == 0xfc) {
-			    utf_extra = 5;
-			} else { /* garbage */
-			    utf_extra = 0;
+			if (text->T.output_utf8 && !isascii(tmp[0])) {
+			    if ((*tmp & 0xe0) == 0xc0) {
+				utf_extra = 1;
+			    } else if ((*tmp & 0xf0) == 0xe0) {
+				utf_extra = 2;
+			    } else if ((*tmp & 0xf8) == 0xf0) {
+				utf_extra = 3;
+			    } else if ((*tmp & 0xfc) == 0xf8) {
+				utf_extra = 4;
+			    } else if ((*tmp & 0xfe) == 0xfc) {
+				utf_extra = 5;
+			    } else {
+				/*
+				 *  Garbage.
+				 */
+				utf_extra = 0;
+			    }
+			    if (strlen(&line->data[itmp+1]) < utf_extra) {
+				/*
+				 *  Shouldn't happen.
+				 */
+				utf_extra = 0;
+			    }
 			}
-			if (strlen(&line->data[1]) < utf_extra)
-			    utf_extra = 0; /* shouldn't happen */
-		    }
-		    if (utf_extra) {
-			strncpy(&tmp[1], &line->data[itmp+1], utf_extra);
-			tmp[utf_extra+1] = '\0';
-			itmp += utf_extra;
-			addstr(tmp);
-			tmp[1] = '\0';
-			written = written + utf_extra + 1;
-			utf_extra = 0;
-			utf_found++;
+			if (utf_extra) {
+			    strncpy(&tmp[1], &line->data[itmp+1], utf_extra);
+			    tmp[utf_extra+1] = '\0';
+			    itmp += utf_extra;
+			    addstr(tmp);
+			    tmp[1] = '\0';
+			    written += (utf_extra + 1);
+			    utf_extra = 0;
 		    } else
 #endif /* EXP_CHARTRANS */
-		    if (HTCJK != NOCJK && !isascii(tmp[0])) {
-		        /* For CJK strings, by Masanobu Kimura */
-		        tmp[1] = line->data[++itmp];
-			addstr(tmp);
-			tmp[1] = '\0';
-			written += 2;
-		    } else {
-		        addstr(tmp);
-			written++;
-		    }
+			if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			    /*
+			     *  For CJK strings, by Masanobu Kimura.
+			     */
+			    tmp[1] = data[++itmp];
+			    addstr(tmp);
+			    tmp[1] = '\0';
+			    written += 2;
+			} else {
+			    addstr(tmp);
+			    written++;
+			}
 
-		} else if (&line->data[itmp] > cp) { 
-		    /* print all the other target chars */
+		    } else if (&data[itmp] > cp) { 
+			/*
+			 *  Output all the other printable target chars.
+			 */
 #ifdef EXP_CHARTRANS
-		    if (text->T.output_utf8 && !isascii(tmp[0])) {
-			if ((*tmp & 0xe0) == 0xc0) {
-			    utf_extra = 1;
-			} else if ((*tmp & 0xf0) == 0xe0) {
-			    utf_extra = 2;
-			} else if ((*tmp & 0xf8) == 0xf0) {
-			    utf_extra = 3;
-			} else if ((*tmp & 0xfc) == 0xf8) {
-			    utf_extra = 4;
-			} else if ((*tmp & 0xfe) == 0xfc) {
-			    utf_extra = 5;
-			} else { /* garbage */
-			    utf_extra = 0;
+			if (text->T.output_utf8 && !isascii(tmp[0])) {
+			    if ((*tmp & 0xe0) == 0xc0) {
+				utf_extra = 1;
+			    } else if ((*tmp & 0xf0) == 0xe0) {
+				utf_extra = 2;
+			    } else if ((*tmp & 0xf8) == 0xf0) {
+				utf_extra = 3;
+			    } else if ((*tmp & 0xfc) == 0xf8) {
+				utf_extra = 4;
+			    } else if ((*tmp & 0xfe) == 0xfc) {
+				utf_extra = 5;
+			    } else {
+				/*
+				 *  Garbage.
+				 */
+				utf_extra = 0;
+			    }
+			    if (strlen(&line->data[itmp+1]) < utf_extra) {
+				/*
+				 *  Shouldn't happen.
+				 */
+				utf_extra = 0;
+			    }
 			}
-			if (strlen(&line->data[1]) < utf_extra)
-			    utf_extra = 0; /* shouldn't happen */
-		    }
-		    if (utf_extra) {
-			strncpy(&tmp[1], &line->data[itmp+1], utf_extra);
-			tmp[utf_extra+1] = '\0';
-			itmp += utf_extra;
-			addstr(tmp);
-			tmp[1] = '\0';
-			written = written + utf_extra + 1;
-			utf_extra = 0;
-			utf_found++;
+			if (utf_extra) {
+			    strncpy(&tmp[1], &line->data[itmp+1], utf_extra);
+			    tmp[utf_extra+1] = '\0';
+			    itmp += utf_extra;
+			    addstr(tmp);
+			    tmp[1] = '\0';
+			    written += (utf_extra + 1);
+			    utf_extra = 0;
 		    } else
 #endif /* EXP_CHARTRANS */
-		    if (HTCJK != NOCJK && !isascii(tmp[0])) {
-		        /* For CJK strings, by Masanobu Kimura */
-		        tmp[1] = line->data[++itmp];
-			addstr(tmp);
-			tmp[1] = '\0';
-			written += 2;
-		    } else {
-		        addstr(tmp);
-			written++;
+			if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			    /*
+			     *  For CJK strings, by Masanobu Kimura.
+			     */
+			    tmp[1] = data[++itmp];
+			    addstr(tmp);
+			    tmp[1] = '\0';
+			    written += 2;
+			} else {
+			    addstr(tmp);
+			    written++;
+			}
 		    }
 		}
-	    }
 
-	    lynx_stop_target_color ();
-	    move(i+2, 0);
-	}
+		/*
+		 *  Stop the emphasis, and reset the offset and
+		 *  data pointer for our current position in the
+		 *  line. - FM
+		 */
+		LYstopTargetEmphasis();
+		LYGetYX(y, offset);
+		data = (char *)&data[itmp];
 
-	/*
-	 *  Stop if at the last line.
-	 */
-	if (line == text->last_line)  {
-	    /* clr remaining lines of display */
-	    for (i++; i < (display_lines); i++) {
-		move(i+1,0);
-		clrtoeol();
+		/*
+		 *  Adjust the cursor position, should we be at
+		 *  the end of the line, or not have another hit
+		 *  in it. - FM
+		 */
+		move((i + 2), 0);
 	    }
-	    break;
-	}
+#endif /* FANCY CURSES || USE_SLANG */
 
-	display_flag=TRUE;
-	line = line->next;
-      }
+	    /*
+	     *  Stop if this is the last line.  Otherwise, make sure
+	     *  display_flag is set and process the next line. - FM
+	     */
+	    if (line == text->last_line) {
+		/*
+		 *  Clear remaining lines of display.
+		 */
+		for (i++; i < (display_lines); i++) {
+		    move((i + 1), 0);
+		    clrtoeol();
+		}
+		break;
+	    }
+	    display_flag = TRUE;
+	    line = line->next;
+	}
     }
 
     text->next_line = line;	/* Line after screen */
@@ -1119,17 +1213,20 @@ PRIVATE void display_page ARGS3(
 
 	if (Anchor_ptr->line_num >= line_number &&
 		Anchor_ptr->line_num < line_number+(display_lines)) {
-
-		/* load normal hypertext anchors */
+	    /*
+	     *  Load normal hypertext anchors.
+	     */
 	    if (Anchor_ptr->show_anchor && Anchor_ptr->hightext && 
-			strlen(Anchor_ptr->hightext)>0 && 
+			strlen(Anchor_ptr->hightext) > 0 && 
 			(Anchor_ptr->link_type & HYPERTEXT_ANCHOR)) {
 
                 links[nlinks].hightext  = Anchor_ptr->hightext;
                 links[nlinks].hightext2 = Anchor_ptr->hightext2;
                 links[nlinks].hightext2_offset = Anchor_ptr->hightext2offset;
+		links[nlinks].inUnderline = Anchor_ptr->inUnderline;
 
                 links[nlinks].anchor_number = Anchor_ptr->number;
+		links[nlinks].anchor_line_num = Anchor_ptr->line_num;
 
 		link_dest = HTAnchor_followMainLink(
 					     (HTAnchor *)Anchor_ptr->anchor);
@@ -1175,7 +1272,7 @@ PRIVATE void display_page ARGS3(
 		}
 
       	        links[nlinks].lx = Anchor_ptr->line_pos;
-      	        links[nlinks].ly = (Anchor_ptr->line_num+1)-line_number;
+		links[nlinks].ly = ((Anchor_ptr->line_num + 1) - line_number);
 		if (link_dest_intl)
 		    links[nlinks].type = WWW_INTERN_LINK_TYPE;
 		else
@@ -1188,17 +1285,21 @@ PRIVATE void display_page ARGS3(
 
 	    } else if (Anchor_ptr->link_type == INPUT_ANCHOR
 			&& Anchor_ptr->input_field->type != F_HIDDEN_TYPE) {
-
+		/*
+		 *  Handle form fields.
+		 */
 		lynx_mode = FORMS_LYNX_MODE;
 
 		FormInfo_ptr = Anchor_ptr->input_field;
 
                 links[nlinks].anchor_number = Anchor_ptr->number;
+		links[nlinks].anchor_line_num = Anchor_ptr->line_num;
 
 	   	links[nlinks].form = FormInfo_ptr;
 		links[nlinks].lx = Anchor_ptr->line_pos;
-		links[nlinks].ly = (Anchor_ptr->line_num+1)-line_number;
+		links[nlinks].ly = ((Anchor_ptr->line_num + 1) - line_number);
 		links[nlinks].type = WWW_FORM_LINK_TYPE;
+		links[nlinks].inUnderline = Anchor_ptr->inUnderline;
 		links[nlinks].target = empty_string;
 		StrAllocCopy(links[nlinks].lname, empty_string);
 
@@ -1221,17 +1322,24 @@ PRIVATE void display_page ARGS3(
 		    links[nlinks].hightext = FormInfo_ptr->value;
 		}
 
-  		/* never a second line on form types */
+  		/*
+		 *  Never a second line on form types.
+		 */
 		links[nlinks].hightext2 = NULL;
 		links[nlinks].hightext2_offset = 0;
 
 		nlinks++;
-	         /* bold the link after incrementing nlinks */
-		highlight(OFF,nlinks-1);
+	        /*
+		 *  Bold the link after incrementing nlinks.
+		 */
+		highlight(OFF, (nlinks - 1), target);
 	
 		display_flag = TRUE;
 
-	    } else { /* not showing anchor */
+	    } else {
+		/*
+		 *  Not showing anchor.
+		 */
 		if (TRACE &&
 		    Anchor_ptr->hightext && *Anchor_ptr->hightext) 
 		    fprintf(stderr,
@@ -1280,8 +1388,12 @@ PRIVATE void display_page ARGS3(
             more_links = TRUE;
     }
 
-    if (!display_flag) /* nothing on the page */
+    if (!display_flag) {
+	/*
+	 *  Nothing on the page.
+	 */
 	addstr("\n     Document is empty");
+    }
 
 
     if (HTCJK != NOCJK ||
@@ -1289,7 +1401,9 @@ PRIVATE void display_page ARGS3(
 	text->T.output_utf8 ||
 #endif /* EXP_CHARTRANS */
 	TRACE) {
-        /* for non-multibyte curses ;_; */
+	/*
+	 *  For non-multibyte curses.
+	 */
         clearok(curscr, TRUE);
     }
     refresh();
@@ -1336,9 +1450,14 @@ PRIVATE void split_line ARGS2(
 {
     HTStyle * style = text->style;
     HTLine * temp;
-    int spare;
+    int spare, inew;
     int indent = text->in_line_1 ?
     	  text->style->indent1st : text->style->leftIndent;
+    TextAnchor * a;
+    int CurLine = text->Lines;
+    int HeadTrim = 0;
+    int SpecialAttrChars = 0;
+    int TailTrim = 0;
 
     /*
      *  Make new line.
@@ -1364,19 +1483,102 @@ PRIVATE void split_line ARGS2(
 #if defined(USE_COLOR_STYLE) || defined(SLCS)
 #define LastStyle (previous->numstyles-1)
     line->numstyles = 0;
-    /* FIXME: RJP - shouldn't use 0xffffffff for largest integer */
-    line->styles[0].horizpos = 0xffffffff;
-    if (previous->numstyles && previous->styles[LastStyle].direction)
-    {
-	line->numstyles = 1;
-	line->styles[0].horizpos = 0;
-	line->styles[0].direction = ON;
-	line->styles[0].style = previous->styles[LastStyle].style;
-	previous->styles[previous->numstyles].style = line->styles[0].style;
-	previous->styles[previous->numstyles].direction = ABS_OFF;
-	previous->styles[previous->numstyles].horizpos = previous->size;
-	previous->numstyles++;
+    inew = MAX_STYLES_ON_LINE - 1;
+    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) ||
+#if 0
+	     (previous->styles[LastStyle].direction == STACK_ON &&
+	      previous->styles[previous->numstyles-2].direction == STACK_OFF) ||
+#endif
+	     (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 pervious 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 a matched pair.
+	     *  Assume it is safer to leave whatever comes before
+	     *  it on the previous line alone.  Setting spare to 0
+	     *  ensures that it won't be used in a following
+	     *  iteration. - kw
+	     */
+	    spare = 0;
+	} else {
+	    /*
+	     *  Nothing applied, so we are done with the loop. - kw
+	     */
+	    break;
+	}
     }
+    if (previous->numstyles > 0 && previous->styles[LastStyle].direction) {
+	if (TRACE)
+	    fprintf(stderr, "%s\n%s%s\n",
+		    "........... Too many character styles on line:",
+		    "........... ", previous->data);
+    }
+    if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) {
+	inew ++;
+	memmove(line->styles, &line->styles[inew],
+		line->numstyles * sizeof(line->styles[0]));
+    } else
+	if (line->numstyles == 0)
+	/* FIXME: RJP - shouldn't use 0xffffffff for largest integer */
+	line->styles[0].horizpos = 0xffffffff;
+    if (previous->numstyles == 0)
+	previous->styles[0].horizpos = 0xffffffff;
 #endif
     previous->next = line;
     text->last_line = line;
@@ -1422,8 +1624,10 @@ PRIVATE void split_line ARGS2(
 	 *  of our new line. - FM
 	 */
 	p = prevdata + split;
-        while (*p == ' ' || *p == LY_SOFT_HYPHEN)
+        while (*p == ' ' || *p == LY_SOFT_HYPHEN) {
 	    p++;
+	    HeadTrim++;
+	}
         plen = strlen(p);
 
 	/*
@@ -1450,6 +1654,7 @@ PRIVATE void split_line ARGS2(
 	        linedata[line->size++] = LY_UNDERLINE_START_CHAR;
 		linedata[line->size] = '\0';
 		ctrl_chars_on_this_line++;
+		SpecialAttrChars++;
 	    }
 	    for (i = (plen - 1); i >= 0; i--) {
 		if (p[i] == LY_UNDERLINE_START_CHAR) {
@@ -1490,6 +1695,7 @@ PRIVATE void split_line ARGS2(
 	    linedata[line->size++] = LY_BOLD_START_CHAR;
 	    linedata[line->size] = '\0';
 	    ctrl_chars_on_this_line++;
+	    SpecialAttrChars++;;
 	}
 	for (i = (plen - 1); i >= 0; i--) {
 	    if (p[i] == LY_BOLD_START_CHAR) {
@@ -1505,8 +1711,7 @@ PRIVATE void split_line ARGS2(
 	    if (p[i] == LY_BOLD_START_CHAR ||
 	        p[i] == LY_BOLD_END_CHAR ||
 #ifdef EXP_CHARTRANS
-#define IS_UTFEXTRA(ch) (text->T.output_utf8 && ((unsigned char)(ch)&0xc0) == 0x80)
-		IS_UTFEXTRA(p[i]) ||
+		IS_UTF_EXTRA(p[i]) ||
 #endif /* EXP_CHARTRANS */
 		p[i] == LY_SOFT_HYPHEN) {
 	        ctrl_chars_on_this_line++;
@@ -1533,6 +1738,7 @@ PRIVATE void split_line ARGS2(
 	 */
 	previous->data[previous->size-1] = '\0';
         previous->size--;
+	TailTrim++;
     }
     temp = (HTLine *)calloc(1, LINE_SIZE(previous->size));
     if (temp == NULL)
@@ -1548,7 +1754,6 @@ PRIVATE void split_line ARGS2(
      *  Terminate finished line for printing.
      */
     previous->data[previous->size] = '\0';
-     
     
     /*
      *  Align left, right or center.
@@ -1559,7 +1764,7 @@ PRIVATE void split_line ARGS2(
 	    *cp == LY_BOLD_START_CHAR ||
 	    *cp == LY_BOLD_END_CHAR ||
 #ifdef EXP_CHARTRANS
-	    IS_UTFEXTRA(*cp) ||
+	    IS_UTF_EXTRA(*cp) ||
 #endif /* EXP_CHARTRANS */
 	    *cp == LY_SOFT_HYPHEN)
 	    ctrl_chars_on_previous_line++;
@@ -1589,7 +1794,20 @@ PRIVATE void split_line ARGS2(
 
     text->chars = text->chars + previous->size + 1;	/* 1 for the line */
     text->in_line_1 = NO;		/* unless caller sets it otherwise */
-    
+
+    /*
+     *  If we split the line, adjust the anchor
+     *  structure values for the new line. - FM
+     */
+    if (split > 0) {
+	for (a = text->first_anchor; a; a = a->next) {
+	    if (a->line_num == CurLine && a->line_pos >= split) {
+		a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
+		a->line_pos -= (split - SpecialAttrChars + HeadTrim);
+		a->line_num = text->Lines;
+	    }
+	}
+    }
 } /* split_line */
 
 
@@ -1600,11 +1818,14 @@ PRIVATE void blank_lines ARGS2(
 	HText *,	text,
 	int,		newlines)
 {
-    if (!HText_LastLineSize(text)) {	/* No text on current line */
+    BOOL IgnoreSpaces = FALSE;
+
+    if (!HText_LastLineSize(text, IgnoreSpaces)) { /* No text on current line */
 	HTLine * line = text->last_line->prev;
 	while ((line != text->last_line) &&
-	       (HText_TrueLineSize(line, text) == 0)) {
-	    if (newlines == 0) break;
+	       (HText_TrueLineSize(line, text, IgnoreSpaces) == 0)) {
+	    if (newlines == 0)
+	        break;
 	    newlines--;		/* Don't bother: already blank */
 	    line = line->prev;
 	}
@@ -1672,12 +1893,6 @@ PUBLIC void HText_appendCharacter ARGS2(
     if (!text)
 	return;
 
-#ifdef NOTDEFINED
-    /* Make sure nbsp is handled properly. */
-    if ((unsigned char)ch == 160)
-        ch = HT_NON_BREAK_SPACE;
-#endif /* NOTDEFINED */
-
     /*
      *  Make sure we don't hang on escape sequences.
      */
@@ -1819,7 +2034,7 @@ PUBLIC void HText_appendCharacter ARGS2(
 	return;
     }
 
-    if (ch != LY_SOFT_HYPHEN && IsSpecialAttrChar(ch)) {
+    if (IsSpecialAttrChar(ch)) {
 #ifndef USE_COLOR_STYLE
         if (ch == LY_UNDERLINE_START_CHAR) { 
             line->data[line->size++] = LY_UNDERLINE_START_CHAR;
@@ -1847,6 +2062,29 @@ PUBLIC void HText_appendCharacter ARGS2(
             bold_on = OFF;
 	    ctrl_chars_on_this_line++;
             return;
+	} else if (ch == LY_SOFT_HYPHEN) {
+	    int i;
+
+	    /*
+	     *  Ignore the soft hyphen if it is the first character
+	     *  on the line, or if it is preceded by a space or
+	     *  hyphen. - FM
+	     */
+	    if (line->size < 1 || text->permissible_split >= (int)line->size)
+		return;
+
+	    for (i = (text->permissible_split + 1); line->data[i]; i++) {
+		if (!IsSpecialAttrChar((unsigned char)line->data[i]) &&
+		    !isspace((unsigned char)line->data[i]) &&
+		    (unsigned char)line->data[i] != '-' &&
+		    (unsigned char)line->data[i] != HT_NON_BREAK_SPACE &&
+		    (unsigned char)line->data[i] != HT_EM_SPACE) {
+		    break;
+		}
+	    }
+	    if (line->data[i] == '\0') {
+		return;
+	    }
 	}
 #else
 	return;
@@ -1854,7 +2092,7 @@ PUBLIC void HText_appendCharacter ARGS2(
     }
 
 #ifdef EXP_CHARTRANS
-    if (IS_UTFEXTRA(ch)) {
+    if (IS_UTF_EXTRA(ch)) {
 	line->data[line->size++] = ch;
 	line->data[line->size] = '\0';
 	ctrl_chars_on_this_line++;
@@ -1978,9 +2216,11 @@ check_IgnoreExcess:
      *  Check for end of line.
      */
     if (((indent + (int)line->offset + (int)line->size) + 
-	(int)style->rightIndent - ctrl_chars_on_this_line +
-	(int)(line->data[line->size] == LY_SOFT_HYPHEN ?
-						     1 : 0)) >= (LYcols-1)) {
+	 (int)style->rightIndent - ctrl_chars_on_this_line +
+	 ((line->size > 0) &&
+	  (int)(line->data[line->size-1] ==
+		 		LY_SOFT_HYPHEN ?
+					     1 : 0))) >= (LYcols - 1)) {
 
         if (style->wordWrap && HTOutputFormat != WWW_SOURCE) {
 	    split_line(text, text->permissible_split);
@@ -2064,11 +2304,11 @@ check_IgnoreExcess:
         if (font & HT_DOUBLE)		/* Do again if doubled */
             HText_appendCharacter(text, HT_NON_BREAK_SPACE);
 	    /* NOT a permissible split */ 
-    }
 
-    if (ch == LY_SOFT_HYPHEN) {
-        ctrl_chars_on_this_line++;
-        text->permissible_split = (int)line->size;	/* Can split here */
+	if (ch == LY_SOFT_HYPHEN) {
+	    ctrl_chars_on_this_line++;
+	    text->permissible_split = (int)line->size;	/* Can split here */
+	}
     }
 }
 
@@ -2145,8 +2385,9 @@ PUBLIC void HText_setIgnoreExcess ARGS2(
 
 /*	Start an anchor field
 */
-PUBLIC void HText_beginAnchor ARGS2(
+PUBLIC int HText_beginAnchor ARGS3(
 	HText *,		text,
+	BOOL,			underline,
 	HTChildAnchor *,	anc)
 {
     char marker[16];
@@ -2158,7 +2399,9 @@ PUBLIC void HText_beginAnchor ARGS2(
     a->hightext  = 0;
     a->hightext2 = 0;
     a->start = text->chars + text->last_line->size;
+    a->inUnderline = underline;
 
+    a->line_num = text->Lines;
     a->line_pos = text->last_line->size;
     if (text->last_anchor) {
         text->last_anchor->next = a;
@@ -2181,46 +2424,103 @@ PUBLIC void HText_beginAnchor ARGS2(
 	a->link_type = HYPERTEXT_ANCHOR;
     }
 
-    /* if we are doing link_numbering add the link number */
-    if (keypad_mode == LINKS_ARE_NUMBERED && a->number > 0) {
+    /*
+     *  If we are doing link_numbering add the link number.
+     */
+    if ((a->number > 0) &&
+        (keypad_mode == LINKS_ARE_NUMBERED ||
+	 keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)) {
 	sprintf(marker,"[%d]", a->number);
         HText_appendText(text, marker);
 	a->start = text->chars + text->last_line->size;
+	a->line_num = text->Lines;
 	a->line_pos = text->last_line->size;
     }
+
+    return(a->number);
 }
 
 
-PUBLIC void HText_endAnchor ARGS1(
-	HText *,	text)
+PUBLIC void HText_endAnchor ARGS2(
+	HText *,	text,
+	int,		number)
 {
-    TextAnchor * a = text->last_anchor;
+    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) {
+	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;
+	}
+    }
+    if (TRACE)
+	fprintf(stderr, "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
+	 */
+	if (TRACE)
+	    fprintf(stderr,
+	   "HText_endAnchor: internal error: last anchor was input field!\n");
+	return;
+    }
     if (a->number) {
         /*
 	 *  If it goes somewhere...
 	 */
-	int i, j, k;
+	int i, j, k, l;
 	BOOL remove_numbers_on_empty =
-	    (keypad_mode == LINKS_ARE_NUMBERED &&
+	    ((keypad_mode == LINKS_ARE_NUMBERED ||
+	      keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) &&
 	     (LYHiddenLinks != HIDDENLINKS_MERGE ||
 	      (LYNoISMAPifUSEMAP &&
 	       HTAnchor_isISMAPScript(
 		   HTAnchor_followMainLink((HTAnchor *)a->anchor)))));
 	HTLine *last = text->last_line;
 	HTLine *prev = text->last_line->prev;
+	int CurBlankExtent = 0;
+	int BlankExtent = 0;
 
 	/*
 	 *  Check if the anchor content has only
-	 *  white and special characters. - FM
+	 *  white and special characters, starting
+	 *  with the content on the last line. - FM
 	 */
-        a->extent += text->chars + last->size - a->start;
+        a->extent += (text->chars + last->size) - a->start -
+		     (text->Lines - a->line_num);
 	if (a->extent > last->size) {
 	    /*
-	     *  It extends over more than one line, so
-	     *  set up to check the last line. - FM
+	     *  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;
 	}
 	j = (last->size - i);
@@ -2233,22 +2533,46 @@ PUBLIC void HText_endAnchor ARGS1(
 	    i--;
 	    j++;
 	}
-	if (i == 0 && a->extent > last->size) {
-	    /*
-	     *  The last line had only white and special
-	     *  characters, and it extends over more than
-	     *  one line, so check the next to last. - FM
-	     */
-	    j = prev->size - a->extent + last->size + 1;
+	if (i == 0) {
+	    if (a->extent > 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
+	 *  immediatedly preceding line also has only
+	 *  white and special characters. - FM
+	 */
+	while (i == 0 && a->extent > CurBlankExtent) {
+	    j = prev->size - a->extent + CurBlankExtent;
 	    if (j < 0) {
 	        /*
-		 *  It extends over more than two lines,
-		 *  so check all of the previous line. - FM
+		 *  The anchor starts on a preceding line,
+		 *  so check all of this line. - FM
 		 */
 	        j = 0;
 		i = prev->size;
 	    } else {
-	        i = a->extent - last->size - 1;
+	        /*
+		 *  The anchor starts on this line. - FM
+		 */
+	        i = a->extent - CurBlankExtent;
 	    }
 	    while (j < prev->size) {
 	        if (!IsSpecialAttrChar(prev->data[j]) &&
@@ -2259,42 +2583,25 @@ PUBLIC void HText_endAnchor ARGS1(
 		i--;
 		j++;
 	    }
-	    if (i == 0 && a->extent > (last->size + prev->size + 1)) {
-	        /*
-		 *  It extends over more than two lines, and the
-		 *  last two have only white and special characters,
-		 *  so check the second to last line. - FM
-		 */
-	        prev = prev->prev;
-		j = prev->size - a->extent + last->size + prev->next->size + 2;
-		if (j < 0) {
+	    if (i == 0) {
+		if (a->extent > (CurBlankExtent + prev->size)) {
 		    /*
-		     *  It extends over more than three lines,
-		     *  so check all of the second to last. - FM
+		     *  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
 		     */
-		    j = 0;
-		    i = prev->size;
+		    CurBlankExtent += prev->size;
+		    BlankExtent = CurBlankExtent;
+		    prev = prev->prev;
 		} else {
-		    i = a->extent - last->size - prev->next->size - 2;
-		}
-		while (j < prev->size) {
-		    if (!IsSpecialAttrChar(prev->data[j]) &&
-		        !isspace((unsigned char)prev->data[j]) &&
-			prev->data[j] != HT_NON_BREAK_SPACE &&
-			prev->data[j] != HT_EM_SPACE)
-			break;
-		    i--;
-		    j++;
-		}
-		if (i == 0 &&
-		    a->extent >
-		    (last->size + prev->size + prev->prev->size + 2)) {
 		    /*
-		     *  It extends over more than three lines, and the
-		     *  last three have only white and special characters,
-		     *  so for now, we'll assume it should be shown. - FM
+		     *  The anchor starts on this line, and it
+		     *  has only white or special characters, so
+		     *  declare the anchor's extent as blank. - FM
 		     */
-		    i = a->extent;
+		    BlankExtent = a->extent;
+		    break;
 		}
 	    }
 	}
@@ -2305,7 +2612,6 @@ PUBLIC void HText_endAnchor ARGS1(
 	     *  USEMAP. - FM
 	     */
 	    a->show_anchor = NO;
-	    prev = last->prev;
 
 	    /*
 	     *  If links are numbered, then try to get rid of the
@@ -2320,39 +2626,75 @@ PUBLIC void HText_endAnchor ARGS1(
 	     * possibly caused by HTML errors. - kw
 	     */
 	    if (remove_numbers_on_empty) {
-		j = (last->size - a->extent - 1);
+		HTLine *start;
+		int NumSize = 0;
+		TextAnchor *anc;
+
+		/*
+		 *  Set start->data[j] to the close-square-bracket,
+		 *  or to the beginning of the line on which the
+		 *  anchor start. - FM
+		 */
+		if (prev == last->prev) {
+		    /*
+		     *  The anchor starts on the last line. - FM
+		     */
+		    start = last;
+		    j = (last->size - a->extent - 1);
+		} else {
+		    /*
+		     *  The anchor starts on a previous line. - FM
+		     */
+		    start = prev;
+		    prev = prev->prev;
+		    j = (start->size - a->extent + CurBlankExtent - 1);
+		}
 		if (j < 0)
 		    j = 0;
 		i = j;
-		if (last->data[j] == ']') {
+
+		/*
+		 *  If start->data[j] is a close-square-bracket, verify
+		 *  that it's the end of the numbered bracket, and if so,
+		 *  strip the numbered bracket.  If start->data[j] is not
+		 *  a close-square-bracket, check whether we had a wrap
+		 *  and the close-square-bracket is at the end of the
+		 *  previous line.  If so, strip the numbered bracket
+		 *  from that line. - FM
+		 */
+		if (start->data[j] == ']') {
 		    j--;
-		    while (j >= 0 && isdigit((unsigned char)last->data[j]))
+		    NumSize++;
+		    while (j >= 0 && isdigit((unsigned char)start->data[j])) {
 		        j--;
-		    if (j < 0)
-		        j = 0;
-		    if (last->data[j] == '[') {
+			NumSize++;
+		    }
+		    while (j < 0) {
+		        j++;
+			NumSize--;
+		    }
+		    if (start->data[j] == '[') {
 		        /*
-			 *  The numbered bracket is on the last line. - FM
+			 *  The numbered bracket is entirely
+			 *  on this line. - FM
 			 */
-			HText_AddHiddenLink(text, a);
-			a->number = 0;
-			text->last_anchor_number--;
-			k = (i + 1);
-			while (k < last->size) {
-			    if (last->data[k] == LY_UNDERLINE_START_CHAR ||
-				last->data[k] == LY_UNDERLINE_END_CHAR ||
-				last->data[k] == LY_BOLD_START_CHAR ||
-				last->data[k] == LY_BOLD_END_CHAR ||
-				last->data[k] == LY_SOFT_HYPHEN)
-			        ctrl_chars_on_this_line--;
-			    k++;
+			NumSize++;
+			k = j + NumSize;
+			while (k < start->size)
+			    start->data[j++] = start->data[k++];
+			if (start != last)
+			    text->chars -= NumSize;
+			for (anc = a; anc; anc = anc->next) {
+			    anc->start -= NumSize;
+			    anc->line_pos -= NumSize;
 			}
-		        last->size = j;
-			last->data[j] = '\0';
+		        start->size = j;
+			start->data[j++] = '\0';
+			while (j < k)
+			     start->data[j++] = '\0';
 		    } else if (prev && prev->size > 1) {
-		        k = (i + 1);
-		        i = prev->size;
-		        j = (prev->size - 1);
+			k = (i + 1);
+			j = (prev->size - 1);
 			while ((j >= 0) &&
 			       (prev->data[j] == LY_BOLD_START_CHAR ||
 			        prev->data[j] == LY_BOLD_END_CHAR ||
@@ -2360,92 +2702,107 @@ PUBLIC void HText_endAnchor ARGS1(
 			        prev->data[j] == LY_UNDERLINE_END_CHAR ||
 				prev->data[j] == LY_SOFT_HYPHEN))
 			    j--;
-			while (j >= 0 && isdigit((unsigned char)prev->data[j]))
+		        i = (j + 1);
+			while (j >= 0 &&
+			       isdigit((unsigned char)prev->data[j])) {
 			    j--;
-			if (j < 0)
-			    j = 0;
+			    NumSize++;
+			}
+			while (j < 0) {
+			    j++;
+			    NumSize--;
+			}
 			if (prev->data[j] == '[') {
 			    /*
 			     *  The numbered bracket started on the
 			     *  previous line, and part of it was
-			     *  wrapped to the last line. - FM
+			     *  wrapped to this line. - FM
 			     */
-			    HText_AddHiddenLink(text, a);
-			    a->number = 0;
-			    text->last_anchor_number--;
+			    NumSize++;
+			    l = (i - j);
+			    while (i < prev->size)
+				start->data[j++] = start->data[i++];
+			    text->chars -= l;
+			    for (anc = a; anc; anc = anc->next) {
+				anc->start -= l;
+			    }
 			    prev->size = j;
 			    prev->data[j] = '\0';
-			    text->chars -= (i - j);
-			    while (k < last->size) {
-				if (last->data[k] == LY_UNDERLINE_START_CHAR ||
-				    last->data[k] == LY_UNDERLINE_END_CHAR ||
-				    last->data[k] == LY_BOLD_START_CHAR ||
-				    last->data[k] == LY_BOLD_END_CHAR ||
-				    last->data[k] == LY_SOFT_HYPHEN)
-			            ctrl_chars_on_this_line--;
-				k++;
+			    while (j < i)
+				start->data[j++] = '\0';
+			    j = 0;
+			    i = k;
+			    while (k < start->size)
+			        start->data[j++] = start->data[k++];
+			    if (start != last)
+			        text->chars -= i;
+			    for (anc = a; anc; anc = anc->next) {
+				anc->start -= i;
+				anc->line_pos -= i;
 			    }
-			    last->size = 0;
-			    last->data[0] = '\0';
-			    for (j = 1; j < k; j++)
-			        last->data[j] = '\0';
+			    start->size = j;
+			    start->data[j++] = '\0';
+			    while (j < k)
+			        start->data[j++] = '\0';
+			} else {
+			    /*
+			     *  Shucks!  We didn't find the
+			     *  numbered bracket. - FM
+			     */
+			    a->show_anchor = YES;
 			}
+		    } else {
+			/*
+			 *  Shucks!  We didn't find the
+			 *  numbered bracket. - FM
+			 */
+			a->show_anchor = YES;
 		    }
 		} else if (prev && prev->size > 2) {
-		    i = (prev->size - 1);
-		    while ((i >= 0) &&
-			   (prev->data[i] == LY_BOLD_START_CHAR ||
-			    prev->data[i] == LY_BOLD_END_CHAR ||
-			    prev->data[i] == LY_UNDERLINE_START_CHAR ||
-			    prev->data[i] == LY_UNDERLINE_END_CHAR ||
-			    prev->data[i] == LY_SOFT_HYPHEN))
-		        i--;
-		    if (i < 0)
-		        i = 0;
-		    j = i;
-		    i++;
+		    j = (prev->size - 1);
+		    while ((j >= 0) &&
+			   (prev->data[j] == LY_BOLD_START_CHAR ||
+			    prev->data[j] == LY_BOLD_END_CHAR ||
+			    prev->data[j] == LY_UNDERLINE_START_CHAR ||
+			    prev->data[j] == LY_UNDERLINE_END_CHAR ||
+			    prev->data[j] == LY_SOFT_HYPHEN))
+		        j--;
+		    if (j < 0)
+		        j = 0;
+		    i = (j + 1);
 		    if ((j > 2) &&
 		        (prev->data[j] == ']' &&
 			 isdigit((unsigned char)prev->data[j - 1]))) {
-		        k = (j + 1);
 		        j--;
-			while (j >=0 && isdigit((unsigned char)prev->data[j]))
+			NumSize++;
+		        k = (j + 1);
+			while (j >= 0 &&
+			       isdigit((unsigned char)prev->data[j])) {
 			    j--;
-			if (j < 0)
-			    j = 0;
+			    NumSize++;
+			}
+			while (j < 0) {
+			    j++;
+			    NumSize--;
+			}
 			if (prev->data[j] == '[') {
 			    /*
 			     *  The numbered bracket is all on the
 			     *  previous line, and the anchor content
 			     *  was wrapped to the last line. - FM
 			     */
-			    HText_AddHiddenLink(text, a);
-			    a->number = 0;
-			    text->last_anchor_number--;
-			    while (k < prev->size) {
-				if (prev->data[k] == LY_UNDERLINE_START_CHAR ||
-				    prev->data[k] == LY_UNDERLINE_END_CHAR ||
-				    prev->data[k] == LY_BOLD_START_CHAR ||
-				    prev->data[k] == LY_BOLD_END_CHAR ||
-				    prev->data[k] == LY_SOFT_HYPHEN)
+			    NumSize++;
+			    k = j + NumSize;
+			    while (k < prev->size)
 				prev->data[j++] = prev->data[k++];
-				i++;
+			    text->chars -= NumSize;
+			    for (anc = a; anc; anc = anc->next) {
+				anc->start -= NumSize;
 			    }
 			    prev->size = j;
-			    prev->data[j] = '\0';
-			    text->chars -= (i - j);
-			    k = 0;
-			    while (k < last->size) {
-				if (last->data[k] == LY_UNDERLINE_START_CHAR ||
-				    last->data[k] == LY_UNDERLINE_END_CHAR ||
-				    last->data[k] == LY_BOLD_START_CHAR ||
-				    last->data[k] == LY_BOLD_END_CHAR ||
-				    last->data[k] == LY_SOFT_HYPHEN)
-			            ctrl_chars_on_this_line--;
-				k++;
-			    }
-			    last->data[0] = '\0';
-			    last->size = 0;
+			    prev->data[j++] = '\0';
+			    while (j < k)
+				start->data[j++] = '\0';
 			} else {
 			    /*
 			     *  Shucks!  We didn't find the
@@ -2467,22 +2824,38 @@ PUBLIC void HText_endAnchor ARGS1(
 		     */
 		    a->show_anchor = YES;
 		}
-	    } else if (LYHiddenLinks != HIDDENLINKS_MERGE) {
-		HText_AddHiddenLink(text, a);
-		a->number = 0;
-	        text->last_anchor_number--;
 	    }
 	} else {
 	    /*
-	     *  The anchor content does not contain only
-	     *  white and special characters (or extends
-	     *  over more than three lines and we're punting,
-	     *  for now), so we'll show it as a link. - FM
+	     *  The anchor's content does not resticted to only
+	     *  white and special characters, so we'll show it
+	     *  as a link. - FM
 	     */
 	    a->show_anchor = YES;
 	}
 	if (a->show_anchor == NO) {
+	    /*
+	     *  The anchor's content is restricted to white
+	     *  and special characters, so set it's number
+	     *  and extent to zero, decrement the visible
+	     *  anchor number counter, and add this anchor
+	     *  to the hidden links list. - FM
+	     */
 	    a->extent = 0;
+	    if (LYHiddenLinks != HIDDENLINKS_MERGE) {
+		a->number = 0;
+		HText_AddHiddenLink(text, a);
+	        text->last_anchor_number--;
+	    }
+	} else {
+	    /*
+	     *  The anchor's content is not restricted to white
+	     *  and special characters, so we'll display the
+	     *  content, but shorten it's extent by any trailing
+	     *  blank lines we've detected. - FM
+	     */
+	    a->extent -= ((BlankExtent < a->extent) ?
+					BlankExtent : 0);
 	}
     } else {
         /*
@@ -2516,8 +2889,10 @@ PRIVATE void remove_special_attr_chars ARGS1(
 {
     register char *cp;
 
-    for (cp=buf; *cp != '\0' ; cp++) {
-         /* don't print underline chars */
+    for (cp = buf; *cp != '\0' ; cp++) {
+        /*
+	 *  Don't print underline chars.
+	 */
         if (!IsSpecialAttrChar(*cp)) {
            *buf = *cp, 
            buf++;
@@ -2531,59 +2906,65 @@ PRIVATE void remove_special_attr_chars ARGS1(
 **  This function trims blank lines from the end of the document, and
 **  then gets the hightext from the text by finding the char position,
 **  and brings the anchors in line with the text by adding the text
-**  offset to each of the anchors
+**  offset to each of the anchors.
 */
 PUBLIC void HText_endAppend ARGS1(
 	HText *,	text)
 {
-    int cur_line, cur_char;
+    int cur_line, cur_char, cur_shift;
     TextAnchor *anchor_ptr;
     HTLine *line_ptr;
     unsigned char ch;
 
     if (!text)
 	return;
+    if (TRACE)
+	fprintf(stderr,"Gridtext: Entering HText_endAppend\n");
 
+    /*
+     *  Create a  blank line at the bottom.
+     */
     new_line(text);
     
     /*
-     *  Get the first line
+     *  Get the first line.
      */
     line_ptr = text->last_line->next;
-    cur_char = line_ptr->size;;
+    cur_char = line_ptr->size;
     cur_line = 0;
+    cur_shift = 0;
 
     /*
      *  Remove the blank lines at the end of document.
      */
     while (text->last_line->data[0] == '\0' && text->Lines > 2) {
-        HTLine *next_to_the_last_line;
+        HTLine *next_to_the_last_line = text->last_line->prev;
 
         if (TRACE)
             fprintf(stderr, "GridText: Removing bottom blank line: %s\n",
                             text->last_line->data);
-    
-        next_to_the_last_line = text->last_line->prev;
-
-        /* line_ptr points to the first line */
+        /*
+	 *  line_ptr points to the first line.
+	 */
         next_to_the_last_line->next = line_ptr;
         line_ptr->prev = next_to_the_last_line;
 	FREE(text->last_line);
         text->last_line = next_to_the_last_line;
         text->Lines--;
 #ifdef NOTUSED_BAD_FOR_SCREEN
-        if (TRACE)
+        if (TRACE) {
             fprintf(stderr, "GridText: New bottom line: %s\n",
                             text->last_line->data);
+	}
 #endif
     }
 
-    if (TRACE)
-	fprintf(stderr,"Gridtext: Entering HText_endAppend\n");
-
+    /*
+     *  Fix up the anchor structure values and
+     *  create the hightext strings. - FM
+     */
     for (anchor_ptr = text->first_anchor;
          anchor_ptr; anchor_ptr=anchor_ptr->next) {
-
 re_parse:
 	/*
 	 *  Find the right line.
@@ -2591,17 +2972,17 @@ re_parse:
 	for (; anchor_ptr->start >= cur_char;
 	       line_ptr = line_ptr->next,
 	       cur_char += line_ptr->size+1,
-	       cur_line++) 
+	       cur_line++) {
 	    ; /* null body */
-
-	if (anchor_ptr->start == cur_char)
+	}
+	if (anchor_ptr->start == cur_char) {
 	    anchor_ptr->line_pos = line_ptr->size;
-	else
-	    anchor_ptr->line_pos = anchor_ptr->start-(cur_char-line_ptr->size);
-
+	} else {
+	    anchor_ptr->line_pos = anchor_ptr->start -
+				   (cur_char - line_ptr->size);
+	}
 	if (anchor_ptr->line_pos < 0)
 	    anchor_ptr->line_pos = 0;
-
 	if (TRACE)
 	    fprintf(stderr, "Gridtext: Anchor found on line:%d col:%d\n",
 			    cur_line, anchor_ptr->line_pos);
@@ -2616,29 +2997,31 @@ re_parse:
 	           IsSpecialAttrChar(ch)) {
 		anchor_ptr->line_pos++;
 		anchor_ptr->extent--;
+		cur_shift++;
 		ch = (unsigned char)line_ptr->data[anchor_ptr->line_pos];
 	    }
 	}
-
-	if (anchor_ptr->extent < 0)
+	if (anchor_ptr->extent < 0) {
 	    anchor_ptr->extent = 0;
+	}
 #ifdef NOTUSED_BAD_FOR_SCREEN
 	if (TRACE)
 	    fprintf(stderr, "anchor text: '%s'   pos: %d\n",
 	    		    line_ptr->data, anchor_ptr->line_pos);
 #endif
 	/* 
-	 *  If the link begins with a end of line and we have more
-	 *  lines, then start the highlighting on the next line.
+	 *  If the link begins with an end of line and we have more
+	 *  lines, then start the highlighting on the next line. - FM
 	 */
 	if (anchor_ptr->line_pos >= strlen(line_ptr->data) &&
 	    cur_line < text->Lines) {
-	    anchor_ptr->start++;
-
+	    anchor_ptr->start += (cur_shift + 1);
+	    cur_shift = 0;
 	    if (TRACE)
 		fprintf(stderr, "found anchor at end of line\n");
 	    goto re_parse;
 	}
+	cur_shift = 0;
 #ifdef NOTUSED_BAD_FOR_SCREEN
 	if (TRACE)
 	    fprintf(stderr, "anchor text: '%s'   pos: %d\n",
@@ -2649,7 +3032,6 @@ re_parse:
 	 */
 	if (line_ptr->data &&
 	    anchor_ptr->extent > 0 && anchor_ptr->line_pos >= 0) {
-
 	    StrnAllocCopy(anchor_ptr->hightext,
 	    		  &line_ptr->data[anchor_ptr->line_pos],
 			  anchor_ptr->extent);
@@ -2663,15 +3045,19 @@ re_parse:
 	 */
 	if (anchor_ptr->extent > strlen(anchor_ptr->hightext)) {
             HTLine *line_ptr2 = line_ptr->next;
-	    /* double check! */
+	    /*
+	     *  Double check that we have a line pointer,
+	     *  and if so, copy into hightext2.
+	     */
 	    if (line_ptr) {
-		StrnAllocCopy(anchor_ptr->hightext2, line_ptr2->data, 
-			 (anchor_ptr->extent - strlen(anchor_ptr->hightext))-1);
+		StrnAllocCopy(anchor_ptr->hightext2,
+			      line_ptr2->data,
+			      (anchor_ptr->extent -
+			       strlen(anchor_ptr->hightext)));
 	        anchor_ptr->hightext2offset = line_ptr2->offset;
 	 	remove_special_attr_chars(anchor_ptr->hightext2);
 	    }
 	}   
-
 	remove_special_attr_chars(anchor_ptr->hightext);
 
         /*
@@ -2682,7 +3068,7 @@ re_parse:
             register int offset = 0, i = 0;
             for (; i < anchor_ptr->line_pos; i++)
 #ifdef EXP_CHARTRANS
-		if (IS_UTFEXTRA(line_ptr->data[i]))
+		if (IS_UTF_EXTRA(line_ptr->data[i]))
 		    offset++;
 		else
 #endif /* EXP_CHARTRANS */
@@ -2691,15 +3077,19 @@ re_parse:
             anchor_ptr->line_pos -= offset;
         }
 
-        anchor_ptr->line_pos += line_ptr->offset;  /* add the offset */
+	/*
+	 *  Add the offset, and set the line number.
+	 */
+        anchor_ptr->line_pos += line_ptr->offset;
         anchor_ptr->line_num  = cur_line;
-
-
 	if (TRACE)
 	    fprintf(stderr,
 	    	    "GridText: adding link on line %d in HText_endAppend\n",
 		    cur_line);
 
+	/*
+	 *  If this is the last anchor, we're done!
+	 */
  	if (anchor_ptr == text->last_anchor)
 	    break;
     }
@@ -2726,16 +3116,16 @@ PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(
 /*				GridText specials
 **				=================
 */
-/*	Return the anchor with index N
-**
-**	The index corresponds to the number we print in the anchor.
-*/
+/*
+ *  HTChildAnchor() returns the anchor with index N.
+ *  The index corresponds to the [number] we print for the anchor.
+ */
 PUBLIC HTChildAnchor * HText_childNumber ARGS1(
 	int,		number)
 {
     TextAnchor * a;
 
-    if (!HTMainText)
+    if (!(HTMainText && HTMainText->first_anchor) || number <= 0)
         return (HTChildAnchor *)0;	/* Fail */
 
     for (a = HTMainText->first_anchor; a; a = a->next) {
@@ -2746,19 +3136,98 @@ PUBLIC HTChildAnchor * HText_childNumber ARGS1(
 }
 
 /*
+ *  HText_FormDescNumber() returns a description of the form field
+ *  with index N.  The index corresponds to the [number] we print
+ *  for the field. - FM & LE
+ */
+PUBLIC void HText_FormDescNumber ARGS2(
+	int,		number,
+	char **,	desc)
+{
+    TextAnchor * a;
+
+    if (!desc)
+        return;
+
+    if (!(HTMainText && HTMainText->first_anchor) || number <= 0) {
+         *desc = "unknown field or link";
+	 return;
+    }
+
+    for (a = HTMainText->first_anchor; a; a = a->next) {
+        if (a->number == number) {
+	    if (!(a->input_field && a->input_field->type)) {
+	        *desc = "unknown field or link";
+		return;
+	    }
+	    break;
+	}
+    }
+
+    switch (a->input_field->type) {
+	case F_TEXT_TYPE:
+	    *desc = "text entry field";
+	    return;
+	case F_PASSWORD_TYPE:
+	    *desc = "password entry field";
+	    return;
+	case F_CHECKBOX_TYPE:
+	    *desc = "checkbox";
+	    return;
+	case F_RADIO_TYPE:
+	    *desc = "radio button";
+	    return;
+	case F_SUBMIT_TYPE:
+	    *desc = "submit button";
+	    return;
+	case F_RESET_TYPE:
+	    *desc = "reset button";
+	    return;
+	case F_OPTION_LIST_TYPE:
+	    *desc = "popup menu";
+	    return;
+	case F_HIDDEN_TYPE:
+	    *desc = "hidden form field";
+	    return;
+	case F_TEXTAREA_TYPE:
+	    *desc = "text entry area";
+	    return;
+	case F_RANGE_TYPE:
+	    *desc = "range entry field";
+	    return;
+	case F_FILE_TYPE:
+	    *desc = "file entry field";
+	    return;
+	case F_TEXT_SUBMIT_TYPE:
+	    *desc = "text-submit field";
+	    return;
+	case F_IMAGE_SUBMIT_TYPE:
+	    *desc = "image-submit button";
+	    return;
+	case F_KEYGEN_TYPE:
+	    *desc = "keygen field";
+	    return;
+	default:
+	    *desc = "unknown form field";
+	    return;
+    }
+}
+ 
+/*
  *  HTGetLinkInfo returns some link info based on the number.
  *
- *  If go_line is not NULL, caller requests to know a line number for
+ *  If want_go is not NULL, caller requests to know a line number for
  *  the link indicated by number.  It will be returned in *go_line, and
  *  *linknum will be set to an index into the links[] array, to use after
  *  the line in *line has been made the new top screen line.
  *  *hightext and *lname are unchanged. - KW
  *
- *  If go_line is NULL, info on the link indicated by number is deposited
- *  in *hightext and *lname.
+ *  If want_go is 0 and the number doesn't represent an input field, info
+ *  on the link indicated by number is deposited in *hightext and *lname.
  */
-PUBLIC int HTGetLinkInfo ARGS5(
+PUBLIC int HTGetLinkInfo ARGS6(
 	int,		number,
+	int,		want_go,
 	int *,		go_line,
 	int *,		linknum,
 	char **,	hightext,
@@ -2776,13 +3245,13 @@ PUBLIC int HTGetLinkInfo ARGS5(
 	/*
 	 *  Count anchors, first on current line if there is more
 	 *  than one.  We have to count all links, including form
-	 *  field anchors and others with a->number==0, because
+	 *  field anchors and others with a->number == 0, because
 	 *  they are or will be included in the links[] array.
-	 *  The exception are hidden form fields and anchors with
+	 *  The exceptions are hidden form fields and anchors with
 	 *  show_anchor not set, because they won't appear in links[]
 	 *  and don't count towards nlinks. - KW
 	 */
-	if ((go_line && a->show_anchor) &&
+	if ((a->show_anchor) &&
 	    (a->link_type != INPUT_ANCHOR ||
 	     a->input_field->type != F_HIDDEN_TYPE)) {
 	    if (a->line_num == prev_anchor_line) {
@@ -2814,7 +3283,7 @@ PUBLIC int HTGetLinkInfo ARGS5(
 	     *  We found it.  Now process it, depending
 	     *  on what kind of info is requested. - KW
 	     */
-	    if (go_line) {
+	    if (want_go || a->link_type == INPUT_ANCHOR) {
 		if (a->show_anchor == NO) {
 		    /*
 		     *  The number requested has been assigned to an anchor
@@ -2876,9 +3345,9 @@ PUBLIC int HTGetLinkInfo ARGS5(
 		link_dest = HTAnchor_followMainLink((HTAnchor *)a->anchor);
 		{
 		    char *cp_freeme = NULL;
-		    if (traversal)
+		    if (traversal) {
 			cp_freeme = stub_HTAnchor_address(link_dest);
-		    else {
+		    } else {
 			if (a->link_type == INTERNAL_LINK_ANCHOR) {
 			    link_dest_intl = HTAnchor_followTypedLink(
 				(HTAnchor *)a->anchor, LINK_INTERNAL);
@@ -2917,6 +3386,91 @@ PUBLIC int HTGetLinkInfo ARGS5(
 }
 
 /*
+ *  This function finds the line indicated by line_num in the
+ *  HText structure indicated by text, and searches that line
+ *  for the first hit with the string indicated by target.  If
+ *  there is no hit, FALSE is returned.  If there is a hit, then
+ *  a copy of the line starting at that first hit is loaded into
+ *  *data with all IsSpecial characters stripped, it's offset and
+ *  the printable target length (without IsSpecial, or extra CJK
+ *  or utf8 characters) are loaded into *offset and *tLen, and
+ *  TRUE is returned. - FM
+ */
+PUBLIC BOOL HText_getFirstTargetInLine ARGS7(
+	HText *,	text,
+	int,		line_num,
+	BOOL,		utf_flag,
+	int *,		offset,
+	int *,		tLen,
+	char **,	data,
+	char *,		target)
+{
+    HTLine *line;
+    char *LineData;
+    int LineOffset, HitOffset, LenNeeded, i;
+    char *cp;
+
+    /*
+     *  Make sure we have an HText structure, that line_num is
+     *  in its range, and that we have a target string. - FM
+     */
+    if (!(text && line_num >= 0 && line_num <= text->Lines &&
+	  target && *target))
+        return(FALSE);
+
+    /*
+     *  Find the line and set up its data and offset - FM
+     */
+    for (i = 0, line = text->last_line->next;
+    	 i < line_num && (line != text->last_line);
+         i++, line = line->next) {
+	if (line->next == NULL) {
+	    return(FALSE);
+	}
+    }
+    if (!line && line->data[0])
+        return(FALSE);
+    LineData = (char *)line->data;
+    LineOffset = (int)line->offset;
+
+    /*
+     *  If the target is on the line, load the offset of
+     *  its first character and the subsequent line data,
+     *  strip any special characters from the loaded line
+     *  data, and return TRUE. - FM
+     */
+    if ((case_sensitive ?
+	 (cp = LYno_attr_mbcs_strstr(LineData,
+				     target,
+				     utf_flag,
+				     &HitOffset,
+				     &LenNeeded)) != NULL :
+	 (cp = LYno_attr_mbcs_case_strstr(LineData,
+				     target,
+				     utf_flag,
+				     &HitOffset,
+				     &LenNeeded)) != NULL) &&
+	(LineOffset + LenNeeded) < LYcols) {
+	/*
+	 *  We had a hit so load the results,
+	 *  remove IsSpecial characters from
+	 *  the allocated data string, and
+	 *  return TRUE. - FM
+	 */
+	*offset = (LineOffset + HitOffset);
+	*tLen = (LenNeeded - HitOffset);
+	 StrAllocCopy(*data, cp);
+	 remove_special_attr_chars(*data);
+	 return(TRUE);
+    }
+
+    /*
+     *  The line does not contain the target. - FM
+     */
+    return(FALSE);
+}
+
+/*
  *  HText_getNumOfLines returns the number of lines in the
  *  current document.
  */
@@ -3722,24 +4276,34 @@ PUBLIC void print_crawl_to_fd ARGS3(
     if (thetitle != NULL)fprintf(fp,"THE_TITLE:%s\n",thetitle);;
       
     for (;; line = line->next) {
-        /* add offset */
+        /*
+	 *  Add offset.
+	 */
         for (i = 0; i < (int)line->offset; i++)
             fputc(' ',fp);
 
-        /* add data */
+        /*
+	 *  Add data.
+	 */
         for (i = 0; line->data[i] != '\0'; i++)
             if (!IsSpecialAttrChar(line->data[i]))
                 fputc(line->data[i],fp);
 
-        /* add the return */
+        /*
+	 *  Add the return.
+	 */
         fputc('\n',fp);
 
 	if (line == HTMainText->last_line)
 	    break;
     }
 
-    /* add the References list if appropriate */
-    if (keypad_mode == LINKS_ARE_NUMBERED && !nolist)
+    /*
+     *  Add the References list if appropriate
+     */
+    if ((nolist == FALSE) &&
+        (keypad_mode == LINKS_ARE_NUMBERED ||
+	 keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED))
         printlist(fp,FALSE);
 
 #ifdef VMS
@@ -4173,7 +4737,9 @@ PUBLIC void user_message ARGS2(
 	return;
     }
 
-   /* make sure we don't overun any buffers */
+    /*
+     *  Make sure we don't overrun any buffers.
+     */
     LYstrncpy(temp_arg, ((argument == NULL) ? "" : argument), 255);
     temp_arg[255] = '\0';
     temp = (char *)malloc(strlen(message) + strlen(temp_arg) + 1);
@@ -4256,20 +4822,22 @@ PUBLIC void HTuncache_current_document NOARGS
 	}
 #endif /* EXP_CHARTRANS */
 	if (TRACE) {
-	    fprintf(stderr, "\rHTuncache.. freeing document for %s %s\n",
-		    (htmain_anchor && htmain_anchor->address) ?
-		    htmain_anchor->address : "unknown anchor",
-		    (htmain_anchor && htmain_anchor->post_data) ?
-		    "with POST data" : ""
-		    );
+	    fprintf(stderr, "\rHTuncache.. freeing document for '%s'%s\n",
+			    ((htmain_anchor &&
+			      htmain_anchor->address) ?
+			       htmain_anchor->address : "unknown anchor"),
+			    ((htmain_anchor &&
+			      htmain_anchor->post_data) ?
+				      " with POST data" : ""));
 	}
         HTList_removeObject(loaded_texts, HTMainText);
 	HText_free(HTMainText);
 	HTMainText = NULL;
-    } else
+    } else {
 	if (TRACE) {
 	    fprintf(stderr, "HTuncache.. HTMainText already is NULL!\n");
 	}
+    }
 }
 
 PUBLIC int HTisDocumentSource NOARGS
@@ -4372,16 +4940,18 @@ PUBLIC char * HTLoadedDocumentBookmark NOARGS
 	return (NULL);
 }
 
-PUBLIC int HText_LastLineSize ARGS1(
-	HText *,	text)
+PUBLIC int HText_LastLineSize ARGS2(
+	HText *,	text,
+	BOOL,		IgnoreSpaces)
 {
     if (!text || !text->last_line || !text->last_line->size)
         return 0;
-    return HText_TrueLineSize(text->last_line, text);
+    return HText_TrueLineSize(text->last_line, text, IgnoreSpaces);
 }
 
-PUBLIC int HText_PreviousLineSize ARGS1(
-	HText *,	text)
+PUBLIC int HText_PreviousLineSize ARGS2(
+	HText *,	text,
+	BOOL,		IgnoreSpaces)
 {
     HTLine * line;
 
@@ -4389,24 +4959,45 @@ PUBLIC int HText_PreviousLineSize ARGS1(
         return 0;
     if (!(line = text->last_line->prev))
         return 0;
-    return HText_TrueLineSize(line, text);
+    return HText_TrueLineSize(line, text, IgnoreSpaces);
 }
 
-PRIVATE int HText_TrueLineSize ARGS2(HTLine *,line, HText *,text)
+PRIVATE int HText_TrueLineSize ARGS3(
+	HTLine *,	line,
+	HText *,	text,
+	BOOL,		IgnoreSpaces)
 {
     size_t i;
     int true_size = 0;
 
-    if (!line || !line->size)
+    if (!(line && line->size))
         return 0;
 
-    for (i = 0; i < line->size; i++) {
-    	if (!IsSpecialAttrChar(line->data[i])) {
+    if (IgnoreSpaces) {
+	for (i = 0; i < line->size; i++) {
+	    if (!IsSpecialAttrChar((unsigned char)line->data[i]) &&
+		(!(text && text->T.output_utf8) ||
+		 (unsigned char)line->data[i] < 128 ||
+		 ((unsigned char)(line->data[i] & 0xc0) == 0xc0)) &&
+	        !isspace((unsigned char)line->data[i]) &&
+		(unsigned char)line->data[i] != HT_NON_BREAK_SPACE &&
+		(unsigned char)line->data[i] != HT_EM_SPACE) {
 #ifdef EXP_CHARTRANS
 	  if (!text->T.output_utf8 || (unsigned char)line->data[i] < 128 ||
     		((unsigned char)(line->data[i] & 0xc0) == 0xc0))
 #endif /* EXP_CHARTRANS */
-	    true_size++;
+		true_size++;
+	    }
+	}
+    } else {
+	for (i = 0; i < line->size; i++) {
+	    if (!IsSpecialAttrChar(line->data[i])) {
+#ifdef EXP_CHARTRANS
+	  if (!text->T.output_utf8 || (unsigned char)line->data[i] < 128 ||
+    		((unsigned char)(line->data[i] & 0xc0) == 0xc0))
+#endif /* EXP_CHARTRANS */
+		true_size++;
+	    }
 	}
     }
     return true_size;
@@ -4462,11 +5053,13 @@ PUBLIC int HText_getCurrentColumn ARGS1(
 	HText *,	text)
 {
     int column = 0;
+    BOOL IgnoreSpaces = FALSE;
 
     if (text) {
         column = (text->in_line_1 ?
 		  (int)text->style->indent1st : (int)text->style->leftIndent)
-		  + HText_LastLineSize(text) + (int)text->last_line->offset;
+		  + HText_LastLineSize(text, IgnoreSpaces)
+		  + (int)text->last_line->offset;
     }
     return column;
 }
@@ -4768,7 +5361,86 @@ PUBLIC void HText_beginSelect ARGS3(
 } 
 
 /*
-**  We couln't set the value field for the previous option
+**  This function returns the number of the option whose
+**  value currently is being accumulated for a select
+**  block. - LE && FM
+*/
+PUBLIC int HText_getOptionNum ARGS1(
+	HText *,	text)
+{
+    TextAnchor *a;
+    OptionType *op;
+    int n = 1; /* start count at 1 */
+
+    if (!(text && text->last_anchor))
+        return(0);
+
+    a = text->last_anchor;
+    if (!(a->link_type == INPUT_ANCHOR && a->input_field &&
+          a->input_field->type == F_OPTION_LIST_TYPE))
+        return(0);
+
+    for (op = a->input_field->select_list; op; op = op->next)
+	n++;
+    if (TRACE)
+        fprintf(stderr, "HText_getOptionNum: Got number '%d'.\n", n);
+    return(n);
+}
+
+/*
+**  This function checks for a numbered option pattern
+**  as the prefix for an option value.  If present, and
+**  we are in the correct keypad mode, it returns a
+**  pointer to the actual value, following that prefix.
+**  Otherwise, it returns the original pointer.
+*/
+PRIVATE char * HText_skipOptionNumPrefix ARGS1(
+	char *,		opname)
+{
+    /*
+     *  Check if we are in the correct keypad mode.
+     */
+    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+	/*
+	 *  Skip the option number embedded in the option name so the
+	 *  extra chars won't mess up cgi scripts processing the value.
+	 *  The format is (nnn)__ where nnn is a number and there is a
+	 *  minumum of 5 chars (no underscores if (nnn) exceeds 5 chars).
+	 *  See HTML.c.  If the chars don't exactly match this format,
+	 *  just use all of opname.  - LE
+	 */
+	char *cp = opname;
+
+	if ((cp && *cp && *cp++ == '(') &&
+	    *cp && isdigit(*cp++)) {
+	    while (*cp && isdigit(*cp))
+	        ++cp;
+	    if (*cp && *cp++ == ')') {
+		int i = (cp - opname);
+
+		while (i < 5) {
+		    if (*cp != '_')
+		        break;
+		    i++;
+		    cp++;
+		}
+		if (i < 5 ) {
+		    cp = opname;
+		}
+	    } else {
+	        cp = opname;
+	    }
+	} else {
+	    cp = opname;
+	}
+	return(cp);
+    }
+
+    return(opname);
+}
+
+/*
+**  We couldn't set the value field for the previous option
 **  tag so we have to do it now.  Assume that the last anchor
 **  was the previous options tag.
 */
@@ -4779,7 +5451,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5(
 	int,		order,
 	BOOLEAN,	checked)
 {
-    char *cp;
+    char *cp, *cp1;
     unsigned char *tmp = NULL;
     int number = 0, i, j;
 
@@ -4810,6 +5482,26 @@ PUBLIC char * HText_setLastOptionValue ARGS5(
     while (isspace((unsigned char)*cp) ||
    	   IsSpecialAttrChar((unsigned char)*cp))
         cp++;
+    if (HTCurSelectGroupType == F_RADIO_TYPE &&
+	LYSelectPopups &&
+	keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+	/*
+	 *  Collapse any space beteen the popup option
+	 *  prefix and actual value. - FM
+	 */
+	if ((cp1 = HText_skipOptionNumPrefix(cp)) > cp) {
+	    i = 0, j = (cp1 - cp);
+	    while (isspace((unsigned char)cp1[i]) ||
+		   IsSpecialAttrChar((unsigned char)cp1[i])) {
+		i++;
+	    }
+	    if (i > 0) {
+		while (cp1[i] != '\0')
+		    cp[j++] = cp1[i++];
+		cp[j] = '\0';
+	    }
+	}
+    }
 
     if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
         StrAllocCopy(text->last_anchor->input_field->value, cp);
@@ -4896,8 +5588,9 @@ PUBLIC char * HText_setLastOptionValue ARGS5(
 	    StrAllocCopy(new_ptr->name, cp);
 	}
 	StrAllocCopy(new_ptr->cp_submit_value,
-	    	     (submit_value ? submit_value : new_ptr->name));
-	
+		     (submit_value ? submit_value :
+		      HText_skipOptionNumPrefix(new_ptr->name)));
+
 	if (first_option) {
 	    StrAllocCopy(HTCurSelectedOptionValue, new_ptr->name);
 	    text->last_anchor->input_field->num_value = 0;
@@ -4961,12 +5654,13 @@ PUBLIC char * HText_setLastOptionValue ARGS5(
 }
 
 /*
- *  Assign a form input anchor
- *  returns the number of charactors to leave blank
- *  so that the input field can fit
+ *  Assign a form input anchor.
+ *  Returns the number of charactors to leave
+ *  blank so that the input field can fit.
  */
-PUBLIC int HText_beginInput ARGS2(
+PUBLIC int HText_beginInput ARGS3(
 	HText *,		text,
+	BOOL,			underline,
 	InputFieldData *,	I)
 {
 	
@@ -4984,6 +5678,7 @@ PUBLIC int HText_beginInput ARGS2(
         outofmem(__FILE__, "HText_beginInput");
 
     a->start = text->chars + text->last_line->size;
+    a->inUnderline = underline;
     a->line_pos = text->last_line->size;
 
 
@@ -5166,6 +5861,8 @@ PUBLIC int HText_beginInput ARGS2(
 	    f->type = F_RANGE_TYPE;
 	} else if (!strcasecomp(I->type,"file")) {
 	    f->type = F_FILE_TYPE;
+	} else if (!strcasecomp(I->type,"keygen")) {
+	    f->type = F_KEYGEN_TYPE;
 	} else {
 	    /*
 	     *  Note that TYPE="scribble" defaults to TYPE="text". - FM
@@ -5279,25 +5976,80 @@ PUBLIC int HText_beginInput ARGS2(
     }
 
     /*
+     *  Add numbers to form fields if needed. - LE & FM
+     */
+    switch (f->type) {
+	/*
+	 *  Do not supply number for hidden fields, nor
+	 *  for types that are not yet implemented.
+	 */
+	case F_HIDDEN_TYPE:
+	case F_FILE_TYPE:
+	case F_RANGE_TYPE:
+	case F_KEYGEN_TYPE:
+	    a->number = 0;
+	    break;
+
+	default:
+	    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)
+		a->number = ++(text->last_anchor_number);
+	    else 
+		a->number = 0;
+	    break;
+    }
+    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED && a->number > 0) {
+	char marker[16];
+
+	if (f->type != F_OPTION_LIST_TYPE)
+	    /*
+	     *  '[' was already put out for a popup menu
+	     *  designator.  See HTML.c.
+	     */
+	    HText_appendCharacter(text, '[');
+	sprintf(marker,"%d]", a->number);
+	HText_appendText(text, marker);
+	if (f->type == F_OPTION_LIST_TYPE)
+	    /*
+	     *  Add option list designation char.
+	     */
+	    HText_appendCharacter(text, '[');
+	a->start = text->chars + text->last_line->size;
+	a->line_pos = text->last_line->size;
+    }
+
+    /*
      *  Restrict SIZE to maximum allowable size.
      */
     switch (f->type) {
-        int MaximumSize;
+	int MaximumSize;
 
 	case F_SUBMIT_TYPE:
 	case F_IMAGE_SUBMIT_TYPE:
 	case F_RESET_TYPE:
+	case F_TEXT_TYPE:
+	case F_TEXTAREA_TYPE:
 	    /*
-	     *  For submit and reset buttons, we limit the size
-	     *  element to that of one line for the current style
-	     *  because that's the most we could highlight on
-	     *  overwrites- FM
+	     *  For submit and reset buttons, and for text entry
+	     *  fields and areas, we limit the size element to that
+	     *  of one line for the current style because that's
+	     *  the most we could highlight on overwrites, and/or
+	     *  handle in the line editor.  The actual values for
+	     *  text entry lines can be long, and will be scrolled
+	     *  horizontally within the editing window. - FM
 	     */
 	    MaximumSize = (LYcols - 1) -
 			  (int)text->style->leftIndent -
 			  (int)text->style->rightIndent;
+
+	    /*
+	     *  If we are numbering form links, take that into
+	     *  account as well. - FM
+	     */
+	    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED)
+	        MaximumSize -= ((a->number/10) + 3);
 	    if (f->size > MaximumSize)
 	        f->size = MaximumSize;
+
 	    /*
 	     *  Save value for submit/reset buttons so they
 	     *  will be visible when printing the page. - LE
@@ -5305,13 +6057,13 @@ PUBLIC int HText_beginInput ARGS2(
 	    I->value = f->value;
 	    break;
 
+
 	default:
 	    /*
-	     *  For all other fields we limit the size element
-	     *  to 10 less than the screen width, because either
-	     *  they are types with small placeholders, or are a
-	     *  type which can be scrolled horizontally within
-	     *  an editing window. - FM
+	     *  For all other fields we limit the size element to
+	     *  10 less than the screen width, because either they
+	     *  are types with small placeholders, and/or are a
+	     *  type which is handled via a popup window. - FM
 	     */
 	    if (f->size > LYcols-10)
 		f->size = LYcols-10;  /* maximum */
@@ -5328,7 +6080,7 @@ PUBLIC int HText_beginInput ARGS2(
 		 	f->name,
 			((f->value != NULL) ? f->value : ""),
 			f->size);
-	
+
     /*
      *  Return the SIZE of the input field.
      */
@@ -6269,6 +7021,12 @@ PUBLIC BOOL HText_hasNoCacheSet ARGS1(
     return ((text && text->no_cache) ? TRUE : FALSE);
 }
 
+PUBLIC BOOL HText_hasUTF8OutputSet ARGS1(
+	HText *,	text)
+{
+    return ((text && text->T.output_utf8) ? TRUE : FALSE);
+}
+
 /*
 **  Check charset and set the kcode element. - FM
 */
@@ -6347,7 +7105,9 @@ PUBLIC BOOL HText_AreDifferent ARGS2(
 	CONST char *,		full_address)
 {
     HTParentAnchor *MTanc;
-    char *pound;
+    char *MTaddress;
+    char *MTpound;
+    char *TargetPound;
 
     /*
      *  Do we have a loaded document and both
@@ -6366,67 +7126,76 @@ PUBLIC BOOL HText_AreDifferent ARGS2(
     /*
      *  Do we have a fragment associated with the target?
      */
-    if ((pound = strchr(full_address, '#')) == NULL)
+    if ((TargetPound = strchr(full_address, '#')) == NULL)
 	return (TRUE);
 
     /*
      *  Always treat client-side image map menus
-     *  as potentially stale.
+     *  as potentially stale, so we'll create a
+     *  fresh menu from the LynxMaps HTList.
      */
     if (!strncasecomp(anchor->address, "LYNXIMGMAP:", 11))
 	return (TRUE);
 
     /*
-     *  Do they differ in the type of request?
+     *  Do the docs differ in the type of request?
      */
     if (MTanc->isHEAD != anchor->isHEAD)
         return (TRUE);
 
     /* 
-     *  Are the actual URLs different?
+     *  Are the actual URLs different, after factoring
+     *  out a "LYNXIMGMAP:" leader in the MainText URL
+     *  and its fragment, if present?
      */
-    if (strcmp(MTanc->address, anchor->address))
+    MTaddress = (strncasecomp(MTanc->address,
+			      "LYNXIMGMAP:", 11) ?
+				  MTanc->address : (MTanc->address + 11));
+    if ((MTpound = strchr(MTaddress, '#')) != NULL)
+        *MTpound = '\0';
+    if (strcmp(MTaddress, anchor->address)) {
+    	if (MTpound != NULL) {
+	    *MTpound = '#';
+	}
 	return(TRUE);
+    }
+    if (MTpound != NULL) {
+	*MTpound = '#';
+    }
 
     /*
-     *  Do the docs have different contents?
+     *  If the MainText is not an image map menu,
+     *  do the docs have different POST contents?
      */
-    if (MTanc->post_data) {
-	if (anchor->post_data) {
-	    if (strcmp(MTanc->post_data, anchor->post_data)) {
-	        /*
-		 *  Both have contents, and they differ.
+    if (MTaddress == MTanc->address) {
+	if (MTanc->post_data) {
+	    if (anchor->post_data) {
+		if (strcmp(MTanc->post_data, anchor->post_data)) {
+		    /*
+		     *  Both have contents, and they differ.
+		     */
+		    return(TRUE);
+		}
+	    } else {
+		/*
+		 *  The loaded document has content, but the
+		 *  target doesn't, so they're different.
 		 */
 		return(TRUE);
 	    }
-	} else {
+	} else if (anchor->post_data) {
 	    /*
-	     *  The loaded document has content, but the
-	     *  target doesn't, so they're different.
-	     */
-	    return(TRUE);
-	}
-    } else if (anchor->post_data) {
-    	    /*
 	     *  The loaded document does not have content, but
 	     *  the target does, so they're different.
 	     */
 	    return(TRUE);
+	}
     }
 
     /*
-     *  Are we seeking a position in the loaded document
-     *  based on a fragment?
-     */
-    if (!strncmp(MTanc->address, full_address, (pound - full_address)))
-	return(FALSE);
-
-    /*
-     *  We'll assume the loaded document and target should be
-     *  treated as different, either because we are reloading,
-     *  or because we had header, META, or other directives not
-     *  to use a cached rendition. - FM
+     *  We'll assume the target is a position in the currently
+     *  displayed document, and thus can ignore any header, META,
+     *  or other directives not to use a cached rendition. - FM
      */
-    return(TRUE);
-
+    return(FALSE);
 }
diff --git a/src/GridText.h b/src/GridText.h
index d606c16f..92c2d40f 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -44,6 +44,7 @@ extern BOOLEAN mustshow;
 extern int HTVirtualMemorySize;
 #endif /* VMS && VAXC && !__DECC */
 extern HTChildAnchor * HText_childNumber PARAMS((int n));
+extern void HText_FormDescNumber PARAMS((int n, char **desc));
 
 /*	Is there any file left?
 */
@@ -87,10 +88,19 @@ extern BOOL HText_POSTReplyLoaded PARAMS((document *doc));
 extern BOOL HTFindPoundSelector PARAMS((char *selector));
 extern int HTGetLinkInfo PARAMS((
 	int		number,
+	int		want_go,
 	int *		go_line,
 	int *		linknum,
 	char **		hightext,
 	char **		lname));
+extern BOOL HText_getFirstTargetInLine PARAMS((
+	HText *		text,
+	int		line_num,
+	BOOL		utf_flag,
+	int *		offset,
+	int *		tLen,
+	char **		data,
+	char *		target));
 extern int HTisDocumentSource NOPARAMS;
 extern void HTuncache_current_document NOPARAMS;
 extern int HText_getTopOfScreen NOPARAMS;
@@ -106,8 +116,8 @@ extern char * HTLoadedDocumentCharset NOPARAMS;
 extern BOOL HTLoadedDocumentEightbit NOPARAMS;
 extern void HText_setNodeAnchorBookmark PARAMS((CONST char *bookmark));
 extern char * HTLoadedDocumentBookmark NOPARAMS;
-extern int HText_LastLineSize PARAMS((HText *me));
-extern int HText_PreviousLineSize PARAMS((HText *me));
+extern int HText_LastLineSize PARAMS((HText *me, BOOL IgnoreSpaces));
+extern int HText_PreviousLineSize PARAMS((HText *me, BOOL IgnoreSpaces));
 extern void HText_NegateLineOne PARAMS((HText *text));
 extern void HText_RemovePreviousLine PARAMS((HText *text));
 extern int HText_getCurrentColumn PARAMS((HText *text));
@@ -125,13 +135,17 @@ extern void HText_beginForm PARAMS((
 	char *		title));
 extern void HText_endForm PARAMS((HText *text));
 extern void HText_beginSelect PARAMS((char *name, BOOLEAN multiple, char *len));
+extern int HText_getOptionNum PARAMS((HText *text));
 extern char * HText_setLastOptionValue PARAMS((
 	HText *		text,
 	char *		value,
 	char *		submit_value,
 	int 		order,
 	BOOLEAN		checked));
-extern int HText_beginInput PARAMS((HText *text, InputFieldData *I));
+extern int HText_beginInput PARAMS((
+	HText *		text,
+	BOOL		underline,
+	InputFieldData *I));
 extern void HText_SubmitForm PARAMS((
 	FormInfo *	submit_item,
 	document *	doc,
@@ -163,6 +177,7 @@ extern BOOL HText_hasToolbar PARAMS((HText *text));
 extern void HText_setNoCache PARAMS((HText *text));
 extern BOOL HText_hasNoCacheSet PARAMS((HText *text));
 
+extern BOOL HText_hasUTF8OutputSet PARAMS((HText *text));
 extern void HText_setKcode PARAMS((HText *text, CONST char *charset));
 
 extern void HText_setBreakPoint PARAMS((HText *text));
diff --git a/src/HTAlert.c b/src/HTAlert.c
index 246716e3..78a931e0 100644
--- a/src/HTAlert.c
+++ b/src/HTAlert.c
@@ -140,11 +140,14 @@ PUBLIC char * HTPromptPassword ARGS1(
 **  On entry,
 **      Msg             is the prompting message.
 **      *username and
-**      *password       are char pointers; they are changed
+**      *password       are char pointers which contain default
+**			or zero-length strings; they are changed
 **                      to point to result strings.
+**	IsProxy		should be TRUE if this is for
+**			proxy authentication.
 **
 **                      If *username is not NULL, it is taken
-**                      to point to  a default value.
+**                      to point to a default value.
 **                      Initial value of *password is
 **                      completely discarded.
 **
@@ -154,40 +157,71 @@ PUBLIC char * HTPromptPassword ARGS1(
 **      are NOT freed.
 **
 */
-PUBLIC void HTPromptUsernameAndPassword ARGS3(
+PUBLIC void HTPromptUsernameAndPassword ARGS4(
 	CONST char *,	Msg,
 	char **,	username,
-	char **,	password)
+	char **,	password,
+	BOOL,		IsProxy)
 {
-    if (authentication_info[0] && authentication_info[1]) {
+    if ((IsProxy == FALSE &&
+	 authentication_info[0] && authentication_info[1]) ||
+	(IsProxy == TRUE &&
+	 proxyauth_info[0] && proxyauth_info[1])) {
 	/* 
-	**  -auth parameter gave us both the username and password
-	**  to use for the first realm, so just use them without
-	**  any prompting. - FM
+	**  The -auth or -pauth parameter gave us both the username
+	**  and password to use for the first realm or proxy server,
+	**  respectively, so just use them without any prompting. - FM
 	*/
- 	StrAllocCopy(*username, authentication_info[0]);
-	FREE(authentication_info[0]);
-	StrAllocCopy(*password, authentication_info[1]);
-	FREE(authentication_info[1]);
+ 	StrAllocCopy(*username, (IsProxy ?
+		       proxyauth_info[0] : authentication_info[0]));
+	if (IsProxy) {
+	    FREE(proxyauth_info[0]);
+	} else {
+	    FREE(authentication_info[0]);
+	}
+	StrAllocCopy(*password, (IsProxy ?
+		       proxyauth_info[1] : authentication_info[1]));
+	if (IsProxy) {
+	    FREE(proxyauth_info[1]);
+	} else {
+	    FREE(authentication_info[1]);
+	}
     } else if (dump_output_immediately) {
-        if (authentication_info[0]) {
+        /*
+	 *  We are not interactive and don't have both the
+	 *  username and password from the command line,
+	 *  but might have one or the other. - FM
+	 */
+        if ((IsProxy == FALSE && authentication_info[0]) ||
+	    (IsProxy == TRUE && proxyauth_info[0])) {
 	    /*
 	    **  Use the command line username. - FM
 	    */
-	    StrAllocCopy(*username, authentication_info[0]);
-	    FREE(authentication_info[0]);
+	    StrAllocCopy(*username, (IsProxy ?
+			   proxyauth_info[0] : authentication_info[0]));
+	    if (IsProxy) {
+		FREE(proxyauth_info[0]);
+	    } else {
+		FREE(authentication_info[0]);
+	    }
 	} else {
 	    /*
 	    **  Default to "WWWuser". - FM
 	    */
             StrAllocCopy(*username, "WWWuser");
 	}
-	if (authentication_info[1]) {
+        if ((IsProxy == FALSE && authentication_info[1]) ||
+	    (IsProxy == TRUE && proxyauth_info[1])) {
 	    /*
 	    **  Use the command line password. - FM
 	    */
-	    StrAllocCopy(*password, authentication_info[1]);
-	    FREE(authentication_info[1]);
+	    StrAllocCopy(*password, (IsProxy ?
+			   proxyauth_info[1] : authentication_info[1]));
+	    if (IsProxy) {
+		FREE(proxyauth_info[1]);
+	    } else {
+		FREE(authentication_info[1]);
+	    }
 	} else {
 	    /*
 	    **  Default to a zero-length string. - FM
@@ -195,30 +229,51 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3(
 	    StrAllocCopy(*password, "");
 	}
 	printf("\n%s\n", USERNAME_PASSWORD_REQUIRED);
+
     } else {
-        if (authentication_info[0]) {
+        /*
+	 *  We are interactive and don't have both the
+	 *  username and password from the command line,
+	 *  but might have one or the other. - FM
+	 */
+        if ((IsProxy == FALSE && authentication_info[0]) ||
+	    (IsProxy == TRUE && proxyauth_info[0])) {
 	    /*
-	    **  Offer command line username in the prompt
-	    **  for the first realm. - FM
+	    **  Offer the command line username in the
+	    **  prompt for the first realm. - FM
 	    */
-	    StrAllocCopy(*username, authentication_info[0]);
-	    FREE(authentication_info[0]);
+	    StrAllocCopy(*username, (IsProxy ?
+			   proxyauth_info[0] : authentication_info[0]));
+	    if (IsProxy) {
+		FREE(proxyauth_info[0]);
+	    } else {
+		FREE(authentication_info[0]);
+	    }
 	}
+	/*
+	 *  Prompt for confirmation or entry of the username. - FM
+	 */
 	if (Msg != NULL) {
 	    *username = HTPrompt(Msg, *username);
 	} else {
 	    *username = HTPrompt(USERNAME_PROMPT, *username);
 	}
-	if (authentication_info[1]) {
+        if ((IsProxy == FALSE && authentication_info[1]) ||
+	    (IsProxy == TRUE && proxyauth_info[1])) {
 	    /*
 	    **  Use the command line password for the first realm. - FM
 	    */
-	    StrAllocCopy(*password, authentication_info[1]);
-	    FREE(authentication_info[1]);
+	    StrAllocCopy(*password, (IsProxy ?
+			   proxyauth_info[1] : authentication_info[1]));
+	    if (IsProxy) {
+		FREE(proxyauth_info[1]);
+	    } else {
+		FREE(authentication_info[1]);
+	    }
 	} else if (*username != NULL && *username[0] != '\0') {
 	    /*
-	    **  If we have a non-zero length username,
-	    **  prompt for the password. - FM
+	    **  We have a non-zero length username,
+	    **  so prompt for the password. - FM
 	    */
 	    *password = HTPromptPassword(PASSWORD_PROMPT);
 	} else {
@@ -227,7 +282,6 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3(
 	    */
 	    StrAllocCopy(*password, "");
 	}
-	
     }
 }
 
diff --git a/src/HTAlert.h b/src/HTAlert.h
index 73013918..ec1d2397 100644
--- a/src/HTAlert.h
+++ b/src/HTAlert.h
@@ -64,6 +64,8 @@ extern char * HTPromptPassword PARAMS((CONST char * Msg));
 **      *username and
 **      *password       are char pointers; they are changed
 **                      to point to result strings.
+**	IsProxy		should be TRUE if this is for
+**			proxy authentication.
 **
 **                      If *username is not NULL, it is taken
 **                      to point to  a default value.
@@ -79,7 +81,8 @@ extern char * HTPromptPassword PARAMS((CONST char * Msg));
 extern void HTPromptUsernameAndPassword PARAMS((
 	CONST char *	Msg,
 	char **		username,
-	char **		password));
+	char **		password,
+	BOOL		IsProxy));
 
 
 /*	Confirm a cookie operation.			HTConfirmCookie()
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index 24bbb136..3589811b 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -44,9 +44,6 @@ PUBLIC char * WWW_Download_File=NULL; /* contains the name of the temp file
 				      */
 PUBLIC char LYCancelDownload=FALSE;   /* exported to HTFormat.c in libWWW */
 
-/* Type mismatch found here - char != BOOLEAN - WSB */
-extern BOOLEAN dump_output_immediately;  /* if true dump to stdout and quit */
-
 #ifdef VMS
 extern BOOLEAN HadVMSInterrupt;      /* flag from cleanup_sig()		*/
 PRIVATE char * FIXED_RECORD_COMMAND = NULL;
@@ -224,14 +221,20 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
 		    FREE(path);
 		    FREE(me->anchor->content_encoding);
 #ifdef EXP_CHARTRANS
-		    /* lock the chartrans info we may possibly have,
-		       so HTCharSetFormat will not apply the default for
-		       local files */
+		    /*
+		     *  Lock the chartrans info we may possibly have,
+		     *  so HTCharsetFormat() will not apply the default
+		     *  for local files. - KW
+		     */
 		    HTAnchor_copyUCInfoStage(me->anchor,
 					     UCT_STAGE_PARSER,
 					     UCT_STAGE_MIME,
 					     UCT_SETBY_PARSER);
 #endif
+		    /*
+		     *  Now have HTLoadFile() handle the uncompressed
+		     *  file as if it were the original reply. - FM
+		     */
 		    status = HTLoadFile(addr,
 			    		me->anchor,
 			    		me->output_format,
@@ -512,6 +515,7 @@ SaveAndExecute_tempname:
 	FREE(me);
 	return NULL;
     }
+    chmod(fnam, 0600);
 
     /*
      *  Make command to process file.
@@ -522,7 +526,7 @@ SaveAndExecute_tempname:
     if (me->end_command == NULL)
         outofmem(__FILE__, "HTSaveAndExecute");
     
-    sprintf (me->end_command, pres->command, fnam, "");
+    sprintf(me->end_command, pres->command, fnam, "", "", "", "", "", "");
 
     /*
      *  Make command to delete file.
@@ -533,7 +537,7 @@ SaveAndExecute_tempname:
     if (me->remove_command == NULL)
         outofmem(__FILE__, "HTSaveAndExecute");
     
-    sprintf (me->remove_command, REMOVE_COMMAND, fnam);
+    sprintf(me->remove_command, REMOVE_COMMAND, fnam, "", "", "", "", "", "");
 
     StrAllocCopy(anchor->FileCache, fnam);
     return me;
@@ -710,6 +714,7 @@ SaveToFile_tempname:
         FREE(ret_obj);
         return NULL;
     }
+    chmod(fnam, 0600);
 
     /*
      *  Any "application/foo" or other non-"text/foo" types that
@@ -731,8 +736,9 @@ SaveToFile_tempname:
     			 * sizeof (char),1);
     if (ret_obj->remove_command == NULL)
         outofmem(__FILE__, "HTSaveToFile");
-    
-    sprintf (ret_obj->remove_command, REMOVE_COMMAND, fnam);
+
+    sprintf(ret_obj->remove_command,
+	    REMOVE_COMMAND, fnam, "", "", "", "", "", "");
 
 #ifdef VMS
     if (IsBinary && UseFixedRecords) {
@@ -745,7 +751,8 @@ SaveToFile_tempname:
     		* sizeof (char),1);
         if (FIXED_RECORD_COMMAND == NULL)
 	    outofmem(__FILE__, "HTSaveToFile");
-        sprintf(FIXED_RECORD_COMMAND, FIXED_RECORD_COMMAND_MASK, fnam);
+        sprintf(FIXED_RECORD_COMMAND,
+		FIXED_RECORD_COMMAND_MASK, fnam, "", "", "", "", "", "");
     } else {
 #endif /* VMS */
     ret_obj->end_command = (char *)calloc (sizeof(char)*12,1);
@@ -909,7 +916,7 @@ PUBLIC HTStream* HTCompressed ARGS3(
      */
 Compressed_tempname:
     tempname(fnam, NEW_FILE);
-    if ((cp = strchr(fnam, '.')) != NULL) {
+    if ((cp = strrchr(fnam, '.')) != NULL) {
 	*cp = '\0';
 	if (!strcasecomp(anchor->content_type, "text/html")) {
 #ifdef VMS
@@ -970,6 +977,7 @@ Compressed_tempname:
 	FREE(me);
 	return NULL;
     }
+    chmod(fnam, 0600);
 
     /*
      *  Make command to process file. - FM
@@ -978,7 +986,7 @@ Compressed_tempname:
     					 strlen(fnam)) * sizeof(char));
     if (me->end_command == NULL)
         outofmem(__FILE__, "HTCompressed");
-    sprintf (me->end_command, uncompress_mask, fnam);
+    sprintf(me->end_command, uncompress_mask, fnam, "", "", "", "", "", "");
     FREE(uncompress_mask);
 
     /*
@@ -988,7 +996,7 @@ Compressed_tempname:
     					    strlen(fnam)) * sizeof(char));
     if (me->remove_command == NULL)
         outofmem(__FILE__, "HTCompressed");
-    sprintf (me->remove_command, REMOVE_COMMAND, fnam);
+    sprintf(me->remove_command, REMOVE_COMMAND, fnam, "", "", "", "", "", "");
 
     /*
      *  Save the filename and return the structure. - FM
diff --git a/src/HTML.c b/src/HTML.c
index f49e0084..2e98ae53 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -138,24 +138,23 @@ PRIVATE void actually_set_style ARGS1(HTStructured *, me)
 {
     if (!me->text) {			/* First time through */
 #ifdef EXP_CHARTRANS
-	html_get_chartrans_info(me);
+	LYGetChartransInfo(me);
 	UCSetTransParams(&me->T,
 		     me->UCLYhndl, me->UCI,
 		     HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_HTEXT),
 		     HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_HTEXT));
 #endif /* EXP_CHARTRANS */
-	    me->text = HText_new2(me->node_anchor, me->target);
-	    HText_beginAppend(me->text);
-	    HText_setStyle(me->text, me->new_style);
-	    me->in_word = NO;
-	    LYCheckForContentBase(me);
+	me->text = HText_new2(me->node_anchor, me->target);
+	HText_beginAppend(me->text);
+	HText_setStyle(me->text, me->new_style);
+	me->in_word = NO;
+	LYCheckForContentBase(me);
     } else {
-	    HText_setStyle(me->text, me->new_style);
+	HText_setStyle(me->text, me->new_style);
     }
 
     me->old_style = me->new_style;
     me->style_change = NO;
-
 }
 
 /*
@@ -522,14 +521,16 @@ PRIVATE void HTML_start_element ARGS5(
 #endif
     HTParentAnchor *dest = NULL;	     /* An anchor's destination */
     BOOL dest_ismap = FALSE;	     	     /* Is dest an image map script? */
+    BOOL UseBASE = TRUE;		     /* Resoved vs. BASE if present? */
     HTChildAnchor *ID_A = NULL;		     /* HTML_foo_ID anchor */
     int url_type = 0, i = 0;
     BOOL intern_flag = FALSE;
     char *cp = NULL;
+    int ElementNumber = element_number;
 
     if (LYMapsOnly) {
-        if (!(element_number == HTML_MAP || element_number == HTML_AREA ||
-	      element_number == HTML_BASE)) {
+        if (!(ElementNumber == HTML_MAP || ElementNumber == HTML_AREA ||
+	      ElementNumber == HTML_BASE)) {
 	    return;
 	}
     }
@@ -586,7 +587,7 @@ PRIVATE void HTML_start_element ARGS5(
                         fprintf(stderr, " ca=%d\n", hashStyles[hcode].color);
         }
 
-    if (displayStyles[element_number].color > -2) /* actually set */
+    if (displayStyles[element_number].color > -1) /* actually set */
     {
         if (TRACE)
                 fprintf(stderr, "CSSTRIM: start_element: top <%s>\n", HTML_dtd.tags[element_number].name);
@@ -598,24 +599,16 @@ PRIVATE void HTML_start_element ARGS5(
 	me->inStyle[element_number]=1; /* this is a goodthing(tm) */
 #endif
 
-    switch (element_number) {
+    switch (ElementNumber) {
 
     case HTML_HTML:
 	if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	break;
 
     case HTML_HEAD:
 	if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	break;
 
     case HTML_BASE:
@@ -709,10 +702,6 @@ PRIVATE void HTML_start_element ARGS5(
 	if (!me->text)
 	    UPDATE_STYLE;
         HTChunkClear(&me->title);
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	break;
 
     case HTML_LINK:
@@ -966,6 +955,17 @@ PRIVATE void HTML_start_element ARGS5(
 		break;
 	    }
 
+	    if (me->inA) {
+	        /*
+		 *  Ugh!  The LINK tag, which is a HEAD element,
+		 *  is in an Anchor, which is BODY element.  All
+		 *  we can do is close the Anchor and cross our
+		 *  fingers. - FM
+		 */
+		SET_SKIP_STACK(HTML_A);
+		HTML_end_element(me, HTML_A, (char **)&include);
+	    }
+
 	    /*
 	     *  Create anchors for the links that simulate
 	     *  a toolbar. - FM
@@ -990,11 +990,12 @@ PRIVATE void HTML_start_element ARGS5(
 					NULL,			/* Addresss */
 					(HTLinkType*)0))) {	/* Type */
 		HText_appendCharacter(me->text, '#');
-		HText_beginAnchor(me->text, ID_A);
-		HText_endAnchor(me->text);
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
+		HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		HText_endAnchor(me->text, 0);
 		HText_setToolbar(me->text);
 	    }
-	    HText_beginAnchor(me->text, me->CurrentA);
+	    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
 	    if (me->inBoldH == FALSE)
 	        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 #if USE_COLOR_STYLE
@@ -1020,7 +1021,7 @@ PRIVATE void HTML_start_element ARGS5(
 #endif
 	    if (me->inBoldH == FALSE)
 	        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-	    HText_endAnchor(me->text);
+	    HText_endAnchor(me->text, 0);
 	}
 	FREE(href);
 	FREE(title);
@@ -1135,10 +1136,6 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_BODY:
 	if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	LYCheckForID(me, present, value, (int)HTML_BODY_ID);
 	if (HText_hasToolbar(me->text))
 	    HText_appendParagraph(me->text);
@@ -1190,6 +1187,10 @@ PRIVATE void HTML_start_element ARGS5(
 			         me->inBASE) ?
 			       me->base_href : me->node_anchor->address));
 
+	    if (me->inA) {
+		SET_SKIP_STACK(HTML_A);
+		HTML_end_element(me, HTML_A, (char **)&include);
+	    }
 	    me->CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 				NULL,			/* Tag */
@@ -1203,17 +1204,20 @@ PRIVATE void HTML_start_element ARGS5(
 	        HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	    HTML_put_character(me, ' ');
 	    me->in_word = NO;
-	    HText_beginAnchor(me->text, me->CurrentA);
+	    LYCheckForID(me, present, value, (int)HTML_FRAME_ID);
+	    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
 	    if (me->inBoldH == FALSE)
 		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    HTML_put_string(me, (id_string ? id_string : href));
 	    FREE(href);
-	    FREE(id_string);
 	    if (me->inBoldH == FALSE)
 		HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-	    HText_endAnchor(me->text);
+	    HText_endAnchor(me->text, 0);
 	    LYEnsureSingleSpace(me);
+	} else {
+	    LYCheckForID(me, present, value, (int)HTML_FRAME_ID);
 	}
+	FREE(id_string);
 	break;
 
     case HTML_NOFRAMES:
@@ -1223,11 +1227,84 @@ PRIVATE void HTML_start_element ARGS5(
 	LYResetParagraphAlignment(me);
 	break;
 
+    case HTML_IFRAME:
+	if (!me->text)
+	    UPDATE_STYLE;
+	if (present && present[HTML_IFRAME_NAME] &&
+	    value[HTML_IFRAME_NAME] && *value[HTML_IFRAME_NAME]) {
+	    StrAllocCopy(id_string, value[HTML_IFRAME_NAME]);
+	    if (current_char_set)
+		LYExpandString(&id_string);
+	    /*
+	     *  Convert any HTML entities or decimal escaping. - FM
+	     */
+	    LYUnEscapeEntities(id_string, TRUE, FALSE);
+	    LYTrimHead(id_string);
+	    LYTrimTail(id_string);
+	}
+	if (present && present[HTML_IFRAME_SRC] &&
+	    value[HTML_IFRAME_SRC] && *value[HTML_IFRAME_SRC] != '\0') {
+	    StrAllocCopy(href, value[HTML_IFRAME_SRC]);
+	    CHECK_FOR_INTERN(href);
+	    url_type = LYLegitimizeHREF(me, (char**)&href, TRUE, TRUE);
+
+	    /*
+	     *  Check whether a base tag is in effect. - FM
+	     */
+	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
+		*temp != '\0')
+		/*
+		 *  Use reference related to the base.
+		 */
+		StrAllocCopy(href, temp);
+	    FREE(temp);
+
+	    /*
+	     *  Check whether to fill in localhost. - FM
+	     */
+	    LYFillLocalFileURL((char **)&href,
+			       ((*href != '\0' && *href != '#' &&
+			         me->inBASE) ?
+			       me->base_href : me->node_anchor->address));
+
+	    if (me->inA)
+		HTML_end_element(me, HTML_A, (char **)&include);
+	    me->CurrentA = HTAnchor_findChildAndLink(
+				me->node_anchor,	/* Parent */
+				NULL,			/* Tag */
+				href,			/* Addresss */
+				INTERN_LT);		/* Type */
+	    LYEnsureDoubleSpace(me);
+	    LYResetParagraphAlignment(me);
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    HTML_put_string(me, "IFRAME:");
+	    if (me->inUnderline == FALSE)
+	        HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    HTML_put_character(me, ' ');
+	    me->in_word = NO;
+	    LYCheckForID(me, present, value, (int)HTML_IFRAME_ID);
+	    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+	    HTML_put_string(me, (id_string ? id_string : href));
+	    FREE(href);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+	    HText_endAnchor(me->text, 0);
+	    LYEnsureSingleSpace(me);
+	} else {
+	    LYCheckForID(me, present, value, (int)HTML_IFRAME_ID);
+	}
+	FREE(id_string);
+	break;
+
     case HTML_BANNER:
     case HTML_MARQUEE:
     	change_paragraph_style(me, styles[HTML_BANNER]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == element_number)
+	if (me->sp->tag_number == ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	if (!HText_hasToolbar(me->text) &&
 	    (ID_A = HTAnchor_findChildAndLink(
@@ -1235,8 +1312,8 @@ PRIVATE void HTML_start_element ARGS5(
 					LYToolbarName,		/* Tag */
 					NULL,			/* Addresss */
 					(HTLinkType*)0))) {	/* Type */
-	    HText_beginAnchor(me->text, ID_A);
-	    HText_endAnchor(me->text);
+	    HText_beginAnchor(me->text, me->inUnderline, ID_A);
+	    HText_endAnchor(me->text, 0);
 	    HText_setToolbar(me->text);
 	}
 	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
@@ -1251,7 +1328,7 @@ PRIVATE void HTML_start_element ARGS5(
 		"HTML: ****** Maximum nesting of %d divisions exceeded!\n",
             	MAX_NESTING);
 	}
-	if (element_number == HTML_CENTER) {
+	if (ElementNumber == HTML_CENTER) {
 	    me->DivisionAlignments[me->Division_Level] = HT_CENTER;
     	    change_paragraph_style(me, styles[HTML_DCENTER]);
 	    UPDATE_STYLE;
@@ -1302,6 +1379,45 @@ PRIVATE void HTML_start_element ARGS5(
 	i_prior_style = element_number;
 	 */
 
+	/*
+	 *  Check whether we have an H# in a list,
+	 *  and if so, treat it as an LH. - FM
+	 */
+	if ((me->List_Nesting_Level >= 0) &&
+	    (me->sp[0].tag_number == HTML_UL ||
+	     me->sp[0].tag_number == HTML_OL ||
+	     me->sp[0].tag_number == HTML_MENU ||
+	     me->sp[0].tag_number == HTML_DIR)) {
+	    if (HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY) {
+		ElementNumber = HTML_LH;
+		if (!me->text)
+		    UPDATE_STYLE;
+	    } else {
+		me->new_style = me->sp[0].style;
+		ElementNumber = me->sp[0].tag_number;
+		UPDATE_STYLE;
+	    }
+	    /*
+	     *  Some authors use H# headers as a substitute for
+	     *  FONT, so check if this one immediately followed
+	     *  an LI.  If so, both me->inP and me->in_word will
+	     *  be FALSE (though the line might not be empty due
+	     *  to a bullet and/or nbsp) and we can assume it is
+	     *  just for a FONT change.  We thus will not create
+	     *  another line break nor add to the current left
+	     *  indentation. - FM
+	     */
+	    if (!(me->inP == FALSE && me->in_word == NO)) {
+		HText_appendParagraph(me->text);
+		HTML_put_character(me, HT_NON_BREAK_SPACE);
+		HText_setLastChar(me->text, ' ');
+		me->in_word = NO;
+		me->inP = FALSE;
+	    }
+	    LYCheckForID(me, present, value, (int)HTML_H_ID);
+	    break;
+	}
+
 	if (present && present[HTML_H_ALIGN] &&
 	    value[HTML_H_ALIGN] && *value[HTML_H_ALIGN]) {
 	    if (!strcasecomp(value[HTML_H_ALIGN], "center"))
@@ -1312,7 +1428,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    	     !strcasecomp(value[HTML_H_ALIGN], "justify"))
 	        change_paragraph_style(me, styles[HTML_HLEFT]);
 	    else
-	        change_paragraph_style(me, styles[element_number]);
+	        change_paragraph_style(me, styles[ElementNumber]);
 	} else if (me->Division_Level >= 0) {
 	    if (me->DivisionAlignments[me->Division_Level] == HT_CENTER) {
 		change_paragraph_style(me, styles[HTML_HCENTER]);
@@ -1322,14 +1438,14 @@ PRIVATE void HTML_start_element ARGS5(
 		change_paragraph_style(me, styles[HTML_HRIGHT]);
 	    }
 	} else {
-    	    change_paragraph_style(me, styles[element_number]);
+    	    change_paragraph_style(me, styles[ElementNumber]);
 	}
 	UPDATE_STYLE;
 	LYCheckForID(me, present, value, (int)HTML_H_ID);
 	    
 	if ((bold_headers == TRUE ||
-	     (element_number == HTML_H1 && bold_H1 == TRUE)) &&
-	    (styles[element_number]->font&HT_BOLD)) {
+	     (ElementNumber == HTML_H1 && bold_H1 == TRUE)) &&
+	    (styles[ElementNumber]->font&HT_BOLD)) {
 	    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
 	        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    }
@@ -1375,7 +1491,8 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  to start a newline, if needed, then fall through
 	     *  to handle attributes. - FM
 	     */
-	    if (HText_LastLineSize(me->text)) {
+	    if (HText_LastLineSize(me->text, FALSE)) {
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
 	        HText_appendCharacter(me->text, '\r');
 	    }
 	} else if (!(me->inLABEL && !me->inP)) {
@@ -1401,8 +1518,8 @@ PRIVATE void HTML_start_element ARGS5(
 	    else if (!strcasecomp(value[HTML_P_ALIGN], "right") &&
 	        !(me->List_Nesting_Level >= 0 && !me->inP))
 	        me->sp->style->alignment = HT_RIGHT;
-	    else if (!strcasecomp(value[HTML_H_ALIGN], "left") ||
-	    	     !strcasecomp(value[HTML_H_ALIGN], "justify"))
+	    else if (!strcasecomp(value[HTML_P_ALIGN], "left") ||
+	    	     !strcasecomp(value[HTML_P_ALIGN], "justify"))
 	        me->sp->style->alignment = HT_LEFT;
 	}
 
@@ -1420,7 +1537,8 @@ PRIVATE void HTML_start_element ARGS5(
     case HTML_BR:
         UPDATE_STYLE;
 	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
-	if (LYCollapseBRs == FALSE || HText_LastLineSize(me->text)) {
+	if ((LYCollapseBRs == FALSE) ||
+	    HText_LastLineSize(me->text, FALSE)) {
 	    HText_setLastChar(me->text, ' ');  /* absorb white space */
 	    HText_appendCharacter(me->text, '\r');
 	}
@@ -1452,9 +1570,10 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  the last line are blank. - FM
 	     */
 	    UPDATE_STYLE;
-	    if (HText_LastLineSize(me->text)) {
-	        HText_appendCharacter(me->text, '\r');
-	    } else if (!HText_PreviousLineSize(me->text)) {
+	    if (HText_LastLineSize(me->text, FALSE)) {
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
+		HText_appendCharacter(me->text, '\r');
+	    } else if (!HText_PreviousLineSize(me->text, FALSE)) {
 	        HText_RemovePreviousLine(me->text);
 	    }
 	    me->in_word = NO;
@@ -1535,8 +1654,9 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  paragraph separator for other blocks. - FM
 	     */
 	    if (me->List_Nesting_Level >= 0 ||
-	        me->sp[0].tag_number == HTML_ADDRESS) {
-	        HText_appendCharacter(me->text, '\r');
+		me->sp[0].tag_number == HTML_ADDRESS) {
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
+		HText_appendCharacter(me->text, '\r');
 	    } else {
 	        HText_appendParagraph(me->text);
 	    }
@@ -1617,7 +1737,8 @@ PRIVATE void HTML_start_element ARGS5(
 		 "HTML: Column out of bounds. Using space instead of TAB.\n");
 	    } else {
 	        for (i = column; i < target; i++)
-		    HText_appendCharacter(me->text, ' ');  
+		    HText_appendCharacter(me->text, ' ');
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
 	    }
 	}
 	me->in_word = NO;
@@ -1760,21 +1881,21 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  or single-quotes. - FM
 	 */
 	if (!(me->Quote_Level & 1))
-	    HText_appendCharacter(me->text, '"');
+	    HTML_put_character(me, '"');
 	else
-	    HText_appendCharacter(me->text, '`');
+	    HTML_put_character(me, '`');
 	me->Quote_Level++;
 	break;
 
     case HTML_PRE:				/* Formatted text */
-        if (!HText_PreviousLineSize(me->text))
+        if (!HText_PreviousLineSize(me->text, FALSE))
 	    me->inPRE = FALSE;
 	else
             me->inPRE = TRUE;
     case HTML_LISTING:				/* Litteral text */
     case HTML_XMP:
     case HTML_PLAINTEXT:
-	change_paragraph_style(me, styles[element_number]);
+	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
 	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
     	if (me->comment_end)
@@ -1783,17 +1904,17 @@ PRIVATE void HTML_start_element ARGS5(
 
     case HTML_BLOCKQUOTE:
     case HTML_BQ:
-    	change_paragraph_style(me, styles[element_number]);
+    	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == element_number)
+	if (me->sp->tag_number == ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	LYCheckForID(me, present, value, (int)HTML_BQ_ID);
 	break;
 
     case HTML_NOTE:
-    	change_paragraph_style(me, styles[element_number]);
+    	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == element_number)
+	if (me->sp->tag_number == ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	LYCheckForID(me, present, value, (int)HTML_NOTE_ID);
 	{
@@ -1835,9 +1956,9 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_ADDRESS:
-    	change_paragraph_style(me, styles[element_number]);
+    	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == element_number)
+	if (me->sp->tag_number == ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	LYCheckForID(me, present, value, (int)HTML_ADDRESS_ID);
 	break;
@@ -1895,7 +2016,7 @@ PRIVATE void HTML_start_element ARGS5(
 	LYCheckForID(me, present, value, (int)HTML_GEN_ID);
 	HText_setLastChar(me->text, ' ');  /* absorb white space */
         if (!me->style_change)  {
-	    if (HText_LastLineSize(me->text))
+	    if (HText_LastLineSize(me->text, FALSE))
 		HText_appendCharacter(me->text, '\r');
 	} else {
             UPDATE_STYLE;
@@ -2000,7 +2121,7 @@ PRIVATE void HTML_start_element ARGS5(
 	me->List_Nesting_Level++;
 
 	if (me->List_Nesting_Level <= 0) {
-       	    change_paragraph_style(me, styles[element_number]);
+       	    change_paragraph_style(me, styles[ElementNumber]);
 
 	} else if (me->List_Nesting_Level >= 6) {
        	    change_paragraph_style(me, styles[HTML_OL6]);
@@ -2021,10 +2142,10 @@ PRIVATE void HTML_start_element ARGS5(
 	        !(present && present[HTML_UL_TYPE] &&
 		  value[HTML_UL_TYPE] &&
 		  0==strcasecomp(value[HTML_UL_TYPE], "PLAIN"))) {
-       	        change_paragraph_style(me, styles[element_number]);
+       	        change_paragraph_style(me, styles[ElementNumber]);
 	    } else {
        	        change_paragraph_style(me, styles[HTML_DIR]);
-		element_number = HTML_DIR;
+		ElementNumber = HTML_DIR;
 	    }
 
 	} else if (me->List_Nesting_Level >= 6) {
@@ -2035,7 +2156,7 @@ PRIVATE void HTML_start_element ARGS5(
        	        change_paragraph_style(me, styles[HTML_OL6]);
 	    } else {
        	        change_paragraph_style(me, styles[HTML_MENU6]);
-		element_number = HTML_DIR;
+		ElementNumber = HTML_DIR;
 	    }
 
 	} else {
@@ -2048,7 +2169,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    } else {
                 change_paragraph_style(me, 
 		          styles[HTML_MENU1 + me->List_Nesting_Level - 1]);
-		element_number = HTML_DIR;
+		ElementNumber = HTML_DIR;
 	    }
 	}
 	UPDATE_STYLE;  /* update to the new style */
@@ -2060,7 +2181,7 @@ PRIVATE void HTML_start_element ARGS5(
 	me->List_Nesting_Level++;
 
 	if (me->List_Nesting_Level <= 0) {
-       	    change_paragraph_style(me, styles[element_number]);
+       	    change_paragraph_style(me, styles[ElementNumber]);
 
 	} else if (me->List_Nesting_Level >= 6) {
        	    change_paragraph_style(me, styles[HTML_MENU6]);
@@ -2080,6 +2201,7 @@ PRIVATE void HTML_start_element ARGS5(
 	HTML_put_character(me, HT_NON_BREAK_SPACE);
 	HText_setLastChar(me->text, ' ');
 	me->in_word = NO;
+	me->inP = FALSE;
 	break;
 
     case HTML_LI:
@@ -2253,9 +2375,9 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_FN:
-    	change_paragraph_style(me, styles[element_number]);
+    	change_paragraph_style(me, styles[ElementNumber]);
 	UPDATE_STYLE;
-	if (me->sp->tag_number == element_number)
+	if (me->sp->tag_number == ElementNumber)
 	    LYEnsureDoubleSpace(me);
 	LYCheckForID(me, present, value, (int)HTML_FN_ID);
 	if (me->inUnderline == FALSE)
@@ -2416,9 +2538,10 @@ PRIVATE void HTML_start_element ARGS5(
 	        if (present[HTML_A_CHARSET] &&
 		    value[HTML_A_CHARSET] && *value[HTML_A_CHARSET] != '\0') {
 		    dest_char_set = UCGetLYhndl_byMIME(value[HTML_A_CHARSET]);
-		    if (dest_char_set < 0)
+		if (dest_char_set < 0) {
 		        dest_char_set = UCLYhndl_for_unrec;
 		}
+		}
 		if (title != NULL || dest_ismap == TRUE || dest_char_set >= 0)
 #else
 	    if (title != NULL || dest_ismap == TRUE)
@@ -2442,7 +2565,8 @@ PRIVATE void HTML_start_element ARGS5(
 	    FREE(title);
 	}
 	UPDATE_STYLE;
-	HText_beginAnchor(me->text, me->CurrentA);
+	me->CurrentANum = HText_beginAnchor(me->text,
+					    me->inUnderline, me->CurrentA);
 	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
 	    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 #ifdef NOTUSED_FOTEMODS
@@ -2451,8 +2575,10 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  content bold, and let the check in HTML_end_element() deal
 	 *  with any dangling end tag this creates. - FM
 	 */
-	if (href == NULL && me->inBoldA == FALSE)
+	if (href == NULL && me->inBoldA == FALSE) {
+	    SET_SKIP_STACK(HTML_A);
 	    HTML_end_element(me, HTML_A, (char **)&include);
+	}
 #endif /* NOTUSED_FOTEMODS */
 	FREE(href);
     	break;
@@ -2496,31 +2622,53 @@ PRIVATE void HTML_start_element ARGS5(
 	    StrAllocCopy(map_href, value[HTML_IMG_USEMAP]);
 	    CHECK_FOR_INTERN(map_href);
 	    url_type = LYLegitimizeHREF(me, (char**)&map_href, TRUE, TRUE);
-	    if (*map_href == '\0') {
+	    /*
+	     *	If map_href ended up zero-length or otherwise doesn't
+	     *	have a hash, it can't be valid, so ignore it. - FM
+	     */
+	    if (strchr(map_href, '#') == NULL) {
 	        FREE(map_href);
 	    }
 	}
-	if (map_href && strchr(map_href, '#')) {
+	if (map_href) {
 
 	    /*
 	     *  Check whether a base tag is in effect. - FM
 	     */
-	    if ((me->inBASE && *map_href != '#') &&
-	        (temp = HTParse(map_href, me->base_href, PARSE_ALL)) &&
-	        *temp != '\0')
+	    if (!url_type && me->inBASE) {
 		/*
-		 *  Use reference related to the base.
+		 *  If the
+		 *  USEMAP value is a lone fragment and LYSeekFragMAPinCur
+		 *  is set, we'll use the current document's URL for
+		 *  resolving.  Otherwise use the BASE. - kw
 		 */
-		StrAllocCopy(map_href, temp);
-	    FREE(temp);
+		if ((*map_href == '#' &&
+		     LYSeekFragMAPinCur == TRUE)) {
+	 	    /*
+		     *  Use reference related to the current stream. - FM
+		     */
+		    temp = HTParse(map_href, me->node_anchor->address,
+		    		    PARSE_ALL);
+		    StrAllocCopy(map_href, temp);
+		    UseBASE = FALSE;
+		} else {
+		    /*
+		     *  Use reference related to the base. - FM
+		     */
+	            temp = HTParse(map_href, me->base_href, PARSE_ALL);
+		    StrAllocCopy(map_href, temp);
+		    UseBASE = TRUE;
+		}
+		FREE(temp);
+	    }
 
 	    /*
 	     *  Check whether to fill in localhost. - FM
 	     */
 	    LYFillLocalFileURL((char **)&map_href,
-			       ((*map_href != '\0' && *map_href != '#' &&
-			         me->inBASE) ?
-			      me->base_href : me->node_anchor->address));
+			       ((UseBASE && me->inBASE) ?
+			  me->base_href : me->node_anchor->address));
+	    UseBASE = TRUE;
 
 	    /*
 	     *  If it's not yet a URL, resolve versus
@@ -2545,7 +2693,7 @@ PRIVATE void HTML_start_element ARGS5(
 	 *  Check whether we want to suppress the server-side
 	 *  ISMAP link if a client-side MAP is present. - FM
 	 */
-	if (LYNoISMAPifUSEMAP && map_href) {
+	if (LYNoISMAPifUSEMAP && map_href && dest_ismap) {
 	    dest_ismap = FALSE;
 	    dest = NULL;
 	}
@@ -2700,25 +2848,26 @@ PRIVATE void HTML_start_element ARGS5(
 		 */
 		if (map_href) {
 		    if (dest_ismap) {
-		        HTML_put_string(me, "[ISMAP]");
+			HTML_put_string(me, "[ISMAP]");
 		    } else if (dest) {
-		        HTML_put_string(me, "[LINK]");
+			HTML_put_string(me, "[LINK]");
 		    }
 		    if (me->inBoldA == TRUE && me->inBoldH == FALSE) {
 		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		    }
 		    me->inBoldA = FALSE;
-		    HText_endAnchor(me->text);
+		    HText_endAnchor(me->text, me->CurrentANum);
+		    me->CurrentANum = 0;
 		    if (dest_ismap || dest)
-		        HText_appendCharacter(me->text, '-');
+			HTML_put_character(me, '-');
 		    if (id_string) {
 		        if ((ID_A = HTAnchor_findChildAndLink(
 				  me->node_anchor,	/* Parent */
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (HTLinkType*)0)) != NULL) {	/* Type */
-		            HText_beginAnchor(me->text, ID_A);
-		            HText_endAnchor(me->text);
+		            HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		            HText_endAnchor(me->text, 0);
 		        }
 		    }
 		    me->CurrentA = HTAnchor_findChildAndLink(
@@ -2734,7 +2883,9 @@ PRIVATE void HTML_start_element ARGS5(
 			        HTAnchor_setTitle(dest, title);
 			}
 		    }
-		    HText_beginAnchor(me->text, me->CurrentA);
+		    me->CurrentANum = HText_beginAnchor(me->text,
+		    					me->inUnderline,
+							me->CurrentA);
 		    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
 		        HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		    }
@@ -2745,8 +2896,9 @@ PRIVATE void HTML_start_element ARGS5(
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
 		me->inBoldA = FALSE;
-		HText_endAnchor(me->text);
-		HText_appendCharacter(me->text, '-');
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
+		HTML_put_character(me, '-');
 		StrAllocCopy(alt_string,
 			     ((present &&
 			       present[HTML_IMG_ISOBJECT]) ?
@@ -2758,8 +2910,8 @@ PRIVATE void HTML_start_element ARGS5(
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (HTLinkType*)0)) != NULL) {	/* Type */
-		        HText_beginAnchor(me->text, ID_A);
-		        HText_endAnchor(me->text);
+		        HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		        HText_endAnchor(me->text, 0);
 		    }
 		}
 	    } else if (map_href) {
@@ -2771,8 +2923,8 @@ PRIVATE void HTML_start_element ARGS5(
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (HTLinkType*)0)) != NULL) {	/* Type */
-		        HText_beginAnchor(me->text, ID_A);
-		        HText_endAnchor(me->text);
+		        HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		        HText_endAnchor(me->text, 0);
 		    }
 		}
 		me->CurrentA = HTAnchor_findChildAndLink(
@@ -2788,7 +2940,9 @@ PRIVATE void HTML_start_element ARGS5(
 			    HTAnchor_setTitle(dest, title);
 		    }
 		}
-		HText_beginAnchor(me->text, me->CurrentA);
+		me->CurrentANum = HText_beginAnchor(me->text,
+						    me->inUnderline,
+						    me->CurrentA);
 		if (me->inBoldA == FALSE && me->inBoldH == FALSE)
 		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		me->inBoldA = TRUE;
@@ -2797,8 +2951,9 @@ PRIVATE void HTML_start_element ARGS5(
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
 		me->inBoldA = FALSE;
-		HText_endAnchor(me->text);
-		HText_appendCharacter(me->text, '-');
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
+		HTML_put_character(me, '-');
 		StrAllocCopy(alt_string,
 			     ((present &&
 			       present[HTML_IMG_ISOBJECT]) ?
@@ -2812,8 +2967,8 @@ PRIVATE void HTML_start_element ARGS5(
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (HTLinkType*)0)) != NULL) {	/* Type */
-		        HText_beginAnchor(me->text, ID_A);
-		        HText_endAnchor(me->text);
+		        HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		        HText_endAnchor(me->text, 0);
 		    }
 		}
 	    }
@@ -2827,14 +2982,17 @@ PRIVATE void HTML_start_element ARGS5(
 			href,				/* Addresss */
 			(HTLinkType*)0);		/* Type */
 	    FREE(href);
-	    HText_beginAnchor(me->text, me->CurrentA);
+	    me->CurrentANum = HText_beginAnchor(me->text,
+	    					me->inUnderline,
+						me->CurrentA);
 	    if (me->inBoldH == FALSE)
 		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    HTML_put_string(me, alt_string);
 	    if (!me->inA) {
 	        if (me->inBoldH == FALSE)
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		HText_endAnchor(me->text);
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 	    } else {
@@ -2855,9 +3013,10 @@ PRIVATE void HTML_start_element ARGS5(
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
 		me->inBoldA = FALSE;
-		HText_endAnchor(me->text);
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
 		if (dest_ismap || dest)
-		    HText_appendCharacter(me->text, '-');
+		    HTML_put_character(me, '-');
 	    } else {
 	        HTML_put_character(me, ' ');
 	        me->in_word = NO;
@@ -2875,7 +3034,9 @@ PRIVATE void HTML_start_element ARGS5(
 		        HTAnchor_setTitle(dest, title);
 		}
 	    }
-	    HText_beginAnchor(me->text, me->CurrentA);
+	    me->CurrentANum = HText_beginAnchor(me->text,
+	    					me->inUnderline,
+						me->CurrentA);
 	    if (me->inBoldA == FALSE && me->inBoldH == FALSE) {
 		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    }
@@ -2886,7 +3047,8 @@ PRIVATE void HTML_start_element ARGS5(
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
 		}
 		me->inBoldA = FALSE;
-		HText_endAnchor(me->text);
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
 	    }
 	} else {
 	    /*
@@ -2904,8 +3066,8 @@ PRIVATE void HTML_start_element ARGS5(
 				  id_string,		/* Tag */
 				  NULL,			/* Addresss */
 				  (HTLinkType*)0)) != NULL) {	/* Type */
-		    HText_beginAnchor(me->text, ID_A);
-		    HText_endAnchor(me->text);
+		    HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		    HText_endAnchor(me->text, 0);
 		}
 	    }
 	    HTML_put_string(me, alt_string);
@@ -2924,14 +3086,14 @@ PRIVATE void HTML_start_element ARGS5(
     
     case HTML_MAP:
 	/*
-	 *  Load id_string if we have an ID or NAME. - FM
+	 *  Load id_string if we have a NAME or ID. - FM
 	 */
-	if (present && present[HTML_MAP_ID] &&
-	    value[HTML_MAP_ID] && *value[HTML_MAP_ID]) {
-	    StrAllocCopy(id_string, value[HTML_MAP_ID]);
-	} else if (present && present[HTML_MAP_NAME] &&
-		   value[HTML_MAP_NAME] && *value[HTML_MAP_NAME]) {
+	if (present && present[HTML_MAP_NAME] &&
+	    value[HTML_MAP_NAME] && *value[HTML_MAP_NAME]) {
 	    StrAllocCopy(id_string, value[HTML_MAP_NAME]);
+	} else if (present && present[HTML_MAP_ID] &&
+		   value[HTML_MAP_ID] && *value[HTML_MAP_ID]) {
+	    StrAllocCopy(id_string, value[HTML_MAP_ID]);
 	}
 	if (id_string) {
 	    LYUnEscapeToLatinOne(&id_string, TRUE);
@@ -2948,7 +3110,9 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  The MAP must be in the current stream, even if it
 	     *  had a BASE tag, so we'll use its address here, but
 	     *  still use the BASE, if present, when resolving the
-	     *  AREA elements in its content. - FM && KW
+	     *  AREA elements in it's content, unless the AREA's
+	     *  HREF is a lone fragment and LYSeekFragAREAinCur is
+	     *  set. - FM && KW
 	     */
 	    StrAllocCopy(me->map_address, me->node_anchor->address);
 	    if ((cp = strrchr(me->map_address, '#')) != NULL)
@@ -2990,9 +3154,12 @@ PRIVATE void HTML_start_element ARGS5(
 	    /*
 	     *  Check whether a BASE tag is in effect, and use it
 	     *  for resolving, even though we used this stream's
-	     *  address for locating the MAP itself. - FM
+	     *  address for locating the MAP itself, unless the
+	     *  HREF is a lone fragment and LYSeekFragAREAinCur
+	     *  is set. - FM
 	     */
-	    if ((me->inBASE && *href != '\0' && *href != '#') &&
+	    if (((me->inBASE && *href != '\0') &&
+	         !(*href == '#' && LYSeekFragAREAinCur == TRUE)) &&
 		(temp = HTParse(href, me->base_href, PARSE_ALL)) &&
 		*temp != '\0')
 		/*
@@ -3005,10 +3172,11 @@ PRIVATE void HTML_start_element ARGS5(
 	     *  Check whether to fill in localhost. - FM
 	     */
 	    LYFillLocalFileURL((char **)&href,
-			       ((*href != '\0' && *href != '#' &&
-			         me->inBASE) ?
-			       me->base_href : me->node_anchor->address));
-
+			       ((((me->inBASE && *href != '\0') &&
+			          !(*href == '#' &&
+				    LYSeekFragAREAinCur == TRUE)))
+						?
+				  me->base_href : me->node_anchor->address));
 	    if (!(url_type = is_url(href))) {
 	        temp = HTParse(href, me->node_anchor->address, PARSE_ALL);
 		if (!(temp && *temp)) {
@@ -3090,6 +3258,10 @@ PRIVATE void HTML_start_element ARGS5(
         me->inFIG = TRUE;
 	if (!me->text)
 	    UPDATE_STYLE;
+	if (me->inA) {
+	    SET_SKIP_STACK(HTML_A);
+	    HTML_end_element(me, HTML_A, (char **)&include);
+	}
 	if (!present ||
 	    (present && !present[HTML_FIG_ISOBJECT])) {
 	    LYEnsureDoubleSpace(me);
@@ -3129,25 +3301,23 @@ PRIVATE void HTML_start_element ARGS5(
 				     me->inBASE) ?
 				   me->base_href : me->node_anchor->address));
 
-		if ((me->CurrentA = HTAnchor_findChildAndLink(
+		me->CurrentA = HTAnchor_findChildAndLink(
 		       			me->node_anchor,	/* Parent */
 		       			NULL,			/* Tag */
 		       			href,			/* Addresss */
-		       			INTERN_LT))) {		/* Type */
-		    HText_beginAnchor(me->text, me->CurrentA);
-		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-		    HTML_put_string(me,
-		    		    (present[HTML_FIG_ISOBJECT] ?
+		       			INTERN_LT);		/* Type */
+		HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		HTML_put_string(me, (present[HTML_FIG_ISOBJECT] ?
 		      (present[HTML_FIG_IMAGEMAP] ?
 					"(IMAGE)" : "(OBJECT)") : "[FIGURE]"));
-		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		    HText_endAnchor(me->text);
-		    HText_appendCharacter(me->text, '-');
-		    HTML_put_character(me, ' '); /* space char may be ignored */
-		    me->in_word = NO;
-		}
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		HText_endAnchor(me->text, 0);
+		HTML_put_character(me, '-');
+		HTML_put_character(me, ' '); /* space char may be ignored */
+		me->in_word = NO;
 	    }
 	    FREE(href);
 	}
@@ -3303,27 +3473,32 @@ PRIVATE void HTML_start_element ARGS5(
 				     me->inBASE) ?
 				   me->base_href : me->node_anchor->address));
 
-		if ((me->CurrentA = HTAnchor_findChildAndLink(
+		if (me->inA) {
+		    SET_SKIP_STACK(HTML_A);
+		    HTML_end_element(me, HTML_A, (char **)&include);
+		}
+		me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
-					INTERN_LT))) {		/* Type */
-		    if (!me->text) {
-		        UPDATE_STYLE;
-		    } else {
-		        HTML_put_character(me, ' ');
-			HText_appendCharacter(me->text, '+');
-		    }
-		    HText_beginAnchor(me->text, me->CurrentA);
-		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-		    HTML_put_string(me, "[OVERLAY]");
-		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		    HText_endAnchor(me->text);
+					INTERN_LT);		/* Type */
+		if (!me->text) {
+		    UPDATE_STYLE;
+		} else {
 		    HTML_put_character(me, ' ');
-		    me->in_word = NO;
+		    HText_appendCharacter(me->text, '+');
 		}
+		me->CurrentANum = HText_beginAnchor(me->text,
+						    me->inUnderline,
+						    me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		HTML_put_string(me, "[OVERLAY]");
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		HText_endAnchor(me->text, me->CurrentANum);
+		HTML_put_character(me, ' ');
+		me->in_word = NO;
 	    }
 	    FREE(href);
 	}
@@ -3445,19 +3620,30 @@ PRIVATE void HTML_start_element ARGS5(
 	    FREE(base);
 	    FREE(code);
 
-	    if ((href && *href) &&
-	        (me->CurrentA = HTAnchor_findChildAndLink(
+	    if (href && *href) {
+	        if (me->inA) {
+		    if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		    HText_endAnchor(me->text, me->CurrentANum);
+		    HTML_put_character(me, '-');
+		}
+	        me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
-					(HTLinkType*)0))) {	/* Type */
-		HText_beginAnchor(me->text, me->CurrentA);
+					(HTLinkType*)0);	/* Type */
+		me->CurrentANum = HText_beginAnchor(me->text,
+						    me->inUnderline,
+						    me->CurrentA);
 		if (me->inBoldH == FALSE)
 		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 		HTML_put_string(me, alt_string);
-		if (me->inBoldH == FALSE)
-		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		HText_endAnchor(me->text);
+		if (me->inA == FALSE) {
+		    if (me->inBoldH == FALSE)
+		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		    HText_endAnchor(me->text, me->CurrentANum);
+		    me->CurrentANum = 0;
+		}
 		HTML_put_character(me, ' ');  /* space char may be ignored */
 		me->in_word = NO;
 	    }
@@ -3510,23 +3696,34 @@ PRIVATE void HTML_start_element ARGS5(
 
 	    if (!me->text)
 	        UPDATE_STYLE;
-	    if ((me->CurrentA = HTAnchor_findChildAndLink(
+	    if (me->inA) {
+		if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		HText_endAnchor(me->text, me->CurrentANum);
+		HTML_put_character(me, '-');
+	    } else {
+		HTML_put_character(me, ' ');  /* space char may be ignored */
+		me->in_word = NO;
+	    }
+	    me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
-					INTERN_LT))) {		/* Type */
-		HTML_put_character(me, ' ');  /* space char may be ignored */
-		me->in_word = NO;
-		HText_beginAnchor(me->text, me->CurrentA);
-		if (me->inBoldH == FALSE)
-		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-		HTML_put_string(me, "[BGSOUND]");
+					INTERN_LT);		/* Type */
+	    me->CurrentANum = HText_beginAnchor(me->text,
+	    					me->inUnderline,
+						me->CurrentA);
+	    if (me->inBoldH == FALSE)
+		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+	    HTML_put_string(me, "[BGSOUND]");
+	    if (me->inA == FALSE) {
 		if (me->inBoldH == FALSE)
 		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		HText_endAnchor(me->text);
-		HTML_put_character(me, ' ');  /* space char may be ignored */
-		me->in_word = NO;
+		HText_endAnchor(me->text, me->CurrentANum);
+		me->CurrentANum = 0;
 	    }
+	    HTML_put_character(me, ' ');  /* space char may be ignored */
+	    me->in_word = NO;
 	    FREE(href);
 	}
 	break;
@@ -3616,21 +3813,33 @@ PRIVATE void HTML_start_element ARGS5(
 				     me->inBASE) ?
 				   me->base_href : me->node_anchor->address));
 
-		if ((me->CurrentA = HTAnchor_findChildAndLink(
+	        if (me->inA) {
+		    if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		    HText_endAnchor(me->text, me->CurrentANum);
+		    HTML_put_character(me, '-');
+		}
+		me->CurrentA = HTAnchor_findChildAndLink(
 					me->node_anchor,	/* Parent */
 					NULL,			/* Tag */
 					href,			/* Addresss */
-					INTERN_LT))) {		/* Type */
-		    HText_beginAnchor(me->text, me->CurrentA);
-		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-		    HTML_put_string(me, alt_string);
+					INTERN_LT);		/* Type */
+		me->CurrentANum = HText_beginAnchor(me->text,
+						    me->inUnderline,
+						    me->CurrentA);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		HTML_put_string(me, alt_string);
+		if (me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		if (me->inA == FALSE) {
 		    if (me->inBoldH == FALSE)
-			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-		    HText_endAnchor(me->text);
-		    HTML_put_character(me, ' ');
-		    me->in_word = NO;
+		        HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		    HText_endAnchor(me->text, me->CurrentANum);
+		    me->CurrentANum = 0;
 		}
+		HTML_put_character(me, ' ');
+		me->in_word = NO;
 	    }
 	    FREE(href);
 	} else if (*alt_string) {
@@ -3855,9 +4064,21 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_FIELDSET:
+	if (!me->text)
+	    UPDATE_STYLE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
         LYCheckForID(me, present, value, (int)HTML_FIELDSET_ID);
         break;
 
+    case HTML_LEGEND:
+	if (!me->text)
+	    UPDATE_STYLE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+        LYCheckForID(me, present, value, (int)HTML_LEGEND_ID);
+        break;
+
     case HTML_LABEL:
         LYCheckForID(me, present, value, (int)HTML_LABEL_ID);
         break;
@@ -3866,20 +4087,41 @@ PRIVATE void HTML_start_element ARGS5(
         LYCheckForID(me, present, value, (int)HTML_KEYGEN_ID);
         break;
 
-    case HTML_INPUT:
+    case HTML_BUTTON:
 	{
 	    InputFieldData I;
 	    int chars;
-	    BOOL UseALTasVALUE = FALSE;
-	    BOOL HaveSRClink = FALSE;
-	    BOOL IsSubmitOrReset = FALSE;
+
+	    /* init */
+	    I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
+	    I.disabled=NO; I.error=NULL; I.height= NULL; I.id=NULL;
+	    I.lang=NULL; I.max=NULL; I.maxlength=NULL; I.md=NULL;
+	    I.min=NULL; I.name=NULL; I.size=NULL; I.src=NULL;
+	    I.type=NULL; I.value=NULL; I.width=NULL;
+
+	    UPDATE_STYLE;
+	    if ((present && present[HTML_BUTTON_TYPE] &&
+	         value[HTML_BUTTON_TYPE]) &&
+		(!strcasecomp((char *)value[HTML_BUTTON_TYPE], "submit") ||
+		 !strcasecomp((char *)value[HTML_BUTTON_TYPE], "reset"))) {
+	        /*
+		 *  It's a button for submitting or resetting a form. - FM
+		 */
+		I.type = (char *)value[HTML_BUTTON_TYPE];
+	    } else {
+	        /*
+		 *  Ugh, it's a button for a script. - FM
+		 */
+		HTML_put_string(me," [BUTTON] ");
+		break;
+	    }
 
 	    /*
 	     *  Make sure we're in a form.
 	     */
 	    if (!me->inFORM) {
 	        if (TRACE) {
-		    fprintf(stderr, "HTML: INPUT tag not within FORM tag\n");
+		    fprintf(stderr, "HTML: BUTTON tag not within FORM tag\n");
 		} else if (!me->inBadHTML) {
 	            _statusline(BAD_HTML_USE_TRACE);
 		    me->inBadHTML = TRUE;
@@ -3893,16 +4135,146 @@ PRIVATE void HTML_start_element ARGS5(
 		 */
 	    }
 
-	    /* Check for unclosed TEXTAREA */
-	    if (me->inTEXTAREA) {
-	        if (TRACE) {
-		    fprintf(stderr, "HTML: Missing TEXTAREA end tag.\n");
-		} else if (!me->inBadHTML) {
-		    _statusline(BAD_HTML_USE_TRACE);
-		    me->inBadHTML = TRUE;
-		    sleep(MessageSecs);
+	    /*
+	     *  Before any input field, add a collapsible space if
+	     *  we're not in a PRE block, to promote a wrap there
+	     *  for any long values that would extent past the right
+	     *  margin from our current position in the line.  If
+	     *  we are in a PRE block, start a new line if the last
+	     *  line already is within 6 characters of the wrap point
+	     *  for PRE blocks. - FM
+	     */
+	    if (me->sp[0].tag_number != HTML_PRE && !me->inPRE &&
+		me->sp->style->freeFormat) {
+		HTML_put_character(me, ' ');
+		me->in_word = NO;
+	    } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) {
+		HTML_put_character(me, '\n');
+		me->in_word = NO;
+	    }
+	    HTML_put_character(me, '(');
+
+	    if (present && present[HTML_BUTTON_NAME] && value[HTML_BUTTON_NAME])
+		I.name = (char *)value[HTML_BUTTON_NAME];
+	    else
+	        I.name = "";
+
+	    if (present && present[HTML_BUTTON_VALUE] &&
+	        value[HTML_BUTTON_VALUE] && *value[HTML_BUTTON_VALUE]) {
+	        /*
+		 *  Convert any HTML entities or decimal escaping. - FM
+		 */
+		int CurrentCharSet = current_char_set;
+		BOOL CurrentEightBitRaw = HTPassEightBitRaw;
+		BOOLEAN CurrentUseDefaultRawMode = LYUseDefaultRawMode;
+		HTCJKlang CurrentHTCJK = HTCJK;
+		int len;
+
+		me->UsePlainSpace = TRUE;
+		if (current_char_set) {
+		    LYExpandString((char **)&value[HTML_BUTTON_VALUE]);
+		}
+	        LYUnEscapeEntities((char *)value[HTML_BUTTON_VALUE],
+				   me->UsePlainSpace, me->HiddenValue);
+		I.value = (char *)value[HTML_BUTTON_VALUE];
+		/*
+		 *  Convert any newlines or tabs to spaces,
+		 *  and trim any lead or trailing spaces. - FM
+		 */
+		convert_to_spaces(I.value, FALSE);
+		while (I.value && I.value[0] == ' ')
+		    I.value++;
+		len = strlen(I.value) - 1;
+		while (len > 0 && I.value[len] == ' ')
+		    I.value[len--] = '\0';
+		me->UsePlainSpace = FALSE;
+	    }
+		
+	    if (present && present[HTML_BUTTON_DISABLED])
+		I.disabled = YES;
+
+	    if (present && present[HTML_BUTTON_CLASS] && /* Not yet used. */
+	        value[HTML_BUTTON_CLASS] && *value[HTML_BUTTON_CLASS])
+		I.class = (char *)value[HTML_BUTTON_CLASS];
+
+	    if (present && present[HTML_BUTTON_ID] &&
+	        value[HTML_BUTTON_ID] && *value[HTML_BUTTON_ID]) {
+		I.id = (char *)value[HTML_BUTTON_ID];
+		LYCheckForID(me, present, value, (int)HTML_BUTTON_ID);
+	    }
+
+	    if (present && present[HTML_BUTTON_LANG] && /* Not yet used. */
+	        value[HTML_BUTTON_LANG] && *value[HTML_BUTTON_LANG])
+		I.lang = (char *)value[HTML_BUTTON_LANG];
+
+	    chars = HText_beginInput(me->text, me->inUnderline, &I);
+	    /*
+	     *  Submit and reset buttons have values which don't change,
+	     *  so HText_beginInput() sets I.value to the string which
+	     *  should be displayed, and we'll enter that instead of
+	     *  underscore placeholders into the HText structure to
+	     *  see it instead of underscores when dumping or printing.
+	     *  We also won't worry about a wrap in PRE blocks, because
+	     *  the line editor never is invoked for submit or reset
+	     *  buttons. - LE & FM
+	     */
+	    if (me->sp[0].tag_number == HTML_PRE ||
+		    !me->sp->style->freeFormat) {
+		/*
+		 *  We have a submit or reset button in a PRE block,
+		 *  so output the entire value from the markup.  If
+		 *  it extends to the right margin, it will wrap
+		 *  there, and only the portion before that wrap will
+		 *  be hightlighted on screen display (Yuk!) but we
+		 *  may as well show the rest of the full value on
+		 *  the next or more lines. - FM
+		 */
+		while (I.value[i])
+		    HTML_put_character(me, I.value[i++]);
+	    } else {
+		/*
+		 *  The submit or reset button is not in a PRE block.
+		 *  Note that if a wrap occurs before outputting the
+		 *  entire value, the wrapped portion will not be
+		 *  highlighted or clearly indicated as part of the
+		 *  link for submission or reset (Yuk!).
+		 *  We'll replace any spaces in the submit or reset
+		 *  button value with nbsp, to promote a wrap at the
+		 *  space we ensured would be present before the start
+		 *  of the string, as when we use all underscores
+		 *  instead of the INPUT's actual value, but we could
+		 *  still get a wrap at the right margin, instead, if
+		 *  the value is greater than a line width for the
+		 *  current style.  Also, if chars somehow ended up
+		 *  longer than the length of the actual value
+		 *  (shouldn't have), we'll continue padding with nbsp
+		 *  up to the length of chars. - FM
+		 */
+	        for (i = 0; I.value[i]; i++) {
+		    HTML_put_character(me,
+			   	       (I.value[i] ==  ' ' ?
+					HT_NON_BREAK_SPACE : I.value[i]));
+		}
+		while (i < chars) {
+		    HTML_put_character(me, HT_NON_BREAK_SPACE);
 		}
 	    }
+	    HTML_put_character(me, ')');
+	    if (me->sp[0].tag_number != HTML_PRE &&
+		me->sp->style->freeFormat) {
+		HTML_put_character(me, ' ');
+		me->in_word = NO;
+	    }
+	}
+	break;
+
+    case HTML_INPUT:
+	{
+	    InputFieldData I;
+	    int chars;
+	    BOOL UseALTasVALUE = FALSE;
+	    BOOL HaveSRClink = FALSE;
+	    BOOL IsSubmitOrReset = FALSE;
 
 	    /* init */
 	    I.align=NULL; I.accept=NULL; I.checked=NO; I.class=NULL;
@@ -3926,15 +4298,14 @@ PRIVATE void HTML_start_element ARGS5(
 		me->sp->style->freeFormat) {
 		HTML_put_character(me, ' ');
 		me->in_word = NO;
-	    } else if (HText_LastLineSize(me->text) > (LYcols - 7)) {
+	    } else if (HText_LastLineSize(me->text, FALSE) > (LYcols - 7)) {
 		HTML_put_character(me, '\n');
 		me->in_word = NO;
 	    }
 
-	    if (present && present[HTML_INPUT_NAME] && value[HTML_INPUT_NAME])
-		I.name = (char *)value[HTML_INPUT_NAME];
-	    else
-	        I.name = "";
+	    /*
+	     *  Get the TYPE and make sure we can handle it. - FM
+	     */
 	    if (present && present[HTML_INPUT_TYPE] &&
 	        value[HTML_INPUT_TYPE] && *value[HTML_INPUT_TYPE]) {
 		I.type = (char *)value[HTML_INPUT_TYPE];
@@ -3948,7 +4319,8 @@ PRIVATE void HTML_start_element ARGS5(
 		     *  Not yet implemented.
 		     */
 		    HTML_put_string(me,"[RANGE Input] (Not yet implemented.)");
-		    HText_DisableCurrentForm();
+		    if (me->inFORM)
+			HText_DisableCurrentForm();
 		    if (TRACE)
 		        fprintf(stderr, "HTML: Ignoring TYPE=\"range\"\n");
 		    break;
@@ -3968,12 +4340,60 @@ PRIVATE void HTML_start_element ARGS5(
 		        HText_appendCharacter(me->text,
 					      LY_UNDERLINE_END_CHAR);
 		    }
-		    HText_DisableCurrentForm();
+		    if (me->inFORM)
+			HText_DisableCurrentForm();
 		    if (TRACE)
 		        fprintf(stderr, "HTML: Ignoring TYPE=\"file\"\n");
 		    break;
+
+		} else if (!strcasecomp(I.type, "button")) {
+		    /*
+		     *  Ugh, a button for a script.
+		     */
+		    HTML_put_string(me,"[BUTTON] ");
+		    break;
+		}
+	    }
+
+	    /*
+	     *  Check if we're in a form. - FM
+	     */
+	    if (!me->inFORM) {
+	        if (TRACE) {
+		    fprintf(stderr, "HTML: INPUT tag not within FORM tag\n");
+		} else if (!me->inBadHTML) {
+	            _statusline(BAD_HTML_USE_TRACE);
+		    me->inBadHTML = TRUE;
+		    sleep(MessageSecs);
 		}
+		/*
+		 *  We'll process it, since the chances of a crash are
+		 *  small, and we probably do have a form started. - FM
+		 *
+		break;
+		 */
 	    }
+
+	    /*
+	     *  Check for an unclosed TEXTAREA.
+	     */
+	    if (me->inTEXTAREA) {
+	        if (TRACE) {
+		    fprintf(stderr, "HTML: Missing TEXTAREA end tag.\n");
+		} else if (!me->inBadHTML) {
+		    _statusline(BAD_HTML_USE_TRACE);
+		    me->inBadHTML = TRUE;
+		    sleep(MessageSecs);
+		}
+	    }
+
+	    /*
+	     *  Handle the INPUT as for a FORM. - FM
+	     */
+	    if (present && present[HTML_INPUT_NAME] && value[HTML_INPUT_NAME])
+		I.name = (char *)value[HTML_INPUT_NAME];
+	    else
+	        I.name = "";
 	    if ((present && present[HTML_INPUT_ALT] &&
 		 value[HTML_INPUT_ALT] && *value[HTML_INPUT_ALT] &&
 		 I.type && !strcasecomp(I.type, "image")) &&
@@ -4022,20 +4442,23 @@ PRIVATE void HTML_start_element ARGS5(
 				       me->base_href :
 				       me->node_anchor->address));
 
-		    if ((me->CurrentA = HTAnchor_findChildAndLink(
+		    if (me->inA) {
+			SET_SKIP_STACK(HTML_A);
+		        HTML_end_element(me, HTML_A, (char **)&include);
+		    }
+		    me->CurrentA = HTAnchor_findChildAndLink(
 		       			me->node_anchor,	/* Parent */
 		       			NULL,			/* Tag */
 		       			href,			/* Addresss */
-		       			(HTLinkType*)0))) {	/* Type */
-		        HText_beginAnchor(me->text, me->CurrentA);
-			if (me->inBoldH == FALSE)
-			    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
-			HTML_put_string(me, "[IMAGE]");
-			if (me->inBoldH == FALSE)
-			    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-			HText_endAnchor(me->text);
-			HText_appendCharacter(me->text, '-');
-		    }
+		       			(HTLinkType*)0);	/* Type */
+		    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+		    HTML_put_string(me, "[IMAGE]");
+		    if (me->inBoldH == FALSE)
+			HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		    HText_endAnchor(me->text, 0);
+		    HTML_put_character(me, '-');
 		    HaveSRClink = TRUE;
 	        }
 	        FREE(href);
@@ -4147,7 +4570,7 @@ PRIVATE void HTML_start_element ARGS5(
 	        value[HTML_INPUT_MD] && *value[HTML_INPUT_MD])
 		I.md = (char *)value[HTML_INPUT_MD];
 
-	    chars = HText_beginInput(me->text, &I);
+	    chars = HText_beginInput(me->text, me->inUnderline, &I);
 	    /*
 	     *  Submit and reset buttons have values which don't change,
 	     *  so HText_beginInput() sets I.value to the string which
@@ -4175,7 +4598,7 @@ PRIVATE void HTML_start_element ARGS5(
 		chars = 0;
 		me->in_word = YES;
 		if (me->sp[0].tag_number != HTML_PRE &&
-		    !me->sp->style->freeFormat) {
+		    me->sp->style->freeFormat) {
 		    HTML_put_character(me, ' ');
 		    me->in_word = NO;
 		}
@@ -4190,7 +4613,7 @@ PRIVATE void HTML_start_element ARGS5(
 		chars = 0;
 		me->in_word = YES;
 		if (me->sp[0].tag_number != HTML_PRE &&
-		    !me->sp->style->freeFormat) {
+		    me->sp->style->freeFormat) {
 		    HTML_put_character(me, ' ');
 		    me->in_word = NO;
 		}
@@ -4338,8 +4761,8 @@ PRIVATE void HTML_start_element ARGS5(
 				(HTLinkType*)0))) {	/* Type */
 		if (!me->text)
 		    UPDATE_STYLE;
-		HText_beginAnchor(me->text, ID_A);
-		HText_endAnchor(me->text);
+		HText_beginAnchor(me->text, me->inUnderline, ID_A);
+		HText_endAnchor(me->text, 0);
 		StrAllocCopy(me->textarea_id, id_string);
 	    } else {
 	        FREE(me->textarea_id);
@@ -4351,9 +4774,24 @@ PRIVATE void HTML_start_element ARGS5(
 	break;
 
     case HTML_SELECT:
+        /*
+	 *  Check for an already open SELECT block. - FM
+	 */
+	if (me->inSELECT) {
+	    if (TRACE) {
+		fprintf(stderr,
+		   "HTML: Embedded SELECT start end. Faking SELECT end tag.\n");
+	    } else if (!me->inBadHTML) {
+		_statusline(BAD_HTML_USE_TRACE);
+		me->inBadHTML = TRUE;
+		sleep(MessageSecs);
+	    }
+	    SET_SKIP_STACK(HTML_SELECT);
+	    HTML_end_element(me, HTML_SELECT, (char **)&include);
+	}
 	{
 	    char *name = NULL;
-	    BOOLEAN multiple=NO;
+	    BOOLEAN multiple = NO;
 	    char *size = NULL;
 
             /*
@@ -4439,7 +4877,7 @@ PRIVATE void HTML_start_element ARGS5(
 	if ((multiple == NO && LYSelectPopups == TRUE) &&
 	    (me->sp[0].tag_number == HTML_PRE || me->inPRE == TRUE ||
 	     !me->sp->style->freeFormat) &&
-	        HText_LastLineSize(me->text) > (LYcols - 8)) {
+	        HText_LastLineSize(me->text, FALSE) > (LYcols - 8)) {
 		/*
 		 *  Force a newline when we're using a popup in
 		 *  a PRE block and are within 7 columns from the
@@ -4583,13 +5021,13 @@ PRIVATE void HTML_start_element ARGS5(
 				    value[HTML_OPTION_ID], /* Tag */
 				    NULL,		   /* Addresss */
 				    (HTLinkType*)0)) != NULL) {	   /* Type */
-			HText_beginAnchor(me->text, ID_A);
-			HText_endAnchor(me->text);
+			HText_beginAnchor(me->text, me->inUnderline, ID_A);
+			HText_endAnchor(me->text, 0);
 		        I.id = (char *)value[HTML_OPTION_ID];
 		    }
 		}
 
-	        HText_beginInput(me->text, &I);
+	        HText_beginInput(me->text, me->inUnderline, &I);
     
 		if (HTCurSelectGroupType == F_CHECKBOX_TYPE) {
 	            /*
@@ -4601,6 +5039,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    	    HText_appendCharacter(me->text, '_');
 	    	    HText_appendCharacter(me->text, ']');
 	            HText_appendCharacter(me->text, ' ');
+		    HText_setLastChar(me->text, ' ');  /* absorb white space */
 		    me->in_word = NO;
 		} else if (LYSelectPopups == FALSE) {
 	            /*
@@ -4612,6 +5051,7 @@ PRIVATE void HTML_start_element ARGS5(
 	    	    HText_appendCharacter(me->text, '_');
 	    	    HText_appendCharacter(me->text, ')');
 	            HText_appendCharacter(me->text, ' ');
+		    HText_setLastChar(me->text, ' ');  /* absorb white space */
 		    me->in_word = NO;
 		}
 	    }
@@ -4634,26 +5074,106 @@ PRIVATE void HTML_start_element ARGS5(
 	        StrAllocCopy(me->LastOptionValue, value[HTML_OPTION_VALUE]);
 	    else
 	        StrAllocCopy(me->LastOptionValue, me->option.data);
+
+	    /*
+	     *  If this is a popup option, print its option
+	     *  for use in selecting option by number. - LE
+	     */
+	    if (HTCurSelectGroupType == F_RADIO_TYPE &&
+	        LYSelectPopups &&
+		keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+		char marker[8];
+		int opnum = HText_getOptionNum(me->text);
+
+		if (opnum > 0 && opnum < 100000) {
+		    sprintf(marker,"(%d)", opnum);
+		    HTML_put_string(me, marker);
+		    for (i = strlen(marker); i < 5; ++i) {
+			HTML_put_character(me, '_');
+		    }
+		}
+	    }
 	}
 	break;
 
     case HTML_TABLE:
-        UPDATE_STYLE;
-	LYCheckForID(me, present, value, (int)HTML_TABLE_ID);
+	/*
+	 *  Not implemented.  Just treat as a division
+	 *  with respect to any ALIGN attribute, with
+	 *  a default of HT_LEFT. - FM
+	 */
 	me->inTABLE = TRUE;
-        break;
+	if (me->Division_Level < (MAX_NESTING - 1)) {
+	    me->Division_Level++;
+	} else if (TRACE) {
+            fprintf(stderr, 
+	    "HTML: ****** Maximum nesting of %d divisions/tables exceeded!\n",
+            	    MAX_NESTING);
+	}
+	if (present && present[HTML_TABLE_ALIGN] &&
+	    value[HTML_TABLE_ALIGN] && *value[HTML_TABLE_ALIGN]) {
+	    if (!strcasecomp(value[HTML_TABLE_ALIGN], "center")) {
+	        me->DivisionAlignments[me->Division_Level] = HT_CENTER;
+		change_paragraph_style(me, styles[HTML_DCENTER]);
+		UPDATE_STYLE;
+		me->current_default_alignment = styles[HTML_DCENTER]->alignment;
+	    } else if (!strcasecomp(value[HTML_TABLE_ALIGN], "right")) {
+	        me->DivisionAlignments[me->Division_Level] = HT_RIGHT;
+		change_paragraph_style(me, styles[HTML_DRIGHT]);
+		UPDATE_STYLE;
+		me->current_default_alignment = styles[HTML_DRIGHT]->alignment;
+	    } else {
+	        me->DivisionAlignments[me->Division_Level] = HT_LEFT;
+		change_paragraph_style(me, styles[HTML_DLEFT]);
+		UPDATE_STYLE;
+		me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+	    }
+	} else {
+	    me->DivisionAlignments[me->Division_Level] = HT_LEFT;
+	    change_paragraph_style(me, styles[HTML_DLEFT]);
+	    UPDATE_STYLE;
+	    me->current_default_alignment = styles[HTML_DLEFT]->alignment;
+	}
+	LYCheckForID(me, present, value, (int)HTML_TABLE_ID);
+	break;
 
     case HTML_TR:
         /*
 	 *  Not yet implemented.  Just start a new row,
-	 *  if needed, and check for an ID link. - FM
+	 *  if needed, act on an ALIGN attribute if present,
+	 *  and check for an ID link. - FM
 	 */
         UPDATE_STYLE;
-	if (HText_LastLineSize(me->text)) {
+	if (HText_LastLineSize(me->text, FALSE)) {
+	    HText_setLastChar(me->text, ' ');  /* absorb white space */
 	    HText_appendCharacter(me->text, '\r');
 	}
-	LYCheckForID(me, present, value, (int)HTML_TR_ID);
 	me->in_word = NO;
+
+	if (LYoverride_default_alignment(me)) {
+	    me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment;
+	} else if (me->List_Nesting_Level >= 0 ||
+		   ((me->Division_Level < 0) &&
+		    (!strcmp(me->sp->style->name, "Normal") ||
+		     !strcmp(me->sp->style->name, "Preformatted")))) {
+	        me->sp->style->alignment = HT_LEFT;
+	} else {
+	    me->sp->style->alignment = me->current_default_alignment;
+	}
+	if (present && present[HTML_TR_ALIGN] && value[HTML_TR_ALIGN]) {
+	    if (!strcasecomp(value[HTML_TR_ALIGN], "center") &&
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
+	        me->sp->style->alignment = HT_CENTER;
+	    else if (!strcasecomp(value[HTML_TR_ALIGN], "right") &&
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
+	        me->sp->style->alignment = HT_RIGHT;
+	    else if (!strcasecomp(value[HTML_TR_ALIGN], "left") ||
+	    	     !strcasecomp(value[HTML_TR_ALIGN], "justify"))
+	        me->sp->style->alignment = HT_LEFT;
+	}
+
+	LYCheckForID(me, present, value, (int)HTML_TR_ID);
+	me->inP = FALSE;
         break;
 
     case HTML_THEAD:
@@ -4711,7 +5231,7 @@ PRIVATE void HTML_start_element ARGS5(
 
     } /* end switch */
 
-    if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
+    if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY) {
 	if (me->skip_stack > 0) {
 	    if (TRACE)
 		fprintf(stderr,
@@ -4737,7 +5257,7 @@ PRIVATE void HTML_start_element ARGS5(
 
     	(me->sp)--;
 	me->sp[0].style = me->new_style;	/* Stack new style */
-	me->sp[0].tag_number = element_number;
+	me->sp[0].tag_number = ElementNumber;
 
 	if (TRACE)
 	    fprintf(stderr,"HTML:begin_element: adding style to stack - %s\n",
@@ -4746,7 +5266,7 @@ PRIVATE void HTML_start_element ARGS5(
 
 #if defined(USE_COLOR_STYLE)
 /* end empty tags straight away */
-        if (HTML_dtd.tags[element_number].contents == SGML_EMPTY)
+        if (HTML_dtd.tags[ElementNumber].contents == SGML_EMPTY)
         {
                 if (TRACE)
                         fprintf(stderr, "STYLE:begin_element:ending EMPTY element style\n");
@@ -4766,7 +5286,8 @@ PRIVATE void HTML_start_element ARGS5(
                         {
                                 end = start;
                                 start = strstr(lookfrom, tmp);
-                                lookfrom = start + 1;
+				if (start)
+				    lookfrom = start + 1;
                         }
                         while (start);
                         if (end)
@@ -4809,6 +5330,7 @@ PRIVATE void HTML_end_element ARGS3(
 {
     int i = 0;
     char *temp = NULL, *cp = NULL;
+    BOOL BreakFlag = FALSE;
 
 #ifdef CAREFUL			/* parser assumed to produce good nesting */
     if (element_number != me->sp[0].tag_number &&
@@ -4836,6 +5358,26 @@ PRIVATE void HTML_end_element ARGS3(
      *  SGML_EMPTY in HTMLDTD.c. - FM & KW
      */
     if (HTML_dtd.tags[element_number].contents != SGML_EMPTY) {
+	if ((element_number != me->sp[0].tag_number) &&
+	    me->skip_stack <= 0 &&
+            HTML_dtd.tags[HTML_LH].contents != SGML_EMPTY &&
+	    (me->sp[0].tag_number == HTML_UL ||
+	     me->sp[0].tag_number == HTML_OL ||
+	     me->sp[0].tag_number == HTML_MENU ||
+	     me->sp[0].tag_number == HTML_DIR) &&
+            (element_number == HTML_H1 ||
+	     element_number == HTML_H2 ||
+	     element_number == HTML_H3 ||
+	     element_number == HTML_H4 ||
+	     element_number == HTML_H6 ||
+	     element_number == HTML_H6)) {
+	    /*
+	     *  Set the break flag if we're popping
+	     *  a dummy HTML_LH substituted for an
+	     *  HTML_H# encountered in a list.
+	     */
+	    BreakFlag = TRUE;
+	}
 	if (me->skip_stack > 0) {
 	    if (TRACE)
 		fprintf(stderr,
@@ -4856,6 +5398,33 @@ PRIVATE void HTML_end_element ARGS3(
 	     *  if an overrun does occur. - FM
 	     */
 	    return;
+	} else if (element_number == HTML_SELECT &&
+	    me->sp[0].tag_number != HTML_SELECT) {
+	    /*
+	     *  Ignore non-corresponding SELECT tags, since we
+	     *  probably popped it and closed the SELECT block
+	     *  to deal with markup which amounts to a nested
+	     *  SELECT, or an out of order FORM end tag. - FM
+	     */
+	    return;
+	} else if ((element_number != me->sp[0].tag_number) &&
+            HTML_dtd.tags[HTML_LH].contents == SGML_EMPTY &&
+	    (me->sp[0].tag_number == HTML_UL ||
+	     me->sp[0].tag_number == HTML_OL ||
+	     me->sp[0].tag_number == HTML_MENU ||
+	     me->sp[0].tag_number == HTML_DIR) &&
+	    (element_number == HTML_H1 ||
+	     element_number == HTML_H2 ||
+	     element_number == HTML_H3 ||
+	     element_number == HTML_H4 ||
+	     element_number == HTML_H6 ||
+	     element_number == HTML_H6)) {
+	    /*
+	     *  It's an H# for which we substituted
+	     *  an HTML_LH, which we've declared as
+	     *  SGML_EMPTY, so just return. - FM
+	     */
+	    return;
 	} else if (me->sp < (me->stack + MAX_NESTING - 1)) {
 	    (me->sp)++;
 	    if (TRACE)
@@ -4868,7 +5437,9 @@ PRIVATE void HTML_end_element ARGS3(
   "Stack underflow error!  Tried to pop off more styles than exist in stack\n");
 	}
     }
-    
+    if (BreakFlag == TRUE)
+        return;
+
     /*
      *  Check for unclosed TEXTAREA. - FM
      */
@@ -4889,10 +5460,6 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_HTML:
         if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	if (me->inA || me->inSELECT || me->inTEXTAREA)
 	    if (TRACE) {
 	        fprintf(stderr,
@@ -4907,10 +5474,6 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_HEAD:
         if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	if (HText_hasToolbar(me->text))
 	    HText_appendParagraph(me->text);
 	break;
@@ -4997,10 +5560,6 @@ PRIVATE void HTML_end_element ARGS3(
     case HTML_BODY:
 	if (!me->text)
 	    UPDATE_STYLE;
-	if (me->inUnderline) {	/* This block could go away(?) - kw */
-	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
-	    me->inUnderline = FALSE;
-	}
 	if (me->inA || me->inSELECT || me->inTEXTAREA)
 	    if (TRACE) {
 	        fprintf(stderr,
@@ -5019,6 +5578,7 @@ PRIVATE void HTML_end_element ARGS3(
 	break;
 
     case HTML_NOFRAMES:
+    case HTML_IFRAME:
 	if (!me->text)
 	    UPDATE_STYLE;
 	LYEnsureDoubleSpace(me);
@@ -5125,7 +5685,8 @@ PRIVATE void HTML_end_element ARGS3(
 	     *  We're in an ADDRESS. Treat </P> as an instruction 
 	     *  to start a newline, if needed. - kw
 	     */
-	    if (HText_LastLineSize(me->text)) {
+	    if (HText_LastLineSize(me->text, FALSE)) {
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
 	        HText_appendCharacter(me->text, '\r');
 	    }
 	} else {
@@ -5261,9 +5822,9 @@ PRIVATE void HTML_end_element ARGS3(
 	 *  or single-quotes. - FM
 	 */
 	if (!(me->Quote_Level & 1))
-	    HText_appendCharacter(me->text, '"');
+	    HTML_put_character(me, '"');
 	else
-	    HText_appendCharacter(me->text, '\'');
+	    HTML_put_character(me, '\'');
         break;
 
     case HTML_PRE:				/* Formatted text */
@@ -5342,7 +5903,8 @@ PRIVATE void HTML_end_element ARGS3(
 	UPDATE_STYLE;
 	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
 	    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-	HText_endAnchor(me->text);
+	HText_endAnchor(me->text, me->CurrentANum);
+	me->CurrentANum = 0;
 	me->inBoldA = FALSE;
 	if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
 	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
@@ -5380,6 +5942,10 @@ PRIVATE void HTML_end_element ARGS3(
 	me->inFIGwithP = FALSE;
     	me->inFIG = FALSE;
 	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
+	if (me->List_Nesting_Level >= 0) {
+	    UPDATE_STYLE;
+	    HText_NegateLineOne(me->text);
+	}
 	break;
 
     case HTML_OBJECT:
@@ -5781,11 +6347,27 @@ End_Object:
 	break;
 
     case HTML_FIELDSET:
+	if (!me->text)
+	    UPDATE_STYLE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
+        break;
+
+    case HTML_LEGEND:
+	if (!me->text)
+	    UPDATE_STYLE;
+	LYEnsureDoubleSpace(me);
+	LYResetParagraphAlignment(me);
+	change_paragraph_style(me, me->sp->style);  /* Often won't really change */
         break;
 
     case HTML_LABEL:
         break;
 
+    case HTML_BUTTON:
+        break;
+
     case HTML_TEXTAREA:
         {
             InputFieldData I;
@@ -5850,7 +6432,7 @@ End_Object:
 	    for (i = 0; i < me->textarea_rows; i++) {
 		I.value = cp;
 
-                chars = HText_beginInput(me->text, &I);
+                chars = HText_beginInput(me->text, me->inUnderline, &I);
 	        for (; chars > 0; chars--)
 	    	    HTML_put_character(me, '_');
 	        HText_appendCharacter(me->text, '\r');
@@ -5865,7 +6447,7 @@ End_Object:
 	    while (cp) {
 		I.value = cp;
 
-                chars = HText_beginInput(me->text, &I);
+                chars = HText_beginInput(me->text, me->inUnderline, &I);
                 for (chars = atoi(me->textarea_cols); chars>0; chars--)
                     HTML_put_character(me, '_');
                 HText_appendCharacter(me->text, '\r');
@@ -5937,7 +6519,9 @@ End_Object:
 	     *  Finish the data off.
 	     */
        	    HTChunkTerminate(&me->option);
-	    /* finish the previous option @@@@@ */
+	/*
+	 *  Finish the previous option.
+	 */
 	    ptr = HText_setLastOptionValue(me->text,
 	    				   me->option.data,
 					   me->LastOptionValue,
@@ -6006,6 +6590,16 @@ End_Object:
 
     case HTML_TABLE:
         me->inTABLE = FALSE;
+	if (me->Division_Level >= 0)
+	    me->Division_Level--;
+	if (me->Division_Level >= 0)
+	    me->sp->style->alignment =
+	    			me->DivisionAlignments[me->Division_Level];
+	change_paragraph_style(me, me->sp->style);
+	UPDATE_STYLE;
+	me->current_default_alignment = me->sp->style->alignment;
+	if (me->List_Nesting_Level >= 0)
+	    HText_NegateLineOne(me->text);
         break;
 
 /* These TABLE related elements may now not be SGML_EMPTY. - kw */
@@ -6077,7 +6671,8 @@ End_Object:
         {
             end = start;
             start = strstr(lookfrom, tmp);
-            lookfrom = start + 1;
+            if (start)
+                lookfrom = start + 1;
         }
         while (start);
 /* trim the last matching element off the end
@@ -6085,6 +6680,7 @@ End_Object:
 */
         if (end)
             *end='\0';
+        hcode=hash_code(lookfrom && *lookfrom ? lookfrom : &tmp[1]);
         if (TRACE)
             fprintf(stderr, "CSS:%s (trimmed %s, END_ELEMENT)\n", Style_className, tmp);
     }
@@ -6177,7 +6773,7 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me)
 	HTML_put_string(me, me->comment_end);
     if (me->text) {
 	/*
-	 *  Emphasis containters, A, FONT, and FORM may be declared
+	 *  Emphasis containers, A, FONT, and FORM may be declared
 	 *  SGML_EMPTY in HTMLDTD.c, and SGML_character() in SGML.c
 	 *  may check for their end tags to call HTML_end_element()
 	 *  directly (with a check in that to bypass decrementing
@@ -6213,6 +6809,24 @@ PRIVATE void HTML_free ARGS1(HTStructured *, me)
 	}
 
 	/*
+	 *  If we're interactive and have hidden links but no visible
+	 *  links, add a message informing the user about this and
+	 *  suggesting use of the 'l'ist command. - FM
+	 */
+	if (!dump_output_immediately &&
+	    HText_sourceAnchors(me->text) < 1 &&
+	    HText_HiddenLinkCount(me->text) > 0) {
+	    HTML_start_element(me, HTML_P, 0, 0, (char **)&include);
+	    HTML_put_character(me, '[');
+	    HTML_start_element(me, HTML_EM, 0, 0, (char **)&include);
+	    HTML_put_string(me,
+		"Document has only hidden links. Use the 'l'ist command.");
+	    HTML_end_element(me, HTML_EM, (char **)&include);
+	    HTML_put_character(me, ']');
+	    HTML_end_element(me, HTML_P, (char **)&include);
+	}
+
+	/*
 	 *  Now call the cleanup function. - FM
 	 */
 	HText_endAppend(me->text);
@@ -6435,7 +7049,8 @@ PUBLIC HTStructured* HTML_new ARGS3(
     me->node_anchor = anchor;
 
     me->CurrentA = NULL;
-    me->base_href = NULL;;
+    me->CurrentANum = 0;
+    me->base_href = NULL;
     me->map_address = NULL;
 
     me->title.size = 0;
@@ -6549,9 +7164,9 @@ PUBLIC HTStructured* HTML_new ARGS3(
  
     me->comment_start = NULL;
     me->comment_end = NULL;
-#ifdef EXP_CHARTRANS
-    html_get_chartrans_info(me);
 
+#ifdef EXP_CHARTRANS
+    LYGetChartransInfo(me);
     UCTransParams_clear(&me->T);
 #endif /* EXP_CHARTRANS */
 
diff --git a/src/HTML.h b/src/HTML.h
index 3593ba8a..8d313e81 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -50,6 +50,7 @@ struct _HTStructured {
     HTStreamClass		targetClass;		/* Output routines */
 
     HTChildAnchor *		CurrentA;	/* current HTML_A anchor */
+    int				CurrentANum;	/* current HTML_A number */
     char *			base_href;	/* current HTML_BASE href */
     char *			map_address;	/* current HTML_MAP address */
 
diff --git a/src/LYBookmark.c b/src/LYBookmark.c
index caf859a1..c5f26577 100644
--- a/src/LYBookmark.c
+++ b/src/LYBookmark.c
@@ -347,7 +347,7 @@ PUBLIC void save_bookmark_link ARGS2(
     if (first_time) {
 	fprintf(fp,"<head>\n");
 #ifdef EXP_CHARTRANS
-	add_META_charset_to_fd(fp, -1);
+	LYAddMETAcharsetToFD(fp, -1);
 #endif
 	fprintf(fp,"<title>%s</title>\n</head>\n",BOOKMARK_TITLE);
 	fprintf(fp,"\
diff --git a/src/LYCharSets.c b/src/LYCharSets.c
index 016d24c4..b7c84b9d 100644
--- a/src/LYCharSets.c
+++ b/src/LYCharSets.c
@@ -3,6 +3,8 @@
 #include "HTCJK.h"
 
 #include "LYGlobalDefs.h"
+#include "UCMap.h"
+#include "UCDefs.h"
 #include "LYCharSets.h"
 #include "LYCharUtils.h"
 #ifdef EXP_CHARTRANS
@@ -27,11 +29,11 @@ PUBLIC BOOLEAN LYHaveCJKCharacterSet = FALSE;
 extern void UCInit NOARGS;
 extern int UCInitialized;
 #else 
-#ifndef MAX_CHARSETS
-#define MAX_CHARSETS
+#ifndef MAXCHARSETS
+#define MAXCHARSETS
 #endif
-#ifndef MAX_CHARSETSP
-#define MAX_CHARSETSP
+#ifndef MAXCHARSETSP
+#define MAXCHARSETSP
 #endif
 #endif /* EXP_CHARTRANS */
 
@@ -2044,7 +2046,7 @@ PUBLIC char * SevenBitApproximations[] = {
 /* 
  *  Add the array name to LYCharSets
  */
-PUBLIC char ** LYCharSets[MAX_CHARSETS]={
+PUBLIC char ** LYCharSets[MAXCHARSETS]={
 	ISO_Latin1,
 	ISO_Latin2,
 	ISO_LatinN,
@@ -2060,14 +2062,14 @@ PUBLIC char ** LYCharSets[MAX_CHARSETS]={
 	Korean,
 	Taipei,
 	SevenBitApproximations,
-	ISO_Latin1		/* maybe... - kw */
+	ISO_Latin1		/* Maybe... - KW */
 };
 
 /*
  *  Add the name that the user will see below.
  *  The order of LYCharSets and char_set_names MUST be the same
  */
-PUBLIC char * LYchar_set_names[MAX_CHARSETSP]={
+PUBLIC char * LYchar_set_names[MAXCHARSETSP]={
 	"ISO Latin 1         ",
 	"ISO Latin 2         ",
 	"Other ISO Latin     ",
@@ -2090,20 +2092,19 @@ PUBLIC char * LYchar_set_names[MAX_CHARSETSP]={
 
 PUBLIC int LYNumCharsets = 0; /* will be initialized later by UC_Register... */
 
-#include <UCDefs.h>
 /*
  *  Associate additional pieces of info with each of the charsets listed
  *  above.
  *  Will be automatically modified (and extended) by charset translations
- *  which are loaded using the EXP_CHARTRANS mechanism.
+ *  which are loaded using the chartrans mechanism.
  *  Most important piece of info to put here is a MIME charset name.
- *  Used for EXP_CHARTRANS.
+ *  Used for chartrans.
  *  The order of LYCharSets and LYCharSet_UC MUST be the same.
  *
  *  Note that most of the charsets added by the new mechanism in src/chrtrans
  *  don't show up here at all.  They don't have to.
  */
-PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]=
+PUBLIC LYUCcharset LYCharSet_UC[MAXCHARSETS]=
 {
   {-1,"iso-8859-1",    UCT_ENC_8BIT,UCT_REP_IS_LAT1,UCT_CP_IS_LAT1,UCT_R_LAT1,
                                                                    UCT_R_LAT1},
@@ -2116,14 +2117,16 @@ PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]=
   {-1,"macintosh",	UCT_ENC_8BIT,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"x-next",		UCT_ENC_8BIT,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"koi8-r",		UCT_ENC_8BIT,0,0,	UCT_R_8BIT,UCT_R_ASCII},
-/* There is no strict correlation for the next five, since the tranfer
- * charset gets decoded into Display Char Set by the CJK code (separate
- * from EXP_CHARTRANS mechanism).  For now, just put something there for
- * MIME charset name. */
-  {-1,"iso-2022-cn",	UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
+  /*
+   *  There is no strict correlation for the next five, since the tranfer
+   *  charset gets decoded into Display Char Set by the CJK code (separate
+   *  from EXP_CHARTRANS mechanism).  For now, just put something there for
+   *  MIME charset name.
+   */
+  {-1,"euc-cn",		UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"euc-jp",		UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"shift_jis",	UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
-  {-1,"iso-2022-kr",	UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
+  {-1,"euc-kr",		UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"big5",		UCT_ENC_CJK,0,0,	UCT_R_8BIT,UCT_R_ASCII},
   {-1,"us-ascii",	UCT_ENC_7BIT,UCT_REP_SUBSETOF_LAT1,
                                      UCT_CP_SUBSETOF_LAT1,
@@ -2133,13 +2136,14 @@ PUBLIC LYUCcharset LYCharSet_UC[MAX_CHARSETS]=
 #endif
 
 #if defined(USE_SLANG) || defined(EXP_CHARTRANS)
+
 /*
  *  Add the code of the the lowest character with the high bit set
  *  that can be directly displayed.
  *  Used by SLANG and for EXP_CHARTRANS.
  *  The order of LYCharSets and LYlowest_eightbit MUST be the same.
  */
-PUBLIC int LYlowest_eightbit[MAX_CHARSETS]={
+PUBLIC int LYlowest_eightbit[MAXCHARSETS]={
 	160,	/* ISO Latin 1 */
 	160,	/* ISO Latin 2 */
 	160,	/* Other ISO Latin */
@@ -2179,31 +2183,35 @@ PUBLIC void HTMLSetCharacterHandling ARGS1(int,i)
 #ifdef EXP_CHARTRANS
     if (LYCharSet_UC[i].enc != UCT_ENC_CJK) {
 	int chndl = 0;
+
 	if (UCAssume_MIMEcharset)
 	    chndl = UCGetLYhndl_byMIME(UCAssume_MIMEcharset);
 	HTCJK = NOCJK;
 	kanji_code = NOKANJI;
-	if (i == (chndl < 0 ? 0 : chndl))
+	if (i == (chndl < 0 ? 0 : chndl)) {
 	    LYRawMode = LYUseDefaultRawMode ? TRUE : FALSE;
-	else
+	} else {
 	    LYRawMode = LYUseDefaultRawMode ? FALSE : TRUE;
-	if (LYRawMode)
+	}
+	if (LYRawMode) {
 	    HTPassEightBitRaw = (LYlowest_eightbit[i] <= 160);
-	else
+	} else {
 	    HTPassEightBitRaw = FALSE;
+	}
 
 	HTPassEightBitNum =
 	    ((LYCharSet_UC[i].codepoints & UCT_CP_SUPERSETOF_LAT1) ||
 		(LYCharSet_UC[i].like8859 & UCT_R_HIGH8BIT));
 	
-	if (LYRawMode || i == chndl)
+	if (LYRawMode || i == chndl) {
 	    HTPassHighCtrlRaw = (LYlowest_eightbit[i] <= 130);
-	else
+	} else {
 	    HTPassHighCtrlRaw = FALSE;
+	}
 
 	HTPassHighCtrlNum = FALSE;
     } else
-#endif
+#endif /* EXP_CHARTRANS */
     if (!strncmp(LYchar_set_names[i], "ISO Latin 1", 11)) {
 	HTCJK = NOCJK;
 	kanji_code = NOKANJI;
@@ -2295,11 +2303,14 @@ PUBLIC void HTMLSetCharacterHandling ARGS1(int,i)
 #endif /* EXP_CHARTRANS */
 
 #ifdef USE_SLANG
-    if (LYlowest_eightbit[i] > 191)
-      /* higher than this may output cntrl chars to screen - kw */
+    if (LYlowest_eightbit[i] > 191) {
+	/*
+	 *  Higher than this may output cntrl chars to screen. - KW
+	 */
 	SLsmg_Display_Eight_Bit = 191;
-    else
+    } else {
 	SLsmg_Display_Eight_Bit = LYlowest_eightbit[i];
+    }
 #endif /* USE_SLANG */
 
     return;
@@ -2343,11 +2354,11 @@ PUBLIC void HTMLSetUseDefaultRawMode ARGS2(int,i, BOOLEAN,modeflag)
     } else
 #endif /* EXP_CHARTRANS */
     if (!strncmp(LYchar_set_names[i], "ISO Latin 1", 11) ||
-    	!strncmp(LYchar_set_names[i], "Chinese", 7) ||
-	!strncmp(LYchar_set_names[i], "Japanese (EUC)", 14) ||
-	!strncmp(LYchar_set_names[i], "Japanese (SJIS)", 15) ||
-	!strncmp(LYchar_set_names[i], "Korean", 6) ||
-	!strncmp(LYchar_set_names[i], "Taipei (Big5)", 13)) {
+	       !strncmp(LYchar_set_names[i], "Chinese", 7) ||
+	       !strncmp(LYchar_set_names[i], "Japanese (EUC)", 14) ||
+	       !strncmp(LYchar_set_names[i], "Japanese (SJIS)", 15) ||
+	       !strncmp(LYchar_set_names[i], "Korean", 6) ||
+	       !strncmp(LYchar_set_names[i], "Taipei (Big5)", 13)) {
 	if (modeflag == TRUE) {
 	    LYUseDefaultRawMode = TRUE;
 	} else {
@@ -2497,13 +2508,10 @@ PUBLIC CONST char * HTMLGetEntityName ARGS1(int,i)
 }
 
 /*
- *  Function to return the values of the
- *  ISO_Latin1 Character Set.  It assumes
- *  the strings have only one character,
- *  and restores nbsp to 160 and shy to
- *  173, but keeps our substitutions for
- *  characters that are not part of the
- *  ISO-8859-1 charset. - FM
+ *  Function to return the values of the ISO_Latin1 Character Set.
+ *  It assumes the strings have only one character, and restores
+ *  nbsp to 160 and shy to 173, but keeps our substitutions for
+ *  characters that are not part of the ISO-8859-1 charset. - FM
  *
  *  Return '\0' to signal that there isn't a one-character
  *  equivalent.  Caller must check! and do whatever additional
@@ -2527,8 +2535,12 @@ PUBLIC char HTMLGetLatinOneValue ARGS1(int,i)
 	    break;
 
 	default:
-	    if (ch && ISO_Latin1[i][1])	/* Got a string longer than 1 char */
-	      return '\0';
+	    if (ch && ISO_Latin1[i][1]) {
+		/*
+		 *  Got a string longer than 1 char.
+		 */
+		return '\0';
+	    }
 	    break;
      }
 
@@ -2546,12 +2558,10 @@ PUBLIC void HTMLUseCharacterSet ARGS1(int,i)
     HTMLSetHaveCJKCharacterSet(i);
     return;
 }
+
 /*
- * Initializer, calls initialization function for the
- * CHARTRANS handling if compiled in. - kw
- * (Also to ensure this module is linked
- * if the external model is common block, and the
- * module is ever placed in a library. - FM) ??
+ *  Initializer, calls initialization function for the
+ *  CHARTRANS handling if compiled in. - KW
  */
 PUBLIC int LYCharSetsDeclared NOPARAMS
 {
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index cf1ecfb8..14b036ce 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -195,18 +195,35 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 	**  Check for a numeric or named entity. - FM
 	*/
         if (*p == '&') {
+	    BOOL isHex = FALSE;
+	    BOOL isDecimal = FALSE;
 	    p++;
 	    len = strlen(p);
 	    /*
 	    **  Check for a numeric entity. - FM
 	    */
 	    if (*p == '#' && len > 2 &&
-	        (unsigned char)*(p+1) < 127 &&
-		isdigit((unsigned char)*(p+1))) {
-		cp = ++p;
+	        (unsigned char)*(p+1) == 'x' &&
+		(unsigned char)*(p+2) < 127 && 
+		isxdigit((unsigned char)*(p+2))) {
+		isHex = TRUE;
+	    } else if (*p == '#' && len > 2 &&
+		       (unsigned char)*(p+1) < 127 &&
+		       isdigit((unsigned char)*(p+1))) {
+		isDecimal = TRUE;
+	    }
+	    if (isHex || isDecimal) {
+		if (isHex) {
+		    p += 2;
+		    cp = p;
+		} else {
+		    cp = ++p;
+		}
 		while (*p && (unsigned char)*p < 127 &&
-		       isdigit((unsigned char)*p))
+		       (isHex ? isxdigit((unsigned char)*p) :
+				isdigit((unsigned char)*p))) {
 		    p++;
+		}
 		/*
 		**  Save the terminator and isolate the digit(s). - FM
 		*/
@@ -222,7 +239,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		**	or HTCJK set.
 		**  (4) Is 128 - 159 and we don't have HTPassHighCtrlNum set.
 		*/
-		if ((sscanf(cp, "%d", &value) != 1) ||
+		if (((isHex ? sscanf(cp, "%x", &value) :
+			      sscanf(cp, "%d", &value)) != 1) ||
 		    (value > 255 &&
 		     value != 8194 && value != 8195 && value != 8201 &&
 		     value != 8211 && value != 8212 && value != 8482) ||
@@ -240,6 +258,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		    */
 		    *q++ = '&';
 		    *q++ = '#';
+		    if (isHex)
+		        *q++ = 'x';
 		    if (cpe != '\0')
 		       *(p-1) = cpe;
 		    p = cp;
@@ -292,6 +312,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		    if (hidden) {
 		        *q++ = '&';
 		        *q++ = '#';
+			if (isHex)
+			    *q++ = 'x';
 			if (cpe != '\0')
 			    *(p-1) = cpe;
 			p = cp;
@@ -315,6 +337,8 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		    if (hidden) {
 		        *q++ = '&';
 		        *q++ = '#';
+			if (isHex)
+			    *q++ = 'x';
 			if (cpe != '\0')
 			    *(p-1) = cpe;
 			p = cp;
@@ -330,11 +354,13 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		/*
 		**  For 8482 (trade) use the character reference if it's
 		**  a hidden INPUT, otherwise use whatever the tables have
-		**  for &trade;. - FM, kw
+		**  for &trade;. - FM & KW
 		*/
 	        } else if (value == 8482 && hidden) {
 		        *q++ = '&';
 		        *q++ = '#';
+			if (isHex)
+			    *q++ = 'x';
 			if (cpe != '\0')
 			    *(p-1) = cpe;
 			p = cp;
@@ -345,9 +371,10 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		**  use it's value. - FM
 		*/
 		} else if (value < 161 || 
-			   (value < 256 && (HTPassEightBitNum ||
-			   !strncmp(LYchar_set_names[current_char_set],
-			   	    "ISO Latin 1", 11)))) {
+			   (value < 256 &&
+			    (HTPassEightBitNum ||
+			     !strncmp(LYchar_set_names[current_char_set],
+				      "ISO Latin 1", 11)))) {
 		    /*
 		    **  No conversion needed.
 		    */
@@ -363,16 +390,21 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		*/
 		} else {
 		    CONST char * name;
-		    if (value == 8482) { /* trade mark sign falls through to here -kw */
-		      name = "trade";
+		    if (value == 8482) {
+			/*
+			**  Trade mark sign falls through to here. - KW
+			*/
+			name = "trade";
 		    } else {
-		      value -= 160;
-		      name = HTMLGetEntityName(value);
+			value -= 160;
+			name = HTMLGetEntityName(value);
 		    }
-		    for(low = 0, high = HTML_dtd.number_of_entities;
-		        high > low;
-			diff < 0 ? (low = i+1) : (high = i)) {
-			/* Binary search */
+		    for (low = 0, high = HTML_dtd.number_of_entities;
+			 high > low;
+			 diff < 0 ? (low = i+1) : (high = i)) {
+			/*
+			**  Binary search.
+			*/
 			i = (low + (high-low)/2);
 			diff = strcmp(HTML_dtd.entity_names[i], name);
 			if (diff == 0) {
@@ -413,7 +445,9 @@ PUBLIC char * LYUnEscapeEntities ARGS3(
 		for (low = 0, high = HTML_dtd.number_of_entities;
 		     high > low ;
 		     diff < 0 ? (low = i+1) : (high = i)) {
-		    /* Binary search */
+		    /*
+		    **  Binary search.
+		    */
 		    i = (low + (high-low)/2);
 		    diff = strcmp(HTML_dtd.entity_names[i], p);
 		    if (diff == 0) {
@@ -738,7 +772,9 @@ PUBLIC void LYUnEscapeToLatinOne ARGS2(
 		for (low = 0, high = HTML_dtd.number_of_entities;
 		     high > low ;
 		     diff < 0 ? (low = i+1) : (high = i)) {
-		    /* Binary search */
+		    /*
+		    **  Binary search.
+		    */
 		    i = (low + (high-low)/2);
 		    diff = strcmp(HTML_dtd.entity_names[i], p);
 		    if (diff == 0) {
@@ -752,31 +788,42 @@ PUBLIC void LYUnEscapeToLatinOne ARGS2(
 			buf[0] = HTMLGetLatinOneValue(i);
                         if (buf[0] == '\0') {
                             /*
-                            **  The entity does not have an 8859-1 representation
-                            **  of exactly one char length.  Try to deal with it
-                            **  anyway - either HTEscape the whole mess, or pass
-                            **  through raw.  So make sure the ISO_Latin1 table,
-                            **  which is the first table in LYCharSets, has resonable
-			    **  substitution strings! (if it really must have any
-			    **  longer than one char..) -kw
+                            **  The entity does not have an 8859-1
+			    **  representation of exactly one char length.
+			    **  Try to deal with it anyway - either HTEscape
+			    **  the whole mess, or pass through raw.  So
+			    **  make sure the ISO_Latin1 table, which is the
+			    **  first table in LYCharSets, has reasonable
+			    **  substitution strings! (if it really must
+			    **  have any longer than one char) - KW
                             */
-			    if (!LYCharSets[0][i][0]) /* totally empty, skip - kw */
-			        /* do nothing */ ;
-			    else if (isURL) {
-			      /* *All* will be HTEscape'd - kw */
-			      esc = HTEscape(LYCharSets[0][i], URL_XALPHAS);
-			      for (e = 0; esc[e]; e++)
-				*q++ = esc[e];
-			      FREE(esc);
+			    if (!LYCharSets[0][i][0]) {
+				/*
+				**  Totally empty, skip. - KW
+				*/
+			        ; /* do nothing */
+			    } else if (isURL) {
+				/*
+				**  All will be HTEscape'd. - KW
+				*/
+				esc = HTEscape(LYCharSets[0][i], URL_XALPHAS);
+				for (e = 0; esc[e]; e++)
+				    *q++ = esc[e];
+				FREE(esc);
 			    } else {
-			      /* *Nothing* will be HTEscape'd - kw */
-			      for (e = 0; LYCharSets[0][i][e]; e++)
-                                *q++ = (unsigned char)(LYCharSets[0][i][e]);
+				/*
+				**  Nothing will be HTEscape'd. - KW 
+				*/
+				for (e = 0; LYCharSets[0][i][e]; e++) {
+				    *q++ =
+					(unsigned char)(LYCharSets[0][i][e]);
+				}
 			    }
-                        } else if ((unsigned char)buf[0] > 159 && isURL == TRUE) {
+		        } else if ((unsigned char)buf[0] > 159 &&
+				   isURL == TRUE) {
 			    esc = HTEscape(buf, URL_XALPHAS);
 			    for (e = 0; esc[e]; e++)
-			    *q++ = esc[e];
+				*q++ = esc[e];
 			    FREE(esc);
 			} else {
 			    *q++ = buf[0];
@@ -1225,6 +1272,67 @@ PUBLIC void LYFillLocalFileURL ARGS2(
     return;
 }
 
+#ifdef EXP_CHARTRANS
+/*
+**  This function writes a line with a META tag to an open file,
+**  which will specify a charset parameter to use when the file is
+**  read back in.  It is meant for temporary HTML files used by the
+**  various special pages which may show titles of documents.  When those
+**  files are created, the title strings normally have been translated and
+**  expanded to the display character set, so we have to make sure they
+**  don't get translated again.
+**  If the user has changed the display character set during the lifetime
+**  of the Lynx session (or, more exactly, during the time the title
+**  strings to be written were generated), they may now have different
+**  character encodings and there is currently no way to get it all right.
+**  To change this, we would have to add a variable for each string which
+**  keeps track of its character encoding...
+**  But at least we can try to ensure that reading the file after future
+**  display character set changes will give reasonable output.
+**
+**  The META tag is not written if the display character set (passed as
+**  disp_chndl) already corresponds to the charset assumption that
+**  would be made when the file is read. - KW
+*/
+PUBLIC void LYAddMETAcharsetToFD ARGS2(
+	FILE *,		fd,
+	int,		disp_chndl)
+{
+    if (disp_chndl == -1)
+	/*
+	 *  -1 means use current_char_set.
+	 */
+	disp_chndl = current_char_set;
+
+    if (fd == NULL || disp_chndl < 0)
+	/*
+	 *  Should not happen.
+	 */
+	return;
+
+    if (UCLYhndl_HTFile_for_unspec == disp_chndl)
+	/*
+	 *  Not need to do, so we don't.
+	 */
+	return;
+
+    if (LYCharSet_UC[disp_chndl].enc == UCT_ENC_7BIT)
+	/*
+	 *  There shouldn't be any 8-bit characters in this case.
+	 */
+	return;
+
+    /*
+     *  In other cases we don't know because UCLYhndl_for_unspec may
+     *  change during the lifetime of the file (by toggling raw mode
+     *  or changing the display character set), so proceed.
+     */
+    fprintf(fd, "<META %s content=\"text/html;charset=%s\">\n",
+		"http-equiv=\"content-type\"",
+		LYCharSet_UC[disp_chndl].MIMEname);
+}
+#endif /* EXP_CHARTRANS */
+
 /*
 ** This function returns OL TYPE="A" strings in
 ** the range of " A." (1) to "ZZZ." (18278). - FM
@@ -1583,72 +1691,28 @@ PUBLIC void LYZero_OL_Counter ARGS1(
 /*
 **  This function is used by the HTML Structured object. - kw
 */
-PUBLIC void html_get_chartrans_info ARGS1(HTStructured *, me)
+PUBLIC void LYGetChartransInfo ARGS1(
+	HTStructured *,		me)
 {
-    me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,UCT_STAGE_STRUCTURED);
+    me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
+					UCT_STAGE_STRUCTURED);
     if (me->UCLYhndl < 0) {
 	int chndl = HTAnchor_getUCLYhndl(me->node_anchor, UCT_STAGE_HTEXT);
+
 	if (chndl < 0) {
 	    chndl = current_char_set;
 	    HTAnchor_setUCInfoStage(me->node_anchor, chndl, UCT_STAGE_HTEXT,
-			    UCT_SETBY_STRUCTURED);
+				    UCT_SETBY_STRUCTURED);
 	}
 	HTAnchor_setUCInfoStage(me->node_anchor, chndl,
 				UCT_STAGE_STRUCTURED, UCT_SETBY_STRUCTURED);
 	me->UCLYhndl = HTAnchor_getUCLYhndl(me->node_anchor,
 					    UCT_STAGE_STRUCTURED);
     }
-    me->UCI = HTAnchor_getUCInfoStage(me->node_anchor,UCT_STAGE_STRUCTURED);
-}
-
-/*
-**  This function writes a line with a META tag to an open file,
-**  which will specify a charset parameter to use when the file is
-**  read back in.  It is meant for temporary HTML files used by the
-**  various special pages which may show titles of documents.  When those
-**  files are created, the title strings normally have been translated and
-**  expanded to the display character set, so we have to make sure the
-**  don't get translated again.
-**  If the user has changed the display character set during the lifetime
-**  of the Lynx session (or, more exactly, during the time the title
-**  strings to be written were generated), the may now have different
-**  character encodings and there is currently no way to get it all right.
-**  To change this, we would have to add a variable for each string which
-**  keeps track of its character encoding...
-**  But at least we can try to ensure that reading the file after future
-**  display character set changes will give reasonable output.
-**
-**  The META tag is not written if the display character set (passed as
-**  disp_chndl) already corresponds to the charset assumption that
-**  would be made when the file is read. -kw
-*/
-PUBLIC void add_META_charset_to_fd ARGS2(
-    FILE *,	fp,
-    int,	disp_chndl
-    )
-{
-    if (disp_chndl == -1)	/* -1 means use current_char_set */
-	disp_chndl = current_char_set;
-    if (fp == NULL || disp_chndl < 0)
-	return;			/* should not happen */
-    if (UCLYhndl_HTFile_for_unspec == disp_chndl)
-	return;			/* not need to do, so we don't */
-    if (LYCharSet_UC[disp_chndl].enc == UCT_ENC_7BIT)
-	return;			/* There shouldn't be any 8-bit characters
-				 in this case. */
-    /*
-     * In other cases we don't know because UCLYhndl_for_unspec may
-     * change during the lifetime of the file (by toggling raw mode
-     * or changing the display character set), so proceed.
-     */
-
-    fprintf(fp,"<META %s content=\"text/html;charset=%s\">\n",
-	    "http-equiv=\"content-type\"",
-	    LYCharSet_UC[disp_chndl].MIMEname);
+    me->UCI = HTAnchor_getUCInfoStage(me->node_anchor, UCT_STAGE_STRUCTURED);
 }
 
 #endif /* EXP_CHARTRANS */
-
 /*
 **  This function processes META tags in HTML streams. - FM
 */
@@ -1800,15 +1864,40 @@ PUBLIC void LYHandleMETA ARGS4(
 	 *  If we didn't get an Expires MIME header,
 	 *  store it in the anchor element, and if we
 	 *  haven't yet set no_cache, check whether we
-	 *  should. - FM
+	 *  should.  Note that we don't accept a Date
+	 *  header via META tags, because it's likely
+	 *  to be untrustworthy, but do check for a
+	 *  Date header from a server when making the
+	 *  comparsion. - FM
 	 */
 	LYUnEscapeToLatinOne(&content, FALSE);
 	LYTrimHead(content);
 	LYTrimTail(content);
 	StrAllocCopy(me->node_anchor->expires, content);
 	if (me->node_anchor->no_cache == FALSE) {
-	    if ((content[0] == '0' && content[1] == '\0') ||
-		LYmktime(content) <= 0) {
+	    if (!strcmp(content, "0")) {
+		/*
+		 *  The value is zero, which we treat as
+		 *  an absolute no-cache directive. - FM
+		 */
+		me->node_anchor->no_cache = TRUE;
+		HText_setNoCache(me->text);
+	    } else if (me->node_anchor->date != NULL) {
+	        /*
+		 *  We have a Date header, so check if
+		 *  the value is less than or equal to
+		 *  that. - FM
+		 */
+		if (LYmktime(content, TRUE) <=
+		    LYmktime(me->node_anchor->date, TRUE)) {
+		    me->node_anchor->no_cache = TRUE;
+		    HText_setNoCache(me->text);
+		}
+	    } else if (LYmktime(content, FALSE) <= 0) {
+	        /*
+		 *  We don't have a Date header, and
+		 *  the value is in past for us. - FM
+		 */
 		me->node_anchor->no_cache = TRUE;
 		HText_setNoCache(me->text);
 	    }
@@ -1833,88 +1922,91 @@ PUBLIC void LYHandleMETA ARGS4(
 	if ((cp = strstr(content, "text/html;")) != NULL &&
 	    (cp1 = strstr(content, "charset")) != NULL &&
 	    cp1 > cp) {
-			BOOL chartrans_ok = NO;
-			char *cp3 = NULL, *cp4;
-			int chndl;
+	    BOOL chartrans_ok = NO;
+	    char *cp3 = NULL, *cp4;
+	    int chndl;
 
 	    cp1 += 7;
-			while (*cp1 == ' ' || *cp1 == '=' || *cp1 == '"')
+	    while (*cp1 == ' ' || *cp1 == '=' || *cp1 == '"')
 	        cp1++;
 #ifdef EXP_CHARTRANS
-			    StrAllocCopy(cp3, cp1); /* copy to mutilate more */
-			    for (cp4=cp3; (*cp4 != '\0' && *cp4 != '"' &&
-					   *cp4 != ';'  && *cp4 != ':' &&
-					   !WHITE(*cp4));	cp4++)
-				/* nothing */ ;
-			    *cp4 = '\0';
-			    cp4 = cp3;
-			    chndl = UCGetLYhndl_byMIME(cp3);
-			    if (chndl < 0) {
-				if (0==strcmp(cp4, "cn-big5")) {
-				    cp4 += 3;
-				    chndl = UCGetLYhndl_byMIME(cp4);
-				}
-				else if (0==strncmp(cp4, "cn-gb", 5)) {
-				    StrAllocCopy(cp3, "gb2312");
-				    cp4 = cp3;
-				    chndl = UCGetLYhndl_byMIME(cp4);
-				}
-			    }
-			    if (UCCanTranslateFromTo(chndl, current_char_set))
-			    {
-				chartrans_ok = YES;
-				StrAllocCopy(me->node_anchor->charset, cp4);
-				HTAnchor_setUCInfoStage(me->node_anchor, chndl,
-				   UCT_STAGE_PARSER, UCT_SETBY_STRUCTURED);
-			    }
-			    else if (chndl < 0)	{/* got something but we don't
-						 recognize it */
-				chndl = UCLYhndl_for_unrec;
-				if (UCCanTranslateFromTo(chndl,
-							 current_char_set))
-				{
-				    chartrans_ok = YES;
-				    HTAnchor_setUCInfoStage(me->node_anchor,
-							    chndl,
-				       UCT_STAGE_PARSER, UCT_SETBY_STRUCTURED);
-				}
-			    }
-			    FREE(cp3);
-			    if (chartrans_ok) {
-				LYUCcharset * p_in =
-				    HTAnchor_getUCInfoStage(me->node_anchor,
-							     UCT_STAGE_PARSER);
-				LYUCcharset * p_out =
-				    HTAnchor_setUCInfoStage(me->node_anchor,
-							    current_char_set,
-					 UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT);
-				if (!p_out) /* try again */
-				    p_out =
-				      HTAnchor_getUCInfoStage(me->node_anchor,
-							     UCT_STAGE_HTEXT);
-				if (0==strcmp(p_in->MIMEname,"x-transparent"))
-				{
-				    HTPassEightBitRaw = TRUE;
-				    HTAnchor_setUCInfoStage(me->node_anchor,
-				       HTAnchor_getUCLYhndl(me->node_anchor,
-							    UCT_STAGE_HTEXT),
-				       UCT_STAGE_PARSER, UCT_SETBY_DEFAULT);
-				}
-				if (0==strcmp(p_out->MIMEname,"x-transparent"))
-				{
-				    HTPassEightBitRaw = TRUE;
-				    HTAnchor_setUCInfoStage(me->node_anchor,
-				       HTAnchor_getUCLYhndl(me->node_anchor,
-							    UCT_STAGE_PARSER),
-				       UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT);
-				}
-				if (!(p_in->enc & UCT_ENC_CJK) &&
-				    (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)){
-				    HTCJK = NOCJK;
-				} else if (chndl == current_char_set) {
-				HTPassEightBitRaw = TRUE;
-				}
-				html_get_chartrans_info(me);
+	    StrAllocCopy(cp3, cp1); /* copy to mutilate more */
+	    for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' &&
+			     *cp4 != ';'  && *cp4 != ':' &&
+			     !WHITE(*cp4)); cp4++) {
+		; /* do nothing */
+	    }
+	    *cp4 = '\0';
+	    cp4 = cp3;
+	    chndl = UCGetLYhndl_byMIME(cp3);
+	    if (chndl < 0) {
+		if (!strcmp(cp4, "cn-big5")) {
+		    cp4 += 3;
+		    chndl = UCGetLYhndl_byMIME(cp4);
+		} else if (!strncmp(cp4, "cn-gb", 5)) {
+		    StrAllocCopy(cp3, "gb2312");
+		    cp4 = cp3;
+		    chndl = UCGetLYhndl_byMIME(cp4);
+		}
+	    }
+	    if (UCCanTranslateFromTo(chndl, current_char_set)) {
+		chartrans_ok = YES;
+		StrAllocCopy(me->node_anchor->charset, cp4);
+		HTAnchor_setUCInfoStage(me->node_anchor, chndl,
+					UCT_STAGE_PARSER,
+					UCT_SETBY_STRUCTURED);
+	    } else if (chndl < 0) {
+		/*
+		 *  Got something but we don't recognize it.
+		 */
+		chndl = UCLYhndl_for_unrec;
+		if (UCCanTranslateFromTo(chndl, current_char_set)) {
+		    chartrans_ok = YES;
+		    HTAnchor_setUCInfoStage(me->node_anchor, chndl,
+					    UCT_STAGE_PARSER,
+					    UCT_SETBY_STRUCTURED);
+		}
+	    }
+	    FREE(cp3);
+	    if (chartrans_ok) {
+		LYUCcharset * p_in =
+				HTAnchor_getUCInfoStage(me->node_anchor,
+							UCT_STAGE_PARSER);
+		LYUCcharset * p_out =
+				HTAnchor_setUCInfoStage(me->node_anchor,
+							current_char_set,
+							UCT_STAGE_HTEXT,
+							UCT_SETBY_DEFAULT);
+		if (!p_out) {
+		    /*
+		     *  Try again.
+		     */
+		    p_out = HTAnchor_getUCInfoStage(me->node_anchor,
+						    UCT_STAGE_HTEXT);
+		}
+		if (!strcmp(p_in->MIMEname, "x-transparent")) {
+		    HTPassEightBitRaw = TRUE;
+		    HTAnchor_setUCInfoStage(me->node_anchor,
+				HTAnchor_getUCLYhndl(me->node_anchor,
+						     UCT_STAGE_HTEXT),
+						     UCT_STAGE_PARSER,
+						     UCT_SETBY_DEFAULT);
+		}
+		if (!strcmp(p_out->MIMEname, "x-transparent")) {
+		    HTPassEightBitRaw = TRUE;
+		    HTAnchor_setUCInfoStage(me->node_anchor,
+				HTAnchor_getUCLYhndl(me->node_anchor,
+						     UCT_STAGE_PARSER),
+						     UCT_STAGE_HTEXT,
+						     UCT_SETBY_DEFAULT);
+		}
+		if (!(p_in->enc & UCT_ENC_CJK) &&
+		    (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)) {
+		    HTCJK = NOCJK;
+		} else if (chndl == current_char_set) {
+		    HTPassEightBitRaw = TRUE;
+		}
+		LYGetChartransInfo(me);
 			} else  /* Fall through to old behavior */
 #endif /* EXP_CHARTRANS */
 	    if (!strncmp(cp1, "us-ascii", 8) ||
@@ -2089,6 +2181,20 @@ PUBLIC void LYHandleMETA ARGS4(
 		StrAllocCopy(id_string, cp);
 		*cp = '\0';
 	    }
+	    if (me->inA) {
+	        /*
+		 *  Ugh!  The META tag, which is a HEAD element,
+		 *  is in an Anchor, which is BODY element.  All
+		 *  we can do is close the Anchor and cross our
+		 *  fingers. - FM
+		 */
+		if (me->inBoldA == TRUE && me->inBoldH == FALSE)
+		    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+		me->inBoldA = FALSE;
+	        HText_endAnchor(me->text, me->CurrentANum);
+		me->inA = FALSE;
+		me->CurrentANum = 0;
+	    }
 	    me->CurrentA = HTAnchor_findChildAndLink(
 				me->node_anchor,	/* Parent */
 				id_string,		/* Tag */
@@ -2108,14 +2214,14 @@ PUBLIC void LYHandleMETA ARGS4(
 		HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
 	    HTML_put_character(me, ' ');
 	    me->in_word = NO;
-	    HText_beginAnchor(me->text, me->CurrentA);
+	    HText_beginAnchor(me->text, me->inUnderline, me->CurrentA);
 	    if (me->inBoldH == FALSE)
 		HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
 	    HTML_put_string(me, href);
 	    FREE(href);
 	    if (me->inBoldH == FALSE)
 		HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
-	    HText_endAnchor(me->text);
+	    HText_endAnchor(me->text, 0);
 	    LYEnsureSingleSpace(me);
 	}
 
@@ -2169,6 +2275,333 @@ free_META_copies:
     FREE(content);
 }
 
+#ifdef NOTUSED_FOTEMODS
+/*  next two functions done in HTML.c instead in this code set -
+    see there. - kw */
+/*
+**  This function handles P elements in HTML streams.
+**  If start is TRUE it handles a start tag, and if
+**  FALSE, an end tag.  We presently handle start
+**  and end tags identically, but this can lead to
+**  a different number of blank lines between the
+**  current paragraph and subsequent text when a P
+**  end tag is present or not in the markup. - FM
+*/
+PUBLIC void LYHandleP ARGS5(
+	HTStructured *,		me,
+	CONST BOOL*,	 	present,
+	CONST char **,		value,
+	char **,		include,
+	BOOL,			start)
+{
+    if (TRUE) {
+	/*
+	 *  FIG content should be a true block, which like P inherits
+	 *  the current style.  APPLET is like character elements or
+	 *  an ALT attribute, unless it content contains a block element.
+	 *  If we encounter a P in either's content, we set flags to treat
+	 *  the content as a block.  - FM
+	 */
+	if (me->inFIG)
+	    me->inFIGwithP = TRUE;
+
+	if (me->inAPPLET)
+	    me->inAPPLETwithP = TRUE;
+
+	UPDATE_STYLE;
+	if (me->List_Nesting_Level >= 0) {
+	    /*
+	     *  We're in a list.  Treat P as an instruction to
+	     *  create one blank line, if not already present,
+	     *  then fall through to handle attributes, with
+	     *  the "second line" margins. - FM
+	     */
+	    if (me->inP) {
+	        if (me->inFIG || me->inAPPLET ||
+		    me->inCAPTION || me->inCREDIT ||
+		    me->sp->style->spaceAfter > 0 ||
+		    me->sp->style->spaceBefore > 0) {
+	            LYEnsureDoubleSpace(me);
+		} else {
+	            LYEnsureSingleSpace(me);
+		}
+	    }
+	} else if (me->sp[0].tag_number == HTML_ADDRESS) {
+	    /*
+	     *  We're in an ADDRESS. Treat P as an instruction 
+	     *  to start a newline, if needed, then fall through
+	     *  to handle attributes. - FM
+	     */
+	    if (HText_LastLineSize(me->text, FALSE)) {
+		HText_setLastChar(me->text, ' ');  /* absorb white space */
+	        HText_appendCharacter(me->text, '\r');
+	    }
+	} else if (!(me->inLABEL && !me->inP)) {
+	    HText_appendParagraph(me->text);
+	    me->inLABEL = FALSE;
+	}
+	me->in_word = NO;
+
+	if (LYoverride_default_alignment(me)) {
+	    me->sp->style->alignment = styles[me->sp[0].tag_number]->alignment;
+	} else if (me->List_Nesting_Level >= 0 ||
+		   ((me->Division_Level < 0) &&
+		    (!strcmp(me->sp->style->name, "Normal") ||
+		     !strcmp(me->sp->style->name, "Preformatted")))) {
+	        me->sp->style->alignment = HT_LEFT;
+	} else {
+	    me->sp->style->alignment = me->current_default_alignment;
+	}
+	if (present && present[HTML_P_ALIGN] && value[HTML_P_ALIGN]) {
+	    if (!strcasecomp(value[HTML_P_ALIGN], "center") &&
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
+	        me->sp->style->alignment = HT_CENTER;
+	    else if (!strcasecomp(value[HTML_P_ALIGN], "right") &&
+	        !(me->List_Nesting_Level >= 0 && !me->inP))
+	        me->sp->style->alignment = HT_RIGHT;
+	    else if (!strcasecomp(value[HTML_P_ALIGN], "left") ||
+	    	     !strcasecomp(value[HTML_P_ALIGN], "justify"))
+	        me->sp->style->alignment = HT_LEFT;
+	}
+
+	LYCheckForID(me, present, value, (int)HTML_P_ID);
+
+	/*
+	 *  Mark that we are starting a new paragraph
+	 *  and don't have any of it's text yet. - FM
+	 *
+	 */
+	me->inP = FALSE;
+    }
+
+    return;
+}
+
+/*
+**  This function handles SELECT elements in HTML streams.
+**  If start is TRUE it handles a start tag, and if FALSE,
+**  an end tag. - FM
+*/
+PUBLIC void LYHandleSELECT ARGS5(
+	HTStructured *,		me,
+	CONST BOOL*,	 	present,
+	CONST char **,		value,
+	char **,		include,
+	BOOL,			start)
+{
+    int i;
+
+    if (start == TRUE) {
+	char *name = NULL;
+	BOOLEAN multiple = NO;
+	char *size = NULL;
+
+        /*
+	 *  Initialize the disable attribute.
+	 */
+	me->select_disabled = FALSE;
+
+	/*
+	 *  Make sure we're in a form.
+	 */
+	if (!me->inFORM) {
+	    if (TRACE) {
+		fprintf(stderr,
+			"HTML: SELECT start tag not within FORM tag\n");
+	    } else if (!me->inBadHTML) {
+		_statusline(BAD_HTML_USE_TRACE);
+		me->inBadHTML = TRUE;
+		sleep(MessageSecs);
+	    }
+
+	    /*
+	     *  Too likely to cause a crash, so we'll ignore it. - FM
+	     */
+	    return;
+	}
+
+	/*
+	 *  Check for unclosed TEXTAREA.
+	 */
+	if (me->inTEXTAREA) {
+	    if (TRACE) {
+		fprintf(stderr, "HTML: Missing TEXTAREA end tag\n");
+	    } else if (!me->inBadHTML) {
+		_statusline(BAD_HTML_USE_TRACE);
+		me->inBadHTML = TRUE;
+		sleep(MessageSecs);
+	    }
+	}
+
+	/*
+	 *  Set to know we are in a select tag.
+	 */
+	me->inSELECT = TRUE;
+
+	if (!me->text)
+	    UPDATE_STYLE;
+	if (present && present[HTML_SELECT_NAME] &&
+	    value[HTML_SELECT_NAME] && *value[HTML_SELECT_NAME])  
+	    StrAllocCopy(name, value[HTML_SELECT_NAME]);
+	else
+	    StrAllocCopy(name, "");
+	if (present && present[HTML_SELECT_MULTIPLE])  
+	    multiple=YES;
+	if (present && present[HTML_SELECT_DISABLED])  
+	    me->select_disabled = TRUE;
+	if (present && present[HTML_SELECT_SIZE] &&
+	    value[HTML_SELECT_SIZE] && *value[HTML_SELECT_SIZE]) {
+#ifdef NOTDEFINED
+	    StrAllocCopy(size, value[HTML_SELECT_SIZE]);
+#else
+	    /*
+	     *  Let the size be determined by the number of OPTIONs. - FM
+	     */
+	    if (TRACE)
+		fprintf(stderr,
+			"HTML: Ignoring SIZE=\"%s\" for SELECT.\n",
+			(char *)value[HTML_SELECT_SIZE]);
+#endif /* NOTDEFINED */
+	}
+
+	if (me->inBoldH == TRUE &&
+	    (multiple == NO || LYSelectPopups == FALSE)) {
+	    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
+	    me->inBoldH = FALSE;
+	    me->needBoldH = TRUE;
+	}
+	if (me->inUnderline == TRUE &&
+	    (multiple == NO || LYSelectPopups == FALSE)) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR);
+	    me->inUnderline = FALSE;
+	}
+
+	if ((multiple == NO && LYSelectPopups == TRUE) &&
+	    me->sp[0].tag_number == HTML_PRE &&
+	        HText_LastLineSize(me->text, FALSE) > (LYcols - 8)) {
+		/*
+		 *  Force a newline when we're using a popup in
+		 *  a PRE block and are within 7 columns from the
+		 *  right margin.  This will allow for the '['
+		 *  popup designater and help avoid a wrap in the
+		 *  underscore placeholder for the retracted popup
+		 *  entry in the HText structure. - FM
+		 */
+		HTML_put_character(me, '\n');
+		me->in_word = NO;
+	    }
+
+	LYCheckForID(me, present, value, (int)HTML_SELECT_ID);
+
+	HText_beginSelect(name, multiple, size);
+	FREE(name);
+	FREE(size);
+
+	me->first_option = TRUE;
+    } else {
+        /*
+	 *  Handle end tag.
+	 */
+	char *ptr;
+	if (!me->text)
+	    UPDATE_STYLE;
+
+	/*
+	 *  Make sure we had a select start tag.
+	 */
+	if (!me->inSELECT) {
+	    if (TRACE) {
+		fprintf(stderr, "HTML: Unmatched SELECT end tag\n");
+	    } else if (!me->inBadHTML) {
+		_statusline(BAD_HTML_USE_TRACE);
+		me->inBadHTML = TRUE;
+		sleep(MessageSecs);
+	    }
+	    return;
+	}
+
+	/*
+	 *  Set to know that we are no longer in a select tag.
+	 */
+	me->inSELECT = FALSE;
+
+	/*
+	 *  Clear the disable attribute.
+	 */
+	me->select_disabled = FALSE;
+
+	/*
+	 *  Finish the data off.
+	 */
+       	HTChunkTerminate(&me->option);
+	/*
+	 *  Finish the previous option.
+	 */
+	ptr = HText_setLastOptionValue(me->text,
+				       me->option.data,
+				       me->LastOptionValue,
+				       LAST_ORDER,
+				       me->LastOptionChecked);
+	FREE(me->LastOptionValue);
+
+	me->LastOptionChecked = FALSE;
+
+	if (HTCurSelectGroupType == F_CHECKBOX_TYPE ||
+	    LYSelectPopups == FALSE) {
+	    /*
+	     *  Start a newline after the last checkbox/button option.
+	     */
+	    LYEnsureSingleSpace(me);
+	} else {
+	    /*
+	     *  Output popup box with the default option to screen,
+	     *  but use non-breaking spaces for output.
+	     */
+	    if (ptr &&
+		me->sp[0].tag_number == HTML_PRE && strlen(ptr) > 6) {
+	        /*
+		 *  The code inadequately handles OPTION fields in PRE tags.
+		 *  We'll put up a minimum of 6 characters, and if any
+		 *  more would exceed the wrap column, we'll ignore them.
+		 */
+		for (i = 0; i < 6; i++) {
+		    if (*ptr == ' ')
+	                HText_appendCharacter(me->text, HT_NON_BREAK_SPACE); 
+		    else
+	    	        HText_appendCharacter(me->text, *ptr);
+		    ptr++;
+		}
+		HText_setIgnoreExcess(me->text, TRUE);
+	    }
+	    for (; ptr && *ptr != '\0'; ptr++) {
+		if (*ptr == ' ')
+	            HText_appendCharacter(me->text, HT_NON_BREAK_SPACE); 
+		else
+	    	    HText_appendCharacter(me->text, *ptr);
+	    }
+	    /*
+	     *  Add end option character.
+	     */
+	    HText_appendCharacter(me->text, ']');
+	    HText_setLastChar(me->text, ']');
+	    me->in_word = YES;
+	    HText_setIgnoreExcess(me->text, FALSE); 
+	}
+    	HTChunkClear(&me->option);
+
+	if (me->Underline_Level > 0 && me->inUnderline == FALSE) {
+	    HText_appendCharacter(me->text, LY_UNDERLINE_START_CHAR);
+	    me->inUnderline = TRUE;
+	}
+	if (me->needBoldH == TRUE && me->inBoldH == FALSE) {
+	    HText_appendCharacter(me->text, LY_BOLD_START_CHAR);
+	    me->inBoldH = TRUE;
+	    me->needBoldH = FALSE;
+	}
+    }
+}
+#endif /* NOTUSED_FOTEMODS */
+
 /*
 **  This function strips white characters and
 **  generally fixes up attribute values that
@@ -2183,6 +2616,8 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 	BOOL,			strip_dots)
 {
     int url_type = 0;
+    char *pound = NULL;
+    char *fragment = NULL;
 
     if (!me || !href || *href == NULL || *(*href) == '\0')
         return(url_type);
@@ -2200,7 +2635,23 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 	HTUnEscapeSome(*href, " \r\n\t");
 	convert_to_spaces(*href, TRUE);
     } else {
+        /*
+	 *  Collapse spaces in the actual URL, but just
+	 *  protect against tabs or newlines in the
+	 *  fragment, if present.  This seeks to cope
+	 *  with atrocities inflicted on the Web by
+	 *  authoring tools such as Frontpage. - FM
+	 */
+	if ((pound = strchr(*href, '#')) != NULL) {
+	    StrAllocCopy(fragment, pound);
+	    *pound = '\0';
+	    convert_to_spaces(fragment, FALSE);
+	}
         collapse_spaces(*href);
+	if (fragment != NULL) {
+	    StrAllocCat(*href, fragment);
+	    FREE(fragment);
+	}
     }
     if (*(*href) == '\0')
         return(url_type);
@@ -2245,10 +2696,10 @@ PUBLIC int LYLegitimizeHREF ARGS4(
 	char *temp = NULL, *str = "";
 
 	if (((temp = HTParse((me->inBASE ?
-			  me->base_href : me->node_anchor->address),
-			     "", PARSE_PATH + PARSE_PUNCTUATION)) == NULL) ||
-	    *temp == '\0' ||
-	    strchr(&temp[1], '/') == NULL) {
+			   me->base_href : me->node_anchor->address),
+			     "", PARSE_PATH+PARSE_PUNCTUATION)) == NULL) ||
+	    temp[0] == '\0' ||
+	    !strchr((char *)&temp[1], '/')) {
 	    FREE(temp);
 	    temp = *href;
 	    if ((me->inBASE ?
@@ -2382,8 +2833,8 @@ PUBLIC void LYCheckForID ARGS4(
 				temp,			/* Tag */
 				NULL,			/* Addresss */
 				(void *)0))) {		/* Type */
-	    HText_beginAnchor(me->text, ID_A);
-	    HText_endAnchor(me->text);
+	    HText_beginAnchor(me->text, me->inUnderline, ID_A);
+	    HText_endAnchor(me->text, 0);
 	}
 	FREE(temp);
     }
@@ -2412,8 +2863,8 @@ PUBLIC void LYHandleID ARGS2(
 				id,			/* Tag */
 				NULL,			/* Addresss */
 				(void *)0)) != NULL) {	/* Type */
-	HText_beginAnchor(me->text, ID_A);
-	HText_endAnchor(me->text);
+	HText_beginAnchor(me->text, me->inUnderline, ID_A);
+	HText_endAnchor(me->text, 0);
     }
 }
 
@@ -2456,10 +2907,12 @@ PUBLIC void LYEnsureDoubleSpace ARGS1(
     if (!me || !me->text)
         return;
 
-    if (HText_LastLineSize(me->text)) {
+    if (HText_LastLineSize(me->text, FALSE)) {
+	HText_setLastChar(me->text, ' ');  /* absorb white space */
 	HText_appendCharacter(me->text, '\r');
 	HText_appendCharacter(me->text, '\r');
-    } else if (HText_PreviousLineSize(me->text)) {
+    } else if (HText_PreviousLineSize(me->text, FALSE)) {
+	HText_setLastChar(me->text, ' ');  /* absorb white space */
 	HText_appendCharacter(me->text, '\r');
     } else if (me->List_Nesting_Level >= 0) {
 	HText_NegateLineOne(me->text);
@@ -2479,7 +2932,8 @@ PUBLIC void LYEnsureSingleSpace ARGS1(
     if (!me || !me->text)
         return;
 
-    if (HText_LastLineSize(me->text)) {
+    if (HText_LastLineSize(me->text, FALSE)) {
+	HText_setLastChar(me->text, ' ');  /* absorb white space */
 	HText_appendCharacter(me->text, '\r');
     } else if (me->List_Nesting_Level >= 0) {
 	HText_NegateLineOne(me->text);
diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h
index b6b0d892..55433d18 100644
--- a/src/LYCharUtils.h
+++ b/src/LYCharUtils.h
@@ -27,6 +27,11 @@ extern char *LYFindEndOfComment PARAMS((
 extern void LYFillLocalFileURL PARAMS((
 	char **		href,
 	char *		base));
+#ifdef EXP_CHARTRANS
+extern void LYAddMETAcharsetToFD PARAMS((
+	FILE *			fd,
+	int			disp_chndl));
+#endif /* EXP_CHARTRANS */
 
 #ifdef Lynx_HTML_Handler
 extern int OL_CONTINUE;		/* flag for whether CONTINUE is set */
@@ -41,6 +46,16 @@ extern char *LYUppercaseI_OL_String PARAMS((
 	int			seqnum));
 extern char *LYLowercaseI_OL_String PARAMS((
 	int			seqnum));
+#ifdef EXP_CHARTRANS
+#ifdef HTML_H
+extern void LYGetChartransInfo PARAMS((
+	HTStructured *		me));
+#endif
+extern void add_META_charset_to_fd PARAMS((
+    FILE *	fp,
+    int		disp_chndl));
+#endif /* EXP_CHARTRANS */
+
 extern void LYHandleMETA PARAMS((
 	HTStructured *		me,
 	CONST BOOL*	 	present,
@@ -74,13 +89,4 @@ extern BOOLEAN LYCheckForCSI PARAMS((
 	char **			url));
 #endif /* Lynx_HTML_Handler */
 
-#ifdef EXP_CHARTRANS
-#ifdef HTML_H
-extern void html_get_chartrans_info PARAMS((HTStructured * me));
-#endif
-extern void add_META_charset_to_fd PARAMS((
-    FILE *	fp,
-    int		disp_chndl));
-#endif /* EXP_CHARTRANS */
-
 #endif /* LYCHARUTILS_H */
diff --git a/src/LYCookie.c b/src/LYCookie.c
index d43a6664..008797e3 100644
--- a/src/LYCookie.c
+++ b/src/LYCookie.c
@@ -8,8 +8,13 @@
 **  Based on:
 **	http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt
 **
+**	Updated for:
+**   http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt
+**		- FM					1997-07-09
+**
 **  TO DO: (roughly in order of decreasing priority)
-      * host_matches() is only lightly tested in the Internet at large.
+      * A means to specify "always allow" and "never allow" domains via
+        a configuration file is needed.
       * Hex escaping isn't considered at all.  Any semi-colons, commas,
         or spaces actually in cookie names or values (i.e., not serving
 	as punctuation for the overall Set-Cookie value) should be hex
@@ -29,8 +34,6 @@
 	collections to bring us back down under the limits, rather than
 	actively removing cookies and/or domains based on age or frequency
 	of use.
-      * The comments in this file chould contain extracts from the -05
-        HTTP State Management draft (URL above).
       * If the a cookie has the secure flag set, we presently treat only
         SSL connections as secure.  This may need to be expanded for other
         secure communication protocols that become standarized.
@@ -52,6 +55,8 @@
 #include "LYStrings.h"
 #include "LYSystem.h"
 #include "GridText.h"
+#include "LYUtils.h"
+#include "LYCharUtils.h"
 #include "LYCookie.h"
 
 #define FREE(x) if (x) {free(x); x = NULL;}
@@ -70,24 +75,28 @@ PRIVATE HTList *cookie_list = NULL;
 PRIVATE int total_cookies = 0;
 
 struct _cookie {
-    char *lynx_id; /* Lynx cookie identifier */
+    char *lynxID;  /* Lynx cookie identifier */
     char *name;    /* Name of this cookie */
     char *value;   /* Value of this cookie */
     int version;   /* Cookie protocol version (=1) */
     char *comment; /* Comment to show to user */
+    char *commentURL; /* URL for comment to show to user */
     char *domain;  /* Domain for which this cookie is valid */
     int port;      /* Server port from which this cookie was given (usu. 80) */
+    char *PortList;/* List of ports for which cookie can be sent */
     char *path;    /* Path prefix for which this cookie is valid */
     int pathlen;   /* Length of the path */
     int flags;     /* Various flags */
-    time_t expires;   /* The time when this cookie expires */
+    time_t expires;/* The time when this cookie expires */
     BOOL quoted;   /* Was a value quoted in the Set-Cookie header? */
 };
 typedef struct _cookie cookie;
 
 #define COOKIE_FLAG_SECURE 1	   /* If set, cookie requires secure links */
-#define COOKIE_FLAG_EXPIRES_SET 2  /* If set, an expiry date was set */
-
+#define COOKIE_FLAG_DISCARD 2	   /* If set, expire at end of session */
+#define COOKIE_FLAG_EXPIRES_SET 4  /* If set, an expiry date was set */
+#define COOKIE_FLAG_DOMAIN_SET 8   /* If set, an non-default domain was set */
+#define COOKIE_FLAG_PATH_SET 16    /* If set, an non-default path was set */
 struct _HTStream 
 {
   HTStreamClass * isa;
@@ -116,12 +125,12 @@ PRIVATE void MemAllocCopy ARGS3(
 PRIVATE cookie * newCookie NOARGS
 {
     cookie *p = (cookie *)calloc(1, sizeof(cookie));
-    char lynx_id[64];
+    char lynxID[64];
 
     if (p == NULL)
         outofmem(__FILE__, "newCookie");
-    sprintf(lynx_id, "%p", p);
-    StrAllocCopy(p->lynx_id, lynx_id);
+    sprintf(lynxID, "%p", p);
+    StrAllocCopy(p->lynxID, lynxID);
     p->port = 80; 
     return p;
 }
@@ -130,12 +139,14 @@ PRIVATE void freeCookie ARGS1(
 	cookie *,	co)
 {
     if (co) {
-        FREE(co->lynx_id);
+        FREE(co->lynxID);
 	FREE(co->name); 
 	FREE(co->value);
 	FREE(co->comment);
+	FREE(co->commentURL);
 	FREE(co->domain);
 	FREE(co->path);
+	FREE(co->PortList);
 	FREE(co);
     }
 }
@@ -173,6 +184,7 @@ PRIVATE void LYCookieJar_free NOARGS
 	    if (co) {
 		HTList_removeObject(cookie_list, co);
 		freeCookie(co);
+		co = NULL;
 	    }
 	    cl = next;
 	}
@@ -185,7 +197,8 @@ PRIVATE void LYCookieJar_free NOARGS
 
 /*
 **  Compare two hostnames as specified in Section 2 of:
-**    http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-mgmt-05.txt
+**   http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt
+**	- AK & FM
 */
 PRIVATE BOOLEAN host_matches ARGS2(
 	CONST char *,	A,
@@ -213,7 +226,36 @@ PRIVATE BOOLEAN host_matches ARGS2(
 }
 
 /*
-**  Store a cookie somewhere in the domain list.
+**  Compare the current port with a port list as specified in Section 4.3 of:
+**   http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-02.txt
+**	- FM
+*/
+PRIVATE BOOLEAN port_matches ARGS2(
+	int,		port,
+	CONST char *,	list)
+{
+    char *number = (char *)list;
+
+    if (!(number && isdigit(*number)))
+        return(FALSE);
+
+    while (*number != '\0') {
+	if (atoi(number) == port) {
+	    return(TRUE);
+	}
+        while (isdigit(*number)) {
+	    number++;
+	}
+	while (*number != '\0' && !isdigit(*number)) {
+	    number++;
+	}
+    }
+
+    return(FALSE);
+}
+
+/*
+**  Store a cookie somewhere in the domain list. - AK & FM
 */
 PRIVATE void store_cookie ARGS3(
 	cookie *,	co,
@@ -226,6 +268,7 @@ PRIVATE void store_cookie ARGS3(
     int pos;
     CONST char *ptr;
     domain_entry *de = NULL;
+    BOOL Replacement = FALSE;
 
     if (co == NULL)
         return;
@@ -241,6 +284,8 @@ PRIVATE void store_cookie ARGS3(
 	    fprintf(stderr,
 	    "store_cookie: Rejecting because '%s' is not a prefix of '%s'.\n",
 		    co->path, path);
+	freeCookie(co);
+	co = NULL;
         return;
     }
     /*
@@ -256,6 +301,8 @@ PRIVATE void store_cookie ARGS3(
 		fprintf(stderr,
 			"store_cookie: Rejecting because '%s' has no dot.\n",
 			hostname);
+	    freeCookie(co);
+	    co = NULL;
 	    return;
 	}
 
@@ -269,6 +316,8 @@ PRIVATE void store_cookie ARGS3(
 		fprintf(stderr,
 			"store_cookie: Rejecting domain '%s'.\n",
 			co->domain);
+	    freeCookie(co);
+	    co = NULL;
 	    return;
 	}
 	ptr = strchr((co->domain + 1), '.');
@@ -277,6 +326,8 @@ PRIVATE void store_cookie ARGS3(
 		fprintf(stderr,
 			"store_cookie: Rejecting domain '%s'.\n",
 			co->domain);
+	    freeCookie(co);
+	    co = NULL;
 	    return;
 	}
       
@@ -289,6 +340,8 @@ PRIVATE void store_cookie ARGS3(
 		fprintf(stderr,
 			"store_cookie: Rejecting domain '%s' for host '%s'.\n",
 			co->domain, hostname);
+	    freeCookie(co);
+	    co = NULL;
 	    return;
 	}
 
@@ -303,6 +356,8 @@ PRIVATE void store_cookie ARGS3(
 		fprintf(stderr,
 			"store_cookie: Rejecting domain '%s' for host '%s'.\n",
 			co->domain, hostname);
+	    freeCookie(co);
+	    co = NULL;
 	    return;
 	}
     }
@@ -369,7 +424,7 @@ PRIVATE void store_cookie ARGS3(
 	/*
 	 *  Check if this cookie matches the one we're inserting.
 	 */
-	} else if ((c2) && (co->port == c2->port) && 
+	} else if ((c2) &&
 		   !strcmp(co->domain, c2->domain) &&
 		   !strcmp(co->path, c2->path) &&
 		   !strcmp(co->name, c2->name)) {
@@ -377,6 +432,7 @@ PRIVATE void store_cookie ARGS3(
 	    freeCookie(c2);
 	    c2 = NULL;
 	    total_cookies--;
+	    Replacement = TRUE;
 
 	} else if ((c2) && (c2->pathlen) > (co->pathlen)) {
 	    pos++;
@@ -412,6 +468,15 @@ PRIVATE void store_cookie ARGS3(
 	co = NULL;
 
     /*
+     *  If it's a replacement for a cookie that had not expired,
+     *  and never allow has not been set, add it again without
+     *  confirmation. - FM
+     */
+    } else if ((Replacement == TRUE && de) && de->bv != REJECT_ALWAYS) {
+	HTList_insertObjectAt(cookie_list, co, pos);
+	total_cookies++;
+
+    /*
      *  Get confirmation if we need it, and add cookie
      *  if confirmed or 'allow' is set to always. - FM
      */
@@ -425,6 +490,10 @@ PRIVATE void store_cookie ARGS3(
     }
 }
 
+/*
+**  Scan a domain's cookie_list for any cookies we should
+**  include in a Cookie: request header. - AK & FM
+*/
 PRIVATE char * scan_cookie_sublist ARGS6(
 	CONST char *,	hostname,
 	CONST char *,	path,
@@ -437,7 +506,10 @@ PRIVATE char * scan_cookie_sublist ARGS6(
     cookie *co;
     time_t now = time(NULL);
     BOOL Quoted = FALSE;
+    int len = 0;
+    char crlftab[8];
 
+    sprintf(crlftab, "%c%c%c", CR, LF, '\t');
     while (hl) {
 	co = (cookie *)hl->object;
 	next = hl->next;
@@ -471,7 +543,7 @@ PRIVATE char * scan_cookie_sublist ARGS6(
 	 *  Check if we have a unexpired match, and handle if we do.
 	 */
 	if (((co != NULL) &&
-	     co->port == port && host_matches(hostname, co->domain)) && 
+	     host_matches(hostname, co->domain)) && 
 	    (co->pathlen == 0 || !strncmp(path, co->path, co->pathlen))) {
 	    /*
 	     *  Skip if the secure flag is set and we don't have
@@ -484,6 +556,15 @@ PRIVATE char * scan_cookie_sublist ARGS6(
 	    }
 
 	    /*
+	     *  Skip if we have a port list and the
+	     *  current port is not listed. - FM
+	     */
+	    if (co->PortList && !port_matches(port, co->PortList)) {
+	        hl = next;
+		continue;
+	    }
+
+	    /*
 	     *  Start or append to the request header.
 	     */
 	    if (header == NULL) {
@@ -494,64 +575,64 @@ PRIVATE char * scan_cookie_sublist ARGS6(
 		     *  first cookie.
 		     */
 		    char version[16];
-		    sprintf(version, "$Version=%i; ", co->version);
+		    sprintf(version, "$Version=\"%i\"; ", co->version);
 		    StrAllocCopy(header, version);
+		    len += strlen(header);
 		}
 	    } else {
 		/*
-		 *  There's already cookie data there,
-		 *  so add a separator.
+		 *  There's already cookie data there, so add
+		 *  a separator (always use a semi-colon for
+		 *  "backward compatibility"). - FM
 		 */
 		StrAllocCat(header, "; ");
+		/*
+		 *  Check if we should fold the header. - FM
+		 */
+		if (len > 800) {
+		    StrAllocCat(header, crlftab);
+		    len = 0;
+		}
 	    }
 	    /*
 	     *  Include the cookie name=value pair.
 	     */
 	    StrAllocCat(header, co->name);
 	    StrAllocCat(header, "=");
-	    if (co->quoted && strchr(co->value, ' ')) {
+	    if (co->quoted) {
 	    	StrAllocCat(header, "\"");
-		Quoted = TRUE;
+		len++;
 	    }
 	    StrAllocCat(header, co->value);
-	    if (Quoted) {
+	    if (co->quoted) {
 	    	StrAllocCat(header, "\"");
-		Quoted = FALSE;
+		len++;
 	    }
+ 	    len += (strlen(co->name) + strlen(co->value) + 1);
 	    /*
 	     *  For Version 1 (or greater) cookies, add
-	     *  attributes for the cookie. - FM
+	     *  $PATH and/or $DOMAIN attributes for the
+	     *  cookie if they were specified via a server
+	     *  reply header. - FM
 	     */
 	    if (co->version > 0) {
-		if (co->path) {
+		if (co->path && (co->flags & COOKIE_FLAG_PATH_SET)) {
 		    /*
 		     *  Append the path attribute. - FM
 		     */
-		    StrAllocCat(header, "; $Path=");
-		    if (co->quoted && strchr(co->path, ' ')) {
-		        StrAllocCat(header, "\"");
-			Quoted = TRUE;
-		    }
+		    StrAllocCat(header, "; $Path=\"");
 		    StrAllocCat(header, co->path);
-		    if (Quoted) {
-		        StrAllocCat(header, "\"");
-			Quoted = FALSE;
-		    }
+		    StrAllocCat(header, "\"");
+		    len != (strlen(co->path) + 8);
 		}
-		if (co->domain) {
+		if (co->domain && (co->flags & COOKIE_FLAG_DOMAIN_SET)) {
 		    /*
 		     *  Append the domain attribute. - FM
 		     */
-		    StrAllocCat(header, "; $Domain=");
-		    if (co->quoted && strchr(co->domain, ' ')) {
-		        StrAllocCat(header, "\"");
-			Quoted = TRUE;
-		    }
+		    StrAllocCat(header, "; $Domain=\"");
 		    StrAllocCat(header, co->domain);
-		    if (Quoted) {
-		        StrAllocCat(header, "\"");
-			Quoted = FALSE;
-		    }
+		    StrAllocCat(header, "\"");
+		    len != (strlen(co->domain) + 10);
 		}
 	    }
 	}
@@ -561,63 +642,60 @@ PRIVATE char * scan_cookie_sublist ARGS6(
     return(header);
 }
 
-PUBLIC void LYSetCookie ARGS2(
-	CONST char *,	header,
-	CONST char *,	address)
+/*
+**  Process potentially concatenated Set-Cookie2 and/or Set-Cookie
+**  headers. - FM
+*/  
+PRIVATE void LYProcessSetCookies ARGS6(
+	CONST char *,	SetCookie,
+	CONST char *,	SetCookie2,
+	CONST char *,	address,
+	char *,		hostname,
+	char *,		path,
+	int,		port)
 {
+    char *header = NULL;
     CONST char *p, *attr_start, *attr_end, *value_start, *value_end;
-    char *hostname = NULL, *path = NULL, *ptr;
-    cookie *cur_cookie = NULL;
-    int port = 80;
-    int length = 0;
+    HTList *CombinedCookies = NULL, *cl = NULL;
+    cookie *cur_cookie = NULL, *co = NULL;
+    int length = 0, url_type = 0;
+    int NumCookies = 0;
+    BOOL MaxAgeAttrSet = FALSE;
     BOOL Quoted = FALSE;
 
-    /*
-     *  Get the hostname, port and path of the address, and report
-     *  the Set-Cookie request if trace mode is on, but set the cookie
-     *  only if LYSetCookies is TRUE. - FM
-     */
-    if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) &&
-	(ptr = strchr(hostname, ':')) != NULL)  {
+    if (!(SetCookie && *SetCookie) &&
+	!(SetCookie2 && *SetCookie2)) {
 	/*
-	 *  Replace default port number.
+	 *  Yuk!  Garbage in, so nothing out. - FM
 	 */
-	*ptr = '\0';
-	ptr++;
-        port = atoi(ptr);
-    } else if (!strncasecomp(address, "https:", 6)) {
-        port = 443;
-    } 
-    if (((path = HTParse(address, "",
-    			 PARSE_PATH|PARSE_PUNCTUATION)) != NULL) &&
-	(ptr = strrchr(path, '/')) != NULL) {
-	if (ptr == path)
-	    *(ptr+1) = '\0';	/* Leave a single '/' alone */
-	else
-	    *ptr = '\0'; 
-      }
-    if (TRACE) {
-	fprintf(stderr,
-    "LYSetCookie called with host '%s', path '%s',\n    and header '%s'%s\n",
-		(hostname ? hostname : ""),
-		(path ? path : ""),
-		(header ? header : ""),
-	     (LYSetCookies ? "" : "\n    Ignoring this Set-Cookie request."));
-    }
-    if (LYSetCookies == FALSE) {
-	FREE(hostname);
-	FREE(path);
 	return;
     }
 
     /*
-     *  Process the Set-Cookie header value.
+     *  If we have both Set-Cookie and Set-Cookie2 headers,
+     *  and must combine them because the Set-Cookie2 headers
+     *  are not required to have complete cookies if Set-Cookie
+     *  headers are present.  So set up a list for the cookies
+     *  we process out of the header(s).  Note that if more than
+     *  one instance of a valued attribute for the same cookie
+     *  is encountered, the value for the first instance is
+     *  retained, with preference to that in a Set-Cookie2
+     *  header.  We only accept up to 50 cookies from either
+     *  header, and only if a cookie's values do not exceed
+     *  the 4096 byte limit on overall size. - FM
+     */
+    CombinedCookies = HTList_new();
+
+    /*
+     *  First process the Set-Cookie2 header, if present, adding
+     *  each cookie to the CombinedCoookies list. - FM
      */
-    p = (char *)header;
-    while (length <= 4096 && *p) {
+    p = (SetCookie2 ? SetCookie2 : "");
+    while (NumCookies <= 50 && *p) {
 	attr_start = attr_end = value_start = value_end = NULL;
-#define SKIP_SPACES while (*p != '\0' && isspace((unsigned char)*p)) p++;
-        SKIP_SPACES;
+	while (*p != '\0' && isspace((unsigned char)*p)) {
+	    p++;
+	}
 	/*
 	 *  Get the attribute name.
 	 */
@@ -626,7 +704,9 @@ PUBLIC void LYSetCookie ARGS2(
 	       *p != '=' && *p != ';' && *p != ',')
 	    p++;
 	attr_end = p;
-	SKIP_SPACES;
+	while (*p != '\0' && isspace((unsigned char)*p)) {
+	    p++;
+	}
       
         /*
 	 *  Check for an '=' delimiter, or an 'expires' name followed
@@ -639,8 +719,12 @@ PUBLIC void LYSetCookie ARGS2(
 	    /*
 	     *  Get the value string.
 	     */
-	    p++;
-	    SKIP_SPACES;
+	    if (*p == '=') {
+		p++;
+	    }
+	    while (*p != '\0' && isspace((unsigned char)*p)) {
+		p++;
+	    }
 	    /*
 	     *  Hack alert!  We must handle Netscape-style cookies with
 	     *		"Expires=Mon, 01-Jan-96 13:45:35 GMT" or
@@ -651,11 +735,28 @@ PUBLIC void LYSetCookie ARGS2(
 	     *  looks for a space after the 5th space separator or dash to
 	     *  mark the end of the value. - FM
 	     */
-	    if ((attr_end - attr_start) == 7 && 
+	    if ((attr_end - attr_start) == 7 &&
 		!strncasecomp(attr_start, "Expires", 7)) {
 		int spaces = 6;
 		value_start = p;
-		while (*p != '\0' && *p != ';' && spaces) {
+		if (isdigit((unsigned char)*p)) {
+		    /*
+		     *  No alphabetic day field. - FM
+		     */
+		    spaces--;
+		} else {
+		    /*
+		     *  Skip the alphabetic day field. - FM
+		     */
+		    while (*p != '\0' && isalpha((unsigned char)*p)) {
+			p++;
+		    }
+		    while (*p == ',' || isspace((unsigned char)*p)) {
+			p++;
+		    }
+		    spaces--;
+		}
+		while (*p != '\0' && *p != ';' && *p != ',' && spaces) {
 		    p++;
 		    if (isspace((unsigned char)*p)) {
 		        while (isspace((unsigned char)*(p + 1)))
@@ -666,6 +767,62 @@ PUBLIC void LYSetCookie ARGS2(
 		    }
 		}
 	        value_end = p;
+	    /*
+	     *  Hack Alert!  The port attribute can take a
+	     *  comma separated list of numbers as a value,
+	     *  and such values should be quoted, but if
+	     *  not, make sure we don't treat a number in
+	     *  the list as the start of a new cookie. - FM
+	     */
+	    } else if ((attr_end - attr_start) == 4 &&
+		       !strncasecomp(attr_start, "port", 4) &&
+		       isdigit((unsigned char)*p)) {
+		/*
+		 *  The value starts as an unquoted number.
+		 */
+		CONST char *cp, *cp1;
+		value_start = p;
+		while (1) {
+		    while (isdigit((unsigned char)*p))
+			p++;
+		    value_end = p;
+		    while (isspace((unsigned char)*p))
+			p++;
+		    if (*p == '\0' || *p == ';')
+			break;
+		    if (*p == ',') {
+			cp = (p + 1);
+			while (*cp != '\0' && isspace((unsigned char)*cp))
+			    cp++;
+			if (*cp != '\0' && isdigit((unsigned char)*cp)) {
+			    cp1 = cp;
+			    while (isdigit((unsigned char)*cp1))
+				cp1++;
+			    while (*cp != '\0' && isspace((unsigned char)*cp))
+				cp1++;
+			    if (*cp1 == '\0' || *cp1 == ',' || *cp1 == ';') {
+				p = cp;
+				continue;
+			    }
+			}
+		    }
+		    while (*p != '\0' && *p != ';' && *p != ',')
+			p++;
+		    value_end = p;
+		    /*
+		     *  Trim trailing spaces.
+		     */
+		    if ((value_end > value_start) &&
+			isspace((unsigned char)*(value_end - 1))) {
+			value_end--;
+			while ((value_end > (value_start + 1)) &&
+			       isspace((unsigned char)*value_end) &&
+			       isspace((unsigned char)*(value_end - 1))) {
+			    value_end--;
+			}
+		    }
+		    break;
+		}
 	    } else if (*p == '"') {
 	        /*
 		 *  It's a quoted string.
@@ -677,10 +834,9 @@ PUBLIC void LYSetCookie ARGS2(
 		value_end = p;
 		if (*p == '"')
 		    p++;
-		Quoted = TRUE;
 	    } else {
 		/*
-		 *   Otherwise, it's an unquoted string.
+		 *  Otherwise, it's an unquoted string.
 		 */
 		value_start = p;
 		while (*p != '\0' && *p != ';' && *p != ',')
@@ -718,42 +874,161 @@ PUBLIC void LYSetCookie ARGS2(
 	    if (value_end > value_start) {
 		int value_len = (value_end - value_start);
 
-		length += value_len;
-		if (length > 4096)
-		    break;
+		if (value_len > 4096) {
+		    value_len = 4096;
+		}
 		value = (char *)calloc(1, value_len + 1);
 		if (value == NULL)
-		    outofmem(__FILE__, "LYSetCookie");
+		    outofmem(__FILE__, "LYProcessSetCookies");
 		LYstrncpy(value, (char *)value_start, value_len);
 	    }
 	    if (len == 6 && !strncasecomp(attr_start, "secure", 6)) {
-		known_attr = YES;
-		if (cur_cookie != NULL)
-		    cur_cookie->flags |= COOKIE_FLAG_SECURE;
+	        if (value == NULL) {
+		    known_attr = YES;
+		    if (cur_cookie != NULL) {
+			cur_cookie->flags |= COOKIE_FLAG_SECURE;
+		    }
+		} else {
+		    /*
+		     *  If secure has a value, assume someone
+		     *  misused it as cookie name. - FM
+		     */
+		    known_attr = NO;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "discard", 7)) {
+	        if (value == NULL) {
+		    known_attr = YES;
+		    if (cur_cookie != NULL) {
+		        cur_cookie->flags |= COOKIE_FLAG_DISCARD;
+		    }
+		} else {
+		    /*
+		     *  If discard has a value, assume someone
+		     *  used it as a cookie name. - FM
+		     */
+		    known_attr = NO;
+		}
 	    } else if (len == 7 && !strncasecomp(attr_start, "comment", 7)) {
 		known_attr = YES;
-		if (cur_cookie != NULL && value)
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat comment. - FM
+		     */
+		    cur_cookie->comment == NULL) {
 		    StrAllocCopy(cur_cookie->comment, value);
+		    length += strlen(cur_cookie->comment);
+		}
+	    } else if (len == 10 && !strncasecomp(attr_start,
+	    					  "commentURL", 10)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat commentURL. - FM
+		     */
+		    cur_cookie->commentURL == NULL) {
+		    /*
+		     *  We should get only absolute URLs as
+		     *  values, but will resolve versus the
+		     *  request's URL just in case. - FM
+		     */
+		    cur_cookie->commentURL = HTParse(value,
+						     address,
+						     PARSE_ALL);
+		    /*
+		     *  Accept only URLs for servers. - FM
+		     */
+		    if ((url_type = is_url(cur_cookie->commentURL)) &&
+		        (url_type == HTTP_URL_TYPE ||
+		    	 url_type == HTTPS_URL_TYPE ||
+			 url_type == FTP_URL_TYPE ||
+			 url_type == GOPHER_URL_TYPE ||
+			 url_type == HTML_GOPHER_URL_TYPE ||
+			 url_type == INDEX_GOPHER_URL_TYPE ||
+			 url_type == NEWS_URL_TYPE ||
+			 url_type == NNTP_URL_TYPE ||
+			 url_type == SNEWS_URL_TYPE ||
+			 url_type == WAIS_URL_TYPE ||
+			 url_type == CSO_URL_TYPE ||
+			 url_type == FINGER_URL_TYPE)) {
+		        length += strlen(cur_cookie->commentURL);
+		    } else {
+			FREE(cur_cookie->commentURL);
+		    }
+		}
 	    } else if (len == 6 && !strncasecomp(attr_start, "domain", 6)) {
 		known_attr = YES;
-		if (cur_cookie != NULL && value)
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat domain. - FM
+		     */
+		    !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
+		    length -= strlen(cur_cookie->domain);
 		    StrAllocCopy(cur_cookie->domain, value);
+		    length += strlen(cur_cookie->domain);
+		    cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET;
+		}
 	    } else if (len == 4 && !strncasecomp(attr_start, "path", 4)) {
 		known_attr = YES;
-		if (cur_cookie != NULL && value) {
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat path. - FM
+		     */
+		    !(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
+		    length -= strlen(cur_cookie->path);
 		    StrAllocCopy(cur_cookie->path, value);
-		    cur_cookie->pathlen = strlen(cur_cookie->path);
+		    length += (cur_cookie->pathlen = strlen(cur_cookie->path));
+		    cur_cookie->flags |= COOKIE_FLAG_PATH_SET;
+		}
+	    } else if (len == 4 && !strncasecomp(attr_start, "port", 4)) {
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat port. - FM
+		     */
+		    cur_cookie->PortList == NULL) {
+		    char *cp = value;
+		    while ((*cp != '\0') &&
+			   (isdigit((unsigned char)*cp) ||
+			    *cp == ',' || *cp == ' ')) {
+			cp++;
+		    }
+		    if (*cp == '\0') {
+			StrAllocCopy(cur_cookie->PortList, value);
+			length += strlen(cur_cookie->PortList);
+			known_attr = YES;
+		    } else {
+			known_attr = NO;
+		    }
+		} else if (cur_cookie != NULL) {
+		    /*
+		     *  Don't process a repeat port. - FM
+		     */
+		    if (cur_cookie->PortList == NULL) {
+			char temp[256];
+			sprintf(temp, "%d", port);
+			StrAllocCopy(cur_cookie->PortList, temp);
+			length += strlen(cur_cookie->PortList);
+		    }
+		    known_attr = YES;
 		}
 	    } else if (len == 7 && !strncasecomp(attr_start, "version", 7)) {
 		known_attr = YES;
-		if (cur_cookie != NULL && value) {
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat version. - FM
+		     */
+		    cur_cookie->version < 1) {
 		    int temp = strtol(value, NULL, 10);
-		    if (errno != -ERANGE)
+		    if (errno != -ERANGE) {
 			cur_cookie->version = temp;
+		    }
 		}
 	    } else if (len == 7 && !strncasecomp(attr_start, "max-age", 7)) {
 		known_attr = YES;
-		if (cur_cookie != NULL && value) {
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat max-age. - FM
+		     */
+		    !MaxAgeAttrSet) {
 		    int temp = strtol(value, NULL, 10);
 		    cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
 		    if (errno == -ERANGE) {
@@ -762,50 +1037,478 @@ PUBLIC void LYSetCookie ARGS2(
 			cur_cookie->expires = (time(NULL) + temp);
 			if (TRACE)
 			    fprintf(stderr,
-			    	    "LYSetCooke: expires %ld, %s",
+			    	    "LYSetCookie: expires %ld, %s",
 				    (long) cur_cookie->expires,
 				    ctime(&cur_cookie->expires));
 		    }
+		    MaxAgeAttrSet = TRUE;
 		}
 	    } else if (len == 7 && !strncasecomp(attr_start, "expires", 7)) {
 	    	/*
-		 *  Convert an 'expires' attribute value for Version 0
-		 *  cookies, or for Version 1 if we haven't received a
-		 *  'max-age', to the equivalent of a Version 1 (or greater)
-		 *  'max-age' value added to 'time(NULL)'.  Note that
-		 *  'expires' should not be used in Version 1 cookies,
-		 *  but, as explained below, it might be used for "backward
-		 *  compatibility", and, in turn, ill-informed people
-		 *  surely would start using it instead of, rather than
-		 *  in addition to, 'max-age'. - FM
+		 *  Convert an 'expires' attribute value if we haven't
+		 *  received a 'max-age'.  Note that 'expires' should not
+		 *  be used in Version 1 cookies, but it might be used for
+		 *  "backward compatibility", and, in turn, ill-informed
+		 *  people surely would start using it instead of, rather
+		 *  than in addition to, 'max-age'. - FM
 		 */
-		if (((cur_cookie) && cur_cookie->version < 1) ||
-		    ((cur_cookie) &&
-		     !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET))) {
+		known_attr = YES;
+		if ((cur_cookie != NULL && !MaxAgeAttrSet) &&
+		     !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) {
 		    known_attr = YES;
 		    if (value) {
 			cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
-		        cur_cookie->expires = LYmktime(value);
+		        cur_cookie->expires = LYmktime(value, FALSE);
 			if (cur_cookie->expires > 0) {
 			    if (TRACE)
 				fprintf(stderr,
-					"LYSetCooke: expires %ld, %s",
+					"LYSetCookie: expires %ld, %s",
 					(long) cur_cookie->expires,
 					ctime(&cur_cookie->expires));
 			}
 		    }
 		}
+	    }
+
+	    /*
+	     *  If none of the above comparisions succeeded, and we have
+	     *  a value, then we have an unknown pair of the form 'foo=bar',
+	     *  which means it's time to create a new cookie.  If we don't
+	     *  have a non-zero-length value, assume it's an error or a
+	     *  new, unknown attribute which doesn't take a value, and
+	     *  ignore it. - FM
+	     */
+	    if (!known_attr && value_end > value_start) {
+		/*
+		 *  If we've started a cookie, and it's not too big,
+		 *  save it in the CombinedCookies list. - FM
+		 */
+		if (length <= 4096 && cur_cookie != NULL) {
+		    /*
+		     *  Assume version 1 if not set to that or higher. - FM
+		     */
+		    if (cur_cookie->version < 1) {
+			cur_cookie->version = 1;
+		    }
+		    HTList_appendObject(CombinedCookies, cur_cookie);
+		}
+		/*
+		 *  Start a new cookie. - FM
+		 */
+		cur_cookie = newCookie();
+		length = 0;
+		NumCookies++;
+		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
+		length += strlen(cur_cookie->name);
+		MemAllocCopy(&(cur_cookie->value), value_start, value_end);
+		length += strlen(cur_cookie->value);
+		StrAllocCopy(cur_cookie->domain, hostname);
+		length += strlen(cur_cookie->domain);
+		StrAllocCopy(cur_cookie->path, path);
+		length += (cur_cookie->pathlen = strlen(cur_cookie->path));
+		cur_cookie->port = port;
+		MaxAgeAttrSet = FALSE;
+		cur_cookie->quoted = TRUE;
+	    }
+	    FREE(value);
+	}
+    }
+
+    /*
+     *  Add any final SetCookie2 cookie to the CombinedCookie list
+     *  if we are within the length limit. - FM
+     */
+    if (NumCookies <= 50 && length <= 4096 && cur_cookie != NULL) {
+	if (cur_cookie->version < 1) {
+	    cur_cookie->version = 1;
+	}
+	HTList_appendObject(CombinedCookies, cur_cookie);
+    } else if (cur_cookie != NULL) {
+	if (TRACE) {
+	    fprintf(stderr,
+	 "LYProcessSetCookies: Rejecting Set-Cookie2: %s=%s\n",
+		    (cur_cookie->name ? cur_cookie->name : "[no name]"),
+		    (cur_cookie->value ? cur_cookie->value : "[no value]"));
+	    fprintf(stderr,
+	 "                     due to excessive %s%s%s\n",
+		    (length > 4096 ? "length" : ""),
+		    (length > 4096 && NumCookies > 50 ? " and " : ""),
+		    (NumCookies > 50 ? "number!\n" : "!\n"));
+	}
+        freeCookie(cur_cookie);
+	cur_cookie = NULL;
+    }
+
+    /*
+     *  Now process the Set-Cookie header, if present, checking the
+     *  CombinedCookies list for a corresponding cookie and supplementing
+     *  that if one is present, otherwise, adding the new cookie. - FM
+     */
+    length = 0;
+    NumCookies = 0;
+    cur_cookie = NULL;
+    p = (SetCookie ? SetCookie : "");
+    while (NumCookies <= 50 && *p) {
+	attr_start = attr_end = value_start = value_end = NULL;
+	while (*p != '\0' && isspace((unsigned char)*p)) {
+	    p++;
+	}
+	/*
+	 *  Get the attribute name.
+	 */
+	attr_start = p;
+	while (*p != '\0' && !isspace((unsigned char)*p) &&
+	       *p != '=' && *p != ';' && *p != ',')
+	    p++;
+	attr_end = p;
+	while (*p != '\0' && isspace((unsigned char)*p)) {
+	    p++;
+	}
+      
+        /*
+	 *  Check for an '=' delimiter, or an 'expires' name followed
+	 *  by white, since Netscape's bogus parser doesn't require
+	 *  an '=' delimiter, and 'expires' attributes are being
+	 *  encountered without them. - FM
+	 */
+	if (*p == '=' ||
+	     !strncasecomp(attr_start, "Expires", 7)) {
+	    /*
+	     *  Get the value string.
+	     */
+	    if (*p == '=') {
+		p++;
+	    }
+	    while (*p != '\0' && isspace((unsigned char)*p)) {
+		p++;
+	    }
+	    /*
+	     *  Hack alert!  We must handle Netscape-style cookies with
+	     *		"Expires=Mon, 01-Jan-96 13:45:35 GMT" or
+	     *		"Expires=Mon,  1 Jan 1996 13:45:35 GMT".
+	     *  No quotes, but there are spaces.  Argh... 
+	     *  Anyway, we know it will have at least 3 space separators
+	     *  within it, and two dashes or two more spaces, so this code
+	     *  looks for a space after the 5th space separator or dash to
+	     *  mark the end of the value. - FM
+	     */
+	    if ((attr_end - attr_start) == 7 && 
+		!strncasecomp(attr_start, "Expires", 7)) {
+		int spaces = 6;
+		value_start = p;
+		if (isdigit((unsigned char)*p)) {
+		    /*
+		     *  No alphabetic day field. - FM
+		     */
+		    spaces--;
+		} else {
+		    /*
+		     *  Skip the alphabetic day field. - FM
+		     */
+		    while (*p != '\0' && isalpha((unsigned char)*p)) {
+			p++;
+		    }
+		    while (*p == ',' || isspace((unsigned char)*p)) {
+			p++;
+		    }
+		    spaces--;
+		}
+		while (*p != '\0' && *p != ';' && *p != ',' && spaces) {
+		    p++;
+		    if (isspace((unsigned char)*p)) {
+		        while (isspace((unsigned char)*(p + 1)))
+			    p++;
+		        spaces--;
+		    } else if (*p == '-') {
+		        spaces--;
+		    }
+		}
+	        value_end = p;
+	    /*
+	     *  Hack Alert!  The port attribute can take a
+	     *  comma separated list of numbers as a value,
+	     *  and such values should be quoted, but if
+	     *  not, make sure we don't treat a number in
+	     *  the list as the start of a new cookie. - FM
+	     */
+	    } else if ((attr_end - attr_start) == 4 &&
+		       !strncasecomp(attr_start, "port", 4) &&
+		       isdigit((unsigned char)*p)) {
 		/*
-		 *  If it's a version 1 (or greater) cookie, then you
-		 *  really can set a cookie named 'expires', so we 
-		 *  perhaps shouldn't set known_attr.  However, an
-		 *  -06 draft, which hopefully will be shot down as
-		 *  bogus, suggests adding (invalidly) 'expires'
-		 *  headers for "backward compatibility".  So, we'll
-		 *  set known-attr, to ignore it, and hope it works
-		 *  out. - FM
+		 *  The value starts as an unquoted number.
+		 */
+		CONST char *cp, *cp1;
+		value_start = p;
+		while (1) {
+		    while (isdigit((unsigned char)*p))
+			p++;
+		    value_end = p;
+		    while (isspace((unsigned char)*p))
+			p++;
+		    if (*p == '\0' || *p == ';')
+			break;
+		    if (*p == ',') {
+			cp = (p + 1);
+			while (*cp != '\0' && isspace((unsigned char)*cp))
+			    cp++;
+			if (*cp != '\0' && isdigit((unsigned char)*cp)) {
+			    cp1 = cp;
+			    while (isdigit((unsigned char)*cp1))
+				cp1++;
+			    while (*cp != '\0' && isspace((unsigned char)*cp))
+				cp1++;
+			    if (*cp1 == '\0' || *cp1 == ',' || *cp1 == ';') {
+				p = cp;
+				continue;
+			    }
+			}
+		    }
+		    while (*p != '\0' && *p != ';' && *p != ',')
+			p++;
+		    value_end = p;
+		    /*
+		     *  Trim trailing spaces.
+		     */
+		    if ((value_end > value_start) &&
+			isspace((unsigned char)*(value_end - 1))) {
+			value_end--;
+			while ((value_end > (value_start + 1)) &&
+			       isspace((unsigned char)*value_end) &&
+			       isspace((unsigned char)*(value_end - 1))) {
+			    value_end--;
+			}
+		    }
+		    break;
+		}
+	    } else if (*p == '"') {
+	        /*
+		 *  It's a quoted string.
 		 */
+		p++;
+		value_start = p;
+		while (*p != '\0' && *p != '"')
+		    p++;
+		value_end = p;
+		if (*p == '"')
+		    p++;
+		Quoted = TRUE;
+	    } else {
+		/*
+		 *  Otherwise, it's an unquoted string.
+		 */
+		value_start = p;
+		while (*p != '\0' && *p != ';' && *p != ',')
+		    p++;
+		value_end = p;
+		/*
+		 *  Trim trailing spaces.
+		 */
+		if ((value_end > value_start) &&
+		    isspace((unsigned char)*(value_end - 1))) {
+		    value_end--;
+		    while ((value_end > (value_start + 1)) &&
+		    	   isspace((unsigned char)*value_end) &&
+			   isspace((unsigned char)*(value_end - 1))) {
+		        value_end--;
+		    }
+		}
+	    }
+	}
+
+	/*
+	 *  Check for a separator character, and skip it.
+	 */
+	if (*p == ';' || *p == ',')
+	    p++;
+
+	/*
+	 *  Now, we can handle this attribute/value pair.
+	 */
+	if (attr_end > attr_start) {
+	    int len = (attr_end - attr_start);
+	    BOOLEAN known_attr = NO;
+	    char *value = NULL;
+
+	    if (value_end > value_start) {
+		int value_len = (value_end - value_start);
+
+		if (value_len > 4096) {
+		    value_len = 4096;
+		}
+		value = (char *)calloc(1, value_len + 1);
+		if (value == NULL)
+		    outofmem(__FILE__, "LYProcessSetCookie");
+		LYstrncpy(value, (char *)value_start, value_len);
+	    }
+	    if (len == 6 && !strncasecomp(attr_start, "secure", 6)) {
+	        if (value == NULL) {
+		    known_attr = YES;
+		    if (cur_cookie != NULL) {
+			cur_cookie->flags |= COOKIE_FLAG_SECURE;
+		    }
+		} else {
+		    /*
+		     *  If secure has a value, assume someone
+		     *  misused it as cookie name. - FM
+		     */
+		    known_attr = NO;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "discard", 7)) {
+	        if (value == NULL) {
+		    known_attr = YES;
+		    if (cur_cookie != NULL) {
+		        cur_cookie->flags |= COOKIE_FLAG_DISCARD;
+		    }
+		} else {
+		    /*
+		     *  If discard has a value, assume someone
+		     *  used it as a cookie name. - FM
+		     */
+		    known_attr = NO;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "comment", 7)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat comment. - FM
+		     */
+		    cur_cookie->comment == NULL) {
+		    StrAllocCopy(cur_cookie->comment, value);
+		    length += strlen(cur_cookie->comment);
+		}
+	    } else if (len == 10 && !strncasecomp(attr_start,
+	    					  "commentURL", 10)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat commentURL. - FM
+		     */
+		    cur_cookie->commentURL == NULL) {
+		    /*
+		     *  We should get only absolute URLs as
+		     *  values, but will resolve versus the
+		     *  request's URL just in case. - FM
+		     */
+		    cur_cookie->commentURL = HTParse(value,
+						     address,
+						     PARSE_ALL);
+		    /*
+		     *  Accept only URLs for servers. - FM
+		     */
+		    if ((url_type = is_url(cur_cookie->commentURL)) &&
+		        (url_type == HTTP_URL_TYPE ||
+		    	 url_type == HTTPS_URL_TYPE ||
+			 url_type == FTP_URL_TYPE ||
+			 url_type == GOPHER_URL_TYPE ||
+			 url_type == HTML_GOPHER_URL_TYPE ||
+			 url_type == INDEX_GOPHER_URL_TYPE ||
+			 url_type == NEWS_URL_TYPE ||
+			 url_type == NNTP_URL_TYPE ||
+			 url_type == SNEWS_URL_TYPE ||
+			 url_type == WAIS_URL_TYPE ||
+			 url_type == CSO_URL_TYPE ||
+			 url_type == FINGER_URL_TYPE)) {
+		        length += strlen(cur_cookie->commentURL);
+		    } else {
+			FREE(cur_cookie->commentURL);
+		    }
+		}
+	    } else if (len == 6 && !strncasecomp(attr_start, "domain", 6)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat domain. - FM
+		     */
+		    !(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
+		    length -= strlen(cur_cookie->domain);
+		    StrAllocCopy(cur_cookie->domain, value);
+		    length += strlen(cur_cookie->domain);
+		    cur_cookie->flags |= COOKIE_FLAG_DOMAIN_SET;
+		}
+	    } else if (len == 4 && !strncasecomp(attr_start, "path", 4)) {
 		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat path. - FM
+		     */
+		    !(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
+		    length -= strlen(cur_cookie->path);
+		    StrAllocCopy(cur_cookie->path, value);
+		    length += (cur_cookie->pathlen = strlen(cur_cookie->path));
+		    cur_cookie->flags |= COOKIE_FLAG_PATH_SET;
+		}
+	    } else if (len == 4 && !strncasecomp(attr_start, "port", 4)) {
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat port. - FM
+		     */
+		    cur_cookie->PortList == NULL) {
+		    char *cp = value;
+		    while ((*cp != '\0') &&
+			   (isdigit((unsigned char)*cp) ||
+			    *cp == ',' || *cp == ' ')) {
+			cp++;
+		    }
+		    if (*cp == '\0') {
+			StrAllocCopy(cur_cookie->PortList, value);
+			length += strlen(cur_cookie->PortList);
+			known_attr = YES;
+		    } else {
+			known_attr = NO;
+		    }
+		} else if (cur_cookie != NULL) {
+		    /*
+		     *  Don't process a repeat port. - FM
+		     */
+		    if (cur_cookie->PortList == NULL) {
+			char temp[256];
+			sprintf(temp, "%d", port);
+			StrAllocCopy(cur_cookie->PortList, temp);
+			length += strlen(cur_cookie->PortList);
+		    }
+		    known_attr = YES;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "version", 7)) {
+		known_attr = YES;
+		if (cur_cookie != NULL && value &&
+		    /*
+		     *  Don't process a repeat version. - FM
+		     */
+		    cur_cookie->version < 0) {
+		    int temp = strtol(value, NULL, 10);
+		    if (errno != -ERANGE) {
+			cur_cookie->version = temp;
+		    }
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "max-age", 7)) {
+		known_attr = YES;
+		if ((cur_cookie != NULL) && !MaxAgeAttrSet && value) {
+		    int temp = strtol(value, NULL, 10);
+		    cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
+		    if (errno == -ERANGE) {
+			cur_cookie->expires = (time_t)0;
+		    } else {
+			cur_cookie->expires = (time(NULL) + temp);
+		    }
+		    MaxAgeAttrSet = TRUE;
+		}
+	    } else if (len == 7 && !strncasecomp(attr_start, "expires", 7)) {
+	    	/*
+		 *  Convert an 'expires' attribute value if we haven't
+		 *  received a 'max-age'.  Note that 'expires' should not
+		 *  be used in Version 1 cookies, but it might be used for
+		 *  "backward compatibility", and, in turn, ill-informed
+		 *  people surely would start using it instead of, rather
+		 *  than in addition to, 'max-age'. - FM
+		 */
+		known_attr = YES;
+		if ((cur_cookie != NULL) && !(MaxAgeAttrSet) &&
+		    !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) {
+		    if (value) {
+			cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
+		        cur_cookie->expires = LYmktime(value, FALSE);
+		    }
+		}
 	    }
 
 	    /*
@@ -817,81 +1520,406 @@ PUBLIC void LYSetCookie ARGS2(
 	     *  ignore it. - FM
 	     */
 	    if (!known_attr && value_end > value_start) {
-		store_cookie(cur_cookie, hostname, path);
-		cur_cookie = newCookie();
-		length += len;
-		if (length > 4096) {
-		    FREE(value);
-		    break;
+		if (cur_cookie) {
+		    if (SetCookie2 != NULL) {
+		        /*
+			 *  If we had a Set-Cookie2 header, make sure
+			 *  the version is at least 1, and mark it for
+			 *  quoting. - FM
+			 */
+			if (cur_cookie->version < 1) {
+			    cur_cookie->version = 1;
+			}
+			cur_cookie->quoted = TRUE;
+		    }
+		    cl = CombinedCookies;
+		    while (NULL != (co = (cookie *)HTList_nextObject(cl))) {
+			/*
+			 *  Check whether the cookie from the Set-Cookie2
+			 *  header has the same name and value as this one
+			 *  from the Set-Cookie header.  If they both had a
+			 *  domain attribute, make sure those match, and
+			 *  similarly if they both had a path attribute. - FM
+			 */
+			if ((!strcmp(co->name, cur_cookie->name) &&
+			     !strcmp(co->value, cur_cookie->value)) &&
+			    !(((co->flags & COOKIE_FLAG_DOMAIN_SET) &&
+			       (cur_cookie->flags &
+					    COOKIE_FLAG_DOMAIN_SET)) &&
+			      strcmp(co->domain, cur_cookie->domain)) &&
+			    !(((co->flags & COOKIE_FLAG_PATH_SET) &&
+			       (cur_cookie->flags &
+					    COOKIE_FLAG_PATH_SET)) &&
+			      strcmp(co->path, cur_cookie->path))) {
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a domain attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) &&
+				(cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
+				StrAllocCopy(co->domain, cur_cookie->domain);
+				co->flags |= COOKIE_FLAG_DOMAIN_SET;
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a path attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!(co->flags & COOKIE_FLAG_PATH_SET) &&
+				(cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
+				StrAllocCopy(co->path, cur_cookie->path);
+				co->pathlen = cur_cookie->pathlen;
+				co->flags |= COOKIE_FLAG_DOMAIN_SET;
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a comment attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!co->comment && cur_cookie->comment) {
+				StrAllocCopy(co->comment,
+					     cur_cookie->comment);
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a commentURL attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!co->commentURL && cur_cookie->commentURL) {
+				StrAllocCopy(co->commentURL,
+					     cur_cookie->commentURL);
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a port attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!co->PortList && cur_cookie->PortList) {
+				StrAllocCopy(co->PortList,
+					     cur_cookie->PortList);
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't include
+			     *  a secure attribute and the Set-Cookie
+			     *  header did, add it. - FM
+			     */
+			    if (!(co->flags & COOKIE_FLAG_SECURE) &&
+				(cur_cookie->flags & COOKIE_FLAG_SECURE)) {
+				co->flags |= COOKIE_FLAG_SECURE;
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't set an
+			     *  expiration and the Set-Cookie header did,
+			     *  add it. - FM
+			     */
+			    if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) &&
+				(cur_cookie->flags &
+				 COOKIE_FLAG_EXPIRES_SET)) {
+				co->expires = cur_cookie->expires;
+				co->flags |= COOKIE_FLAG_EXPIRES_SET;
+			    }
+			    /*
+			     *  If the Set-Cookie2 header didn't set
+			     *  discard and the Set-Cookie header did,
+			     *  add it. - FM
+			     */
+			    if (!(co->flags & COOKIE_FLAG_DISCARD) &&
+				(cur_cookie->flags & COOKIE_FLAG_DISCARD)) {
+				co->flags |= COOKIE_FLAG_DISCARD;
+			    }
+			    /*
+			     *  If the cookie from the Set-Cookie2 header
+			     *  has a lower version than this cookie, use
+			     *  this cookie's version (though it should
+			     *  not have a version number). - FM
+			     */
+			    if (co->version < cur_cookie->version) {
+				co->version = cur_cookie->version;
+			    }
+			    freeCookie(cur_cookie);
+			    cur_cookie = NULL;
+			    break;
+			}
+		    }
+		    if (co == NULL) {
+			HTList_appendObject(CombinedCookies, cur_cookie);
+		    }
 		}
+		cur_cookie = newCookie();
+		length = 0;
+		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
+		length += strlen(cur_cookie->name);
+		MemAllocCopy(&(cur_cookie->value), value_start, value_end);
+		length += strlen(cur_cookie->value);
 		StrAllocCopy(cur_cookie->domain, hostname);
+		length += strlen(cur_cookie->domain);
 		StrAllocCopy(cur_cookie->path, path);
-		cur_cookie->pathlen = strlen(cur_cookie->path);
+		length += (cur_cookie->pathlen = strlen(cur_cookie->path));
 		cur_cookie->port = port;
-		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
-		MemAllocCopy(&(cur_cookie->value), value_start, value_end);
+		MaxAgeAttrSet = FALSE;
 		cur_cookie->quoted = Quoted;
 		Quoted = FALSE;
 	    }
 	    FREE(value);
 	}
-	if (TRACE) {
-	    fprintf(stderr, "LYSetCookie: attr=value pair: ");
-	    if (attr_start == attr_end)  {
-		fprintf(stderr, "[No attr]");
-	    } else {
-		CONST char *i;
-	      
-		for (i = attr_start; i < attr_end; i++)
-		    putc(*i, stderr);
+    }
+
+    /*
+     *  Handle the final Set-Cookie cookie if within length limit. - FM
+     */
+    if (NumCookies <= 50 && length <= 4096 && cur_cookie != NULL) {
+	if (SetCookie2 != NULL) {
+	    if (cur_cookie->version < 1) {
+		cur_cookie->version = 1;
 	    }
-	    fprintf(stderr, "=");
-	    if (value_start >= value_end) {
-		fprintf(stderr, "[No value]");
-	    } else {
-		CONST char *i;
+	    cur_cookie->quoted = TRUE;
+	}
+	cl = CombinedCookies;
+	while (NULL != (co = (cookie *)HTList_nextObject(cl))) {
+	    /*
+	     *  Check whether the cookie from the Set-Cookie2
+	     *  header has the same name and value as this one
+	     *  from the Set-Cookie header.  If they both had a
+	     *  domain attribute, make sure those match, and
+	     *  similarly if they both had a path attribute. - FM
+	     */
+	    if ((!strcmp(co->name, cur_cookie->name) &&
+		 !strcmp(co->value, cur_cookie->value)) &&
+		!(((co->flags & COOKIE_FLAG_DOMAIN_SET) &&
+		   (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) &&
+		  strcmp(co->domain, cur_cookie->domain)) &&
+		!(((co->flags & COOKIE_FLAG_PATH_SET) &&
+		   (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) &&
+		  strcmp(co->path, cur_cookie->path))) {
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a domain attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!(co->flags & COOKIE_FLAG_DOMAIN_SET) &&
+		    (cur_cookie->flags & COOKIE_FLAG_DOMAIN_SET)) {
+		    StrAllocCopy(co->domain, cur_cookie->domain);
+		    co->flags |= COOKIE_FLAG_DOMAIN_SET;
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a path attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!(co->flags & COOKIE_FLAG_PATH_SET) &&
+		    (cur_cookie->flags & COOKIE_FLAG_PATH_SET)) {
+		    StrAllocCopy(co->path, cur_cookie->path);
+		    co->pathlen = cur_cookie->pathlen;
+		    co->flags |= COOKIE_FLAG_DOMAIN_SET;
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a comment attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!co->comment && cur_cookie->comment) {
+		    StrAllocCopy(co->comment, cur_cookie->comment);
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a commentURL attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!co->commentURL && cur_cookie->commentURL) {
+		    StrAllocCopy(co->commentURL, cur_cookie->commentURL);
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a port attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!co->PortList && cur_cookie->PortList) {
+		    StrAllocCopy(co->PortList, cur_cookie->PortList);
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't include
+		 *  a secure attribute and the Set-Cookie
+		 *  header did, add it. - FM
+		 */
+		if (!(co->flags & COOKIE_FLAG_SECURE) &&
+		    (cur_cookie->flags & COOKIE_FLAG_SECURE)) {
+		    co->flags |= COOKIE_FLAG_SECURE;
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't set an
+		 *  expiration and the Set-Cookie header did,
+		 *  add it. - FM
+		 */
+		if (!(co->flags & COOKIE_FLAG_EXPIRES_SET) &&
+		    (cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) {
+		    co->expires = cur_cookie->expires;
+		    co->flags |= COOKIE_FLAG_EXPIRES_SET;
+		}
+		/*
+		 *  If the Set-Cookie2 header didn't set
+		 *  discard and the Set-Cookie header did,
+		 *  add it. - FM
+		 */
+		if (!(co->flags & COOKIE_FLAG_DISCARD) &&
+		    (cur_cookie->flags & COOKIE_FLAG_DISCARD)) {
+		    co->flags |= COOKIE_FLAG_DISCARD;
+		}
+		/*
+		 *  If the cookie from the Set-Cookie2 header
+		 *  has a lower version than this cookie, use
+		 *  this cookie's version (though it should
+		 *  not have a version number). - FM
+		 */
+		if (co->version < cur_cookie->version) {
+		    co->version = cur_cookie->version;
+		}
+		freeCookie(cur_cookie);
+		cur_cookie = NULL;
+		break;
+	    }
+	}
+	if (co == NULL) {
+	    HTList_appendObject(CombinedCookies, cur_cookie);
+	}
+    } else if (cur_cookie != NULL) {
+	if (TRACE) {
+	    fprintf(stderr,
+	  "LYProcessSetCookies: Rejecting Set-Cookie: %s=%s\n",
+		    (cur_cookie->name ? cur_cookie->name : "[no name]"),
+		    (cur_cookie->value ? cur_cookie->value : "[no value]"));
+	    fprintf(stderr,
+	  "                     due to excessive %s%s%s\n",
+		    (length > 4096 ? "length" : ""),
+		    (length > 4096 && NumCookies > 50 ? " and " : ""),
+		    (NumCookies > 50 ? "number!\n" : "!\n"));
+	}
+        freeCookie(cur_cookie);
+	cur_cookie = NULL;
+    }
 
-		for (i = value_start; i < value_end; i++)
-		    putc(*i, stderr);
+    /*
+     *  OK, now we can actually store any cookies
+     *  in the CombinedCookies list. - FM
+     */
+    cl = CombinedCookies;
+    while (NULL != (co = (cookie *)HTList_nextObject(cl))) {
+	if (TRACE) {
+	    fprintf(stderr, "LYProcessSetCookie: attr=value pair: '%s=%s'\n",
+			    (co->name ? co->name : "[no name]"),
+			    (co->value ? co->value : "[no value]"));
+	    if (co->expires > 0) {
+		fprintf(stderr, "                    expires: %i, %s\n",
+				 co->expires,
+				 ctime(&co->expires));
+	    }
+	}
+        if (!strncasecomp(address, "https:", 6) &&
+	    LYForceSSLCookiesSecure == TRUE &&
+	    !(co->flags & COOKIE_FLAG_SECURE)) {
+	    co->flags |= COOKIE_FLAG_SECURE;
+	    if (TRACE) {
+	        fprintf(stderr,
+			"                    Forced the 'secure' flag on.\n");
 	    }
-	    fprintf(stderr, "\n");
 	}
+	store_cookie(co, hostname, path);
     }
+    HTList_delete(CombinedCookies);
+    CombinedCookies = NULL;
+
+    return;
+}
+
+/*
+**  Entry function for handling Set-Cookie: and/or Set-Cookie2:
+**  reply headers.   They may have been concatenated as comma
+**  separated lists in HTTP.c or HTMIME.c. - FM
+*/
+PUBLIC void LYSetCookie ARGS3(
+	CONST char *,	SetCookie,
+	CONST char *,	SetCookie2,
+	CONST char *,	address)
+{
+    BOOL BadHeaders = FALSE;
+    char *hostname = NULL, *path = NULL, *ptr;
+    int port = 80;
 
     /*
-     *  Store the final cookie if within length limit. - FM
+     *  Get the hostname, port and path of the address, and report
+     *  the Set-Cookie request if trace mode is on, but set the cookie
+     *  only if LYSetCookies is TRUE. - FM
      */
-    if (length <= 4096 && cur_cookie != NULL) {
-        /*
-	 *  Force the secure flag on if it's not set but this
-	 *  is an https URL.  This ensures that cookies from
-	 *  https servers will not be shared with ones for
-	 *  http (non-SSL) servers and thus be transmitted
-	 *  unencrypted, and is redundant with the current,
-	 *  blanket port restriction.  However, this seemed
-	 *  a side-effect rather than conscious intent within
-	 *  the port restriction.  A port attribute is likely
-	 *  to be added, and we can independently regulate
-	 *  sharing based on port versus scheme, with user
-	 *  configuration and run time options, "when the
-	 *  time is right". - FM
+    if (((hostname = HTParse(address, "", PARSE_HOST)) != NULL) &&
+	(ptr = strchr(hostname, ':')) != NULL)  {
+	/*
+	 *  Replace default port number.
 	 */
-        if (!strncasecomp(address, "https:", 6) &&
-	    !(cur_cookie->flags & COOKIE_FLAG_SECURE)) {
-	    cur_cookie->flags |= COOKIE_FLAG_SECURE;
-	    if (TRACE)
-	        fprintf(stderr, "LYSetCookie: Forced the 'secure' flag on.\n");
+	*ptr = '\0';
+	ptr++;
+        port = atoi(ptr);
+    } else if (!strncasecomp(address, "https:", 6)) {
+        port = 443;
+    } 
+    if (((path = HTParse(address, "",
+    			 PARSE_PATH|PARSE_PUNCTUATION)) != NULL) &&
+	(ptr = strrchr(path, '/')) != NULL) {
+	if (ptr == path) {
+	    *(ptr+1) = '\0';	/* Leave a single '/' alone */
+	} else {
+	    *ptr = '\0'; 
 	}
-        store_cookie(cur_cookie, hostname, path);
-    } else {
-	if (TRACE)
-	    fprintf(stderr, "LYSetCookie: Rejecting cookie due to length!\n");
-        freeCookie(cur_cookie);
     }
+    if (!(SetCookie && *SetCookie) &&
+	!(SetCookie2 && *SetCookie2)) {
+	/*
+	 *  Yuk, something must have gone wrong in
+	 *  HTMIME.c or HTTP.c because both SetCookie
+	 *  and SetCookie2 are NULL or zero-length. - FM
+	 */
+	BadHeaders = TRUE;
+    }
+    if (TRACE) {
+	fprintf(stderr,
+		"LYSetCookie called with host '%s', path '%s',\n",
+		(hostname ? hostname : ""),
+		(path ? path : ""));
+	if (SetCookie) {
+	    fprintf(stderr, "    and Set-Cookie: '%s'\n",
+			    (SetCookie ? SetCookie : ""));
+	}
+	if (SetCookie2) {
+	    fprintf(stderr, "    and Set-Cookie2: '%s'\n",
+			    (SetCookie2 ? SetCookie2 : ""));
+	}
+	if (LYSetCookies == FALSE || BadHeaders == TRUE) {
+	    fprintf(stderr,
+		    "    Ignoring this Set-Cookie/Set-Cookie2 request.\n");
+	}
+    }
+
+    /*
+     *  We're done if LYSetCookies is off or we have bad headers. - FM
+     */
+    if (LYSetCookies == FALSE || BadHeaders == TRUE) {
+	FREE(hostname);
+	FREE(path);
+	return;
+    }
+
+    /*
+     *  Process the header(s).
+     */
+    LYProcessSetCookies(SetCookie, SetCookie2, address, hostname, path, port);
     FREE(hostname);
     FREE(path);
+    return;
 }
 
+/*
+**  Entry function from creating a Cookie: request header
+**  if needed. - AK & FM
+*/
 PUBLIC char * LYCookie ARGS4(
 	CONST char *,	hostname,
 	CONST char *,	path,
@@ -946,9 +1974,9 @@ PUBLIC char * LYCookie ARGS4(
         return(header);
 
     /*
-     *  If we set a header, perhaps all the cookies have
-     *  expired and we deleted the last of them above, so
-     *  check if we should delete and NULL the domain_list. - FM
+     *  If we didn't set a header, perhaps all the cookies have
+     *  expired and we deleted the last of them above, so check
+     *  if we should delete and NULL the domain_list. - FM
      */
     if (domain_list) {
 	if (HTList_isEmpty(domain_list)) {
@@ -972,7 +2000,7 @@ PUBLIC char * LYCookie ARGS4(
 **  Semantics:
 **	LYNXCOOKIE:/			Create and load the Cookie Jar Page.
 **	LYNXCOOKIE://domain		Manipulate the domain.
-**	LYNXCOOKIE://domain/lynx_id	Delete cookie with lynx_id in domain.
+**	LYNXCOOKIE://domain/lynxID	Delete cookie with lynxID in domain.
 **
 **	New functions can be added as extensions to the path, and/or by
 **	assigning meanings to ;parameters, a ?searchpart, and/or #fragments.
@@ -987,11 +2015,12 @@ PRIVATE int LYHandleCookies ARGS4 (
     HTStream *target = NULL;
     char buf[1024];
     char *domain = NULL;
-    char *lynx_id = NULL;
+    char *lynxID = NULL;
     HTList *dl, *cl, *next;
     domain_entry *de;
     cookie *co;
-    char *name = NULL, *value = NULL, *path = NULL, *comment = NULL;
+    char *name = NULL, *value = NULL, *path = NULL;
+    char *comment = NULL, *Address = NULL, *Title = NULL;
     int ch;
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt;
@@ -1017,12 +2046,12 @@ PRIVATE int LYHandleCookies ARGS4 (
 	} else {
 	    /*
 	     *  If there is a path string (not just a slash) in the
-	     *  LYNXCOOKIE: URL, that's a cookie's lynx_id and this
+	     *  LYNXCOOKIE: URL, that's a cookie's lynxID and this
 	     *  is a request to delete it from the Cookie Jar. - FM
 	     */ 
-	    if ((lynx_id = HTParse(arg, "", PARSE_PATH)) != NULL) {
-	        if (*lynx_id == '\0') {
-		    FREE(lynx_id);
+	    if ((lynxID = HTParse(arg, "", PARSE_PATH)) != NULL) {
+	        if (*lynxID == '\0') {
+		    FREE(lynxID);
 		}
 	    }
 	}
@@ -1041,11 +2070,11 @@ PRIVATE int LYHandleCookies ARGS4 (
 	    if (!strcmp(domain, de->domain)) {
 	        /*
 		 *  We found the domain.  Check
-		 *  whether a lynx_id is present. - FM
+		 *  whether a lynxID is present. - FM
 		 */
-	        if (lynx_id) {
+	        if (lynxID) {
 		    /*
-		     *  Seek and delete the cookie with this lynx_id
+		     *  Seek and delete the cookie with this lynxID
 		     *  in the domain's cookie list. - FM
 		     */
 		    for (cl = de->cookie_list; cl != NULL; cl = cl->next) {
@@ -1054,7 +2083,7 @@ PRIVATE int LYHandleCookies ARGS4 (
 			     *  First object is always empty. - FM
 			     */
 			    continue;
-			if (!strcmp(lynx_id, co->lynx_id)) {
+			if (!strcmp(lynxID, co->lynxID)) {
 			    /*
 			     *  We found the cookie.
 			     *  Delete it if confirmed. - FM
@@ -1322,13 +2351,13 @@ Delete_all_cookies_in_domain:
 	        StrAllocCopy(value, NO_VALUE);
 	    }
 	    sprintf(buf, "<DD><A HREF=\"LYNXCOOKIE://%s/%s\">%s=%s</A>\n",
-			 de->domain, co->lynx_id, name, value);
+			 de->domain, co->lynxID, name, value);
 	    FREE(name);
 	    FREE(value);
 	    (*target->isa->put_block)(target, buf, strlen(buf));
 
 	    /*
-	     *  Show the path, port, and secure setting. - FM
+	     *  Show the path, port, secure and discard setting. - FM
 	     */
  	    if (co->path) {
 	        StrAllocCopy(path, co->path);
@@ -1343,14 +2372,29 @@ Delete_all_cookies_in_domain:
 	    (*target->isa->put_block)(target, buf, strlen(buf));
 
 	    /*
-	     *  Show the Maximum Gobble Date. - FM
+	     *  Show the list of acceptable ports, if present. - FM
 	     */
-	    sprintf(buf, "<DD><EM>Maximum Gobble Date:</EM> %s%s",
-	    		 ((co->expires > 0) ?
-			ctime(&co->expires) : END_OF_SESSION),
-			 ((co->expires > 0) ?
-				 	 "" : "\n"));
-	    (*target->isa->put_block)(target, buf, strlen(buf));
+	    if (co->PortList) {
+	        sprintf(buf, "<DD>PortList=\"%s\"\n", co->PortList);
+		(*target->isa->put_block)(target, buf, strlen(buf));
+	    }
+
+	    /*
+	     *  Show the commentURL, if we have one. - FM
+	     */
+ 	    if (co->commentURL) {
+	        StrAllocCopy(Address, co->commentURL);
+		LYEntify(&Address, FALSE);
+	        StrAllocCopy(Title, co->commentURL);
+		LYEntify(&Title, TRUE);
+		sprintf(buf,
+			"<DD>CommentURL: <A href=\"%s\">%s</A>\n",
+			Address,
+			Title);
+		FREE(Address);
+		FREE(Title);
+		(*target->isa->put_block)(target, buf, strlen(buf));
+	    }
 
 	    /*
 	     *  Show the comment, if we have one. - FM
@@ -1358,10 +2402,24 @@ Delete_all_cookies_in_domain:
  	    if (co->comment) {
 	        StrAllocCopy(comment, co->comment);
 		LYEntify(&comment, TRUE);
-		sprintf(buf, "<DD><EM>Comment:</EM> %s\n", comment);
+		sprintf(buf, "<DD>Comment: %s\n", comment);
 		FREE(comment);
 		(*target->isa->put_block)(target, buf, strlen(buf));
 	    }
+
+	    /*
+	     *  Show the Maximum Gobble Date. - FM
+	     */
+	    sprintf(buf, "<DD><EM>Maximum Gobble Date:</EM> %s%s",
+	    		 ((co->expires > 0 &&
+			   !(co->flags & COOKIE_FLAG_DISCARD))
+					    ?
+			ctime(&co->expires) : END_OF_SESSION),
+			 ((co->expires > 0 &&
+			   !(co->flags & COOKIE_FLAG_DISCARD))
+					    ?
+				 	 "" : "\n"));
+	    (*target->isa->put_block)(target, buf, strlen(buf));
 	}
 	sprintf(buf, "</DT>\n");
 	(*target->isa->put_block)(target, buf, strlen(buf));
diff --git a/src/LYCookie.h b/src/LYCookie.h
index abc8a018..9900a017 100644
--- a/src/LYCookie.h
+++ b/src/LYCookie.h
@@ -3,7 +3,8 @@
 #define LYCOOKIES_H
 
 extern void LYSetCookie PARAMS((
-	CONST char *	header,
+	CONST char *	SetCookie,
+	CONST char *	SetCookie2,
 	CONST char *	address));
 extern char *LYCookie PARAMS((
 	CONST char *	hostname,
diff --git a/src/LYCurses.c b/src/LYCurses.c
index 968c23d5..1424417e 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -52,10 +52,14 @@ PRIVATE int Current_Attr;
 
 #ifdef USE_SLANG
 PUBLIC unsigned int Lynx_Color_Flags = 0;
+PRIVATE int Current_Attr;
 PUBLIC BOOLEAN FullRefresh = FALSE;
 PUBLIC int curscr = 0;
 #ifdef SLANG_MBCS_HACK
-PUBLIC int PHYSICAL_SLtt_Screen_Cols = 10;/* will be set by size_change - kw */
+/*
+ *  Will be set by size_change. - KW
+ */
+PUBLIC int PHYSICAL_SLtt_Screen_Cols = 10;
 #endif /* SLANG_MBCS_HACK */
 
 PUBLIC void LY_SLrefresh NOARGS
@@ -84,14 +88,14 @@ PUBLIC void VTHome NOARGS
 }
 #endif /* VMS */
 
-PUBLIC void lynx_add_attr ARGS1(
+PUBLIC void LYaddAttr ARGS1(
 	int,		a)
 {
     Current_Attr |= a;
     SLsmg_set_color(Current_Attr);
 }
 
-PUBLIC void lynx_sub_attr ARGS1(
+PUBLIC void LYsubAttr ARGS1(
 	int,		a)
 {
     Current_Attr &= ~a;
@@ -264,6 +268,14 @@ PUBLIC void curses_w_style ARGS4(WINDOW*,win,int,style,int,dir,int,previous)
 		return;
 
 	case STACK_ON: /* remember the current attributes */
+	    	if (last_ptr > 127) {
+		    if (TRACE)
+			fprintf(stderr,"........... %s (0x%x) %s\r\n",
+				"attribute cache FULL, dropping last",
+				last_styles[last_ptr],
+				"in LynxChangStyle(curses_w_style)");
+		    last_ptr--;
+		}
 #ifndef _NCURSES_H
 		last_styles[last_ptr++] = getattrs(stdscr);
 #else
@@ -334,7 +346,7 @@ PUBLIC void curses_style ARGS3(int,style,int,dir,int,previous)
         curses_w_style(stdscr, style, dir, previous);
 }
 
-#if UNUSED
+#ifdef NOT_USED
 void attribute ARGS2(int,style,int,dir)
 {
         curses_style(style, dir, 0);
@@ -380,7 +392,7 @@ PRIVATE struct {
  * Map the SGR attributes (0-7) into ANSI colors, modified with the actual BOLD
  * attribute we'll get 16 colors.
  */
-PRIVATE void lynx_set_wattr ARGS1(WINDOW *, win)
+PRIVATE void LYsetWAttr ARGS1(WINDOW *, win)
 {
     if (lynx_uses_color) {
 	int code = 0;
@@ -484,31 +496,9 @@ PUBLIC void lynx_set_color ARGS1(int, a)
 PUBLIC void lynx_standout ARGS1(int, flag)
 {
     if (flag)
-	lynx_add_attr(A_REVERSE);
+	LYaddAttr(A_REVERSE);
     else
-	lynx_sub_attr(A_REVERSE);
-}
-
-PUBLIC void lynx_add_wattr ARGS2(WINDOW *, win, int, a)
-{
-    Current_Attr |= a;
-    lynx_set_wattr(win);
-}
-
-PUBLIC void lynx_add_attr ARGS1(int, a)
-{
-    lynx_add_wattr (stdscr, a);
-}
-
-PUBLIC void lynx_sub_wattr ARGS2(WINDOW *, win, int, a)
-{
-    Current_Attr &= ~a;
-    lynx_set_wattr(win);
-}
-
-PUBLIC void lynx_sub_attr ARGS1(int, a)
-{
-    lynx_sub_wattr (stdscr, a);
+	LYsubAttr(A_REVERSE);
 }
 
 PRIVATE void lynx_init_colors NOARGS
@@ -619,8 +609,8 @@ PUBLIC void start_curses NOARGS
    SLtty_set_suspend_state(1);
 #endif /* _WINDOWS */
 #ifdef SIGTSTP
-   if (!no_suspend)
-       signal(SIGTSTP, sl_suspend);
+    if (!no_suspend)
+	signal(SIGTSTP, sl_suspend);
 #endif /* SIGTSTP */
     signal(SIGINT, cleanup_sig);
 #endif /* !VMS */
@@ -631,7 +621,7 @@ PUBLIC void start_curses NOARGS
 
 #ifdef VMS
     /*
-     *  If we are VMS then do initscr() everytime start_curses()
+     *  If we are VMS then do initsrc() everytime start_curses()
      *  is called!
      */
     initscr();  /* start curses */
@@ -743,10 +733,6 @@ PUBLIC void stop_curses NOARGS
 #endif
 #if defined (DOSPATH) && !defined (USE_SLANG)
 	 clrscr();
-/*
-		  clear();
-		  refresh();
-*/
 #else
 
     /*
@@ -764,16 +750,18 @@ PUBLIC void stop_curses NOARGS
 
     LYCursesON = FALSE;
 
+#if defined(SIGTSTP) && defined(USE_SLANG)
 #ifndef VMS
-#ifdef SIGTSTP
    if (!no_suspend)
        signal(SIGTSTP, SIG_DFL);
-#endif /* SIGTSTP */
+#endif /* !VMS */
+#endif /* SIGTSTP && USE_SLANG */
+
+#ifndef VMS
     signal(SIGINT, SIG_DFL);
 #endif /* !VMS */
 }
 
-
 #ifdef VMS
 /*
  *  Check terminal type, start curses & setup terminal.
@@ -807,7 +795,8 @@ PUBLIC BOOLEAN setup ARGS1(
 	 */
 	dump_output_immediately = TRUE;
         LYcols = 80;
-	keypad_mode = LINKS_ARE_NUMBERED;
+	if (keypad_mode == NUMBERS_AS_ARROWS)
+	    keypad_mode = LINKS_ARE_NUMBERED;
 	status = mainloop();
         (void) signal (SIGHUP, SIG_DFL);
         (void) signal (SIGTERM, SIG_DFL);
@@ -841,6 +830,10 @@ PUBLIC BOOLEAN setup ARGS1(
 
     LYlines = LINES;
     LYcols = COLS;
+    if (LYlines <= 0)
+        LYlines = 24;
+    if (LYcols <= 0)
+        LYcols = 80;
 
     return(TRUE);
 }
@@ -903,6 +896,10 @@ PUBLIC BOOLEAN setup ARGS1(
 
     LYlines = LINES;
     LYcols = COLS;
+    if (LYlines <= 0)
+        LYlines = 24;
+    if (LYcols <= 0)
+        LYcols = 80;
 
     return(1);
 }
@@ -926,8 +923,60 @@ PRIVATE int dumbterm ARGS1(
 	dumb = TRUE;
     return(dumb);
 }
+
+#ifdef FANCY_CURSES
+#ifndef USE_COLOR_STYLE
+#if USE_COLOR_TABLE
+PUBLIC void LYaddWAttr ARGS2(
+	WINDOW *,	win,
+	int,		a)
+{
+    Current_Attr |= a;
+    LYsetWAttr(win);
+}
+
+PUBLIC void LYaddAttr ARGS1(
+	int,		a)
+{
+    LYaddWAttr(stdscr, a);
+}
+
+PUBLIC void LYsubWAttr ARGS2(
+	WINDOW *,	win,
+	int,		a)
+{
+    Current_Attr &= ~a;
+    LYsetWAttr(win);
+}
+
+PUBLIC void LYsubAttr ARGS1(
+	int,		a)
+{
+    LYsubWAttr(stdscr, a);
+}
+#endif
+#endif /* USE_COLOR_STYLE */
+#endif /* FANCY_CURSES */
 #endif /* VMS */
 
+PUBLIC void LYstartTargetEmphasis NOARGS
+{
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+    start_bold();
+    start_reverse();
+#endif /* FANCY_CURSES || USE_SLANG */
+    start_underline();
+}
+
+PUBLIC void LYstopTargetEmphasis NOARGS
+{
+    stop_underline();
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+    stop_reverse();
+    stop_bold();
+#endif /* FANCY_CURSES || USE_SLANG */
+}
+
 #ifdef VMS
 /*
  *	Cut-down termio --
@@ -1471,7 +1520,9 @@ PUBLIC void lynx_stop_title_color NOARGS
 {
 }
 
-PUBLIC void lynx_start_link_color ARGS1(int, flag)
+PUBLIC void lynx_start_link_color ARGS2(
+	int,	flag,
+	int,	pending)
 {
     if (flag) {
 	/* makes some terminals work wrong because
@@ -1480,26 +1531,48 @@ PUBLIC void lynx_start_link_color ARGS1(int, flag)
 	 */
 	/* start_bold();  */
 	start_reverse();
-#if defined(USE_SLANG) || defined(FANCY_CURSES)
+#if defined(USE_SLANG)
+	if (SLtt_Use_Ansi_Colors)
+	    start_underline ();
+#endif /* USE_SLANG */
+#if defined(FANCY_CURSES)
 	start_underline ();
 #endif /* USE_SLANG */
      } else {
 	start_bold();
+	/*
+	 *  Make sure when flag is OFF that "unhighlighted" links
+	 *  will be underlined if appropriate. - LE & FM
+	 */
+	if (pending)
+	    start_underline();
      }
 }
 
-PUBLIC void lynx_stop_link_color ARGS1(int, flag)
+PUBLIC void lynx_stop_link_color ARGS2(
+	int,	flag,
+	int,	pending)
 {
 #ifdef USE_COLOR_STYLE
     LynxChangeStyle(flag == ON ? s_alink : s_a, ABS_OFF, 0);
 #else
     if (flag) {
 	stop_reverse();
-#if defined(USE_SLANG) || defined(FANCY_CURSES)
+#if defined(USE_SLANG)
+	if (SLtt_Use_Ansi_Colors)
+	stop_underline ();
+#endif /* USE_SLANG */
+#if defined(FANCY_CURSES)
 	stop_underline ();
 #endif /* USE_SLANG */
-    } else
+    } else {
 	stop_bold();
+	/*
+	 *  If underlining was turned on above, turn it off. - LE & FM
+	 */
+	if (pending)
+	    stop_underline();
+    }
 #endif
 }
 
diff --git a/src/LYCurses.h b/src/LYCurses.h
index 82efadc9..8ea9ce78 100644
--- a/src/LYCurses.h
+++ b/src/LYCurses.h
@@ -30,7 +30,7 @@
 
 #ifdef VMS
 #define FANCY_CURSES
-#endif
+#endif /* VMS */
 
 /*
  *	CR may be defined before the curses.h include occurs.
@@ -108,6 +108,8 @@ extern int LYcols;   /* replaces COLS */
 extern void start_curses NOPARAMS;
 extern void stop_curses NOPARAMS;
 extern BOOLEAN setup PARAMS((char *terminal));
+extern void LYstartTargetEmphasis NOPARAMS;
+extern void LYstopTargetEmphasis NOPARAMS;
 
 #ifdef VMS
 extern void VMSexit();
@@ -121,21 +123,21 @@ extern void VMSbox PARAMS((WINDOW *win, int height, int width));
 #endif /* VMS */
 
 #if defined(USE_COLOR_STYLE)
-extern void curses_css PARAMS((char * name,int dir));
-extern void curses_style PARAMS((int style,int dir,int previous));
-extern void curses_w_style PARAMS((WINDOW* win,int style,int dir,int previous));
-extern void setHashStyle PARAMS((int style,int color,int cattr,int mono,char* element));
-extern void setStyle PARAMS((int style,int color,int cattr,int mono));
-extern void wcurses_css PARAMS((WINDOW * win,char* name,int dir));
+extern void curses_css PARAMS((char * name, int dir));
+extern void curses_style PARAMS((int style, int dir, int previous));
+extern void curses_w_style PARAMS((WINDOW* win, int style, int dir, int previous));
+extern void setHashStyle PARAMS((int style, int color, int cattr, int mono, char* element));
+extern void setStyle PARAMS((int style, int color, int cattr, int mono));
+extern void wcurses_css PARAMS((WINDOW * win, char* name, int dir));
 #define LynxChangeStyle curses_style
 #else
-extern int slang_style PARAMS((int style,int dir,int previous));
+extern int slang_style PARAMS((int style, int dir, int previous));
 #define LynxChangeStyle slang_style
 #endif /* USE_COLOR_STYLE */
 
 #if USE_COLOR_TABLE
-extern void lynx_add_attr PARAMS((int a));
-extern void lynx_sub_attr PARAMS((int a));
+extern void LYaddAttr PARAMS((int a));
+extern void LYsubAttr PARAMS((int a));
 extern void lynx_setup_colors NOPARAMS;
 extern unsigned int Lynx_Color_Flags;
 #endif
@@ -147,18 +149,20 @@ extern unsigned int Lynx_Color_Flags;
 
 #define SL_LYNX_USE_COLOR	1
 #define SL_LYNX_USE_BLINK	2
-#define start_bold()      lynx_add_attr(1)
-#define start_reverse()   lynx_add_attr(2)
-#define start_underline() lynx_add_attr(4)
-#define stop_bold()       lynx_sub_attr(1)
-#define stop_reverse()    lynx_sub_attr(2)
-#define stop_underline()  lynx_sub_attr(4)
+#define start_bold()      	LYaddAttr(1)
+#define start_reverse()   	LYaddAttr(2)
+#define start_underline() 	LYaddAttr(4)
+#define stop_bold()       	LYsubAttr(1)
+#define stop_reverse()    	LYsubAttr(2)
+#define stop_underline()  	LYsubAttr(4)
 
 #ifdef FANCY_CURSES
 #undef FANCY_CURSES
 #endif /* FANCY_CURSES */
 
-/* Map some curses functions to slang functions. */
+/*
+ *  Map some curses functions to slang functions.
+ */
 #define stdscr NULL
 #ifdef SLANG_MBCS_HACK
 extern int PHYSICAL_SLtt_Screen_Cols;
@@ -203,80 +207,109 @@ extern void VTHome NOPARAMS;
 #ifdef FANCY_CURSES
 
 #ifdef VMS
+/*
+ *  For VMS curses, [w]setattr() and [w]clrattr()
+ *  add and subtract, respectively, the attributes
+ *  _UNDERLINE, _BOLD, _REVERSE, and _BLINK. - FM
+ */
 #ifdef UNDERLINE_LINKS
-#define start_bold()      setattr(_UNDERLINE)
-#define stop_bold()       clrattr(_UNDERLINE)
-#define start_underline() setattr(_BOLD)
-#define stop_underline()  clrattr(_BOLD)
+#define start_bold()		setattr(_UNDERLINE)
+#define stop_bold()		clrattr(_UNDERLINE)
+#define start_underline()	setattr(_BOLD)
+#define stop_underline()	clrattr(_BOLD)
 #else /* not UNDERLINE_LINKS */
-#define start_bold()      setattr(_BOLD)
-#define stop_bold()       clrattr(_BOLD)
-#define start_underline() setattr(_UNDERLINE)
-#define stop_underline()  clrattr(_UNDERLINE)
+#define start_bold()		setattr(_BOLD)
+#define stop_bold()		clrattr(_BOLD)
+#define start_underline()	setattr(_UNDERLINE)
+#define stop_underline()	clrattr(_UNDERLINE)
 #endif /* UNDERLINE_LINKS */
-#define start_reverse()   setattr(_REVERSE)
-#define wstart_reverse(a)   wsetattr(a,_REVERSE)
-#define wstop_underline(a)  wclrattr(a,_UNDERLINE)
-#define stop_reverse()    clrattr(_REVERSE)
-#define wstop_reverse(a)    wclrattr(a,_REVERSE)
+#define start_reverse()		setattr(_REVERSE)
+#define wstart_reverse(a)	wsetattr(a, _REVERSE)
+#define wstop_underline(a)	wclrattr(a, _UNDERLINE)
+#define stop_reverse()		clrattr(_REVERSE)
+#define wstop_reverse(a)	wclrattr(a, _REVERSE)
 
-#else /* NOT VMS: */
+#else /* Not VMS: */
 
+/*
+ *  For Unix FANCY_FANCY curses we interpose
+ *  our own functions to add or subtract the
+ *  A_foo attributes. - FM
+ */
 #if USE_COLOR_TABLE
-extern void lynx_add_wattr PARAMS((WINDOW *, int));
-extern void lynx_sub_wattr PARAMS((WINDOW *, int));
-extern void lynx_set_color PARAMS((int));
-extern void lynx_standout  PARAMS((int));
+extern void LYaddWAttr PARAMS((WINDOW *win, int a));
+extern void LYaddAttr PARAMS((int a));
+extern void LYsubWAttr PARAMS((WINDOW *win, int a));
+extern void LYsubAttr PARAMS((int a));
+extern void LYaddWAttr PARAMS((WINDOW *win, int a));
+extern void LYsubWAttr PARAMS((WINDOW *win, int a));
+extern void lynx_set_color PARAMS((int a));
+extern void lynx_standout  PARAMS((int a));
 extern int  lynx_chg_color PARAMS((int, int, int));
 #undef  standout
-#define standout() lynx_standout(TRUE)
+#define standout() 		lynx_standout(TRUE)
 #undef  standend
-#define standend() lynx_standout(FALSE)
+#define standend() 		lynx_standout(FALSE)
 #else
-#define lynx_add_attr	attrset
-#define lynx_add_wattr	wattrset
-#define lynx_sub_attr	attroff
-#define lynx_sub_wattr	wattroff
+#define LYaddAttr		attrset
+#define LYaddWAttr		wattrset
+#define LYsubAttr		attroff
+#define LYsubWAttr		wattroff
 #endif
 
 #ifdef UNDERLINE_LINKS
-#define start_bold()      lynx_add_attr(A_UNDERLINE)
-#define stop_bold()       lynx_sub_attr(A_UNDERLINE)
-#define start_underline() lynx_add_attr(A_BOLD)
-#define stop_underline()  lynx_sub_attr(A_BOLD)
+#define start_bold()		LYaddAttr(A_UNDERLINE)
+#define stop_bold()		LYsubAttr(A_UNDERLINE)
+#define start_underline()	LYaddAttr(A_BOLD)
+#define stop_underline()	LYsubAttr(A_BOLD)
 #else /* not UNDERLINE_LINKS: */
-#define start_bold()      lynx_add_attr(A_BOLD)
-#define stop_bold()       lynx_sub_attr(A_BOLD)
-#define start_underline() lynx_add_attr(A_UNDERLINE)
-#define stop_underline()  lynx_sub_attr(A_UNDERLINE)
+#define start_bold()		LYaddAttr(A_BOLD)
+#define stop_bold()		LYsubAttr(A_BOLD)
+#define start_underline()	LYaddAttr(A_UNDERLINE)
+#define stop_underline()	LYsubAttr(A_UNDERLINE)
 #endif /* UNDERLINE_LINKS */
 #if defined(SNAKE) && defined(HP_TERMINAL)
-#define start_reverse()   lynx_add_wattr(stdscr,A_DIM)
-#define wstart_reverse(a) lynx_add_wattr(a,A_DIM)
-#define stop_reverse()    lynx_sub_wattr(stdscr,A_DIM)
-#define wstop_reverse(a)  lynx_sub_wattr(a,A_DIM)
+#define start_reverse()		LYaddWAttr(stdscr, A_DIM)
+#define wstart_reverse(a)	LYaddWAttr(a, A_DIM)
+#define stop_reverse()		LYsubWAttr(stdscr, A_DIM)
+#define wstop_reverse(a)	LYsubWAttr(a, A_DIM)
 #else
-#define start_reverse()   lynx_add_attr(A_REVERSE)
-#define wstart_reverse(a) lynx_add_wattr(a,A_REVERSE)
-#define stop_reverse()    lynx_sub_attr(A_REVERSE)
-#define wstop_reverse(a)  lynx_sub_wattr(a,A_REVERSE)
+#define start_reverse()		LYaddAttr(A_REVERSE)
+#define wstart_reverse(a)	LYaddWAttr(a, A_REVERSE)
+#define stop_reverse()		LYsubAttr(A_REVERSE)
+#define wstop_reverse(a)	LYsubWAttr(a, A_REVERSE)
 #endif /* SNAKE && HP_TERMINAL */
 #endif /* VMS */
 
 #else /* Not FANCY_CURSES: */
 
-#define start_bold()      standout()  
-#define start_underline() /* nothing */
-#define start_reverse()   standout()
-#define wstart_reverse(a)   wstandout(a)
-#define stop_bold()       standend()  
-#define stop_underline()  /* nothing */
-#define stop_reverse()    standend()
-#define wstop_reverse(a)    wstandend(a)
+/*
+ *  We only have [w]standout() and [w]standin(),
+ *  so we'll use them synonymously for bold and
+ *  reverse, and ignore underline. - FM
+ */
+#define start_bold()		standout()  
+#define start_underline()	1  /* nothing */
+#define start_reverse()		standout()
+#define wstart_reverse(a)	wstandout(a)
+#define stop_bold()		standend()  
+#define stop_underline()	1  /* nothing */
+#define stop_reverse()		standend()
+#define wstop_reverse(a)	wstandend(a)
 
 #endif /* FANCY_CURSES */
 #endif /* USE_SLANG */
 
+#ifdef USE_SLANG
+#define LYGetYX(y, x)   y = SLsmg_get_row(), x = SLsmg_get_column()
+#else
+#ifdef getyx
+#define LYGetYX(y, x)   getyx(stdscr, y, x)
+#else
+#define LYGetYX(y, x)   y = stdscr->_cury, x = stdscr->_curx
+#endif /* getyx */
+#endif /* USE_SLANG */
+
 extern void lynx_enable_mouse PARAMS((int));
 extern void lynx_start_underline_color NOPARAMS;
 extern void lynx_stop_underline_color NOPARAMS;
@@ -284,8 +317,8 @@ extern void lynx_start_bold_color NOPARAMS;
 extern void lynx_stop_bold_color NOPARAMS;
 extern void lynx_start_title_color NOPARAMS;
 extern void lynx_stop_title_color NOPARAMS;
-extern void lynx_start_link_color PARAMS((int));
-extern void lynx_stop_link_color PARAMS((int));
+extern void lynx_start_link_color PARAMS((int flag, int pending));
+extern void lynx_stop_link_color PARAMS((int flag, int pending));
 extern void lynx_stop_target_color NOPARAMS;
 extern void lynx_start_target_color NOPARAMS;
 extern void lynx_start_status_color NOPARAMS;
@@ -298,5 +331,4 @@ extern void lynx_start_radio_color NOPARAMS;
 extern void lynx_stop_radio_color NOPARAMS;
 extern void lynx_stop_all_colors NOPARAMS;
 
-
 #endif /* LYCURSES_H */
diff --git a/src/LYDownload.c b/src/LYDownload.c
index 32a3bf00..53758e9a 100644
--- a/src/LYDownload.c
+++ b/src/LYDownload.c
@@ -27,13 +27,11 @@
 /*
  *  LYDownload takes a URL and downloads it using a user selected
  *  download program
- */
-
-/* it parses an incoming link that looks like
+ *
+ *  It parses an incoming link that looks like
  *
  *  LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
  */
-
 #ifdef VMS
 #define COPY_COMMAND "copy/nolog/noconf %s %s"
 PUBLIC BOOLEAN LYDidRename = FALSE;
@@ -41,14 +39,15 @@ PUBLIC BOOLEAN LYDidRename = FALSE;
 
 PRIVATE char LYValidDownloadFile[256] = "\0";
 
-PUBLIC void LYDownload ARGS1(char *,line) 
+PUBLIC void LYDownload ARGS1(
+	char *,		line) 
 {
-    char *Line = NULL, *method, *file, *sug_file = NULL;
+    char *Line = NULL, *method, *file, *theFile, *sug_file = NULL;
     int method_number;
     int count;
-    char buffer[256];
-    char command[256];
-    char *cp;
+    char buffer[512];
+    char command[512];
+    char *cp, *cp1;
     lynx_html_item_type *download_command = 0;
     int c, len;
     FILE *fp;
@@ -68,7 +67,7 @@ PUBLIC void LYDownload ARGS1(char *,line)
      *  the download options menu. - FM
      */
     if (LYValidDownloadFile[0] == '\0') {
-    goto failed;
+	goto failed;
     }
 
     /*
@@ -77,18 +76,25 @@ PUBLIC void LYDownload ARGS1(char *,line)
      */
     StrAllocCopy(Line, line);
 
-    /* parse out the sug_file, Method and the File */
+    /*
+     *  Parse out the sug_file, Method and the File.
+     */
     if ((sug_file = (char *)strstr(Line, "SugFile=")) != NULL) {
 	*(sug_file-1) = '\0';
-        /* go past "SugFile=" */
+        /*
+	 *  Go past "SugFile=".
+	 */
         sug_file += 8;
     }
 
     if ((file = (char *)strstr(Line, "File=")) == NULL)
 	goto failed;
     *(file-1) = '\0';
-    /* go past "File=" */
+    /*
+     *  Go past "File=".
+     */
     file += 5;
+
     /*
      *  Make sure that the file string is the one from
      *  the last displayed download options menu. - FM
@@ -97,7 +103,6 @@ PUBLIC void LYDownload ARGS1(char *,line)
         goto failed;
     }
 
-
 #ifdef DIRED_SUPPORT
     if (!strncmp(file, "file://localhost", 16))
         file += 16;
@@ -108,45 +113,50 @@ PUBLIC void LYDownload ARGS1(char *,line)
 
     if ((method = (char *)strstr(Line, "Method=")) == NULL)
 	goto failed;
-    /* go past "Method=" */
+    /*
+     *  Go past "Method=".
+     */
     method += 7;
     method_number = atoi(method);
  
-
-    /* set up the sug_filenames recall buffer */
+    /*
+     *  Set up the sug_filenames recall buffer.
+     */
     FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0);
     recall = ((FnameTotal >= 1) ? RECALL : NORECALL);
     FnameNum = FnameTotal;
 
-
     if (method_number < 0) {
-	/* write to local file */
+	/*
+	 *  Write to local file.
+	 */
 	_statusline(FILENAME_PROMPT);
-retry:	
+retry:
 	if (sug_file)
-	    strcpy(buffer, sug_file);
+	    LYstrncpy(buffer, sug_file, ((sizeof(buffer)/2) - 1));
 	else
 	    *buffer = '\0';
 check_recall:
-	if ((ch = LYgetstr(buffer, VISIBLE, sizeof(buffer), recall)) < 0 ||
+	if ((ch = LYgetstr(buffer,
+			   VISIBLE, (sizeof(buffer)/2), recall)) < 0 ||
 	    *buffer == '\0' || ch == UPARROW || ch == DNARROW) {
 	    if (recall && ch == UPARROW) {
-	        if (FirstRecall) {
+		if (FirstRecall) {
 		    FirstRecall = FALSE;
 		    /*
-		     *  Use the last Fname in the list. - FM
+		     *	Use the last Fname in the list. - FM
 		     */
 		    FnameNum = 0;
 		} else {
 		    /*
-		     *  Go back to the previous Fname in the list. - FM
+		     *	Go back to the previous Fname in the list. - FM
 		     */
 		    FnameNum++;
 		}
 		if (FnameNum >= FnameTotal) {
 		    /*
-		     *  Reset the FirstRecall flag,
-		     *  and use sug_file or a blank. - FM
+		     *	Reset the FirstRecall flag,
+		     *	and use sug_file or a blank. - FM
 		     */
 		    FirstRecall = TRUE;
 		    FnameNum = FnameTotal;
@@ -218,13 +228,26 @@ check_recall:
 		goto retry;
 	  }
 	}
+	/*
+	 *  Cancel if the user entered "/dev/null" on Unix,
+	 *  or an "nl:" path (case-insensitive) on VMS. - FM
+	 */
+#ifdef VMS
+	if (!strncasecomp(buffer, "nl:", 3) ||
+	    !strncasecomp(buffer, "/nl/", 4))
+#else
+	if (!strcmp(buffer, "/dev/null"))
+#endif /* VMS */
+	{
+	    goto cancelled;
+	}
 	if ((cp = strchr(buffer, '~'))) {
 	    *(cp++) = '\0';
 	    strcpy(command, buffer);
 	    if ((len = strlen(command)) > 0 && command[len-1] == '/')
 	        command[len-1] = '\0';
 #ifdef DOSPATH
-		 strcat(command, HTDOS_wwwName((char *)Home_Dir()));
+	    strcat(command, HTDOS_wwwName((char *)Home_Dir()));
 #else
 #ifdef VMS
 	    strcat(command, HTVMS_wwwName((char *)Home_Dir()));
@@ -253,16 +276,18 @@ check_recall:
 	else
 	    cp = NULL;
 	if (cp) {
-            sprintf(command,"%s/%s", cp, buffer);
+            sprintf(command, "%s/%s", cp, buffer);
 #ifdef DOSPATH
-		 strcpy(buffer, HTDOS_name(command));
+	    strcpy(buffer, HTDOS_name(command));
 #else
 	    strcpy(buffer, command);
 #endif
 	}
 #endif /* VMS */
 
-	/* see if it already exists */
+	/*
+	 *  See if it already exists.
+	 */
 	if ((fp = fopen(buffer, "r")) != NULL) {
 	    fclose(fp);
 
@@ -294,7 +319,9 @@ check_recall:
 	    }
 	}
 
-	/* see if we can write to it */
+	/*
+	 *  See if we can write to it.
+	 */
 	if ((fp = fopen(buffer, "w")) != NULL) {
 	    fclose(fp);
 	    remove(buffer);
@@ -314,15 +341,23 @@ check_recall:
 	 *  Try rename() first. - FM
 	 */
 	if (TRACE)
-	    fprintf(stderr, "command: rename(%s,%s)\n", file, buffer);
+	    fprintf(stderr, "command: rename(%s, %s)\n", file, buffer);
 	if (rename(file, buffer)) {
 	    /*
 	     *  Failed.  Use spawned COPY_COMMAND. - FM
 	     */
+	    if (TRACE)
+	        fprintf(stderr, "         FAILED!\n");
 	    sprintf(command, COPY_COMMAND, file, buffer);
 	    if (TRACE)
-	        fprintf(stderr, "FAILED!\ncommand: %s\n", command);
+	        fprintf(stderr, "command: %s\n", command);
+	    fflush(stderr);
+	    fflush(stdout);
+	    stop_curses();
 	    system(command);
+	    fflush(stdout);
+	    fflush(stderr);
+	    start_curses();
 	} else {
 	    /*
 	     *  We don't have the temporary file (it was renamed to
@@ -335,20 +370,29 @@ check_recall:
 	/*
 	 *  Prevent spoofing of the shell.
 	 */
-	cp = quote_pathname(buffer);
-	sprintf(command,"%s %s %s", COPY_PATH, file, cp);
+	cp = quote_pathname(file);
+	cp1 = quote_pathname(buffer);
+	sprintf(command, "%s %s %s", COPY_PATH, cp, cp1);
 	FREE(cp);
+	FREE(cp1);
 	if (TRACE)
-	    fprintf(stderr,"command: %s\n",command);
+	    fprintf(stderr, "command: %s\n", command);
+        fflush(stderr);
+        fflush(stdout);
+        stop_curses();
 	system(command);
+        fflush(stdout);
+	fflush(stderr);
+        start_curses();
 #endif /* VMS */
+	chmod(buffer, 0600);
 
     } else {
 	/*
 	 *  Use configured download commands.
 	 */
 	buffer[0] = '\0';
-        for (count = 0, download_command = downloaders;
+        for (count = 0, download_command=downloaders;
 	     count < method_number;
        	     count++, download_command = download_command->next)
 	    ; /* null body */
@@ -460,6 +504,19 @@ check_recall:
 		        goto again;
 		    }
 	        }
+		/*
+		 *  Cancel if the user entered "/dev/null" on Unix,
+		 *  or an "nl:" path (case-insensitive) on VMS. - FM
+		 */
+#ifdef VMS
+		if (!strncasecomp(buffer, "nl:", 3) ||
+		    !strncasecomp(buffer, "/nl/", 4))
+#else
+		if (!strcmp(buffer, "/dev/null"))
+#endif /* VMS */
+		{
+		    goto cancelled;
+		}
 		SecondS = TRUE;
 	    }
 
@@ -471,14 +528,18 @@ check_recall:
 	     *  putting both names on the command line.
 	     */
 #ifdef VMS
-   	    sprintf(command, download_command->command, file, buffer);
+   	    sprintf(command, download_command->command, file, buffer,
+			     "", "", "", "", "", "", "", "", "", "");
 #else /* Unix: */
 	    /*
 	     *  Prevent spoofing of the shell.
 	     */
-	    cp = quote_pathname(buffer);
-   	    sprintf(command, download_command->command, file, cp);
+	    cp = quote_pathname(file);
+	    cp1 = quote_pathname(buffer);
+   	    sprintf(command, download_command->command, cp, cp1,
+			     "", "", "", "", "", "", "", "", "", "");
 	    FREE(cp);
+	    FREE(cp1);
 #endif /* VMS */
 
         } else {
@@ -487,11 +548,14 @@ check_recall:
 	    goto failed;
         }
 
-        stop_curses();
         if (TRACE)
             fprintf(stderr, "command: %s\n", command);
+        stop_curses();
+	fflush(stderr);
+	fflush(stdout);
         system(command);
-        fflush(stdout);
+        fflush(stderr);
+	fflush(stdout);
         start_curses();
         /* don't remove(file); */
     }
@@ -525,18 +589,17 @@ cancelled:
     sleep(InfoSecs);
     FREE(Line);
     return;
-
 }	
 
 /*
- * LYdownload_options writes out the current download choices to a file
- * so that the user can select printers in the same way that
- * they select all other links 
- * download links look like
+ *  LYdownload_options writes out the current download choices to
+ *  a file so that the user can select printers in the same way that
+ *  they select all other links.  Download links look like:
  *  LYNXDOWNLOAD://Method=<#>/File=<STRING>/SugFile=<STRING>
  */
-
-PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file)
+PUBLIC int LYdownload_options ARGS2(
+	char **,	newfile,
+	char *,		data_file)
 {
     static char tempfile[256];
     static BOOLEAN first = TRUE;
@@ -560,20 +623,21 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file)
 #endif /* VMS */
     }
 
-
-    /* get a suggested filename */
+    /*
+     *  Get a suggested filename.
+     */
     StrAllocCopy(sug_filename, *newfile);
     change_sug_filename(sug_filename);
 
-    if ((fp0 = fopen(tempfile,"w")) == NULL) {
+    if ((fp0 = fopen(tempfile, "w")) == NULL) {
 	HTAlert(CANNOT_OPEN_TEMP);
 	return(-1);
     }
     chmod(tempfile, 0600);
 
     LYstrncpy(LYValidDownloadFile,
-          data_file,
-          (sizeof(LYValidDownloadFile) - 1));
+	      data_file,
+	      (sizeof(LYValidDownloadFile) - 1));
     StrAllocCopy(*newfile, download_filename);
     LYforce_no_cache = TRUE;  /* don't cache this doc */
 
@@ -589,7 +653,9 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file)
 
     if(!no_disk_save && !child_lynx)
 #ifdef DIRED_SUPPORT
-	/* disable save to disk option for local files */
+	/*
+	 *  Disable save to disk option for local files.
+	 */
 	if (!lynx_edit_mode) 
 #endif /* DIRED_SUPPORT */
             fprintf(fp0,"   \
@@ -601,31 +667,29 @@ PUBLIC int LYdownload_options ARGS2(char **,newfile, char *,data_file)
     else
 	fprintf(fp0,"   Save to disk disabled.\n");
 
-    if(downloaders != NULL) {
-
-        for(count = 0, cur_download = downloaders; cur_download !=  NULL; 
-			    cur_download = cur_download->next, count++) {
-
-	    if(!no_download || cur_download->always_enabled) {
+    if (downloaders != NULL) {
+        for (count = 0, cur_download = downloaders; cur_download != NULL; 
+			cur_download = cur_download->next, count++) {
+	    if (!no_download || cur_download->always_enabled) {
 	        fprintf(fp0,"   \
 <a href=\"LYNXDOWNLOAD://Method=%d/File=%s/SugFile=%s\">", 
-				count,data_file,sug_filename);
-
+				count,data_file, sug_filename);
 		fprintf(fp0, (cur_download->name ? 
 				cur_download->name : "No Name Given"));
 		fprintf(fp0,"</a>\n");
 	    }
 	}
     } else {
-	fprintf(fp0, "\n   \
-No other download methods have been defined yet.  You may define\n   \
+	fprintf(fp0, "\n\
+No other download methods have been defined yet.  You may define\n\
 an unlimited number of download methods using the lynx.cfg file.\n");
-
     }
     fprintf(fp0, "</pre>\n</body>\n");
     fclose(fp0);
 
-    /* free off temp copy */
+    /*
+     *  Free off temp copy.
+     */
     FREE(sug_filename);
 
     return(0);
diff --git a/src/LYEdit.c b/src/LYEdit.c
index 98940c4e..38346c90 100644
--- a/src/LYEdit.c
+++ b/src/LYEdit.c
@@ -23,46 +23,50 @@
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 /*
- *  in edit mode invoke either emacs, vi, pico, jove, jed or the default
- *  editor to display and edit the current file
- *  emacs, vi, pico, jove and jed will open the file to the same line that
- *  the screen cursor is on when editing is invoked
- *  returns FALSE if file uneditable
+ *  In edit mode invoke either emacs, vi, pico, jove, jed sedt or the
+ *  default editor to display and edit the current file.
+ *  For emacs, vi, pico, jove and jed, Lynx will open the file to the
+ *  same line that the screen cursor is on when editing is invoked.
+ *  Returns FALSE if file is uneditable.
  */
-
-PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno)
+PUBLIC int edit_current_file ARGS3(
+	char *,		newfile,
+	int,		cur,
+	int,		lineno)
 {
+    char command[512];
+    char *filename = NULL;
+    char *colon, *number_sign;
+    FILE *fp;
 
-	char command[512];
-        char *filename = NULL;
-	char *colon, *number_sign;
-	FILE *fp;
+    /*
+     *  If its a remote file then we can't edit it.
+     */
+    if (!LYisLocalFile(newfile)) {
+	_statusline(CANNOT_EDIT_REMOTE_FILES);
+	sleep(MessageSecs);
+	return FALSE;
+    }
 
-	/*
-	 * If its a remote file then we can't edit it.
-	 */
-	if(!LYisLocalFile(newfile)) {
-	    _statusline(CANNOT_EDIT_REMOTE_FILES);
-	    sleep(MessageSecs);
-	    return FALSE;
-	}
+    /*
+     *  If there's a fragment, trim it. - FM
+     */
+    number_sign = strchr(newfile, '#');
+    if (number_sign)
+	*number_sign = '\0';
 
-	number_sign = strchr(newfile,'#');
-	if(number_sign)
-	    *number_sign = '\0';
-	   
-	 /*
-	  * On Unix, first try to open it as a completely referenced file,
-	  * then via the path alone.
-	  *
-	  * On VMS, only try the path.
-	  */
+    /*
+     *  On Unix, first try to open it as a completely referenced file,
+     *  then via the path alone.
+     *
+     * On VMS, only try the path.
+     */
 #if !defined (VMS) && !defined (DOSPATH)
-	colon = strchr(newfile,':');
-	StrAllocCopy(filename, colon+1);
-	HTUnEscape(filename);
-	if((fp = fopen(filename,"r")) == NULL) {
-	    FREE(filename);
+    colon = strchr(newfile, ':');
+    StrAllocCopy(filename, (colon + 1));
+    HTUnEscape(filename);
+    if ((fp = fopen(filename, "r")) == NULL) {
+	FREE(filename);
 #endif /* !VMS */
 	    filename = HTParse(newfile,"",PARSE_PATH+PARSE_PUNCTUATION);
 	    HTUnEscape(filename);
@@ -73,20 +77,20 @@ PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno)
 		 if ((fp = fopen(HTDOS_name(filename),"r")) == NULL) {
 #else
 #ifdef VMS
-	    if ((fp = fopen(HTVMS_name("",filename),"r")) == NULL) {
+	if ((fp = fopen(HTVMS_name("", filename), "r")) == NULL) {
 #else
-	    if ((fp = fopen(filename,"r")) == NULL) {
+	if ((fp = fopen(filename, "r")) == NULL) {
 #endif /* VMS */
 #endif /* DOSPATH */
-	        HTAlert(COULD_NOT_ACCESS_FILE);
-		FREE(filename);
-		goto failure;
-	    }
-#if !defined (VMS) && !defined (DOSPATH)
+	    HTAlert(COULD_NOT_ACCESS_FILE);
+	    FREE(filename);
+	    goto failure;
 	}
+#if !defined (VMS) && !defined (DOSPATH)
+    }
 #endif /* !VMS */
-	fclose(fp);
-		
+    fclose(fp);
+
 #if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES)
         /*
 	 * Don't allow editing if user lacks append access.
@@ -95,54 +99,87 @@ PUBLIC int edit_current_file ARGS3(char *,newfile, int,cur, int,lineno)
 	if ((fp = fopen(HTDOS_name("",filename),"a")) == NULL) {
 #else
 #ifdef VMS
-	if ((fp = fopen(HTVMS_name("",filename),"a")) == NULL) {
+    if ((fp = fopen(HTVMS_name("", filename), "a")) == NULL) {
 #else
-	if ((fp = fopen(filename,"a")) == NULL) {
+    if ((fp = fopen(filename, "a")) == NULL) {
 #endif /* VMS */
 #endif /* DOSPATH */
-		_statusline(NOAUTH_TO_EDIT_FILE);
-		sleep(MessageSecs);
-		goto failure;
-	}
-	fclose(fp);
+	_statusline(NOAUTH_TO_EDIT_FILE);
+	sleep(MessageSecs);
+	goto failure;
+    }
+    fclose(fp);
 #endif /* VMS || CANT_EDIT_UNWRITABLE_FILES */
 
+    /*
+     *  Make sure cur is at least zero. - FM
+     */
+    if (cur < 0) {
+	cur = 0;
+    }
+
+    /*
+     *  Set up the command for the editor. - FM
+     */
 #ifdef VMS
-        sprintf(command,"%s %s",editor, HTVMS_name("",filename));
+    if ((strstr(editor, "sedt") || strstr(editor, "SEDT")) &&
+	((lineno - 1) + (nlinks ? links[cur].ly : 0)) > 0) {
+	sprintf(command, "%s %s -%d",
+			 editor,
+			 HTVMS_name("", filename),
+			 ((lineno - 1) + (nlinks ? links[cur].ly : 0)));
+    } else {
+	sprintf(command, "%s %s", editor, HTVMS_name("", filename));
+    }
 #else
-	if (strstr(editor,"emacs") || strstr(editor,"vi") ||
-	    strstr(editor, "pico") || strstr(editor,"jove") ||
-	    strstr(editor, "jed"))
-	    sprintf(command,"%s +%d \"%s\"",editor, lineno+links[cur].ly, 
+    if (strstr(editor, "emacs") || strstr(editor, "vi") ||
+	strstr(editor, "pico") || strstr(editor, "jove") ||
+	strstr(editor, "jed"))
+	sprintf(command, "%s +%d \"%s\"",
+			 editor,
+			 (lineno + (nlinks ? links[cur].ly : 0)),
 #ifdef DOSPATH
-																	 HTDOS_name(filename));
+		HTDOS_name(filename));
 #else
                                                                 filename);
 #endif /* DOSPATH */
-	else
-		 sprintf(command,"%s \"%s\"",editor,
+    else
+	sprintf(command, "%s \"%s\"", editor,
 #ifdef DOSPATH
 				 HTDOS_name(filename));
 #else
 				 filename);
 #endif /* DOSPATH */
 #endif /* VMS */
-	if (TRACE) {
-	    fprintf(stderr, "LYEdit: %s\n",command);
-	    sleep(MessageSecs);
-	}
-	FREE(filename);
+    if (TRACE) {
+	fprintf(stderr, "LYEdit: %s\n", command);
+	sleep(MessageSecs);
+    }
+    FREE(filename);
 
-	stop_curses();
-	system(command);
-	start_curses();
+    /*
+     *  Invoke the editor. - FM
+     */
+    fflush(stderr);
+    fflush(stdout);
+    stop_curses();
+    system(command);
+    fflush(stdout);
+    fflush(stderr);
+    start_curses();
 
-	if(number_sign)
-	    *number_sign = '#';
-	return TRUE;
+    /*
+     *  Restore the fragment if there was one. - FM
+     */
+    if (number_sign)
+	*number_sign = '#';
+    return TRUE;
 
 failure:
-	if(number_sign)
-	    *number_sign = '#';
-	return FALSE;
+    /*
+     *  Restore the fragment if there was one. - FM
+     */
+    if (number_sign)
+	*number_sign = '#';
+    return FALSE;
 }
diff --git a/src/LYExtern.c b/src/LYExtern.c
index 7ec3f5d8..cbe7ac3d 100644
--- a/src/LYExtern.c
+++ b/src/LYExtern.c
@@ -15,7 +15,6 @@
  See lynx.cfg for other info.
 */
 
-#ifdef USE_EXTERNALS
 #include "tcp.h"
 #include "LYGlobalDefs.h"
 #include "LYUtils.h"
@@ -23,6 +22,7 @@
 
 #include "LYLeaks.h"
 
+#ifdef USE_EXTERNALS
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 void run_external(char * c)
diff --git a/src/LYExtern.h b/src/LYExtern.h
index be9d1562..09983b47 100644
--- a/src/LYExtern.h
+++ b/src/LYExtern.h
@@ -1,10 +1,10 @@
-#ifndef EXTERNALS_H

+#ifndef EXTERNALS_H
 #define EXTERNALS_H
 
 #ifndef LYSTRUCTS_H
-#include "LYStructs.h"

-#endif /* LYSTRUCTS_H */

+#include "LYStructs.h"
+#endif /* LYSTRUCTS_H */
 
-void run_external(char * c);
+void run_external PARAMS((char * c));
 
-#endif /* EXTERNALS_H */

+#endif /* EXTERNALS_H */
diff --git a/src/LYForms.c b/src/LYForms.c
index 281612bc..83f41bf0 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -6,7 +6,7 @@
 #include "LYCurses.h"
 #include "GridText.h"
 #include "LYUtils.h"
-#include "LYStructs.h"  /* includes HTForms.h */
+#include "LYStructs.h"	/* includes HTForms.h */
 #include "LYStrings.h"
 #include "LYGlobalDefs.h"
 #include "LYKeymap.h"
@@ -33,18 +33,29 @@
 
 extern HTCJKlang HTCJK;
 
-PRIVATE int form_getstr PARAMS((struct link * form_link));
-PRIVATE int popup_options PARAMS((int cur_selection, OptionType *list, 
-				  int ly, int lx, int width,
-				  int i_length, int disabled));
-
-PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, 
-				  document *,newdoc, BOOLEAN *,refresh_screen,
-				  char *,link_name, char *,link_value)
+PRIVATE int form_getstr PARAMS((
+	struct link *	form_link));
+PRIVATE int popup_options PARAMS((
+	int		cur_selection,
+	OptionType *	list, 
+	int		ly,
+	int		lx,
+	int		width,
+	int		i_length,
+	int		disabled));
+
+PUBLIC int change_form_link ARGS6(
+	struct link *,	form_link,
+	int,		mode, 
+	document *,	newdoc,
+	BOOLEAN *,	refresh_screen,
+	char *,		link_name,
+	char *,		link_value)
 {
     extern BOOL reloading;
     FormInfo *form = form_link->form;
-    int c=DO_NOTHING;
+    int c = DO_NOTHING;
+    int OrigNumValue;
 
 	/*
 	 *  If there is no form to perform action on, don't do anything.
@@ -53,13 +64,15 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	    return(c);
 	}
 
-    /* move to the link position */
+    /*
+     *  Move to the link position.
+     */
     move(form_link->ly, form_link->lx);
 
     switch(form->type) {
 	case F_CHECKBOX_TYPE:
 	    if (form->disabled == YES)
-	        break;
+		break;
 	    if (form->num_value) {
 		form_link->hightext = unchecked_box;
 		form->num_value = 0;
@@ -71,66 +84,99 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 
 	case F_OPTION_LIST_TYPE:
 	    if (!form->select_list) {
-	        HTAlert(BAD_HTML_NO_POPUP);
+		HTAlert(BAD_HTML_NO_POPUP);
 		c = DO_NOTHING;
 		break;
 	    }
 
 	    if (form->disabled == YES) {
-	        int dummy;
+		int dummy;
 		dummy = popup_options(form->num_value, form->select_list,
 				form_link->ly, form_link->lx, form->size,
 				form->size_l, form->disabled);
-	        c = 12;  /* CTRL-L for repaint */
-	        break;
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+		if (!enable_scrollback)
+#if defined(VMS) && !defined(USE_SLANG)
+		    c = DO_NOTHING;
+#else
+		    c = 23;  /* CTRL-W for repaint */
+#endif /* VMS && !USE_SLANG */
+		else
+#endif /* FANCY_CURSES || USE_SLANG */
+		    c = 12;  /* CTRL-L for repaint */
+		break;
 	    }
+	    OrigNumValue = form->num_value;
 	    form->num_value = popup_options(form->num_value, form->select_list,
 				form_link->ly, form_link->lx, form->size,
 				form->size_l, form->disabled);
 
 	    {
-    	        OptionType * opt_ptr=form->select_list;
+    	        OptionType * opt_ptr = form->select_list;
 		int i;
-    	        for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) 
+		for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next)
 		    ; /* null body */
-		form->value = opt_ptr->name;   /* set the name */
-		form->cp_submit_value = opt_ptr->cp_submit_value; /* set the value */
+		/*
+		 *  Set the name.
+		 */
+		form->value = opt_ptr->name;
+		/*
+		 *  Set the value.
+		 */
+		form->cp_submit_value = opt_ptr->cp_submit_value;
 	    }
-	    c = 12;  /* CTRL-L for repaint */
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+	    if (!enable_scrollback && form->num_value == OrigNumValue)
+#if defined(VMS) && !defined(USE_SLANG)
+		c = DO_NOTHING;
+#else
+		c = 23;  /* CTRL-W for repaint */
+#endif /* VMS && !USE_SLANG */
+	    else
+#endif /* FANCY_CURSES || USE_SLANG */
+		c = 12;  /* CTRL-L for repaint */
 	    break;
 
 	case F_RADIO_TYPE:
 	    if (form->disabled == YES)
-	        break;
-		/* radio buttons must have one and
-		 * only one down at a time! 
+		break;
+		/*
+		 *  Radio buttons must have one and
+		 *  only one down at a time!
 		 */
 	    if (form->num_value) {
 		_statusline(NEED_CHECKED_RADIO_BUTTON);
 		sleep(MessageSecs);
 
-	    } else {	
+	    } else {
 		int i;
-		/* run though list of the links on the screen and
-		 * unselect any that are selected. :) 
+		/*
+		 *  Run though list of the links on the screen and
+		 *  unselect any that are selected. :)
 		 */
 		lynx_start_radio_color ();
-		for (i = 0; i < nlinks; i++)
-		   if (links[i].type == WWW_FORM_LINK_TYPE &&
-		       links[i].form->type == F_RADIO_TYPE &&
-		        links[i].form->number == form->number &&
-   		         /* if it has the same name and its on */
-                          !strcmp(links[i].form->name, form->name) &&
-                            links[i].form->num_value ) 
-		     {
+		for (i = 0; i < nlinks; i++) {
+		    if (links[i].type == WWW_FORM_LINK_TYPE &&
+		        links[i].form->type == F_RADIO_TYPE &&
+			links[i].form->number == form->number &&
+			/*
+			 *  If it has the same name and its on...
+			 */
+			!strcmp(links[i].form->name, form->name) &&
+			links[i].form->num_value) {
 			move(links[i].ly, links[i].lx);
 			addstr(unchecked_radio);
 			links[i].hightext = unchecked_radio;
 		     }
+		}
 		lynx_stop_radio_color ();
-		/* will unselect other button and select this one */
+		/*
+		 *  Will unselect other button and select this one.
+		 */
 		HText_activateRadioButton(form);
-		/* now highlight this one */
+		/*
+		 *  Now highlight this one.
+		 */
 		form_link->hightext = checked_radio;
 	    }
 	    break;
@@ -139,28 +185,28 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 	case F_TEXTAREA_TYPE:
 	case F_PASSWORD_TYPE:
 	    c = form_getstr(form_link);
-	    if (form->type == F_PASSWORD_TYPE) 
-        	form_link->hightext = STARS(strlen(form->value));
+	    if (form->type == F_PASSWORD_TYPE)
+		form_link->hightext = STARS(strlen(form->value));
 	    else
-	    	form_link->hightext = form->value;
+		form_link->hightext = form->value;
 	    break;
 
 	case F_RESET_TYPE:
 	    if (form->disabled == YES)
-	        break;
+		break;
 	    HText_ResetForm(form);
-            *refresh_screen = TRUE;
+	    *refresh_screen = TRUE;
 	    break;
-	
+
 	case F_TEXT_SUBMIT_TYPE:
 	    c = form_getstr(form_link);
 	    if (form->disabled == YES &&
-	        (c == '\r' || c == '\n')) {
-	        c = '\t';
+		(c == '\r' || c == '\n')) {
+		c = '\t';
 		break;
 	    }
 	    if (c == '\r' || c == '\n') {
-	        form_link->hightext = form->value;
+		form_link->hightext = form->value;
 		if (!form->submit_action || *form->submit_action == '\0') {
 		    _statusline(NO_FORM_ACTION);
 		    sleep(MessageSecs);
@@ -172,41 +218,43 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 		    break;
 		} else {
 		    if (form->no_cache &&
-		        form->submit_method != URL_MAIL_METHOD) {
-		        LYforce_no_cache = TRUE;
+			form->submit_method != URL_MAIL_METHOD) {
+			LYforce_no_cache = TRUE;
 			reloading = TRUE;
 		    }
-	            HText_SubmitForm(form, newdoc, link_name, form->value);
+		    HText_SubmitForm(form, newdoc, link_name, form->value);
 		}
-		if (form->submit_method == URL_MAIL_METHOD)
+		if (form->submit_method == URL_MAIL_METHOD) {
 		    *refresh_screen = TRUE;
-		else {
-	            /* returns new document URL */
-	            newdoc->link = 0;
+		} else {
+		    /*
+		     *  Returns new document URL.
+		     */
+		    newdoc->link = 0;
 		    newdoc->internal_link = FALSE;
 		}
 		c = DO_NOTHING;
 		break;
 	    } else {
-	    	form_link->hightext = form->value;
+		form_link->hightext = form->value;
 	    }
 	    break;
 
 	case F_SUBMIT_TYPE:
 	case F_IMAGE_SUBMIT_TYPE:
 	    if (form->disabled == YES)
-	        break;
+		break;
 	    if (form->no_cache &&
-	        form->submit_method != URL_MAIL_METHOD) {
+		form->submit_method != URL_MAIL_METHOD) {
 		LYforce_no_cache = TRUE;
 		reloading = TRUE;
 	    }
 	    HText_SubmitForm(form, newdoc, link_name, link_value);
 	    if (form->submit_method == URL_MAIL_METHOD)
-                *refresh_screen = TRUE;
+		*refresh_screen = TRUE;
 	    else {
-	        /* returns new document URL */
-	        newdoc->link = 0;
+		/* returns new document URL */
+		newdoc->link = 0;
 		newdoc->internal_link = FALSE;
 	    }
 	    break;
@@ -215,76 +263,116 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode,
 
     return(c);
 
-} 
-
-#ifdef USE_SLANG
-#define GetYX(y,x)   y = SLsmg_get_row(), x = SLsmg_get_column()
-#else
-#ifdef getyx
-#define GetYX(y,x)   getyx(stdscr,y,x)
-#else
-#define GetYX(y,x)   y = stdscr->_cury, x = stdscr->_curx
-#endif /* getyx */
-#endif /* USE_SLANG */
-
-PRIVATE int form_getstr ARGS1(struct link *, form_link)
+}
+PRIVATE int form_getstr ARGS1(
+	struct link *,	form_link)
 {
     FormInfo *form = form_link->form;
+    char *value = form->value;
     int ch;
     int far_col;
-    int max_length = (form->maxlength ? form->maxlength : 1023);
+    int max_length;
     int startcol, startline;
     BOOL HaveMaxlength = FALSE;
+    int action;
 
 #ifdef VMS
-    extern BOOLEAN HadVMSInterrupt;/* Flag from cleanup_sig() AST       */
+    extern BOOLEAN HadVMSInterrupt;	/* Flag from cleanup_sig() AST */
 #endif
 
     EditFieldData MyEdit;
-    BOOLEAN Edited = FALSE;       /* Value might be updated? */
-
-    /* get the initial position of the cursor */
-    GetYX(startline, startcol);
+    BOOLEAN Edited = FALSE;		/* Value might be updated? */
 
-    if (startcol + form->size > LYcols-1)
-	far_col = LYcols-1;
+    /*
+     *  Get the initial position of the cursor.
+     */
+    LYGetYX(startline, startcol);
+    if ((startcol + form->size) > (LYcols - 1))
+	far_col = (LYcols - 1);
     else
-	far_col = startcol + form->size;
+	far_col = (startcol + form->size);
 
-    /* Print panned line */
+    /*
+     *  Make sure the form field value does not exceed our buffer. - FM
+     */
+    max_length = ((form->maxlength > 0 &&
+		   form->maxlength < sizeof(MyEdit.buffer)) ?
+					    form->maxlength :
+					    (sizeof(MyEdit.buffer) - 1));
+    if (strlen(form->value) > max_length) {
+	/*
+	 *  We can't fit the entire value into the editing buffer,
+	 *  so enter as much of the tail as fits. - FM
+	 */
+	value += (strlen(form->value) - max_length);
+	if (!form->disabled &&
+	    !(form->submit_method == URL_MAIL_METHOD && no_mail)) {
+	    /*
+	     *  If we can edit it, report that we are using the tail. - FM
+	     */
+	    _statusline(FORM_VALUE_TOO_LONG);
+	    sleep(MessageSecs);
+	    switch(form->type) {
+		case F_PASSWORD_TYPE:
+		    statusline(FORM_LINK_PASSWORD_MESSAGE);
+		    break;
+		case F_TEXT_SUBMIT_TYPE:
+		    if (form->submit_method == URL_MAIL_METHOD) {
+			statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_MSG);
+		    } else if (form->no_cache) {
+			statusline(FORM_LINK_TEXT_RESUBMIT_MESSAGE);
+		    } else {
+			statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE);
+		    }
+		    break;
+		case F_TEXT_TYPE:
+		case F_TEXTAREA_TYPE:
+		    statusline(FORM_LINK_TEXT_MESSAGE);
+		    break;
+		default:
+		    break;
+	    }
+	    move(startline, startcol);
+	}
+    }
 
-    LYSetupEdit(&MyEdit, form->value, max_length, far_col-startcol);
-    MyEdit.pad='_';
+    /*
+     *  Print panned line
+     */
+    LYSetupEdit(&MyEdit, value, max_length, (far_col - startcol));
+    MyEdit.pad = '_';
     MyEdit.hidden = (form->type == F_PASSWORD_TYPE);
     LYRefreshEdit(&MyEdit);
 
-    /* And go for it.. */
-
+    /*
+     *  And go for it!
+     */
     for (;;) {
 again:
-        ch = LYgetch();
+	ch = LYgetch();
 #ifdef VMS
-        if (HadVMSInterrupt) {
+	if (HadVMSInterrupt) {
 	    HadVMSInterrupt = FALSE;
 	    ch = 7;
 	}
 #endif /* VMS */
 
 	/*
-	 * Filter out global navigation keys that should not be passed
-	 * to line editor, and LYK_REFRESH.
+	 *  Filter out global navigation keys that should not be passed
+	 *  to line editor, and LYK_REFRESH.
 	 */
-	if (EditBinding(ch) == LYE_ENTER)
+	action = EditBinding(ch);
+	if (action == LYE_ENTER)
 	    break;
-	if (EditBinding(ch) == LYE_AIX && HTCJK == NOCJK)
+	if (action == LYE_AIX && HTCJK == NOCJK)
 	    break;
-        if (EditBinding(ch) == LYE_TAB)
-	  {
+	if (action == LYE_TAB) {
 	    ch = (int)('\t');
 	    break;
-	  }
-	if (EditBinding(ch) == LYE_ABORT)
+	}
+	if (action == LYE_ABORT) {
 	    return(DO_NOTHING);
+	}
 	if (keymap[ch + 1] == LYK_REFRESH)
 	    goto breakfor;
 	switch (ch) {
@@ -298,31 +386,24 @@ again:
 	    case FIND_KEY:
 	    case SELECT_KEY:
 #endif /* NOTDEFINED */
-                goto breakfor;
+		goto breakfor;
 
 	    /*
-	     * Left arrrow in column 0 deserves special treatment here,
-	     * else you can get trapped in a form without submit button!
+	     *  Left arrrow in column 0 deserves special treatment here,
+	     *  else you can get trapped in a form without submit button!
 	     */
 	    case LTARROW:
-	        if (MyEdit.pos==0) {
-		    int c='Y';	/* Go back immediately if no changes */
-		    if (strcmp(MyEdit.buffer, form->value)) {
-		        _statusline(PREV_DOC_QUERY);
-			c=LYgetch();
+		if (MyEdit.pos == 0) {
+		    int c = 'Y';    /* Go back immediately if no changes */
+		    if (strcmp(MyEdit.buffer, value)) {
+			_statusline(PREV_DOC_QUERY);
+			c = LYgetch();
 		    }
 		    if (TOUPPER(c) == 'Y') {
-#ifdef NOTDEFINED
-			/*
-			 * Why not just keep what we have??
-			 * We don't erase the other fields either??
-			 */
-			StrAllocCopy(form->value, "");
-#endif /* NOTDEFINED */
 			return(ch);
 		    } else {
-		        if (form->disabled == YES)
-		            _statusline(ARROWS_OR_TAB_TO_MOVE);
+			if (form->disabled == YES)
+			    _statusline(ARROWS_OR_TAB_TO_MOVE);
 			else
 			    _statusline(ENTER_TEXT_ARROWS_OR_TAB);
 		    }
@@ -332,9 +413,10 @@ again:
 	    default:
 		if (form->disabled == YES)
 		    goto again;
-		/* Make sure the statusline uses editmode help... */
-		Edited = TRUE;
-		LYLineEdit(&MyEdit,ch,TRUE);
+		/*
+		 *  Make sure the statusline uses editmode help.
+		 */
+		LYLineEdit(&MyEdit, ch, TRUE);
 		if (MyEdit.strlen >= max_length) {
 		    HaveMaxlength = TRUE;
 		} else if (HaveMaxlength &&
@@ -342,30 +424,91 @@ again:
 		    HaveMaxlength = FALSE;
 		    _statusline(ENTER_TEXT_ARROWS_OR_TAB);
 		}
+		if (strcmp(value, MyEdit.buffer)) {
+		    Edited = TRUE;
+		}
 		LYRefreshEdit(&MyEdit);
 	}
     }
 breakfor:
     if (Edited) {
-        char  *p;
-	StrAllocCopy(form->value, MyEdit.buffer);
+	char  *p;
+
+	/*
+	 *  Load the new value.
+	 */
+	if (value == form->value) {
+	    /*
+	     *  The previous value did fit in the line buffer,
+	     *  so replace it with the new value. - FM
+	     */
+	    StrAllocCopy(form->value, MyEdit.buffer);
+	} else {
+	    /*
+	     *  Combine the modified tail with the unmodified head. - FM
+	     */
+	    form->value[(strlen(form->value) - strlen(value))] = '\0';
+	    StrAllocCat(form->value, MyEdit.buffer);
+	    _statusline(FORM_TAIL_COMBINED_WITH_HEAD);
+	    sleep(MessageSecs);
+	}
 
 	/*
-	 * Remove trailing spaces
+	 *  Remove trailing spaces
 	 *
-	 * Do we really need to do that here? Trailing spaces will only
-	 * be there if user keyed them in. Rather rude to throw away
-	 * their hard earned spaces. Better deal with trailing spaces
-	 * when submitting the form????
+	 *  Do we really need to do that here? Trailing spaces will only
+	 *  be there if user keyed them in. Rather rude to throw away
+	 *  their hard earned spaces. Better deal with trailing spaces
+	 *  when submitting the form????
 	 */
 	p = &(form->value[strlen(form->value)]);
-	while ((p != form->value) && (p[-1]==' '))
+	while ((p != form->value) && (p[-1] == ' '))
 	    p--;
 	*p = '\0';
     }
     return(ch);
 }
 
+/*
+**  This function prompts for an option or page number.
+**  If a 'g' or 'p' suffix is included, that will be
+**  loaded into c.  Otherwise, c is zeroed. - FM & LE
+*/
+PRIVATE int get_popup_option_number ARGS1(
+	int *,		c)
+{
+    char temp[120];
+
+    /*
+     *  Load the c argument into the prompt buffer.
+     */
+    temp[0] = *c;
+    temp[1] = '\0';
+    _statusline(SELECT_OPTION_NUMBER);
+
+    /*
+     *  Get the number, possibly with a suffix, from the user.
+     */
+    if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) {
+	_statusline(CANCELLED);
+	sleep(InfoSecs);
+	*c = '\0';
+	return(0);
+    }
+
+    /*
+     *  If we had a 'g' or 'p' suffix, load it into c.
+     *  Otherwise, zero c.  Then return the number.
+     */
+    if (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL) {
+	*c = 'g';
+    } else if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) {
+	*c = 'p';
+    } else {
+	*c = '\0';
+    }
+    return(atoi(temp));
+}
 
 /* Use this rather than the 'wprintw()' function to write a blank-padded
  * string to the given window, since someone's asserted that printw doesn't
@@ -378,7 +521,7 @@ breakfor:
 PRIVATE void paddstr ARGS3(
 	WINDOW *,	the_window,
 	int,		width,
-	char *,		the_string)
+	char *, 	the_string)
 {
 	width -= strlen(the_string);
 	waddstr(the_window, the_string);
@@ -411,10 +554,11 @@ PRIVATE int popup_options ARGS7(
     OptionType * opt_ptr = list;
     int window_offset = 0;
     int display_lines;
+    int npages;
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
 #endif /* VMS */
-    static char prev_target[512]; 		/* Search string buffer */
+    static char prev_target[512];		/* Search string buffer */
     static char prev_target_buffer[512];	/* Next search buffer */
     static BOOL first = TRUE;
     char *cp;
@@ -424,6 +568,8 @@ PRIVATE int popup_options ARGS7(
     BOOLEAN FirstRecall = TRUE;
     OptionType * tmp_ptr;
     BOOLEAN ReDraw = FALSE;
+    int number;
+    char buffer[512];
 
     /*
      * Initialize the search string buffer. - FM
@@ -440,17 +586,17 @@ PRIVATE int popup_options ARGS7(
     /*
      *  Set display_lines based on the user_mode global.
      */
-    if (user_mode==NOVICE_MODE)
+    if (user_mode == NOVICE_MODE)
         display_lines = LYlines-4;
     else
-        display_lines = LYlines-2;
+	display_lines = LYlines-2;
 
     /*
      *  Counting the number of options to be displayed.
      *   num_options ranges 0...n
      */
     for (; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next)
-         ; /* null body */
+	 ; /* null body */
 
     /*
      *  Let's assume for the sake of sanity that ly is the number
@@ -473,8 +619,7 @@ PRIVATE int popup_options ARGS7(
      */
     if (!i_length) {
         i_length = num_options;
-    }
-    else {
+    } else {
         /*
 	 *  Otherwise, it is really one number too high.
 	 */
@@ -489,18 +634,18 @@ PRIVATE int popup_options ARGS7(
     bottom = top + i_length + 3;
 
     /*
-     *  Hmm...  If the bottom goes beyond the number of lines available,
+     *  Hmm...	If the bottom goes beyond the number of lines available,
      */
     if (bottom > display_lines) {
-        /*
+	/*
 	 *  Position the window at the top if we have more
 	 *  options than will fit in the window.
 	 */
 	if (i_length+3 > display_lines) {
 	    top = 0;
-            bottom = top + i_length+3;
+	    bottom = top + i_length+3;
 	    if (bottom > display_lines)
-	        bottom = display_lines + 1;
+		bottom = display_lines + 1;
 	} else {
 	    /*
 	     *  Try to position the window so that the selected option will
@@ -522,7 +667,7 @@ PRIVATE int popup_options ARGS7(
      *  Move the window down if it's too high.
      */
     if (bottom < ly + 2) {
-        bottom = ly + 2;
+	bottom = ly + 2;
 	if (bottom > display_lines + 1)
 	    bottom = display_lines + 1;
 	top = bottom - length - 2;
@@ -532,11 +677,13 @@ PRIVATE int popup_options ARGS7(
      *  Set up the overall window, including the boxing characters ('*'),
      *  if it all fits.  Otherwise, set up the widest window possible. - FM
      */
-#ifndef USE_SLANG
-    if (!(form_window = newwin(bottom - top, width+4, top, lx - 1)) &&
+#ifdef USE_SLANG
+    SLsmg_fill_region(top, lx - 1, bottom - top, width + 4, ' ');
+#else
+    if (!(form_window = newwin(bottom - top, width + 4, top, lx - 1)) &&
         !(form_window = newwin(bottom - top, 0, top, 0))) {
 	HTAlert(POPUP_FAILED);
-        return(orig_selection);
+	return(orig_selection);
     }
     scrollok(form_window, TRUE);
 #ifdef NCURSES
@@ -548,9 +695,7 @@ PRIVATE int popup_options ARGS7(
     wbkgd(form_window, getbkgd(stdscr));
 #endif
 #endif
-#else
-    SLsmg_fill_region (top, lx - 1, bottom - top, width + 4, ' ');
-#endif /* !USE_SLANG */
+#endif /* USE_SLANG */
 
     /*
      *  Set up the window_offset for options.
@@ -558,14 +703,20 @@ PRIVATE int popup_options ARGS7(
      *   length ranges from 0...m
      */
     if (cur_selection >= length) {
-        window_offset = cur_selection - length + 1;
+	window_offset = cur_selection - length + 1;
     }
 
+    /*
+     *  Compute the number of popup window pages. - FM
+     */
+    npages = ((num_options + 1) > length) ?
+		(((num_options + 1) + (length - 1))/(length))
+					  : 1;
 /*
- * OH!  I LOVE GOTOs! hack hack hack
- *        07-11-94 GAB
- *      MORE hack hack hack
- *        09-05-94 FM
+ * OH!	I LOVE GOTOs! hack hack hack
+ *    07-11-94 GAB
+ *  MORE hack hack hack
+ *    09-05-94 FM
  */
 redraw:
     opt_ptr = list;
@@ -574,17 +725,19 @@ redraw:
      *  Display the boxed options.
      */
     for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) {
-        if (i >= window_offset && i - window_offset < length) {
-#ifndef USE_SLANG
-	    wmove(form_window,(i+1)-window_offset,2);
-	    paddstr(form_window, width, opt_ptr->name);
+	if (i >= window_offset && i - window_offset < length) {
+#ifdef USE_SLANG
+	    SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2));
+	    SLsmg_write_nstring(opt_ptr->name, width);
 #else
-	    SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2);
-	    SLsmg_write_nstring (opt_ptr->name, width);
-#endif /* !USE_SLANG */
+	    wmove(form_window, ((i + 1) - window_offset), 2);
+	    paddstr(form_window, width, opt_ptr->name);
+#endif /* USE_SLANG */
 	}
     }
-#ifndef USE_SLANG
+#ifdef USE_SLANG
+    SLsmg_draw_box(top, (lx - 1), (bottom - top), (width + 4));
+#else
 #ifdef VMS
     VMSbox(form_window, (bottom - top), (width + 4));
 #else
@@ -597,9 +750,7 @@ redraw:
 #endif
 #endif /* VMS */
     wrefresh(form_window);
-#else
-    SLsmg_draw_box (top, lx - 1, bottom - top, width + 4);
-#endif /* !USE_SLANG */
+#endif /* USE_SLANG */
     opt_ptr = NULL;
 
     /*
@@ -607,39 +758,68 @@ redraw:
      */
     while (cmd != LYK_ACTIVATE) {
 
-        /*
+	/*
 	 *  Unreverse cur selection.
 	 */
 	if (opt_ptr != NULL) {
-#ifndef USE_SLANG
-	    wmove(form_window,(i+1)-window_offset,2);
-            paddstr(form_window, width, opt_ptr->name);
+#ifdef USE_SLANG
+	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
+	    SLsmg_write_nstring(opt_ptr->name, width);
 #else
-	    SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2);
-	    SLsmg_write_nstring (opt_ptr->name, width);
-#endif /* !USE_SLANG */
+	    wmove(form_window, ((i + 1) - window_offset), 2);
+	    paddstr(form_window, width, opt_ptr->name);
+#endif /* USE_SLANG */
 	}
 
-        opt_ptr = list;
+	opt_ptr = list;
 
-        for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next) 
+	for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next)
 	    ; /* null body */
 
-#ifndef USE_SLANG
-        wstart_reverse(form_window);
-        wmove(form_window,(i+1)-window_offset,2);
-        paddstr(form_window, width, opt_ptr->name);
-        wstop_reverse(form_window);
-        wrefresh(form_window);
+#ifdef USE_SLANG
+	SLsmg_set_color(2);
+	SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
+	SLsmg_write_nstring(opt_ptr->name, width);
+	SLsmg_set_color(0);
+	/*
+	 *  If LYShowCursor is ON, move the cursor to the left
+	 *  of the current option, so that blind users, who are
+	 *  most likely to have LYShowCursor ON, will have it's
+	 *  string spoken or passed to the braille interface as
+	 *  each option is made current.  Otherwise, move it to
+	 *  the bottom, right column of the screen, to "hide"
+	 *  the cursor as for the main document, and let sighted
+	 *  users rely on the current option's highlighting or
+	 *  color without the distraction of a blinking cursor
+	 *  in the window. - FM
+	 */
+	if (LYShowCursor)
+	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 1));
+	else
+	    SLsmg_gotorc((LYlines - 1), (LYcols - 1));
+	SLsmg_refresh();
 #else
-        SLsmg_set_color (2);
-        SLsmg_gotorc (top + (i+1)-window_offset, lx - 1 + 2);
-        SLsmg_write_nstring (opt_ptr->name, width);
-        SLsmg_set_color (0);
-        SLsmg_refresh ();
-#endif /* !USE_SLANG  */
-
-        c = LYgetch();
+	wstart_reverse(form_window);
+	wmove(form_window, ((i + 1) - window_offset), 2);
+	paddstr(form_window, width, opt_ptr->name);
+	wstop_reverse(form_window);
+	/*
+	 *  If LYShowCursor is ON, move the cursor to the left
+	 *  of the current option, so that blind users, who are
+	 *  most likely to have LYShowCursor ON, will have it's
+	 *  string spoken or passed to the braille interface as
+	 *  each option is made current.  Otherwise, leave it to
+	 *  the right of the current option, since we can't move
+	 *  it out of the window, and let sighted users rely on
+	 *  the highlighting of the current option without the
+	 *  distraction of a blinking cursor preceding it. - FM
+	 */
+	if (LYShowCursor)
+	    wmove(form_window, ((i + 1) - window_offset), 1);
+	wrefresh(form_window);
+#endif /* USE_SLANG  */
+
+	c = LYgetch();
 	if (c == 3 || c == 7)	/* Control-C or Control-G */
 	    cmd = LYK_QUIT;
 	else
@@ -651,35 +831,220 @@ redraw:
 	}
 #endif /* VMS */
 
-        switch(cmd) {
-            case LYK_PREV_LINK:
+	switch(cmd) {
+	    case LYK_F_LINK_NUM:
+		c = '\0';
+	    case LYK_1:
+	    case LYK_2:
+	    case LYK_3:
+	    case LYK_4:
+	    case LYK_5:
+	    case LYK_6:
+	    case LYK_7:
+	    case LYK_8:
+	    case LYK_9:
+		/*
+		 *  Get a number from the user, possibly with
+		 *  a 'g' or 'p' suffix (which will be loaded
+		 *  into c). - FM & LE
+		 */
+		number = get_popup_option_number((int *)&c);
+
+		/*
+		 *  Check for a 'p' suffix. - FM
+		 */
+		if (c == 'p') {
+		    /*
+		     *  Treat 1 or less as the first page. - FM
+		     */
+		    if (number <= 1) {
+			if (window_offset == 0) {
+			    _statusline(ALREADY_AT_OPTION_BEGIN);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				_statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			    } else {
+				_statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			    }
+			    break;
+			}
+			window_offset = 0;
+			cur_selection = 0;
+			if (disabled) {
+			    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			} else {
+			    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			}
+			goto redraw;
+		    }
+
+		    /*
+		     *  Treat a number equal to or greater than the
+		     *  number of pages as the last page. - FM
+		     */
+		    if (number >= npages) {
+			if (window_offset >= ((num_options - length) + 1)) {
+			    _statusline(ALREADY_AT_OPTION_END);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				_statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			    } else {
+				_statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			    }
+			    break;
+			}
+			window_offset = ((npages - 1) * length);
+			if (window_offset > (num_options - length)) {
+			    window_offset = (num_options - length + 1);
+			}
+			if (cur_selection < window_offset)
+			    cur_selection = window_offset;
+			if (disabled) {
+			    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			} else {
+			    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			}
+			goto redraw;
+		    }
+
+		    /*
+		     *  We want an intermediate page. - FM
+		     */
+		    if (((number - 1) * length) == window_offset) {
+			sprintf(buffer, ALREADY_AT_OPTION_PAGE, number);
+			_statusline(buffer);
+			sleep(MessageSecs);
+			if (disabled) {
+			    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			} else {
+			    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			}
+			break;
+		    }
+		    cur_selection = window_offset = ((number - 1) * length);
+		    if (disabled) {
+			_statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+		    } else {
+			_statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+		    }
+		    goto redraw;
+
+		}
+
+		/*
+		 *  Check for a positive number, which signifies
+		 *  that an option should be sought. - FM
+		 */
+		if (number > 0) {
+		    /*
+		     *  Decrement the number so as to correspond
+		     *  with our cur_selection values. - FM
+		     */
+		    number--;
+
+		    /*
+		     *  If the number is in range and had no legal
+		     *  suffix, select the indicated option. - FM
+		     */
+		    if (number <= num_options && c == '\0') {
+			cur_selection = number;
+			cmd = LYK_ACTIVATE;
+			break;
+		    }
+
+		    /*
+		     *  Verify that we had a 'g' suffix,
+		     *  and act on the number. - FM
+		     */
+		    if (c == 'g') {
+			if (cur_selection == number) {
+			    /*
+			     *  The option already is current. - FM
+			     */
+			    sprintf(buffer,
+				    OPTION_ALREADY_CURRENT, (number + 1));
+			    _statusline(buffer);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				_statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			    } else {
+				_statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			    }
+			    break;
+			}
+
+			if (number <= num_options) {
+			    /*
+			     *  The number is in range and had a 'g'
+			     *  suffix, so make it the current option,
+			     *  scrolling if needed. - FM
+			     */
+			    j = (number - cur_selection);
+			    cur_selection = number;
+			    if ((j > 0) &&
+				(cur_selection - window_offset) >= length) {
+				window_offset += j;
+				if (window_offset > (num_options - length + 1))
+				    window_offset = (num_options - length + 1);
+			    } else if ((cur_selection - window_offset) < 0) {
+				window_offset -= abs(j);
+				if (window_offset < 0)
+				    window_offset = 0;
+			    }
+			    if (disabled) {
+				_statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+			    } else {
+				_statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+			    }
+			    goto redraw;
+			}
+
+			/*
+			 *  Not in range. - FM
+			 */
+			_statusline(BAD_OPTION_NUM_ENTERED);
+			sleep(MessageSecs);
+		    }
+		}
+
+		/*
+		 *  Restore the popup statusline. - FM
+		 */
+		if (disabled) {
+		    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
+		} else {
+		    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
+		}
+		break;
+
+	    case LYK_PREV_LINK:
 	    case LYK_UP_LINK:
 
 		if (cur_selection > 0)
 		    cur_selection--;
 
 		/*
-		 *  Scroll the window up if neccessary.
+		 *  Scroll the window up if necessary.
 		 */
 		if ((cur_selection - window_offset) < 0) {
 		    window_offset--;
 		    goto redraw;
 		}
-                break;
+		break;
 
-            case LYK_NEXT_LINK:
+	    case LYK_NEXT_LINK:
 	    case LYK_DOWN_LINK:
 		if (cur_selection < num_options)
-                    cur_selection++;
+		    cur_selection++;
 
 		/*
-		 *  Scroll the window down if neccessary
+		 *  Scroll the window down if necessary
 		 */
 		if ((cur_selection - window_offset) >= length) {
 		    window_offset++;
 		    goto redraw;
 		}
-                break;
+		break;
 
 	    case LYK_NEXT_PAGE:
 		/*
@@ -700,7 +1065,7 @@ redraw:
 		     */
 		    window_offset += length;
 		    if (window_offset > (num_options - length)) {
-		        window_offset = (num_options - length + 1);
+			window_offset = (num_options - length + 1);
 		    }
 
 		    /*
@@ -738,7 +1103,7 @@ redraw:
 		     */
 		    window_offset -= length;
 		    if (window_offset < 0) {
-		        window_offset = 0;
+			window_offset = 0;
 		    }
 
 		    /*
@@ -756,7 +1121,7 @@ redraw:
 		break;
 
 	    case LYK_HOME:
-	        cur_selection = 0;
+		cur_selection = 0;
 		if (window_offset > 0) {
 		    window_offset = 0;
 		    goto redraw;
@@ -764,80 +1129,80 @@ redraw:
 		break;
 
 	    case LYK_END:
-	        cur_selection = num_options;
+		cur_selection = num_options;
 		if (window_offset != (num_options - length + 1)) {
 		    window_offset = (num_options - length + 1);
 		    goto redraw;
 		}
 		break;
 
-            case LYK_DOWN_TWO:
-	        cur_selection += 2;
+	    case LYK_DOWN_TWO:
+		cur_selection += 2;
 		if (cur_selection > num_options)
-                    cur_selection = num_options;
+		    cur_selection = num_options;
 
 		/*
-		 *  Scroll the window down if neccessary.
+		 *  Scroll the window down if necessary.
 		 */
 		if ((cur_selection - window_offset) >= length) {
 		    window_offset += 2;
 		    if (window_offset > (num_options - length + 1))
-		        window_offset = (num_options - length + 1);
+			window_offset = (num_options - length + 1);
 		    goto redraw;
 		}
-                break;
+		break;
 
 	    case LYK_UP_TWO:
-	        cur_selection -= 2;
+		cur_selection -= 2;
 		if (cur_selection < 0)
 		    cur_selection = 0;
 
 		/*
-		 *  Scroll the window up if neccessary.
+		 *  Scroll the window up if necessary.
 		 */
 		if ((cur_selection - window_offset) < 0) {
 		    window_offset -= 2;
 		    if (window_offset < 0)
-		        window_offset = 0;
+			window_offset = 0;
 		    goto redraw;
 		}
-                break;
+		break;
 
-            case LYK_DOWN_HALF:
-	        cur_selection += (length/2);
+	    case LYK_DOWN_HALF:
+		cur_selection += (length/2);
 		if (cur_selection > num_options)
-                    cur_selection = num_options;
+		    cur_selection = num_options;
 
 		/*
-		 *  Scroll the window down if neccessary.
+		 *  Scroll the window down if necessary.
 		 */
 		if ((cur_selection - window_offset) >= length) {
 		    window_offset += (length/2);
 		    if (window_offset > (num_options - length + 1))
-		        window_offset = (num_options - length + 1);
+			window_offset = (num_options - length + 1);
 		    goto redraw;
 		}
-                break;
+		break;
 
 	    case LYK_UP_HALF:
-	        cur_selection -= (length/2);
+		cur_selection -= (length/2);
 		if (cur_selection < 0)
 		    cur_selection = 0;
 
 		/*
-		 *  Scroll the window up if neccessary.
+		 *  Scroll the window up if necessary.
 		 */
 		if ((cur_selection - window_offset) < 0) {
 		    window_offset -= (length/2);
 		    if (window_offset < 0)
-		        window_offset = 0;
+			window_offset = 0;
 		    goto redraw;
 		}
-                break;
+		break;
 
 	    case LYK_REFRESH:
-	        clearok(curscr, TRUE);
-	        refresh();
+		clearok(curscr, TRUE);
+		refresh();
 		break;
 
 	    case LYK_NEXT:
@@ -857,18 +1222,18 @@ redraw:
 		     *  of a popup window. - FM
 		     */
 		    if ((cp = (char *)HTList_objectAt(search_queries,
-	    					      0)) != NULL) {
+						      0)) != NULL) {
 			strcpy(prev_target_buffer, cp);
 			QueryNum = 0;
 			FirstRecall = FALSE;
 		    }
 		}
-	        strcpy(prev_target, prev_target_buffer);
+		strcpy(prev_target, prev_target_buffer);
 	    case LYK_WHEREIS:
-	        if (*prev_target == '\0' ) {
+		if (*prev_target == '\0' ) {
 		    _statusline(ENTER_WHEREIS_QUERY);
 		    if ((ch = LYgetstr(prev_target, VISIBLE,
-	    		 	       sizeof(prev_target_buffer),
+				       sizeof(prev_target_buffer),
 				       recall)) < 0) {
 			/*
 			 *  User cancelled the search via ^G. - FM
@@ -885,14 +1250,14 @@ check_recall:
 		    /*
 		     *  No entry.  Simply break.   - FM
 		     */
-	            _statusline(CANCELLED);
+		    _statusline(CANCELLED);
 		    sleep(InfoSecs);
 		    goto restore_popup_statusline;
 		}
 
 		if (recall && ch == UPARROW) {
 		    if (FirstRecall) {
-		        /*
+			/*
 			 *  Use the current string or
 			 *  last query in the list. - FM
 			 */
@@ -900,7 +1265,8 @@ check_recall:
 			if (*prev_target_buffer) {
 			    for (QueryNum = (QueryTotal - 1);
 			         QueryNum > 0; QueryNum--) {
-				if ((cp=(char *)HTList_objectAt(search_queries,
+				if ((cp = (char *)HTList_objectAt(
+							search_queries,
 	    						QueryNum)) != NULL &&
 				    !strcmp(prev_target_buffer, cp)) {
 				    break;
@@ -920,8 +1286,8 @@ check_recall:
 			 *  Roll around to the last query in the list. - FM
 			 */
 			QueryNum = 0;
-		    if ((cp=(char *)HTList_objectAt(search_queries,
-	    					    QueryNum)) != NULL) {
+		    if ((cp = (char *)HTList_objectAt(search_queries,
+	    					      QueryNum)) != NULL) {
 			strcpy(prev_target, cp);
 			if (*prev_target_buffer &&
 			    !strcmp(prev_target_buffer, prev_target)) {
@@ -933,7 +1299,7 @@ check_recall:
 			} else {
 			    _statusline(EDIT_A_PREV_QUERY);
 			}
-			if ((ch=LYgetstr(prev_target, VISIBLE,
+			if ((ch = LYgetstr(prev_target, VISIBLE,
 				sizeof(prev_target_buffer), recall)) < 0) {
 			    /*
 			     *  User cancelled the search via ^G. - FM
@@ -954,14 +1320,15 @@ check_recall:
 		    if (*prev_target_buffer) {
 			for (QueryNum = 0;
 			     QueryNum < (QueryTotal - 1); QueryNum++) {
-			    if ((cp=(char *)HTList_objectAt(search_queries,
-	    					    QueryNum)) != NULL &&
+			    if ((cp = (char *)HTList_objectAt(
+							search_queries,
+	    						QueryNum)) != NULL &&
 				!strcmp(prev_target_buffer, cp)) {
 				    break;
 			    }
 			}
 		    } else {
-			QueryNum = QueryTotal - 1;
+			QueryNum = (QueryTotal - 1);
 		    }
 		} else {
 		    /*
@@ -973,9 +1340,9 @@ check_recall:
 		    /*
 		     *  Roll around to the first query in the list. - FM
 		     */
-		    QueryNum = QueryTotal - 1;
-		    if ((cp=(char *)HTList_objectAt(search_queries,
-	    				QueryNum)) != NULL) {
+		    QueryNum = (QueryTotal - 1);
+		    if ((cp = (char *)HTList_objectAt(search_queries,
+	    					      QueryNum)) != NULL) {
 			strcpy(prev_target, cp);
 			if (*prev_target_buffer &&
 			    !strcmp(prev_target_buffer, prev_target)) {
@@ -997,10 +1364,10 @@ check_recall:
 			    _statusline(CANCELLED);
 			    sleep(InfoSecs);
 			    goto restore_popup_statusline;
-	    		}
+			}
 			goto check_recall;
 		    }
- 		}
+		}
 		/*
 		 *  Replace the search string buffer with the new target. - FM
 		 */
@@ -1026,10 +1393,10 @@ check_recall:
 		     */
 		    cur_selection += j;
 		    /*
-		     *  Scroll the window down if neccessary.
+		     *  Scroll the window down if necessary.
 		     */
 		    if ((cur_selection - window_offset) >= length) {
-		        window_offset += j;
+			window_offset += j;
 			if (window_offset > (num_options - length + 1))
 			    window_offset = (num_options - length + 1);
 			ReDraw = TRUE;
@@ -1066,10 +1433,10 @@ check_recall:
 		    j = (cur_selection - j);
 		    cur_selection -= j;
 		    /*
-		     *  Scroll the window up if neccessary.
+		     *  Scroll the window up if necessary.
 		     */
 		    if ((cur_selection - window_offset) < 0) {
-		        window_offset -= j;
+			window_offset -= j;
 			if (window_offset < 0)
 			    window_offset = 0;
 			ReDraw = TRUE;
@@ -1090,7 +1457,7 @@ restore_popup_statusline:
 		 */
 		if (disabled)
 		    _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
-   		else
+		else
 		    _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
 		*prev_target = '\0';
 		QueryTotal = (search_queries ? HTList_count(search_queries)
@@ -1109,7 +1476,7 @@ restore_popup_statusline:
 		cur_selection = orig_selection;
 		cmd = LYK_ACTIVATE; /* to exit */
 		break;
-        }
+	}
 
     }
 #ifndef USE_SLANG
@@ -1118,7 +1485,6 @@ restore_popup_statusline:
     LYsubwindow(0);
 #endif
 #endif /* !USE_SLANG */
-    refresh();
 
-    return(cur_selection);
+    return(disabled ? orig_selection : cur_selection);
 }
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index 9abe48d8..3ac5ca37 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -575,7 +575,7 @@ Try_Redirected_URL:
 			    StrAllocCopy(tmp, "http://");
 			    if (TRACE)
 			        fprintf(stderr,
-					"LYGetFile: URL %s\nchanged to ",
+					"LYGetFile: URL %s\n",
 					doc->address);
 			    *cp = '\0';
 			    StrAllocCat(tmp, doc->address+9);
@@ -590,7 +590,8 @@ Try_Redirected_URL:
 			        StrAllocCat(tmp, cp+8);
 			    StrAllocCopy(doc->address, tmp);
 			    if (TRACE)
-			        fprintf(stderr, "%s\n",doc->address);
+			        fprintf(stderr, "    changed to %s\n",
+						doc->address);
 			    FREE(tmp);
 			    url_type = HTTP_URL_TYPE;
 		        }
@@ -601,36 +602,56 @@ Try_Redirected_URL:
 			url_type == CSO_URL_TYPE)
 			fix_http_urls(doc);
 		    WWWDoc.address = doc->address;  /* possible reload */
-
 #ifdef DIRED_SUPPORT
 		    lynx_edit_mode = FALSE;
+#endif /* DIRED_SUPPORT */
+
 		    if (url_type == FILE_URL_TYPE) {
-		        doc->address = LYSanctify(doc->address);
-		        WWWDoc.address = doc->address;
-		    }
-#else
-		    if (url_type == FILE_URL_TYPE &&
-		        (cp=strstr(doc->address, "/~")) != NULL) {
-			*cp = '\0';
-			cp += 2;
-			StrAllocCopy(temp, doc->address);
+			/*
+			 *  If a file URL has a '~' as the lead character
+			 *  of its first symbolic element, convert the '~'
+			 *  to Home_Dir(), then append the rest of of path,
+			 *  if present, skipping "user" if "~user" was
+			 *  entered, simplifying, and eliminating any
+			 *  residual relative elements. - FM
+			 */
+		        if (((cp = HTParse(doc->address, "",
+				   PARSE_PATH+PARSE_ANCHOR+PARSE_PUNCTUATION))
+			      != NULL) &&
+			    !strncmp(cp, "/~", 2)) {
+			    char *cp1 = strstr(doc->address, "/~");
+			    char *cp2;
+
+			    if (TRACE)
+			        fprintf(stderr, "LYGetFile: URL %s\n",
+						doc->address);
+			    *cp1 = '\0';
+			    cp1 += 2;
+			    StrAllocCopy(temp, doc->address);
 #ifdef DOSPATH
 			StrAllocCat(temp, HTDOS_wwwName((char *)Home_Dir()));
 #else
 #ifdef VMS
-			StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir()));
+			    StrAllocCat(temp, 
+					HTVMS_wwwName((char *)Home_Dir()));
 #else
-			StrAllocCat(temp, Home_Dir());
+			    StrAllocCat(temp, Home_Dir());
 #endif /* VMS */
 #endif /* DOSPATH */
-			if (*cp)
-			    StrAllocCat(temp, cp);
-			StrAllocCopy(doc->address, temp);
-			FREE(temp);
-			WWWDoc.address = doc->address;
+			    if ((cp2 = strchr(cp1, '/')) != NULL) {
+				LYTrimRelFromAbsPath(cp2);
+				StrAllocCat(temp, cp2);
+			    }
+			    StrAllocCopy(doc->address, temp);
+			    FREE(temp);
+			    if (TRACE)
+			        fprintf(stderr, "    changed to %s\n",
+						doc->address);
+			    WWWDoc.address = doc->address;
+			}
+			FREE(cp);
 		    }
-#endif /* DIRED_SUPPORT */
-		    if (TRACE)
+		    if (TRACE && LYTraceLogFP == NULL)
 		        sleep(MessageSecs);
 		    user_message(WWW_WAIT_MESSAGE, doc->address);
 #ifdef NOTDEFINED
@@ -645,6 +666,22 @@ Try_Redirected_URL:
 #endif /* USE_SLANG */
 		        fprintf(stderr,"\n");
 		    }
+		    if ((LYNoRefererHeader == FALSE &&
+			 LYNoRefererForThis == FALSE) &&
+			(url_type == HTTP_URL_TYPE ||
+			 url_type == HTTPS_URL_TYPE) &&
+			(cp = strchr(HTLoadedDocumentURL(), '?')) != NULL &&
+			strchr(cp, '=') != NULL) {
+			/*
+			 *  Don't send a Referer header if the URL is
+			 *  the reply from a form with method GET, in
+			 *  case the content has personal data (e.g.,
+			 *  a password or credit card number) which
+			 *  would become visible in logs. - FM
+			 */
+			LYNoRefererForThis = TRUE;
+		    }
+		    cp = NULL;
 		    if (!HTLoadAbsolute(&WWWDoc)) {
 			/*
 			 *  Check for redirection.
@@ -819,7 +856,7 @@ Try_Redirected_URL:
 }
 
 /*
- *  The user wants to select a link or a page by number.
+ *  The user wants to select a link or page by number.
  *  If follow_link_number returns DO_LINK_STUFF do_link
  *   will be run immediately following its execution.
  *  If follow_link_number returns DO_GOTOLINK_STUFF
@@ -897,10 +934,11 @@ PUBLIC int follow_link_number ARGS4(
 	 *  in the current document, whether it is displayed
 	 *  on the screen or not!
 	 */
-	if ((info = HTGetLinkInfo(*num,
-				  want_go ? &new_top : NULL,
-				  want_go ? &new_link : NULL,
-			  &links[cur].hightext, 
+	if ((info = HTGetLinkInfo(*num, 
+				  want_go,
+				  &new_top,
+				  &new_link,
+			  	  &links[cur].hightext, 
 			  &links[cur].lname)) == WWW_INTERN_LINK_TYPE) {
 	    links[cur].type = WWW_INTERN_LINK_TYPE;
 	    return(DO_LINK_STUFF);
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 0877cfec..111b2a43 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -81,6 +81,7 @@ extern BOOLEAN local_exec_on_local_files; /* TRUE to enable local program  *
 /* Values to which keypad_mode can be set */
 #define NUMBERS_AS_ARROWS 0
 #define LINKS_ARE_NUMBERED 1
+#define LINKS_AND_FORM_FIELDS_ARE_NUMBERED 2
 
 #define HIDDENLINKS_MERGE	0
 #define HIDDENLINKS_SEPARATE	1
@@ -97,7 +98,8 @@ extern char star_string[MAX_LINE + 1]; /* from GridText.c */
  ((n) >= MAX_LINE ? star_string : &star_string[(MAX_LINE-1)] - (n))
 #define DIRNAMESIZE 256
 
-extern BOOLEAN LYShowCursor;   /* show the cursor or hide it */
+extern BOOLEAN LYShowCursor;	/* Show the cursor or hide it?	    */
+extern BOOLEAN LYUseDefShoCur;	/* Command line -show_cursor toggle */
 extern BOOLEAN LYCursesON;  /* start_curses()->TRUE, stop_curses()->FALSE */
 extern BOOLEAN LYUserSpecifiedURL;  /* URL from a goto or document? */
 extern BOOLEAN LYJumpFileURL;   /* URL from the jump file shortcuts? */
@@ -235,7 +237,8 @@ extern BOOLEAN no_url_redirection;   /* Don't follow URL redirections */
 extern char *form_post_data;         /* User data for post form */
 extern char *form_get_data;          /* User data for get form */
 extern char *http_error_file;        /* Place HTTP status code in this file */
-extern char *authentication_info[2]; /* Id:Password for protected forms */
+extern char *authentication_info[2]; /* Id:Password for protected documents */
+extern char *proxyauth_info[2];	  /* Id:Password for protected proxy server */
 extern BOOLEAN HEAD_request;	     /* Do a HEAD request */
 extern BOOLEAN scan_for_buried_news_references;
 extern BOOLEAN bookmark_start;	  /* Use bookmarks as startfile */
@@ -302,6 +305,9 @@ extern FILE *LYTraceLogFP;		/* Pointer for TRACE log	 */
 extern char *LYTraceLogPath;		/* Path for TRACE log		 */
 extern BOOLEAN LYUseTraceLog;		/* Use a TRACE log?		 */
 extern FILE LYOrigStderr;		/* Original stderr pointer	 */
+extern BOOLEAN LYSeekFragMAPinCur;
+extern BOOLEAN LYSeekFragAREAinCur;
 extern BOOLEAN LYStripDotDotURLs;	/* Try to fix ../ in some URLs?  */
+extern BOOLEAN LYForceSSLCookiesSecure;
 
 #endif /* LYGLOBALDEFS_H */
diff --git a/src/LYHash.c b/src/LYHash.c
index 49a0696a..7fbb55ad 100644
--- a/src/LYHash.c
+++ b/src/LYHash.c
@@ -12,7 +12,7 @@
 
 PUBLIC int hash_table[HASHSIZE]; /* 32K should be big enough */
 
-#if UNUSED
+#ifdef NOT_USED
 PUBLIC int hash_code_rp ARGS1(char*,string)
 {
 	char* hash_ptr = string;
@@ -27,7 +27,20 @@ PUBLIC int hash_code_rp ARGS1(char*,string)
 }
 #endif
 
+/*
+ *	This is the same function as the private HASH_FUNCTION() in HTAnchor.c,
+ *      but with a different value for HASH_SIZE.
+ */ 
+
+#define HASH_SIZE 8193		/* Arbitrary prime. Memory/speed tradeoff */
+
 PUBLIC int hash_code ARGS1 (char*, string)
 {
-	return HASH_FUNCTION(string);
+    int hash;
+    unsigned char *p;
+
+    for (p = (unsigned char *)string, hash = 0; *p; p++)
+    	hash = (int) (hash * 3 + (*(unsigned char *)p)) % HASH_SIZE;
+
+    return hash;
 }
diff --git a/src/LYHash.h b/src/LYHash.h
index 474a2cae..b466f2aa 100644
--- a/src/LYHash.h
+++ b/src/LYHash.h
@@ -19,7 +19,7 @@ typedef struct _hashbucket bucket;
 #define NOSTYLE -1
 
 extern bucket hashStyles[HASHSIZE];
-extern int hash_code PARAMS((char*));
+extern int hash_code PARAMS((char* string));
 extern int hash_table[HASHSIZE]; /* 32K should be big enough */
 
 extern int	s_alink, s_a, s_status,
diff --git a/src/LYHistory.c b/src/LYHistory.c
index b54d8778..741ebe52 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -179,12 +179,13 @@ PUBLIC void LYpush ARGS2(
 	}
     }
 
-#ifdef NOT_USED
-    /* The following segment not used any more - What's it good for,
-       anyway??  Doing a pop when a push is requested is confusing,
-       also to the user.  Moreover, the way it was done seems to cause
-       a memory leak. - kw */
-    /*
+#ifdef NOTDEFINED
+/*
+**  The following segment not used any more - What's it good for,
+**  anyway??  Doing a pop when a push is requested is confusing,
+**  also to the user.  Moreover, the way it was done seems to cause
+**  a memory leak. - KW
+*/  /*
      *  If file is identical to one two before it, don't push it.
      */
     if (nhist > 2 &&
@@ -204,7 +205,7 @@ PUBLIC void LYpush ARGS2(
 	nhist--;
         return;
     }
-#endif	/* NOT_USED */
+#endif /* NOTDEFINED */
 
     /*
      *  OK, push it if we have stack space.
@@ -317,8 +318,8 @@ PUBLIC void LYpush ARGS2(
 	    }
 	}
 	nhist++;
-	if (TRACE) {
-	    fprintf(stderr,
+   	if (TRACE) {
+    	    fprintf(stderr,
 		    "\nLYpush: address:%s\n        title:%s\n",
 		    doc->address, doc->title);
 	}
@@ -404,6 +405,14 @@ PUBLIC int showhistory ARGS1(
 
     if (first) {
 	tempname(tempfile, NEW_FILE);
+	/*
+	 *  Make the file a URL now.
+	 */
+#if defined (VMS) || defined (DOSPATH)
+	sprintf(hist_filename,"file://localhost/%s", tempfile);
+#else
+	sprintf(hist_filename,"file://localhost%s", tempfile);
+#endif /* VMS */
 	first = FALSE;
 #ifdef VMS
     } else {
@@ -415,26 +424,18 @@ PUBLIC int showhistory ARGS1(
 	HTAlert(CANNOT_OPEN_TEMP);
 	return(-1);
     }
+    chmod(tempfile, 0600);
 
-    /*
-     *  Make the file a URL now.
-     */
-#if defined (VMS) || defined (DOSPATH)
-    sprintf(hist_filename,"file://localhost/%s", tempfile);
-#else
-    sprintf(hist_filename,"file://localhost%s", tempfile);
-#endif /* VMS */
     StrAllocCopy(*newfile, hist_filename);
     LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
     LYforce_no_cache = TRUE;	/* force this file to be new */
 
     fprintf(fp0, "<head>\n");
 #ifdef EXP_CHARTRANS
-    add_META_charset_to_fd(fp0, -1);
+    LYAddMETAcharsetToFD(fp0, -1);
 #endif
     fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n",
 		 HISTORY_PAGE_TITLE);
-
     fprintf(fp0, "<h1>You have reached the History Page</h1>\n");
     fprintf(fp0, "<h2>%s Version %s</h2>\n<pre>", LYNX_NAME, LYNX_VERSION);
     fprintf(fp0, "<em>You selected:</em>\n");
@@ -501,7 +502,8 @@ PUBLIC BOOLEAN historytarget ARGS1(
 
     LYpop_num(number, newdoc);
     if (newdoc->internal_link &&
-	history[number].intern_seq_start == history[nhist-1].intern_seq_start) {
+	history[number].intern_seq_start == history[nhist-1].intern_seq_start
+	&& !(LYforce_no_cache == TRUE && LYoverride_no_cache == FALSE)) {
 	LYforce_no_cache = FALSE;
 	LYoverride_no_cache = TRUE;
 	treat_as_intern = TRUE;
@@ -567,6 +569,14 @@ PUBLIC int LYShowVisitedLinks ARGS1(
 
     if (first) {
 	tempname(tempfile, NEW_FILE);
+	/*
+	 *  Make the file a URL now.
+	 */
+#if defined (VMS) || defined (DOSPATH)
+	sprintf(vl_filename,"file://localhost/%s", tempfile);
+#else
+	sprintf(vl_filename,"file://localhost%s", tempfile);
+#endif /* VMS */
 	first = FALSE;
 #ifdef VMS
     } else {
@@ -578,26 +588,18 @@ PUBLIC int LYShowVisitedLinks ARGS1(
 	HTAlert(CANNOT_OPEN_TEMP);
 	return(-1);
     }
+    chmod(tempfile, 0600);
 
-    /*
-     *  Make the file a URL now.
-     */
-#if defined (VMS) || defined (DOSPATH)
-    sprintf(vl_filename,"file://localhost/%s", tempfile);
-#else
-    sprintf(vl_filename,"file://localhost%s", tempfile);
-#endif /* VMS */
     StrAllocCopy(*newfile, vl_filename);
     LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
     LYforce_no_cache = TRUE;	/* force this file to be new */
 
     fprintf(fp0, "<head>\n");
 #ifdef EXP_CHARTRANS
-    add_META_charset_to_fd(fp0, -1);
+    LYAddMETAcharsetToFD(fp0, -1);
 #endif
     fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n",
 		 VISITED_LINKS_TITLE);
-
     fprintf(fp0, "<h1>You have reached the Visited Links Page</h1>\n");
     fprintf(fp0, "<h2>%s Version %s</h2>\n<pre>", LYNX_NAME, LYNX_VERSION);
     fprintf(fp0, 
diff --git a/src/LYLeaks.c b/src/LYLeaks.c
index 8bdc8694..58edfb32 100644
--- a/src/LYLeaks.c
+++ b/src/LYLeaks.c
@@ -55,6 +55,7 @@ PUBLIC void LYLeaks NOARGS	{
 	if(Fp_leakagesink == NULL)	{
 		return;
 	}
+	chmod(LEAKAGE_SINK, 0600);
 
 	while(ALp_RunTimeAllocations != NULL)	{
 		/*
diff --git a/src/LYList.c b/src/LYList.c
index 66c02dbb..4d32c649 100644
--- a/src/LYList.c
+++ b/src/LYList.c
@@ -29,7 +29,7 @@
 **  	Create a temporary text/html file with a list of links to
 **	HyperText References in the current document.
 **
-** On entry
+**  On entry
 **	titles		Set:	if we want titles where available
 **			Clear:  we only get addresses.
 */
@@ -41,7 +41,9 @@ PUBLIC char * LYlist_temp_url NOARGS
     return list_filename;
 }
 
-PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
+PUBLIC int showlist ARGS2(
+	char **,	newfile,
+	BOOLEAN,	titles)
 {
     int cnt;
     int refs, hidden_links;
@@ -49,6 +51,7 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
     static BOOLEAN first = TRUE;
     FILE *fp0;
     char *Address = NULL, *Title = NULL, *cp = NULL;
+    char *desc = "unknown field or link";
 
     refs = HText_sourceAnchors(HTMainText);
     hidden_links = HText_HiddenLinkCount(HTMainText);
@@ -65,7 +68,15 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
     }
 
     if (first) {
-	tempname(tempfile,NEW_FILE);
+	tempname(tempfile, NEW_FILE);
+	/*
+	 *  Make the file a URL now.
+	 */
+#if defined (VMS) || defined (DOSPATH)
+	sprintf(list_filename, "file://localhost/%s", tempfile);
+#else
+	sprintf(list_filename, "file://localhost%s", tempfile);
+#endif /* VMS */
 	first = FALSE;
 #ifdef VMS
     } else {
@@ -78,48 +89,64 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
 	sleep(MessageSecs);
 	return(-1);
     }
+    chmod(tempfile, 0600);
 
-    /*
-     *  Make the file a URL now.
-     */
-#if defined (VMS) || defined (DOSPATH)
-    sprintf(list_filename, "file://localhost/%s", tempfile);
-#else
-    sprintf(list_filename, "file://localhost%s", tempfile);
-#endif /* VMS */
     StrAllocCopy(*newfile, list_filename);
-    LYforce_HTML_mode = TRUE; /* force this file to be HTML */
-    LYforce_no_cache = TRUE; /* force this file to be new */
+    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
+    LYforce_no_cache = TRUE;	/* force this file to be new */
 
 
     fprintf(fp0, "<head>\n");
 #ifdef EXP_CHARTRANS
-    add_META_charset_to_fd(fp0, -1);
+    LYAddMETAcharsetToFD(fp0, -1);
 #endif
     fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n",
 		 LIST_PAGE_TITLE);
-
     fprintf(fp0, "<h1>You have reached the List Page</h1>\n");
     fprintf(fp0, "<h2>%s Version %s</h2>\n", LYNX_NAME, LYNX_VERSION);
 
     fprintf(fp0, "  References in this document:<p>\n");
-    fprintf(fp0, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ?
-    				   "ul" : "ol");
+    if (refs > 0) {
+	fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+    				       "ol" : "ul"));
+	if (hidden_links > 0)
+	    fprintf(fp0, "<lh><em>Visible links:</em>\n");
+    }
     if (hidden_links > 0) {
-        fprintf(fp0, "<lh><em>Visible links:</em>\n");
 	if (LYHiddenLinks == HIDDENLINKS_IGNORE)
 	    hidden_links = 0;
     }
-    for (cnt=1; cnt<=refs; cnt++) {
+    for (cnt = 1; cnt <= refs; cnt++) {
 	HTChildAnchor *child = HText_childNumber(cnt);
-	HTAnchor *dest_intl = HTAnchor_followTypedLink((HTAnchor *)child,
+	HTAnchor *dest_intl;
+	HTAnchor *dest;
+	HTParentAnchor *parent;
+	char *address;
+	CONST char *title;
+
+	if (child == 0) {
+	    /*
+	     *  child should not be 0 unless form field numbering is on
+	     *  and cnt is the number of a form input field.
+	     *  HText_FormDescNumber() will set desc to a description
+	     *  of what type of input field this is.  We'll list it to
+	     *  ensure that the link numbers on the list page match the
+	     *  numbering in the original document, but won't create a
+	     *  forward link to the form. - FM && LE
+	     */
+	    if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+		HText_FormDescNumber(cnt, (char **)&desc);
+		fprintf(fp0, "<li>[%d](<em>%s</em>)</a>\n", cnt, desc);
+	    }
+	    continue;
+	}
+	dest_intl = HTAnchor_followTypedLink((HTAnchor *)child,
 						       LINK_INTERNAL);
-	HTAnchor *dest = dest_intl ?
+	dest = dest_intl ?
 	    dest_intl : HTAnchor_followMainLink((HTAnchor *)child);
-	HTParentAnchor *parent = HTAnchor_parent(dest);
-	char *address =  HTAnchor_address(dest);
-	CONST char *title = titles ? HTAnchor_title(parent) : NULL;
-
+	parent = HTAnchor_parent(dest);
+	address =  HTAnchor_address(dest);
+	title = titles ? HTAnchor_title(parent) : NULL;
 	StrAllocCopy(Address, address);
 	FREE(address);
 	LYEntify(&Address, TRUE);
@@ -147,10 +174,10 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
     if (hidden_links > 0) {
         if (refs > 0)
 	    fprintf(fp0, "\n</%s>\n\n<p>\n",
-	    		 (keypad_mode == LINKS_ARE_NUMBERED) ?
-							"ul" : "ol");
-        fprintf(fp0, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ?
-    				       "ul" : "ol continue");
+	    		 ((keypad_mode == NUMBERS_AS_ARROWS) ?
+						        "ol" : "ul"));
+        fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+    				        "ol continue" : "ul"));
         fprintf(fp0, "<lh><em>Hidden links:</em>\n");
     }
 
@@ -166,24 +193,22 @@ PUBLIC int showlist ARGS2(char **, newfile, BOOLEAN, titles)
 	FREE(Address);
     }
 
-    fprintf(fp0,"\n</%s>\n</body>\n", (keypad_mode == LINKS_ARE_NUMBERED) ?
-    				      "ul" : "ol");
+    fprintf(fp0,"\n</%s>\n</body>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+    				       "ol" : "ul"));
 
     fclose(fp0);
     return(0);
 }      
 
-
 /* 	printlist - F.Macrides (macrides@sci.wfeb.edu)
 **	---------
 **  	Print a text/plain list of HyperText References
 **	in the current document.
 **
-** On entry
+**  On entry
 **	titles		Set:	if we want titles where available
 **			Clear:  we only get addresses.
 */
-
 PUBLIC void printlist ARGS2(
 	FILE *,		fp,
 	BOOLEAN,	titles)
@@ -194,6 +219,7 @@ PUBLIC void printlist ARGS2(
     int cnt;
     int refs, hidden_links;
     char *address = NULL;
+    char *desc = "unknown field or link";
 
     refs = HText_sourceAnchors(HTMainText);
     if (refs <= 0 && LYHiddenLinks != HIDDENLINKS_SEPARATE)
@@ -209,12 +235,29 @@ PUBLIC void printlist ARGS2(
 		hidden_links = 0;
 	}
 	for (cnt = 1; cnt <= refs; cnt++) {
-	    HTAnchor *dest =
-		HTAnchor_followMainLink((HTAnchor *)
-					HText_childNumber(cnt));
-	    HTParentAnchor * parent = HTAnchor_parent(dest);
-	    CONST char * title = titles ? HTAnchor_title(parent) : NULL;
+	    HTChildAnchor *child = HText_childNumber(cnt);
+	    HTAnchor *dest;
+	    HTParentAnchor *parent;
+	    CONST char *title;
 
+	    if (child == 0) {
+		/*
+		 *  child should not be 0 unless form field numbering is on
+		 *  and cnt is the number of a form intput field.
+		 *  HText_FormDescNumber() will set desc to a description
+		 *  of what type of input field this is.  We'll list it to
+		 *  ensure that the link numbers on the list page match the
+		 *  numbering in the original document. - FM && LE
+		 */
+		if (keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED) {
+		    HText_FormDescNumber(cnt, (char **)&desc);
+		    fprintf(fp, "%4d. (%s)\n", cnt, desc);
+		}
+		continue;
+	    }
+	    dest = HTAnchor_followMainLink((HTAnchor *)child);
+	    parent = HTAnchor_parent(dest);
+	    title = titles ? HTAnchor_title(parent) : NULL;
 	    address =  HTAnchor_address(dest);
 	    fprintf(fp, "%4d. %s%s\n", cnt,
 		    ((HTAnchor*)parent != dest) && title ? "in " : "",
diff --git a/src/LYLocal.c b/src/LYLocal.c
index 3dd45b97..22b66886 100644
--- a/src/LYLocal.c
+++ b/src/LYLocal.c
@@ -15,9 +15,18 @@
 	  unescaping took place before).
 	Dynamic memory instead of fixed length buffers in a few cases.
 	Other minor changes to make things work as intended. */
+/* Modified Jun-97 Klaus Weide (kweide@tezcat.com) & FM:
+	Modified the code handling DIRED_MENU to do more careful
+	  checking of the selected file.  In addition to "TAG", "FILE", and
+	  "DIR", DIRED_MENU definitions in lynx.cfg now also recognize LINK as
+	  a type.  DIRED_MENU definitions with a type field of "LINK" are only
+	  used if the current selection is a symbolic link ("FILE" and "DIR"
+	  definitions are not used in that case).  The default menu
+	  definitions have been updated to reflect this change, and to avoid
+	  the showing of menu items whose action would always fail - KW
+	Cast all code into the Lynx programming style. - FM */
 
 #ifdef DIRED_SUPPORT
-
 #include "HTUtils.h"
 #include "tcp.h"
 #include "HTParse.h"
@@ -41,35 +50,48 @@
 
 #define FREE(x) if (x) {free(x); x = NULL;}
 
-PRIVATE int my_spawn PARAMS((char *path, char **argv, char *msg));
-PRIVATE char *filename PARAMS((char *prompt, char *buf, int bufsize));
+PRIVATE int my_spawn PARAMS((
+	char *		path,
+	char **		argv,
+	char *		msg));
+PRIVATE char *filename PARAMS((
+	char *		prompt,
+	char *		buf,
+	int		bufsize));
 
 #ifdef OK_PERMIT
-PRIVATE BOOLEAN permit_location PARAMS((char * destpath, char * srcpath,
-					char ** newpath));
+PRIVATE BOOLEAN permit_location PARAMS((
+	char *		destpath,
+	char *		srcpath,
+	char **		newpath));
 #endif /* OK_PERMIT */
 
-PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf,
-				  int bufsize, BOOLEAN url_syntax));
+PRIVATE char *render_item PARAMS((
+	char *		s,
+	char *		path,
+	char *		dir,
+	char *		buf,
+	int		bufsize,
+	BOOLEAN		url_syntax));
 
 PRIVATE struct dired_menu *menu_head = NULL;
 struct dired_menu {
-	int cond;
-#		define	DE_TAG	1
-#		define	DE_DIR	2
-#		define	DE_FILE	3
-#define			DE_SYMLINK	4
-	char *sfx;
-	char *link;
-	char *rest;
-	char *href;
-	struct dired_menu *next;
+    int cond;
+#define DE_TAG	   1
+#define DE_DIR	   2
+#define DE_FILE	   3
+#define DE_SYMLINK 4
+    char *sfx;
+    char *link;
+    char *rest;
+    char *href;
+    struct dired_menu *next;
 } defmenu[] = {
 /*
- * The following initializations determine the contents of the f)ull menu
- * selection when in dired mode.  If any menu entries are defined in the
- * configuration file via DIRED_MENU lines, then these default entries
- * are discarded entirely.
+ *  The following initializations determine the contents of the f)ull menu
+ *  selection when in dired mode.  If any menu entries are defined in the
+ *  configuration file via DIRED_MENU lines, then these default entries
+ *  are discarded entirely.
  */
 { 0,		      "", "New File",
 "(in current directory)", "LYNXDIRED://NEW_FILE%d",		NULL },
@@ -189,163 +211,171 @@ struct dired_menu {
 		    NULL, NULL,					NULL }
 };
 
-/* Remove all tagged files and directories. */
-
+/*
+ *  Remove all tagged files and directories.
+ */
 PRIVATE BOOLEAN remove_tagged NOARGS
-{ 
-   int c, ans;
-   char *cp,*tp;
-   char tmpbuf[1024];
-   char *testpath = NULL;
-   struct stat dir_info;
-   int count,i;
-   HTList *tag;
-   char *args[5];
-
-   if (HTList_isEmpty(tagged))  /* should never happen */
-       return 0;
-
-   _statusline("Remove all tagged files and directories (y or n): ");
-   c = LYgetch();
-   ans=TOUPPER(c);
-
-   count = 0;
-   tag = tagged;
-   while(ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) {
-      if(is_url(cp) == FILE_URL_TYPE) { /* unecessary check */
-	 tp = cp;
-	 if(!strncmp(tp,"file://localhost",16))
-	   tp += 16;
-	 else if(!strncmp(tp,"file:",5))
-	   tp += 5;
-	 StrAllocCopy(testpath,tp);
-	 HTUnEscape(testpath);
-	 if((i = strlen(testpath)) && testpath[i-1] == '/')
-	   testpath[i-1] = '\0';
-
-/* check the current status of the path to be deleted */
-
-	 if (stat(testpath,&dir_info) == -1) {
-	    sprintf(tmpbuf,"System error - failed to get status of %s ",testpath);
-	    _statusline(tmpbuf);
-	    sleep(AlertSecs);
-	    return count;
-	 } else {
-	    args[0] = "rm";
-	    args[1] = "-rf";
-	    args[2] = testpath;
-	    args[3] = (char *) 0;
-	    sprintf(tmpbuf, "remove %s", testpath);
-	    if (my_spawn(RM_PATH, args, tmpbuf) <= 0) {
-		FREE(testpath);
-		return ((count == 0) ? -1 : count);
+{
+    int c, ans;
+    char *cp, *tp;
+    char tmpbuf[1024];
+    char *testpath = NULL;
+    struct stat dir_info;
+    int count, i;
+    HTList *tag;
+    char *args[5];
+
+    if (HTList_isEmpty(tagged))  /* should never happen */
+	return 0;
+
+    _statusline("Remove all tagged files and directories (y or n): ");
+    c = LYgetch();
+    ans = TOUPPER(c);
+
+    count = 0;
+    tag = tagged;
+    while (ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) {
+	if (is_url(cp) == FILE_URL_TYPE) { /* unecessary check */
+	    tp = cp;
+	    if (!strncmp(tp, "file://localhost", 16)) {
+		tp += 16;
+	    } else if (!strncmp(tp, "file:", 5)) {
+		tp += 5;
 	    }
-	    ++count;
-	 }
-      }
-   }
-   FREE(testpath);
-   clear_tags();
-   return count;
+	    StrAllocCopy(testpath, tp);
+	    HTUnEscape(testpath);
+	    if ((i = strlen(testpath)) && testpath[i-1] == '/')
+		testpath[(i - 1)] = '\0';
+
+	    /*
+	     *  Check the current status of the path to be deleted.
+	     */
+	    if (stat(testpath,&dir_info) == -1) {
+		sprintf(tmpbuf,
+			"System error - failed to get status of '%s'.",
+			testpath);
+		_statusline(tmpbuf);
+		sleep(AlertSecs);
+		return count;
+	    } else {
+		args[0] = "rm";
+		args[1] = "-rf";
+		args[2] = testpath;
+		args[3] = (char *) 0;
+		sprintf(tmpbuf, "remove %s", testpath);
+		if (my_spawn(RM_PATH, args, tmpbuf) <= 0) {
+		    FREE(testpath);
+		    return ((count == 0) ? -1 : count);
+		}
+		++count;
+	    }
+	}
+    }
+    FREE(testpath);
+    clear_tags();
+    return count;
 }
 
-/* Move all tagged files and directories to a new location. */
-/* Input is current directory. */
-/* The tests in this function can, at best, prevent some user mistakes -
-   anybody who relies on them for security is seriously misguided.
-   If a user has enough permissions to move a file somewhere, the same 
-   uid with Lynx & dired can do the same thing. */
-
+/*
+ *  Move all tagged files and directories to a new location.
+ *  Input is current directory.
+ *  The tests in this function can, at best, prevent some user mistakes -
+ *   anybody who relies on them for security is seriously misguided.
+ *  If a user has enough permissions to move a file somewhere, the same 
+ *   uid with Lynx & dired can do the same thing.
+ */
 PRIVATE BOOLEAN modify_tagged ARGS1(
 	char *,		testpath)
 {
-   char *cp;
-   dev_t dev;
-   ino_t inode;
-   uid_t owner;
-   char tmpbuf[1024];
-   char *savepath = NULL;
-   char *srcpath = NULL;
-   struct stat dir_info;
-   char *args[5];
-   int count = 0;
-   HTList *tag;
-
-   if (HTList_isEmpty(tagged))  /* should never happen */
-       return 0;
-
-   _statusline("Enter new location for tagged items: ");
-
-   tmpbuf[0] = '\0';
-   LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL);
-   if (strlen(tmpbuf)) {
-
-/* determine the ownership of the current location */
-
-   
-      /*
-       *  This test used to always fail from the dired menu...
-       *  changed to something that hopefully makes more sense - KW
-       */ 
-      if (testpath && *testpath && 0!=strcmp(testpath,"/")) {
-	  /*
-	   *  testpath passed in and is not empty and not
-	   *  a single "/" (which would probably be bogus) - use it
-	   */
-	  cp = testpath;
-      } else {
-	  /*
-	   *  Prepare to get directory path from one of the tagged files.
-	   */
-	  cp = HTList_lastObject(tagged);
-	  testpath = NULL;	/* won't be needed any more in this function,
-				 set to NULL as a flag */
-	  if (!cp)   /* last resort, should never happen */
-	      cp = "/";
-      }
-      if (!strncmp(cp,"file://localhost",16))
-	cp += 16;
-      else if (!strncmp(cp,"file:",5))
-	cp += 5;
-      if (testpath==NULL) {
-          /*
-	   *  Get the directory containing the file or subdir.
-	   */
-	  cp = strip_trailing_slash(cp);
-	  savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION);
-      } else {
-	  StrAllocCopy(savepath, cp);
-      }
-      HTUnEscape(savepath);
-      if (stat(savepath,&dir_info) == -1) {
-	 sprintf(tmpbuf,"Unable to get status of %s ",savepath);
-	 _statusline(tmpbuf);
-	 sleep(AlertSecs);
-	 FREE(savepath);
-	 return 0;
-      } 
-
-/* save the owner of the current location for later use */
-/* also save the device and inode for location checking */
-
-      dev = dir_info.st_dev;
-      inode = dir_info.st_ino;
-      owner = dir_info.st_uid;
-
-/* replace ~/ references to the home directory */
-
-      if (!strncmp(tmpbuf,"~/",2)) {
-	  char *cp1 = NULL;
-	  StrAllocCopy(cp1, (char *)Home_Dir());
-	  StrAllocCat(cp1, (tmpbuf+1));
-	  if (strlen(cp1) > (sizeof(tmpbuf)-1)) {
-	      sprintf(tmpbuf, "%s ", "Path too long");
-	      _statusline(tmpbuf);
-	      sleep(AlertSecs);
-	      FREE(savepath);
-	      FREE(cp1);
-	      return 0;
-	  }
+    char *cp;
+    dev_t dev;
+    ino_t inode;
+    uid_t owner;
+    char tmpbuf[1024];
+    char *savepath = NULL;
+    char *srcpath = NULL;
+    struct stat dir_info;
+    char *args[5];
+    int count = 0;
+    HTList *tag;
+
+    if (HTList_isEmpty(tagged))  /* should never happen */
+	return 0;
+
+    _statusline("Enter new location for tagged items: ");
+
+    tmpbuf[0] = '\0';
+    LYgetstr(tmpbuf, VISIBLE, sizeof(tmpbuf), NORECALL);
+    if (strlen(tmpbuf)) {
+    /*
+     *  Determine the ownership of the current location.
+     */
+	/*
+	 *  This test used to always fail from the dired menu...
+	 *  changed to something that hopefully makes more sense - KW
+	 */ 
+	if (testpath && *testpath && 0!=strcmp(testpath,"/")) {
+	    /*
+	     *  testpath passed in and is not empty and not a single "/"
+	     *  (which would probably be bogus) - use it.
+	     */
+	    cp = testpath;
+	} else {
+	    /*
+	     *  Prepare to get directory path from one of the tagged files.
+	     */
+	    cp = HTList_lastObject(tagged);
+	    testpath = NULL;	/* Won't be needed any more in this function,
+				   set to NULL as a flag. */
+	    if (!cp)	/* Last resort, should never happen. */
+		cp = "/";
+	}
+	if (!strncmp(cp, "file://localhost", 16)) {
+	    cp += 16;
+	} else if (!strncmp(cp, "file:", 5)) {
+	    cp += 5;
+	}
+	if (testpath == NULL) {
+	    /*
+	     *  Get the directory containing the file or subdir.
+	     */
+	    cp = strip_trailing_slash(cp);
+	    savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION);
+	} else {
+	    StrAllocCopy(savepath, cp);
+	}
+	HTUnEscape(savepath);
+	if (stat(savepath, &dir_info) == -1) {
+	    sprintf(tmpbuf, "Unable to get status of '%s'.", savepath);
+	    _statusline(tmpbuf);
+	    sleep(AlertSecs);
+	    FREE(savepath);
+	    return 0;
+	} 
+
+	/*
+	 *  Save the owner of the current location for later use.
+	 *  Also save the device and inode for location checking/
+	 */
+	dev = dir_info.st_dev;
+	inode = dir_info.st_ino;
+	owner = dir_info.st_uid;
+
+	/*
+	 *  Replace ~/ references to the home directory.
+	 */
+	if (!strncmp(tmpbuf, "~/", 2)) {
+	    char *cp1 = NULL;
+	    StrAllocCopy(cp1, (char *)Home_Dir());
+	    StrAllocCat(cp1, (tmpbuf + 1));
+	    if (strlen(cp1) > (sizeof(tmpbuf) - 1)) {
+		sprintf(tmpbuf, "%s", "Path too long");
+		_statusline(tmpbuf);
+		sleep(AlertSecs);
+		FREE(savepath);
+		FREE(cp1);
+		return 0;
+	    }
 	  strcpy(tmpbuf, cp1);
 	  FREE(cp1);
       }
@@ -363,7 +393,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
 /* stat the target location to determine type and ownership */
 
       if (stat(savepath,&dir_info) == -1) {
-	 sprintf(tmpbuf,"Unable to get status of %s ",savepath);
+	 sprintf(tmpbuf,"Unable to get status of '%s'.",savepath);
 	 _statusline(tmpbuf);
 	 sleep(AlertSecs);
 	 FREE(savepath);
@@ -431,539 +461,582 @@ PRIVATE BOOLEAN modify_tagged ARGS1(
    return 0;
 }
 
-/* Modify the name of the specified item. */
+/*
+ *  Modify the name of the specified item.
+ */
 
 PRIVATE BOOLEAN modify_name ARGS1(
 	char *,		testpath)
 {
-   char *cp;
-   char tmpbuf[512];
-   char newpath[512];
-   char savepath[512];
-   struct stat dir_info;
-   char *args[5];
+    char *cp;
+    char tmpbuf[512];
+    char newpath[512];
+    char savepath[512];
+    struct stat dir_info;
+    char *args[5];
 
-/* Determine the status of the selected item. */
+    /*
+     *  Determine the status of the selected item.
+     */
+    testpath = strip_trailing_slash(testpath);
 
-   testpath = strip_trailing_slash(testpath);
+    if (stat(testpath, &dir_info) == -1) {
+	sprintf(tmpbuf, "Unable to get status of '%s'.", testpath);
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+    } else {
+	/*
+	 *  Change the name of the file or directory.
+	 */
+	if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+	     cp = "Enter new name for directory: ";
+	} else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	     cp = "Enter new name for file: ";
+	} else {
+	     _statusline(
+	 "The selected item is not a file or a directory! Request ignored.");
+	     sleep(AlertSecs);
+	     return 0;
+	}
+	if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
+	    return 0;
 
-   if (stat(testpath,&dir_info) == -1) {
-      sprintf(tmpbuf,"Unable to get status of %s ",testpath);
-      _statusline(tmpbuf);
-      sleep(AlertSecs);
-   } else {
+	/*
+	 *  Do not allow the user to also change the location at this time.
+	 */
+	if (strchr(tmpbuf, '/') != NULL) {
+	    _statusline("Illegal character \"/\" found! Request ignored.");
+	    sleep(AlertSecs);
+	} else if (strlen(tmpbuf) &&
+		   (cp = strrchr(testpath, '/')) != NULL) {
+	    strcpy(savepath,testpath);
+	    *(++cp) = '\0';
+	    strcpy(newpath,testpath);
+	    strcat(newpath,tmpbuf);
 
-/* Change the name of the file or directory. */
+	    /*
+	     *  Make sure the destination does not already exist.
+	     */
+	    if (stat(newpath, &dir_info) == -1) {
+		if (errno != ENOENT) {
+		    sprintf(tmpbuf,
+			    "Unable to determine status of '%s'.", newpath);
+		    _statusline(tmpbuf);
+		    sleep(AlertSecs);
+		} else {
+		    sprintf(tmpbuf, "move %s to %s", savepath, newpath);
+		    args[0] = "mv";
+		    args[1] = savepath;
+		    args[2] = newpath;
+		    args[3] = (char *) 0;
+		    if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
+			return (-1);
+		    return 1; 
+		}
+	    } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+		_statusline(
+	    "There is already a directory with that name! Request ignored.");
+		sleep(AlertSecs);
+	    } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+		_statusline(
+	    	 "There is already a file with that name! Request ignored.");
+		sleep(AlertSecs);
+	    } else {
+		_statusline(
+	    	   "The specified name is already in use! Request ignored.");
+		sleep(AlertSecs);
+	    }
+	}
+    }
+    return 0;
+}
 
-      if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-	 cp = "Enter new name for directory: ";
-      } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
-	 cp = "Enter new name for file: ";
-      } else {
-	 _statusline(
-	 "The selected item is not a file or a directory! Request ignored. ");
-	 sleep(AlertSecs);
-	 return 0;
-      }
-      if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
-	 return 0;
+/*
+ *  Change the location of a file or directory.
+ */
+PRIVATE BOOLEAN modify_location ARGS1(
+	char *,		testpath)
+{
+    int mode;
+    char *cp;
+    dev_t dev;
+    ino_t inode;
+    uid_t owner;
+    char tmpbuf[1024];
+    char newpath[512];
+    char savepath[512];
+    struct stat dir_info;
+    char *args[5];
 
-/* Do not allow the user to also change the location at this time */
+    /*
+     *  Determine the status of the selected item.
+     */
+    testpath = strip_trailing_slash(testpath);
 
-      if(strchr(tmpbuf,'/') != NULL) {
-	 _statusline("Illegal character \"/\" found! Request ignored. ");
-	 sleep(AlertSecs);
-      } else if(strlen(tmpbuf) && (cp = strrchr(testpath,'/')) != NULL) {
-	 strcpy(savepath,testpath);
-	 *++cp = '\0';
-	 strcpy(newpath,testpath);
-	 strcat(newpath,tmpbuf);
+    if (stat(testpath, &dir_info) == -1) {
+	sprintf(tmpbuf, "Unable to get status of '%s'.", testpath);
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+	return 0;
+    } 
 
-/* Make sure the destination does not already exist. */
+    /*
+     *  Change the location of the file or directory.
+     */
+    if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+	cp = "Enter new location for directory: ";
+    } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	cp = "Enter new location for file: ";
+    } else {
+	_statusline(
+        "The specified item is not a file or a directory - request ignored.");
+	sleep(AlertSecs);
+	return 0;
+    }
+    if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
+	return 0;
+    if (strlen(tmpbuf)) {
+	strcpy(savepath, testpath);
+	strcpy(newpath, testpath);
 
-	 if (stat(newpath,&dir_info) == -1) {
-	    if (errno != ENOENT) {
-	       sprintf(tmpbuf,"Unable to determine status of %s ",newpath);
-	       _statusline(tmpbuf);
-	       sleep(AlertSecs);
+	/*
+	 *  Allow ~/ references to the home directory.
+	 */
+	if (!strncmp(tmpbuf,"~/",2)) {
+	    cp = (char *)Home_Dir();
+	    strcpy(newpath, cp);
+	    strcat(newpath, (tmpbuf + 1));
+	    strcpy(tmpbuf, newpath);
+	}
+	if (tmpbuf[0] != '/') {
+	    if ((cp = strrchr(newpath,'/')) != NULL) {
+		*++cp = '\0';
+		strcat(newpath,tmpbuf);
 	    } else {
-	       sprintf(tmpbuf,"move %s to %s",savepath,newpath);
-	       args[0] = "mv";
-	       args[1] = savepath;
-	       args[2] = newpath;
-	       args[3] = (char *) 0;
-	       if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
-		  return (-1);
-	       return 1; 
+	    _statusline("Unexpected failure - unable to find trailing \"/\"");
+		sleep(AlertSecs);
+		return 0;
 	    }
-	 } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-	    _statusline(
-	     "There is already a directory with that name! Request ignored. ");
+	} else {
+	    strcpy(newpath,tmpbuf);
+	}
+
+	/*
+	 *  Make sure the source and target have the same owner (uid).
+	 */
+	dev = dir_info.st_dev;
+	mode = dir_info.st_mode;
+	inode = dir_info.st_ino;
+	owner = dir_info.st_uid;  
+	if (stat(newpath, &dir_info) == -1) {
+	    sprintf(tmpbuf,"Unable to get status of '%s'.",newpath);
+	    _statusline(tmpbuf);
 	    sleep(AlertSecs);
-	 } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	    return 0;
+	}
+	if ((dir_info.st_mode & S_IFMT) != S_IFDIR) {
 	    _statusline(
-	    	"There is already a file with that name! Request ignored. ");
+	 	"Destination is not a valid directory! Request denied.");
 	    sleep(AlertSecs);
-	 } else {
+	    return 0;
+	}
+
+	/*
+	 *  Make sure the source and target are not the same location.
+	 */
+	if (dev == dir_info.st_dev && inode == dir_info.st_ino) {
 	    _statusline(
-	    	"The specified name is already in use! Request ignored. ");
+	   "Source and destination are the same location! Request ignored!");
 	    sleep(AlertSecs);
-	 }
-      }
-   }
-   return 0;
-}
-
-/* Change the location of a file or directory. */
-
-PRIVATE BOOLEAN modify_location ARGS1(
-	char *,		testpath)
-{
-   int mode;
-   char *cp;
-   dev_t dev;
-   ino_t inode;
-   uid_t owner;
-   char tmpbuf[1024];
-   char newpath[512];
-   char savepath[512];
-   struct stat dir_info;
-   char *args[5];
-
-/* Determine the status of the selected item. */
-
-   testpath = strip_trailing_slash(testpath);
-
-   if (stat(testpath,&dir_info) == -1) {
-      sprintf(tmpbuf,"Unable to get status of %s ",testpath);
-      _statusline(tmpbuf);
-      sleep(AlertSecs);
-      return 0;
-   } 
-
-/* Change the location of the file or directory */
-
-   if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-      cp = "Enter new location for directory: ";
-   } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
-      cp = "Enter new location for file: ";
-   } else {
-      _statusline(
-        "The specified item is not a file or a directory - request ignored.");
-      sleep(AlertSecs);
-      return 0;
-   }
-   if (filename(cp, tmpbuf, sizeof(tmpbuf)) == NULL)
-      return 0;
-   if (strlen(tmpbuf)) {
-      strcpy(savepath,testpath);
-      strcpy(newpath,testpath);
-
-/* Allow ~/ references to the home directory. */
-
-      if (!strncmp(tmpbuf,"~/",2)) {
-	 cp = (char *)Home_Dir();
-	 strcpy(newpath,cp);
-	 strcat(newpath,tmpbuf+1);
-	 strcpy(tmpbuf,newpath);
-      }
-      if (tmpbuf[0] != '/') {
-	 if ((cp = strrchr(newpath,'/')) != NULL) {
-	    *++cp = '\0';
-	    strcat(newpath,tmpbuf);
-	 } else {
-	    _statusline("Unexpected failure - unable to find trailing \"/\"");
+	    return 0;
+	}
+	if (dir_info.st_uid == owner) {
+	    sprintf(tmpbuf,"move %s to %s",savepath,newpath);
+	    args[0] = "mv";
+	    args[1] = savepath;
+	    args[2] = newpath;
+	    args[3] = (char *) 0;
+	    if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
+		return (-1);
+	    return 1;
+	} else {
+	 _statusline("Destination has different owner! Request denied.");
 	    sleep(AlertSecs);
 	    return 0;
-	 }
-      } else {
-	 strcpy(newpath,tmpbuf);
-      }
-      
-/* Make sure the source and target have the same owner (uid) */
-
-      dev = dir_info.st_dev;
-      mode = dir_info.st_mode;
-      inode = dir_info.st_ino;
-      owner = dir_info.st_uid;  
-      if (stat(newpath,&dir_info) == -1) {
-	 sprintf(tmpbuf,"Unable to get status of %s ",newpath);
-	 _statusline(tmpbuf);
-	 sleep(AlertSecs);
-	 return 0;
-      }
-      if ((dir_info.st_mode & S_IFMT) != S_IFDIR) {
-	 _statusline(
-	 	"Destination is not a valid directory! Request denied. ");
-	 sleep(AlertSecs);
-	 return 0;
-      }
-
-/* make sure the source and target are not the same location */
-
-      if (dev == dir_info.st_dev && inode == dir_info.st_ino) {
-	 _statusline(
-	   "Source and destination are the same location! Request ignored!");
-	 sleep(AlertSecs);
-	 return 0;
-      }
-      if(dir_info.st_uid == owner) {
-	 sprintf(tmpbuf,"move %s to %s",savepath,newpath);
-	 args[0] = "mv";
-	 args[1] = savepath;
-	 args[2] = newpath;
-	 args[3] = (char *) 0;
-	 if (my_spawn(MV_PATH, args, tmpbuf) <= 0)
-	    return (-1);
-	 return 1;
-      } else {
-	 _statusline("Destination has different owner! Request denied. ");
-	 sleep(AlertSecs);
-	 return 0;
-      }
-   }
-   return 0;
-}   
-
-/* Modify name or location of a file or directory on localhost. */
+	}
+    }
+    return 0;
+}
 
+/*
+ *  Modify name or location of a file or directory on localhost.
+ */
 PUBLIC BOOLEAN local_modify ARGS2(
 	document *,	doc,
 	char **,	newpath)
 {
-   int c, ans;
-   char *cp;
-   char testpath[512]; /* a bit ridiculous */
-   int count;
-
-   if (!HTList_isEmpty(tagged)) {
-      cp = doc->address;
-      if (!strncmp(cp,"file://localhost",16))
-	cp += 16;
-      else if (!strncmp(cp,"file:",5))
-	cp += 5;
-      strcpy(testpath,cp);
-      HTUnEscapeSome(testpath,"/");
-      count = modify_tagged(testpath);
+    int c, ans;
+    char *cp;
+    char testpath[512]; /* a bit ridiculous */
+    int count;
 
-      if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1;
-      doc->link = doc->link < 0 ? 0 : doc->link; 
+    if (!HTList_isEmpty(tagged)) {
+	cp = doc->address;
+	if (!strncmp(cp, "file://localhost", 16)) {
+	    cp += 16;
+	} else if (!strncmp(cp, "file:", 5)) {
+	    cp += 5;
+	}
+	strcpy(testpath, cp);
+	HTUnEscapeSome(testpath, "/");
+	count = modify_tagged(testpath);
 
-      return count;
-   } else if (doc->link < 0 || doc->link > nlinks) /* added protection */
-      return 0;
+	if (doc->link > (nlinks-count - 1))
+	    doc->link = (nlinks-count - 1);
+ 	doc->link = (doc->link < 0) ?
+				  0 : doc->link; 
 
-/* Do not allow simultaneous change of name and location as in Unix */
-/* This reduces functionality but reduces difficulty for the novice */
+	return count;
+    } else if (doc->link < 0 || doc->link > nlinks) {
+        /*
+	 *  Added protection.
+	 */
+	return 0;
+    }
 
+    /*
+     *  Do not allow simultaneous change of name and location as in Unix.
+     *  This reduces functionality but reduces difficulty for the novice.
+     */
 #ifdef OK_PERMIT
-   _statusline("Modify name, location, or permission (n, l, or p): ");
+    _statusline("Modify name, location, or permission (n, l, or p): ");
 #else
-   _statusline("Modify name, or location (n or l): ");
+    _statusline("Modify name, or location (n or l): ");
 #endif /* OK_PERMIT */
-   c = LYgetch();
-   ans=TOUPPER(c);
-
-   if (strchr("NLP",ans) != NULL) {
-      cp = links[doc->link].lname;
-      if(!strncmp(cp,"file://localhost",16))
-	cp += 16;
-      else if(!strncmp(cp,"file:",5))
-	cp += 5;
-      strcpy(testpath,cp);
-      HTUnEscape(testpath);
-
-      if (ans == 'N') {
-
-	 return(modify_name(testpath));
-
-      } else if (ans == 'L') {
-
-	 if (modify_location(testpath)) {
-
-	   if (doc->link == (nlinks-1)) --doc->link;
-
-	   return 1;
+    c = LYgetch();
+    ans = TOUPPER(c);
+
+    if (strchr("NLP", ans) != NULL) {
+	cp = links[doc->link].lname;
+	if (!strncmp(cp, "file://localhost", 16)) {
+	    cp += 16;
+	} else if(!strncmp(cp, "file:", 5)) {
+	    cp += 5;
 	}
+	strcpy(testpath, cp);
+	HTUnEscape(testpath);
+
+	if (ans == 'N') {
+	    return(modify_name(testpath));
+	} else if (ans == 'L') {
+	    if (modify_location(testpath)) {
+		if (doc->link == (nlinks-1))
+		    --doc->link;
+		return 1;
+	    }
 #ifdef OK_PERMIT
-      } else if (ans == 'P') {
-	  return(permit_location(NULL, testpath, newpath));
+	} else if (ans == 'P') {
+	    return(permit_location(NULL, testpath, newpath));
 #endif /* OK_PERMIT */
-
-      } else {
-
-/* code for changing ownership needed here */
-
-	 _statusline("This feature not yet implemented! ");
-	 sleep(AlertSecs);
-      }
-   }
-   return 0;
+	} else {
+	    /*
+	     *  Code for changing ownership needed here.
+	     */
+	     _statusline("This feature not yet implemented!");
+	    sleep(AlertSecs);
+	}
+    }
+    return 0;
 }
 
-/* Create a new empty file in the current directory. */
-
+/*
+ *  Create a new empty file in the current directory.
+ */
 PRIVATE BOOLEAN create_file ARGS1(
 	char *,		current_location)
 {
-   char tmpbuf[512];
-   char testpath[512];
-   struct stat dir_info;
-   char *args[5];
-   char *bad_chars = ".~/";
-
-   if (filename("Enter name of file to create: ",
-   		tmpbuf, sizeof(tmpbuf)) == NULL)
-      return 0;
-
-   if (!no_dotfiles && show_dotfiles) {
-       bad_chars = "~/";
-   }
+    char tmpbuf[512];
+    char testpath[512];
+    struct stat dir_info;
+    char *args[5];
+    char *bad_chars = ".~/";
 
-   if(strstr(tmpbuf,"//") != NULL) {
-      _statusline("Illegal redirection \"//\" found! Request ignored.");
-      sleep(AlertSecs);
-   } else if(strlen(tmpbuf) && strchr(bad_chars,tmpbuf[0]) == NULL) {
-      strcpy(testpath,current_location);
-      if(testpath[strlen(testpath)-1] != '/')
-	strcat(testpath,"/");
+    if (filename("Enter name of file to create: ",
+   		 tmpbuf, sizeof(tmpbuf)) == NULL) {
+	return 0;
+    }
 
-/* append the target filename to the current location */
+    if (!no_dotfiles && show_dotfiles) {
+	bad_chars = "~/";
+    }
 
-      strcat(testpath,tmpbuf);
+    if (strstr(tmpbuf, "//") != NULL) {
+	_statusline("Illegal redirection \"//\" found! Request ignored.");
+	sleep(AlertSecs);
+    } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) {
+	strcpy(testpath,current_location);
+	if (testpath[(strlen(testpath) - 1)] != '/') {
+	    strcat(testpath,"/");
+	}
 
-/* make sure the target does not already exist */
+	/*
+	 *  Append the target filename to the current location.
+	 */
+	strcat(testpath, tmpbuf);
 
-      if (stat(testpath,&dir_info) == -1) {
-	 if (errno != ENOENT) {
-	    sprintf(tmpbuf,"Unable to determine status of %s ",testpath);
-	    _statusline(tmpbuf);
+	/*
+	 *  Make sure the target does not already exist
+	 */
+	if (stat(testpath, &dir_info) == -1) {
+	    if (errno != ENOENT) {
+		sprintf(tmpbuf,
+			"Unable to determine status of '%s'.", testpath);
+		_statusline(tmpbuf);
+		sleep(AlertSecs);
+		return 0;
+	    } 
+	    sprintf(tmpbuf,"create %s",testpath);
+	    args[0] = "touch";
+	    args[1] = testpath;
+	    args[2] = (char *) 0;
+	    if (my_spawn(TOUCH_PATH, args, tmpbuf) <= 0)
+		return (-1);
+	    return 1;
+	} else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+	    _statusline(
+	   "There is already a directory with that name! Request ignored.");
 	    sleep(AlertSecs);
-	    return 0;
-	 } 
-	 sprintf(tmpbuf,"create %s",testpath);
-	 args[0] = "touch";
-	 args[1] = testpath;
-	 args[2] = (char *) 0;
-	 if (my_spawn(TOUCH_PATH, args, tmpbuf) <= 0)
-	    return (-1);
-	 return 1;
-      } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-	 _statusline(
-	   "There is already a directory with that name! Request ignored. ");
-	 sleep(AlertSecs);
-      } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
-	 _statusline(
-	 	"There is already a file with that name! Request ignored. ");
-	 sleep(AlertSecs);
-      } else {
-	 _statusline(
-	 	"The specified name is already in use! Request ignored. ");
-	 sleep(AlertSecs);
-      }
-   }
-   return 0;
+	} else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	    _statusline(
+	 	"There is already a file with that name! Request ignored.");
+	    sleep(AlertSecs);
+	} else {
+	    _statusline(
+		  "The specified name is already in use! Request ignored.");
+	    sleep(AlertSecs);
+	}
+    }
+    return 0;
 }
 
-/* Create a new directory in the current directory. */
-
+/*
+ *  Create a new directory in the current directory.
+ */
 PRIVATE BOOLEAN create_directory ARGS1(
 	char *,		current_location)
 {
-   char tmpbuf[512];
-   char testpath[512];
-   struct stat dir_info;
-   char *args[5];
-   char *bad_chars = ".~/";
-
-   if (filename("Enter name for new directory: ",
-   		tmpbuf, sizeof(tmpbuf)) == NULL)
-      return 0;
-
-   if (!no_dotfiles && show_dotfiles) {
-       bad_chars = "~/";
-   }
-
-   if(strstr(tmpbuf,"//") != NULL) {
-      _statusline("Illegal redirection \"//\" found! Request ignored.");
-      sleep(AlertSecs);
-   } else if(strlen(tmpbuf) && strchr(bad_chars,tmpbuf[0]) == NULL) {
-      strcpy(testpath,current_location);
+    char tmpbuf[512];
+    char testpath[512];
+    struct stat dir_info;
+    char *args[5];
+    char *bad_chars = ".~/";
 
-      if(testpath[strlen(testpath)-1] != '/')
-	strcat(testpath,"/");
+    if (filename("Enter name for new directory: ",
+   		 tmpbuf, sizeof(tmpbuf)) == NULL) {
+	return 0;
+    }
 
-      strcat(testpath,tmpbuf);
+    if (!no_dotfiles && show_dotfiles) {
+	bad_chars = "~/";
+    }
 
-/* make sure the target does not already exist */
+    if (strstr(tmpbuf, "//") != NULL) {
+	_statusline("Illegal redirection \"//\" found! Request ignored.");
+	sleep(AlertSecs);
+    } else if (strlen(tmpbuf) && strchr(bad_chars, tmpbuf[0]) == NULL) {
+ 	strcpy(testpath,current_location);
+ 	if (testpath[(strlen(testpath) - 1)] != '/') {
+	    strcat(testpath,"/");
+	}
+	strcat(testpath, tmpbuf);
 
-      if (stat(testpath,&dir_info) == -1) {
-	 if (errno != ENOENT) {
-	    sprintf(tmpbuf,"Unable to determine status of %s ",testpath);
-	    _statusline(tmpbuf);
+	/*
+	 *  Make sure the target does not already exist.
+	 */
+	if (stat(testpath, &dir_info) == -1) {
+	    if (errno != ENOENT) {
+		sprintf(tmpbuf,
+			"Unable to determine status of '%s'.", testpath);
+		_statusline(tmpbuf);
+		sleep(AlertSecs);
+		return 0;
+	    } 
+	    sprintf(tmpbuf,"make directory %s",testpath);
+	    args[0] = "mkdir";
+	    args[1] = testpath;
+	    args[2] = (char *) 0;
+	    if (my_spawn(MKDIR_PATH, args, tmpbuf) <= 0)
+		return (-1);
+	    return 1;
+	} else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+	    _statusline(
+	   "There is already a directory with that name! Request ignored.");
 	    sleep(AlertSecs);
-	    return 0;
-	 } 
-	 sprintf(tmpbuf,"make directory %s",testpath);
-	 args[0] = "mkdir";
-	 args[1] = testpath;
-	 args[2] = (char *) 0;
-	 if (my_spawn(MKDIR_PATH, args, tmpbuf) <= 0)
-	    return (-1);
-	 return 1;
-      } else if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-	 _statusline(
-	   "There is already a directory with that name! Request ignored. ");
-	 sleep(AlertSecs);
-      } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
-	 _statusline(
-	 	"There is already a file with that name! Request ignored. ");
-	 sleep(AlertSecs);
-      } else {
-	 _statusline(
-	 	"The specified name is already in use! Request ignored. ");
-	 sleep(AlertSecs);
-      }
-   }
-   return 0;
+	} else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	    _statusline(
+	 	"There is already a file with that name! Request ignored.");
+	    sleep(AlertSecs);
+	} else {
+	    _statusline(
+		  "The specified name is already in use! Request ignored.");
+	    sleep(AlertSecs);
+	}
+    }
+    return 0;
 }
 
-/* Create a file or a directory at the current location. */
-
+/*
+ *  Create a file or a directory at the current location.
+ */
 PUBLIC BOOLEAN local_create ARGS1(
 	document *,	doc)
 {
-   int c, ans;
-   char *cp;
-   char testpath[512];
-
-   _statusline("Create file or directory (f or d): ");
-   c = LYgetch();
-   ans = TOUPPER(c);
-
-   cp = doc->address;
-   if(!strncmp(cp,"file://localhost",16))
-     cp += 16;
-   else if(!strncmp(cp,"file:",5))
-     cp += 5;
-   strcpy(testpath,cp);
-   HTUnEscape(testpath);
-   
-   if (ans == 'F') 
-     return(create_file(testpath));
-   else if (ans == 'D') 
-     return(create_directory(testpath));
-   else return 0;
+    int c, ans;
+    char *cp;
+    char testpath[512];
 
-}
+    _statusline("Create file or directory (f or d): ");
+    c = LYgetch();
+    ans = TOUPPER(c);
 
-/* Remove a single file or directory. */
+    cp = doc->address;
+    if (!strncmp(cp, "file://localhost", 16)) {
+	cp += 16;
+    } else if (!strncmp(cp, "file:", 5)) {
+	cp += 5;
+    }
+    strcpy(testpath,cp);
+    HTUnEscape(testpath);
+
+    if (ans == 'F') {
+	return(create_file(testpath));
+    } else if (ans == 'D') {
+	return(create_directory(testpath));
+    } else {
+	return 0;
+    }
+}
 
+/*
+ *  Remove a single file or directory.
+ */
 PRIVATE BOOLEAN remove_single ARGS1(
 	char *,		testpath) 
 {
-   int c;
-   char *cp;
-   char tmpbuf[1024];
-   struct stat dir_info;
-   char *args[5];
-
-/* lstat first in case its a symbolic link */
-
-   if (lstat(testpath,&dir_info) == -1 && stat(testpath,&dir_info) == -1) {
-      sprintf(tmpbuf,"System error - failed to get status of %s. ",testpath);
-      _statusline(tmpbuf);
-      sleep(AlertSecs);
-      return 0;
-   } 
-
-/* locate the filename portion of the path */
-
-   if ((cp = strrchr(testpath,'/')) != NULL) {
-      ++cp;
-   } else {
-      cp = testpath;
-   }
-   if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
-      if(strlen(cp) < 37)
-	sprintf(tmpbuf,"Remove %s and all of its contents (y or n): ",cp);
-      else
-	sprintf(tmpbuf,"Remove directory and all of its contents (y or n): ");
-   } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
-      if(strlen(cp) < 60)
-	sprintf(tmpbuf,"Remove file %s (y or n): ",cp);
-      else 
-	sprintf(tmpbuf,"Remove file (y or n): ");
-   } else if ((dir_info.st_mode & S_IFMT) == S_IFLNK) {
-      if(strlen(cp) < 50)
-	sprintf(tmpbuf,"Remove symbolic link %s (y or n): ",cp);
-      else 
-	sprintf(tmpbuf,"Remove symbolic link (y or n): ");
-   } else {
-      sprintf(tmpbuf,"Unable to determine status of %s. ",testpath);
-      _statusline(tmpbuf);
-      sleep(AlertSecs);
-      return 0;
-   }
-   _statusline(tmpbuf);
-
-   c = LYgetch();
-   if(TOUPPER(c) == 'Y') {
-      sprintf(tmpbuf,"remove %s",testpath);
-      args[0] = "rm";
-      args[1] = "-rf";
-      args[2] = testpath;
-      args[3] = (char *) 0;
-      if (my_spawn(RM_PATH, args, tmpbuf) <= 0)
-	  return (-1);
-      return 1;
-   }
-   return 0;
-}
+    int c;
+    char *cp;
+    char tmpbuf[1024];
+    struct stat dir_info;
+    char *args[5];
 
-/* Remove a file or a directory. */
+    /*
+     *  lstat() first in case its a symbolic link.
+     */
+    if (lstat(testpath, &dir_info) == -1 &&
+        stat(testpath, &dir_info) == -1) {
+	sprintf(tmpbuf,
+		"System error - failed to get status of '%s'.", testpath);
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+	return 0;
+    }
+
+    /*
+     *  Locate the filename portion of the path.
+     */
+    if ((cp = strrchr(testpath, '/')) != NULL) {
+	++cp;
+    } else {
+	cp = testpath;
+    }
+    if ((dir_info.st_mode & S_IFMT) == S_IFDIR) {
+	if (strlen(cp) < 37) {
+	    sprintf(tmpbuf,
+		    "Remove '%s' and all of its contents (y or n): ", cp);
+	} else {
+	    sprintf(tmpbuf,
+		    "Remove directory and all of its contents (y or n): ");
+	}
+    } else if ((dir_info.st_mode & S_IFMT) == S_IFREG) {
+	if (strlen(cp) < 60) {
+	    sprintf(tmpbuf, "Remove file '%s' (y or n): ", cp);
+	} else {
+	    sprintf(tmpbuf, "Remove file (y or n): ");
+	}
+    } else if ((dir_info.st_mode & S_IFMT) == S_IFLNK) {
+	if (strlen(cp) < 50) {
+	    sprintf(tmpbuf, "Remove symbolic link '%s' (y or n): ", cp);
+	} else {
+	    sprintf(tmpbuf, "Remove symbolic link (y or n): ");
+	}
+    } else {
+	sprintf(tmpbuf, "Unable to determine status of '%s'.", testpath);
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+	return 0;
+    }
+    _statusline(tmpbuf);
+
+    c = LYgetch();
+    if (TOUPPER(c) == 'Y') {
+	sprintf(tmpbuf,"remove %s",testpath);
+	args[0] = "rm";
+	args[1] = "-rf";
+	args[2] = testpath;
+	args[3] = (char *) 0;
+	if (my_spawn(RM_PATH, args, tmpbuf) <= 0)
+	    return (-1);
+	return 1;
+    }
+    return 0;
+}
 
+/*
+ *  Remove a file or a directory.
+ */
 PUBLIC BOOLEAN local_remove ARGS1(
 	document *,	doc)
 {  
-   char *cp,*tp;
-   char testpath[512];
-   int count,i;
-
-   if (!HTList_isEmpty(tagged)) {
-
-      count = remove_tagged();
-
-      if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1;
-      doc->link = doc->link < 0 ? 0 : doc->link; 
-
-      return count;
-   } else if (doc->link < 0 || doc->link > nlinks)
-      return 0;
-   cp = links[doc->link].lname;
-   if(is_url(cp) == FILE_URL_TYPE) {
-      tp = cp;
-      if(!strncmp(tp,"file://localhost",16))
-	tp += 16;
-      else if(!strncmp(tp,"file:",5))
-	tp += 5;
-      strcpy(testpath,tp);
-      HTUnEscape(testpath);
-      if((i = strlen(testpath)) && testpath[i-1] == '/')
-	testpath[i-1] = '\0';
-
-      if (remove_single(testpath)) {
-
-	 if (doc->link == (nlinks-1)) --doc->link;
-
-	 return 1;
-      }
-   }
-   return 0;
+    char *cp, *tp;
+    char testpath[512];
+    int count, i;
+
+    if (!HTList_isEmpty(tagged)) {
+	count = remove_tagged();
+	if (doc->link > (nlinks-count - 1))
+	    doc->link = (nlinks-count - 1);
+	doc->link = (doc->link < 0) ?
+				  0 : doc->link; 
+	return count;
+    } else if (doc->link < 0 || doc->link > nlinks) {
+	return 0;
+    }
+    cp = links[doc->link].lname;
+    if (is_url(cp) == FILE_URL_TYPE) {
+	tp = cp;
+	if (!strncmp(tp, "file://localhost", 16)) {
+	    tp += 16;
+	} else if (!strncmp(tp, "file:", 5)) {
+	    tp += 5;
+	}
+	strcpy(testpath, tp);
+	HTUnEscape(testpath);
+	if ((i = strlen(testpath)) && testpath[i - 1] == '/')
+	    testpath[(i - 1)] = '\0';
+	if (remove_single(testpath)) {
+	    if (doc->link == (nlinks - 1))
+		--doc->link;
+	    return 1;
+	}
+    }
+    return 0;
 }
 
 #ifdef OK_PERMIT
-/* Table of permission strings and chmod values. Makes the code a bit cleaner */
+/*
+ *  Table of permission strings and chmod values.
+ *  Makes the code a bit cleaner.
+ */
 static struct {
     char *string_mode;	/* Key for  value below */
     long permit_bits;	/* Value for chmod/whatever */
@@ -977,20 +1050,22 @@ static struct {
     {"IROTH", S_IROTH},
     {"IWOTH", S_IWOTH},
     {"IXOTH", S_IXOTH},
-    {NULL, 0}			/* Don't include setuid and friends,
-				   use shell access for that */
+    {NULL, 0}			/* Don't include setuid and friends;
+				   use shell access for that. */
 };
 
 #ifndef S_ISDIR
-#  define S_ISDIR(mode)   ((mode&0xF000) == 0x4000)
+#define S_ISDIR(mode)   ((mode&0xF000) == 0x4000)
 #endif /* !S_ISDIR */
     
+/*
+ *  Handle DIRED permissions.
+ */
 PRIVATE BOOLEAN permit_location ARGS3(
 	char *,		destpath,
 	char *,		srcpath,
 	char **,	newpath)
 {
-
 #ifndef UNIX
     _statusline("Sorry, don't know how to permit non-UNIX files yet.");
     sleep(AlertSecs);
@@ -1002,21 +1077,24 @@ PRIVATE BOOLEAN permit_location ARGS3(
     char tmpbuf[LINESIZE];
     struct stat dir_info;
 
-    if (srcpath) {                      /* Create form */
+    if (srcpath) {
+        /*
+	 *  Create form.
+	 */
 	FILE *fp0;
 	char print_filename[256];
 	char * user_filename;
 	struct group * grp;
 	char * group_name;
 
-	/* A couple of sanity tests */
-
+	/*
+	 *  A couple of sanity tests.
+	 */
 	srcpath = strip_trailing_slash(srcpath);
-	if(strncmp(srcpath,"file://localhost",16) == 0)
+	if (strncmp(srcpath, "file://localhost", 16) == 0)
 	    srcpath += 16;
-	
-	if (lstat(srcpath,&dir_info) == -1) {
-	    sprintf(tmpbuf,"Unable to get status of %s ",srcpath);
+	if (lstat(srcpath, &dir_info) == -1) {
+	    sprintf(tmpbuf, "Unable to get status of '%s'.", srcpath);
 	    _statusline(tmpbuf);
 	    sleep(AlertSecs);
 	    return 0;
@@ -1031,7 +1109,7 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	user_filename = srcpath;
 	cp = strrchr(srcpath, '/');
 	if (cp != NULL) {
-	    user_filename = cp + 1;
+	    user_filename = (cp + 1);
 	}
 	
 	if (first) {
@@ -1039,17 +1117,20 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	    first = FALSE;
 	}
 	
-	if ((fp0 = fopen(tempfile,"w")) == NULL) {
+	if ((fp0 = fopen(tempfile, "w")) == NULL) {
 	    _statusline("Unable to open permit options file");
 	    sleep(AlertSecs);
 	    return(0);
 	}
+	chmod(tempfile, 0600);
 	
-	/* make the tempfile a URL */
+	/*
+	 *  Make the tempfile a URL.
+	 */
 	strcpy(print_filename, "file://localhost");
 	strcat(print_filename, tempfile);
 	StrAllocCopy(*newpath, print_filename);
-	
+
 	grp = getgrgid(dir_info.st_gid);
 	if (grp == NULL) {
 	    group_name = "";
@@ -1060,7 +1141,9 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	fprintf(fp0, "<Html><Head>\n<Title>%s</Title>\n</Head>\n<Body>\n",
 		PERMIT_OPTIONS_TITLE);
 	fprintf(fp0,"<H1>Permissions for %s</H1>\n", user_filename);
-	{  /* prevent filenames which include '#' or '?' from messing it up */
+	{   /*
+	     *  Prevent filenames which include '#' or '?' from messing it up.
+	     */
 	    char * srcpath_url = HTEscape(srcpath, URL_PATH);
 	    fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n",
 		    srcpath_url);
@@ -1070,62 +1153,64 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	fprintf(fp0, "<Ol><Li>Specify permissions below:<Br><Br>\n");
 	fprintf(fp0, "Owner:<Br>\n");
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n",
-		dir_info.st_mode & S_IRUSR ? "checked" : "");
+     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRUSR\" %s> Read<Br>\n",
+		(dir_info.st_mode & S_IRUSR) ? "checked" : "");
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n",
-		dir_info.st_mode & S_IWUSR ? "checked" : "");
+    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWUSR\" %s> Write<Br>\n",
+		(dir_info.st_mode & S_IWUSR) ? "checked" : "");
 	/*
-	 * If restricted, only change eXecute permissions on directories.
+	 *  If restricted, only change eXecute permissions on directories.
 	 */
 	if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 	    fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXUSR\" %s> %s<Br>\n",
-		dir_info.st_mode & S_IXUSR ? "checked" : "",
+       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXUSR\" %s> %s<Br>\n",
+		(dir_info.st_mode & S_IXUSR) ? "checked" : "",
 		S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 	
 	fprintf(fp0, "Group %s:<Br>\n", group_name);
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n",
-		dir_info.st_mode & S_IRGRP ? "checked" : "");
+     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IRGRP\" %s> Read<Br>\n",
+		(dir_info.st_mode & S_IRGRP) ? "checked" : "");
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n",
-		dir_info.st_mode & S_IWGRP ? "checked" : "");
+    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWGRP\" %s> Write<Br>\n",
+		(dir_info.st_mode & S_IWGRP) ? "checked" : "");
 	/*
-	 * If restricted, only change eXecute permissions on directories.
+	 *  If restricted, only change eXecute permissions on directories.
 	 */
 	if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 	    fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXGRP\" %s> %s<Br>\n",
-		dir_info.st_mode & S_IXGRP ? "checked" : "",
+       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXGRP\" %s> %s<Br>\n",
+		(dir_info.st_mode & S_IXGRP) ? "checked" : "",
 		S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 	
 	fprintf(fp0, "Others:<Br>\n");
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n",
-		dir_info.st_mode & S_IROTH ? "checked" : "");
+     "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IROTH\" %s> Read<Br>\n",
+		(dir_info.st_mode & S_IROTH) ? "checked" : "");
 	fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n",
-		dir_info.st_mode & S_IWOTH ? "checked" : "");
+    "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IWOTH\" %s> Write<Br>\n",
+		(dir_info.st_mode & S_IWOTH) ? "checked" : "");
 	/*
-	 * If restricted, only change eXecute permissions on directories.
+	 *  If restricted, only change eXecute permissions on directories.
 	 */
 	if (!no_change_exec_perms || S_ISDIR(dir_info.st_mode))
 	    fprintf(fp0,
-		"<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXOTH\" %s> %s<Br>\n",
-		dir_info.st_mode & S_IXOTH ? "checked" : "",
+       "<Input Type=\"checkbox\" Name=\"mode\" Value=\"IXOTH\" %s> %s<Br>\n",
+		(dir_info.st_mode & S_IXOTH) ? "checked" : "",
 		S_ISDIR(dir_info.st_mode) ? "Search" : "Execute");
 	
-	fprintf(fp0, "<Br>\n<Li><Input Type=\"submit\" Value=\"Submit\"> form to permit %s %s.\n</Ol>\n</Form>\n",
+	fprintf(fp0,
+"<Br>\n<Li><Input Type=\"submit\" Value=\"Submit\"> \
+form to permit %s %s.\n</Ol>\n</Form>\n",
 		(dir_info.st_mode & S_IFMT) == S_IFDIR ? "directory" : "file",
 		user_filename);
 	fprintf(fp0, "</Body></Html>");
 	fclose(fp0);
 	
-	++LYforce_no_cache;
+	LYforce_no_cache = TRUE;
 	return(PERMIT_FORM_RESULT);      /* Special flag for LYMainLoop */
 
-    } else {                             /* The form being activated */
+    } else {                             /* The form being activated. */
 	mode_t new_mode = 0;
 	char *args[5];
 	char amode[10];
@@ -1135,17 +1220,19 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	    cp++;
 	}
 	if (*cp == '\0') {
-	    return(0);	/* Nothing to permit */
+	    return(0);	/* Nothing to permit. */
 	}
-	*cp++ = '\0';	/* Null terminate file name
-			   and start working on the masks */
+	*cp++ = '\0';	/* Null terminate file name and
+			   start working on the masks. */
 
-	HTUnEscape(destpath);	/* will now operate only on filename part */
+	HTUnEscape(destpath);	/* Will now operate only on filename part. */
 	
-	/* A couple of sanity tests */
+	/*
+	 *  A couple of sanity tests.
+	 */
 	destpath = strip_trailing_slash(destpath);
-	if (stat(destpath,&dir_info) == -1) {
-	    sprintf(tmpbuf,"Unable to get status of %s ",destpath);
+	if (stat(destpath, &dir_info) == -1) {
+	    sprintf(tmpbuf, "Unable to get status of '%s'.", destpath);
 	    _statusline(tmpbuf);
 	    sleep(AlertSecs);
 	    return 0;
@@ -1157,24 +1244,26 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	    return 0;
 	}
 	
-	/* Cycle over permission strings */
+	/*
+	 *  Cycle over permission strings.
+	 */
 	while(*cp != '\0') {
 	    char *cr = cp;
 	    
-	    while(*cr != '\0' && *cr != '&') { /* GET data split by '&' */
+	    while(*cr != '\0' && *cr != '&') { /* GET data split by '&'. */
 		cr++;
 	    }
 	    if (*cr != '\0') {
 		*cr++ = '\0';
 	    }
-	    if (strncmp(cp, "mode=", 5) == 0) {	/* Magic string */
+	    if (strncmp(cp, "mode=", 5) == 0) {	/* Magic string. */
 		int i;
 
 		for(i = 0; permissions[i].string_mode != NULL; i++) {
 		    if (strcmp(permissions[i].string_mode, cp+5) == 0) {
 		        /*
-			 * If restricted, only change eXecute
-			 * permissions on directories
+			 *  If restricted, only change eXecute
+			 *  permissions on directories.
 			 */
 			if (!no_change_exec_perms ||
 			    strchr(cp+5,'X') == NULL ||
@@ -1197,8 +1286,10 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	    cp = cr;
 	}
 	
-	/* Call chmod */
-	sprintf(tmpbuf,"chmod %.4o %s", new_mode, destpath);
+	/*
+	 *  Call chmod().
+	 */
+	sprintf(tmpbuf, "chmod %.4o %s", new_mode, destpath);
 	sprintf(amode, "%.4o", new_mode);
 	args[0] = "chmod";
 	args[1] = amode;
@@ -1207,318 +1298,302 @@ PRIVATE BOOLEAN permit_location ARGS3(
 	if (my_spawn(CHMOD_PATH, args, tmpbuf) <= 0) {
 	    return (-1);
 	}
-	++LYforce_no_cache;         /* Force update of dired listing */
+	LYforce_no_cache = TRUE;	/* Force update of dired listing. */
 	return 1;
     }
 #endif /* !UNIX */
 }
 #endif /* OK_PERMIT */
 
-#ifdef NOTDEFINED
-PUBLIC BOOLEAN is_a_file ARGS1(
-	char *,		testname)
-{ 
-   char *cp;
-   char testpath[512];
-   struct stat dir_info;
-
-   cp = testname;
-   if(!strncmp(cp,"file://localhost",16))
-     cp += 16;
-   else if(!strncmp(cp,"file:",5))
-     cp += 5;
-   strcpy(testpath,cp);
-   HTUnEscape(testpath);
-   if (stat(testpath,&dir_info) == -1) 
-      return -1; 
-   else
-     if (((dir_info.st_mode) & S_IFMT) == S_IFREG)
-       return 1;
-     else
-       return 0;
-}
-#endif /* NOTDEFINED */
-
-/* display or remove a tag from a given link */
-
+/*
+ *  Display or remove a tag from a given link.
+ */
 PUBLIC void tagflag ARGS2(
-	int,	flag,
-	int,	cur)
+	int,		flag,
+	int,		cur)
 {
-    if (nlinks > 0 /*&& links[cur].lx == 3*/) {
-       move(links[cur].ly,2 /*links[cur].lx-2*/);
-       stop_reverse();
-       if (flag == ON)
-	  addch('+');
-       else
-	  addch(' ');
+    if (nlinks > 0) {
+	move(links[cur].ly, 2);
+	stop_reverse();
+	if (flag == ON) {
+	    addch('+');
+	} else {
+	    addch(' ');
+	}
 
 #if defined(FANCY_CURSES) || defined(USE_SLANG)
-      if(!LYShowCursor)
-          move(LYlines-1,LYcols-1);  /* get cursor out of the way */
-      else
+	if (!LYShowCursor)
+	    move((LYlines - 1), (LYcols - 1)); /* get cursor out of the way */
+	else
 #endif /* FANCY CURSES || USE_SLANG */
-	  /* never hide the cursor if there's no FANCY CURSES */
-          move(links[cur].ly, links[cur].lx);
+	    /*
+	     *  Never hide the cursor if there's no FANCY CURSES.
+	     */
+	    move(links[cur].ly, links[cur].lx);
 
-/***
-      if(flag)
-***/
-          refresh();
+	refresh();
     }
 }
 
+/*
+ *  Handle DIRED tags.
+ */
 PUBLIC void showtags ARGS1(
 	HTList *,	t)
 {
     int i;
     HTList *s;
-    char * name;
-
-    for(i=0;i<nlinks;i++) {
-      s = t;
-      while((name = HTList_nextObject(s)) != NULL) {
-	 if(!strcmp(links[i].lname,name)) {
-	    tagflag(ON,i);
-	    break;
-	 }
-      }
-   }
+    char *name;
+
+    for (i = 0; i < nlinks; i++) {
+	s = t;
+	while ((name = HTList_nextObject(s)) != NULL) {
+	    if (!strcmp(links[i].lname, name)) {
+		tagflag(ON, i);
+		break;
+	    }
+	}
+    }
 }
 
 /*
-**  Perform file management operations for LYNXDIRED URL's.
-**  Attempt to be consistent.  These are (pseudo) URLs - i.e. they should
-**  be in URL syntax: some bytes will be URL-escaped with '%'.  This is 
-**  necessary because these (pseudo) URLs will go through some of the same 
-**  kinds of interpretations and mutilations as real ones: HTParse, stripping
-**  off #fragments etc.  (Some access schemes currently have special rules 
-**  about not escaping parsing '#' "the URL way" built into HTParse, but that
-**  doesn't look like a clean way.)  
-*/
+ *  Perform file management operations for LYNXDIRED URL's.
+ *  Attempt to be consistent.  These are (pseudo) URLs - i.e. they should
+ *  be in URL syntax: some bytes will be URL-escaped with '%'.  This is 
+ *  necessary because these (pseudo) URLs will go through some of the same 
+ *  kinds of interpretations and mutilations as real ones: HTParse, stripping
+ *  off #fragments etc.  (Some access schemes currently have special rules 
+ *  about not escaping parsing '#' "the URL way" built into HTParse, but that
+ *  doesn't look like a clean way.)  
+ */
 PUBLIC int local_dired ARGS1(
 	document *,	doc)
 {
-   char *line_url;    /* will point to doc's address, which is a URL */
-   char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */
-   char *cp, *tp, *bp;
-   char tmpbuf[256];
-   char buffer[512];
+    char *line_url;    /* will point to doc's address, which is a URL */
+    char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */
+    char *cp, *tp, *bp;
+    char tmpbuf[256];
+    char buffer[512];
 
-   line_url = doc->address;
-   HTUnEscapeSome(line_url,"/");	/* don't mess too much with *doc */
+    line_url = doc->address;
+    HTUnEscapeSome(line_url, "/");	/* don't mess too much with *doc */
 
-   StrAllocCopy(line, line_url);
-   HTUnEscape(line);	/* _file_ (not URL) syntax, for those functions
+    StrAllocCopy(line, line_url);
+    HTUnEscape(line);	/* _file_ (not URL) syntax, for those functions
 			   that need it.  DOn't forget to FREE it. */
 
-   /* This causes a SIGSEGV later when StrAllocCopy tries to free tp
-    * let's make it point to NULL
-   tp = tmpbuf;
-    */
-   tp = NULL;
-   if (!strncmp(line,"LYNXDIRED://NEW_FILE",20)) {
-      if (create_file(&line[20]) > 0)
-          ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://NEW_FOLDER",22)) {
-      if (create_directory(&line[22]) > 0)
-          ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://INSTALL_SRC",23)) {
-      local_install(NULL, &line[23], &tp);
-      StrAllocCopy(doc->address, tp);
-      FREE(line);
-      return 0;
-   } else if (!strncmp(line,"LYNXDIRED://INSTALL_DEST",24)) {
-      local_install(&line[24], NULL, &tp);
-      LYpop(doc);
-   } else if (!strncmp(line,"LYNXDIRED://MODIFY_NAME",23)) {
-      if (modify_name(&line[23]) > 0)
-          ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://MODIFY_LOCATION",27)) {
-      if (modify_location(&line[27]) > 0)
-          ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://MOVE_TAGGED",23)) {
-      if (modify_tagged(&line_url[23]) > 0)
-          ++LYforce_no_cache;
+    tp = NULL;
+    if (!strncmp(line, "LYNXDIRED://NEW_FILE", 20)) {
+	if (create_file(&line[20]) > 0)
+	    LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://NEW_FOLDER", 22)) {
+	if (create_directory(&line[22]) > 0)
+ 	    LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://INSTALL_SRC", 23)) {
+	local_install(NULL, &line[23], &tp);
+	StrAllocCopy(doc->address, tp);
+	FREE(line);
+	return 0;
+    } else if (!strncmp(line, "LYNXDIRED://INSTALL_DEST", 24)) {
+	local_install(&line[24], NULL, &tp);
+	LYpop(doc);
+    } else if (!strncmp(line, "LYNXDIRED://MODIFY_NAME", 23)) {
+	if (modify_name(&line[23]) > 0)
+	LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://MODIFY_LOCATION", 27)) {
+	if (modify_location(&line[27]) > 0)
+ 	    LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://MOVE_TAGGED", 23)) {
+	if (modify_tagged(&line_url[23]) > 0)
+	    LYforce_no_cache = TRUE;
 #ifdef OK_PERMIT
-   } else if (!strncmp(line,"LYNXDIRED://PERMIT_SRC",22)) {
-      permit_location(NULL, &line[22], &tp);
-      if (tp)			/* one of the checks may have failed */
-	  StrAllocCopy(doc->address, tp);
-      FREE(line);
-      return 0;
-   } else if (!strncmp(line,"LYNXDIRED://PERMIT_LOCATION",27)) {
-       permit_location(&line_url[27], NULL, &tp);
-#endif /* OK_PERMIT */
-   } else if (!strncmp(line,"LYNXDIRED://REMOVE_SINGLE",25)) {
-      if (remove_single(&line[25]) > 0)
-          ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://REMOVE_TAGGED",25)) {
-      if (remove_tagged()) ++LYforce_no_cache;
-   } else if (!strncmp(line,"LYNXDIRED://CLEAR_TAGGED",24)) {
-      clear_tags();
-   } else if (!strncmp(line,"LYNXDIRED://UPLOAD",18)) {
-      /*
-       *  They're written by LYUpload_options() HTUnEscaped,
-       *  don't want to change that for now... so pass through
-       *  without more unescaping.  Directory names containing
-       *  '#' will probably fail..
-       */
-      if (LYUpload(line_url)) ++LYforce_no_cache;
-   } else {
-      if (line[strlen(line)-1] == '/')
-	line[strlen(line)-1] = '\0';
-      if ((cp = strrchr(line,'/')) == NULL) {
+    } else if (!strncmp(line, "LYNXDIRED://PERMIT_SRC", 22)) {
+	permit_location(NULL, &line[22], &tp);
+	if (tp)
+	    /*
+	     *  One of the checks may have failed.
+	     */
+	    StrAllocCopy(doc->address, tp);
 	FREE(line);
 	return 0;
-      }
-
-/* Construct the appropriate system command taking care to escape all
-   path references to avoid spoofing the shell. */
+    } else if (!strncmp(line, "LYNXDIRED://PERMIT_LOCATION", 27)) {
+	permit_location(&line_url[27], NULL, &tp);
+#endif /* OK_PERMIT */
+    } else if (!strncmp(line, "LYNXDIRED://REMOVE_SINGLE", 25)) {
+	if (remove_single(&line[25]) > 0)
+	    LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://REMOVE_TAGGED", 25)) {
+	if (remove_tagged())
+	    LYforce_no_cache = TRUE;
+    } else if (!strncmp(line, "LYNXDIRED://CLEAR_TAGGED", 24)) {
+	clear_tags();
+    } else if (!strncmp(line, "LYNXDIRED://UPLOAD", 18)) {
+	/*
+	 *  They're written by LYUpload_options() HTUnEscaped;
+	 *  don't want to change that for now... so pass through
+	 *  without more unescaping.  Directory names containing
+	 *  '#' will probably fail.
+	 */
+	if (LYUpload(line_url))
+	    LYforce_no_cache = TRUE;
+    } else {
+	if (line[(strlen(line) - 1)] == '/')
+	    line[strlen(line)-1] = '\0';
+	if ((cp = strrchr(line, '/')) == NULL) {
+	    FREE(line);
+	    return 0;
+	}
 
-      *buffer = '\0';
-      if (!strncmp(line,"LYNXDIRED://DECOMPRESS",22)) {
-	tp = quote_pathname(line+22); 
-	sprintf(buffer,"%s %s", UNCOMPRESS_PATH, tp);
-	FREE(tp);
+	/*
+	 *  Construct the appropriate system command taking care to
+	 *  escape all path references to avoid spoofing the shell.
+	 */
+	*buffer = '\0';
+	if (!strncmp(line, "LYNXDIRED://DECOMPRESS", 22)) {
+	    tp = quote_pathname(line + 22);
+	    sprintf(buffer,"%s %s", UNCOMPRESS_PATH, tp);
+	    FREE(tp);
 
 #if defined(OK_UUDECODE) && !defined(ARCHIVE_ONLY)
-      } else if (!strncmp(line,"LYNXDIRED://UUDECODE",20)) {
-	tp = quote_pathname(line+20); 
-	sprintf(buffer,"%s %s", UUDECODE_PATH, tp);
-	_statusline(
+	} else if (!strncmp(line, "LYNXDIRED://UUDECODE", 20)) {
+	    tp = quote_pathname(line + 20);
+	    sprintf(buffer,"%s %s", UUDECODE_PATH, tp);
+	    _statusline(
       "Warning! UUDecoded file will exist in the directory you started Lynx.");
-	sleep(AlertSecs);
-	FREE(tp);
+	    sleep(AlertSecs);
+	    FREE(tp);
 #endif /* OK_UUDECODE && !ARCHIVE_ONLY */
 
 #ifdef OK_TAR
 # ifndef ARCHIVE_ONLY
 #  ifdef OK_GZIP
-      } else if (!strncmp(line,"LYNXDIRED://UNTAR_GZ",20)) {
-	tp = quote_pathname(line+20);
-	*cp++ = '\0';
-	cp = quote_pathname(line+20);
-	sprintf(buffer, "%s -qdc %s | (cd %s; %s -xf -)",
-			GZIP_PATH, tp, cp, TAR_PATH);
-	FREE(cp);
-	FREE(tp);
+	} else if (!strncmp(line, "LYNXDIRED://UNTAR_GZ", 20)) {
+	    tp = quote_pathname(line+20);
+	    *cp++ = '\0';
+	    cp = quote_pathname(line + 20);
+	    sprintf(buffer, "%s -qdc %s | (cd %s; %s -xf -)",
+			    GZIP_PATH, tp, cp, TAR_PATH);
+	    FREE(cp);
+	    FREE(tp);
 #  endif /* OK_GZIP */
 
-      } else if (!strncmp(line,"LYNXDIRED://UNTAR_Z",19)) {
-	tp = quote_pathname(line+19);
-	*cp++ = '\0';
-	cp = quote_pathname(line+19);
-	sprintf(buffer, "%s %s | (cd %s; %s -xf -)",
-			ZCAT_PATH, tp, cp, TAR_PATH);
-	FREE(cp);
-	FREE(tp);
-
-      } else if (!strncmp(line,"LYNXDIRED://UNTAR",17)) {
-	tp = quote_pathname(line+17);
-	*cp++ = '\0';
-	cp = quote_pathname(line+17);
-	sprintf(buffer,"cd %s; %s -xf %s", cp, TAR_PATH, tp);
-	FREE(cp);
-	FREE(tp);
+	} else if (!strncmp(line, "LYNXDIRED://UNTAR_Z", 19)) {
+	    tp = quote_pathname(line + 19);
+	    *cp++ = '\0';
+	    cp = quote_pathname(line + 19);
+	    sprintf(buffer, "%s %s | (cd %s; %s -xf -)",
+			    ZCAT_PATH, tp, cp, TAR_PATH);
+	    FREE(cp);
+	    FREE(tp);
+
+	} else if (!strncmp(line, "LYNXDIRED://UNTAR", 17)) {
+	    tp = quote_pathname(line + 17);
+	    *cp++ = '\0';
+	    cp = quote_pathname(line + 17);
+	    sprintf(buffer, "cd %s; %s -xf %s", cp, TAR_PATH, tp);
+	    FREE(cp);
+	    FREE(tp);
 # endif /* !ARCHIVE_ONLY */
 
 # ifdef OK_GZIP
-      } else if (!strncmp(line,"LYNXDIRED://TAR_GZ",18)) {
-	*cp++ = '\0';
-	cp = quote_pathname(cp);
-	tp = quote_pathname(line+18);
-	sprintf(buffer, "(cd %s; %s -cf - %s) | %s -qc >%s/%s.tar.gz",
-			tp, TAR_PATH, cp, GZIP_PATH, tp, cp);
-	FREE(cp);
-	FREE(tp);
+	} else if (!strncmp(line, "LYNXDIRED://TAR_GZ", 18)) {
+	    *cp++ = '\0';
+	    cp = quote_pathname(cp);
+	    tp = quote_pathname(line + 18);
+	    sprintf(buffer, "(cd %s; %s -cf - %s) | %s -qc >%s/%s.tar.gz",
+			    tp, TAR_PATH, cp, GZIP_PATH, tp, cp);
+	    FREE(cp);
+	    FREE(tp);
 # endif /* OK_GZIP */
 
-      } else if (!strncmp(line,"LYNXDIRED://TAR_Z",17)) {
-	*cp++ = '\0';
-        cp = quote_pathname(cp);
-	tp = quote_pathname(line+17);
-	sprintf(buffer, "(cd %s; %s -cf - %s) | %s >%s/%s.tar.Z",
-			tp, TAR_PATH, cp, COMPRESS_PATH, tp, cp);
-	FREE(cp);
-	FREE(tp);
-
-      } else if (!strncmp(line,"LYNXDIRED://TAR",15)) {
-	*cp++ = '\0';
-        cp = quote_pathname(cp);
-	tp = quote_pathname(line+15);
-	sprintf(buffer,"(cd %s; %s -cf %s.tar %s)", tp, TAR_PATH, cp, cp);
-	FREE(cp);
-	FREE(tp);
+	} else if (!strncmp(line, "LYNXDIRED://TAR_Z", 17)) {
+	    *cp++ = '\0';
+            cp = quote_pathname(cp);
+	    tp = quote_pathname(line + 17);
+	    sprintf(buffer, "(cd %s; %s -cf - %s) | %s >%s/%s.tar.Z",
+			    tp, TAR_PATH, cp, COMPRESS_PATH, tp, cp);
+	    FREE(cp);
+	    FREE(tp);
+
+	} else if (!strncmp(line, "LYNXDIRED://TAR", 15)) {
+	    *cp++ = '\0';
+            cp = quote_pathname(cp);
+	    tp = quote_pathname(line + 15);
+	    sprintf(buffer, "(cd %s; %s -cf %s.tar %s)",
+	    		    tp, TAR_PATH, cp, cp);
+	    FREE(cp);
+	    FREE(tp);
 #endif /* OK_TAR */
 
 #ifdef OK_GZIP
-      } else if (!strncmp(line,"LYNXDIRED://GZIP",16)) {
-	tp = quote_pathname(line+16);
-	sprintf(buffer,"%s -q %s", GZIP_PATH, tp);
-	FREE(tp);
-# ifndef ARCHIVE_ONLY
-      } else if (!strncmp(line,"LYNXDIRED://UNGZIP",18)) {
-	tp = quote_pathname(line+18);
-	sprintf(buffer,"%s -d %s", GZIP_PATH, tp);
-	FREE(tp);
-# endif /* !ARCHIVE_ONLY */
+	} else if (!strncmp(line, "LYNXDIRED://GZIP", 16)) {
+	    tp = quote_pathname(line + 16);
+	    sprintf(buffer, "%s -q %s", GZIP_PATH, tp);
+	    FREE(tp);
+#ifndef ARCHIVE_ONLY
+	} else if (!strncmp(line, "LYNXDIRED://UNGZIP", 18)) {
+	    tp = quote_pathname(line + 18);
+	    sprintf(buffer, "%s -d %s", GZIP_PATH, tp);
+	    FREE(tp);
+#endif /* !ARCHIVE_ONLY */
 #endif /* OK_GZIP */
 
 #ifdef OK_ZIP
-      } else if (!strncmp(line,"LYNXDIRED://ZIP",15)) {
-	tp = quote_pathname(line+15);
-	*cp++ = '\0';
-	bp = quote_pathname(cp);
-	cp = quote_pathname(line+15);
-	sprintf(buffer,"cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp);
-	FREE(cp);
-	FREE(bp);
-	FREE(tp);
-# ifndef ARCHIVE_ONLY
-      } else if (!strncmp(line,"LYNXDIRED://UNZIP",17)) {
-	tp = quote_pathname(line+17);
-	*cp = '\0';
-	cp = quote_pathname(line+17);
-	sprintf(buffer,"cd %s; %s -q %s", cp, UNZIP_PATH, tp);
-	FREE(cp);
-	FREE(tp);
+	} else if (!strncmp(line, "LYNXDIRED://ZIP", 15)) {
+	    tp = quote_pathname(line + 15);
+	    *cp++ = '\0';
+	    bp = quote_pathname(cp);
+	    cp = quote_pathname(line + 15);
+	    sprintf(buffer, "cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp);
+	    FREE(cp);
+	    FREE(bp);
+	    FREE(tp);
+#ifndef ARCHIVE_ONLY
+	} else if (!strncmp(line, "LYNXDIRED://UNZIP", 17)) {
+	    tp = quote_pathname(line + 17);
+	    *cp = '\0';
+	    cp = quote_pathname(line + 17);
+	    sprintf(buffer, "cd %s; %s -q %s", cp, UNZIP_PATH, tp);
+	    FREE(cp);
+	    FREE(tp);
 # endif /* !ARCHIVE_ONLY */
 #endif /* OK_ZIP */
 
-      } else if (!strncmp(line,"LYNXDIRED://COMPRESS",20)) {
-	tp = quote_pathname(line+20);
-	sprintf(buffer,"%s %s",COMPRESS_PATH, tp);
-	FREE(tp);
-      }
+	} else if (!strncmp(line, "LYNXDIRED://COMPRESS", 20)) {
+	    tp = quote_pathname(line + 20);
+	    sprintf(buffer, "%s %s", COMPRESS_PATH, tp);
+	    FREE(tp);
+	}
 
-      if (strlen(buffer)) {
-	 if (strlen(buffer) < 60) 
-	    sprintf(tmpbuf,"Executing %s ",buffer);
-	 else
-	    sprintf(tmpbuf,
-		    "Executing system command. This might take a while.");
-	 _statusline(tmpbuf);
-	 stop_curses();
-	 printf("%s\n", tmpbuf);
-	 fflush(stdout);
-	 system(buffer);
+	if (strlen(buffer)) {
+	    if (strlen(buffer) < 60) {
+		sprintf(tmpbuf, "Executing %s ", buffer);
+	    } else {
+		sprintf(tmpbuf,
+			"Executing system command. This might take a while.");
+	    }
+	    _statusline(tmpbuf);
+	    stop_curses();
+	    printf("%s\n", tmpbuf);
+	    fflush(stdout);
+	    system(buffer);
 #ifdef VMS
-	 extern BOOLEAN HadVMSInterrupt
-	 HadVMSInterrupt = FALSE;
+	    extern BOOLEAN HadVMSInterrupt
+	    HadVMSInterrupt = FALSE;
 #endif /* VMS */
-	 start_curses();
-	 ++LYforce_no_cache;
-      }
-   }
+	    start_curses();
+	    LYforce_no_cache = TRUE;
+	}
+    }
 
-   FREE(line);
-   LYpop(doc);
-   return 0;
+    FREE(line);
+    LYpop(doc);
+    return 0;
 }
 
-/* Provide a menu of file management options. */
-
+/*
+ *  Provide a menu of file management options.
+ */
 PUBLIC int dired_options ARGS2(
 	document *,	doc,
 	char **,	newfile)
@@ -1531,13 +1606,13 @@ PUBLIC int dired_options ARGS2(
     struct stat dir_info;
     FILE *fp0;
     char *cp = NULL;
-    char * dir_url = NULL;	/* will hold URL-escaped path of
+    char *dir_url = NULL;	/* Will hold URL-escaped path of
 				   directory from where DIRED_MENU was
-				   invoked (NOT its full URL) */
-    char * path_url = NULL;	/* will hold URL-escaped path of file
+				   invoked (NOT its full URL). */
+    char *path_url = NULL;	/* Will hold URL-escaped path of file
 				   (or directory) which was selected
 				   when DIRED_MENU was invoked (NOT
-				   its full URL) */
+				   its full URL). */
     BOOLEAN nothing_tagged;
     int count;
     struct dired_menu *mp;
@@ -1550,106 +1625,116 @@ PUBLIC int dired_options ARGS2(
     }
 
     if ((fp0 = fopen(tempfile,"w")) == NULL) {
-       _statusline("Unable to open file management menu file");
-       sleep(AlertSecs);
-       return(0);
+	_statusline("Unable to open file management menu file.");
+	sleep(AlertSecs);
+	return(0);
     }
+    chmod(tempfile, 0600);
     
     /* make the tempfile a URL */
     StrAllocCopy(*newfile, "file://localhost");
     StrAllocCat(*newfile, tempfile);
     
     cp = doc->address;
-    if(!strncmp(cp,"file://localhost",16))
-      cp += 16;
-    else if(!strncmp(cp,"file:",5))
-      cp += 5;
-    strcpy(dir,cp);
+    if (!strncmp(cp, "file://localhost", 16)) {
+	cp += 16;
+    } else if (!strncmp(cp, "file:", 5)) {
+	cp += 5;
+    }
+    strcpy(dir, cp);
     StrAllocCopy(dir_url, cp);
-    if (dir_url[strlen(dir_url)-1] == '/')
-      dir_url[strlen(dir_url)-1] = '\0';
+    if (dir_url[(strlen(dir_url) - 1)] == '/')
+	dir_url[(strlen(dir_url) - 1)] = '\0';
     HTUnEscape(dir);
-    if (dir[strlen(dir)-1] == '/')
-      dir[strlen(dir)-1] = '\0';
+    if (dir[(strlen(dir) - 1)] == '/')
+	dir[(strlen(dir) - 1)] = '\0';
 
     if (doc->link > -1 && doc->link < (nlinks+1)) {
-       cp = links[doc->link].lname;
-       if(!strncmp(cp,"file://localhost",16))
-	 cp += 16;
-       else if(!strncmp(cp,"file:",5))
-	 cp += 5;
-       strcpy(path,cp);
-       StrAllocCopy(path_url,cp);
-       if (*path_url && path_url[1] && path_url[strlen(path_url)-1] == '/')
-	   path_url[strlen(path_url)-1] = '\0';
-       HTUnEscape(path);
-       if (*path && path[1] && path[strlen(path)-1] == '/')
-	   path[strlen(path)-1] = '\0';
-
-       if (lstat(path,&dir_info) == -1 && stat(path,&dir_info) == -1) {
-	  sprintf(tmpbuf,"Unable to get status of %s ",path);
-	  _statusline(tmpbuf);
-	  sleep(AlertSecs);
-	  FREE(dir_url);
-	  FREE(path_url);
-	  return 0;
-       } 
+	cp = links[doc->link].lname;
+	if (!strncmp(cp, "file://localhost", 16)) {
+	    cp += 16;
+	} else if (!strncmp(cp, "file:", 5)) {
+	    cp += 5;
+	}
+	strcpy(path, cp);
+	StrAllocCopy(path_url, cp);
+	if (*path_url && path_url[1] && path_url[(strlen(path_url) - 1)] == '/')
+	    path_url[(strlen(path_url) - 1)] = '\0';
+	HTUnEscape(path);
+	if (*path && path[1] && path[(strlen(path) - 1)] == '/')
+	    path[(strlen(path) - 1)] = '\0';
+
+	if (lstat(path, &dir_info) == -1 && stat(path, &dir_info) == -1) {
+	    sprintf(tmpbuf, "Unable to get status of '%s'.", path);
+	    _statusline(tmpbuf);
+	    sleep(AlertSecs);
+	    FREE(dir_url);
+	    FREE(path_url);
+	    return 0;
+	} 
 
     } else {
-        path[0] = '\0';
+	path[0] = '\0';
 	StrAllocCopy(path_url, path);
     }
 
     nothing_tagged = (HTList_isEmpty(tagged));
 
-    fprintf(fp0,"<head>\n<title>%s</title></head>\n<body>\n",DIRED_MENU_TITLE);
+    fprintf(fp0,
+	    "<head>\n<title>%s</title></head>\n<body>\n", DIRED_MENU_TITLE);
 
-    fprintf(fp0,"\n<h1>File Management Options (%s Version %s)</h1>",
-    						LYNX_NAME, LYNX_VERSION);
+    fprintf(fp0,
+	    "\n<h1>File Management Options (%s Version %s)</h1>",
+    	    LYNX_NAME, LYNX_VERSION);
 
-    fprintf(fp0,"Current directory is %s <br>\n",dir);
+    fprintf(fp0, "Current directory is %s<br>\n", dir);
 
-    if (nothing_tagged)
-       if (strlen(path))
-          fprintf(fp0,"Current selection is %s <p>\n",path);
-       else
-          fprintf(fp0,"Nothing currently selected. <p>\n");
-    else {    /* write out number of tagged items, and names of first
-	      few of them relative to current (in the DIRED sense) directory */
+    if (nothing_tagged) {
+	if (strlen(path)) {
+	    fprintf(fp0, "Current selection is %s<p>\n", path);
+	} else {
+	    fprintf(fp0, "Nothing currently selected.<p>\n");
+	}
+    } else {
+	/*
+	 *  Write out number of tagged items, and names of first
+	 *  few of them relative to current (in the DIRED sense)
+	 *  directory.
+	 */
 	int n = HTList_count(tagged);
-	char * cp1 = NULL;
-	char * cd = NULL;
+	char *cp1 = NULL;
+	char *cd = NULL;
 	int i, m;
 #define NUM_TAGS_TO_WRITE 10
-	fprintf(fp0,"Current selection is %d tagged item%s",
-		n, (n==1 ? ":" : "s:"));
+	fprintf(fp0, "Current selection is %d tagged item%s",
+		     n, ((n == 1) ? ":" : "s:"));
 	StrAllocCopy(cd, doc->address);
 	HTUnEscapeSome(cd, "/");
-	if (*cd && cd[strlen(cd)-1] != '/')
+	if (*cd && cd[(strlen(cd) - 1)] != '/')
 	    StrAllocCat(cd, "/");
 	m = (n < NUM_TAGS_TO_WRITE) ? n : NUM_TAGS_TO_WRITE;
-	for (i=1; i <= m; i++) {
-		cp1 = HTRelative(HTList_objectAt(tagged, i-1),
+	for (i = 1; i <= m; i++) {
+	    cp1 = HTRelative(HTList_objectAt(tagged, i-1),
 		             (*cd ? cd : "file://localhost"));
-		HTUnEscape(cp1);
-		LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */
-		fprintf(fp0,"%s <br>\n &nbsp;&nbsp;&nbsp;%s",
-			(i==1 ? "" : " ,"), cp1);
-		FREE(cp1);
+	    HTUnEscape(cp1);
+	    LYEntify(&cp1, TRUE); /* _should_ do this everywhere... */
+	    fprintf(fp0, "%s <br>\n &nbsp;&nbsp;&nbsp;%s",
+			 (i == 1 ? "" : " ,"), cp1);
+	    FREE(cp1);
 	}
         if (n > m) {
 	    fprintf(fp0," , ...");
 	}
-	fprintf(fp0, " <p>\n");
+	fprintf(fp0, "<p>\n");
 	FREE(cd);
     }
 
     /*
-     * if menu_head is NULL then use defaults and link them together now
+     *  If menu_head is NULL then use defaults and link them together now.
      */
     if (menu_head == NULL) {
-	for (mp = defmenu; mp->href != NULL ; mp++)
-	    mp->next = mp + 1;
+	for (mp = defmenu; mp->href != NULL; mp++)
+	    mp->next = (mp + 1);
 	(--mp)->next = NULL;
 	menu_head = defmenu;
     }
@@ -1670,7 +1755,7 @@ PUBLIC int dired_options ARGS2(
 	    continue;
 	if (*mp->sfx &&
 	    (strlen(path) < strlen(mp->sfx) ||
-	     strcmp(mp->sfx, &path[strlen(path)-strlen(mp->sfx)]) != 0))
+	     strcmp(mp->sfx, &path[(strlen(path) - strlen(mp->sfx))]) != 0))
 	    continue;
 	fprintf(fp0, "<a href=\"%s",
 		render_item(mp->href, path_url, dir_url, buf,2048, YES));
@@ -1681,24 +1766,30 @@ PUBLIC int dired_options ARGS2(
     }
 
     if (uploaders != NULL) {
-       fprintf(fp0, "<p>Upload to current directory:<p>\n");
-       for (count=0, nxt = uploaders; nxt != NULL; nxt = nxt->next, count++) {
-	  fprintf(fp0,"<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n",
-	      count,dir,nxt->name);
-       }
+	fprintf(fp0, "<p>Upload to current directory:<p>\n");
+	for (count = 0, nxt = uploaders;
+	     nxt != NULL;
+	     nxt = nxt->next, count++) {
+	    fprintf(fp0,
+		"<a href=\"LYNXDIRED://UPLOAD=%d/TO=%s\"> %s </a><br>\n",
+		    count, dir, nxt->name);
+	}
     }
 
-    fprintf(fp0,"</body>\n");
+    fprintf(fp0, "</body>\n");
     fclose(fp0);
 
     FREE(dir_url);
     FREE(path_url);
 
-    LYforce_no_cache = 1;
+    LYforce_no_cache = TRUE;
 
     return(0);
 }
 
+/*
+ *  Execute DIRED command.
+ */
 PRIVATE int my_spawn ARGS3(
 	char *,		path,
 	char **,	argv,
@@ -1718,26 +1809,26 @@ PRIVATE int my_spawn ARGS3(
     stop_curses();
     pid = fork();	/* fork and execute rm */
     switch (pid) {
-      case -1:
-	sprintf(tmpbuf, "Unable to %s due to system error!", msg);
-	rc = 0;
-	break;		/* don't fall thru! - KW */
-      case 0:  /* child */
-	execv(path, argv);
-	exit(-1);	/* execv failed, give wait() something to look at */
-      default:  /* parent */
+ 	case -1:
+	    sprintf(tmpbuf, "Unable to %s due to system error!", msg);
+	    rc = 0;
+	    break;	/* don't fall thru! - KW */
+	case 0:  /* child */
+	    execv(path, argv);
+	    exit(-1);	/* execv failed, give wait() something to look at */
+	default:  /* parent */
 #if defined(NeXT) || defined(AIX4) || defined(sony_news)
-	while (wait(&wstatus) != pid)
-	    ; /* do nothing */
+	    while (wait(&wstatus) != pid)
+		; /* do nothing */
 #else
-	waitpid(pid, &wstatus, 0); /* wait for child */
+	    waitpid(pid, &wstatus, 0); /* wait for child */
 #endif /* NeXT || AIX4 || sony_news */
-	if (WEXITSTATUS(wstatus) != 0 ||
-	    WTERMSIG(wstatus) > 0)  { /* error return */
-	    sprintf(tmpbuf, "Probable failure to %s due to system error!",
-		    msg);
-	    rc = 0;
-	}
+	    if (WEXITSTATUS(wstatus) != 0 ||
+		WTERMSIG(wstatus) > 0)  { /* error return */
+		sprintf(tmpbuf, "Probable failure to %s due to system error!",
+				msg);
+		rc = 0;
+	    }
     }
 #ifdef VMS
     {
@@ -1762,133 +1853,141 @@ PRIVATE int my_spawn ARGS3(
     return(rc);
 }
 
+/*
+ *  Check DIRED filename.
+ */
 PRIVATE char *filename ARGS3(
 	char *,		prompt,
 	char *,		buf,
 	int,		bufsize)
 {
-   char *cp;
+    char *cp;
 
-   _statusline(prompt);
+    _statusline(prompt);
 
-   *buf = '\0';
-   LYgetstr(buf, VISIBLE, bufsize, NORECALL);
-   if(strstr(buf,"../") != NULL) {
-       _statusline("Illegal filename; request ignored.");
-       sleep(AlertSecs);
-       return NULL;
-   }
+    *buf = '\0';
+    LYgetstr(buf, VISIBLE, bufsize, NORECALL);
+    if (strstr(buf, "../") != NULL) {
+	_statusline("Illegal filename; request ignored.");
+	sleep(AlertSecs);
+ 	return NULL;
+    }
 
-   if (no_dotfiles || !show_dotfiles) {
-       cp = strrchr(buf, '/');	/* find last slash */
-       if (cp) 
-	   cp += 1;
-       else
-	   cp = buf;
-       if (*cp == '.') {
-	   _statusline("Illegal filename; request ignored.");
-	   sleep(AlertSecs);
-	   return NULL;
-       }
-   }
-   return buf;
+    if (no_dotfiles || !show_dotfiles) {
+	cp = strrchr(buf, '/');	/* find last slash */
+	if (cp) 
+	    cp += 1;
+	else
+	    cp = buf;
+	if (*cp == '.') {
+	    _statusline("Illegal filename; request ignored.");
+	    sleep(AlertSecs);
+	    return NULL;
+	}
+    }
+    return buf;
 }
 
-/* Install the specified file or directory. */
-
+/*
+ *  Install the specified file or directory.
+ */
 PUBLIC BOOLEAN local_install ARGS3(
 	char *,		destpath,
 	char *,		srcpath,
 	char **,	newpath)
 {
-   char tmpbuf[512];
-   static char savepath[512]; /* this will be the link that is to be installed */
-   struct stat dir_info;
-   char *args[6];
-   HTList *tag;
-   int count = 0;
-   int n = 0, src;	/* indices into 'args[]' */
-
-/* Determine the status of the selected item. */
-
-   if (srcpath) {
-      srcpath = strip_trailing_slash(srcpath);
-
-      if(strncmp(srcpath,"file://localhost",16) == 0)
-	 srcpath += 16;
-      if (stat(srcpath,&dir_info) == -1) {
-         sprintf(tmpbuf,"Unable to get status of %s ",srcpath);
-         _statusline(tmpbuf);
-         sleep(AlertSecs);
-         return 0;
-      } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR && 
-                 (dir_info.st_mode & S_IFMT) != S_IFREG) {
-         _statusline(
-	  "The selected item is not a file or a directory! Request ignored. ");
-         sleep(AlertSecs);
-         return 0;
-      }
-      strcpy(savepath, srcpath);
-      ++LYforce_no_cache;
-      strcpy(tmpbuf, "file://localhost");
-      strcat(tmpbuf, Home_Dir());
-      strcat(tmpbuf, "/.installdirs.html");
-      StrAllocCopy(*newpath, tmpbuf);
-      return 0;
-   }
+    char tmpbuf[512];
+    static char savepath[512]; /* This will be the link that
+				  is to be installed. */
+    struct stat dir_info;
+    char *args[6];
+    HTList *tag;
+    int count = 0;
+    int n = 0, src;	/* indices into 'args[]' */
 
-      destpath = strip_trailing_slash(destpath);
-
-      if (stat(destpath,&dir_info) == -1) {
-         sprintf(tmpbuf,"Unable to get status of %s ",destpath);
-         _statusline(tmpbuf);
-         sleep(AlertSecs);
-         return 0;
-      } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR) {
-         _statusline(
-	 	"The selected item is not a directory! Request ignored. ");
-         sleep(AlertSecs);
-         return 0;
-      } else if (0 /*directory not writeable*/) {
-         _statusline("Install in the selected directory not permitted.");
-         sleep(AlertSecs);
-         return 0;
-      }
+    /*
+     *  Determine the status of the selected item.
+     */
+    if (srcpath) {
+	srcpath = strip_trailing_slash(srcpath);
+	if (strncmp(srcpath, "file://localhost", 16) == 0)
+	    srcpath += 16;
+	if (stat(srcpath, &dir_info) == -1) {
+	    sprintf(tmpbuf, "Unable to get status of '%s'.", srcpath);
+	    _statusline(tmpbuf);
+	    sleep(AlertSecs);
+	    return 0;
+	} else if ((dir_info.st_mode & S_IFMT) != S_IFDIR &&
+		   (dir_info.st_mode & S_IFMT) != S_IFREG) {
+	    _statusline(
+	  "The selected item is not a file or a directory! Request ignored.");
+	    sleep(AlertSecs);
+	    return 0;
+	}
+	strcpy(savepath, srcpath);
+	LYforce_no_cache = TRUE;
+	strcpy(tmpbuf, "file://localhost");
+	strcat(tmpbuf, Home_Dir());
+	strcat(tmpbuf, "/.installdirs.html");
+	StrAllocCopy(*newpath, tmpbuf);
+	return 0;
+    }
+
+    destpath = strip_trailing_slash(destpath);
+
+    if (stat(destpath,&dir_info) == -1) {
+	sprintf(tmpbuf,"Unable to get status of '%s'.",destpath);
+	_statusline(tmpbuf);
+	sleep(AlertSecs);
+	return 0;
+    } else if ((dir_info.st_mode & S_IFMT) != S_IFDIR) {
+	_statusline(
+	 	"The selected item is not a directory! Request ignored.");
+	sleep(AlertSecs);
+	return 0;
+    } else if (0 /*directory not writeable*/) {
+	_statusline("Install in the selected directory not permitted.");
+	sleep(AlertSecs);
+	return 0;
+    }
 
-   statusline("Just a moment, ...");
-   args[n++] = "install";
+    statusline("Just a moment, ...");
+    args[n++] = "install";
 #ifdef INSTALL_ARGS
-   args[n++] = INSTALL_ARGS;
-#endif
-   src = n++;
-   args[n++] = destpath;
-   args[n] = (char *) 0;
-   sprintf(tmpbuf, "install %s", destpath);
-   tag = tagged;
-
-   if (HTList_isEmpty(tagged)) {
-         args[src] = savepath;
-	 if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
-	     return (-1);
-	 count++;
-   } else {
-       char * name;
-       while ((name = (char *)HTList_nextObject(tag))) {
-	   args[src] = name;
-	   if (strncmp("file://localhost", args[src], 16) == 0)
-	       args[src] = name + 16;
-
-	   if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
-	       return ((count == 0) ? -1 : count);
-	   count++;
-       }	
-       clear_tags();
-   }
-   statusline("Installation complete");
-   sleep(InfoSecs);
-   return count;
+    args[n++] = INSTALL_ARGS;
+#endif /* INSTALL_ARGS */
+    src = n++;
+    args[n++] = destpath;
+    args[n] = (char *)0;
+    sprintf(tmpbuf, "install %s", destpath);
+    tag = tagged;
+
+    if (HTList_isEmpty(tagged)) {
+	args[src] = savepath;
+	if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
+	    return (-1);
+	count++;
+    } else {
+	char *name;
+	while ((name = (char *)HTList_nextObject(tag))) {
+	    args[src] = name;
+	    if (strncmp("file://localhost", args[src], 16) == 0)
+		 args[src] = (name + 16);
+
+	    if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0)
+		return ((count == 0) ? -1 : count);
+	    count++;
+	}	
+	clear_tags();
+    }
+    statusline("Installation complete");
+    sleep(InfoSecs);
+    return count;
 }
 
+/*
+ *  Clear DIRED tags.
+ */
 PUBLIC void clear_tags NOARGS
 {
     char *cp = NULL;
@@ -1900,6 +1999,9 @@ PUBLIC void clear_tags NOARGS
 	FREE(tagged);
 }
 
+/*
+ *  Handle DIRED menu item.
+ */
 PUBLIC void add_menu_item ARGS1(
 	char *,		str)
 {
@@ -1907,27 +2009,32 @@ PUBLIC void add_menu_item ARGS1(
     char *cp;
 
     /*
-     * First custom menu definition causes entire default menu to be
-     * discarded.
+     *  First custom menu definition causes entire default menu to be
+     *  discarded.
      */
     if (menu_head == defmenu)
 	menu_head = NULL;
 
     new = (struct dired_menu *)calloc(1, sizeof(*new));
 
-    /* conditional on tagged != NULL ? */
+    /*
+     *  Conditional on tagged != NULL ?
+     */
     cp = strchr(str, ':');
     *cp++ = '\0';
-    if (strcasecomp(str, "tag") == 0)
+    if (strcasecomp(str, "tag") == 0) {
 	new->cond = DE_TAG;
-    else if (strcasecomp(str, "dir") == 0)
+    } else if (strcasecomp(str, "dir") == 0) {
 	new->cond = DE_DIR;
-    else if (strcasecomp(str, "file") == 0)
+    } else if (strcasecomp(str, "file") == 0) {
 	new->cond = DE_FILE;
-    else if (strcasecomp(str, "link") == 0)
+    } else if (strcasecomp(str, "link") == 0) {
 	new->cond = DE_SYMLINK;
+    }
 
-    /* conditional on matching suffix */
+    /*
+     *  Conditional on matching suffix.
+     */
     str = cp;
     cp = strchr(str, ':');
     *cp++ = '\0';
@@ -1953,6 +2060,9 @@ PUBLIC void add_menu_item ARGS1(
 	menu_head = new;
 }
 
+/*
+ *  Create URL for DIRED HREF value.
+ */
 PRIVATE char * render_item ARGS6(
 	char *,		s,
 	char *,		path,
@@ -1961,19 +2071,18 @@ PRIVATE char * render_item ARGS6(
 	int,		bufsize,
 	BOOLEAN,	url_syntax)
 {
-	char *cp;
-	char *bp;
-	char overrun = '\0';
-	char *taglist = NULL;
+    char *cp;
+    char *bp;
+    char overrun = '\0';
+    char *taglist = NULL;
 #define BP_INC (bp>buf+bufsize-2 ?  &overrun : bp++)
 				/* Buffer overrun could happen for very long
-				 tag list, if %l or %t are used */
-
-	bp = buf;
-	while (*s && !overrun) {
-	    if (*s == '%') {
-		s++;
-		switch (*s) {
+				   tag list, if %l or %t are used */
+    bp = buf;
+    while (*s && !overrun) {
+	if (*s == '%') {
+	    s++;
+	    switch (*s) {
 		case '%':
 		    *BP_INC = '%';
 #ifdef NOTDEFINED
@@ -2013,8 +2122,8 @@ PRIVATE char * render_item ARGS6(
 			HTList *cur = tagged; 
 			char *name;
 
-			while(!overrun &&
-			      (name = (char *)HTList_nextObject(cur))!=NULL) {
+			while (!overrun &&
+			       (name = (char *)HTList_nextObject(cur))!=NULL) {
 			    if (*s == 'l' && (cp = strrchr(name, '/')))
 				cp++;
 			    else
@@ -2041,24 +2150,24 @@ PRIVATE char * render_item ARGS6(
 #endif /* NOTDEFINED */
 		    *BP_INC =*s;
 		    break;
-		}
-	    } else {
-	        /*
-		 *  Other chars come from the lynx.cfg or
-		 *  the default. Let's assume there isn't
-		 *  anything weird there that needs escaping.
-		 */
-		*BP_INC =*s;
 	    }
-	    s++;
-	}
-	if (overrun & url_syntax) {
-	    sprintf(buf,"Temporary URL or list would be too long.");
-	    _statusline(buf);
-	    sleep(AlertSecs);
-	    bp = buf;	/* set to start, will return empty string as URL */
+	} else {
+	    /*
+	     *  Other chars come from the lynx.cfg or
+	     *  the default. Let's assume there isn't
+	     *  anything weird there that needs escaping.
+	     */
+	    *BP_INC =*s;
 	}
-	*bp = '\0';
-	return buf;
+	s++;
+    }
+    if (overrun & url_syntax) {
+	sprintf(buf,"Temporary URL or list would be too long.");
+	_statusline(buf);
+	sleep(AlertSecs);
+	bp = buf;	/* set to start, will return empty string as URL */
+    }
+    *bp = '\0';
+    return buf;
 }
 #endif /* DIRED_SUPPORT */
diff --git a/src/LYMail.c b/src/LYMail.c
index 271d2af3..d85a12ae 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -1,5 +1,7 @@
 #include "HTUtils.h"
 #include "tcp.h"
+#include "HTParse.h"
+#include "LYGlobalDefs.h"
 #include "HTAlert.h"
 #include "LYCurses.h"
 #include "LYSignal.h"
@@ -8,8 +10,6 @@
 #include "LYStrings.h"
 #include "GridText.h"
 #include "LYSystem.h"
-#include "LYGlobalDefs.h"
-#include "HTParse.h"
 #include "LYMail.h"
 #ifdef EXP_CHARTRANS
 #include "LYCharSets.h"  /* to get current charset for mail header */
@@ -188,6 +188,7 @@ PUBLIC void mailform ARGS4(
 	FREE(address);
 	return;
     }
+    chmod(tmpfile, 0600);
     if (*self) {
         cp = self;
 	while (*cp == ' ' || *cp == ',')
@@ -328,6 +329,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
     FILE *fd, *fp;
     char *address = NULL;
     char cmd[512], *cp, *cp0, *cp1;
+    int i;
 #if defined(VMS) || defined(DOSPATH)
     char my_tempfile[256];
     char *address_ptr1, *address_ptr2;
@@ -382,6 +384,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 	FREE(address);
 	return;
     }
+    chmod(tmpfile, 0600);
 #endif /* VMS */
 
     fprintf(fd, "The link   %s :?: %s \n",
@@ -454,6 +457,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address,
 #endif /* SIGTSTP */
 		exit(-1);
             }
+	    chmod(TRAVERSE_ERRORS, 0600);
 	}
 
 	fprintf(ofp, "%s	%s 	in %s\n",
@@ -520,6 +524,7 @@ PUBLIC void reply_by_mail ARGS3(
 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
 	return;
     }
+    chmod(my_tempfile, 0600);
     subject[0] = '\0';
 
     /*
@@ -727,17 +732,22 @@ PUBLIC void reply_by_mail ARGS3(
      *  as display character set...
      *  Don't send a charset if we have a CJK character set
      *  selected, since it may not be appropriate for mail...
-     *  Also don't use an inofficial "x-" charset. - kw
+     *  Also don't use an inofficial "x-" charset.
+     *  Also if the charset would be "us-ascii" (7-bit replacements
+     *  selected, don't send any MIME headers. - kw
      */
-    StrAllocCat(header, "Mime-Version: 1.0\n");
-    if (!LYHaveCJKCharacterSet &&
-	strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2)
-	!= 0) {
-	sprintf(buf,"Content-Type: text/plain; charset=%s\n",
-		LYCharSet_UC[current_char_set].MIMEname);
-	StrAllocCat(header, buf);
+    if (strncasecomp(LYCharSet_UC[current_char_set].MIMEname,
+		     "us-ascii", 8) != 0) {
+	StrAllocCat(header, "Mime-Version: 1.0\n");
+	if (!LYHaveCJKCharacterSet &&
+	    strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2)
+	    != 0) {
+	    sprintf(buf,"Content-Type: text/plain; charset=%s\n",
+		    LYCharSet_UC[current_char_set].MIMEname);
+	    StrAllocCat(header, buf);
+	}
+	StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n");
     }
-    StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n");
 #endif
     /*
      *  Put the X-URL and X-Mailer lines in the header.
@@ -966,7 +976,9 @@ PUBLIC void reply_by_mail ARGS3(
 	           !term_letter && c != 7   && c != 3)
                 c = LYgetch();
             if (TOUPPER(c) == 'Y') {
-                /* the 1 will add the reply ">" in front of every line */
+                /*
+		 *  The 1 will add the reply "> " in front of every line.
+		 */
                 print_wwwfile_to_fd(fd, 1);
 	    }
         }
diff --git a/src/LYMain.c b/src/LYMain.c
index 85d7d55e..b6d4297f 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -4,6 +4,8 @@
 #include "HTAccess.h"
 #include "HTList.h"
 #include "HTFile.h"
+#include "UCMap.h"
+#include "UCDefs.h"
 #ifdef VMS
 #include "HTVMSUtils.h"
 #endif /* VMS */
@@ -152,6 +154,7 @@ PUBLIC lynx_html_item_type *externals = NULL;
 PUBLIC lynx_html_item_type *uploaders = NULL;
 PUBLIC int port_syntax = 1;
 PUBLIC BOOLEAN LYShowCursor = SHOW_CURSOR; /* to show or not to show */
+PUBLIC BOOLEAN LYUseDefShoCur = TRUE;	/* Command line -show_cursor toggle */
 PUBLIC BOOLEAN LYforce_no_cache = FALSE;
 PUBLIC BOOLEAN LYoverride_no_cache = FALSE;
 PUBLIC BOOLEAN LYresubmit_posts = ALWAYS_RESUBMIT_POSTS;
@@ -289,8 +292,10 @@ PUBLIC BOOLEAN no_url_redirection = FALSE; /* Don't follow URL redirections */
 PUBLIC char *form_post_data = NULL;  /* User data for post form */
 PUBLIC char *form_get_data = NULL;   /* User data for get form */
 PUBLIC char *http_error_file = NULL; /* Place HTTP status code in this file */
-	     /* Id:Password for protected forms */
+	     /* Id:Password for protected documents */
 PUBLIC char *authentication_info[2] = {NULL, NULL};
+	     /* Id:Password for protected proxy servers */
+PUBLIC char *proxyauth_info[2] = {NULL, NULL};
 
 PUBLIC char *MBM_A_subbookmark[MBM_V_MAXFILES+1];
 PUBLIC char *MBM_A_subdescript[MBM_V_MAXFILES+1];
@@ -345,7 +350,11 @@ PUBLIC FILE *LYTraceLogFP = NULL;		/* Pointer for TRACE log  */
 PUBLIC char *LYTraceLogPath = NULL;		/* Path for TRACE log	   */
 PUBLIC BOOLEAN LYUseTraceLog = USE_TRACE_LOG;	/* Use a TRACE log?	   */
 PUBLIC FILE LYOrigStderr;			/* Original stderr pointer */
+PUBLIC BOOLEAN LYSeekFragMAPinCur = TRUE;
+PUBLIC BOOLEAN LYSeekFragAREAinCur = TRUE;
+
 PUBLIC BOOLEAN LYStripDotDotURLs = FALSE;	/* Try to fix ../ in some URLs? */
+PUBLIC BOOLEAN LYForceSSLCookiesSecure = FALSE;
 
 /* These are declared in cutil.h for current freeWAIS libraries. - FM */
 #ifdef DECLARE_WAIS_LOGFILES
@@ -363,6 +372,7 @@ PRIVATE char *terminal = NULL;
 PRIVATE char *pgm;
 PRIVATE BOOLEAN number_links = FALSE;
 PRIVATE BOOLEAN LYPrependBase = FALSE;
+PRIVATE HTList *LYStdinArgs = NULL;
 
 PRIVATE void parse_arg PARAMS((char **arg, int *i, int argc));
 #ifndef VMS
@@ -437,6 +447,8 @@ PRIVATE void free_lynx_globals NOARGS
     FREE(editor);
     FREE(authentication_info[0]);
     FREE(authentication_info[1]);
+    FREE(proxyauth_info[0]);
+    FREE(proxyauth_info[1]);
     FREE(lynxjumpfile);
     FREE(startrealm);
     FREE(personal_mail_address);
@@ -456,31 +468,24 @@ PRIVATE void free_lynx_globals NOARGS
     char *lynx_lss_file=NULL;
 #endif
 
-PRIVATE char *make_homedir_lynxrc_filename ARGS1(char *, name)
+
+/*
+ *  This function frees the LYStdinArgs list. - FM
+ */
+PRIVATE void LYStdinArgs_free NOARGS
 {
-   char *home = NULL;
+    char *argument;
+    HTList *cur = LYStdinArgs;
 
-   if (name == NULL)
-     {
-#if defined(UNIX) && !defined(DJGPP)
-	name = "/.lynxrc";
-#else
-	name = "/lynx.rc";
-#endif
-     }
+    if (cur == NULL)
+        return;
 
-#ifdef DOSPATH
-   StrAllocCopy(home, HTDOS_wwwName((char *)Home_Dir()));
-#else
-#ifdef VMS
-   StrAllocCopy(home, HTVMS_wwwName((char *)Home_Dir()));
-#else
-   StrAllocCopy(home, Home_Dir());
-#endif /* VMS */
-#endif /* DOSPATH */
-   
-   StrAllocCat(home, name);
-   return home;
+    while (NULL != (argument = (char *)HTList_nextObject(cur))) {
+	FREE(argument);
+    }
+    HTList_delete(LYStdinArgs);
+    LYStdinArgs = NULL;
+    return;
 }
 
 /*
@@ -498,29 +503,30 @@ PUBLIC int main ARGS2(
     char *cp;
     FILE *fp;
     char filename[256];
+    BOOL LYGetStdinArgs = FALSE;
 
 #ifdef _WINDOWS 
-WSADATA WSAData;
- {
-                int err;
-                WORD wVerReq;
-
-                _fmode = O_BINARY;
-
-                wVerReq = MAKEWORD(1,1);
-
-                err = WSAStartup(wVerReq, &WSAData);
-                if (err != 0)
-                {
-                        printf("No Winsock found, sorry.");
-                        sleep(5);
-                        return;
-                }
- }
+    WSADATA WSAData;
+    {
+	int err;
+	WORD wVerReq;
+
+	_fmode = O_BINARY;
+
+	wVerReq = MAKEWORD(1,1);
+
+	err = WSAStartup(wVerReq, &WSAData);
+	if (err != 0)
+	{
+	    printf("No Winsock found, sorry.");
+	    sleep(5);
+	    return;
+	}
+    }
 #endif /* _WINDOWS */
 
 #ifdef DJGPP
-        sock_init();
+    sock_init();
 #endif
 
 #ifdef DOSPATH
@@ -535,6 +541,15 @@ WSADATA WSAData;
 	pgm = cp + 1;
     }
 
+    /*
+     *  Act on -help NOW, so we only output the help and exit. - FM
+     */
+    for (i = 1; i < argc; i++) {
+	if (strncmp(argv[i], "-help", 5) == 0) {
+	    parse_arg(&argv[i], &i, argc);
+	}
+    }
+
 #ifdef LY_FIND_LEAKS
     /*
      *	Register the final function to be executed when being exited.
@@ -608,6 +623,21 @@ WSADATA WSAData;
     StrAllocCopy(pref_charset, PREFERRED_CHARSET);
     StrAllocCopy(system_mail, SYSTEM_MAIL);
     StrAllocCopy(system_mail_flags, SYSTEM_MAIL_FLAGS);
+    StrAllocCopy(LYUserAgent, LYNX_NAME);
+    StrAllocCat(LYUserAgent, "/");
+    StrAllocCat(LYUserAgent, LYNX_VERSION);
+    if (HTLibraryVersion) {
+        StrAllocCat(LYUserAgent, " libwww-FM/");
+	StrAllocCat(LYUserAgent, HTLibraryVersion);
+    }
+    StrAllocCopy(LYUserAgentDefault, LYUserAgent);
+#ifdef VMS
+    Define_VMSLogical("LYNX_VERSION", LYNX_VERSION);
+#else
+    StrAllocCopy(lynx_version_putenv_command, "LYNX_VERSION=");
+    StrAllocCat(lynx_version_putenv_command, LYNX_VERSION);
+    putenv(lynx_version_putenv_command);
+#endif /* VMS */
 #ifdef DOSPATH
        if ((cp = getenv("TEMP")) != NULL)
                 StrAllocCopy(lynx_temp_space, cp);
@@ -637,21 +667,20 @@ WSADATA WSAData;
 	StrAllocCopy(lynx_temp_space, temp);
 	FREE(temp);
     }
-    StrAllocCopy(LYUserAgent, LYNX_NAME);
-    StrAllocCat(LYUserAgent, "/");
-    StrAllocCat(LYUserAgent, LYNX_VERSION);
-    if (HTLibraryVersion) {
-        StrAllocCat(LYUserAgent, " libwww-FM/");
-	StrAllocCat(LYUserAgent, HTLibraryVersion);
+    if ((cp = strstr(lynx_temp_space, "$USER")) != NULL) {
+	char *cp1;
+
+	if ((cp1 = (char *)getenv("USER")) != NULL) {
+	    *cp = '\0';
+	    StrAllocCopy(temp, lynx_temp_space);
+	    *cp = '$';
+	    StrAllocCat(temp, cp1);
+	    cp += 5;
+	    StrAllocCat(temp, cp);
+	    StrAllocCopy(lynx_temp_space, temp);
+	    FREE(temp);
+	}
     }
-    StrAllocCopy(LYUserAgentDefault, LYUserAgent);
-#ifdef VMS
-    Define_VMSLogical("LYNX_VERSION", LYNX_VERSION);
-#else
-    StrAllocCopy(lynx_version_putenv_command, "LYNX_VERSION=");
-    StrAllocCat(lynx_version_putenv_command, LYNX_VERSION);
-    putenv(lynx_version_putenv_command);
-#endif /* VMS */
 #ifdef VMS
     for (i = 0; lynx_temp_space[i]; i++)
         lynx_temp_space[i] = TOLOWER(lynx_temp_space[i]);
@@ -751,10 +780,163 @@ WSADATA WSAData;
                 StrAllocCopy(lynx_cfg_file, argv[i+1]);
                 i++;
             }
-	} else if (strncmp(argv[i], "-help", 5) == 0) {
-	    parse_arg(&argv[i], &i, argc);
 	}
     }
+
+    /*
+     *  If we have a lone "-" switch for getting arguments from stdin,
+     *  get them NOW, and act on the relevant ones, saving the others
+     *  into an HTList for handling after the other initializations.
+     *  The primary purpose of this feature is to allow for the
+     *  potentially very long command line that can be associated with
+     *  post or get data.  The original implementation required that
+     *  the lone "-" be the only command line argument, but that
+     *  precluded its use when the lynx command is aliased with other
+     *  arguments.  When interactive, the stdin input is terminated by
+     *  by Control-D on Unix or Control-Z on VMS, and each argument
+     *  is terminated by a RETURN.  When the argument is -get_data or
+     *  -post_data, the data are terminate by a "___" string, alone
+     *  on the line (also terminated by RETURN). - FM
+     */
+    for (i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-") == 0) {
+	    LYGetStdinArgs = TRUE;
+	}
+    }
+    if (LYGetStdinArgs == TRUE) {
+	char buf[1025];
+ 
+	while (fgets(buf, sizeof(buf) - 1, stdin)) {
+	    int j;
+     
+	    for (j = strlen(buf) - 1; j > 0 && 
+		(buf[j] == CR || buf[j] == LF); j--) {
+		buf[j] = '\0';
+	    }
+
+	    if (strncmp(buf, "-trace", 6) == 0) {
+		WWW_TraceFlag = TRUE;
+	    } else if (strncmp(buf, "-tlog", 5) == 0) {
+		if (LYUseTraceLog) {
+		    LYUseTraceLog = FALSE;
+		} else {
+		    LYUseTraceLog = TRUE;
+		}
+	    } else if (strncmp(buf, "-anonymous", 10) == 0) {
+		if (!LYValidate && !anon_restrictions_set)
+		    parse_restrictions("default");
+		anon_restrictions_set = TRUE;
+	    } else if (strcmp(buf, "-validate") == 0) {
+		/*
+		 *  Follow only http URLs.
+		 */
+		LYValidate = TRUE;
+#ifdef SOCKS
+	    } else if (strncmp(buf, "-nosocks", 8) == 0) {
+		socks_flag = FALSE;
+#endif /* SOCKS */
+	    } else if (strncmp(buf, "-cfg", 4) == 0) {
+		if ((cp = strchr(buf,'=')) != NULL) {
+		    StrAllocCopy(lynx_cfg_file, cp+1);
+		} else {
+		    cp = buf;
+		    while (*cp && !isspace((unsigned char)*cp))
+			cp++;
+		    while (*cp && isspace((unsigned char)*cp))
+			cp++;
+		    if (*cp)
+			StrAllocCopy(lynx_cfg_file, cp);
+	        }
+	    } else if (strcmp(buf, "-get_data") == 0) {
+		/*
+		 *  User data for GET form.
+		 */
+		char **get_data;
+
+		/*
+		 *  On Unix, conflicts with curses when interactive
+		 *  so let's force a dump.  - CL
+		 *
+		 *  On VMS, mods have been made in LYCurses.c to deal
+		 *  with potential conflicts, so don't force the dump
+		 *  here. - FM
+		 */
+#ifndef VMS
+		dump_output_immediately = TRUE;
+		LYcols = 80;
+#endif /* VMS */
+
+		StrAllocCopy(form_get_data, "?");   /* Prime the pump */
+		get_data = &form_get_data;
+
+		/*
+		 *  Build GET data for later.  Stop reading when we see
+		 *  a line with "---" as its first three characters.
+		 */
+		while (fgets(buf, sizeof(buf), stdin) &&
+		       strncmp(buf, "---", 3) != 0) {
+		    int j;
+
+		    /*
+		     *  Strip line terminators.
+		     */
+		    for (j = strlen(buf) - 1; j >= 0 &&
+			 (buf[j] == CR || buf[j] == LF); j--) {
+			buf[j] = '\0';
+		    }
+		    StrAllocCat(*get_data, buf);
+		}
+	    } else if (strcmp(buf, "-post_data") == 0) {
+		/*
+		 *  User data for POST form.
+		 */
+		char **post_data;
+
+		/*
+		 *  On Unix, conflicts with curses when interactive
+		 *  so let's force a dump.  - CL
+		 *
+		 *  On VMS, mods have been made in LYCurses.c to deal
+		 *  with potential conflicts, so don't force a dump
+		 *  here. - FM
+		 */
+#ifndef VMS
+		dump_output_immediately = TRUE;
+		LYcols = 80;
+#endif /* VMS */
+
+		post_data = &form_post_data;
+
+		/*
+		 *  Build post data for later.  Stop reading when we see
+		 *  a line with "---" as its first three characters.
+		 */
+		while (fgets(buf, sizeof(buf), stdin) &&
+		       strncmp(buf, "---", 3) != 0) {
+		    int j;
+
+		     /*
+		      *  Strip line terminators.
+		      */
+		    for (j = strlen(buf) - 1; j >= 0 &&
+			 (buf[j] == CR || buf[j] == LF); j--) {
+			buf[j] = '\0';
+		    }
+		    StrAllocCat(*post_data, buf);
+		}
+	    } else if (buf[0] != '\0') {
+	        char *argument = NULL;
+
+		if (LYStdinArgs == NULL) {
+		    LYStdinArgs = HTList_new();
+		    atexit(LYStdinArgs_free);
+		}
+		StrAllocCopy(argument, buf);
+		HTList_appendObject(LYStdinArgs, argument);
+	    }
+	}
+    }
+
 #ifdef SOCKS
     if (socks_flag)
         SOCKSinit(argv[0]);
@@ -825,6 +1007,7 @@ WSADATA WSAData;
 	    exit(-1);
 	}
 #endif /* VMS */
+	chmod(LYTraceLogPath, 0600);
 	*stderr = *LYTraceLogFP;
 	fprintf(stderr, "\t\t%s\n\n", LYNX_TRACELOG_TITLE);
     }
@@ -868,21 +1051,6 @@ WSADATA WSAData;
 	    StrAllocCopy(lynx_cfg_file, cp);
     }
 
-   /* If we still have no config file, check one in home directory */
-   if (NULL == lynx_cfg_file)
-     {
-	temp = make_homedir_lynxrc_filename (NULL);
-	if (temp != NULL)
-	  {
-	     if (NULL != (fp = fopen (temp, "r")))
-	       {
-		  fclose (fp);
-		  StrAllocCopy (lynx_cfg_file, temp);
-	       }
-	     FREE(temp);
-	  }
-     }
-
     /*
      *  If we still don't have a configuration file,
      *  use the userdefs.h definition.
@@ -897,10 +1065,14 @@ WSADATA WSAData;
    /* I think this should only be performed if lynx_cfg_file starts with ~/ */
    if ((lynx_cfg_file[0] == '~') && (lynx_cfg_file[1] == '/'))
      {
-	temp = make_homedir_lynxrc_filename (lynx_cfg_file + 2);
-	FREE(lynx_cfg_file);
-	lynx_cfg_file = temp;
-	temp = NULL;
+#ifdef VMS
+	StrAllocCopy(temp, HTVMS_wwwName((char *)Home_Dir()));
+#else
+	StrAllocCopy(temp, Home_Dir());
+#endif /* VMS */
+	StrAllocCat(temp, lynx_cfg_file + 1);
+	StrAllocCopy(lynx_cfg_file, temp);
+	FREE(temp);
      }
 #endif
 
@@ -1119,37 +1291,25 @@ WSADATA WSAData;
     LYEnsureAbsoluteURL((char **)&LynxHome, "LynxHome");
 
     /*
-     *  Process arguments - with none, look for the database in STARTDIR,
-     *  starting with STARTFILE.
-     *
-     *  If a pathname is given, use it as the starting point.  Split it
-     *  into directory and file components, 'cd' to the directory, and
-     *  view the file.
-     *
-     *  If the only argument is '-' then we expect to see the arguments on
-     *  stdin, this is to allow for the potentially very long command line
-     *  that can be associated with post or get data.
+     *  Process any command line arguments not already handled. - FM
      */
-    if (argc == 2 && strcmp(argv[1], "-") == 0) {
-	char buf[1025];
-	char *my_args[2];
- 
-	my_args[0] = buf;
-	my_args[1] = NULL;
- 
-	while (fgets(buf, sizeof(buf) - 1, stdin)) {
-	    int j;
-     
-	    for (j = strlen(buf) - 1; j > 0 && 
-		(buf[j] == CR || buf[j] == LF); j--) {
-		buf[j] = '\0';
-	    }
-	    parse_arg(my_args, NULL, -1);
-	}
-    } else {
-	for (i = 1; i < argc; i++) {
-	    parse_arg(&argv[i], &i, argc);
+    for (i = 1; i < argc; i++) {
+	parse_arg(&argv[i], &i, argc);
+    }
+
+    /*
+     *  Process any stdin-derived arguments for a lone "-"  which we've
+     *  loaded into LYStdinArgs. - FM
+     */
+    if (LYStdinArgs != NULL) {
+	char *argv[2];
+	HTList *cur = LYStdinArgs;
+
+	argv[1] = NULL;
+	while (NULL != (argv[0] = (char *)HTList_nextObject(cur))) {
+	    parse_arg(argv, NULL, -1);
 	}
+	LYStdinArgs_free();
     }
 
 #ifndef VMS
@@ -1182,7 +1342,7 @@ WSADATA WSAData;
     if (vi_keys)
         set_vi_keys();
  
-    if (number_links)
+    if (number_links && keypad_mode == NUMBERS_AS_ARROWS)
 	keypad_mode = LINKS_ARE_NUMBERED;
     if (keypad_mode == NUMBERS_AS_ARROWS)
         set_numbers_as_arrows();
@@ -1198,6 +1358,16 @@ WSADATA WSAData;
     }
 
     /*
+     *  Check the -show_cursor command line toggle. - FM
+     */
+    if (LYUseDefShoCur == FALSE) {
+	if (LYShowCursor == TRUE)
+	    LYShowCursor = FALSE;
+	else
+	    LYShowCursor = TRUE;
+    }
+
+    /*
      *  Disable multiple bookmark support if not interactive,
      *  so it doesn't crash on curses functions, or if the
      *  support was blocked via userdefs.h and/or lynx.cfg,
@@ -1422,13 +1592,17 @@ WSADATA WSAData;
         if (crawl && !number_links) {
 	    keypad_mode = NUMBERS_AS_ARROWS;
 	} else if (!nolist) {
-	    keypad_mode = LINKS_ARE_NUMBERED;
+	    if (keypad_mode == NUMBERS_AS_ARROWS) {
+		keypad_mode = LINKS_ARE_NUMBERED;
+	    }
 	}
 	if (display != NULL && *display != '\0') {
 	    LYisConfiguredForX = TRUE;
 	}
 	status = mainloop();
-        if (!nolist && keypad_mode == LINKS_ARE_NUMBERED)
+	if (!nolist &&
+	    (keypad_mode == LINKS_ARE_NUMBERED ||
+	     keypad_mode == LINKS_AND_FORM_FIELDS_ARE_NUMBERED))
 	    printlist(stdout,FALSE);
 #ifndef NOSIGHUP
         (void) signal(SIGHUP, SIG_DFL);
@@ -1464,10 +1638,10 @@ WSADATA WSAData;
  *    LYNXKEYMAP, lynxcgi, LYNXIMGMAP, LYNXCOOKIE
  */
 #ifdef GLOBALREF_IS_MACRO
-extern GLOBALREF (HTProtocol,LYLynxKeymap);
-extern GLOBALREF (HTProtocol,LYLynxCGI);
-extern GLOBALREF (HTProtocol,LYLynxIMGmap);
-extern GLOBALREF (HTProtocol,LYLynxCookies);
+extern GLOBALREF (HTProtocol, LYLynxKeymap);
+extern GLOBALREF (HTProtocol, LYLynxCGI);
+extern GLOBALREF (HTProtocol, LYLynxIMGmap);
+extern GLOBALREF (HTProtocol, LYLynxCookies);
 #else
 GLOBALREF  HTProtocol LYLynxKeymap;
 GLOBALREF  HTProtocol LYLynxCGI;
@@ -1533,6 +1707,15 @@ PRIVATE void parse_arg ARGS3(
 	return;
     }
 
+    /*
+     *  Skip any lone "-" arguments, because we've loaded
+     *  the stdin input into an HTList structure for
+     *  special handling. - FM
+     */
+    if (strcmp(argv[0], "-") == 0) {
+        return;
+    }
+
     switch (TOLOWER(argv[0][1])) {
 
     case 'a':
@@ -1586,23 +1769,23 @@ PRIVATE void parse_arg ARGS3(
 
     } else if (strncmp(argv[0], "-auth", 5) == 0) {
         /*
-	 *  Authentication information for protected forms.
+	 *  Authentication information for protected documents.
 	 */
 	char *auth_info = NULL;
 	
 	if (nextarg) {
 	    StrAllocCopy(auth_info, cp);
-	    memset(cp, ' ', strlen(cp));/* Let's not show too much */
+	    memset(cp, ' ', strlen(cp));	/* Let's not show too much */
 	}
         if (auth_info != NULL)  {
-	    if ((cp = strchr(auth_info, ':')) != NULL) { /* Pw */
+	    if ((cp = strchr(auth_info, ':')) != NULL) {	/* Pw */
 		*cp++ = '\0';	/* Terminate ID */
 		if (*cp) {
 		    HTUnEscape(cp);
 		    StrAllocCopy(authentication_info[1], cp);
 		}
 	    }
-	    if (*auth_info) { /* Id */
+	    if (*auth_info) {					/* Id */
 	        HTUnEscape(auth_info);
 		StrAllocCopy(authentication_info[0], auth_info);
 	    }
@@ -1768,6 +1951,12 @@ PRIVATE void parse_arg ARGS3(
 	break;;
 #endif /* VMS */
 	
+    } else if (strncmp(argv[0], "-force_secure", 13) == 0) {
+        if (LYForceSSLCookiesSecure)
+	    LYForceSSLCookiesSecure = FALSE;
+	else
+	    LYForceSSLCookiesSecure = TRUE;
+
     } else if (strncmp(argv[0], "-from", 5) == 0) {
         if (LYNoFromHeader)
 	    LYNoFromHeader = FALSE;
@@ -2024,7 +2213,32 @@ PRIVATE void parse_arg ARGS3(
     break;
 
     case 'p':
-    if (strncmp(argv[0], "-popup", 6) == 0) {
+    if (strncmp(argv[0], "-pauth", 6) == 0) {
+        /*
+	 *  Authentication information for protected proxy server. - AJL
+	 */
+	char *pauth_info = NULL;
+	
+	if (nextarg) {
+	    StrAllocCopy(pauth_info, cp);
+	    memset(cp, ' ', strlen(cp));	/* Let's not show too much */
+	}
+        if (pauth_info != NULL)  {
+	    if ((cp = strchr(pauth_info, ':')) != NULL) {	/* Pw */
+		*cp++ = '\0';	/* Terminate ID */
+		if (*cp) {
+		    HTUnEscape(cp);
+		    StrAllocCopy(proxyauth_info[1], cp);
+		}
+	    }
+	    if (*pauth_info) {					/* Id */
+	        HTUnEscape(pauth_info);
+		StrAllocCopy(proxyauth_info[0], pauth_info);
+	    }
+	    FREE(pauth_info);
+	}
+
+    } else if (strncmp(argv[0], "-popup", 6) == 0) {
 	LYUseDefSelPop = FALSE;
 
     } else if (strcmp(argv[0], "-post_data") == 0) {
@@ -2203,10 +2417,7 @@ PRIVATE void parse_arg ARGS3(
 	HTDirAccess = HT_DIR_SELECTIVE;
 
     } else if (strncmp(argv[0], "-show_cursor", 12) == 0) {
-	if (LYShowCursor)
-	    LYShowCursor = FALSE;
-	else
-	    LYShowCursor = TRUE;
+	LYUseDefShoCur = FALSE;
 
     } else if (strncmp(argv[0], "-soft_dquotes", 13) == 0) {
         if (soft_dquotes)
@@ -2348,11 +2559,11 @@ Output_Help_List:
     printf("                     in double-quotes (\"-\") on VMS)\n");
     printf("    -anonymous       used to specify the anonymous account\n");
 #ifdef EXP_CHARTRANS
-    printf("    -assume_charset  charset for documents that don't specify it\n");
-    printf("    -assume_local_charset  charset assumed for local files\n");
-    printf("    -assume_unrec_charset  use this instead of unrecognized charsets\n");
+    printf("    -assume_charset=MIMEname  charset for documents that don't specify it\n");
+    printf("    -assume_local_charset=MIMEname  charset assumed for local files\n");
+    printf("    -assume_unrec_charset=MIMEname  use this instead of unrecognized charsets\n");
 #endif /* EXP_CHARTRANS */
-    printf("    -auth=id:pw      authentication information for protected forms\n");
+    printf("    -auth=id:pw      authentication information for protected documents\n");
     printf("    -base            prepend a request URL comment and BASE tag to text/html\n");
     printf("                     outputs for -source or -mime_header dumps\n");
     printf("    -book            use the bookmark page as the startfile\n");
@@ -2385,6 +2596,7 @@ Output_Help_List:
     printf("    -fileversions    include all versions of files in local VMS directory\n");
     printf("                     listings\n");
     printf("    -force_html      forces the first document to be interpreted as HTML\n");
+    printf("    -force_secure    toggles forcing of the secure flag for SSL cookies\n");
     printf("    -from            toggle transmissions of From headers\n");
     printf("    -ftp             disable ftp access\n");
     printf("    -get_data        user data for get forms, read from stdin,\n");
@@ -2420,6 +2632,7 @@ Output_Help_List:
 #endif /* SOCKS */
     printf("    -nostatus        disable the miscellaneous information messages\n");
     printf("    -number_links    force numbering of links\n");
+    printf("    -pauth=id:pw     authentication information for protected proxy server\n");
     printf("    -popup           toggles handling of single-choice SELECT options via\n");
     printf("                     popup windows or as lists of radio buttons\n");
     printf("    -post_data       user data for post forms, read from stdin,\n");
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index a721ea4b..e751496b 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -141,6 +141,7 @@ int mainloop NOARGS
     char *owner_address = NULL;  /* Holds the responsible owner's address     */
     char *ownerS_address = NULL; /* Holds owner's address during source fetch */
     BOOLEAN first_file = TRUE;
+    BOOLEAN popped_doc = FALSE;
     BOOLEAN refresh_screen = FALSE;
     BOOLEAN force_load = FALSE;
     BOOLEAN try_internal = FALSE;
@@ -306,19 +307,31 @@ initialize:
 		}
 try_again:
 		/*
-		 *  Push the old file onto the history stack.
+		 *  Push the old file onto the history stack if we
+		 *  have a current doc and a new address. - FM
 	 	 */
 		if (curdoc.address && newdoc.address) {
-		    LYpush(&curdoc, ForcePush);
-
+		    /*
+		     *  Don't actually push if this is a LYNXDOWNLOAD
+		     *  URL, because that returns NORMAL even if it
+		     *  fails due to a spoof attempt or file access
+		     *  problem, and we set the newdoc structure
+		     *  elements to the curdoc structure elements
+		     *  under case NORMAL.  - FM
+		     */
+		    if (strncmp(newdoc.address, "LYNXDOWNLOAD:", 13)) {
+			LYpush(&curdoc, ForcePush);
+		    }
 		} else if (!newdoc.address) {
 		    /*
 		     *  If newdoc.address is empty then pop a file
 		     *  and load it.  Force a no_cache override unless
-		     *  it's a bookmark file or it has POST content
-		     *  and LYresubmit_posts is set. - FM
+		     *  it's a bookmark file, or it has POST content
+		     *  and LYresubmit_posts is set without safe also
+		     *  set.
 		     */
                     LYpop(&newdoc);
+		    popped_doc = TRUE;
 		    /*
 		    ** If curdoc had been reached via an internal
 		    ** (fragment) link from what we now have just
@@ -331,7 +344,8 @@ try_again:
 			LYforce_no_cache = FALSE;
 			try_internal = TRUE;
 		    } else if ((newdoc.bookmark != NULL) ||
-		        (newdoc.post_data != NULL && LYresubmit_posts)) {
+			(newdoc.post_data != NULL && !newdoc.safe &&
+			 LYresubmit_posts)) {
 		        LYoverride_no_cache = FALSE;
 		    } else {
 		        LYoverride_no_cache = TRUE;
@@ -466,6 +480,7 @@ try_again:
 		     *  Do any error logging, if appropriate.
 		     */
 		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
+		    popped_doc = FALSE;		 /* Was TRUE if popped. - FM */
 		    if (trace_mode_flag == TRUE) {
 			WWW_TraceFlag = TRUE;
 			trace_mode_flag = FALSE;
@@ -506,6 +521,7 @@ try_again:
 #endif /* SIGTSTP */
 			        exit(-1);
 			    }
+			    chmod(TRAVERSE_ERRORS, 0600);
 		        }
 		        fprintf(ofp, "%s %s	in %s\n",
 		       		     links[curdoc.link].lname, 
@@ -555,6 +571,7 @@ try_again:
 		     *  Not supposed to return any file.
 		     */
 		    LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
+		    popped_doc = FALSE;		 /* Was TRUE if popped. - FM */
 		    if (trace_mode_flag == TRUE) {
 			WWW_TraceFlag = TRUE;
 			trace_mode_flag = FALSE;
@@ -796,7 +813,7 @@ try_again:
 			    FREE(traversal_link_to_add);
 			}
 			if (curdoc.address && curdoc.title &&
-			    strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
+			    strncmp(curdoc.address, "LYNXIMGMAP:", 11))
 			    /*
 			     *  Add the address we got to TRAVERSE_FOUND_FILE.
 			     */
@@ -804,16 +821,15 @@ try_again:
 		    }
 
 		    /*
-		     *  If this was a NORMAL download, we still have curdoc,
+		     *  If this was a LYNXDOWNLOAD, we still have curdoc,
 		     *  not a newdoc, so reset the address, title and
 		     *  positioning elements. - FM
 		     */
-		    if (newdoc.address && curdoc.title &&
-		        !strncmp(newdoc.address, "LYNXDOWNLOAD:", 13) &&
-		        !strcmp((curdoc.title ? curdoc.title : ""),
-				DOWNLOAD_OPTIONS_TITLE)) {
+		    if (newdoc.address && curdoc.address &&
+		        !strncmp(newdoc.address, "LYNXDOWNLOAD:", 13)) {
 			StrAllocCopy(newdoc.address, curdoc.address);
-			StrAllocCopy(newdoc.title, curdoc.title);
+			StrAllocCopy(newdoc.title, (curdoc.title ?
+						    curdoc.title : ""));
 			StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
 			newdoc.line = curdoc.line;
 			newdoc.link = curdoc.link;
@@ -828,10 +844,11 @@ try_again:
                     Newline = newdoc.line;
 
 		    /* 
-		     *  If we are going to a target line,
+		     *  If we are going to a target line or
+		     *  the first page of a popped document,
 		     *  override any www_search line result.
 		     */
-		    if (Newline > 1)	
+		    if (Newline > 1 || popped_doc == TRUE)	
 			 www_search_result = -1;
 
 		    /*
@@ -899,6 +916,7 @@ try_again:
 	   LYPermitURL = FALSE;		/* only set for LYValidate */
 	   ForcePush = FALSE;		/* only set for some PRINT requests. */
 	   LYforce_HTML_mode = FALSE;
+	   popped_doc = FALSE;
 
   	} /* end if (STREQ(newdoc.address, curdoc.address) */
 
@@ -972,7 +990,7 @@ try_again:
 		 *  Set up the crawl output stuff.
 		 */
 		if (curdoc.address && !lookup(curdoc.address)) {
-		    if (strncasecomp(curdoc.address, "LYNXIMGMAP:", 11))
+		    if (strncmp(curdoc.address, "LYNXIMGMAP:", 11))
 		        crawl_ok = TRUE;
 		    add_to_table(curdoc.address);
 		}
@@ -1027,11 +1045,9 @@ try_again:
 	}
 
 	/*
-	 *  If the curdoc.line is different than Newline then there
-	 *  must have been a change since last update.  Run showpage.
-	 *  showpage will put a fresh screen of text out.  If this is
-	 *  a WWW document then use the WWW routine HText_pageDisplay
-	 *  to put the page on the screen.
+	 *  If the curdoc.line is different than Newline then there must
+	 *  have been a change since last update.  Run HText_pageDisplay()
+	 *  create a fresh screen of text out.
          */
 	if (curdoc.line != Newline) {
 	
@@ -1275,7 +1291,10 @@ try_again:
 	      links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
               (links[curdoc.link].form->type == F_TEXT_TYPE ||
 	       links[curdoc.link].form->type == F_TEXTAREA_TYPE)))
-	    highlight(ON, curdoc.link); /* highlight current link */
+	     /*
+	      *  Highlight current link.
+	      */
+	    highlight(ON, curdoc.link, prev_target);
 
 	if (traversal) {
 	    /*
@@ -1287,6 +1306,7 @@ try_again:
 	        sprintf(cfile,"lnk%08d.dat",ccount);
 	        ccount = ccount + 1;
 	        if ((cfp = fopen(cfile,"w"))  != NULL) {
+		    chmod(cfile, 0600);
 	            print_crawl_to_fd(cfp,curdoc.address,curdoc.title);
 	            fclose(cfp);
 	        } else {
@@ -1336,10 +1356,10 @@ try_again:
 		    move(LYlines-1,0); clrtoeol();
 		    addstr(FORM_NOVICELINE_TWO);
 	        }
-	        c=change_form_link(&links[curdoc.link],
-			       FORM_UP, &newdoc, &refresh_screen,
-			       links[curdoc.link].form->name,
-			       links[curdoc.link].form->value);
+	        c = change_form_link(&links[curdoc.link],
+				     FORM_UP, &newdoc, &refresh_screen,
+				     links[curdoc.link].form->name,
+				     links[curdoc.link].form->value);
 
 	        if (c == '\n' || c == '\r')
 #ifdef FASTTAB
@@ -1360,6 +1380,7 @@ try_again:
 		 *  redundant error reporting.
 	         */
 	        real_c = c = LYgetch();	/* get user input */
+		
 #ifndef VMS
 		if (c == 3) {		/* ^C */
 		    /*
@@ -1409,8 +1430,8 @@ new_keyboard_input:
 		    (!lookup_reject(links[curdoc.link].lname) &&
 		     traversal_host && links[curdoc.link].lname &&
 		     !strncmp(traversal_host,
-			      (strncasecomp(links[curdoc.link].lname,
-					    "LYNXIMGMAP:", 11)
+			      (strncmp(links[curdoc.link].lname,
+				       "LYNXIMGMAP:", 11)
 					 ?
 		links[curdoc.link].lname : (links[curdoc.link].lname + 11)),
 			      strlen(traversal_host)));
@@ -1447,8 +1468,7 @@ new_keyboard_input:
 		} else {
 		    StrAllocCopy(traversal_link_to_add,
 		    		 links[curdoc.link].lname);
-		    if (strncasecomp(traversal_link_to_add,
-		    		     "LYNXIMGMAP:", 11))
+		    if (strncmp(traversal_link_to_add, "LYNXIMGMAP:", 11))
 		        crawl_ok = TRUE;
 		    c = RTARROW;
 		}
@@ -1608,7 +1628,7 @@ new_cmd:  /*
 			     *  follow_link_number(), and re-initialize
 			     *  the new link value. - FM
 			     */
-			    highlight(OFF, curdoc.link);
+			    highlight(OFF, curdoc.link, prev_target);
 			    curdoc.link = newdoc.link;
 			    newdoc.link = 0;
 			}
@@ -1703,8 +1723,8 @@ new_cmd:  /*
 	    /*
 	     *  Don't assume the reloaded document will be the same. - FM
 	     */
-	    newdoc.line=1;
-	    newdoc.link=0;
+	    newdoc.line = 1;
+	    newdoc.link = 0;
 #else
 	    /*
 	     *  Do assume the reloaded document will be the same. - FM
@@ -1721,8 +1741,10 @@ new_cmd:  /*
 		_statusline(RELOADING_FORM);
 		sleep(AlertSecs);
 	    }
-	    newdoc.line = ((curdoc.line > 0) ? curdoc.line : 1);
-	    newdoc.link = ((curdoc.link > -1) ? curdoc.link : 0);
+	    newdoc.line = ((curdoc.line > 0) ?
+	    			 curdoc.line : 1);
+	    newdoc.link = ((curdoc.link > -1) ?
+	    			  curdoc.link : 0);
 #endif /* NO_ASSUME_SAME_DOC */
 	    FREE(curdoc.address); /* so it doesn't get pushed */
 #ifdef VMS
@@ -1731,11 +1753,10 @@ new_cmd:  /*
 	    /*
 	     *  Reload should force a cache refresh on a proxy.
 	     *        -- Ari L. <luotonen@dxcern.cern.ch>
-	     */
-	    /* - but only if this was really a reload requested by
+	     *
+	     *  -- but only if this was really a reload requested by
 	     *  the user, not if we jumped here to handle reloading for
-	     *  INLINE_TOGGLE, IMAGE_TOGGLE, RAW_TOGGLE, etc.
-	     *  - kw
+	     *  INLINE_TOGGLE, IMAGE_TOGGLE, RAW_TOGGLE, etc. - KW
 	     */
 	    if (real_cmd == LYK_RELOAD)
 		reloading = TRUE;
@@ -1892,7 +1913,7 @@ new_cmd:  /*
 	    if (more) {
 	        Newline += display_lines;
 	    } else if (curdoc.link < nlinks-1) {
-		highlight(OFF,curdoc.link);
+		highlight(OFF, curdoc.link, prev_target);
 		curdoc.link = nlinks-1;  /* put on last link */
 	    } else if (old_c != real_c) {
 		   old_c = real_c;
@@ -1905,7 +1926,7 @@ new_cmd:  /*
 	    if (Newline > 1) {
 		Newline -= display_lines;
 	    } else if (curdoc.link > 0) {
-		highlight(OFF,curdoc.link);
+		highlight(OFF, curdoc.link, prev_target);
 		curdoc.link = 0;  /* put on first link */
 	    } else if (old_c != real_c) {
 		old_c = real_c;
@@ -2013,17 +2034,21 @@ new_cmd:  /*
 
 	case LYK_PREV_LINK:
 	    if (curdoc.link > 0) {	     /* previous link */
-		highlight(OFF, curdoc.link); /* unhighlight the current link */
+		/*
+		 *  Unhighlight current link.
+		 */
+		highlight(OFF, curdoc.link, prev_target);
 		curdoc.link--;
 
 	    } else if (!more &&
 	    	       curdoc.link==0 && Newline==1) { /* at the top of list */ 
 		/*
 		 *  If there is only one page of data and the user
-		 *  goes off the top, then just move the cursor to
-		 *  last link on the page.
+		 *  goes off the top, then unhighlight the current
+		 *  link and just move the cursor to last link on
+		 *  the page.
 		 */
-		highlight(OFF,curdoc.link); /* unhighlight the current link */
+		highlight(OFF, curdoc.link, prev_target);
 		curdoc.link = nlinks-1;  /* the last link */
 
 	    } else if (curdoc.line > 1) {	/* previous page */
@@ -2042,7 +2067,7 @@ new_cmd:  /*
 
 	case LYK_NEXT_LINK:
 	    if (curdoc.link < nlinks-1) {	/* next link */
-		highlight(OFF, curdoc.link);
+		highlight(OFF, curdoc.link, prev_target);
 #ifdef FASTTAB
 		/*
 		 *  Move to different textarea if TAB in textarea.
@@ -2070,7 +2095,7 @@ new_cmd:  /*
 	     *  Move to the top link on the page.
 	     */
 	    } else if (!more && Newline == 1 && curdoc.link == nlinks-1) {
-		highlight(OFF,curdoc.link); 
+		highlight(OFF, curdoc.link, prev_target); 
 		curdoc.link = 0;
 
             } else if (more) {  /* next page */
@@ -2093,11 +2118,11 @@ new_cmd:  /*
                     }
 		}
                 if (newlink > -1) {
-                    highlight(OFF, curdoc.link);
+                    highlight(OFF, curdoc.link, prev_target);
                     curdoc.link = newlink;
 #ifdef NOTDEFINED
                 } else if (!more && Newline == 1 && curdoc.link == 0) {
-                    highlight(OFF, curdoc.link);
+                    highlight(OFF, curdoc.link, prev_target);
                     curdoc.link = (nlinks-1);
                 } else if (more) {  /* next page */
                         Newline += (display_lines);
@@ -2116,7 +2141,7 @@ new_cmd:  /*
              *  Move to the top link on the page.
              */
             } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) {
-                highlight(OFF, curdoc.link);
+                highlight(OFF, curdoc.link, prev_target);
                 curdoc.link = 0;
 #endif /* NOTDEFINED */
 
@@ -2141,12 +2166,12 @@ new_cmd:  /*
 		   }
 			
 		if (newlink > -1) {
-                    highlight(OFF, curdoc.link);
+                    highlight(OFF, curdoc.link, prev_target);
                     curdoc.link = newlink;
 #ifdef NOTDEFINED
 		} else if (!more &&
 			   Newline == 1 && curdoc.link == (nlinks-1)) {
-                    highlight(OFF, curdoc.link);
+                    highlight(OFF, curdoc.link, prev_target);
                     curdoc.link = 0;
 #endif /* NOTDEFINED */
                 } else if (more) {  /* next page */
@@ -2163,7 +2188,7 @@ new_cmd:  /*
              *  Move to the top link on the page.
              */
             } else if (!more && Newline == 1 && curdoc.link == (nlinks-1)) {
-                highlight(OFF, curdoc.link);
+                highlight(OFF, curdoc.link, prev_target);
                 curdoc.link = 0;
 #endif /* NOTDEFINED */
             } else if (more) {  /* next page */
@@ -2179,7 +2204,7 @@ new_cmd:  /*
 	case LYK_RIGHT_LINK:
 	    if (curdoc.link<nlinks-1 &&
 			links[curdoc.link].ly == links[curdoc.link+1].ly) {
-                highlight(OFF,curdoc.link);
+                highlight(OFF, curdoc.link, prev_target);
 		curdoc.link++;
 	    }
 	    break;
@@ -2187,7 +2212,7 @@ new_cmd:  /*
 	case LYK_LEFT_LINK:
 	    if (curdoc.link>0 &&
 			links[curdoc.link].ly == links[curdoc.link-1].ly) {
-                highlight(OFF,curdoc.link);
+                highlight(OFF, curdoc.link, prev_target);
 		curdoc.link--;
 	    }
 	    break;
@@ -2414,6 +2439,42 @@ new_cmd:  /*
 			    LYforce_no_cache = FALSE;
 			    break;
 			}
+			/*
+			 *  Make sure this isn't a spoof attempt
+			 *  via an internal URL. - FM
+			 */
+			if (!strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXCOOKIE:", 11) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXDIRED:", 10) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXDOWNLOAD:", 13) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXHIST:", 9) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXKEYMAP:", 11) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXIMGMAP:", 11) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "LYNXPRINT:", 10) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "lynxexec:", 9) ||
+			    !strncasecomp(
+				    links[curdoc.link].form->submit_action,
+					  "lynxprog:", 9)) {
+			    HTAlert(SPECIAL_ACTION_DISALLOWED);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
 #ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
 		        /*
 			 *  Check for enctype and let user know we
@@ -2435,7 +2496,7 @@ new_cmd:  /*
 			    LYPermitURL = TRUE;
 			}
 			if (no_filereferer == TRUE &&
-			    !strncasecomp(curdoc.address, "file:", 5)) {
+			    !strncmp(curdoc.address, "file:", 5)) {
 			    LYNoRefererForThis = TRUE;
 			}
 		    }
@@ -2464,6 +2525,10 @@ new_cmd:  /*
 			    break;
 			}
 		    }
+		    if (c == 23) {
+			c = DO_NOTHING;
+			refresh_screen = TRUE;
+		    }
 		    goto new_keyboard_input;
 	        } else {
 		    /*
@@ -2473,8 +2538,8 @@ new_cmd:  /*
 		     *  with restrictions on file URLs. - FM
 		     */
 		    if (no_file_url &&
-		        !strncasecomp(links[curdoc.link].lname, "file:", 5)) {
-			if (strncasecomp(curdoc.address, "file:", 5)) {
+		        !strncmp(links[curdoc.link].lname, "file:", 5)) {
+			if (strncmp(curdoc.address, "file:", 5)) {
 			    HTAlert(FILE_SERVED_LINKS_DISALLOWED);
 			    break;
 			} else if (curdoc.bookmark != NULL) {
@@ -2483,6 +2548,42 @@ new_cmd:  /*
 			}
 		    }
 		    /*
+		     *  Make sure this isn't a spoof attempt
+		     *  via an internal URL in a non-internal
+		     *  document. - FM
+		     */
+		    if ((!strncmp(links[curdoc.link].lname,
+				  "LYNXCOOKIE:", 11) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				COOKIE_JAR_TITLE)) ||
+#ifdef DIRED_SUPPORT
+			(!strncmp(links[curdoc.link].lname,
+				  "LYNXDIRED:", 10) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				DIRED_MENU_TITLE) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				PERMIT_OPTIONS_TITLE) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				UPLOAD_OPTIONS_TITLE)) ||
+#endif /* DIRED_SUPPORT */
+			(!strncmp(links[curdoc.link].lname,
+				 "LYNXDOWNLOAD:", 13) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				DOWNLOAD_OPTIONS_TITLE)) ||
+			(!strncmp(links[curdoc.link].lname,
+				  "LYNXHIST:", 9) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				HISTORY_PAGE_TITLE)) ||
+			(!strncmp(links[curdoc.link].lname,
+				  "LYNXPRINT:", 10) &&
+			 strcmp((curdoc.title ? curdoc.title : ""),
+				PRINT_OPTIONS_TITLE))) {
+			    HTAlert(SPECIAL_VIA_EXTERNAL_DISALLOWED);
+			    HTOutputFormat = WWW_PRESENT;
+			    LYforce_no_cache = FALSE;
+			    break;
+			}
+		    /*
 		     *  Follow a normal link or anchor. 
 		     */
 		    StrAllocCopy(newdoc.address, links[curdoc.link].lname);
@@ -2527,7 +2628,7 @@ new_cmd:  /*
 			        !strcmp(lynxjumpfile, curdoc.address))) {
 		        LYUserSpecifiedURL = TRUE;
 		    } else if (no_filereferer == TRUE &&
-		    	       !strncasecomp(curdoc.address, "file:", 5)) {
+		    	       !strncmp(curdoc.address, "file:", 5)) {
 			LYNoRefererForThis = TRUE;
 		    }
 		    newdoc.link = 0;
@@ -2544,7 +2645,7 @@ new_cmd:  /*
 			  strip_trailing_slash(newdoc.address);
 		    }
 #endif /* DIRED_SUPPORT */
-		    if (!strncasecomp(curdoc.address, "LYNXCOOKIE:", 11)) {
+		    if (!strncmp(curdoc.address, "LYNXCOOKIE:", 11)) {
 		        HTuncache_current_document();
 		    }
 		}
@@ -2891,6 +2992,13 @@ check_goto_URL:
                 _statusline(GOTO_WAIS_DISALLOWED);
                 sleep(MessageSecs);
 
+	    } else if (!strncmp(user_input_buffer, "LYNXCOOKIE:", 11) ||
+		       !strncmp(user_input_buffer, "LYNXDIRED:", 10) ||
+		       !strncmp(user_input_buffer, "LYNXDOWNLOAD:", 13) ||
+		       !strncmp(user_input_buffer, "LYNXPRINT:", 10)) {
+		_statusline(GOTO_SPECIAL_DISALLOWED);
+		sleep(MessageSecs);
+
            } else {
 	        StrAllocCopy(newdoc.address, user_input_buffer);
 		newdoc.isHEAD = FALSE;
@@ -3025,7 +3133,7 @@ check_goto_URL:
 		    newdoc.isHEAD = FALSE;
 		    newdoc.safe = FALSE;
 		    newdoc.internal_link = FALSE;
-	            highlight(OFF,curdoc.link); 
+	            highlight(OFF, curdoc.link, prev_target); 
 #ifdef DIRED_SUPPORT
 		    if (lynx_edit_mode)
 		      HTuncache_current_document();
@@ -3065,13 +3173,13 @@ check_goto_URL:
 		LYRawMode_flag != LYRawMode ||
 		LYSelectPopups_flag != LYSelectPopups ||
 		((strcmp(CurrentUserAgent, (LYUserAgent ?
-					   LYUserAgent : "")) ||
+					    LYUserAgent : "")) ||
 		  strcmp(CurrentNegoLanguage, (language ?
 					       language : "")) ||
 		  strcmp(CurrentNegoCharset, (pref_charset ?
-					      pref_charset : ""))
-		  ) && (strncmp(curdoc.address, "http", 4) == 0 ||
-			strncmp(curdoc.address, "lynxcgi:", 8) == 0))) {
+					      pref_charset : ""))) &&
+		 (!strncmp(curdoc.address, "http", 4) ||
+		  !strncmp(curdoc.address, "lynxcgi:", 8)))) {
 	        /*
 		 *  Check if this is a reply from a POST, and if so,
 		 *  seek confirmation of reload if the safe element
@@ -3086,22 +3194,24 @@ check_goto_URL:
 		} else {
 		    LYforce_no_cache = TRUE;
 		    StrAllocCopy(newdoc.address, curdoc.address);
-		    if (((strcmp(CurrentNegoLanguage,
+		    if (((strcmp(CurrentUserAgent, (LYUserAgent ?
+					    LYUserAgent : "")) ||
+			  strcmp(CurrentNegoLanguage,
 				 (language ? language : "")) ||
 			  strcmp(CurrentNegoCharset,
 				 (pref_charset ? pref_charset : ""))) &&
 			 (strncmp(curdoc.address, "http", 4) == 0 ||
 			  strncmp(curdoc.address, "lynxcgi:", 8) == 0))) {
 			/*
-			 * An option has changed which may influence
-			 * content negotiation, and the resource is from
-			 * a http or https or lynxcgi URL (the only protocols
-			 * which currently do anything with this information).
-			 * Set reloading=TRUE so that proxy caches will be
-			 * flushed, which is necessary until the time when
-			 * all proxies understand HTTP 1.1 Vary: and all
-			 * Servers properly use it...  Treat like
-			 * case LYK_RELOAD (see comments there). - kw
+			 *  An option has changed which may influence
+			 *  content negotiation, and the resource is from
+			 *  a http or https or lynxcgi URL (the only protocols
+			 *  which currently do anything with this information).
+			 *  Set reloading = TRUE so that proxy caches will be
+			 *  flushed, which is necessary until the time when
+			 *  all proxies understand HTTP 1.1 Vary: and all
+			 *  Servers properly use it...  Treat like
+			 *  case LYK_RELOAD (see comments there). - KW
 			 */
 			if (HTisDocumentSource()) {
 			    HTOutputFormat = WWW_SOURCE;
@@ -3109,48 +3219,46 @@ check_goto_URL:
 			HEAD_request = HTLoadedDocumentIsHEAD();
 			HTuncache_current_document();
 #ifdef NO_ASSUME_SAME_DOC
-			newdoc.line=1;
-			newdoc.link=0;
+			newdoc.line = 1;
+			newdoc.link = 0;
 #else
 			if (lynx_mode == FORMS_LYNX_MODE) {
 			    _statusline(RELOADING_FORM);
 			    sleep(AlertSecs);
 			}
-			newdoc.line = ((curdoc.line > 0) ? curdoc.line : 1);
-			newdoc.link = ((curdoc.link > -1) ? curdoc.link : 0);
+			newdoc.line = ((curdoc.line > 0) ?
+					     curdoc.line : 1);
+			newdoc.link = ((curdoc.link > -1) ?
+					      curdoc.link : 0);
 #endif /* NO_ASSUME_SAME_DOC */
 		        FREE(curdoc.address);
 			reloading = TRUE;
 		    } else if (keypad_mode_flag != keypad_mode ||
-		        (user_mode_flag != user_mode &&
-			 (user_mode_flag == NOVICE_MODE ||
-			  user_mode == NOVICE_MODE)) ||
-		        (((HTfileSortMethod_flag != HTfileSortMethod) ||
+			       (user_mode_flag != user_mode &&
+				(user_mode_flag == NOVICE_MODE ||
+				 user_mode == NOVICE_MODE)) ||
+			       (((HTfileSortMethod_flag != HTfileSortMethod) ||
 #ifdef DIRED_SUPPORT
-			  (c != dir_list_style) ||
+				 (c != dir_list_style) ||
 #endif /* DIRED_SUPPORT */
-			  (show_dotfiles_flag != show_dotfiles)) &&
-			 (!strncmp(curdoc.address, "file:", 5) ||
-			  !strncmp(curdoc.address, "ftp:", 4))) ||
-			LYSelectPopups_flag != LYSelectPopups ||
-			(strcmp(CurrentUserAgent, (LYUserAgent ?
-						    LYUserAgent : "")) &&
-			 !strncmp(curdoc.address, "http", 4))) {
+				 (show_dotfiles_flag != show_dotfiles)) &&
+				(!strncmp(curdoc.address, "file:", 5) ||
+				 !strncmp(curdoc.address, "ftp:", 4))) ||
+				LYSelectPopups_flag != LYSelectPopups) {
 		        HTuncache_current_document();
 		        FREE(curdoc.address);
-		    } else {
 		    }
 		}
-		keypad_mode_flag = keypad_mode;
-		user_mode_flag = user_mode;
-		HTfileSortMethod_flag = HTfileSortMethod;
-		CurrentCharSet_flag = current_char_set;
-		show_dotfiles_flag = show_dotfiles;
-		LYRawMode_flag = LYRawMode;
-		LYSelectPopups_flag = LYSelectPopups;
-		StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
-						LYUserAgent : ""));
 	    }
+	    keypad_mode_flag = keypad_mode;
+	    user_mode_flag = user_mode;
+	    HTfileSortMethod_flag = HTfileSortMethod;
+	    CurrentCharSet_flag = current_char_set;
+	    show_dotfiles_flag = show_dotfiles;
+	    LYRawMode_flag = LYRawMode;
+	    LYSelectPopups_flag = LYSelectPopups;
+	    StrAllocCopy(CurrentUserAgent, (LYUserAgent ?
+					    LYUserAgent : ""));
 	    StrAllocCopy(CurrentNegoLanguage, (language ?
 					       language : ""));
 	    StrAllocCopy(CurrentNegoCharset, (pref_charset ?
@@ -3426,10 +3534,10 @@ check_goto_URL:
 		    }
 	        }
 		if (curdoc.link < nlinks-1) {
-		    highlight(OFF, curdoc.link);
+		    highlight(OFF, curdoc.link, prev_target);
 		    curdoc.link++;
 		} else if (!more && Newline == 1 && curdoc.link == nlinks-1) {
-		    highlight(OFF,curdoc.link); 
+		    highlight(OFF, curdoc.link, prev_target); 
 		    curdoc.link = 0;
 		} else if (more) {  /* next page */
 		    Newline += (display_lines);
@@ -3917,7 +4025,7 @@ check_goto_URL:
 	    }
 
 	    if (strcmp((curdoc.title ? curdoc.title : ""),
-	    	       HISTORY_PAGE_TITLE) &&
+		       HISTORY_PAGE_TITLE) &&
 	        strcmp((curdoc.title ? curdoc.title : ""),
 		       SHOWINFO_TITLE) && 
 	        strcmp((curdoc.title ? curdoc.title : ""),
@@ -3934,14 +4042,31 @@ check_goto_URL:
 		       DOWNLOAD_OPTIONS_TITLE) &&
 	        strcmp((curdoc.title ? curdoc.title : ""),
 		       COOKIE_JAR_TITLE) &&
-	        strcmp((curdoc.title ? curdoc.title : ""),
-		       LIST_PAGE_TITLE)) {
+		((nlinks <= 0) ||
+		 (links[curdoc.link].lname != NULL &&
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXHIST:", 9) && 
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXPRINT:", 10) && 
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXDIRED:", 10) && 
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXDOWNLOAD:", 13) && 
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXCOOKIE:", 11) &&
+		  strncmp(links[curdoc.link].lname,
+			 "LYNXLIST:", 9)))) {
 		if (nlinks > 0) {
 		    if (curdoc.post_data == NULL &&
-		        curdoc.bookmark == NULL) {
+		        curdoc.bookmark == NULL &&
+			strcmp((curdoc.title ? curdoc.title : ""),
+			       LIST_PAGE_TITLE) &&
+			strcmp((curdoc.title ? curdoc.title : ""),
+			       VISITED_LINKS_TITLE)) {
 		        /*
-			 *  Document doesn't have POST content,
-			 *  and is not a bookmark file, so we can
+			 *  The document doesn't have POST content,
+			 *  and is not a bookmark file, nor is the
+			 *  list or visited links page, so we can
 			 *  save either that or the link. - FM
 			 */
 		        _statusline(BOOK_D_L_OR_CANCEL);
@@ -4109,7 +4234,7 @@ check_add_bookmark_to_self:
 		     */
 		    *stderr = *LYTraceLogFP;
 	        start_curses();
-	        refresh_screen = TRUE;  /* for a showpage */
+	        refresh_screen = TRUE;  /* for an HText_pageDisplay() */
 	    } else {
 		if (old_c != real_c)	{
 			old_c = real_c;
@@ -4243,13 +4368,27 @@ check_add_bookmark_to_self:
 		     */
 		    LYforce_no_cache = TRUE;
 		    
-		} else if (!strncasecomp(links[curdoc.link].lname,
-					 "data:", 5)) {
+		} else if (!strncmp(links[curdoc.link].lname, "data:", 5)) {
 		    if (old_c != real_c) {
 			old_c = real_c;
 			HTAlert(UNSUPPORTED_DATA_URL);
 		    }
 
+		} else if (!strncmp(links[curdoc.link].lname,
+				    "LYNXCOOKIE:", 11) ||
+			   !strncmp(links[curdoc.link].lname,
+				    "LYNXDIRED:", 10) ||
+			   !strncmp(links[curdoc.link].lname,
+				    "LYNXDOWNLOAD:", 13) ||
+			   !strncmp(links[curdoc.link].lname,
+				    "LYNXPRINT:", 10) ||
+			   !strncmp(links[curdoc.link].lname,
+				    "lynxexec:", 9) ||
+			   !strncmp(links[curdoc.link].lname,
+				    "lynxprog:", 9)) {
+		    _statusline(NO_DOWNLOAD_SPECIAL);
+		    sleep(MessageSecs);
+
                 } else {   /* Not a forms, options or history link */
                     /*
 		     *  Follow a normal link or anchor.  Note that
@@ -4352,6 +4491,7 @@ check_add_bookmark_to_self:
 		    break;
 		}
 #endif /* VMS */
+		chmod(LYTraceLogPath, 0600);
 		*stderr = *LYTraceLogFP;
 		fprintf(stderr, "\t\t%s\n\n", LYNX_TRACELOG_TITLE);
 	    }
@@ -4591,7 +4731,6 @@ check_add_bookmark_to_self:
 		/*
 		 *  Remember whether we are in dired menu
 		 *  so we can display the right keymap.
-		 *  Don't cache the keymap because it changes. - EF
 		 */
 		if (!no_dired_support) {
 		    prev_lynx_edit_mode = lynx_edit_mode;
diff --git a/src/LYMap.c b/src/LYMap.c
index e4141cf6..f15421cc 100644
--- a/src/LYMap.c
+++ b/src/LYMap.c
@@ -154,7 +154,7 @@ PUBLIC BOOL LYAddMapElement ARGS4(
 	char *,		map,
 	char *,		address,
 	char *,		title,
-				  BOOL,	intern_flag)
+	BOOL,		intern_flag)
 {
     LYMapElement *new = NULL;
     LYImageMap *theMap = NULL;
@@ -207,7 +207,6 @@ PUBLIC BOOL LYAddMapElement ARGS4(
  *  with a given address already exists in the LynxMaps
  *  structure. - FM
  */
-#if UNUSED
 PUBLIC BOOL LYHaveImageMap ARGS1(
 	char *,		address)
 {
@@ -225,7 +224,6 @@ PUBLIC BOOL LYHaveImageMap ARGS1(
 
     return FALSE;
 }
-#endif
 
 /* 	LYLoadIMGmap - F.Macrides (macrides@sci.wfeb.edu)
 **	------------
@@ -373,8 +371,8 @@ PRIVATE int LYLoadIMGmap ARGS4 (
     sprintf(buf,"<h2><em>MAP:</em>&nbsp;%s</h2>\n", MapAddress);
     (*target->isa->put_block)(target, buf, strlen(buf));
 
-    sprintf(buf, "<%s compact>\n", (keypad_mode == LINKS_ARE_NUMBERED) ?
-    				   "ul" : "ol");
+    sprintf(buf, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+    				    "ol" : "ul"));
     (*target->isa->put_block)(target, buf, strlen(buf));
     cur = theMap->elements;
     while (NULL != (new=(LYMapElement *)HTList_nextObject(cur))) {
@@ -391,8 +389,8 @@ PRIVATE int LYLoadIMGmap ARGS4 (
 	(*target->isa->put_block)(target, MapTitle, strlen(MapTitle));
 	(*target->isa->put_block)(target, "</a>\n", 5);
     }
-    sprintf(buf,"</%s>\n</body>\n", (keypad_mode == LINKS_ARE_NUMBERED) ?
-    				      "ul" : "ol");
+    sprintf(buf,"</%s>\n</body>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+    				     "ol" : "ul"));
     (*target->isa->put_block)(target, buf, strlen(buf));
 
     (*target->isa->_free)(target);
diff --git a/src/LYNews.c b/src/LYNews.c
index 65186f00..917bc137 100644
--- a/src/LYNews.c
+++ b/src/LYNews.c
@@ -1,9 +1,10 @@
 #include "HTUtils.h"
 #include "tcp.h"
+#include "HTParse.h"
+#include "HTAccess.h"
+#include "HTCJK.h"
 #include "HTAlert.h"
 #include "LYCurses.h"
-#include "HTAccess.h"
-#include "HTParse.h"
 #include "LYSignal.h"
 #include "LYStructs.h"
 #include "LYUtils.h"
@@ -13,7 +14,7 @@
 #include "LYHistory.h"
 #include "LYSystem.h"
 #include "GridText.h"
-#include "LYSignal.h"
+#include "LYCharSets.h"
 #include "LYNews.h"
 
 #include "LYGlobalDefs.h"
@@ -44,14 +45,17 @@ PUBLIC char *LYNewsPost ARGS2(
 	BOOLEAN,	followup)
 {
     char user_input[1024];
+    char CJKinput[1024];
     char *cp = NULL;
     int c = 0;  /* user input */
-    FILE *fd;
+    FILE *fd = NULL;
     char my_tempfile[256];
+    FILE *fc = NULL;
+    char CJKfile[256];
     char *postfile = NULL;
     char *NewsGroups = NULL;
     char *org = NULL;
-    FILE *fp;
+    FILE *fp = NULL;
 
     /*
      *  Make sure a non-zero length newspost, newsreply,
@@ -63,12 +67,35 @@ PUBLIC char *LYNewsPost ARGS2(
     /*
      *  Open a temporary file for the headers
      *  and message body. - FM
-     */ 
+     */
     tempname(my_tempfile, NEW_FILE);
     if ((fd = fopen(my_tempfile, "w")) == NULL) {
 	HTAlert(CANNOT_OPEN_TEMP);
 	return(postfile);
     }
+    chmod(my_tempfile, 0600);
+
+    /*
+     *  If we're using a Japanese display character set,
+     *  open a temporary file for a conversion to JIS. - FM
+     */
+    CJKfile[0] = '\0';
+    if (!strncmp(LYchar_set_names[current_char_set], "Japanese (EUC)", 14) ||
+	!strncmp(LYchar_set_names[current_char_set], "Japanese (SJIS)", 15)) {
+	tempname(CJKfile, NEW_FILE);
+	if ((fc = fopen(CJKfile, "w")) == NULL) {
+	    HTAlert(CANNOT_OPEN_TEMP);
+	    fclose(fd);
+#ifdef VMS
+	    while (remove(my_tempfile) == 0)
+		; /* loop through all versions */
+#else
+	    remove(my_tempfile);
+#endif /* VMS */
+	    return(postfile);
+	}
+	chmod(CJKfile, 0600);
+    }
 
     /*
      *  The newsgroups could be a comma-seperated list.
@@ -109,8 +136,8 @@ PUBLIC char *LYNewsPost ARGS2(
 	term_message) {
         _statusline(NEWS_POST_CANCELLED);
 	sleep(InfoSecs);
-	fclose(fd);		/* close the temp file */
-	scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+	fclose(fd);		 /* Close the temp file. */
+	scrollok(stdscr, FALSE); /* Stop scrolling.	 */
 	goto cleanup;
     }
     fprintf(fd, "%s\n", user_input);
@@ -127,20 +154,26 @@ PUBLIC char *LYNewsPost ARGS2(
 	/*
 	 *  Add the default subject.
 	 */
-	while (isspace(*cp))
+	while (isspace(*cp)) {
 	    cp++;
-	if (strncasecomp(cp, "Re:", 3))
+	}
+	if (strncasecomp(cp, "Re:", 3)) {
             strcat(user_input, "Re: ");
+	    cp += 3;
+	    while (isspace(*cp)) {
+		cp++;
+	    }
+	}
         strcat(user_input, cp);
-	cp = NULL;
     }
+    cp = NULL;
     if (LYgetstr(user_input, VISIBLE,
 		 sizeof(user_input), NORECALL) < 0 ||
 	term_message) {
         _statusline(NEWS_POST_CANCELLED);
         sleep(InfoSecs);
-        fclose(fd);		/* close the temp file */
-	scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+        fclose(fd);		 /* Close the temp file. */
+	scrollok(stdscr, FALSE); /* Stop scrolling.	 */
         goto cleanup;
     }
     fprintf(fd,"%s\n",user_input);
@@ -155,17 +188,19 @@ PUBLIC char *LYNewsPost ARGS2(
     	       *org != '\0') {
 	StrAllocCat(cp, org);
 #ifndef VMS
-    } else if ((fp = fopen("/etc/organization", "r")) != 0) {
+    } else if ((fp = fopen("/etc/organization", "r")) != NULL) {
 	if (fgets(user_input, sizeof(user_input), fp) != NULL) {
-	    if ((cp = strchr(user_input, '\n')) != NULL)
-	        *cp = '\0';
-	    if (user_input[0] != '\0')
+	    if ((org = strchr(user_input, '\n')) != NULL) {
+	        *org = '\0';
+	    }
+	    if (user_input[0] != '\0') {
 	        StrAllocCat(cp, user_input);
+	    }
 	}
 	fclose(fp);
 #endif /* !VMS */
     }
-    strcpy(user_input, cp);
+    LYstrncpy(user_input, cp, (sizeof(user_input) - 16));
     FREE(cp); 
     addstr("\n\n Please provide or edit the Organization: header\n");
     if (LYgetstr(user_input, VISIBLE,
@@ -173,8 +208,8 @@ PUBLIC char *LYNewsPost ARGS2(
 	term_message) {
         _statusline(NEWS_POST_CANCELLED);
         sleep(InfoSecs);
-        fclose(fd);		/* close the temp file */
-	scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+        fclose(fd);		 /* Close the temp file. */
+	scrollok(stdscr, FALSE); /* Stop scrolling.	 */
         goto cleanup;
     }
     fprintf(fd,"%s\n",user_input);
@@ -205,11 +240,15 @@ PUBLIC char *LYNewsPost ARGS2(
 	    if (TOUPPER(c) == 'Y')
 	        /*
 		 *  The 1 will add the reply ">" in front of every line.
+		 *  We're assuming that if the display character set is
+		 *  Japanese and the document did not have a CJK charset,
+		 *  any non-EUC or non-SJIS 8-bit characters in it where
+		 *  converted to 7-bit equivalents. - FM
 		 */
 	        print_wwwfile_to_fd(fd, 1);
 	}
-	fclose(fd);
-	scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+	fclose(fd);		 /* Close the temp file. */
+	scrollok(stdscr, FALSE); /* Stop scrolling.	 */
 	if (term_message || c == 7 || c == 3)
 	    goto cleanup;
 
@@ -244,8 +283,8 @@ PUBLIC char *LYNewsPost ARGS2(
 	    term_message) {
 	    _statusline(NEWS_POST_CANCELLED);
 	    sleep(InfoSecs);
-	    fclose(fd);	/* close the temp file */
-	    scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+	    fclose(fd);			/* Close the temp file.	*/
+	    scrollok(stdscr, FALSE);	/* Stop scrolling.	*/
 	    goto cleanup;
 	}
 	while (!STREQ(user_input,".") && !term_message) { 
@@ -256,14 +295,14 @@ PUBLIC char *LYNewsPost ARGS2(
 	       		 sizeof(user_input), NORECALL) < 0) {
 	        _statusline(NEWS_POST_CANCELLED);
 	        sleep(InfoSecs);
-	        fclose(fd);		/* close the temp file */
-		scrollok(stdscr,FALSE);	/* Stop scrolling.    */
+	        fclose(fd);		 /* Close the temp file. */
+		scrollok(stdscr, FALSE); /* Stop scrolling.	 */
 	        goto cleanup;
 	    }
  	}
 	fprintf(fd, "\n");
-	fclose(fd);		/* close the temp file */
-	scrollok(stdscr,FALSE);  /* stop scrolling */
+	fclose(fd);		 /* Close the temp file. */
+	scrollok(stdscr, FALSE); /* Stop scrolling.	 */
     }
 
     /*
@@ -302,8 +341,40 @@ PUBLIC char *LYNewsPost ARGS2(
 	fclose(fp);
     }
     clear();  /* clear the screen */
-    StrAllocCopy(postfile, my_tempfile);
-    if (!followup)
+
+    /*
+     *  If we are using a Japanese display character
+     *  set, convert the contents of the temp file to
+     *  JIS (nothing should change if it does not, in
+     *  fact, contain EUC or SJIS di-bytes).  Otherwise,
+     *  use the temp file as is. - FM
+     */
+    if (CJKfile[0] != '\0') {
+	if ((fd = fopen(my_tempfile, "r")) != NULL) {
+	    while (fgets(user_input, sizeof(user_input), fd) != NULL) {
+	        TO_JIS((unsigned char *)user_input,
+		       (unsigned char *)CJKinput);
+		fputs(CJKinput, fc);
+	    }
+	    fclose(fc);
+	    StrAllocCopy(postfile, CJKfile);
+	    fclose(fd);
+#ifdef VMS
+	    while (remove(my_tempfile) == 0)
+		; /* loop through all versions */
+#else
+	    remove(my_tempfile);
+#endif /* VMS */
+	    fd = fc;
+	    strcpy(my_tempfile, CJKfile);
+	    CJKfile[0] = '\0';
+	} else {
+	    StrAllocCopy(postfile, my_tempfile);
+	}
+    } else {
+	StrAllocCopy(postfile, my_tempfile);
+    }
+    if (!followup) {
         /*
 	 *  If it's not a followup, the current document
 	 *  most likely is the group listing, so force a
@@ -314,6 +385,7 @@ PUBLIC char *LYNewsPost ARGS2(
 	 *  group listing. - FM
 	 */
         LYforce_no_cache = TRUE;
+    }
     LYStatusLine = (LYlines - 1);
     statusline(POSTING_TO_NEWS);
     LYStatusLine = -1;
@@ -335,6 +407,15 @@ cleanup:
 	remove(my_tempfile);
 #endif /* VMS */
     }
+    if (CJKfile[0] != '\0') {
+#ifdef VMS
+	fclose(fc);
+        while (remove(CJKfile) == 0)
+	    ; /* loop through all versions */
+#else
+	remove(CJKfile);
+#endif /* VMS */
+    }
     FREE(NewsGroups);
 
     return(postfile);
diff --git a/src/LYOptions.c b/src/LYOptions.c
index b26ee2ad..774279d2 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -15,9 +15,25 @@
 #include "LYrcFile.h"
 #include "HTAlert.h"
 #include "LYBookmark.h"
+#include "GridText.h"
 
 #include "LYLeaks.h"
 
+#ifndef BOXVERT
+#ifdef ALT_CHAR_SET
+#define BOXVERT 0   /* use alt char set for popup window vertical borders */
+#else
+#define BOXVERT '*'	/* character for popup window vertical borders */
+#endif
+#endif
+#ifndef BOXHORI
+#ifdef ALT_CHAR_SET
+#define BOXHORI 0   /* use alt char set for popup window horizontal borders */
+#else
+#define BOXHORI '*'	/* character for popup window horizontal borders */
+#endif
+#endif
+
 #define FREE(x) if (x) {free(x); x = NULL;}
 
 #ifdef VMS
@@ -30,8 +46,18 @@
 
 BOOLEAN term_options;
 PRIVATE void terminate_options  PARAMS((int sig));
-PRIVATE int boolean_choice PARAMS((int status, int line,
-				   int column, char **choices));
+PRIVATE int boolean_choice PARAMS((
+	int		status,
+	int		line,
+	int		column,
+	char **		choices));
+PRIVATE int popup_choice PARAMS((
+	int		cur_choice,
+	int		line,
+	int		column,
+	char **		choices, 
+	int		i_length,
+	int		disabled));
 
 #define MAXCHOICES 10
 
@@ -41,7 +67,7 @@ PRIVATE void option_statusline ARGS1(
     /*
      *  Make sure we have a pointer to a string.
      */
-    if (text == 0)
+    if (text == NULL)
         return;
 
     /*
@@ -64,7 +90,9 @@ PUBLIC void options NOARGS
     int itmp;
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
     int response, ch;
-    /* if the user changes the display I need memory to put it in */
+    /*
+     *  If the user changes the display we need memory to put it in.
+     */
     char display_option[256]; 
 #ifndef VMS
     static char putenv_command[142];
@@ -72,6 +100,7 @@ PUBLIC void options NOARGS
     char *choices[MAXCHOICES];
     int CurrentCharSet = current_char_set;
     BOOLEAN CurrentRawMode = LYRawMode;
+    BOOLEAN AddValueAccepted = FALSE;
     
 #ifdef DIRED_SUPPORT
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
@@ -132,7 +161,7 @@ draw_options:
     addstr((LYMultiBookmarks ?
     	      (LYMBMAdvanced ? "ADVANCED"
 	      		     : "STANDARD")
-			     : "OFF"));
+			     : "OFF     "));
     move(L_HOME, B_BOOK);
     if (LYMultiBookmarks) {
         addstr("review/edit B)ookmarks files");
@@ -143,10 +172,10 @@ draw_options:
 
     move(L_FTPSTYPE, 5);
     addstr("F)TP sort criteria           : ");
-    addstr((HTfileSortMethod==FILE_BY_NAME ? "By Filename" :
-	   (HTfileSortMethod==FILE_BY_SIZE ? "By Size" : 
-	   (HTfileSortMethod==FILE_BY_TYPE ? "By Type" :
-	   				     "By Date"))));
+    addstr((HTfileSortMethod == FILE_BY_NAME ? "By Filename" :
+	   (HTfileSortMethod == FILE_BY_SIZE ? "By Size    " : 
+	   (HTfileSortMethod == FILE_BY_TYPE ? "By Type    " :
+	   				       "By Date    "))));
 
     move(L_MAIL_ADDRESS, 5);
     addstr("P)ersonal mail address       : ");
@@ -155,7 +184,7 @@ draw_options:
 
     move(L_SSEARCH, 5); 
     addstr("S)earching type              : ");
-    addstr(case_sensitive ? "CASE SENSITIVE" : "CASE INSENSITIVE");
+    addstr(case_sensitive ? "CASE SENSITIVE  " : "CASE INSENSITIVE");
 
     move(L_CHARSET, 5);
     addstr("display (C)haracter set      : "); 
@@ -163,7 +192,7 @@ draw_options:
     
     move(L_RAWMODE, 5);
     addstr("Raw 8-bit or CJK m(O)de      : ");
-    addstr(LYRawMode ? "ON" : "OFF");
+    addstr(LYRawMode ? "ON " : "OFF");
 
     move(L_LANGUAGE, 5);
     addstr("preferred document lan(G)uage: ");
@@ -175,24 +204,31 @@ draw_options:
 
     move(L_BOOL_A, B_VIKEYS);
     addstr("V)I keys: ");
-    addstr(vi_keys ? "ON" : "OFF");
+    addstr(vi_keys ? "ON " : "OFF");
     
     move(L_BOOL_A, B_EMACSKEYS);
     addstr("e(M)acs keys: ");
-    addstr(emacs_keys ? "ON" : "OFF");
+    addstr(emacs_keys ? "ON " : "OFF");
     
     move(L_BOOL_A, B_SHOW_DOTFILES);
     addstr("sho(W) dot files: ");
-    addstr((!no_dotfiles && show_dotfiles) ? "ON" : "OFF");
+    addstr((!no_dotfiles && show_dotfiles) ? "ON " : "OFF");
 
-    move(L_SELECT_POPUPS, 5);
+    move(L_BOOL_B, B_SELECT_POPUPS);
     addstr("popups for selec(T) fields   : ");
-    addstr(LYSelectPopups ? "ON" : "OFF");
+    addstr(LYSelectPopups ? "ON " : "OFF");
+
+    move(L_BOOL_B, B_SHOW_CURSOR);
+    addstr("show cursor (@) : ");
+    addstr(LYShowCursor ? "ON " : "OFF");
 
-    move(L_KEYPAD, 5); 
-    addstr("K)eypad mode                 : "); 
-    addstr((keypad_mode == NUMBERS_AS_ARROWS) ? "Numbers act as arrows" : 
-						"Links are numbered");
+    move(L_KEYPAD, 5);
+    addstr("K)eypad mode                 : ");
+    addstr((keypad_mode == NUMBERS_AS_ARROWS) ?
+				"Numbers act as arrows             " :
+	 ((keypad_mode == LINKS_ARE_NUMBERED) ?
+				"Links are numbered                " :
+				"Links and form fields are numbered"));
 
     move(L_LINEED, 5);
     addstr("li(N)e edit style            : ");
@@ -201,16 +237,16 @@ draw_options:
 #ifdef DIRED_SUPPORT
     move(L_DIRED, 5);
     addstr("l(I)st directory style       : ");
-    addstr((dir_list_style == FILES_FIRST) ? "Files first          " :
-	  ((dir_list_style == MIXED_STYLE) ? "Mixed style          " : 
-					     "Directories first    "));
+    addstr((dir_list_style == FILES_FIRST) ? "Files first      " :
+	  ((dir_list_style == MIXED_STYLE) ? "Mixed style      " : 
+					     "Directories first"));
 #endif /* DIRED_SUPPORT */
 
     move(L_USER_MODE, 5);
     addstr("U)ser mode                   : ");
-    addstr(  (user_mode == NOVICE_MODE) ? "Novice" : 
+    addstr(  (user_mode == NOVICE_MODE) ? "Novice      " : 
       ((user_mode == INTERMEDIATE_MODE) ? "Intermediate" :
-					  "Advanced"));
+					  "Advanced    "));
 
     move(L_USER_AGENT, 5);
     addstr("user (A)gent                 : ");
@@ -220,12 +256,12 @@ draw_options:
     move(L_EXEC, 5);
     addstr("local e(X)ecution links      : ");
 #ifndef NEVER_ALLOW_REMOTE_EXEC
-    addstr(		  local_exec ? "ALWAYS ON" :
+    addstr(		  local_exec ? "ALWAYS ON           " :
           (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
-				       "ALWAYS OFF"));
+				       "ALWAYS OFF          "));
 #else
     addstr(local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
-				       "ALWAYS OFF");
+				       "ALWAYS OFF          ");
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
@@ -252,121 +288,124 @@ draw_options:
     addstr(TO_RETURN_SEGMENT);
 
     while (TOUPPER(response) != 'R' &&
-    	   !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
+	   !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
            response != '>' && !term_options &&
 	   response != 7 &&  response != 3) {
+	if (AddValueAccepted == TRUE) {
+	    option_statusline(VALUE_ACCEPTED);
+	    AddValueAccepted = FALSE;
+	}
+	move((LYlines - 2), 0);
+	lynx_start_prompt_color ();
+	addstr(COMMAND_PROMPT);
+	lynx_stop_prompt_color ();
 
-           move(LYlines-2, 0);
-           lynx_start_prompt_color ();
-	   addstr(COMMAND_PROMPT);
-           lynx_stop_prompt_color ();
-
-	   refresh();
-           response = LYgetch();
-	   if (term_options || response == 7 || response == 3)
-	       response = 'R';
-	   if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
-	       clearok(curscr, TRUE);
-	       goto draw_options;
-	   }
-	   switch (response) {
-	 	case 'e':  /* change the editor */
-		case 'E':
-	                if (no_editor) {
-			    option_statusline(EDIT_DISABLED);
-	                } else if (system_editor ) {
-			    option_statusline(EDITOR_LOCKED);
-			} else {
-			    if (editor && *editor)
-			        strcpy(display_option, editor);
-			    else {  /* clear the NONE */
-				move(L_EDITOR, COL_OPTION_VALUES);
-				addstr("    ");
-			        *display_option = '\0';
-			    }
-			    option_statusline(ACCEPT_DATA);
-			    move(L_EDITOR, COL_OPTION_VALUES);  
-			    standout();
-			    ch = LYgetstr(display_option, VISIBLE,
-			    		  sizeof(display_option), NORECALL);
-			    standend();
-			    move(L_EDITOR, COL_OPTION_VALUES);
-			    if (term_options || ch == -1) {
-			        addstr((editor && *editor) ?
-						    editor : "NONE");
-			    } else if (*display_option == '\0') {
-				FREE(editor);
-				addstr("NONE");
-			    } else {
-			        StrAllocCopy(editor, display_option);
-				addstr(display_option);
-			    }
-			    clrtoeol();
-			    option_statusline(VALUE_ACCEPTED);
-			}
-			response = ' ';
-			break;
+	refresh();
+	response = LYgetch();
+	if (term_options || response == 7 || response == 3)
+	    response = 'R';
+	if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
+	    clearok(curscr, TRUE);
+	    goto draw_options;
+	}
+	switch (response) {
+	    case 'e':	/* Change the editor. */
+	    case 'E':
+	        if (no_editor) {
+		    option_statusline(EDIT_DISABLED);
+		} else if (system_editor ) {
+		    option_statusline(EDITOR_LOCKED);
+		} else {
+		    if (editor && *editor)
+			strcpy(display_option, editor);
+		    else {  /* clear the NONE */
+			move(L_EDITOR, COL_OPTION_VALUES);
+			addstr("    ");
+			*display_option = '\0';
+		    }
+		    option_statusline(ACCEPT_DATA);
+		    move(L_EDITOR, COL_OPTION_VALUES);  
+		    standout();
+		    ch = LYgetstr(display_option, VISIBLE,
+				  sizeof(display_option), NORECALL);
+		    standend();
+		    move(L_EDITOR, COL_OPTION_VALUES);
+		    if (term_options || ch == -1) {
+		        addstr((editor && *editor) ?
+					    editor : "NONE");
+		    } else if (*display_option == '\0') {
+			FREE(editor);
+			addstr("NONE");
+		    } else {
+		        StrAllocCopy(editor, display_option);
+			addstr(display_option);
+		    }
+		    clrtoeol();
+		    option_statusline(VALUE_ACCEPTED);
+		}
+		response = ' ';
+		break;
 
-		case 'd':  /* change the display */
-		case 'D':
-			if (display && *display) {
-			    strcpy(display_option, display);
-			} else {  /* clear the NONE */
-			    move(L_DISPLAY, COL_OPTION_VALUES);
-			    addstr("    ");
-			    *display_option = '\0';
-			}
-			option_statusline(ACCEPT_DATA);
-	                move(L_DISPLAY, COL_OPTION_VALUES);
-			standout();
-			ch = LYgetstr(display_option, VISIBLE,
-				      sizeof(display_option), NORECALL);
-			standend();
-	                move(L_DISPLAY, COL_OPTION_VALUES);
-			if ((term_options || ch == -1) ||
-			    (display != NULL &&
+	    case 'd':	/* Change the display. */
+	    case 'D':
+		if (display && *display) {
+		    strcpy(display_option, display);
+		} else {  /* clear the NONE */
+		    move(L_DISPLAY, COL_OPTION_VALUES);
+		    addstr("    ");
+		    *display_option = '\0';
+		}
+		option_statusline(ACCEPT_DATA);
+		move(L_DISPLAY, COL_OPTION_VALUES);
+		standout();
+		ch = LYgetstr(display_option, VISIBLE,
+			      sizeof(display_option), NORECALL);
+		standend();
+		move(L_DISPLAY, COL_OPTION_VALUES);
+		if ((term_options || ch == -1) ||
+		    (display != NULL &&
 #ifdef VMS
-			     0 == strcasecomp(display, display_option)))
+		     !strcasecomp(display, display_option)))
 #else
-			     0 == strcmp(display, display_option)))
+		     !strcmp(display, display_option)))
 #endif /* VMS */
-			{
-			    /*
-			     *  Cancelled, or a non-NULL display string
-			     *  wasn't changed. - FM
-			     */
-			    addstr((display && *display) ? display : "NONE");
-			    clrtoeol();
-			    option_statusline(VALUE_ACCEPTED);
-			    response = ' ';
-			    break;
-			} else if (*display_option == '\0') {
-			    if ((display == NULL) ||
-			        (display != NULL && *display == '\0')) {
-				/*
-				 *  NULL or zero-length display string
-				 *  wasn't changed. - FM
-				 */
-			        addstr("NONE");
-				clrtoeol();
-				option_statusline(VALUE_ACCEPTED);
-				response = ' ';
-				break;
-			    }
-			}
+		{
+		    /*
+		     *  Cancelled, or a non-NULL display string
+		     *  wasn't changed. - FM
+		     */
+		    addstr((display && *display) ? display : "NONE");
+		    clrtoeol();
+		    option_statusline(VALUE_ACCEPTED);
+		    response = ' ';
+		    break;
+		} else if (*display_option == '\0') {
+		    if ((display == NULL) ||
+		        (display != NULL && *display == '\0')) {
 			/*
-			 *  Set the new DISPLAY variable. - FM
+			 *  NULL or zero-length display string
+			 *  wasn't changed. - FM
 			 */
+		        addstr("NONE");
+			clrtoeol();
+			option_statusline(VALUE_ACCEPTED);
+			response = ' ';
+			break;
+		    }
+		}
+		/*
+		 *  Set the new DISPLAY variable. - FM
+		 */
 #ifdef VMS
-			{
-			    int i;
-			    for (i = 0; display_option[i]; i++)
-			        display_option[i] = TOUPPER(display_option[i]);
-			    Define_VMSLogical(DISPLAY, display_option);
-			}
+		{
+		    int i;
+		    for (i = 0; display_option[i]; i++)
+		        display_option[i] = TOUPPER(display_option[i]);
+		    Define_VMSLogical(DISPLAY, display_option);
+		}
 #else
-			sprintf(putenv_command, "DISPLAY=%s", display_option);
-			putenv(putenv_command);
+		sprintf(putenv_command, "DISPLAY=%s", display_option);
+		putenv(putenv_command);
 #endif /* VMS */
 			if ((display = getenv(DISPLAY)) != NULL &&
 			    *display == '\0') {
@@ -396,7 +435,7 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'l':
+		case 'l':	/* Change multibookmarks option. */
 		case 'L':
 			if (LYMBMBlocked) {
 			    option_statusline(MULTIBOOKMARKS_DISALLOWED);
@@ -410,20 +449,38 @@ draw_options:
 			choices[2] = NULL;
 			StrAllocCopy(choices[2],"ADVANCED");
 			choices[3] = NULL;
-			LYMultiBookmarks = boolean_choice(LYMultiBookmarks *
-                                                          (1 + LYMBMAdvanced),
+		if (!LYSelectPopups) {
+		    LYMultiBookmarks = boolean_choice((LYMultiBookmarks *
+						       (1 + LYMBMAdvanced)),
                                                           L_HOME, C_MULTI,
                                                           choices);
-			FREE(choices[0]);
-			FREE(choices[1]);
-			FREE(choices[2]);
+		} else {
+		    LYMultiBookmarks = popup_choice((LYMultiBookmarks *
+						     (1 + LYMBMAdvanced)),
+						    L_HOME, (C_MULTI - 1),
+						    choices,
+						    3, FALSE);
+		}
                         if (LYMultiBookmarks == 2) {
                             LYMultiBookmarks = TRUE;
                             LYMBMAdvanced = TRUE;
                         } else {
                             LYMBMAdvanced = FALSE;
                         }
-			
+#if defined(VMS) || defined(USE_SLANG)
+		if (LYSelectPopups) {
+		    move(L_HOME, C_MULTI);
+		    clrtoeol();
+		    addstr(choices[(LYMultiBookmarks * (1 + LYMBMAdvanced))]);
+		}
+#endif /* VMS || USE_SLANG */
+		FREE(choices[0]);
+		FREE(choices[1]);
+		FREE(choices[2]);
+#if !defined(VMS) && !defined(USE_SLANG)
+		if (!LYSelectPopups)
+#endif /* !VMS && !USE_SLANG */
+		{
 			move(L_HOME, B_BOOK);
 			clrtoeol();
     			if (LYMultiBookmarks) {
@@ -433,13 +490,27 @@ draw_options:
 			    addstr((bookmark_page && *bookmark_page) ?
 			    			       bookmark_page : "NONE");
     			}
+		}
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 
-		case 'b':  /* change the bookmark page location */
+		case 'b':	/* Change the bookmark page location. */
 		case 'B':
-			/* anonymous users should not be allowed to
-			 * change the bookmark page
+			/*
+			 *  Anonymous users should not be allowed to
+			 *  change the bookmark page.
 			 */
 			if (!no_bookmark) {
 			    if (LYMultiBookmarks) {
@@ -447,9 +518,9 @@ draw_options:
 				signal(SIGINT, terminate_options);
 				goto draw_options;
 			    }
-			    if (bookmark_page && *bookmark_page)
+		    if (bookmark_page && *bookmark_page) {
 			        strcpy(display_option, bookmark_page);
-			    else {  /* clear the NONE */
+		    } else {  /* clear the NONE */
 				move(L_HOME, C_DEFAULT);
 				clrtoeol();
 			        *display_option = '\0';
@@ -487,9 +558,11 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'f':
-		case 'F':
-                        /* copy strings into choice array */
+		case 'f':	/* Change ftp directory sorting. */
+		case 'F':	/*  (also local for non-DIRED)   */
+                        /*
+			 *  Copy strings into choice array.
+			 */
                         choices[0] = NULL;
                         StrAllocCopy(choices[0],"By Filename");
                         choices[1] = NULL;
@@ -499,19 +572,45 @@ draw_options:
                         choices[3] = NULL;
                         StrAllocCopy(choices[3],"By Date    ");
                         choices[4] = NULL;
+		if (!LYSelectPopups) {
                         HTfileSortMethod = boolean_choice(HTfileSortMethod,
-                                               L_FTPSTYPE, -1, choices);
+						      L_FTPSTYPE, -1,
+						      choices);
+		} else {
+		    HTfileSortMethod = popup_choice(HTfileSortMethod,
+						    L_FTPSTYPE, -1,
+						    choices,
+						    4, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_FTPSTYPE, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(choices[HTfileSortMethod]);
+#endif /* VMS || USE_SLANG */
+		}
                         FREE(choices[0]);
                         FREE(choices[1]);
                         FREE(choices[2]);
+                        FREE(choices[3]);
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
                         break;
 
-		case 'p':  /* change personal mail address for From headers */
+		case 'p': /* Change personal mail address for From headers. */
 		case 'P':
-			if (personal_mail_address && *personal_mail_address)
+		if (personal_mail_address && *personal_mail_address) {
 			    strcpy(display_option, personal_mail_address);
-			else {  /* clear the NONE */
+		} else {  /* clear the NONE */
 			    move(L_MAIL_ADDRESS, COL_OPTION_VALUES);
 			    addstr("    ");
 			    *display_option = '\0';
@@ -539,9 +638,11 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 's':
+		case 's':	/* Change case sentitivity for searches. */
 		case 'S':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0],"CASE INSENSITIVE");
 			choices[1] = NULL;
@@ -554,10 +655,23 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'c':
+		case 'c':	/* Change charset setting. */
 		case 'C':
+		if (!LYSelectPopups) {
 			current_char_set = boolean_choice(current_char_set,
-			    		L_CHARSET, -1, LYchar_set_names);
+		    				      L_CHARSET, -1,
+						      LYchar_set_names);
+		} else {
+		    current_char_set = popup_choice(current_char_set,
+						    L_CHARSET, -1,
+						    LYchar_set_names,
+						    0, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_CHARSET, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(LYchar_set_names[current_char_set]);
+#endif /* VMS || USE_SLANG */
+		}
 			/*
 			 *  Set the raw 8-bit or CJK mode defaults and
 			 *  character set if changed. - FM
@@ -568,30 +682,47 @@ draw_options:
 			    HTMLUseCharacterSet(current_char_set);
 			    CurrentCharSet = current_char_set;
 			    CurrentRawMode = LYRawMode;
+#if !defined(VMS) && !defined(USE_SLANG)
+		    if (!LYSelectPopups)
+#endif /* !VMS && !USE_SLANG */
+		    {
 			    move(L_RAWMODE, COL_OPTION_VALUES);
 			    clrtoeol();
 			    addstr(LYRawMode ? "ON " : "OFF");
 			}
+		}
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 
-		case 'o':
+		case 'o':	/* Change raw mode setting. */
 		case 'O':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0], "OFF");
 			choices[1] = NULL;
 			StrAllocCopy(choices[1], "ON ");
 			choices[2] = NULL;
-			LYRawMode = boolean_choice(LYRawMode,
-						   L_RAWMODE, -1, choices);
+		LYRawMode = boolean_choice(LYRawMode, L_RAWMODE, -1, choices);
 			/*
 			 *  Set the LYUseDefaultRawMode value and character
 			 *  handling if LYRawMode was changed. - FM
 			 */
 			if (CurrentRawMode != LYRawMode) {
-			    HTMLSetUseDefaultRawMode(current_char_set,
-			    			     LYRawMode);
+		    HTMLSetUseDefaultRawMode(current_char_set, LYRawMode);
 			    HTMLSetCharacterHandling(current_char_set);
 			    CurrentRawMode = LYRawMode;
 			}
@@ -600,11 +731,11 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'g':  /* change language preference */
+		case 'g':	/* Change language preference. */
 		case 'G':
-			if (language && *language)
+		if (language && *language) {
 			    strcpy(display_option, language);
-			else {  /* clear the NONE */
+		} else {  /* clear the NONE */
 			    move(L_LANGUAGE, COL_OPTION_VALUES);
 			    addstr("    ");
 			    *display_option = '\0';
@@ -631,11 +762,11 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'h':  /* change character set preference */
+		case 'h':	/* Change charset preference. */
 		case 'H':
-			if (pref_charset && *pref_charset)
+		if (pref_charset && *pref_charset) {
 			    strcpy(display_option, pref_charset);
-			else {  /* clear the NONE */
+		} else {  /* clear the NONE */
 			    move(L_PREF_CHARSET, COL_OPTION_VALUES);
 			    addstr("    ");
 			    *display_option = '\0';
@@ -662,9 +793,11 @@ draw_options:
 			response = ' ';
 			break;
 
-		case 'v':
+		case 'v':	/* Change VI keys setting. */
 		case 'V':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0],"OFF");
 			choices[1] = NULL;
@@ -673,18 +806,21 @@ draw_options:
 			vi_keys = boolean_choice(vi_keys,
 						 L_BOOL_A, C_VIKEYS,
 						 choices);
-			if (vi_keys)
+		if (vi_keys) {
                             set_vi_keys();
-                        else
+		} else {
                             reset_vi_keys();
+		}
 			FREE(choices[0]);
 			FREE(choices[1]);
 			response = ' ';
 			break;
 
-		case 'M':
+		case 'M':	/* Change emacs keys setting. */
 		case 'm':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0],"OFF");
 			choices[1] = NULL;
@@ -693,21 +829,24 @@ draw_options:
 			emacs_keys = boolean_choice(emacs_keys,
 						    L_BOOL_A, C_EMACSKEYS,
 						    choices);
-                        if (emacs_keys)
+		if (emacs_keys) {
                             set_emacs_keys();
-                        else
+		} else {
                             reset_emacs_keys();
+		}
 			FREE(choices[0]);
 			FREE(choices[1]);
 			response = ' ';
 			break;
 
-		case 'W':
+		case 'W':	/* Change show dotfiles setting. */
 		case 'w':
 			   if (no_dotfiles) {
 			       option_statusline(DOTFILE_ACCESS_DISABLED);
 			   } else {
-			       /* copy strings into choice array */
+			       /*
+			        *  Copy strings into choice array.
+				*/
 			       choices[0] = NULL;
 			       StrAllocCopy(choices[0],"OFF");
 			       choices[1] = NULL;
@@ -723,52 +862,134 @@ draw_options:
 			   response = ' ';
 			   break;
 
-		case 't':
+		case 't':	/* Change select popups setting. */
 		case 'T':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0], "OFF");
 			choices[1] = NULL;
 			StrAllocCopy(choices[1], "ON ");
 			choices[2] = NULL;
 			LYSelectPopups = boolean_choice(LYSelectPopups,
-							L_SELECT_POPUPS, -1,
+							L_BOOL_B,
+							C_SELECT_POPUPS,
 							choices);
 			FREE(choices[0]);
 			FREE(choices[1]);
 			response = ' ';
 			break;
 
-		case 'k':
+		case '@':	/* Change show cursor setting. */
+			/*
+			 *  Copy strings into choice array.
+			 */
+			choices[0] = NULL;
+			StrAllocCopy(choices[0], "OFF");
+			choices[1] = NULL;
+			StrAllocCopy(choices[1], "ON ");
+			choices[2] = NULL;
+			LYShowCursor = boolean_choice(LYShowCursor,
+						      L_BOOL_B,
+						      C_SHOW_CURSOR,
+						      choices);
+			FREE(choices[0]);
+			FREE(choices[1]);
+			response = ' ';
+			break;
+
+		case 'k':	/* Change keypad mode. */
 		case 'K':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
-			StrAllocCopy(choices[0],"Numbers act as arrows");
+			StrAllocCopy(choices[0],
+				     "Numbers act as arrows             ");
 			choices[1] = NULL;
-			StrAllocCopy(choices[1],"Links are numbered   ");
+			StrAllocCopy(choices[1],
+				     "Links are numbered                ");
 			choices[2] = NULL;
+			StrAllocCopy(choices[2],
+				     "Links and form fields are numbered");
+			choices[3] = NULL;
+		if (!LYSelectPopups) {
 			keypad_mode = boolean_choice(keypad_mode,
-			       			     L_KEYPAD, -1, choices);
-                        if (keypad_mode == NUMBERS_AS_ARROWS)
+						 L_KEYPAD, -1,
+						 choices);
+		} else {
+		    keypad_mode = popup_choice(keypad_mode,
+					       L_KEYPAD, -1,
+					       choices,
+					       3, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_KEYPAD, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(choices[keypad_mode]);
+#endif /* VMS || USE_SLANG */
+		}
+		if (keypad_mode == NUMBERS_AS_ARROWS) {
                             set_numbers_as_arrows();
-                        else
+		} else {
                             reset_numbers_as_arrows();
+		}
 			FREE(choices[0]);
 			FREE(choices[1]);
+			FREE(choices[2]);
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 
-		case 'n':
+		case 'n':	/* Change line editor key bindings. */
 		case 'N':
+		if (!LYSelectPopups) {
 			current_lineedit = boolean_choice(current_lineedit,
-			    		L_LINEED, -1, LYLineeditNames);
+						      L_LINEED, -1,
+						      LYLineeditNames);
+		} else {
+		    current_lineedit = popup_choice(current_lineedit,
+						    L_LINEED, -1,
+						    LYLineeditNames,
+						    0, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_LINEED, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(LYLineeditNames[current_lineedit]);
+#endif /* VMS || USE_SLANG */
+		}
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 
 #ifdef DIRED_SUPPORT
-		case 'i':
+		case 'i':	/* Change local directory sorting. */
 		case 'I':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0],"Directories first");
 			choices[1] = NULL;
@@ -776,18 +997,45 @@ draw_options:
 			choices[2] = NULL;
 			StrAllocCopy(choices[2],"Mixed style      ");
 			choices[3] = NULL;
+		if (!LYSelectPopups) {
 			dir_list_style = boolean_choice(dir_list_style,
-							L_DIRED, -1, choices);
+						    L_DIRED, -1,
+						    choices);
+		} else {
+		    dir_list_style = popup_choice(dir_list_style,
+						  L_DIRED, -1,
+						  choices,
+						  3, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_DIRED, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(choices[dir_list_style]);
+#endif /* VMS || USE_SLANG */
+		}
 			FREE(choices[0]);
 			FREE(choices[1]);
 			FREE(choices[2]);
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 #endif /* DIRED_SUPPORT */
 
-		case 'u':
+		case 'u':	/* Change user mode. */
 		case 'U':
-			/* copy strings into choice array */
+			/*
+			 *  Copy strings into choice array.
+			 */
 			choices[0] = NULL;
 			StrAllocCopy(choices[0],"Novice      ");
 			choices[1] = NULL;
@@ -795,24 +1043,50 @@ draw_options:
 			choices[2] = NULL;
 			StrAllocCopy(choices[2],"Advanced    ");
 			choices[3] = NULL;
+		if (!LYSelectPopups) {
 			user_mode = boolean_choice(user_mode,
-						   L_USER_MODE, -1, choices);
+					       L_USER_MODE, -1,
+					       choices);
+		} else {
+		    user_mode = popup_choice(user_mode,
+					     L_USER_MODE, -1,
+					     choices,
+					     3, FALSE);
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_USER_MODE, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(choices[user_mode]);
+#endif /* VMS || USE_SLANG */
+		}
 			FREE(choices[0]);
 			FREE(choices[1]);
 			FREE(choices[2]);
-			if(user_mode == NOVICE_MODE)
-			   display_lines = LYlines-4;
-			else
+		if (user_mode == NOVICE_MODE) {
+		    display_lines = (LYlines - 4);
+		} else {
 			   display_lines = LYlines-2;
+		}
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 
-		case 'a':
+		case 'a':	/* Change user agent string. */
 		case 'A':
 			if (!no_useragent) {
-			    if (LYUserAgent && *LYUserAgent)
+		    if (LYUserAgent && *LYUserAgent) {
 			        strcpy(display_option, LYUserAgent);
-			    else {  /* clear the NONE */
+		    } else {  /* clear the NONE */
 				move(L_HOME, COL_OPTION_VALUES);
 				addstr("    ");
 			        *display_option = '\0';
@@ -852,22 +1126,29 @@ draw_options:
 			break;
 
 #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS
-		case 'x':  /* local exec */
+		case 'x':	/* Change local exec restriction. */
 		case 'X':
-			if (!exec_frozen) {
+		if (exec_frozen && !LYSelectPopups) {
+		    option_statusline(CHANGE_OF_SETTING_DISALLOWED);
+		    response = ' ';
+		    break;
+		}
 #ifndef NEVER_ALLOW_REMOTE_EXEC
 			    if (local_exec) {
 				itmp = 2;
-			    } else {
+		} else
 #else
 			  {
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
-			  	if (local_exec_on_local_files)
+		    if (local_exec_on_local_files) {
 				    itmp= 1;
-				else
+		    } else {
 				    itmp = 0;
 			   }
-			   /* copy strings into choice array */
+		}
+			   /*
+			    *  Copy strings into choice array.
+			    */
 			   choices[0] = NULL;
 			   StrAllocCopy(choices[0],"ALWAYS OFF          ");
 			   choices[1] = NULL;
@@ -877,57 +1158,79 @@ draw_options:
 			   StrAllocCopy(choices[2],"ALWAYS ON           ");
 			   choices[3] = NULL;
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
-			   itmp = boolean_choice(itmp, L_EXEC, -1, choices);
-  
+		if (!LYSelectPopups) {
+		    itmp = boolean_choice(itmp,
+					  L_EXEC, -1,
+					  choices);
+		} else {
+		    itmp = popup_choice(itmp,
+					L_EXEC, -1,
+					choices,
+					0, (exec_frozen ? TRUE : FALSE));
+#if defined(VMS) || defined(USE_SLANG)
+		    move(L_EXEC, COL_OPTION_VALUES);
+		    clrtoeol();
+		    addstr(choices[itmp]);
+#endif /* VMS || USE_SLANG */
+		}
 			   FREE(choices[0]);
 			   FREE(choices[1]);
 #ifndef NEVER_ALLOW_REMOTE_EXEC
 			   FREE(choices[2]);
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
+		if (!exec_frozen) {
 			   switch(itmp) {
 			      case 0:
 				  local_exec = FALSE;
 				  local_exec_on_local_files = FALSE;
-				  response = ' ';
 				  break;
 			      case 1:
 				  local_exec = FALSE;
 				  local_exec_on_local_files = TRUE;
-				  response = ' ';
 				  break;
 #ifndef NEVER_ALLOW_REMOTE_EXEC
 			      case 2:
 				  local_exec = TRUE;
 				  local_exec_on_local_files = FALSE;
-				  response = ' ';
 				  break;
 #endif /* NEVER_ALLOW_REMOTE_EXEC */
 			  } /* end switch */
-			} else {
-			   option_statusline(CHANGE_OF_SETTING_DISALLOWED);
 			}
 			response = ' ';
+		if (LYSelectPopups) {
+#if !defined(VMS) || defined(USE_SLANG)
+		    if (exec_frozen || term_options) {
+		        term_options = FALSE;
+	            } else {
+		        AddValueAccepted = TRUE;
+		    }
+		    goto draw_options;
+#else
+		    term_options = FALSE;
+#endif /* !VMS || USE_SLANG */
+		}
 			break;
 #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */
 
-		case '>':
+		case '>':	/* Save current options to RC file. */
                         if (!no_option_save) {
                             option_statusline(SAVING_OPTIONS);
-                            if(save_rc())
+		    if (save_rc()) {
 				option_statusline(OPTIONS_SAVED);
-			    else 
+		    } else {
 				HTAlert(OPTIONS_NOT_SAVED);
-
+		    }
                         } else {
 			    option_statusline(R_TO_RETURN_TO_LYNX);
-			    /* change response so that we don't exit
-			     * the options menu 
+			    /*
+			     *  Change response so that we don't exit
+			     *  the options menu.
 			     */
 			    response = ' ';
 			} 
 			break;
 
-		case 'r':
+		case 'r':	/* Return to document (quit options menu). */
 		case 'R':
 			break;
 
@@ -949,17 +1252,25 @@ draw_options:
  *  and return it.
  */
 PRIVATE int boolean_choice ARGS4(
-	int,		status,
+	int,		cur_choice,
 	int,		line,
 	int,		column,
 	char **,	choices)
 {
     int response = 0;
-    int respcmd;
+    int cmd = 0;
     int number = 0;
     int col = (column >= 0 ? column : COL_OPTION_VALUES);
+    int orig_choice = cur_choice;
+#ifdef VMS
+    extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
+#endif /* VMS */
 	
-    for (; choices[number] != NULL; number++)
+    /*
+     *  Get the number of choices and then make
+     *  number zero-based.
+     */
+    for (number = 0; choices[number] != NULL; number++)
 	;  /* empty loop body */
 
     number--;
@@ -970,11 +1281,13 @@ PRIVATE int boolean_choice ARGS4(
     option_statusline(ANY_KEY_CHANGE_RET_ACCEPT);
 
     /*
-     *  Highlight the current selection.
+     *  Highlight the current choice.
      */
     move(line, col);
     standout();
-    addstr(choices[status]);
+    addstr(choices[cur_choice]);
+    if (LYShowCursor)
+	move(line, (col - 1));
     refresh();
 
     /*
@@ -983,37 +1296,63 @@ PRIVATE int boolean_choice ARGS4(
      *  it can be changed, until the user accepts
      *  the current choice.
      */
+    term_options = FALSE;
     while (1) {
 	move(line, col);
+	if (term_options == FALSE) {
 	response = LYgetch();
-	if (term_options || response == 7 || response == 3)
+	}
+	if (term_options || response == 7 || response == 3) {
+	     /*
+	      *  Control-C or Control-G.
+	      */
+	    response = '\n';
+	    term_options = TRUE;
+	    cur_choice = orig_choice;
+	}
+#ifdef VMS
+	if (HadVMSInterrupt) {
+	    HadVMSInterrupt = FALSE;
 	    response = '\n';
-	if (response != '\n' && response != '\r') {
-	     respcmd = keymap[response+1];
-#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
-                     /* does this make sense here? dunno.. - kw */
-	     if (!respcmd && override[response+1] && !no_dired_support)
-	       respcmd = override[response+1];
-#endif /* DIRED_SUPPORT && OK_OVERRIDE */
-	     switch (respcmd) {
+	    term_options = TRUE;
+	    cur_choice = orig_choice;
+	}
+#endif /* VMS */
+	if ((response != '\n' && response != '\r') &&
+	    (cmd = keymap[response+1]) != LYK_ACTIVATE) {
+	     switch (cmd) {
+		case LYK_HOME:
+		    cur_choice = 0;
+		    break;
+
+		case LYK_END:
+		    cur_choice = number;
+		    break;
+
+		case LYK_REFRESH:
+		    clearok(curscr, TRUE);
+		    refresh();
+		    break;
+
+		case LYK_QUIT:
+		case LYK_ABORT:
+		case LYK_PREV_DOC:
+		    cur_choice = orig_choice;
+		    term_options = TRUE;
+		    break;
+
 	     case LYK_PREV_PAGE:
+		case LYK_UP_HALF:
 	     case LYK_UP_TWO:
 	     case LYK_PREV_LINK:
 	     case LYK_UP_LINK:
 	     case LYK_LEFT_LINK:
-	     case LYK_PREV_DOC:
-		if(status == 0)
-		    status = number;  /* go back to end */
+		if(cur_choice == 0)
+		    cur_choice = number;  /* go back to end */
 		else
-		    status--;
-		break;
-	     case LYK_END:
-		status = number;
+		    cur_choice--;
 		break;
 		
-	     case LYK_HOME:
-		status = 0;
-		break;
 	     case LYK_1:
 	     case LYK_2:
 	     case LYK_3:
@@ -1023,28 +1362,37 @@ PRIVATE int boolean_choice ARGS4(
 	     case LYK_7:
 	     case LYK_8:
 	     case LYK_9:
-	       if((respcmd - LYK_1 + 1) <= number) {
-		 status = respcmd -LYK_1 + 1;
+	       if((cmd - LYK_1 + 1) <= number) {
+		 cur_choice = cmd -LYK_1 + 1;
 		 break;
 	       }  /* else fall through! */
 	     default:
-	    if (status == number)
-		status = 0;  /* go over the top and around */
+	    if (cur_choice == number)
+		cur_choice = 0;  /* go over the top and around */
 	    else
-		status++;
+		cur_choice++;
 	      }  /* end of switch */
-	    addstr(choices[status]);
+	    addstr(choices[cur_choice]);
+	    if (LYShowCursor)
+		move(line, (col - 1));
 	    refresh();
 	} else {
 	    /*
-	     *  Unhighlight selection.
+	     *  Unhighlight choice.
 	     */
 	    move(line, col);
 	    standend();
-	    addstr(choices[status]);
+	    addstr(choices[cur_choice]);
 
+	    if (term_options) {
+	        term_options = FALSE;
+		option_statusline(CANCELLED);
+		sleep(InfoSecs);
+		option_statusline("");
+	    } else {
 	    option_statusline(VALUE_ACCEPTED);
-	    return(status);
+	    }
+	    return(cur_choice);
 	}
     }
 }
@@ -1053,10 +1401,14 @@ PRIVATE void terminate_options ARGS1(
 	int,		sig)
 {
     term_options=TRUE;
-    /* Reassert the AST */
+    /*
+     *  Reassert the AST.
+     */
     signal(SIGINT, terminate_options);
 #ifdef VMS
-    /* refresh the screen to get rid of the "interrupt" message */
+    /*
+     *  Refresh the screen to get rid of the "interrupt" message.
+     */
     if (!dump_output_immediately) {
 	clearok(curscr, TRUE);
 	refresh();
@@ -1345,3 +1697,1035 @@ draw_bookmark_list:
     term_options = FALSE;
     signal(SIGINT, cleanup_sig);
 }
+
+/*
+**  This function prompts for a choice or page number.
+**  If a 'g' or 'p' suffix is included, that will be
+**  loaded into c.  Otherwise, c is zeroed. - FM
+*/
+PRIVATE int get_popup_choice_number ARGS1(
+	int *,		c)
+{
+    char temp[120];
+
+    /*
+     *  Load the c argument into the prompt buffer.
+     */
+    temp[0] = *c;
+    temp[1] = '\0';
+    option_statusline(OPTION_CHOICE_NUMBER);
+
+    /*
+     *  Get the number, possibly with a suffix, from the user.
+     */
+    if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 ||
+        *temp == 0 || term_options) {
+	option_statusline(CANCELLED);
+	sleep(InfoSecs);
+	*c = '\0';
+	term_options = FALSE;
+	return(0);
+    }
+
+    /*
+     *  If we had a 'g' or 'p' suffix, load it into c.
+     *  Otherwise, zero c.  Then return the number.
+     */
+    if (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL) {
+        *c = 'g';
+    } else if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) {
+        *c = 'p';
+    } else {
+        *c = '\0';
+    }
+    return(atoi(temp));
+}
+
+/*
+ *  This function offers the choices for values of an
+ *  option via a popup window which functions like
+ *  that for selection of options in a form. - FM
+ */
+PRIVATE int popup_choice ARGS6(
+	int,		cur_choice,
+	int,		line,
+	int,		column,
+	char **,	choices,
+	int,		i_length,
+	int,		disabled)
+{
+    int ly = line;
+    int lx = (column >= 0 ? column : (COL_OPTION_VALUES - 1));
+    int c = 0, cmd = 0, i = 0, j = 0;
+    int orig_choice = cur_choice;
+#ifndef USE_SLANG
+    WINDOW * form_window;
+#endif /* !USE_SLANG */
+    int num_choices = 0, top, bottom, length = -1, width = 0;
+    char ** Cptr = choices;
+    int window_offset = 0;
+    int DisplayLines = (LYlines - 2);
+    char Cnum[64];
+    int Lnum;
+    int npages;
+#ifdef VMS
+    extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
+#endif /* VMS */
+    static char prev_target[512]; 		/* Search string buffer */
+    static char prev_target_buffer[512];	/* Next search buffer */
+    static BOOL first = TRUE;
+    char *cp;
+    int ch = 0, recall;
+    int QueryTotal;
+    int QueryNum;
+    BOOLEAN FirstRecall = TRUE;
+    BOOLEAN ReDraw = FALSE;
+    int number;
+    char buffer[512];
+
+    /*
+     * Initialize the search string buffer. - FM
+     */
+    if (first) {
+	*prev_target_buffer = '\0';
+	first = FALSE;
+    }
+    *prev_target = '\0';
+    QueryTotal = (search_queries ? HTList_count(search_queries) : 0);
+    recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
+    QueryNum = QueryTotal;
+
+    /*
+     *  Count the number of choices to be displayed, where
+     *  num_choices ranges from 0 to n, and set width to the
+     *  longest choice string length.  Also set Lnum to the
+     *  length for the highest choice number, then decrement
+     *  num_choices so as to be zero-based.  The window width
+     *  will be based on the sum of width and Lnum. - FM
+     */
+    for (num_choices = 0; Cptr[num_choices] != NULL; num_choices++) {
+	if (strlen(Cptr[num_choices]) > width) {
+	    width = strlen(Cptr[num_choices]);
+	}
+    }
+    sprintf(Cnum, "%d: ", num_choices);
+    Lnum = strlen(Cnum);
+    num_choices--;
+
+    /*
+     *  Let's assume for the sake of sanity that ly is the number
+     *   corresponding to the line the option is on.
+     *  Let's also assume that cur_choice is the number of the
+     *   choice that should be initially selected, with 0 being
+     *   the first choice.
+     *  So what we have, is the top equal to the current screen line
+     *   subtracting the cur_choice + 1 (the one must be for the top
+     *   line we will draw in a box).  If the top goes under 0, then
+     *   consider it 0.
+     */
+    top = ly - (cur_choice + 1);
+    if (top < 0)
+	top = 0;
+
+    /*
+     *  Check and see if we need to put the i_length parameter up to
+     *  the number of real choices.
+     */
+    if (i_length < 1) {
+        i_length = num_choices;
+    } else {
+        /*
+	 *  Otherwise, it is really one number too high.
+	 */
+	i_length--;
+    }
+
+    /*
+     *  The bottom is the value of the top plus the number of choices
+     *  to view plus 3 (one for the top line, one for the bottom line,
+     *  and one to offset the 0 counted in the num_choices).
+     */
+    bottom = top + i_length + 3;
+
+    /*
+     *  Hmm...  If the bottom goes beyond the number of lines available,
+     */
+    if (bottom > DisplayLines) {
+        /*
+	 *  Position the window at the top if we have more
+	 *  choices than will fit in the window.
+	 */
+	if ((i_length + 3) > DisplayLines) {
+	    top = 0;
+            bottom = (top + (i_length + 3));
+	    if (bottom > DisplayLines)
+	        bottom = (DisplayLines + 1);
+	} else {
+	    /*
+	     *  Try to position the window so that the selected choice will
+	     *    appear where the choice box currently is positioned.
+	     *  It could end up too high, at this point, but we'll move it
+	     *    down latter, if that has happened.
+	     */
+	    top = (DisplayLines + 1) - (i_length + 3);
+	    bottom = (DisplayLines + 1);
+	}
+    }
+
+    /*
+     *  This is really fun, when the length is 4, it means 0 to 4, or 5.
+     */
+    length = (bottom - top) - 2;
+
+    /*
+     *  Move the window down if it's too high.
+     */
+    if (bottom < ly + 2) {
+        bottom = ly + 2;
+	if (bottom > DisplayLines + 1)
+	    bottom = DisplayLines + 1;
+	top = bottom - length - 2;
+    }
+
+    /*
+     *  Set up the overall window, including the boxing characters ('*'),
+     *  if it all fits.  Otherwise, set up the widest window possible. - FM
+     */
+#ifdef USE_SLANG
+    SLsmg_fill_region(top, lx - 1, bottom - top, (Lnum + width + 4), ' ');
+#else
+    if (!(form_window = newwin(bottom - top, (Lnum + width + 4),
+			       top, (lx - 1))) &&
+        !(form_window = newwin(bottom - top, 0, top, 0))) {
+	option_statusline(POPUP_FAILED);
+        return(orig_choice);
+    }
+    scrollok(form_window, TRUE);
+#endif /* USE_SLANG */
+
+    /*
+     *  Clear the command line and write
+     *  the popup statusline. - FM
+     */
+    move((LYlines - 2), 0);
+    clrtoeol();
+    if (disabled) {
+	option_statusline(CHOICE_LIST_UNM_MSG);
+    } else {
+	option_statusline(CHOICE_LIST_MESSAGE);
+    }
+
+    /*
+     *  Set up the window_offset for choices.
+     *   cur_choice ranges from 0...n
+     *   length ranges from 0...m
+     */
+    if (cur_choice >= length) {
+        window_offset = cur_choice - length + 1;
+    }
+
+    /*
+     *  Compute the number of popup window pages. - FM
+     */
+    npages = ((num_choices + 1) > length) ?
+		(((num_choices + 1) + (length - 1))/(length))
+					  : 1;
+/*
+ *  OH!  I LOVE GOTOs! hack hack hack
+ */
+redraw:
+    Cptr = choices;
+
+    /*
+     *  Display the boxed choices.
+     */
+    for (i = 0; i <= num_choices; i++) {
+        if (i >= window_offset && i - window_offset < length) {
+	    sprintf(Cnum, "%s%d: ",
+			   ((num_choices > 8 && i < 9) ?
+						   " " : ""),
+			   (i + 1));
+#ifdef USE_SLANG
+	    SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2));
+	    addstr(Cnum);
+	    SLsmg_write_nstring(Cptr[i], width);
+#else
+	    wmove(form_window, ((i + 1) - window_offset), 2);
+	    wclrtoeol(form_window);
+	    waddstr(form_window, Cnum);
+	    waddstr(form_window, Cptr[i]);
+#endif /* USE_SLANG */
+	}
+    }
+#ifdef USE_SLANG
+    SLsmg_draw_box(top, (lx - 1), (bottom - top), (Lnum + width + 4));
+#else
+#ifdef VMS
+    VMSbox(form_window, (bottom - top), (Lnum + width + 4));
+#else
+    box(form_window, BOXVERT, BOXHORI);
+#endif /* VMS */
+    wrefresh(form_window);
+#endif /* USE_SLANG */
+    Cptr = NULL;
+
+    /*
+     *  Loop on user input.
+     */
+    while (cmd != LYK_ACTIVATE) {
+        /*
+	 *  Unreverse cur choice.
+	 */
+	if (Cptr != NULL) {
+	    sprintf(Cnum, "%s%d: ",
+			  ((num_choices > 8 && i < 9) ?
+						  " " : ""),
+			  (i + 1));
+#ifdef USE_SLANG
+	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
+	    addstr(Cnum);
+	    SLsmg_write_nstring(Cptr[i], width);
+#else
+	    wmove(form_window, ((i + 1) - window_offset), 2);
+	    waddstr(form_window, Cnum);
+            waddstr(form_window, Cptr[i]);
+#endif /* USE_SLANG */
+	}
+	Cptr = choices;
+	i = cur_choice;
+	sprintf(Cnum, "%s%d: ",
+		      ((num_choices > 8 && i < 9) ?
+					      " " : ""),
+		      (i + 1));
+#ifdef USE_SLANG
+	SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
+	addstr(Cnum);
+	SLsmg_set_color(2);
+	SLsmg_write_nstring(Cptr[i], width);
+	SLsmg_set_color(0);
+	/*
+	 *  If LYShowCursor is ON, move the cursor to the left
+	 *  of the current choice, so that blind users, who are
+	 *  most likely to have LYShowCursor ON, will have it's
+	 *  string spoken or passed to the braille interface as
+	 *  each choice is made current.  Otherwise, move it to
+	 *  the bottom, right column of the screen, to "hide"
+	 *  the cursor as for the main document, and let sighted
+	 *  users rely on the current choice's highlighting or
+	 *  color without the distraction of a blinking cursor
+	 *  in the window. - FM
+	 */
+	if (LYShowCursor)
+	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 1));
+	else
+	    SLsmg_gotorc((LYlines - 1), (LYcols - 1));
+	SLsmg_refresh();
+#else
+	wmove(form_window, ((i + 1) - window_offset), 2);
+	waddstr(form_window, Cnum);
+	wstart_reverse(form_window);
+	waddstr(form_window, Cptr[i]);
+	wstop_reverse(form_window);
+	/*
+	 *  If LYShowCursor is ON, move the cursor to the left
+	 *  of the current choice, so that blind users, who are
+	 *  most likely to have LYShowCursor ON, will have it's
+	 *  string spoken or passed to the braille interface as
+	 *  each choice is made current.  Otherwise, leave it to
+	 *  the right of the current choice, since we can't move
+	 *  it out of the window, and let sighted users rely on
+	 *  the highlighting of the current choice without the
+	 *  distraction of a blinking cursor preceding it. - FM
+	 */
+	if (LYShowCursor)
+	    wmove(form_window, ((i + 1) - window_offset), 1);
+	wrefresh(form_window);
+#endif /* USE_SLANG  */
+
+	term_options = FALSE;
+	c = LYgetch();
+	if (term_options || c == 3 || c == 7) {
+	     /*
+	      *  Control-C or Control-G
+	      */
+	    cmd = LYK_QUIT;
+	} else {
+	    cmd = keymap[c+1];
+	}
+#ifdef VMS
+	if (HadVMSInterrupt) {
+	    HadVMSInterrupt = FALSE;
+	    cmd = LYK_QUIT;
+	}
+#endif /* VMS */
+
+        switch(cmd) {
+	    case LYK_F_LINK_NUM:
+		c = '\0';
+	    case LYK_1:
+	    case LYK_2:
+	    case LYK_3:
+	    case LYK_4:
+	    case LYK_5:
+	    case LYK_6:
+	    case LYK_7:
+	    case LYK_8:
+	    case LYK_9:
+		/*
+		 *  Get a number from the user, possibly with
+		 *  a 'g' or 'p' suffix (which will be loaded
+		 *  into c). - FM & LE
+		 */
+		number = get_popup_choice_number((int *)&c);
+
+		/*
+		 *  Check for a 'p' suffix. - FM
+		 */
+		if (c == 'p') {
+		    /*
+		     *  Treat 1 or less as the first page. - FM
+		     */
+		    if (number <= 1) {
+		        if (window_offset == 0) {
+			    option_statusline(ALREADY_AT_CHOICE_BEGIN);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				option_statusline(CHOICE_LIST_UNM_MSG);
+			    } else {
+				option_statusline(CHOICE_LIST_MESSAGE);
+			    }
+			    break;
+			}
+			window_offset = 0;
+			cur_choice = 0;
+			if (disabled) {
+			    option_statusline(CHOICE_LIST_UNM_MSG);
+			} else {
+			    option_statusline(CHOICE_LIST_MESSAGE);
+			}
+			goto redraw;
+		    }
+
+		    /*
+		     *  Treat a number equal to or greater than the
+		     *  number of pages as the last page. - FM
+		     */
+		    if (number >= npages) {
+		        if (window_offset >= ((num_choices - length) + 1)) {
+			    option_statusline(ALREADY_AT_CHOICE_END);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				option_statusline(CHOICE_LIST_UNM_MSG);
+			    } else {
+				option_statusline(CHOICE_LIST_MESSAGE);
+			    }
+			    break;
+			}
+			window_offset = ((npages - 1) * length);
+			if (window_offset > (num_choices - length)) {
+			    window_offset = (num_choices - length + 1);
+			}
+			if (cur_choice < window_offset)
+			    cur_choice = window_offset;
+			if (disabled) {
+			    option_statusline(CHOICE_LIST_UNM_MSG);
+   			} else {
+			    option_statusline(CHOICE_LIST_MESSAGE);
+			}
+			goto redraw;
+		    }
+
+		    /*
+		     *  We want an intermediate page. - FM
+		     */
+		    if (((number - 1) * length) == window_offset) {
+			sprintf(buffer, ALREADY_AT_CHOICE_PAGE, number);
+			option_statusline(buffer);
+			sleep(MessageSecs);
+			if (disabled) {
+			    option_statusline(CHOICE_LIST_UNM_MSG);
+			} else {
+			    option_statusline(CHOICE_LIST_MESSAGE);
+			}
+			break;
+		    }
+		    cur_choice = window_offset = ((number - 1) * length);
+		    if (disabled) {
+			option_statusline(CHOICE_LIST_UNM_MSG);
+   		    } else {
+			option_statusline(CHOICE_LIST_MESSAGE);
+		    }
+		    goto redraw;
+
+		}
+
+		/*
+		 *  Check for a positive number, which signifies
+		 *  that a choice should be sought. - FM
+		 */
+		if (number > 0) {
+		    /*
+		     *  Decrement the number so as to correspond
+		     *  with our cur_choice values. - FM
+		     */
+		    number--;
+
+		    /*
+		     *  If the number is in range and had no legal
+		     *  suffix, select the indicated choice. - FM
+		     */
+		    if (number <= num_choices && c == '\0') {
+			cur_choice = number;
+			cmd = LYK_ACTIVATE;
+			break;
+		    }
+
+		    /*
+		     *  Verify that we had a 'g' suffix,
+		     *  and act on the number. - FM
+		     */
+		    if (c == 'g') {
+			if (cur_choice == number) {
+			    /*
+			     *  The choice already is current. - FM
+			     */
+			    sprintf(buffer,
+			    	    CHOICE_ALREADY_CURRENT, (number + 1));
+			    option_statusline(buffer);
+			    sleep(MessageSecs);
+			    if (disabled) {
+				option_statusline(CHOICE_LIST_UNM_MSG);
+   			    } else {
+				option_statusline(CHOICE_LIST_MESSAGE);
+			    }
+			    break;
+			}
+
+			if (number <= num_choices) {
+			    /*
+			     *  The number is in range and had a 'g'
+			     *  suffix, so make it the current choice,
+			     *  scrolling if needed. - FM
+			     */
+			    j = (number - cur_choice);
+			    cur_choice = number;
+			    if ((j > 0) &&
+			        (cur_choice - window_offset) >= length) {
+				window_offset += j;
+				if (window_offset > (num_choices - length + 1))
+				    window_offset = (num_choices - length + 1);
+			    } else if ((cur_choice - window_offset) < 0) {
+				window_offset -= abs(j);
+				if (window_offset < 0)
+				    window_offset = 0;
+			    }
+			    if (disabled) {
+				option_statusline(CHOICE_LIST_UNM_MSG);
+   			    } else {
+				option_statusline(CHOICE_LIST_MESSAGE);
+			    }
+			    goto redraw;
+			}
+
+			/*
+			 *  Not in range. - FM
+			 */
+			option_statusline(BAD_CHOICE_NUM_ENTERED);
+			sleep(MessageSecs);
+		    }
+		}
+
+		/*
+		 *  Restore the popup statusline. - FM
+		 */
+		if (disabled) {
+		    option_statusline(CHOICE_LIST_UNM_MSG);
+   		} else {
+		    option_statusline(CHOICE_LIST_MESSAGE);
+		}
+		break;
+
+            case LYK_PREV_LINK:
+	    case LYK_UP_LINK:
+
+		if (cur_choice > 0)
+		    cur_choice--;
+
+		/*
+		 *  Scroll the window up if necessary.
+		 */
+		if ((cur_choice - window_offset) < 0) {
+		    window_offset--;
+		    goto redraw;
+		}
+                break;
+
+            case LYK_NEXT_LINK:
+	    case LYK_DOWN_LINK:
+		if (cur_choice < num_choices)
+                    cur_choice++;
+
+		/*
+		 *  Scroll the window down if necessary
+		 */
+		if ((cur_choice - window_offset) >= length) {
+		    window_offset++;
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_NEXT_PAGE:
+		/*
+		 *  Okay, are we on the last page of the choices list?
+		 *  If not then,
+		 */
+		if (window_offset != (num_choices - length + 1)) {
+		    /*
+		     *  Modify the current choice to not be a
+		     *  coordinate in the list, but a coordinate
+		     *  on the item selected in the window.
+		     */
+		    cur_choice -= window_offset;
+
+		    /*
+		     *  Page down the proper length for the list.
+		     *  If simply to far, back up.
+		     */
+		    window_offset += length;
+		    if (window_offset > (num_choices - length)) {
+		        window_offset = (num_choices - length + 1);
+		    }
+
+		    /*
+		     *  Readjust the current choice to be a choice
+		     *  list coordinate rather than window.
+		     *  Redraw this thing.
+		     */
+		    cur_choice += window_offset;
+		    goto redraw;
+		}
+		else if (cur_choice < num_choices) {
+		    /*
+		     *  Already on last page of the choice list so
+		     *  just redraw it with the last item selected.
+		     */
+		    cur_choice = num_choices;
+		}
+		break;
+
+	    case LYK_PREV_PAGE:
+		/*
+		 *  Are we on the first page of the choice list?
+		 *  If not then,
+		 */
+		if (window_offset != 0) {
+		    /*
+		     *  Modify the current choice to not be a choice
+		     *  list coordinate, but a window coordinate.
+		     */
+		    cur_choice -= window_offset;
+
+		    /*
+		     *  Page up the proper length.
+		     *  If too far, back up.
+		     */
+		    window_offset -= length;
+		    if (window_offset < 0) {
+		        window_offset = 0;
+		    }
+
+		    /*
+		     *  Readjust the current choice.
+		     */
+		    cur_choice += window_offset;
+		    goto redraw;
+		} else if (cur_choice > 0) {
+		    /*
+		     *  Already on the first page so just
+		     *  back up to the first item.
+		     */
+		    cur_choice = 0;
+		}
+		break;
+
+	    case LYK_HOME:
+	        cur_choice = 0;
+		if (window_offset > 0) {
+		    window_offset = 0;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_END:
+	        cur_choice = num_choices;
+		if (window_offset != (num_choices - length + 1)) {
+		    window_offset = (num_choices - length + 1);
+		    goto redraw;
+		}
+		break;
+
+            case LYK_DOWN_TWO:
+	        cur_choice += 2;
+		if (cur_choice > num_choices)
+                    cur_choice = num_choices;
+
+		/*
+		 *  Scroll the window down if necessary.
+		 */
+		if ((cur_choice - window_offset) >= length) {
+		    window_offset += 2;
+		    if (window_offset > (num_choices - length + 1))
+		        window_offset = (num_choices - length + 1);
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_UP_TWO:
+	        cur_choice -= 2;
+		if (cur_choice < 0)
+		    cur_choice = 0;
+
+		/*
+		 *  Scroll the window up if necessary.
+		 */
+		if ((cur_choice - window_offset) < 0) {
+		    window_offset -= 2;
+		    if (window_offset < 0)
+		        window_offset = 0;
+		    goto redraw;
+		}
+                break;
+
+            case LYK_DOWN_HALF:
+	        cur_choice += (length/2);
+		if (cur_choice > num_choices)
+                    cur_choice = num_choices;
+
+		/*
+		 *  Scroll the window down if necessary.
+		 */
+		if ((cur_choice - window_offset) >= length) {
+		    window_offset += (length/2);
+		    if (window_offset > (num_choices - length + 1))
+		        window_offset = (num_choices - length + 1);
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_UP_HALF:
+	        cur_choice -= (length/2);
+		if (cur_choice < 0)
+		    cur_choice = 0;
+
+		/*
+		 *  Scroll the window up if necessary.
+		 */
+		if ((cur_choice - window_offset) < 0) {
+		    window_offset -= (length/2);
+		    if (window_offset < 0)
+		        window_offset = 0;
+		    goto redraw;
+		}
+                break;
+
+	    case LYK_REFRESH:
+	        clearok(curscr, TRUE);
+	        refresh();
+		break;
+
+	    case LYK_NEXT:
+		if (recall && *prev_target_buffer == '\0') {
+		    /*
+		     *  We got a 'n'ext command with no prior query
+		     *  specified within the popup window.  See if
+		     *  one was entered when the popup was retracted,
+		     *  and if so, assume that's what's wanted.  Note
+		     *  that it will become the default within popups,
+		     *  unless another is entered within a popup.  If
+		     *  the within popup default is to be changed at
+		     *  that point, use WHEREIS ('/') and enter it,
+		     *  or the up- or down-arrow keys to seek any of
+		     *  the previously entered queries, regardless of
+		     *  whether they were entered within or outside
+		     *  of a popup window. - FM
+		     */
+		    if ((cp = (char *)HTList_objectAt(search_queries,
+	    					      0)) != NULL) {
+			strcpy(prev_target_buffer, cp);
+			QueryNum = 0;
+			FirstRecall = FALSE;
+		    }
+		}
+	        strcpy(prev_target, prev_target_buffer);
+	    case LYK_WHEREIS:
+	        if (*prev_target == '\0' ) {
+		    option_statusline(ENTER_WHEREIS_QUERY);
+		    if ((ch = LYgetstr(prev_target, VISIBLE,
+	    		 	       sizeof(prev_target_buffer),
+				       recall)) < 0) {
+			/*
+			 *  User cancelled the search via ^G. - FM
+			 */
+			option_statusline(CANCELLED);
+			sleep(InfoSecs);
+			goto restore_popup_statusline;
+		    }
+		}
+
+check_recall:
+		if (*prev_target == '\0' &&
+		    !(recall && (ch == UPARROW || ch == DNARROW))) {
+		    /*
+		     *  No entry.  Simply break.   - FM
+		     */
+	            option_statusline(CANCELLED);
+		    sleep(InfoSecs);
+		    goto restore_popup_statusline;
+		}
+
+		if (recall && ch == UPARROW) {
+		    if (FirstRecall) {
+		        /*
+			 *  Use the current string or
+			 *  last query in the list. - FM
+			 */
+			FirstRecall = FALSE;
+			if (*prev_target_buffer) {
+			    for (QueryNum = (QueryTotal - 1);
+			         QueryNum > 0; QueryNum--) {
+				if ((cp = (char *)HTList_objectAt(
+							search_queries,
+	    						QueryNum)) != NULL &&
+				    !strcmp(prev_target_buffer, cp)) {
+				    break;
+				}
+			    }
+			} else {
+			    QueryNum = 0;
+			}
+		    } else {
+			/*
+			 *  Go back to the previous query in the list. - FM
+			 */
+			QueryNum++;
+		    }
+		    if (QueryNum >= QueryTotal)
+			/*
+			 *  Roll around to the last query in the list. - FM
+			 */
+			QueryNum = 0;
+		    if ((cp = (char *)HTList_objectAt(search_queries,
+	    					      QueryNum)) != NULL) {
+			strcpy(prev_target, cp);
+			if (*prev_target_buffer &&
+			    !strcmp(prev_target_buffer, prev_target)) {
+			    option_statusline(EDIT_CURRENT_QUERY);
+			} else if ((*prev_target_buffer && QueryTotal == 2) ||
+				   (!(*prev_target_buffer) &&
+				      QueryTotal == 1)) {
+			    option_statusline(EDIT_THE_PREV_QUERY);
+			} else {
+			    option_statusline(EDIT_A_PREV_QUERY);
+			}
+			if ((ch = LYgetstr(prev_target, VISIBLE,
+				sizeof(prev_target_buffer), recall)) < 0) {
+			    /*
+			     *  User cancelled the search via ^G. - FM
+			     */
+			    option_statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    goto restore_popup_statusline;
+			}
+			goto check_recall;
+		    }
+		} else if (recall && ch == DNARROW) {
+		    if (FirstRecall) {
+		    /*
+		     *  Use the current string or
+		     *  first query in the list. - FM
+		     */
+		    FirstRecall = FALSE;
+		    if (*prev_target_buffer) {
+			for (QueryNum = 0;
+			     QueryNum < (QueryTotal - 1); QueryNum++) {
+			    if ((cp = (char *)HTList_objectAt(
+							search_queries,
+							QueryNum)) != NULL &&
+				!strcmp(prev_target_buffer, cp)) {
+				    break;
+			    }
+			}
+		    } else {
+			QueryNum = (QueryTotal - 1);
+		    }
+		} else {
+		    /*
+		     *  Advance to the next query in the list. - FM
+		     */
+		    QueryNum--;
+		}
+		if (QueryNum < 0)
+		    /*
+		     *  Roll around to the first query in the list. - FM
+		     */
+		    QueryNum = (QueryTotal - 1);
+		    if ((cp = (char *)HTList_objectAt(search_queries,
+	    					      QueryNum)) != NULL) {
+			strcpy(prev_target, cp);
+			if (*prev_target_buffer &&
+			    !strcmp(prev_target_buffer, prev_target)) {
+			    option_statusline(EDIT_CURRENT_QUERY);
+			} else if ((*prev_target_buffer &&
+				    QueryTotal == 2) ||
+				   (!(*prev_target_buffer) &&
+				    QueryTotal == 1)) {
+			    option_statusline(EDIT_THE_PREV_QUERY);
+			} else {
+			    option_statusline(EDIT_A_PREV_QUERY);
+			}
+			if ((ch = LYgetstr(prev_target, VISIBLE,
+					   sizeof(prev_target_buffer),
+					   recall)) < 0) {
+			    /*
+			     * User cancelled the search via ^G. - FM
+			     */
+			    option_statusline(CANCELLED);
+			    sleep(InfoSecs);
+			    goto restore_popup_statusline;
+	    		}
+			goto check_recall;
+		    }
+ 		}
+		/*
+		 *  Replace the search string buffer with the new target. - FM
+		 */
+		strcpy(prev_target_buffer, prev_target);
+		HTAddSearchQuery(prev_target_buffer);
+
+		/*
+		 *  Start search at the next choice. - FM
+		 */
+		for (j = 1; Cptr[i+j] != NULL; j++) {
+		    sprintf(buffer, "%s%d: %s",
+				    ((num_choices > 8 && (j + i) < 9) ?
+								  " " : ""),
+				    (i + j + 1),
+				    Cptr[i+j]);
+		    if (case_sensitive) {
+			if (strstr(buffer, prev_target_buffer) != NULL)
+			    break;
+		    } else {
+			if (LYstrstr(buffer, prev_target_buffer) != NULL)
+			    break;
+		    }
+		}
+		if (Cptr[i+j] != NULL) {
+		    /*
+		     *  We have a hit, so make that choice the current. - FM
+		     */
+		    cur_choice += j;
+		    /*
+		     *  Scroll the window down if necessary.
+		     */
+		    if ((cur_choice - window_offset) >= length) {
+		        window_offset += j;
+			if (window_offset > (num_choices - length + 1))
+			    window_offset = (num_choices - length + 1);
+			ReDraw = TRUE;
+		    }
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  If we started at the beginning, it can't be present. - FM
+		 */
+		if (cur_choice == 0) {
+		    _user_message(STRING_NOT_FOUND, prev_target_buffer);
+		    sleep(MessageSecs);
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  Search from the beginning to the current choice. - FM
+		 */
+		for (j = 0; j < cur_choice; j++) {
+		    sprintf(buffer, "%s%d: %s",
+				    ((num_choices > 8 && j < 9) ?
+							    " " : ""),
+				    (j + 1),
+				    Cptr[j]);
+		    if (case_sensitive) {
+			if (strstr(buffer, prev_target_buffer) != NULL)
+			    break;
+		    } else {
+			if (LYstrstr(buffer, prev_target_buffer) != NULL)
+			    break;
+		    }
+		}
+		if (j < cur_choice) {
+		    /*
+		     *  We have a hit, so make that choice the current. - FM
+		     */
+		    j = (cur_choice - j);
+		    cur_choice -= j;
+		    /*
+		     *  Scroll the window up if necessary.
+		     */
+		    if ((cur_choice - window_offset) < 0) {
+		        window_offset -= j;
+			if (window_offset < 0)
+			    window_offset = 0;
+			ReDraw = TRUE;
+		    }
+		    goto restore_popup_statusline;
+		}
+
+		/*
+		 *  Didn't find it in the preceding choices either. - FM
+		 */
+		_user_message(STRING_NOT_FOUND, prev_target_buffer);
+		sleep(MessageSecs);
+
+restore_popup_statusline:
+		/*
+		 *  Restore the popup statusline and
+		 *  reset the search variables. - FM
+		 */
+		if (disabled)
+		    option_statusline(CHOICE_LIST_UNM_MSG);
+   		else
+		    option_statusline(CHOICE_LIST_MESSAGE);
+		*prev_target = '\0';
+		QueryTotal = (search_queries ? HTList_count(search_queries)
+					     : 0);
+		recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
+		QueryNum = QueryTotal;
+		if (ReDraw == TRUE) {
+		    ReDraw = FALSE;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_QUIT:
+	    case LYK_ABORT:
+	    case LYK_PREV_DOC:
+		cur_choice = orig_choice;
+		term_options = TRUE;
+		option_statusline(CANCELLED);
+		sleep(MessageSecs);
+		cmd = LYK_ACTIVATE; /* to exit */
+		break;
+        }
+    }
+#ifndef USE_SLANG
+    delwin(form_window);
+#endif /* !USE_SLANG */
+
+    if (disabled || term_options) {
+	option_statusline("");
+        return(orig_choice);
+    } else {
+	option_statusline(VALUE_ACCEPTED);
+	return(cur_choice);
+    }
+}
diff --git a/src/LYOptions.h b/src/LYOptions.h
index c313d257..5b98fcb3 100644
--- a/src/LYOptions.h
+++ b/src/LYOptions.h
@@ -7,7 +7,13 @@ extern BOOLEAN term_options;
 extern void options NOPARAMS;
 extern void edit_bookmarks NOPARAMS;
 
-/* values for options */
+/*
+ *  Values for the options menu. - FM
+ *
+ *  L_foo values are the Y coordinates for the menu item.
+ *  B_foo values are the X coordinates for the item's prompt string.
+ *  C_foo values are the X coordinates for the item's value string.
+ */
 #define L_EDITOR	 2
 #define L_DISPLAY	 3
 
@@ -32,7 +38,12 @@ extern void edit_bookmarks NOPARAMS;
 #define B_SHOW_DOTFILES	44
 #define C_SHOW_DOTFILES	62
 
-#define L_SELECT_POPUPS 13
+#define L_BOOL_B	13
+#define B_SELECT_POPUPS	5
+#define C_SELECT_POPUPS	36
+#define B_SHOW_CURSOR	44
+#define C_SHOW_CURSOR	62
+
 #define L_KEYPAD	14 
 #define L_LINEED	15
 
diff --git a/src/LYPrint.c b/src/LYPrint.c
index 3bd365d7..58d0b1a1 100644
--- a/src/LYPrint.c
+++ b/src/LYPrint.c
@@ -53,7 +53,8 @@ extern BOOLEAN LYHaveCJKCharacterSet;
 PRIVATE int remove_quotes PARAMS((char *string));
 #endif /* VMS */
 
-PUBLIC int printfile ARGS1(document *,newdoc) 
+PUBLIC int printfile ARGS1(
+	document *,	newdoc) 
 {
     static char tempfile[256];
     static BOOLEAN first = TRUE;
@@ -330,6 +331,21 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 			goto retry;
 		    }
 		}
+		/*
+		 *  Cancel if the user entered "/dev/null" on Unix,
+		 *  or an "nl:" path (case-insensitive) on VMS. - FM
+		 */
+#ifdef VMS
+		if (!strncasecomp(filename, "nl:", 3) ||
+		    !strncasecomp(filename, "/nl/", 4))
+#else
+		if (!strcmp(filename, "/dev/null"))
+#endif /* VMS */
+		{
+		    _statusline(SAVE_REQUEST_CANCELLED);
+		    sleep(InfoSecs);
+		    break;
+		}
 		if ((cp = strchr(filename, '~'))) {
 		    *(cp++) = '\0';
 		    strcpy(buffer, filename);
@@ -367,9 +383,9 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    cp = NULL;
 		if (cp)
 #ifdef DOSPATH
-						  sprintf(buffer,"%s/%s", cp, HTDOS_name(filename));
+		    sprintf(buffer,"%s/%s", cp, HTDOS_name(filename));
 #else
-                    sprintf(buffer,"%s/%s", cp, filename);
+                    sprintf(buffer, "%s/%s", cp, filename);
 #endif
 		else
 #ifdef DOSPATH
@@ -379,8 +395,10 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 #endif
 #endif /* VMS */
 
-		/* see if it already exists */
-		if ((outfile_fp = fopen(buffer,"r")) != NULL) {
+		/*
+		 *  See if it already exists.
+		 */
+		if ((outfile_fp = fopen(buffer, "r")) != NULL) {
 		    fclose(outfile_fp);
 #ifdef VMS
 		    _statusline(FILE_EXISTS_HPROMPT);
@@ -419,6 +437,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    FnameNum = FnameTotal;
 		    goto retry;
                 }
+		chmod(buffer, 0600);
 
 		if (HTisDocumentSource()) {
 		    /*
@@ -498,6 +517,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    HTAlert(UNABLE_TO_OPEN_TEMPFILE);
 		    break;
 		}
+		chmod(tempfile, 0600);
 
 		/*
 		 *  Write the contents to a temp file.
@@ -553,11 +573,16 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		
 		/*
 		 *  Determine which mail headers should be sent.
+		 *  Use Content-Type and MIME-Version headers only
+		 *  if needed.  We need them if we are mailing HTML
+		 *  source, or if we have 8-bit characters and will
+		 *  be sending Content-Transfer-Encoding to indicate
+		 *  this.
+		 *
 		 *  Send Content-Transfer-Encoding only if the document
 		 *  has 8-bit characters.  Send a charset parameter only
 		 *  if the document has 8-bit characters and we we seem
-		 *  to have a valid charset.  Also use Content-Type
-		 *  and MIME-Version headers only if needed.  - kw
+		 *  to have a valid charset.  - kw
 		 */
 		use_cte = HTLoadedDocumentEightbit();
 #ifdef EXP_CHARTRANS
@@ -568,10 +593,11 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		 *  Also don't use an inofficial "x-" charset. - kw
 		 */
 		if (!use_cte || LYHaveCJKCharacterSet ||
-		    strncasecomp(disp_charset, "x-", 2) == 0)
+		    strncasecomp(disp_charset, "x-", 2) == 0) {
 		    disp_charset = NULL;
+		}
 #else
-		disp_charset = HTLoadedDocumentCharset();
+		disp_charset = NULL;
 #endif /* EXP_CHARTRANS */
 		use_type =  (disp_charset || HTisDocumentSource());
 		use_mime = (use_cte || use_type);
@@ -600,19 +626,22 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 		    			content_location);
 		} else {
 		    /*
-                     * Add Content-Type: text/plain if we have 8-bit
-		     * characters and a valid charset for non-source
-		     * documents. - kw
-                     */
+		     *  Add Content-Type: text/plain if we have 8-bit
+		     *  characters and a valid charset for non-source
+		     *  documents. - KW
+		     */
 		    if (disp_charset != NULL) {
 			fprintf(outfile_fp,
 				"Content-Type: text/plain; charset=%s\n",
 				disp_charset);
 		    }
 		}
-		fprintf(outfile_fp, "X-URL: %s\n", newdoc->address);
-		fprintf(outfile_fp, "To: %s\nSubject:%s\n\n",
+		/*
+		 *  Add the To, Subject, and X-URL headers. - FM
+		 */
+		fprintf(outfile_fp, "To: %s\nSubject: %s\n",
 				     user_response, sug_filename);
+		fprintf(outfile_fp, "X-URL: %s\n\n", newdoc->address);
 		if (HTisDocumentSource()) {
 		    /*
 		     *  Added the document's base as a BASE tag to
@@ -774,6 +803,7 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 	            HTAlert(FILE_ALLOC_FAILED);
 		    break;
                 }
+		chmod(tempfile, 0600);
 
 		if (HTisDocumentSource()) {
 		    /*
@@ -926,17 +956,34 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 			        goto again;
 			    }
 		        }
+			/*
+			 *  Cancel if the user entered "/dev/null" on Unix,
+			 *  or an "nl:" path (case-insensitive) on VMS. - FM
+			 */
+#ifdef VMS
+			if (!strncasecomp(filename, "nl:", 3) ||
+			    !strncasecomp(filename, "/nl/", 4))
+#else
+			if (!strcmp(filename, "/dev/null"))
+#endif /* VMS */
+			{
+			    _statusline(PRINT_REQUEST_CANCELLED);
+			    sleep(InfoSecs);
+			    break;
+			}
 			HTAddSugFilename(filename);
 		    }
 
 #ifdef VMS
-		    sprintf(buffer, cur_printer->command, tempfile, filename);
+		    sprintf(buffer, cur_printer->command, tempfile, filename,
+				    "", "", "", "", "", "", "", "", "", "");
 #else /* Unix: */
 		    /*
 		     *  Prevent spoofing of the shell.
 		     */
 		    cp = quote_pathname(filename);
-		    sprintf(buffer, cur_printer->command, tempfile, cp);
+		    sprintf(buffer, cur_printer->command, tempfile, cp,
+				    "", "", "", "", "", "", "", "", "", "");
 		    FREE(cp);
 #endif /* !VMS */
 
@@ -975,17 +1022,18 @@ PUBLIC int printfile ARGS1(document *,newdoc)
 }	
 
 #ifdef VMS
-PRIVATE int remove_quotes ARGS1(char *,string)
+PRIVATE int remove_quotes ARGS1(
+	char *,		string)
 {
    int i;
 
-   for(i=0;string[i]!='\0';i++)
-	if(string[i]=='"')
-	   string[i]=' ';
-	else if(string[i]=='&')
-	   string[i]=' ';
-	else if(string[i]=='|')
-	   string[i]=' ';
+   for(i = 0; string[i] != '\0'; i++)
+	if(string[i] == '"')
+	   string[i] = ' ';
+	else if(string[i] == '&')
+	   string[i] = ' ';
+	else if(string[i] == '|')
+	   string[i] = ' ';
 
    return(0);
 }
@@ -1001,12 +1049,13 @@ PRIVATE int remove_quotes ARGS1(char *,string)
  *  LYNXPRINT://MAIL_FILE/lines=#   	     mail the file
  *  LYNXPRINT://PRINTER/lines=#/number=#   print to printer number #
  */
-
-PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file)
+PUBLIC int print_options ARGS2(
+	char **,	newfile,
+	int,		lines_in_file)
 {
     static char tempfile[256];
     static BOOLEAN first = TRUE;
-    char *print_filename = NULL;
+    static char print_filename[256];
     char buffer[LINESIZE];
     int count;
     int pages;
@@ -1016,7 +1065,12 @@ PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file)
     pages = lines_in_file/66 + 1;
 
     if (first) {
-        tempname(tempfile,NEW_FILE);
+        tempname(tempfile, NEW_FILE);
+#if defined (VMS) || defined (DOSPATH)
+	sprintf(print_filename, "file://localhost/%s", tempfile);
+#else
+	sprintf(print_filename, "file://localhost%s", tempfile);
+#endif /* VMS */
 	first = FALSE;
 #ifdef VMS
     } else {
@@ -1028,13 +1082,7 @@ PUBLIC int print_options ARGS2(char **,newfile, int,lines_in_file)
         HTAlert(UNABLE_TO_OPEN_PRINTOP_FILE);
 	return(-1);
     }
-
-#if defined (VMS) || defined (DOSPATH)
-    StrAllocCopy(print_filename, "file://localhost/");
-#else
-    StrAllocCopy(print_filename, "file://localhost");
-#endif /* VMS */
-    StrAllocCat(print_filename, tempfile);
+    chmod(tempfile, 0600);
 
     StrAllocCopy(*newfile, print_filename);
     LYforce_no_cache = TRUE;
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c
index 1ec86c3c..8fdeaa0e 100644
--- a/src/LYReadCFG.c
+++ b/src/LYReadCFG.c
@@ -653,6 +653,9 @@ PUBLIC void read_cfg ARGS1(
 #endif /* VMS */
 	    }
 
+	} else if (!strncasecomp(buffer, "FORCE_SSL_COOKIES_SECURE:", 25)) {
+	    LYForceSSLCookiesSecure = is_true(buffer+25);
+
 	} else if (!strncasecomp(buffer, "ftp_proxy:", 10)) {
 	    if (getenv("ftp_proxy") == NULL) {
 #ifdef VMS
@@ -1008,6 +1011,12 @@ PUBLIC void read_cfg ARGS1(
 	} else if (!strncasecomp(buffer, "SCAN_FOR_BURIED_NEWS_REFS:", 26)) {
 	    scan_for_buried_news_references = is_true(buffer+26);
 
+	} else if (!strncasecomp(buffer, "SEEK_FRAG_AREA_IN_CUR:", 22)) {
+	    LYSeekFragAREAinCur = is_true(buffer+22);
+
+	} else if (!strncasecomp(buffer, "SEEK_FRAG_MAP_IN_CUR:", 21)) {
+	    LYSeekFragMAPinCur = is_true(buffer+21);
+
 	} else if (!strncasecomp(buffer, "SET_COOKIES:", 12)) {
 	    LYSetCookies = is_true(buffer+12);
 
diff --git a/src/LYSearch.c b/src/LYSearch.c
index 495e9e19..d03fc08d 100644
--- a/src/LYSearch.c
+++ b/src/LYSearch.c
@@ -52,8 +52,7 @@ PRIVATE int check_for_target_in_links ARGS2(
 	 *  Search the relevant form fields, taking the
 	 *  case_sensitive setting into account. - FM
 	 */
-	if ((links[i].form != NULL && links[i].type == WWW_FORM_LINK_TYPE &&
-	     links[i].form->value != NULL) &&
+	if ((links[i].form != NULL && links[i].form->value != NULL) &&
 	    links[i].form->type != F_HIDDEN_TYPE) {
 	    if (links[i].form->type == F_PASSWORD_TYPE) {
 	        /*
@@ -168,7 +167,8 @@ PRIVATE int check_for_target_in_links ARGS2(
  *
  */
 		
-PUBLIC BOOL textsearch ARGS3(document *,cur_doc,
+PUBLIC BOOL textsearch ARGS3(
+	document *,	cur_doc,
 	char *,		prev_target,
 	BOOL,		next)
 {
@@ -358,7 +358,7 @@ check_recall:
 	/*
 	 *  Found in link, changed cur, we're done.
 	 */
-	highlight(OFF, oldcur);
+	highlight(OFF, oldcur, prev_target);
 	return(TRUE); 
     }
 	
@@ -374,11 +374,11 @@ check_recall:
     /*
      *  Resume search, this time for all text.
      *  Set www_search_result if string found,
-     *  and position the hit at top of screen.
+     *  and position the hit near top of screen.
      */
-    www_user_search(cur_doc->line+offset, cur_doc, prev_target);
+    www_user_search((cur_doc->line + offset), cur_doc, prev_target);
     if (cur_doc->link != oldcur) {
-	highlight(OFF, oldcur);
+	highlight(OFF, oldcur, prev_target);
 	return(TRUE);
     }
     return(www_search_result > 0);
diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c
index 23c6b6de..7c17df72 100644
--- a/src/LYShowInfo.c
+++ b/src/LYShowInfo.c
@@ -37,7 +37,7 @@ PUBLIC int showinfo ARGS4(
 {
     static char tempfile[256];
     static BOOLEAN first = TRUE;
-    char *info_url = NULL;
+    static char info_url[256];
     int url_type;
     FILE *fp0;
     char *Address = NULL, *Title = NULL;
@@ -50,7 +50,15 @@ PUBLIC int showinfo ARGS4(
     struct group *grp;
 #endif /* DIRED_SUPPORT */
     if (first) {
-        tempname(tempfile,NEW_FILE);
+        tempname(tempfile, NEW_FILE);
+	/*
+	 *  Make the temporary file a URL now.
+	 */
+#if defined (VMS) || defined (DOSPATH)
+	sprintf(info_url, "file://localhost/%s", tempfile);
+#else
+	sprintf(info_url, "file://localhost%s", tempfile);
+#endif /* VMS */
 	first = FALSE;
 #ifdef VMS
     } else {
@@ -58,28 +66,16 @@ PUBLIC int showinfo ARGS4(
 #endif /* VMS */
     }
 
-
-    /*
-     *  Make the temporary file a URL now.
-     */
-#if defined (VMS) || defined (DOSPATH)
-    StrAllocCopy(info_url,"file://localhost/");
-#else
-    StrAllocCopy(info_url,"file://localhost");
-#endif /* VMS */
-    StrAllocCat(info_url,tempfile);
-
-    if ((fp0 = fopen(tempfile,"w")) == NULL) {
+    if ((fp0 = fopen(tempfile, "w")) == NULL) {
         HTAlert(CANNOT_OPEN_TEMP);
-	FREE(info_url);
         return(0);
     }
+    chmod(tempfile, 0600);
 
     /*
      *  Point the address pointer at this Url
      */
     StrAllocCopy(newdoc->address, info_url);
-    FREE(info_url);
 
     if (nlinks > 0 && links[doc->link].lname != NULL &&
 	(url_type = is_url(links[doc->link].lname)) != 0 &&
@@ -94,7 +90,7 @@ PUBLIC int showinfo ARGS4(
 
     fprintf(fp0, "<head>\n");
 #ifdef EXP_CHARTRANS
-    add_META_charset_to_fd(fp0, -1);
+    LYAddMETAcharsetToFD(fp0, -1);
 #endif
     fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n",
 		 SHOWINFO_TITLE);
@@ -297,9 +293,10 @@ PUBLIC int showinfo ARGS4(
 	"<dt>&nbsp;&nbsp;&nbsp;&nbsp;<em>size:</em> %d lines\n", size_of_file);
 
     fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;<em>mode:</em> %s%s%s\n",
-		 (lynx_mode == FORMS_LYNX_MODE ? "forms mode" : "normal"),
-	    (doc->safe ? ", safe" : ""),
-	    (doc->internal_link ? ", internal link" : "")
+		 (lynx_mode == FORMS_LYNX_MODE ?
+				  "forms mode" : "normal"),
+		 ((lynx_mode == FORMS_LYNX_MODE && doc->safe) ? ", safe" : ""),
+		 (doc->internal_link ? ", internal link" : "")
 	    );
 
     fprintf(fp0, "</dl>\n");  /* end of list */
@@ -331,7 +328,7 @@ PUBLIC int showinfo ARGS4(
 	        fprintf(fp0, "<dt>&nbsp;&nbsp;<em>Action:</em> %s\n", Address);
 	    }
 	    if (!(links[doc->link].form->submit_method &&
-		links[doc->link].form->submit_action)) {
+		  links[doc->link].form->submit_action)) {
 	        fprintf(fp0,"<dt>&nbsp;(Form field)\n");
 	    }
 	} else {
@@ -341,7 +338,8 @@ PUBLIC int showinfo ARGS4(
 	    } else {
 	        StrAllocCopy(Title, "");
 	    }
-	    fprintf(fp0, "<dt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>URL:</em> %s\n", Title);
+	    fprintf(fp0,
+	       "<dt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>URL:</em> %s\n", Title);
 	}
 	fprintf(fp0, "</dl>\n");  /* end of list */
 
diff --git a/src/LYStrings.c b/src/LYStrings.c
index f5c88ffd..153e7490 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -92,10 +92,13 @@ PRIVATE int set_clicked_link ARGS2(int,x,int,y)
 
 
 /*
- * LYstrncpy() terminates strings with a null byte.
- * Writes a null byte into the n+1 byte of dst.
+ *  LYstrncpy() terminates strings with a null byte.
+ *  Writes a null byte into the n+1 byte of dst.
  */
-PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n)
+PUBLIC char *LYstrncpy ARGS3(
+	char *,		dst,
+	char *,		src,
+	int,		n)
 {
     char *val;
     int len=strlen(src);
@@ -110,6 +113,10 @@ PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n)
         *(dst+n) = '\0';
     return val;
 }
+
+#define IS_NEW_GLYPH(ch) (utf_flag && ((unsigned char)(ch)&0xc0) != 0x80)
+#define IS_UTF_EXTRA(ch) (utf_flag && ((unsigned char)(ch)&0xc0) == 0x80)
+
 #ifdef EXP_CHARTRANS
 /*
  * LYmbcsstrncpy() terminates strings with a null byte.
@@ -118,7 +125,7 @@ PUBLIC char * LYstrncpy ARGS3(char *,dst, char *,src, int,n)
  * either bytes or glyphs (mbcs sequences) (currently only UTF8).
  */
 PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes,
-				  int,n_glyphs,	int,enc)
+				  int,n_glyphs,	int,utf_flag)
 {
     char *val = dst;
     int i_bytes = 0, i_glyphs = 0;
@@ -128,15 +135,13 @@ PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes,
     if (n_glyphs < 0)
         n_glyphs = 0;
 
-#define IS_NEW_GLYPH(ch) (enc && ((unsigned char)(ch)&0xc0) != 0x80)
-
-    for (; *src != '\0' && i_bytes < n_bytes;
-	 i_bytes++) {
-	if (IS_NEW_GLYPH(*src))
+    for (; *src != '\0' && i_bytes < n_bytes; i_bytes++) {
+	if (IS_NEW_GLYPH(*src)) {
 	    if (i_glyphs++ >= n_glyphs) {
 		*dst = '\0';
 		return val;
 	    }
+	}
 	*(dst++) = *(src++);
     }
     *dst = '\0';
@@ -145,8 +150,44 @@ PUBLIC char * LYmbcsstrncpy ARGS5(char *,dst, char *,src, int,n_bytes,
 }
 #endif /* EXP_CHARTRANS */
 
-#undef GetChar
+/*
+ *  LYmbcsstrlen() returns the printable length of a string
+ *  that might contain IsSpecial or multibyte (CJK or UTF8)
+ *  characters. - FM
+ */
+PUBLIC int LYmbcsstrlen ARGS2(
+	char *,		str,
+	BOOL,		utf_flag)
+{
+    int i, j, len = 0;
+
+    if (!str && *str)
+	return(len);
 
+    for (i = 0; str[i] != '\0'; i++) {
+	if (IsSpecialAttrChar(str[i])) {
+	    continue;
+	} else {
+	    len++;
+	}
+	if (IS_NEW_GLYPH(str[i])) {
+	    j = 0;
+	    while (str[(i + 1)] != '\0' && 
+	    	   !IsSpecialAttrChar(str[(i + 1)]) &&
+		   j < 5 &&
+		   IS_UTF_EXTRA(str[(i + 1)])) {
+		i++;
+		j++;
+	    }
+	} else if (!utf_flag && HTCJK != NOCJK && !isascii(str[i]) &&
+		    str[(i + 1)] != '\0' &&
+		    !IsSpecialAttrChar(str[(i + 1)])) {
+	    i++;
+	}
+    }
+
+    return(len);
+}
 #undef GetChar
 
 #ifdef USE_SLANG
@@ -233,9 +274,9 @@ PRIVATE int map_function_to_key ARGS1(char, keysym)
 #endif
 
 /*
- * LYgetch() translates some escape sequences and may fake noecho
+ *  LYgetch() translates some escape sequences and may fake noecho.
  */
-PUBLIC int LYgetch ()
+PUBLIC int LYgetch NOARGS
 {
     int a, b, c, d = -1;
 
@@ -456,10 +497,9 @@ re_read:
     }
 #if HAVE_KEYPAD
     else {
-
-	/* convert keypad() mode keys into Lynx defined keys
+	/*
+	 *  Convert keypad() mode keys into Lynx defined keys.
 	 */
-
 	switch(c) {
 	case KEY_DOWN:	           /* The four arrow keys ... */
 	   c=DNARROW;
@@ -563,35 +603,29 @@ re_read:
     }
 #endif /* defined(HAVE_KEYPAD) */
 
-    if (c > DO_NOTHING)
-    /* Don't return raw values for KEYPAD symbols which we may have missed
-     * in the switch above if they are obviously invalid when used as an
-     * index into (e.g.) keypad[]. - kw
-     */
-       return (0);
-    else
-    return(c);
+    if (c > DO_NOTHING) {
+	/*
+	 *  Don't return raw values for KEYPAD symbols which we may have
+	 *  missed in the switch above if they are obviously invalid when
+	 *  used as an index into (e.g.) keypad[]. - KW
+	 */
+	return (0);
+    } else {
+	return(c);
+    }
 }
 
 
 /*
- * display the current value of the string and allow the user
- * to edit it.
- */
-
-#ifdef USE_SLANG
-#define GetYX(y,x)   y = SLsmg_get_row(), x = SLsmg_get_column()
-#else
-#ifdef getyx
-#define GetYX(y,x)   getyx(stdscr,y,x)
-#else
-#define GetYX(y,x)   y = stdscr->_cury, x = stdscr->_curx
-#endif /* getyx */
-#endif /* USE_SLANG */
+**  Display the current value of the string and allow the user
+**  to edit it.
+*/
 
 #define EDREC    EditFieldData
 
-/* shorthand to get rid of all most of the "edit->suchandsos" */
+/*
+ *  Shorthand to get rid of all most of the "edit->suchandsos".
+ */
 #define Buf      edit->buffer
 #define Pos      edit->pos
 #define StrLen   edit->strlen
@@ -600,11 +634,16 @@ re_read:
 #define DspStart edit->xpan
 #define Margin   edit->margin
 
-PUBLIC void LYSetupEdit ARGS4(EDREC *,edit, char *,old, int,maxstr, int,maxdsp)
+PUBLIC void LYSetupEdit ARGS4(
+	EDREC *,	edit,
+	char *,		old,
+	int,		maxstr,
+	int,		maxdsp)
 {
-    /* Initialize edit record */
-
-    GetYX(edit->sy, edit->sx);
+    /*
+     *  Initialize edit record
+     */
+    LYGetYX(edit->sy, edit->sx);
     edit->pad   = ' ';
     edit->dirty = TRUE;
     edit->panon = FALSE;
@@ -620,22 +659,42 @@ PUBLIC void LYSetupEdit ARGS4(EDREC *,edit, char *,old, int,maxstr, int,maxdsp)
         if (DspWdth > 4)    /* Else "{}" take up precious screen space */
 	    edit->panon = TRUE;
 
-	/* Figure out margins. If too big we do a lot of unnecessary
-	 * scrolling. If too small user doesn't have sufficient look-ahead.
-	 * Let's say 25% for each margin, upper bound is 10 columns.
+	/*
+	 *  Figure out margins.  If too big, we do a lot of unnecessary
+	 *  scrolling.  If too small, user doesn't have sufficient
+	 *  look-ahead.  Let's say 25% for each margin, upper bound is
+	 *  10 columns.
 	 */
 	Margin = DspWdth/4;
 	if (Margin > 10)
 	    Margin = 10;
     }
-    strcpy(edit->buffer, old);
+
+    /*
+     *  We expect the called function to pass us a default (old) value
+     *  with a length that is less than or equal to maxstr, and to
+     *  handle any messaging associated with actions to achieve that
+     *  requirement.  However, in case the calling function screwed
+     *  up, we'll check it here, and ensure that no buffer overrun can
+     *  occur by loading only as much of the head as fits. - FM
+     */
+    if (strlen(old) >= maxstr) {
+	strncpy(edit->buffer, old, maxstr);
+	edit->buffer[maxstr] = '\0';
+	StrLen = maxstr;
+    } else {
+	strcpy(edit->buffer, old);
+    }
 }
 
-PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
+PUBLIC int LYEdit1 ARGS4(
+	EDREC *,	edit,
+	int,		ch,
+	int,		action,
+	BOOL,		maxMessage)
 {   /* returns 0    character processed
      *         ch   otherwise
      */
-
     int i;
     int length;
 
@@ -648,15 +707,15 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
     switch (action) {
     case LYE_AIX:
         /*
-	 * Hex 97.
-	 * Fall through as a character for CJK.
-	 * Otherwise, we treat this as LYE_ENTER.
+	 *  Hex 97.
+	 *  Fall through as a character for CJK.
+	 *  Otherwise, we treat this as LYE_ENTER.
 	 */
 	 if (HTCJK == NOCJK)
 	     return(ch);
     case LYE_CHAR:
         /*
-	 * ch is printable or ISO-8859-1 escape character.
+	 *  ch is printable or ISO-8859-1 escape character.
 	 */
 	if (Pos <= (MaxLen) && StrLen < (MaxLen)) {
 	    for(i = length; i >= Pos; i--)    /* Make room */
@@ -671,8 +730,8 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_BACKW:
         /*
-	 * Backword.
-	 * Definition of word is very naive: 1 or more a/n characters.
+	 *  Backword.
+	 *  Definition of word is very naive: 1 or more a/n characters.
 	 */
 	while (Pos && !isalnum(Buf[Pos-1]))
 	    Pos--;
@@ -682,7 +741,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_FORWW:
         /*
-	 * Word forward.
+	 *  Word forward.
 	 */
 	while (isalnum(Buf[Pos]))
 	    Pos++;   /* '\0' is not a/n */
@@ -692,28 +751,28 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_ERASE:
         /*
-	 * Erase the line to start fresh.
+	 *  Erase the line to start fresh.
 	 */
 	 Buf[0] = '\0';
 	 /* fall through */
 
     case LYE_BOL:
         /*
-	 * Go to first column.
+	 *  Go to first column.
 	 */
 	Pos = 0;
 	break;
 
     case LYE_EOL:
         /*
-	 * Go to last column.
+	 *  Go to last column.
 	 */
 	Pos = length;
 	break;
 
     case LYE_DELNW:
         /*
-	 * Delete next word.
+	 *  Delete next word.
 	 */
 	{
 	    int pos0 = Pos;
@@ -725,7 +784,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_DELPW:
         /*
-	 * Delete previous word.
+	 *  Delete previous word.
 	 */
 	{
 	    int pos0 = Pos;
@@ -738,7 +797,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_DELN:
         /*
-	 * Delete next character
+	 *  Delete next character
 	 */
 	if (Pos >= length)
 	    break;
@@ -747,7 +806,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_DELP:
         /*
-	 * Delete preceding character.
+	 *  Delete preceding character.
 	 */
 	if (length == 0 || Pos == 0)
 	    break;
@@ -760,7 +819,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_DELC:
         /*
-	 * Delete current character.
+	 *  Delete current character.
 	 */
 	if (length == 0)
 	    break;
@@ -772,7 +831,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_FORW:
         /*
-	 * Move cursor to the right.
+	 *  Move cursor to the right.
 	 */
 	if (Pos < length)
 	    Pos++;
@@ -780,7 +839,7 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 
     case LYE_BACK:
         /*
-	 * Left-arrow move cursor to the left.
+	 *  Left-arrow move cursor to the left.
 	 */
 	if (Pos > 0)
 	    Pos--;
@@ -805,7 +864,8 @@ PUBLIC int LYEdit1 ARGS4(EDREC *,edit, int,ch, int,action, BOOL,maxMessage)
 }
 
 
-PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit)
+PUBLIC void LYRefreshEdit ARGS1(
+	EDREC *,	edit)
 {
     int i;
     int length;
@@ -876,14 +936,14 @@ PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit)
     }
 
     /*
-     * Erase rest of input area.
+     *  Erase rest of input area.
      */
-    padsize= DspWdth-nrdisplayed;
+    padsize = DspWdth-nrdisplayed;
     while (padsize--)
         addch((unsigned char)edit->pad);
 
     /*
-     * Scrolling indicators.
+     *  Scrolling indicators.
      */
     if (edit->panon) {
         if ((DspStart + nrdisplayed) < length) {
@@ -901,9 +961,14 @@ PUBLIC void LYRefreshEdit ARGS1(EDREC *,edit)
 }
 
 
-PUBLIC int LYgetstr ARGS4(char *,inputline, int,hidden,
-			  int,bufsize, int,recall)
+PUBLIC int LYgetstr ARGS4(
+	char *,		inputline,
+	int,		hidden,
+	int,		bufsize,
+	int,		recall)
 {
+    extern BOOLEAN term_letter;     /* Flag from terminate_letter() AST  */
+    extern BOOLEAN term_options;    /* Flag from terminate_options() AST */
     extern BOOLEAN term_message;    /* Flag from terminate_message() AST */
 #ifdef VMS
     extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST       */
@@ -912,7 +977,7 @@ PUBLIC int LYgetstr ARGS4(char *,inputline, int,hidden,
     int ch;
     EditFieldData MyEdit;
 
-    GetYX(y,x);                 /* Use screen from cursor position to eol */
+    LYGetYX(y, x);		/* Use screen from cursor position to eol */
     MaxStringSize = (bufsize < sizeof(MyEdit.buffer)) ?
     		    (bufsize - 1) : (sizeof(MyEdit.buffer) - 1);
     LYSetupEdit(&MyEdit, inputline, MaxStringSize, (LYcols-1)-x);
@@ -943,9 +1008,9 @@ again:
 	    /* fall through */
 	case LYE_AIX:
 	    /*
-	     * Hex 97.
-	     * Treat as a character for CJK.
-	     * Otherwise, we treat this as LYE_ENTER.
+	     *  Hex 97.
+	     *  Treat as a character for CJK.
+	     *  Otherwise, we treat this as LYE_ENTER.
 	     */
 	    if (HTCJK != NOCJK && ch != '\t') {
 	        LYLineEdit(&MyEdit,ch, FALSE);
@@ -953,7 +1018,7 @@ again:
 	    }
 	case LYE_ENTER:
 	    /*
-	     * Terminate the string and return.
+	     *  Terminate the string and return.
 	     */
 	    strcpy(inputline, MyEdit.buffer);
             return(ch);
@@ -961,7 +1026,7 @@ again:
 
         case LYE_ABORT:
 	    /*
-	     * Control-C or Control-G aborts.
+	     *  Control-C or Control-G aborts.
 	     */
 	    inputline[0] = '\0';		   
 	    return(-1);
@@ -974,11 +1039,13 @@ again:
 }
 
 /*
- * LYstrstr will find the first occurence of the string pointed to by tarptr
- * in the string pointed to by chptr.  
- * It is a case insensitive search.
+ *  LYstrstr will find the first occurence of the string
+ *  pointed to by tarptr in the string pointed to by chptr.  
+ *  It is a case insensitive search.
  */
-PUBLIC char * LYstrstr ARGS2(char *,chptr, char *,tarptr)
+PUBLIC char * LYstrstr ARGS2(
+	char *,		chptr,
+	char *,		tarptr)
 {
     register char *tmpchptr, *tmptarptr;
 
@@ -999,16 +1066,19 @@ PUBLIC char * LYstrstr ARGS2(char *,chptr, char *,tarptr)
 }	
 
 /*
- * LYno_attr_char_case_strstr will find the first occurence of the string 
- * pointed to by tarptr in the string pointed to by chptr.
- * It ignores the characters: LY_UNDERLINE_START_CHAR and
- * 			      LY_UNDERLINE_END_CHAR
- * 			      LY_BOLD_START_CHAR
- * 			      LY_BOLD_END_CHAR
- *			      if present in chptr.
- * It is a case insensitive search.
+ *  LYno_attr_char_case_strstr will find the first occurence of the
+ *  string pointed to by tarptr in the string pointed to by chptr.
+ *  It ignores the characters: LY_UNDERLINE_START_CHAR and
+ * 			       LY_UNDERLINE_END_CHAR
+ * 			       LY_BOLD_START_CHAR
+ * 			       LY_BOLD_END_CHAR
+ *				LY_SOFT_HYPHEN
+ *			       if present in chptr.
+ *  It is a case insensitive search.
  */
-PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr)
+PUBLIC char * LYno_attr_char_case_strstr ARGS2(
+	char *,		chptr,
+	char *,		tarptr)
 {
     register char *tmpchptr, *tmptarptr;
 
@@ -1019,10 +1089,10 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr)
         chptr++;
 
     for (; *chptr != '\0'; chptr++) {
-
         if (TOUPPER(*chptr) == TOUPPER(*tarptr)) {
-
-            /* see if they line up */
+            /*
+	     *  See if they line up.
+	     */
 	    tmpchptr = chptr+1;
 	    tmptarptr = tarptr+1;
 
@@ -1031,20 +1101,15 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr)
 
 	    while (1) {
 		 if (!IsSpecialAttrChar(*tmpchptr)) {
-
                     if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr))
 			break;
-
 		    tmpchptr++;
 		    tmptarptr++;
-
 		 } else {
 		    tmpchptr++;
 		 }
-
                  if (*tmptarptr == '\0')
 		     return(chptr);
-
 		 if (*tmpchptr == '\0')
 		     break;
 	    }
@@ -1055,16 +1120,19 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(char *,chptr, char *,tarptr)
 }
 
 /*
- * LYno_attr_char_strstr will find the first occurence of the string
- * pointed to by tarptr in the string pointed to by chptr.
- * It ignores the characters: LY_UNDERLINE_START_CHAR and
- *                            LY_UNDERLINE_END_CHAR
- *                            LY_BOLD_START_CHAR
- *                            LY_BOLD_END_CHAR
- *			      if present in chptr.
- * It is a case sensitive search.
+ *  LYno_attr_char_strstr will find the first occurence of the
+ *  string pointed to by tarptr in the string pointed to by chptr.
+ *  It ignores the characters: LY_UNDERLINE_START_CHAR and
+ *                             LY_UNDERLINE_END_CHAR
+ *                             LY_BOLD_START_CHAR
+ *                             LY_BOLD_END_CHAR
+ *				LY_SOFT_HYPHEN
+ *			       if present in chptr.
+ *  It is a case sensitive search.
  */
-PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr)
+PUBLIC char * LYno_attr_char_strstr ARGS2(
+	char *,		chptr,
+	char *,		tarptr)
 {
     register char *tmpchptr, *tmptarptr;
 
@@ -1075,32 +1143,27 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr)
         chptr++;
 
     for (; *chptr != '\0'; chptr++) {
-
         if ((*chptr) == (*tarptr)) {
-
-            /* see if they line up */
-            tmpchptr = chptr+1;
-            tmptarptr = tarptr+1;
+            /*
+	     *  See if they line up.
+	     */
+            tmpchptr = chptr + 1;
+            tmptarptr = tarptr + 1;
 
 	    if (*tmptarptr == '\0')  /* one char target */
 		 return(chptr);
 
             while (1) {
 		 if (!IsSpecialAttrChar(*tmpchptr)) {
-
                     if ((*tmpchptr) != (*tmptarptr))
                         break;
-
                     tmpchptr++;
                     tmptarptr++;
-
                  } else {
                     tmpchptr++;
                  }
-
                  if (*tmptarptr == '\0')
                      return(chptr);
-
                  if (*tmpchptr == '\0')
                      break;
             }
@@ -1110,9 +1173,6 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr)
     return(NULL);
 }
 
-#ifdef EXP_CHARTRANS
-
-#define IS_UTFEXTRA(ch) (utf_flag && ((unsigned char)(ch)&0xc0) == 0x80)
 /*
  * LYno_attr_mbcs_case_strstr will find the first occurence of the string 
  * pointed to by tarptr in the string pointed to by chptr.
@@ -1122,45 +1182,111 @@ PUBLIC char * LYno_attr_char_strstr ARGS2(char *,chptr, char *,tarptr)
  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  * 			      LY_UNDERLINE_END_CHAR
  * 			      LY_BOLD_START_CHAR
- * 			      LY_BOLD_END_CHAR[B
+ *				LY_BOLD_END_CHAR
+ *				LY_SOFT_HYPHEN
  *			      if present in chptr.
  * It assumes UTF8 if utf_flag is set.
- * It is a case insensitive search.
+ *  It is a case insensitive search. - KW & FM
  */
-PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr,
-					       BOOL, utf_flag, int *,nendp)
+PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
+	char *,		chptr,
+	char *,		tarptr,
+	BOOL,		utf_flag,
+	int *,		nstartp,
+	int *,		nendp)
 {
     register char *tmpchptr, *tmptarptr;
     int len = 0;
+    int offset;
 
-    if (!chptr)
+    if (!(chptr && tarptr))
         return(NULL);
 
+    /*
+     *  Skip initial IsSpecial chars. - FM
+     */
     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
         chptr++;
 
+    /*
+     *  Seek a first target match. - FM
+     */
     for (; *chptr != '\0'; chptr++) {
-	    
-        if (TOUPPER(*chptr) == TOUPPER(*tarptr)) {
+	if ((!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
+	     *chptr == *tarptr &&
+	     *(chptr + 1) != '\0' &&
+	     !IsSpecialAttrChar(*(chptr + 1))) ||
+	    TOUPPER(*chptr) == TOUPPER(*tarptr)) {
 	    int tarlen = 0;
+	    offset = len;
 	    len++;
 
-            /* see if they line up */
-	    tmpchptr = chptr+1;
-	    tmptarptr = tarptr+1;
-
-	    if (*tmptarptr == '\0') { /* one char target */
+            /*
+	     *  See if they line up.
+	     */
+	    tmpchptr = (chptr + 1);
+	    tmptarptr = (tarptr + 1);
+
+	    if (*tmptarptr == '\0') {
+		/*
+		 *  One char target.
+		 */
+		*nstartp = offset;
 		*nendp = len;
 		 return(chptr);
 	    }
+	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
+		 *chptr == *tarptr &&
+		 *tmpchptr != '\0' &&
+		 !IsSpecialAttrChar(*tmpchptr)) {
+		/*
+		 *  Check the CJK mutibyte. - FM
+		 */
+		if (*tmpchptr == *tmptarptr) {
+		    /*
+		     *  It's a match.  Advance to next char. - FM
+		     */
+		    tmpchptr++;
+		    tmptarptr++;
+		    if (*tmptarptr == '\0') {
+		        /*
+			 *  One character match. - FM
+			 */
+			*nstartp = offset;
+			*nendp = len + tarlen;
+			return(chptr);
+		    }
+		    tarlen++;
+		} else {
+		    /*
+		     *  It's not a match, so go back to
+		     *  seeking a first target match. - FM
+		     */
+		    chptr++;
+		    continue;
+		}
+	    }
+	    /*
+	     *  See if the rest of the target matches. - FM
+	     */
 	    while (1) {
 		 if (!IsSpecialAttrChar(*tmpchptr)) {
-
-                    if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr))
+		    if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) {
+			if (*tmpchptr == *tmptarptr &&
+			    *(tmpchptr + 1) == *(tmptarptr + 1) &&
+			    !IsSpecialAttrChar(*(tmpchptr + 1))) {
+			    tmpchptr++;
+			    tmptarptr++;
+			} else {
 			break;
+			}
+		    } else if (TOUPPER(*tmpchptr) != TOUPPER(*tmptarptr)) {
+			break;
+		    }
 
-		    if (!IS_UTFEXTRA(*tmptarptr))
+		    if (!IS_UTF_EXTRA(*tmptarptr)) {
 			tarlen++;
+		    }
 		    tmpchptr++;
 		    tmptarptr++;
 
@@ -1169,17 +1295,23 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr,
 		 }
 
                  if (*tmptarptr == '\0') {
+		    *nstartp = offset;
 		     *nendp = len + tarlen;
 		     return(chptr);
 		 }
-		 if (*tmpchptr == '\0')
+		if (*tmpchptr == '\0') {
 		     break;
 	    }
-        } else if (!( IS_UTFEXTRA(*chptr) ||
+	    }
+        } else if (!(IS_UTF_EXTRA(*chptr) ||
 		      IsSpecialAttrChar(*chptr))) {
+	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
+		*(chptr + 1) != '\0' &&
+		!IsSpecialAttrChar(*(chptr + 1))) {
+		chptr++;
+	    }
 	    len++;
 	}
-		       
     } /* end for */
 
     return(NULL);
@@ -1188,51 +1320,114 @@ PUBLIC char * LYno_attr_mbcs_case_strstr ARGS4(char *,chptr, char *,tarptr,
 /*
  * LYno_attr_mbcs_strstr will find the first occurence of the string
  * pointed to by tarptr in the string pointed to by chptr.
- * It takes account of MultiByte Character Sequences (UTF8).
- * The physical lenght of the displayed string up to the end of the target
- * string is returned in *nendp if the search is successful.
+ *  It takes account of CJK and MultiByte Character Sequences (UTF8).
+ *  The physical lengths of the displayed string up to the start and
+ *  end of the target string are returned in *nstartp and *nendp if
+ *  the search is successful.
  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  *                            LY_UNDERLINE_END_CHAR
  *                            LY_BOLD_START_CHAR
  *                            LY_BOLD_END_CHAR
+ *				LY_SOFT_HYPHEN
  *			      if present in chptr.
  * It assumes UTF8 if utf_flag is set.
- * It is a case sensitive search.
+ *  It is a case sensitive search. - KW & FM
  */
-PUBLIC char * LYno_attr_mbcs_strstr ARGS4(char *,chptr, char *,tarptr,
-					       BOOL, utf_flag, int *,nendp)
+PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
+	char *,		chptr,
+	char *,		tarptr,
+	BOOL,		utf_flag,
+	int *,		nstartp,
+	int *,		nendp)
 {
     register char *tmpchptr, *tmptarptr;
     int len = 0;
+    int offset;
 
-    if (!chptr)
+    if (!(chptr && tarptr))
         return(NULL);
 
+    /*
+     *  Skip initial IsSpecial chars. - FM
+     */
     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
         chptr++;
 
+    /*
+     *  Seek a first target match. - FM
+     */
     for (; *chptr != '\0'; chptr++) {
 
         if ((*chptr) == (*tarptr)) {
 	    int tarlen = 0;
+	    offset = len;
 	    len++;
 
-            /* see if they line up */
-            tmpchptr = chptr+1;
-            tmptarptr = tarptr+1;
-
-	    if (*tmptarptr == '\0') { /* one char target */
+            /*
+	     *  See if they line up.
+	     */
+            tmpchptr = (chptr + 1);
+            tmptarptr = (tarptr + 1);
+
+	    if (*tmptarptr == '\0') {
+		/*
+		 *  One char target.
+		 */
+		*nstartp = offset;
 		*nendp = len + 1;
 		 return(chptr);
 	    }
+	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
+		 *tmpchptr != '\0' &&
+		 !IsSpecialAttrChar(*tmpchptr)) {
+		/*
+		 *  Check the CJK mutibyte. - FM
+		 */
+		if (*tmpchptr == *tmptarptr) {
+		    /*
+		     *  It's a match.  Advance to next char. - FM
+		     */
+		    tmpchptr++;
+		    tmptarptr++;
+		    if (*tmptarptr == '\0') {
+		        /*
+			 *  One character match. - FM
+			 */
+			*nstartp = offset;
+			*nendp = len + tarlen;
+			return(chptr);
+		    }
+		    tarlen++;
+		} else {
+		    /*
+		     *  It's not a match, so go back to
+		     *  seeking a first target match. - FM
+		     */
+		    chptr++;
+		    continue;
+		}
+	    }
+	    /*
+	     *  See if the rest of the target matches. - FM
+	     */
             while (1) {
 		 if (!IsSpecialAttrChar(*tmpchptr)) {
-
-                    if ((*tmpchptr) != (*tmptarptr))
+		    if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) {
+			if (*tmpchptr == *tmptarptr &&
+			    *(tmpchptr + 1) == *(tmptarptr + 1) &&
+			    !IsSpecialAttrChar(*(tmpchptr + 1))) {
+			    tmpchptr++;
+			    tmptarptr++;
+			} else {
+			    break;
+			}
+		    } else if ((*tmpchptr) != (*tmptarptr)) {
                         break;
+		    }
 
-		    if (!IS_UTFEXTRA(*tmptarptr))
+		    if (!IS_UTF_EXTRA(*tmptarptr)) {
 			tarlen++;
+		    }
                     tmpchptr++;
                     tmptarptr++;
 
@@ -1241,60 +1436,73 @@ PUBLIC char * LYno_attr_mbcs_strstr ARGS4(char *,chptr, char *,tarptr,
                  }
 
                  if (*tmptarptr == '\0') {
+		    *nstartp = offset;
 		     *nendp = len + tarlen;
 		     return(chptr);
 		 }
-                 if (*tmpchptr == '\0')
+		if (*tmpchptr == '\0') {
                      break;
             }
-        } else if (!( IS_UTFEXTRA(*chptr) ||
+	    }
+        } else if (!(IS_UTF_EXTRA(*chptr) ||
 		      IsSpecialAttrChar(*chptr))) {
+	    if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
+		*(chptr + 1) != '\0' &&
+		!IsSpecialAttrChar(*(chptr + 1))) {
+		chptr++;
+	    }
 	    len++;
         }
     } /* end for */
 
     return(NULL);
 }
-#endif /* EXP_CHARTRANS */
 
-/*      Allocate a new copy of a string, and returns it
-*/
-PUBLIC char * SNACopy ARGS3 (char **,dest, CONST char *,src, int,n)
+/*
+ *  Allocate a new copy of a string, and returns it.
+ */
+PUBLIC char * SNACopy ARGS3(
+	char **,	dest,
+	CONST char *,	src,
+	int,		n)
 {
-  FREE(*dest);
-  if (src) {
-    *dest = (char *) calloc (1, n + 1);
-    if (*dest == NULL) {
-	fprintf(stderr,"Tried to calloc %d bytes\n",n);
-	outofmem(__FILE__, "SNACopy");
+    FREE(*dest);
+    if (src) {
+	*dest = (char *)calloc(1, n + 1);
+	if (*dest == NULL) {
+	    if (TRACE)
+	        fprintf(stderr, "Tried to calloc %d bytes\n", n);
+	    outofmem(__FILE__, "SNACopy");
+	}
+	strncpy (*dest, src, n);
+	*(*dest + n) = '\0'; /* terminate */
     }
-    strncpy (*dest, src, n);
-    *(*dest + n) = '\0'; /* terminate */
-  }
-  return *dest;
+    return *dest;
 }
 
-/*      String Allocate and Concatenate
-*/
-PUBLIC char * SNACat ARGS3 (char **,dest, CONST char *,src, int,n)
+/*
+ *  String Allocate and Concatenate.
+ */
+PUBLIC char * SNACat ARGS3(
+	char **,	dest,
+	CONST char *,	src,
+	int,		n)
 {
-  if (src && *src) {
-    if (*dest) {
-      int length = strlen (*dest);
-      *dest = (char *) realloc (*dest, length + n + 1);
-      if (*dest == NULL)
-          outofmem(__FILE__, "SNACat");
-      strncpy (*dest + length, src, n);
-      *(*dest + length + n) = '\0'; /* terminate */
-    } else {
-      *dest = (char *) calloc (1, strlen(src) + 1);
-      if (*dest == NULL)
-          outofmem(__FILE__, "SNACat");
-      strncpy (*dest, src, n);
-      *dest[n] = '\0'; /* terminate */
+    if (src && *src) {
+	if (*dest) {
+	    int length = strlen(*dest);
+	    *dest = (char *)realloc(*dest, length + n + 1);
+	    if (*dest == NULL)
+		outofmem(__FILE__, "SNACat");
+	    strncpy(*dest + length, src, n);
+	    *(*dest + length + n) = '\0'; /* terminate */
+	} else {
+	    *dest = (char *)calloc(1, strlen(src) + 1);
+	    if (*dest == NULL)
+		outofmem(__FILE__, "SNACat");
+	    strncpy(*dest, src, n);
+	    *dest[n] = '\0'; /* terminate */
+	}
     }
-  }
-  return *dest;
+    return *dest;
 }
-
-
diff --git a/src/LYStrings.h b/src/LYStrings.h
index ef1afd39..317406e8 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -15,13 +15,21 @@ extern int LYgetstr PARAMS((char *inputline, int hidden,
 extern char * LYstrstr PARAMS((char *chptr, char *tarptr));
 extern char * LYno_attr_char_strstr PARAMS((char *chptr, char *tarptr));
 extern char * LYno_attr_char_case_strstr PARAMS((char *chptr, char *tarptr));
-#ifdef EXP_CHARTRANS
 extern char * LYmbcsstrncpy PARAMS((char *dst, char *src, int n_bytes,
 				    int n_glyphs,	int enc));
-extern char * LYno_attr_mbcs_strstr PARAMS((char *chptr, char *tarptr,
-					    BOOL utf_flag, int *nendp));
-extern char * LYno_attr_mbcs_case_strstr PARAMS((char *chptr, char *tarptr,
-					    BOOL utf_flag, int *nendp));
+#ifdef EXP_CHARTRANS
+extern char * LYno_attr_mbcs_strstr PARAMS((
+	char *		chptr,
+	char *		tarptr,
+	BOOL		utf_flag,
+	int *		nstartp,
+	int *		nendp));
+extern char * LYno_attr_mbcs_case_strstr PARAMS((
+	char *		chptr,
+	char *		tarptr,
+	BOOL		utf_flag,
+	int *		nstartp,
+	int *		nendp));
 #endif
 
 extern char * SNACopy PARAMS((char **dest, CONST char *src, int n));
diff --git a/src/LYStructs.h b/src/LYStructs.h
index 2ea0de0d..fc438376 100644
--- a/src/LYStructs.h
+++ b/src/LYStructs.h
@@ -16,11 +16,13 @@ typedef struct link {
     char *hightext;
     char *hightext2;
     int hightext2_offset;
+    BOOL inUnderline;	/* TRUE when this link is in underlined context. */
     int lx;
     int ly;
-    int type;      /* type of link, Forms, WWW, etc */
-    int anchor_number;   /* the anchor number within the Gridtext structure */
-    struct _FormInfo *form;  /* pointer to form info */
+    int type;		/* Type of link, Forms, WWW, etc. */
+    int anchor_number;	/* The anchor number within the HText structure.  */
+    int anchor_line_num;/* The anchor line number in the HText structure. */
+    struct _FormInfo *form;	/* Pointer to form info. */
 } linkstruct; 
 extern linkstruct links[MAXLINKS];
 extern int nlinks;
diff --git a/src/LYTraversal.c b/src/LYTraversal.c
index 1925860c..c9c7627b 100644
--- a/src/LYTraversal.c
+++ b/src/LYTraversal.c
@@ -32,6 +32,7 @@ PUBLIC BOOLEAN lookup ARGS1(char *,target)
             exit(-1);
 	} else {
             fclose(ifp);
+	    chmod(TRAVERSE_FILE, 0600);
             return(FALSE);
         }
     }
@@ -69,6 +70,7 @@ PUBLIC void add_to_table ARGS1(char *,target)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+    chmod(TRAVERSE_FILE, 0600);
 
     fprintf(ifp,"%s\n",target);
 
@@ -95,6 +97,7 @@ PUBLIC void add_to_traverse_list ARGS2(char *,fname, char *,prev_link_name)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+    chmod(TRAVERSE_FOUND_FILE, 0600);
 
     fprintf(ifp,"%s	%s\n",fname, prev_link_name);
 
@@ -113,6 +116,7 @@ PUBLIC void dump_traversal_history NOARGS
         perror("unable to open traversal file");
 	return;
     }
+    chmod(TRAVERSE_FILE, 0600);
 
     fprintf(ifp, "\n\nTRAVERSAL WAS INTERUPTED\n\n\
 	    here is a list of the history stack so that you may rebuild\n\n");
@@ -144,6 +148,7 @@ PUBLIC void add_to_reject_list ARGS1(char *,target)
 #endif /* SIGTSTP */
 	exit(-1);
     }
+    chmod(TRAVERSE_REJECT_FILE, 0600);
 
     fprintf(ifp,"%s\n",target);
 
diff --git a/src/LYUpload.c b/src/LYUpload.c
index d6cbb1c5..48c6f19d 100644
--- a/src/LYUpload.c
+++ b/src/LYUpload.c
@@ -189,6 +189,7 @@ retry:
     system(cmd);
     fflush(stdout);
     start_curses();
+    chmod(buffer, 0600);
     /* don't remove(file); */
 
     return 1;
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 37ad23f2..5d22ca60 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -1,5 +1,6 @@
 #include "HTUtils.h"
 #include "tcp.h"
+#include <ctype.h>
 #include "HTParse.h"
 #include "HTAccess.h"
 #include "HTCJK.h"
@@ -10,9 +11,7 @@
 #include "LYGlobalDefs.h"
 #include "LYSignal.h"
 #include "GridText.h"
-#ifdef EXP_CHARTRANS
 #include "LYCharSets.h"
-#endif /* EXP_CHARTRANS */
 
 #ifdef DOSPATH
 #include "HTDOS.h"
@@ -54,6 +53,8 @@
 #include "LYStyle.h"
 #endif
 
+#undef hline   /* FIXME: this is a curses feature used as a variable here */
+
 #ifdef SVR4_BSDSELECT
 extern int BSDselect PARAMS((int nfds, fd_set * readfds, fd_set * writefds,
 	 		     fd_set * exceptfds, struct timeval * timeout));
@@ -91,22 +92,35 @@ PRIVATE HTList * localhost_aliases = NULL;	/* Hosts to treat as local */
 PUBLIC  HTList * sug_filenames = NULL;		/* Suggested filenames   */
 
 /*
- * highlight (or unhighlight) a given link
+ *  Highlight (or unhighlight) a given link.
  */
-PUBLIC void highlight ARGS2(
+PUBLIC void highlight ARGS3(
 	int,		flag,
-	int,		cur)
+	int,		cur,
+	char *,		target)
 {
     char buffer[200];
     int i;
-    char tmp[3];
+    char tmp[7], *cp;
+    char *theData = NULL;
+    char *Data = NULL;
+    int Offset, HitOffset, tLen;
+    int LenNeeded;
+    BOOL TargetEmphasisON = FALSE;
+#ifdef EXP_CHARTRANS
+    BOOL utf_flag = (LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8);
+#else
+#define utf_flag TRUE
+#endif
 
     tmp[0] = tmp[1] = tmp[2] = '\0';
 
-    /* Bug in history code can cause -1 to be sent, which will yield
-    ** an ACCVIO when LYstrncpy() is called with a nonsense pointer.
-    ** This works around the bug, for now. -- FM
-    */
+    /*
+     *  Bugs in the history code might cause -1 to be sent for cur, which
+     *  yields a crash when LYstrncpy() is called with a nonsense pointer.
+     *  As far as I know, such bugs have been squashed, but if they should
+     *  reappear, this works around them. - FM
+     */
     if (cur < 0)
         cur = 0;
 
@@ -117,7 +131,7 @@ PUBLIC void highlight ARGS2(
 #endif
 	move(links[cur].ly, links[cur].lx);
 #ifndef USE_COLOR_STYLE
-	lynx_start_link_color (flag == ON);
+	lynx_start_link_color (flag == ON, links[cur].inUnderline);
 #else
 	if (flag == ON) { 
 	    LynxChangeStyle(s_alink, ABS_ON, 0);
@@ -125,7 +139,8 @@ PUBLIC void highlight ARGS2(
 		/* the logic is flawed here - no provision is made for links that
 		** aren't coloured as [s_a] by default - rjp
 		*/
-	    if (cached_styles[LYP][LXP]) {
+	    if (LYP >= 0 && LYP < CACHEH && LXP >= 0 && LXP < CACHEW &&
+		cached_styles[LYP][LXP]) {
 		LynxChangeStyle(cached_styles[LYP][LXP], ABS_ON, 0);
 	    }
 	    else {
@@ -136,75 +151,1519 @@ PUBLIC void highlight ARGS2(
 
 	if (links[cur].type == WWW_FORM_LINK_TYPE) {
 	    int len;
-	    int avail_space = (LYcols-links[cur].lx)-1;
+	    int avail_space = (LYcols - links[cur].lx) - 1;
 
 	    LYstrncpy(buffer,
 	    	      (links[cur].hightext ?
-		       links[cur].hightext : ""), 
-		      (avail_space > links[cur].form->size ? 
+		       links[cur].hightext : ""),
+		      (avail_space > links[cur].form->size ?
 				      links[cur].form->size : avail_space));
-	    addstr(buffer);  
+	    addstr(buffer);
 
 	    len = strlen(buffer);
 	    for (; len < links[cur].form->size && len < avail_space; len++)
 	        addch('_');
 
 	} else {
-
-	    /* copy into the buffer only what will fit within the
-	     * width of the screen
+	    /*
+	     *  Copy into the buffer only what will fit
+	     *  within the width of the screen.
 	     */
 #ifdef EXP_CHARTRANS
-	    LYmbcsstrncpy(buffer,(links[cur].hightext ?
-				  links[cur].hightext : ""), 199,
-			  LYcols - links[cur].lx - 1,
-		       (LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8));
+	    LYmbcsstrncpy(buffer,
+			  (links[cur].hightext ?
+			   links[cur].hightext : ""),
+			  (sizeof(buffer) - 1),
+			  ((LYcols - 1) - links[cur].lx),
+			  utf_flag);
 #else
 	    LYstrncpy(buffer,
 	    	      (links[cur].hightext ?
 		       links[cur].hightext : ""),
 		      LYcols-links[cur].lx-1);
+#define LYmbcsstrncpy(dest,src,n,n_glyphs,enc) LYstrncpy(dest, src, n)
+#define LYmbcsstrlen(str,utf_flag) strlen(str)
 #endif /* EXP_CHARTRANS */
 	    addstr(buffer);  
 	}
 
-	/* display a second line as well */
+	/*
+	 *  Display a second line as well.
+	 */
 	if (links[cur].hightext2 && links[cur].ly < display_lines) {
-	    lynx_stop_link_color (flag == ON);
+	    lynx_stop_link_color (flag == ON, links[cur].inUnderline);
 
 	    addch('\n');
-	    for (i=0; i < links[cur].hightext2_offset; i++)
-		addch(' ');
+	    for (i = 0; i < links[cur].hightext2_offset; i++)
+	        addch(' ');
 
 #ifndef USE_COLOR_STYLE
-	    lynx_start_link_color (flag == ON);
+	    lynx_start_link_color (flag == ON, links[cur].inUnderline);
 #else
 	    LynxChangeStyle(flag == ON ? s_alink : s_a, ABS_ON, 0);
 #endif
 
 	    for (i = 0; (tmp[0] = links[cur].hightext2[i]) != '\0' &&
-		      i+links[cur].hightext2_offset < LYcols; i++) {
+	    	        i+links[cur].hightext2_offset < LYcols; i++) {
 		if (!IsSpecialAttrChar(links[cur].hightext2[i])) {
-		    /* For CJK strings, by Masanobu Kimura */
+	    /*
+		     *  For CJK strings, by Masanobu Kimura.
+	     */
 		    if (HTCJK != NOCJK && !isascii(tmp[0])) {
 			tmp[1] = links[cur].hightext2[++i];
 			addstr(tmp);
 			tmp[1] = '\0';
-		    } else {
+	} else {
 			addstr(tmp);
 		    }
 		 }
 	    }
 	}
-	lynx_stop_link_color (flag == ON);
+	lynx_stop_link_color (flag == ON, links[cur].inUnderline);
 
 #if defined(FANCY_CURSES) || defined(USE_SLANG)
+	/*
+	 *  If we have an emphasized WHEREIS hit in the highlighted
+	 *  text, restore the emphasis.  Note that we never emphasize
+	 *  the first and last characters of the highlighted text when
+	 *  we are making the link current, so the link attributes for
+	 *  the current link will persist at the beginning and end,
+	 *  providing an indication to the user that it has been made
+	 *  current.   Also note that we use HText_getFirstTargetInLine()
+	 *  to determine if there's a hit in the HText structure line
+	 *  containing the link, and if so, get back a copy of the line
+	 *  starting at that first hit (which might be before or after
+	 *  our link), and with all IsSpecial characters stripped, so we
+	 *  don't need to deal with them here. - FM
+	 */
+	if (target && *target && links[cur].type == WWW_LINK_TYPE &&
+	    links[cur].hightext && *links[cur].hightext &&
+	    HText_getFirstTargetInLine(HTMainText,
+				       links[cur].anchor_line_num,
+				       utf_flag,
+				       (int *)&Offset,
+				       (int *)&tLen,
+				       (char **)&theData,
+				       target)) {
+	    int itmp, written, len, y, offset;
+	    char *data;
+	    int tlen = strlen(target);
+	    int hlen, hLen;
+	    int hline = links[cur].ly, hoffset = links[cur].lx;
+	    size_t utf_extra = 0;
+
+	    /*
+	     *  Copy into the buffer only what will fit
+	     *  up to the right border of the screen. - FM
+	     */
+#ifdef EXP_CHARTRANS
+	    LYmbcsstrncpy(buffer,
+			  (links[cur].hightext ?
+			   links[cur].hightext : ""),
+			  (sizeof(buffer) - 1),
+			  ((LYcols - 1) - links[cur].lx),
+			  utf_flag);
+#else
+         LYstrncpy(buffer,
+                      links[cur].hightext,
+                      ((LYcols - 1) - hoffset));
+#endif /* EXP_CHARTRANS */
+	    hlen = strlen(buffer);
+	    hLen = ((HTCJK != NOCJK || utf_flag) ?
+		  LYmbcsstrlen(buffer, utf_flag) : hlen);
+
+	    /*
+	     *  Break out if the first hit in the line
+	     *  starts after this link. - FM
+	     */
+	    if (Offset >= (hoffset + hLen)) {
+		goto highlight_search_hightext2;
+	    }
+
+	    /*
+	     *  Recursively skip hits that end before this link, and
+	     *  break out if there is no hit beyond those. - FM
+	     */
+	    Data = theData;
+	    while ((Offset < hoffset) &&
+		   ((Offset + tLen) <= hoffset)) {
+	        data = (Data + tlen);
+		offset = (Offset + tLen);
+		if ((case_sensitive ?
+		     (cp = LYno_attr_mbcs_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL :
+		     (cp = LYno_attr_mbcs_case_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL) &&
+		    (offset + LenNeeded) < LYcols) {
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		} else {
+		    goto highlight_search_hightext2;
+		}
+	    }
+	    data = buffer;
+	    offset = hoffset;
+
+	    /*
+	     *  If the hit starts before the hightext, and ends
+	     *  in or beyond the hightext, restore the emphasis,
+	     *  skipping the first and last characters of the
+	     *  hightext if we're making the link current. - FM
+	     */
+	    if ((Offset < offset) &&
+		((Offset + tLen) > offset)) {
+		itmp = 0;
+		written = 0;
+		len = (tlen - (offset - Offset)); 
+
+		/*
+		 *  Go to the start of the hightext and
+		 *  handle its first character. - FM
+		 */
+		move(hline, offset);
+		tmp[0] = data[itmp];
+		if (utf_flag && !isascii(tmp[0])) {
+		    if ((*tmp & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*tmp & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*tmp & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*tmp & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*tmp & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			/*
+			 *  Garbage.
+			 */
+			utf_extra = 0;
+		    }
+		    if (strlen(&data[itmp+1]) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
+			utf_extra = 0;
+		    }
+		}
+		if (utf_extra) {
+		    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		    tmp[utf_extra+1] = '\0';
+		    itmp += utf_extra;
+		    /*
+		     *  Start emphasis immediately if we are
+		     *  making the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    tmp[1] = '\0';
+		    written += (utf_extra + 1);
+		    utf_extra = 0;
+		} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
+		    tmp[1] = data[++itmp];
+		    /*
+		     *  Start emphasis immediately if we are
+		     *  making the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    tmp[1] = '\0';
+		    written += 2;
+		} else {
+		    /*
+		     *  Start emphasis immediately if we are making
+		     *  the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    written++;
+		}
+		itmp++;
+		/*
+		 *  Start emphasis after the first character
+		 *  if we are making the link current and this
+		 *  is not the last character. - FM
+		 */
+		if (!TargetEmphasisON &&
+		    data[itmp] != '\0') {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		}
+
+		/*
+		 *  Handle the remaining characters. - FM
+		 */
+		for (;
+		     written < len && (tmp[0] = data[itmp]) != '\0';
+		     itmp++)  {
+		    /*
+		     *  Print all the other target chars, except
+		     *  the last character if it is also the last
+		     *  character of hightext and we are making
+		     *  the link current. - FM
+		     */
+		    if (utf_flag && !isascii(tmp[0])) {
+			if ((*tmp & 0xe0) == 0xc0) {
+			    utf_extra = 1;
+			} else if ((*tmp & 0xf0) == 0xe0) {
+			    utf_extra = 2;
+			} else if ((*tmp & 0xf8) == 0xf0) {
+			    utf_extra = 3;
+			} else if ((*tmp & 0xfc) == 0xf8) {
+			    utf_extra = 4;
+			} else if ((*tmp & 0xfe) == 0xfc) {
+			    utf_extra = 5;
+			} else {
+			    /*
+			     *  Garbage.
+			     */
+			    utf_extra = 0;
+			}
+			if (strlen(&data[itmp+1]) < utf_extra) {
+			    /*
+			     *  Shouldn't happen.
+			     */
+			    utf_extra = 0;
+			}
+		    }
+		    if (utf_extra) {
+			strncpy(&tmp[1], &data[itmp+1], utf_extra);
+			tmp[(utf_extra + 1)] = '\0';
+			itmp += utf_extra;
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			tmp[1] = '\0';
+			written += (utf_extra + 1);
+			utf_extra = 0;
+		    } else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			/*
+			 *  For CJK strings, by Masanobu Kimura.
+			 */
+			tmp[1] = data[++itmp];
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			tmp[1] = '\0';
+			written += 2;
+		    } else {
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			written++;
+		    }
+		}
+
+		/*
+		 *  Stop the emphasis if we haven't already, then
+		 *  reset the offset to our current position in
+		 *  the line, and if that is beyond the link, or
+		 *  or we are making the link current and it is
+		 *  the last character of the hightext, we are
+		 *  done. - FM
+		 */
+		if (TargetEmphasisON) {
+		    LYstopTargetEmphasis();
+		    TargetEmphasisON = FALSE;
+		}
+		LYGetYX(y, offset);
+		if (offset >=
+		    (hoffset +
+		     (flag == ON ? (hLen - 1) : hLen)))  {
+		    goto highlight_search_hightext2;
+		}
+
+		/*
+		 *  See if we have another hit that starts
+		 *  within the hightext. - FM
+		 */
+		data = (Data + (offset - Offset));
+		if ((case_sensitive ?
+		     (cp = LYno_attr_mbcs_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL :
+		     (cp = LYno_attr_mbcs_case_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL) &&
+		    (offset + LenNeeded) < LYcols) {
+		    /*
+		     *  If the hit starts after the end of the hightext,
+		     *  or we are making the link current and the hit
+		     *  starts at its last character, we are done. - FM
+		     */
+		    if ((HitOffset + offset) >=
+			(hoffset +
+			 (flag == ON ? (hLen - 1) : hLen)))  {
+			goto highlight_search_hightext2;
+		    }
+
+		    /*
+		     *  Set up the data and offset for the hit, and let
+		     *  the code for within hightext hits handle it. - FM
+		     */
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		    data = buffer;
+		    offset = hoffset;
+		    goto highlight_hit_within_hightext;
+		}
+		goto highlight_search_hightext2;
+	    }
+
+highlight_hit_within_hightext:
+	    /*
+	     *  If we get to here, the hit starts within the
+	     *  hightext.  If we are making the link current
+	     *  and it's the last character in the hightext,
+	     *  we are done.  Otherwise, move there and start
+	     *  restoring the emphasis. - FM
+	     */
+	    if ((Offset - offset) >
+		(flag == ON ? (hLen - 1) : hLen))  {
+		goto highlight_search_hightext2;
+	    }
+	    data += (Offset - offset);
+	    offset = Offset;
+	    itmp = 0;
+	    written = 0;
+	    len = tlen;
+
+	    /*
+	     *  Go to the start of the hit and
+	     *  handle its first character. - FM
+	     */
+	    move(hline, offset);
+	    tmp[0] = data[itmp];
+	    if (utf_flag && !isascii(tmp[0])) {
+		if ((*tmp & 0xe0) == 0xc0) {
+		    utf_extra = 1;
+		} else if ((*tmp & 0xf0) == 0xe0) {
+		    utf_extra = 2;
+		} else if ((*tmp & 0xf8) == 0xf0) {
+		    utf_extra = 3;
+		} else if ((*tmp & 0xfc) == 0xf8) {
+		    utf_extra = 4;
+		} else if ((*tmp & 0xfe) == 0xfc) {
+		    utf_extra = 5;
+		} else {
+		    /*
+		     *  Garbage.
+		     */
+		    utf_extra = 0;
+		}
+		if (strlen(&data[itmp+1]) < utf_extra) {
+		    /*
+		     *  Shouldn't happen.
+		     */
+		    utf_extra = 0;
+		}
+	    }
+	    if (utf_extra) {
+		strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		tmp[utf_extra+1] = '\0';
+		itmp += utf_extra;
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		tmp[1] = '\0';
+		written += (utf_extra + 1);
+		utf_extra = 0;
+	    } else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		/*
+		 *  For CJK strings, by Masanobu Kimura.
+		 */
+		tmp[1] = data[++itmp];
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		tmp[1] = '\0';
+		written += 2;
+	    } else {
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		written++;
+	    }
+	    itmp++;
+	    /*
+	     *  Start emphasis after the first character
+	     *  if we are making the link current and this
+	     *  is not the last character. - FM
+	     */
+	    if (!TargetEmphasisON &&
+		data[itmp] != '\0') {
+		LYstartTargetEmphasis();
+		TargetEmphasisON = TRUE;
+	    }
+
+	    for (;
+		 written < len && (tmp[0] = data[itmp]) != '\0';
+		 itmp++)  {
+		/*
+		 *  Print all the other target chars, except
+		 *  the last character if it is also the last
+		 *  character of hightext and we are making
+		 *  the link current. - FM
+		 */
+		if (utf_flag && !isascii(tmp[0])) {
+		    if ((*tmp & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*tmp & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*tmp & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*tmp & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*tmp & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			/*
+			 *  Garbage.
+			 */
+			utf_extra = 0;
+		    }
+		    if (strlen(&data[itmp+1]) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
+			utf_extra = 0;
+		    }
+		}
+		if (utf_extra) {
+		    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		    tmp[utf_extra+1] = '\0';
+		    itmp += utf_extra;
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    tmp[1] = '\0';
+		    written += (utf_extra + 1);
+		    utf_extra = 0;
+		} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
+		    tmp[1] = data[++itmp];
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    tmp[1] = '\0';
+		    written += 2;
+		} else {
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    written++;
+		}
+	    }
+
+	    /*
+	     *  Stop the emphasis if we haven't already, then reset
+	     *  the offset to our current position in the line, and
+	     *  if that is beyond the link, or we are making the link
+	     *  current and it is the last character in the hightext,
+	     *  we are done. - FM
+	     */
+	    if (TargetEmphasisON) {
+		LYstopTargetEmphasis();
+		TargetEmphasisON = FALSE;
+	    }
+	    LYGetYX(y, offset);
+	    if (offset >=
+	        (hoffset + (flag == ON ? (hLen - 1) : hLen))) {
+		goto highlight_search_hightext2;
+	    }
+
+	    /*
+	     *  See if we have another hit that starts
+	     *  within the hightext. - FM
+	     */
+	    data = (Data + (offset - Offset));
+	    if ((case_sensitive ?
+		 (cp = LYno_attr_mbcs_strstr(data,
+					     target,
+					     utf_flag,
+					     &HitOffset,
+					     &LenNeeded)) != NULL :
+		 (cp = LYno_attr_mbcs_case_strstr(data,
+					     target,
+					     utf_flag,
+					     &HitOffset,
+					     &LenNeeded)) != NULL) &&
+		(offset + LenNeeded) < LYcols) {
+		/*
+		 *  If the hit starts after the end of the hightext,
+		 *  or we are making the link current and the hit
+		 *  starts at its last character, we are done. - FM
+		 */
+		if ((HitOffset + offset) >=
+		    (hoffset +
+		     (flag == ON ? (hLen - 1) : hLen)))  {
+		    goto highlight_search_hightext2;
+		}
+
+		/*
+		 *  If the target extends beyond our buffer, emphasize
+		 *  everything in the hightext starting at this hit.
+		 *  Otherwise, set up the data and offsets, and loop
+		 *  back. - FM
+		 */
+		if ((HitOffset + (offset + tLen)) >=
+		    (hoffset + hLen)) {
+		    offset = (HitOffset + offset);
+		    data = (buffer + (offset - hoffset));
+		    move(hline, offset);
+		    itmp = 0;
+		    written = 0;
+		    len = strlen(data);
+
+		    /*
+		     *  Turn the emphasis back on. - FM
+		     */
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    for (;
+			 written < len && (tmp[0] = data[itmp]) != '\0';
+			 itmp++)  {
+			/*
+			 *  Print all the other target chars, except
+			 *  the last character if it is also the last
+			 *  character of hightext and we are making
+			 *  the link current. - FM
+			 */
+			if (utf_flag && !isascii(tmp[0])) {
+			    if ((*tmp & 0xe0) == 0xc0) {
+				utf_extra = 1;
+			    } else if ((*tmp & 0xf0) == 0xe0) {
+				utf_extra = 2;
+			    } else if ((*tmp & 0xf8) == 0xf0) {
+				utf_extra = 3;
+			    } else if ((*tmp & 0xfc) == 0xf8) {
+				utf_extra = 4;
+			    } else if ((*tmp & 0xfe) == 0xfc) {
+				utf_extra = 5;
+			    } else {
+				/*
+				 *  Garbage.
+				 */
+				utf_extra = 0;
+			    }
+			    if (strlen(&data[itmp+1]) < utf_extra) {
+				/*
+				 *  Shouldn't happen.
+				 */
+				utf_extra = 0;
+			    }
+			}
+			if (utf_extra) {
+			    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+			    tmp[(utf_extra + 1)] = '\0';
+			    itmp += utf_extra;
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+				LYGetYX(y, offset);
+				move(hline, (offset + 1));
+			    } else {
+				addstr(tmp);
+			    }
+			    tmp[1] = '\0';
+			    written += (utf_extra + 1);
+			    utf_extra = 0;
+			} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			    /*
+			     *  For CJK strings, by Masanobu Kimura.
+			     */
+			    tmp[1] = data[++itmp];
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+			    } else {
+				addstr(tmp);
+			    }
+			    tmp[1] = '\0';
+			    written += 2;
+			} else {
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+			    } else {
+				addstr(tmp);
+			    }
+			    written++;
+			}
+		    }
+		    /*
+		     *  Turn off the emphasis if we haven't already,
+		     *  and then we're done. - FM
+		     */
+		    if (TargetEmphasisON) {
+		        LYstopTargetEmphasis();
+		    }
+		    goto highlight_search_hightext2;
+		} else {
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		    data = buffer;
+		    offset = hoffset;
+		    goto highlight_hit_within_hightext;
+		}
+	    }
+	    goto highlight_search_hightext2;
+	}
+highlight_search_hightext2:
+	if (target && *target && links[cur].type == WWW_LINK_TYPE &&
+	    links[cur].hightext2 && *links[cur].hightext2 &&
+	    links[cur].ly < display_lines &&
+	    HText_getFirstTargetInLine(HTMainText,
+				       (links[cur].anchor_line_num + 1),
+				       utf_flag,
+				       (int *)&Offset,
+				       (int *)&tLen,
+				       (char **)&theData,
+				       target)) {
+	    int itmp, written, len, y, offset;
+	    char *data;
+	    int tlen = strlen(target);
+	    int hlen, hLen;
+	    int hline = (links[cur].ly + 1);
+	    int hoffset = links[cur].hightext2_offset;
+	    size_t utf_extra = 0;
+
+	    /*
+	     *  Copy into the buffer only what will fit
+	     *  up to the right border of the screen. - FM
+	     */
+	    LYmbcsstrncpy(buffer,
+			  (links[cur].hightext2 ?
+			   links[cur].hightext2 : ""),
+			  (sizeof(buffer) - 1),
+			  ((LYcols - 1) - links[cur].hightext2_offset),
+			  utf_flag);
+	    hlen = strlen(buffer);
+	    hLen = ((HTCJK != NOCJK || utf_flag) ?
+		  LYmbcsstrlen(buffer, utf_flag) : hlen);
+
+	    /*
+	     *  Break out if the first hit in the line
+	     *  starts after this link. - FM
+	     */
+	    if (Offset >= (hoffset + hLen)) {
+		goto highlight_search_done;
+	    }
+
+	    /*
+	     *  Recursively skip hits that end before this link, and
+	     *  break out if there is no hit beyond those. - FM
+	     */
+	    Data = theData;
+	    while ((Offset < hoffset) &&
+		   ((Offset + tLen) <= hoffset)) {
+	        data = (Data + tlen);
+		offset = (Offset + tLen);
+		if ((case_sensitive ?
+		     (cp = LYno_attr_mbcs_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL :
+		     (cp = LYno_attr_mbcs_case_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL) &&
+		    (offset + LenNeeded) < LYcols) {
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		} else {
+		    goto highlight_search_done;
+		}
+	    }
+	    data = buffer;
+	    offset = hoffset;
+
+	    /*
+	     *  If the hit starts before the hightext2, and ends
+	     *  in or beyond the hightext2, restore the emphasis,
+	     *  skipping the first and last characters of the
+	     *  hightext2 if we're making the link current. - FM
+	     */
+	    if ((Offset < offset) &&
+		((Offset + tLen) > offset)) {
+		itmp = 0;
+		written = 0;
+		len = (tlen - (offset - Offset)); 
+
+		/*
+		 *  Go to the start of the hightext2 and
+		 *  handle its first character. - FM
+		 */
+		move(hline, offset);
+		tmp[0] = data[itmp];
+		if (utf_flag && !isascii(tmp[0])) {
+		    if ((*tmp & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*tmp & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*tmp & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*tmp & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*tmp & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			/*
+			 *  Garbage.
+			 */
+			utf_extra = 0;
+		    }
+		    if (strlen(&data[itmp+1]) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
+			utf_extra = 0;
+		    }
+		}
+		if (utf_extra) {
+		    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		    tmp[utf_extra+1] = '\0';
+		    itmp += utf_extra;
+		    /*
+		     *  Start emphasis immediately if we are
+		     *  making the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    tmp[1] = '\0';
+		    written += (utf_extra + 1);
+		    utf_extra = 0;
+		} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
+		    tmp[1] = data[++itmp];
+		    /*
+		     *  Start emphasis immediately if we are
+		     *  making the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    tmp[1] = '\0';
+		    written += 2;
+		} else {
+		    /*
+		     *  Start emphasis immediately if we are making
+		     *  the link non-current. - FM
+		     */
+		    if (flag != ON) {
+			LYstartTargetEmphasis();
+			TargetEmphasisON = TRUE;
+			addstr(tmp);
+		    } else {
+			move(hline, (offset + 1));
+		    }
+		    written++;
+		}
+		itmp++;
+		/*
+		 *  Start emphasis after the first character
+		 *  if we are making the link current and this
+		 *  is not the last character. - FM
+		 */
+		if (!TargetEmphasisON &&
+		    data[itmp] != '\0') {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		}
+
+		/*
+		 *  Handle the remaining characters. - FM
+		 */
+		for (;
+		     written < len && (tmp[0] = data[itmp]) != '\0';
+		     itmp++)  {
+		    /*
+		     *  Print all the other target chars, except
+		     *  the last character if it is also the last
+		     *  character of hightext2 and we are making
+		     *  the link current. - FM
+		     */
+		    if (utf_flag && !isascii(tmp[0])) {
+			if ((*tmp & 0xe0) == 0xc0) {
+			    utf_extra = 1;
+			} else if ((*tmp & 0xf0) == 0xe0) {
+			    utf_extra = 2;
+			} else if ((*tmp & 0xf8) == 0xf0) {
+			    utf_extra = 3;
+			} else if ((*tmp & 0xfc) == 0xf8) {
+			    utf_extra = 4;
+			} else if ((*tmp & 0xfe) == 0xfc) {
+			    utf_extra = 5;
+			} else {
+			    /*
+			     *  Garbage.
+			     */
+			    utf_extra = 0;
+			}
+			if (strlen(&data[itmp+1]) < utf_extra) {
+			    /*
+			     *  Shouldn't happen.
+			     */
+			    utf_extra = 0;
+			}
+		    }
+		    if (utf_extra) {
+			strncpy(&tmp[1], &data[itmp+1], utf_extra);
+			tmp[(utf_extra + 1)] = '\0';
+			itmp += utf_extra;
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext2 if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			tmp[1] = '\0';
+			written += (utf_extra + 1);
+			utf_extra = 0;
+		    } else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			/*
+			 *  For CJK strings, by Masanobu Kimura.
+			 */
+			tmp[1] = data[++itmp];
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext2 if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			tmp[1] = '\0';
+			written += 2;
+		    } else {
+			/*
+			 *  Make sure we don't restore emphasis to
+			 *  the last character of hightext2 if we
+			 *  are making the link current. - FM
+			 */
+			if (flag == ON && data[(itmp + 1)] == '\0') {
+			    LYstopTargetEmphasis();
+			    TargetEmphasisON = FALSE;
+			    LYGetYX(y, offset);
+			    move(hline, (offset + 1));
+			} else {
+			    addstr(tmp);
+			}
+			written++;
+		    }
+		}
+
+		/*
+		 *  Stop the emphasis if we haven't already, then
+		 *  reset the offset to our current position in
+		 *  the line, and if that is beyond the link, or
+		 *  or we are making the link current and it is
+		 *  the last character of the hightext2, we are
+		 *  done. - FM
+		 */
+		if (TargetEmphasisON) {
+		    LYstopTargetEmphasis();
+		    TargetEmphasisON = FALSE;
+		}
+		LYGetYX(y, offset);
+		if (offset >=
+		    (hoffset +
+		     (flag == ON ? (hLen - 1) : hLen)))  {
+		    goto highlight_search_done;
+		}
+
+		/*
+		 *  See if we have another hit that starts
+		 *  within the hightext2. - FM
+		 */
+		data = (Data + (offset - Offset));
+		if ((case_sensitive ?
+		     (cp = LYno_attr_mbcs_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL :
+		     (cp = LYno_attr_mbcs_case_strstr(data,
+						 target,
+						 utf_flag,
+						 &HitOffset,
+						 &LenNeeded)) != NULL) &&
+		    (offset + LenNeeded) < LYcols) {
+		    /*
+		     *  If the hit starts after the end of the hightext2,
+		     *  or we are making the link current and the hit
+		     *  starts at its last character, we are done. - FM
+		     */
+		    if ((HitOffset + offset) >=
+			(hoffset +
+			 (flag == ON ? (hLen - 1) : hLen)))  {
+			goto highlight_search_done;
+		    }
+
+		    /*
+		     *  Set up the data and offset for the hit, and let
+		     *  the code for within hightext2 hits handle it. - FM
+		     */
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		    data = buffer;
+		    offset = hoffset;
+		    goto highlight_hit_within_hightext2;
+		}
+		goto highlight_search_done;
+	    }
+
+highlight_hit_within_hightext2:
+	    /*
+	     *  If we get to here, the hit starts within the
+	     *  hightext2.  If we are making the link current
+	     *  and it's the last character in the hightext2,
+	     *  we are done.  Otherwise, move there and start
+	     *  restoring the emphasis. - FM
+	     */
+	    if ((Offset - offset) >
+		(flag == ON ? (hLen - 1) : hLen))  {
+		goto highlight_search_done;
+	    }
+	    data += (Offset - offset);
+	    offset = Offset;
+	    itmp = 0;
+	    written = 0;
+	    len = tlen;
+
+	    /*
+	     *  Go to the start of the hit and
+	     *  handle its first character. - FM
+	     */
+	    move(hline, offset);
+	    tmp[0] = data[itmp];
+	    if (utf_flag && !isascii(tmp[0])) {
+		if ((*tmp & 0xe0) == 0xc0) {
+		    utf_extra = 1;
+		} else if ((*tmp & 0xf0) == 0xe0) {
+		    utf_extra = 2;
+		} else if ((*tmp & 0xf8) == 0xf0) {
+		    utf_extra = 3;
+		} else if ((*tmp & 0xfc) == 0xf8) {
+		    utf_extra = 4;
+		} else if ((*tmp & 0xfe) == 0xfc) {
+		    utf_extra = 5;
+		} else {
+		    /*
+		     *  Garbage.
+		     */
+		    utf_extra = 0;
+		}
+		if (strlen(&data[itmp+1]) < utf_extra) {
+		    /*
+		     *  Shouldn't happen.
+		     */
+		    utf_extra = 0;
+		}
+	    }
+	    if (utf_extra) {
+		strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		tmp[utf_extra+1] = '\0';
+		itmp += utf_extra;
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext2. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		tmp[1] = '\0';
+		written += (utf_extra + 1);
+		utf_extra = 0;
+	    } else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		/*
+		 *  For CJK strings, by Masanobu Kimura.
+		 */
+		tmp[1] = data[++itmp];
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext2. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		tmp[1] = '\0';
+		written += 2;
+	    } else {
+		/*
+		 *  Start emphasis immediately if we are making
+		 *  the link non-current, or we are making it
+		 *  current but this is not the first character
+		 *  of the hightext2. - FM
+		 */
+		if (flag != ON || offset > hoffset) {
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    addstr(tmp);
+		} else {
+		    move(hline, (offset + 1));
+		}
+		written++;
+	    }
+	    itmp++;
+	    /*
+	     *  Start emphasis after the first character
+	     *  if we are making the link current and this
+	     *  is not the last character. - FM
+	     */
+	    if (!TargetEmphasisON &&
+		data[itmp] != '\0') {
+		LYstartTargetEmphasis();
+		TargetEmphasisON = TRUE;
+	    }
+
+	    for (;
+		 written < len && (tmp[0] = data[itmp]) != '\0';
+		 itmp++)  {
+		/*
+		 *  Print all the other target chars, except
+		 *  the last character if it is also the last
+		 *  character of hightext2 and we are making
+		 *  the link current. - FM
+		 */
+		if (utf_flag && !isascii(tmp[0])) {
+		    if ((*tmp & 0xe0) == 0xc0) {
+			utf_extra = 1;
+		    } else if ((*tmp & 0xf0) == 0xe0) {
+			utf_extra = 2;
+		    } else if ((*tmp & 0xf8) == 0xf0) {
+			utf_extra = 3;
+		    } else if ((*tmp & 0xfc) == 0xf8) {
+			utf_extra = 4;
+		    } else if ((*tmp & 0xfe) == 0xfc) {
+			utf_extra = 5;
+		    } else {
+			/*
+			 *  Garbage.
+			 */
+			utf_extra = 0;
+		    }
+		    if (strlen(&data[itmp+1]) < utf_extra) {
+			/*
+			 *  Shouldn't happen.
+			 */
+			utf_extra = 0;
+		    }
+		}
+		if (utf_extra) {
+		    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+		    tmp[utf_extra+1] = '\0';
+		    itmp += utf_extra;
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext2 if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    tmp[1] = '\0';
+		    written += (utf_extra + 1);
+		    utf_extra = 0;
+		} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+		    /*
+		     *  For CJK strings, by Masanobu Kimura.
+		     */
+		    tmp[1] = data[++itmp];
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext2 if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    tmp[1] = '\0';
+		    written += 2;
+		} else {
+		    /*
+		     *  Make sure we don't restore emphasis to
+		     *  the last character of hightext2 if we
+		     *  are making the link current. - FM
+		     */
+		    if (flag == ON && data[(itmp + 1)] == '\0') {
+			LYstopTargetEmphasis();
+			TargetEmphasisON = FALSE;
+			LYGetYX(y, offset);
+			move(hline, (offset + 1));
+		    } else {
+			addstr(tmp);
+		    }
+		    written++;
+		}
+	    }
+
+	    /*
+	     *  Stop the emphasis if we haven't already, then reset
+	     *  the offset to our current position in the line, and
+	     *  if that is beyond the link, or we are making the link
+	     *  current and it is the last character in the hightext2,
+	     *  we are done. - FM
+	     */
+	    if (TargetEmphasisON) {
+		LYstopTargetEmphasis();
+		TargetEmphasisON = FALSE;
+	    }
+	    LYGetYX(y, offset);
+	    if (offset >=
+	        (hoffset + (flag == ON ? (hLen - 1) : hLen))) {
+		goto highlight_search_done;
+	    }
+
+	    /*
+	     *  See if we have another hit that starts
+	     *  within the hightext2. - FM
+	     */
+	    data = (Data + (offset - Offset));
+	    if ((case_sensitive ?
+		 (cp = LYno_attr_mbcs_strstr(data,
+					     target,
+					     utf_flag,
+					     &HitOffset,
+					     &LenNeeded)) != NULL :
+		 (cp = LYno_attr_mbcs_case_strstr(data,
+					     target,
+					     utf_flag,
+					     &HitOffset,
+					     &LenNeeded)) != NULL) &&
+		(offset + LenNeeded) < LYcols) {
+		/*
+		 *  If the hit starts after the end of the hightext2,
+		 *  or we are making the link current and the hit
+		 *  starts at its last character, we are done. - FM
+		 */
+		if ((HitOffset + offset) >=
+		    (hoffset +
+		     (flag == ON ? (hLen - 1) : hLen)))  {
+		    goto highlight_search_done;
+		}
+
+		/*
+		 *  If the target extends beyond our buffer, emphasize
+		 *  everything in the hightext2 starting at this hit.
+		 *  Otherwise, set up the data and offsets, and loop
+		 *  back. - FM
+		 */
+		if ((HitOffset + (offset + tLen)) >=
+		    (hoffset + hLen)) {
+		    offset = (HitOffset + offset);
+		    data = (buffer + (offset - hoffset));
+		    move(hline, offset);
+		    itmp = 0;
+		    written = 0;
+		    len = strlen(data);
+
+		    /*
+		     *  Turn the emphasis back on. - FM
+		     */
+		    LYstartTargetEmphasis();
+		    TargetEmphasisON = TRUE;
+		    for (;
+			 written < len && (tmp[0] = data[itmp]) != '\0';
+			 itmp++)  {
+			/*
+			 *  Print all the other target chars, except
+			 *  the last character if it is also the last
+			 *  character of hightext2 and we are making
+			 *  the link current. - FM
+			 */
+			if (utf_flag && !isascii(tmp[0])) {
+			    if ((*tmp & 0xe0) == 0xc0) {
+				utf_extra = 1;
+			    } else if ((*tmp & 0xf0) == 0xe0) {
+				utf_extra = 2;
+			    } else if ((*tmp & 0xf8) == 0xf0) {
+				utf_extra = 3;
+			    } else if ((*tmp & 0xfc) == 0xf8) {
+				utf_extra = 4;
+			    } else if ((*tmp & 0xfe) == 0xfc) {
+				utf_extra = 5;
+			    } else {
+				/*
+				 *  Garbage.
+				 */
+				utf_extra = 0;
+			    }
+			    if (strlen(&data[itmp+1]) < utf_extra) {
+				/*
+				 *  Shouldn't happen.
+				 */
+				utf_extra = 0;
+			    }
+			}
+			if (utf_extra) {
+			    strncpy(&tmp[1], &data[itmp+1], utf_extra);
+			    tmp[(utf_extra + 1)] = '\0';
+			    itmp += utf_extra;
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext2 if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+				LYGetYX(y, offset);
+				move(hline, (offset + 1));
+			    } else {
+				addstr(tmp);
+			    }
+			    tmp[1] = '\0';
+			    written += (utf_extra + 1);
+			    utf_extra = 0;
+			} else if (HTCJK != NOCJK && !isascii(tmp[0])) {
+			    /*
+			     *  For CJK strings, by Masanobu Kimura.
+			     */
+			    tmp[1] = data[++itmp];
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext2 if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+			    } else {
+				addstr(tmp);
+			    }
+			    tmp[1] = '\0';
+			    written += 2;
+			} else {
+			    /*
+			     *  Make sure we don't restore emphasis to
+			     *  the last character of hightext2 if we
+			     *  are making the link current. - FM
+			     */
+			    if (flag == ON && data[(itmp + 1)] == '\0') {
+				LYstopTargetEmphasis();
+				TargetEmphasisON = FALSE;
+			    } else {
+				addstr(tmp);
+			    }
+			    written++;
+			}
+		    }
+		    /*
+		     *  Turn off the emphasis if we haven't already,
+		     *  and then we're done. - FM
+		     */
+		    if (TargetEmphasisON) {
+		        LYstopTargetEmphasis();
+		    }
+		    goto highlight_search_done;
+		} else {
+		    Data = cp;
+		    Offset = (offset + HitOffset);
+		    data = buffer;
+		    offset = hoffset;
+		    goto highlight_hit_within_hightext2;
+		}
+	    }
+	    goto highlight_search_done;
+	}
+highlight_search_done:
+	FREE(theData);
+
 	if (!LYShowCursor)
-	    move(LYlines-1, LYcols-1);	/* get cursor out of the way */
+	    /*
+	     *  Get cursor out of the way.
+	     */
+	    move((LYlines - 1), (LYcols - 1));
 	else
 #endif /* FANCY CURSES || USE_SLANG */
-	    /* never hide the cursor if there's no FANCY CURSES or SLANG */
-	    move(links[cur].ly, links[cur].lx - 1);
+	    /*
+	     *  Never hide the cursor if there's no FANCY CURSES or SLANG.
+	     */
+	    move(links[cur].ly,
+	         ((links[cur].lx > 0) ? (links[cur].lx - 1) : 0));
 
 	if (flag)
 	    refresh();
@@ -213,8 +1672,8 @@ PUBLIC void highlight ARGS2(
 }
 
 /*
- * free_and_clear will free a pointer if it is non-zero and
- * then set it to zero
+ *  free_and_clear will free a pointer if it
+ *  is non-zero and then set it to zero.
  */
 PUBLIC void free_and_clear ARGS1(
 	char **,	pointer)
@@ -227,7 +1686,7 @@ PUBLIC void free_and_clear ARGS1(
 }
 
 /*
- * Collapse (REMOVE) all spaces in the string. 
+ *  Collapse (REMOVE) all spaces in the string. 
  */
 PUBLIC void collapse_spaces ARGS1(
 	char *,		string)
@@ -307,7 +1766,7 @@ PUBLIC char * strip_trailing_slash ARGS1(
 }
 
 /*
- * display (or hide) the status line
+ *  Display (or hide) the status line.
  */
 BOOLEAN mustshow = FALSE;
 
@@ -433,7 +1892,7 @@ PUBLIC void statusline ARGS1(
 		int a=(strncmp(buffer, "Alert", 5) || !hashStyles[s_alert].name ? s_status : s_alert);
 		LynxChangeStyle (a, ABS_ON, 1);
 		addstr(buffer);
-		wbkgdset(stdscr, hashStyles[a].color);
+		wbkgdset(stdscr, has_color ? hashStyles[a].color : hashStyles[a].mono);
 		clrtoeol();
 		wbkgdset(stdscr, hashStyles[s_normal].color);
 		LynxChangeStyle (a, ABS_OFF, 0);
@@ -608,8 +2067,8 @@ PUBLIC int HTCheckForInterrupt NOARGS
 }
 
 /*
- * A file URL for a remote host is an obsolete ftp URL.
- * Return YES only if we're certain it's a local file. - FM
+ *  A file URL for a remote host is an obsolete ftp URL.
+ *  Return YES only if we're certain it's a local file. - FM
  */
 PUBLIC BOOLEAN LYisLocalFile ARGS1(
 	char *,		filename)
@@ -651,8 +2110,8 @@ PUBLIC BOOLEAN LYisLocalFile ARGS1(
 }
 
 /*
- * Utility for checking URLs with a host field.
- * Return YES only if we're certain it's the local host. - FM
+ *  Utility for checking URLs with a host field.
+ *  Return YES only if we're certain it's the local host. - FM
  */
 PUBLIC BOOLEAN LYisLocalHost ARGS1(
 	char *,		filename)
@@ -690,7 +2149,7 @@ PUBLIC BOOLEAN LYisLocalHost ARGS1(
 }
 
 /* 
- * Utility for freeing the list of local host aliases. - FM
+ *  Utility for freeing the list of local host aliases. - FM
  */
 PUBLIC void LYLocalhostAliases_free NOARGS
 {
@@ -709,7 +2168,7 @@ PUBLIC void LYLocalhostAliases_free NOARGS
 }
 
 /* 
- * Utility for listing hosts to be treated as local aliases. - FM
+ *  Utility for listing hosts to be treated as local aliases. - FM
  */
 PUBLIC void LYAddLocalhostAlias ARGS1(
 	char *,		alias)
@@ -733,8 +2192,8 @@ PUBLIC void LYAddLocalhostAlias ARGS1(
 }
 
 /*
- * Utility for checking URLs with a host field.
- * Return YES only if we've listed the host as a local alias. - FM
+ *  Utility for checking URLs with a host field.
+ *  Return YES only if we've listed the host as a local alias. - FM
  */
 PUBLIC BOOLEAN LYisLocalAlias ARGS1(
 	char *,		filename)
@@ -851,6 +2310,15 @@ PUBLIC int is_url ARGS1(
         return(0);
 
     /*
+     *  Can't be a URL if it starts with a slash.
+     *  So return immediately for this common case,
+     *  also to avoid false positives if there is a
+     *  colon later in the string. - kw
+     */
+    if (*cp == '/')
+        return(0);
+
+    /*
      *  Can't be a URL if it lacks a colon.
      */
     if (NULL == strchr(cp, ':'))
@@ -1235,8 +2703,8 @@ PUBLIC char * quote_pathname ARGS1(
 }
 
 /*
- * checks to see if the current process is attached via a terminal in the
- * local domain
+ *  Checks to see if the current process is attached
+ *  via a terminal in the local domain.
  *
  */
 PUBLIC BOOLEAN inlocaldomain NOARGS
@@ -1310,7 +2778,7 @@ PUBLIC void size_change ARGS1(
     LYcols  = SLtt_Screen_Cols;
 #ifdef SLANG_MBCS_HACK
     PHYSICAL_SLtt_Screen_Cols = LYcols;
-    SLtt_Screen_Cols = LYcols * 6;
+    SLtt_Screen_Cols = (LYcols * 6);
 #endif /* SLANG_MBCS_HACK */
     if (sig == 0)
         /*
@@ -1330,7 +2798,7 @@ PUBLIC void size_change ARGS1(
 #ifdef TIOCGSIZE
     if (ioctl(0, TIOCGSIZE, &win) == 0) {
         if (win.ts_lines != 0) {
-	    LYlines = win.ts_lines - 1;
+	    LYlines = win.ts_lines;
 	}
 	if (win.ts_cols != 0) {
 	    LYcols = win.ts_cols;
@@ -1340,7 +2808,7 @@ PUBLIC void size_change ARGS1(
 #ifdef TIOCGWINSZ
     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
         if (win.ws_row != 0) {
-	    LYlines = win.ws_row - 1;
+	    LYlines = win.ws_row;
 	}
 	if (win.ws_col != 0) {
 	    LYcols = win.ws_col;
@@ -1365,7 +2833,7 @@ PUBLIC void size_change ARGS1(
 }
 
 /* 
- * Utility for freeing the list of previous suggested filenames. - FM
+ *  Utility for freeing the list of previous suggested filenames. - FM
  */
 PUBLIC void HTSugFilenames_free NOARGS
 {
@@ -1431,15 +2899,19 @@ PUBLIC void change_sug_filename ARGS1(
      char *temp, *cp, *cp1, *end;
      size_t len;
 #ifdef VMS
-     char *dot;
-     int j,k;
+    char *dot;
+    int j, k;
 #endif /* VMS */
 
-     /*** establish the current end of fname ***/
-     end = fname + strlen(fname);
+    /*
+     *  Establish the current end of fname.
+     */
+    end = fname + strlen(fname);
 
-     /*** unescape fname ***/
-     HTUnEscape(fname);
+    /*
+     *  Unescape fname.
+     */
+    HTUnEscape(fname);
 
      /*** rename any temporary files ***/
      temp = (char *)calloc(1, (strlen(lynx_temp_space) + 60));
@@ -1448,196 +2920,249 @@ PUBLIC void change_sug_filename ARGS1(
      else
          sprintf(temp, "file://localhost/%sL%d", lynx_temp_space, (int)getpid());
      len = strlen(temp);
-     if (0==strncmp(fname, temp, len)) {
-         cp = strrchr(fname, '.');
-	 if (strlen(cp) > (len - 4))
-	     cp = NULL;
-	 strcpy(temp, (cp ? cp : ""));
-	 strcpy(fname, "temp");
-	 strcat(fname, temp);
-     }
-     FREE(temp);
+    if (!strncmp(fname, temp, len)) {
+	cp = strrchr(fname, '.');
+	if (strlen(cp) > (len - 4))
+	    cp = NULL;
+	strcpy(temp, (cp ? cp : ""));
+	strcpy(fname, "temp");
+	strcat(fname, temp);
+    }
+    FREE(temp);
 
-     /*** remove everything up the the last_slash if there is one ***/
-     if ((cp = strrchr(fname,'/')) != NULL && strlen(cp) > 1) {
-	 cp1=fname;
-	 cp++; /* go past the slash */
-	 for (; *cp != '\0'; cp++, cp1++)
+    /*
+     *  Remove everything up the the last_slash if there is one.
+     */
+    if ((cp = strrchr(fname,'/')) != NULL && strlen(cp) > 1) {
+	cp1 = fname;
+	/*
+	 *  Go past the slash.
+	 */
+	cp++;
+	for (; *cp != '\0'; cp++, cp1++) {
 	    *cp1 = *cp;
+	}
+	*cp1 = '\0';
+    }
 
-	 *cp1 = '\0'; /* terminate */
-     }
+    /*
+     *  Trim off date-size suffix, if present.
+     */
+    if ((*(end - 1) == ']') && ((cp = strrchr(fname, '[')) != NULL) &&
+	(cp > fname) && *(--cp) == ' ') {
+	while (*cp == ' ') {
+	    *(cp--) = '\0';
+	}
+    }
 
-     /*** Trim off date-size suffix, if present ***/
-     if ((*(end - 1) == ']') && ((cp = strrchr(fname, '[')) != NULL) &&
-         (cp > fname) && *(--cp) == ' ')
-	  while (*cp == ' ')
-	       *(cp--) = '\0';
-
-     /*** Trim off VMS device and/or directory specs, if present ***/
-     if ((cp=strchr(fname,'[')) != NULL &&
-         (cp1=strrchr(cp,']')) != NULL && strlen(cp1) > 1) {
-	  cp1++;
-	  for (cp=fname; *cp1 != '\0'; cp1++)
-	       *(cp++) = *cp1;
-	  *cp = '\0';
-     }
+    /*
+     *  Trim off VMS device and/or directory specs, if present.
+     */
+    if ((cp = strchr(fname,'[')) != NULL &&
+	(cp1 = strrchr(cp,']')) != NULL && strlen(cp1) > 1) {
+	cp1++;
+	for (cp=fname; *cp1 != '\0'; cp1++) {
+	    *(cp++) = *cp1;
+	}
+	*cp = '\0';
+    }
 
 #ifdef VMS
-     /*** Replace illegal or problem characters ***/
-     dot = fname + strlen(fname);
-     for (cp = fname; cp < dot; cp++) {
-
-	  /** Replace with underscores **/
-	  if (*cp == ' ' || *cp == '/' || *cp == ':' ||
-	      *cp == '[' || *cp == ']' || *cp == '&')
-	       *cp = '_';
-
-	  /** Replace with dashes **/
-	  else if (*cp == '!' || *cp == '?' || *cp == '\'' || 
+    /*
+     *  Replace illegal or problem characters.
+     */
+    dot = fname + strlen(fname);
+    for (cp = fname; cp < dot; cp++) {
+	/*
+	 *  Replace with underscores.
+	 */
+	if (*cp == ' ' || *cp == '/' || *cp == ':' ||
+	    *cp == '[' || *cp == ']' || *cp == '&') {
+	    *cp = '_';
+	/*
+	 *  Replace with dashes.
+	 */
+	} else if (*cp == '!' || *cp == '?' || *cp == '\'' || 
 	           *cp == ',' || *cp == ':' || *cp == '\"' ||
 	           *cp == '+' || *cp == '@' || *cp == '\\' ||
 	           *cp == '(' || *cp == ')' || *cp == '=' ||
 	           *cp == '<' || *cp == '>' || *cp == '#' ||
 	           *cp == '%' || *cp == '*' || *cp == '`' ||
 	           *cp == '~' || *cp == '^' || *cp == '|' ||
-		   *cp <  ' ' || ((unsigned char)*cp) > 126)
-	       *cp = '-';
+		   *cp <  ' ' || ((unsigned char)*cp) > 126) {
+	    *cp = '-';
+	}
      }
 
-     /** Collapse any serial underscores **/
-     cp = fname + 1;
-     j = 0;
-     while (cp < dot) {
-	  if (fname[j] == '_' && *cp == '_')
-	       cp++;
-	  else
-	       fname[++j] = *cp++;
-     }
-     fname[++j] = '\0';
-
-     /** Collapse any serial dashes **/
-     dot = fname + (strlen(fname));
-     cp = fname + 1;
-     j = 0;
-     while (cp < dot) {
-          if (fname[j] == '-' && *cp == '-')
-	       cp++;
-	  else
-	       fname[++j] = *cp++;
-     }
-     fname[++j] = '\0';
-
-     /** Trim any trailing or leading **/
-     /** underscrores or dashes       **/
-     cp = fname + (strlen(fname)) - 1;
-     while (*cp == '_' || *cp == '-')
-          *cp-- = '\0';
-     if (fname[0] == '_' || fname[0] == '-') {
-          dot = fname + (strlen(fname));
-          cp = fname;
-          while ((*cp == '_' || *cp == '-') && cp < dot)
-	       cp++;
-	  j = 0;
-          while (cp < dot)
-	       fname[j++] = *cp++;
-	  fname[j] = '\0';
-     }
+    /*
+     *  Collapse any serial underscores.
+     */
+    cp = fname + 1;
+    j = 0;
+    while (cp < dot) {
+	if (fname[j] == '_' && *cp == '_') {
+	    cp++;
+	} else {
+	    fname[++j] = *cp++;
+	}
+    }
+    fname[++j] = '\0';
 
-     /** Replace all but the last period with _'s, or second **/
-     /** to last if last is followed by a terminal Z or z,   **/
-     /** or GZ or gz,					     **/
-     /** e.g., convert foo.tar.Z to                          **/
-     /**               foo.tar_Z                             **/
-     /**   or, convert foo.tar.gz to                         **/
-     /**               foo.tar-gz                            **/
-     j = strlen(fname) - 1;
-     if ((dot = strrchr(fname, '.')) != NULL) {
-	  if (TOUPPER(fname[j]) == 'Z') {
-	      if ((fname[j-1] == '.') &&
-	          (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
-		  *dot = '_';
-		  dot = strrchr(fname, '.');
-	      } else if (((TOUPPER(fname[j-1]) == 'G') &&
-	      		  fname[j-2] == '.') &&
-			 (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
-		  *dot = '-';
-		  dot = strrchr(fname, '.');
-	      }
-	  }
-	  cp = fname;
-	  while ((cp = strchr(cp, '.')) != NULL && cp < dot)
-	       *cp = '_';
-
-          /** But if the root is > 39 characters, move **/
-          /** the period appropriately to the left     **/
-	  while (dot - fname > 39) {
-	       *dot = '\0';
-	       if ((cp = strrchr(fname, '_')) != NULL) {
-		    *cp  = '.';
-		    *dot = '_';
-	       } 
-	       else if ((cp = strrchr(fname, '-')) != NULL) {
-		    *cp  = '.';
-		    *dot = '_';
-	       }
-	       else {
-		    *dot = '_';
-		    j = strlen(fname);
-		    fname[j+1] = '\0';
-		    while (j > 39)
-			 fname[j--] = fname[j];
-		    fname[j] = '.';
-	       }
-               dot = strrchr(fname, '.');
-	  }
+    /*
+     *  Collapse any serial dashes.
+     */
+    dot = fname + (strlen(fname));
+    cp = fname + 1;
+    j = 0;
+    while (cp < dot) {
+	if (fname[j] == '-' && *cp == '-') {
+	    cp++;
+	}  else {
+	    fname[++j] = *cp++;
+	}
+    }
+    fname[++j] = '\0';
 
-          /** Make sure the extension is < 40 characters **/
-          if ((fname + strlen(fname) - dot) > 39)
-	       *(dot+40) = '\0';
+    /*
+     *  Trim any trailing or leading
+     *  underscrores or dashes.
+     */
+    cp = fname + (strlen(fname)) - 1;
+    while (*cp == '_' || *cp == '-') {
+	*cp-- = '\0';
+    }
+    if (fname[0] == '_' || fname[0] == '-') {
+	dot = fname + (strlen(fname));
+	cp = fname;
+	while ((*cp == '_' || *cp == '-') && cp < dot) {
+	    cp++;
+	}
+	j = 0;
+	while (cp < dot) {
+	    fname[j++] = *cp++;
+	}
+	fname[j] = '\0';
+    }
 
-	  /** Trim trailing dashes or underscores **/
-	  j = strlen(fname) - 1;
-	  while (fname[j] == '_' || fname[j] == '-')
-	       fname[j--] = '\0';
-     }
-     else {
-	  /** No period, so put one on the end, or after   **/
-	  /** the 39th character, trimming trailing dashes **/
-	  /** or underscrores                              **/
-	  if (strlen(fname) > 39)
-	       fname[39] = '\0';
-	  j = strlen(fname) - 1;
-	  while ((fname[j] == '_') || (fname[j] == '-'))
-	       j--;
-	  fname[++j] = '.';
-	  fname[++j] = '\0';
-     }
+    /*
+     *  Replace all but the last period with _'s, or second
+     *  to last if last is followed by a terminal Z or z,
+     *  or GZ or gz,
+     *  e.g., convert foo.tar.Z to
+     *		      foo.tar_Z
+     *    or, convert foo.tar.gz to
+     *		      foo.tar-gz
+     */
+    j = strlen(fname) - 1;
+    if ((dot = strrchr(fname, '.')) != NULL) {
+	if (TOUPPER(fname[j]) == 'Z') {
+	    if ((fname[j-1] == '.') &&
+		(((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
+		*dot = '_';
+		dot = strrchr(fname, '.');
+	    } else if (((TOUPPER(fname[j-1]) == 'G') &&
+			fname[j-2] == '.') &&
+		       (((cp = strchr(fname, '.')) != NULL) && cp < dot)) {
+		*dot = '-';
+		dot = strrchr(fname, '.');
+	    }
+	}
+	cp = fname;
+	while ((cp = strchr(cp, '.')) != NULL && cp < dot) {
+	    *cp = '_';
+	}
+
+	/*
+	 *  But if the root is > 39 characters, move
+	 *  the period appropriately to the left.
+	 */
+	while (dot - fname > 39) {
+	    *dot = '\0';
+	    if ((cp = strrchr(fname, '_')) != NULL) {
+		*cp  = '.';
+		*dot = '_';
+	    } else if ((cp = strrchr(fname, '-')) != NULL) {
+		*cp  = '.';
+		*dot = '_';
+	    } else if (*(dot + 1) == '\0') {
+		j = strlen(fname);
+		while (j > 39) {
+		    fname[j] = fname[j-1];
+		    j--;
+		}
+		fname[j] = '.';
+	    } else {
+		*dot = '.';
+		j = 39;
+		k = 0;
+		while (dot[k] != '\0') {
+		    fname[j++] = dot[k++];
+		}
+		fname[j] = '\0';
+	    }
+	    dot = strrchr(fname, '.');
+	}
+
+	/*
+	 *  Make sure the extension is < 40 characters.
+	 */
+	if ((fname + strlen(fname) - dot) > 39) {
+	    *(dot + 40) = '\0';
+	}
+
+	/*
+	 *  Trim trailing dashes or underscores.
+	 */
+	j = (strlen(fname) - 1);
+	while (fname[j] == '_' || fname[j] == '-') {
+	    fname[j--] = '\0';
+	}
+     } else {
+	/*
+	 *  No period, so put one on the end, or after
+	 *  the 39th character, trimming trailing dashes
+	 *  or underscrores.
+	 */
+	if (strlen(fname) > 39) {
+	    fname[39] = '\0';
+	}
+	j = (strlen(fname) - 1);
+	while ((fname[j] == '_') || (fname[j] == '-')) {
+	    j--;
+	}
+	fname[++j] = '.';
+	fname[++j] = '\0';
+    }
 
 #else /* Not VMS (UNIX): */
 
-     /*** Replace problem characters ***/
-     for (cp = fname; *cp != '\0'; cp++) {
-	  switch (*cp) {
-	  case '\'':
-	  case '\"':
-	  case '/':
-	  case ' ':
-	       *cp = '-';
-	  }
-     }
+    /*
+     *  Replace problem characters.
+     */
+    for (cp = fname; *cp != '\0'; cp++) {
+	switch (*cp) {
+	    case '\'':
+	    case '\"':
+	    case '/':
+	    case ' ':
+		*cp = '-';
+	}
+    }
 #endif /* VMS (UNIX) */
 
-     /** Make sure the rest of the original string in nulled. **/
-     cp = fname + strlen(fname);
-     while (cp < end)
-          *cp++ = '\0';
+    /*
+     *  Make sure the rest of the original string in nulled.
+     */
+    cp = fname + strlen(fname);
+    while (cp < end) {
+	*cp++ = '\0';
+    }
 
     return;
 }
 
 /*
- *	To create standard temporary file names
+ *  To create standard temporary file names.
  */
 PUBLIC void tempname ARGS2(
 	char *,		namebuffer,
@@ -1779,8 +3304,8 @@ PUBLIC int number2arrows ARGS1(
 }
 
 /*
- * parse_restrictions takes a string of comma-separated restrictions
- * and sets the corresponding flags to restrict the facilities available
+ *  parse_restrictions takes a string of comma-separated restrictions
+ *  and sets the corresponding flags to restrict the facilities available.
  */
 PRIVATE char *restrict_name[] = {
        "inside_telnet" ,
@@ -2132,6 +3657,10 @@ PUBLIC void LYConvertToURL ARGS1(
     char *old_string = *AllocatedString;
     char *temp = NULL;
     char *cp = NULL;
+#ifndef VMS
+    struct stat st;
+    FILE *fptemp = NULL;
+#endif /* !VMS */
 
     if (!old_string || *old_string == '\0')
         return;
@@ -2364,8 +3893,6 @@ have_VMS_URL:
 	     *  Create a full path to the current default directory.
 	     */
 	    char curdir[DIRNAMESIZE];
-	    struct stat st;
-	    FILE *fptemp = NULL;
 	    BOOL is_local = FALSE;
 #if HAVE_GETCWD
 	    getcwd (curdir, DIRNAMESIZE);
@@ -2463,12 +3990,11 @@ have_VMS_URL:
 	    FREE(temp);
 	    if (fptemp) {
 		fclose(fptemp);
+		fptemp = NULL;
 	    }
 	}
 #endif /* VMS */
     } else { 
-	struct stat st;
-	FILE *fptemp = NULL;
 	/*
 	 *  Path begins with a slash.  Simplify and use it.
 	 */
@@ -2482,12 +4008,11 @@ have_VMS_URL:
 	    StrAllocCat(*AllocatedString, HTVMS_wwwName((char *)Home_Dir()));
 #else
 	    StrAllocCat(*AllocatedString, "/");
-#endif /* VMS */
 	} else if ((stat(old_string, &st) > -1) ||
 		   (fptemp = fopen(old_string, "r")) != NULL) {
 	    /*
 	     *  It is an absolute directory or file
-	     *  on the local system. - kw
+	     *  on the local system. - KW
 	     */
 	    StrAllocCopy(temp, old_string);
 	    LYTrimRelFromAbsPath(temp);
@@ -2498,12 +4023,15 @@ have_VMS_URL:
 	    StrAllocCat(*AllocatedString, cp);
 	    FREE(cp);
 	    FREE(temp);
-	    if (fptemp)
+	    if (fptemp) {
 		fclose(fptemp);
+		fptemp = NULL;
+	    }
 	    if (TRACE) {
 		fprintf(stderr, "Converted '%s' to '%s'\n",
 			old_string, *AllocatedString);
 	    }
+#endif /* VMS */
 	} else if (old_string[1] == '~') {
 	    /*
 	     *  Has a Home_Dir() reference.  Handle it
@@ -3076,7 +4604,7 @@ PUBLIC void Define_VMSLogical ARGS2(
 
 PUBLIC CONST char * Home_Dir NOARGS
 {
-    static CONST char *homedir;
+    static CONST char *homedir = NULL;
 
     if (!homedir) {
 	if ((homedir = getenv("HOME")) == NULL) {
@@ -3390,17 +4918,22 @@ PUBLIC void LYAddPathToHome ARGS3(
 /*
  *  This function takes a string in the format
  *	"Mon, 01-Jan-96 13:45:35 GMT" or
- *	"Mon,  1 Jan 1996 13:45:35 GMT""
+ *	"Mon,  1 Jan 1996 13:45:35 GMT"" or
+ *	"dd-mm-yyyy"
  *  as an argument, and returns its conversion to clock format
  *  (seconds since 00:00:00 Jan 1 1970), or 0 if the string
- *  doesn't match the expected pattern.  It also returns 0
- *  if the time is in the past.  It is intended for handling
- *  'expires' strings homologously to 'max-age' strings, for
- *  which 0 is the minimum, and greater values are handled
- *  as '[max-age seconds] + time(NULL)'. - FM
+ *  doesn't match the expected pattern.  It also returns 0 if
+ *  the time is in the past and the "absolute" argument is FALSE.
+ *  It is intended for handling 'expires' strings in Version 0
+ *  cookies homologously to 'max-age' strings in Version 1 cookies,
+ *  for which 0 is the minimum, and greater values are handled as
+ *  '[max-age seconds] + time(NULL)'.   If "absolute" if TRUE, we
+ *  return the clock format value itself, but if anything goes wrong
+ *  when parsing the expected patterns, we still return 0. - FM
  */
-PUBLIC time_t LYmktime ARGS1(
-	char *,		string)
+PUBLIC time_t LYmktime ARGS2(
+	char *,		string,
+	BOOL,		absolute)
 {
     char *s;
     time_t now, clock2;
@@ -3418,17 +4951,13 @@ PUBLIC time_t LYmktime ARGS1(
         fprintf(stderr, "LYmktime: Parsing '%s'\n", s);
          
     /*
-     *  Skip the "Day, " field. - FM
+     *  Skip any lead alphabetic "Day, " field and
+     *  seek a numberic day field. - FM
      */
-    while (*s != '\0' && *s != ',')
+    while (*s != '\0' && !isdigit((unsigned char)*s))
         s++;
     if (*s == '\0')
         return(0);
-    s++;
-    while (*s != '\0' && isspace((unsigned char)*s))
-        s++;
-    if (*s == '\0' || !isdigit((unsigned char)*s))
-        return(0);
 
     /*
      *  Get the numeric day and convert to an integer. - FM
@@ -3446,18 +4975,27 @@ PUBLIC time_t LYmktime ARGS1(
     /*
      *  Get the month string and convert to an integer. - FM
      */
-    while (*s != '\0' && !isalpha((unsigned char)*s))
+    while (*s != '\0' && !isalnum((unsigned char)*s))
         s++;
     if (*s == '\0')
         return(0);
     start = s;
-    while (*s != '\0' && isalpha((unsigned char)*s))
+    while (*s != '\0' && isalnum((unsigned char)*s))
         s++;
-    if (*s == '\0' || (s - start) < 3 || (s - start) > 9)
+    if ((*s == '\0') ||
+	(s - start) < (isdigit((unsigned char)*(s - 1)) ? 2 : 3) ||
+	(s - start) > (isdigit((unsigned char)*(s - 1)) ? 2 : 9))
         return(0);
-    LYstrncpy(temp, start, 3);
+    LYstrncpy(temp, start, (isdigit((unsigned char)*(s - 1)) ? 2 : 3));
     switch (TOUPPER(temp[0])) {
-        case 'A':
+	case '0':
+	case '1':
+	    month = atoi(temp);
+	    if (month < 1 || month > 12) {
+		return(0);
+	    }
+	    break;
+	case 'A':
 	    if (!strcasecomp(temp, "Apr")) {
 	        month = 4;
 	    } else if (!strcasecomp(temp, "Aug")) {
@@ -3535,8 +5073,6 @@ PUBLIC time_t LYmktime ARGS1(
     start = s;
     while (*s != '\0' && isdigit((unsigned char)*s))
         s++;
-    if (*s == '\0')
-        return(0);
     if ((s - start) == 4) {
         LYstrncpy(temp, start, 4);
     } else if ((s - start) == 2) {
@@ -3554,49 +5090,54 @@ PUBLIC time_t LYmktime ARGS1(
      */
     while (*s != '\0' && !isdigit((unsigned char)*s))
         s++;
-    if (*s == '\0')
-        return(0);
-    start = s;
-    while (*s != '\0' && isdigit((unsigned char)*s))
-        s++;
-    if (*s != ':' || (s - start) > 2)
-        return(0);
-    LYstrncpy(temp, start, (int)(s - start));
-    hour = atoi(temp);
+    if (*s == '\0') {
+        hour = 0;
+	minutes = 0;
+	seconds = 0;
+    } else {
+	start = s;
+	while (*s != '\0' && isdigit((unsigned char)*s))
+	    s++;
+	if (*s != ':' || (s - start) > 2)
+	    return(0);
+	LYstrncpy(temp, start, (int)(s - start));
+	hour = atoi(temp);
 
-    /*
-     *  Get the numeric minutes string and convert to an integer. - FM
-     */
-    while (*s != '\0' && !isdigit((unsigned char)*s))
-        s++;
-    if (*s == '\0')
-        return(0);
-    start = s;
-    while (*s != '\0' && isdigit((unsigned char)*s))
-        s++;
-    if (*s != ':' || (s - start) > 2)
-        return(0);
-    LYstrncpy(temp, start, (int)(s - start));
-    minutes = atoi(temp);
+	/*
+	 *  Get the numeric minutes string and convert to an integer. - FM
+	 */
+	while (*s != '\0' && !isdigit((unsigned char)*s))
+	    s++;
+	if (*s == '\0')
+	    return(0);
+	start = s;
+	while (*s != '\0' && isdigit((unsigned char)*s))
+	    s++;
+	if (*s != ':' || (s - start) > 2)
+	    return(0);
+	LYstrncpy(temp, start, (int)(s - start));
+	minutes = atoi(temp);
 
-    /*
-     *  Get the numeric seconds string and convert to an integer. - FM
-     */
-    while (*s != '\0' && !isdigit((unsigned char)*s))
-        s++;
-    if (*s == '\0')
-        return(0);
-    start = s;
-    while (*s != '\0' && isdigit((unsigned char)*s))
-        s++;
-    if (*s == '\0' || (s - start) > 2)
-        return(0);
-    LYstrncpy(temp, start, (int)(s - start));
-    seconds = atoi(temp);
+	/*
+	 *  Get the numeric seconds string and convert to an integer. - FM
+	 */
+	while (*s != '\0' && !isdigit((unsigned char)*s))
+	    s++;
+	if (*s == '\0')
+	    return(0);
+	start = s;
+	while (*s != '\0' && isdigit((unsigned char)*s))
+	    s++;
+	if (*s == '\0' || (s - start) > 2)
+	    return(0);
+	LYstrncpy(temp, start, (int)(s - start));
+	seconds = atoi(temp);
+    }
 
     /*
      *  Convert to clock format (seconds since 00:00:00 Jan 1 1970),
-     *  but then zero it if it's in the past.  - FM
+     *  but then zero it if it's in the past and "absolute" is not
+     *  TRUE.  - FM
      */
     month -= 3;
     if (month < 0) {
@@ -3609,7 +5150,7 @@ PUBLIC time_t LYmktime ARGS1(
     		     (hour * 60 * 60) +
     		     (minutes * 60) +
 		     seconds);
-    if (clock2 <= time(NULL))
+    if (absolute == FALSE && clock2 <= time(NULL))
         clock2 = (time_t)0;
     if (TRACE && clock2 > 0)
         fprintf(stderr,
@@ -3619,7 +5160,8 @@ PUBLIC time_t LYmktime ARGS1(
 }
 
 #if ! HAVE_PUTENV
-/* no putenv on the next so we use this code instead!
+/*
+ *  No putenv on the next so we use this code instead!
  */
 
 /* Copyright (C) 1991 Free Software Foundation, Inc.
@@ -3666,7 +5208,9 @@ extern int errno;
 
 extern char **environ;
 
-/* Put STRING, which is of the form "NAME=VALUE", in  the environment.  */
+/*
+ *  Put STRING, which is of the form "NAME=VALUE", in  the environment.
+ */
 PUBLIC int putenv ARGS1(
 	CONST char *,	string)
 {
diff --git a/src/LYUtils.h b/src/LYUtils.h
index 477504d6..557d971c 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -8,7 +8,7 @@
 #include "HTList.h"
 #endif /* HTLIST_H */
 
-extern void highlight PARAMS((int flag, int cur));
+extern void highlight PARAMS((int flag, int cur, char *target));
 extern void free_and_clear PARAMS((char **obj));
 extern void collapse_spaces PARAMS((char *string));
 extern void convert_to_spaces PARAMS((char *string, BOOL condense));
@@ -52,7 +52,7 @@ extern CONST char *Home_Dir NOPARAMS;
 extern BOOLEAN LYPathOffHomeOK PARAMS((char *fbuffer, int fbuffer_size));
 extern void LYAddPathToHome PARAMS((
 	char *fbuffer, int fbuffer_size, char *fname));
-extern time_t LYmktime PARAMS((char *string));
+extern time_t LYmktime PARAMS((char *string, BOOL absolute));
 #if ! HAVE_PUTENV
 extern int putenv PARAMS((CONST char *string));
 #endif /* HAVE_PUTENV */
diff --git a/src/LYrcFile.c b/src/LYrcFile.c
index a67a64e8..c462715e 100644
--- a/src/LYrcFile.c
+++ b/src/LYrcFile.c
@@ -352,6 +352,21 @@ PUBLIC void read_rc NOPARAMS
 	        LYSelectPopups = TRUE;
 
 	/*
+	 *  Show cursor.
+	 */
+	} else if ((cp = LYstrstr(line_buffer, "show_cursor")) != NULL &&
+		   cp-line_buffer < number_sign) {
+
+	    if ((cp2 = (char * )strchr(cp, '=')) != NULL)
+		cp = cp2 + 1;
+	    while (isspace(*cp))
+	        cp++;  /* get rid of spaces */
+	    if (!strncasecomp(cp, "off", 3))
+	        LYShowCursor = FALSE;
+	    else
+	        LYShowCursor = TRUE;
+
+	/*
 	 *  Keypad mode.
 	 */
 	} else if ((cp = LYstrstr(line_buffer, "keypad_mode")) != NULL &&
@@ -361,8 +376,10 @@ PUBLIC void read_rc NOPARAMS
 		cp = cp2 + 1;
 	    while (isspace(*cp))
 	        cp++;  /* get rid of spaces */
-	    if (LYstrstr(cp,"LINKS_ARE_NUMBERED"))
+	    if (LYstrstr(cp, "LINKS_ARE_NUMBERED"))
 	        keypad_mode = LINKS_ARE_NUMBERED;
+	    else if (LYstrstr(cp, "LINKS_AND_FORM_FIELDS_ARE_NUMBERED"))
+		keypad_mode = LINKS_AND_FORM_FIELDS_ARE_NUMBERED;
 	    else
 	        keypad_mode = NUMBERS_AS_ARROWS;
 
@@ -491,6 +508,7 @@ PUBLIC int save_rc NOPARAMS
     if ((fp = fopen(rcfile, "w")) == NULL) {
 	return FALSE;
     }
+    chmod(rcfile, 0600);
 
     /*
      *  Header.
@@ -680,6 +698,21 @@ PUBLIC int save_rc NOPARAMS
     fprintf(fp, "select_popups=%s\n\n", (LYSelectPopups ? "on" : "off"));
 
     /*
+     *  Show cursor.
+     */
+    fprintf(fp, "\
+# show_cursor specifies whether to 'hide' the cursor to the right (and\n\
+# bottom, if possible) of the screen, or to place it to the left of the\n\
+# current link in documents, or current option in select popup windows.\n\
+# Positioning the cursor to the left of the current link or option is\n\
+# helpful for speech or braille interfaces, and when the terminal is\n\
+# one which does not distingish the current link based on highlighting\n\
+# or color.  A value of \"on\" will set positioning to the left as the\n\
+# default while a value of \"off\" will set 'hiding' of the cursor.\n\
+# The default can be overridden via the -show_cursor command line toggle.\n");
+    fprintf(fp, "show_cursor=%s\n\n", (LYShowCursor ? "on" : "off"));
+
+    /*
      *  Keypad mode.
      */
     fprintf(fp, "\
@@ -688,14 +721,28 @@ PUBLIC int save_rc NOPARAMS
 #             8 = Up Arrow\n\
 #   4 = Left Arrow    6 = Right Arrow\n\
 #             2 = Down Arrow\n\
+# and the corresponding keyboard numbers will act as arrow keys,\n\
+# regardless of whether numlock is on.\n");
+    fprintf(fp, "\
 # If keypad_mode is set to \"LINKS_ARE_NUMBERED\", then numbers will\n\
-# appear next to each link and numbers are used to select links.\n\
+# appear next to each link and numbers are used to select links.\n");
+    fprintf(fp, "\
+# If keypad_mode is set to \"LINKS_AND_FORM_FIELDS_ARE_NUMBERED\", then\n\
+# numbers will appear next to each link and visible form input field.\n\
+# Numbers are used to select links, or to move the \"current link\" to a\n\
+# form input field or button.  In addition, options in popup menus are\n\
+# indexed so that the user may type an option number to select an option in\n\
+# a popup menu, even if the option isn't visible on the screen.  Reference\n\
+# lists and output from the list command also enumerate form inputs.\n");
+    fprintf(fp, "\
 # NOTE: Some fixed format documents may look disfigured when\n\
-# \"LINKS_ARE_NUMBERED\" is enabled.\n");
+# \"LINKS_ARE_NUMBERED\" or \"LINKS_AND_FORM_FIELDS_ARE_NUMBERED\" are\n\
+# enabled.\n");
     fprintf(fp, "keypad_mode=%s\n\n",
-    		(keypad_mode==NUMBERS_AS_ARROWS ? 
-			    "NUMBERS_AS_ARROWS" : "LINKS_ARE_NUMBERED"));
- 
+		((keypad_mode == NUMBERS_AS_ARROWS) ?  "NUMBERS_AS_ARROWS" :
+	       ((keypad_mode == LINKS_ARE_NUMBERED) ? "LINKS_ARE_NUMBERED" :
+				      "LINKS_AND_FORM_FIELDS_ARE_NUMBERED")));
+
     /*
      *  Lineedit mode.
      */
diff --git a/src/UCAuto.c b/src/UCAuto.c
index cd786b76..b09df4ab 100644
--- a/src/UCAuto.c
+++ b/src/UCAuto.c
@@ -1,32 +1,43 @@
-#ifdef EXP_CHARTRANS
-#ifdef EXP_CHARTRANS_AUTOSWITCH
-#ifdef LINUX
-
-/* This file contains code for changing the Linux console mode.
-** Currently some names for font files are hardwired in here.
-** You have to change this code if it needs accomodation for your
-** system (or get the required files...).
+/*
+**  This file contains code for changing the Linux console mode.
+**  Currently some names for font files are hardwired in here.
+**  You have to change this code if it needs accomodation for your
+**  system (or get the required files...).
 ** 
-** Depending on the Display Character Set switched to, and the previous
-** one as far as it is known, system("setfont ...") and/or output of
-** escape sequences to switch console mode are done.  Curses will be
-** temporarily suspended while that happens.
+**  Depending on the Display Character Set switched to, and the previous
+**  one as far as it is known, system("setfont ...") and/or output of
+**  escape sequences to switch console mode are done.  Curses will be
+**  temporarily suspended while that happens.
 **
-** NOTE that the setfont calls will also affect all other virtual consoles.
+**  NOTE that the setfont calls will also affect all other virtual consoles.
 **
-** Any ideas how to do this for other systems?
+**  Any ideas how to do this for other systems?
 */
-#include "tcp.h"
+
 #include "HTUtils.h"
+#include "tcp.h"
+
 #include "UCMap.h"
 #include "UCDefs.h"
 #include "UCAuto.h"
 #include "LYGlobalDefs.h"
 
-typedef enum {Is_Unset, Is_Set, Dunno, Dont_Care} TGen_state_t;
-typedef enum {G0, G1} TGNstate_t;
-typedef enum
-{
+#ifdef EXP_CHARTRANS_AUTOSWITCH
+
+#ifdef VMS
+#define DISPLAY "DECW$DISPLAY"
+#else
+#define DISPLAY "DISPLAY"
+#endif /* VMS */
+
+#ifdef LINUX
+typedef enum {
+    Is_Unset, Is_Set, Dunno, Dont_Care
+} TGen_state_t;
+typedef enum {
+    G0, G1
+} TGNstate_t;
+typedef enum {
     GN_Blat1, GN_0decgraf, GN_Ucp437, GN_Kuser, GN_dunno, GN_dontCare
 } TTransT_t;
 
@@ -36,11 +47,17 @@ static char T_setfont_cmd[200] = "\0";
 #define SETFONT "setfont"
 #define NOOUTPUT "2>/dev/null"
 
-PRIVATE void call_setfont ARGS3(char *,font, char *,fnsuffix, char *,umap)
+PRIVATE void call_setfont ARGS3(
+	char *,		font,
+	char *,		fnsuffix,
+	char *,		umap)
 {
     if (font && *font && umap && *umap &&
-	0==strcmp(font,T_font_fn) && 0==strcmp(umap,T_umap_fn)) {
-	return;			/* no need to repeat */
+	!strcmp(font, T_font_fn) && !strcmp(umap, T_umap_fn)) {
+	/*
+	 *  No need to repeat.
+	 */
+	return;
     }
     if (font)
 	strcpy(T_font_fn, font);
@@ -62,21 +79,21 @@ PRIVATE void call_setfont ARGS3(char *,font, char *,fnsuffix, char *,umap)
     } else {
 	*T_setfont_cmd = '\0';
     }
-    
+
     if (*T_setfont_cmd) {
-    
-            if (TRACE) {
-                        fprintf(stderr, "Executing setfont: '%s'\n", 
-                        T_setfont_cmd);
-                        }
-                                
+	if (TRACE) {
+	    fprintf(stderr, "Executing setfont: '%s'\n", T_setfont_cmd);
+	}
 	system(T_setfont_cmd);
     }
 }
 
-/* This is the thing that actually gets called from display_page(). */
-
-PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p)
+/*
+ *  This is the thing that actually gets called from display_page().
+ */
+PUBLIC void UCChangeTerminalCodepage ARGS2(
+	int,		newcs,
+	LYUCcharset *,	p)
 {
     static int lastcs = -1;
     static char * lastname = NULL;
@@ -94,98 +111,128 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p)
     char tmpbuf1[100], tmpbuf2[20];
     char *cp;
 
-/* Font sizes are currently hardwired here... */
+    /*
+     *  Font sizes are currently hardwired here.
+     */
 #define SUFF1 ".f16"
 #define SUFF2 "-16.psf"
 #define SUFF3 "-8x16"
 #define SUFF4 "8x16"
 
-/* use this for output of escape sequences... */
-/* for some reason stdout won't do... maybe needs flush() somewhere.. */
+    /*
+     *  Use this for output of escape sequences.
+     *
+     *  For some reason stdout won't do; maybe needs flush() somewhere.
+     */
 #define ESCOUT stderr
-
-#ifdef VMS
-#define DISPLAY "DECW$DISPLAY"
-#else
-#define DISPLAY "DISPLAY"
-#endif /* VMS */
-
     if (display || (cp = getenv(DISPLAY)) != NULL) {
-      /* We won't do anything in an xterm.  Better that way...  */
+	/*
+	 *  We won't do anything in an xterm.  Better that way...
+	 */
 	return;
     }
 
-    if (0==strcmp(name,"iso-8859-10")) {
-	call_setfont("iso10", SUFF1,	"iso10.uni");
+    if (!strcmp(name, "iso-8859-10")) {
+	call_setfont("iso10", SUFF1, "iso10.uni");
 	TransT = GN_Kuser;
 	HasUmap = Is_Set;
 	Utf = Is_Unset;
-    } else if (0==strncmp(name,"iso-8859-1",10)) {
-	if ((lastHasUmap==Is_Set) && 0==strcmp(lastname,"cp850")) {
-	    /* cp850 already contains all latin1 characters */
-	    if (lastTransT != GN_Blat1)
+    } else if (!strncmp(name, "iso-8859-1", 10)) {
+	if ((lastHasUmap == Is_Set) && !strcmp(lastname, "cp850")) {
+	    /*
+	     *  cp850 already contains all latin1 characters.
+	     */
+	    if (lastTransT != GN_Blat1) {
 		TransT = GN_Blat1;
+	    }
 	} else {
-	    call_setfont("lat1u", SUFF2,	"lat1u.uni");
-				/* "setfont lat1u-16.psf -u lat1u.uni" */
+	    /*
+	     *  "setfont lat1u-16.psf -u lat1u.uni"
+	     */
+	    call_setfont("lat1u", SUFF2, "lat1u.uni");
 	    HasUmap = Is_Set;
-	    if (lastTransT != GN_Blat1)
+	    if (lastTransT != GN_Blat1) {
 		TransT = GN_Blat1;
+	    }
 	}
 	Utf = Is_Unset;
-    } else if (0==strcmp(name,"iso-8859-2")) {
-/*	call_setfont("lat2", SUFF2,	"lat2.uni");  */
-				/* "setfont lat2-16.psf -u lat2.uni" */
-	call_setfont("iso02", SUFF1,	"iso02.uni");
-				/* "setfont iso02.f16 -u iso02.uni" */
+    } else if (!strcmp(name, "iso-8859-2")) {
+#ifdef NOTDEFINED
+	/*
+	 *  "setfont lat2-16.psf -u lat2.uni"
+	 */
+	call_setfont("lat2", SUFF2, "lat2.uni");  */
+#endif /* NOTDEFINED */
+	/*
+	 *  "setfont iso02.f16 -u iso02.uni"
+	 */
+	call_setfont("iso02", SUFF1, "iso02.uni");
 	TransT = GN_Kuser;
 	HasUmap = Is_Set;
 	Utf = Is_Unset;
-    } else if (0==strncmp(name,"iso-8859-",9)) {
+    } else if (!strncmp(name, "iso-8859-", 9)) {
 	sprintf(tmpbuf1, "iso0%s", &name[9]);
 	sprintf(tmpbuf2, "iso0%s%s", &name[9],".uni");
-        call_setfont(tmpbuf1,SUFF1,	tmpbuf2);
-				/* "setfont iso0N.f16 -u iso0N.uni" */
+	/*
+	 *  "setfont iso0N.f16 -u iso0N.uni"
+	 */
+        call_setfont(tmpbuf1, SUFF1, tmpbuf2);
 	TransT = GN_Kuser;
 	HasUmap = Is_Set;
 	Utf = Is_Unset;
-    } else if (0==strcmp(name,"koi8-r")) {
-	call_setfont("koi8", SUFF3,	NULL);
+    } else if (!strcmp(name, "koi8-r")) {
+	/*
+	 *  "setfont koi8-8x16"
+	 */
+	call_setfont("koi8", SUFF3, NULL);
 	TransT = GN_Kuser;
 	HasUmap = Is_Unset;
 	Utf = Is_Unset;
-    } else if (0==strcmp(name,"cp437")) {
-	call_setfont("default", SUFF4 ,	"cp437.uni");
-				/* "setfont default8x16 -u cp437.uni" */
+    } else if (!strcmp(name, "cp437")) {
+	/*
+	 *  "setfont default8x16 -u cp437.uni"
+	 */
+	call_setfont("default", SUFF4, "cp437.uni");
 	if (TransT == GN_Kuser || TransT == GN_Ucp437)
 	    TransT = GN_dontCare;
 	else
 	    TransT = GN_Ucp437;
 	HasUmap = Is_Set;
 	Utf = Is_Unset;
-    } else if (0==strcmp(name,"cp850")) {
-	call_setfont("cp850"   ,SUFF3 ,	"cp850.uni");
-				/* "setfont cp850-8x16 -u cp850.uni" */
+    } else if (!strcmp(name, "cp850")) {
+	/*
+	 *  "setfont cp850-8x16 -u cp850.uni"
+	 */
+	call_setfont("cp850", SUFF3, "cp850.uni");
 	TransT = GN_Kuser;
 	HasUmap = Is_Set;
 	Utf = Is_Unset;
-    } else if (0==strcmp(name,"x-transparent")) {
+    } else if (!strcmp(name, "x-transparent")) {
 	Utf = Dont_Care;
-    } else if (0==strcmp(name,"us-ascii")) {
+    } else if (!strcmp(name, "us-ascii")) {
 	Utf = Dont_Care;
-    } else if (0==strncmp(name,"mnem",4)) {
+    } else if (!strncmp(name, "mnem", 4)) {
 	Utf = Dont_Care;
     }
 
     if (TransT != lastTransT) {
 	if (TransT == GN_Blat1) {
-	    fprintf(ESCOUT,"\033(B"); /* switch Linux console to lat1 table */
+	    /*
+	     *  Switch Linux console to lat1 table.
+	     */
+	    fprintf(ESCOUT, "\033(B");
 	} else if (TransT == GN_0decgraf) {
-	    fprintf(ESCOUT,"\033(0");
+	    fprintf(ESCOUT, "\033(0");
 	} else if (TransT == GN_Ucp437) {
-	    fprintf(ESCOUT,"\033(U"); /* switch Linux console to 437 table? */
+	     /*
+	      *  Switch Linux console to 437 table?
+	      */
+	    fprintf(ESCOUT, "\033(U");
 	} else if (TransT == GN_Kuser) {
-	    fprintf(ESCOUT,"\033(K"); /* switch Linux console to user table */
+	     /*
+	      *  Switch Linux console to user table.
+	      */
+	    fprintf(ESCOUT, "\033(K");
 	}
 	if (TransT != GN_dunno && TransT != GN_dontCare) {
 	    lastTransT = TransT;
@@ -200,13 +247,19 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p)
     if (p->enc == UCT_ENC_UTF8) {
 	if (lastUtf != Is_Set) {
 	    Utf = Is_Set;
-	    fprintf(ESCOUT,"\033%%G"); /* turn Linux console UTF8 mode ON */
+	    /*
+	     *  Turn Linux console UTF8 mode ON.
+	     */
+	    fprintf(ESCOUT, "\033%%G");
 	    lastUtf = Utf;
 	}
 	return;
     } else if (lastUtf == Is_Set && Utf != Dont_Care) {
 	Utf = Is_Unset;
-	fprintf(ESCOUT,"\033%%@"); /* turn Linux console UTF8 mode OFF */
+	/*
+	 *  Turn Linux console UTF8 mode OFF.
+	 */
+	fprintf(ESCOUT, "\033%%@");
 	lastUtf = Utf;
     }
 
@@ -216,6 +269,33 @@ PUBLIC void UCChangeTerminalCodepage ARGS2(int, newcs, LYUCcharset *,p)
     lastcs = newcs;
     lastname = name;
 }
+
+#else /* Not LINUX: */
+/*
+ *  This is the thing that actually gets called from display_page().
+ */
+PUBLIC void UCChangeTerminalCodepage ARGS2(
+	int,		newcs,
+	LYUCcharset *,	p)
+{
+    if (TRACE) {
+	fprintf(stderr,
+		"UCChangeTerminalCodepage: Called, but not implemented!");
+    }
+}
 #endif /* LINUX */
+
+#else /* EXP_CHARTRANS_AUTOSWITCH not defined: */
+/*
+ *  This is the thing that actually gets called from display_page().
+ */
+PUBLIC void UCChangeTerminalCodepage ARGS2(
+	int,		newcs,
+	LYUCcharset *,	p)
+{
+    if (TRACE) {
+	fprintf(stderr,
+		"UCChangeTerminalCodepage: Called, but not implemented!");
+    }
+}
 #endif /* EXP_CHARTRANS_AUTOSWITCH */
-#endif /* EXP_CHARTRANS */
diff --git a/src/UCAuto.h b/src/UCAuto.h
index 3f43e0c7..b4d582c3 100644
--- a/src/UCAuto.h
+++ b/src/UCAuto.h
@@ -1 +1,7 @@
-extern void UCChangeTerminalCodepage PARAMS((int newcs, LYUCcharset * p));
+
+#ifndef UCAUTO_H
+#define UCAUTO_H
+
+extern void UCChangeTerminalCodepage PARAMS((int newcs, LYUCcharset *p));
+
+#endif /* UCAUTO_H */
diff --git a/src/UCAux.c b/src/UCAux.c
index cca77ebc..db88bbcf 100644
--- a/src/UCAux.c
+++ b/src/UCAux.c
@@ -1,4 +1,3 @@
-#ifdef EXP_CHARTRANS
 #include "HTUtils.h"
 #include "tcp.h"
 
@@ -10,7 +9,8 @@
 extern HTCJKlang HTCJK;
 extern LYUCcharset LYCharSet_UC[];
 
-PUBLIC BOOL UCCanUniTranslateFrom ARGS1(int, from)
+PUBLIC BOOL UCCanUniTranslateFrom ARGS1(
+	int,		from)
 {
     if (from < 0)
 	return NO;
@@ -21,21 +21,24 @@ PUBLIC BOOL UCCanUniTranslateFrom ARGS1(int, from)
 	return YES;
     return (LYCharSet_UC[from].UChndl >= 0);
 }
-PUBLIC BOOL UCCanTranslateUniTo ARGS1(int, to)
+PUBLIC BOOL UCCanTranslateUniTo ARGS1(
+	int,		to)
 {
     if (to < 0)
 	return NO;
     return YES;			/* well at least some characters... */
 }
-PUBLIC BOOL UCCanTranslateFromTo ARGS2(int, from, int, to)
+PUBLIC BOOL UCCanTranslateFromTo ARGS2(
+	int,		from,
+	int,		to)
 {
-    if (from==to)
+    if (from == to)
 	return YES;
     if (from < 0 || to < 0)
 	return NO;
-    if (from==0)
+    if (from == 0)
 	return UCCanTranslateUniTo(to);
-    if (to==0)
+    if (to == 0)
 	return UCCanUniTranslateFrom(from);
     if (LYCharSet_UC[to].enc == UCT_ENC_UTF8) {
 	return (LYCharSet_UC[from].UChndl >= 0);
@@ -43,61 +46,62 @@ PUBLIC BOOL UCCanTranslateFromTo ARGS2(int, from, int, to)
     {
 	char * fromname = LYCharSet_UC[from].MIMEname;
 	char * toname = LYCharSet_UC[to].MIMEname;
-	if (0==strcmp(fromname,"x-transparent") ||
-	    0==strcmp(toname,"x-transparent")) {
+	if (!strcmp(fromname, "x-transparent") ||
+	    !strcmp(toname, "x-transparent")) {
 	    return YES;
 	}
 	if (LYCharSet_UC[from].enc == UCT_ENC_CJK) {
 	    if (HTCJK == NOCJK)	/* use that global flag, for now */
 		return NO;
-	    if (HTCJK == JAPANESE && (
-		0==strcmp(fromname,"euc-jp") ||
-		0==strncmp(fromname,"iso-2022-jp",11) ||
-		0==strcmp(fromname,"shift_jis")
-		))
+	    if (HTCJK == JAPANESE &&
+		(!strcmp(fromname, "euc-jp") ||
+		 !strncmp(fromname, "iso-2022-jp",11) ||
+		 !strcmp(fromname, "shift_jis")))
 		return YES;
-	    return NO;	/* if not handled by (from==to) above */
+	    return NO;	/* if not handled by (from == to) above */
 	}
-	if (0==strcmp(fromname,"koi8-r")) {
-	    			/* will try to uses stripping of high bit... */
+	if (!strcmp(fromname, "koi8-r")) {
+	    /*
+	     *  Will try to uses stripping of high bit...
+	     */
 	    return YES;
 	}
 	    
-	if (0==strcmp(fromname,"koi8-r") || /* from cyrillic */
-	    0==strcmp(fromname,"iso-8859-5") ||
-	    0==strcmp(fromname,"koi-8")) {
-	    if (0!=strcmp(toname,"iso-8859-5") &&
-		0!=strcmp(toname,"koi8-r") &&
-		0!=strcmp(toname,"iso-8859-2"))
+	if (!strcmp(fromname, "koi8-r") || /* from cyrillic */
+	    !strcmp(fromname, "iso-8859-5") ||
+	    !strcmp(fromname, "koi-8")) {
+	    if (strcmp(toname, "iso-8859-5") &&
+		strcmp(toname, "koi8-r") &&
+		strcmp(toname, "iso-8859-2"))
 		return NO;
 	}
     }
     return (LYCharSet_UC[from].UChndl >= 0);
 }
 
-/* The idea here is that any stage of the stream pipe which is interested
-** in some charset dependent processing will call this function.
-** Given input and ouptput charsets, this function will set various flags
-** in a UCTransParams structure that _suggest_ to the caller what to do.
-**
-** Should be called once when a stage starts processing text (and the
-** input and output charsets are known), or whenever one of input or
-** output charsets has changed (e.g. by SGML.c stage after HTML.c stage
-** has processed a META tag).
-** The global flags (LYRawMode, HTPassEightBitRaw etc.) are currently
-** not taken into account here, it's still up to the caller to do something
-** about them.
-*/
+/*
+ *  The idea here is that any stage of the stream pipe which is interested
+ *  in some charset dependent processing will call this function.
+ *  Given input and ouptput charsets, this function will set various flags
+ *  in a UCTransParams structure that _suggest_ to the caller what to do.
+ *
+ *  Should be called once when a stage starts processing text (and the
+ *  input and output charsets are known), or whenever one of input or
+ *  output charsets has changed (e.g. by SGML.c stage after HTML.c stage
+ *  has processed a META tag).
+ *  The global flags (LYRawMode, HTPassEightBitRaw etc.) are currently
+ *  not taken into account here, it's still up to the caller to do something
+ *  about them.
+ */
 PUBLIC void UCSetTransParams ARGS5(
     UCTransParams *, 	pT,
     int,		cs_in,
     CONST LYUCcharset*,	p_in,
     int,		cs_out,
-    CONST LYUCcharset*,	p_out
-    )
+    CONST LYUCcharset*,	p_out)
 {
-    pT->transp = (0==strcmp(p_in->MIMEname,"x-transparent") ||
-		0==strcmp(p_out->MIMEname,"x-transparent"));
+    pT->transp = (!strcmp(p_in->MIMEname, "x-transparent") ||
+		  !strcmp(p_out->MIMEname, "x-transparent"));
     if (pT->transp) {
 	pT->do_cjk = FALSE;
 	pT->decode_utf8 = FALSE;
@@ -121,23 +125,21 @@ PUBLIC void UCSetTransParams ARGS5(
 	    pT->use_raw_char_in = FALSE; /* not used for CJK */
 	    pT->trans_from_uni = FALSE; /* not used for CJK */
 	} else {
-	    intm_ucs = (
-		cs_in == 0 || pT->decode_utf8 ||
-	    (p_in->codepoints & (UCT_CP_SUBSETOF_LAT1|UCT_CP_SUBSETOF_UCS2))
-		);
+	    intm_ucs = (cs_in == 0 || pT->decode_utf8 ||
+			(p_in->codepoints &
+			 (UCT_CP_SUBSETOF_LAT1|UCT_CP_SUBSETOF_UCS2)));
 	    pT->trans_to_uni = (!intm_ucs &&
 				UCCanUniTranslateFrom(cs_in));
-	    pT->strip_raw_char_in =
-		((!intm_ucs ||
-		  (p_out->enc==UCT_ENC_7BIT) ||
-		  (p_out->repertoire & UCT_REP_SUBSETOF_LAT1)) &&
-		cs_in != cs_out &&
-		0==strcmp(p_in->MIMEname,"koi8-r"));
+	    pT->strip_raw_char_in = ((!intm_ucs ||
+				      (p_out->enc == UCT_ENC_7BIT) ||
+				       (p_out->repertoire &
+				        UCT_REP_SUBSETOF_LAT1)) &&
+				     cs_in != cs_out &&
+				     !strcmp(p_in->MIMEname, "koi8-r"));
 	    use_ucs = (intm_ucs || pT->trans_to_uni);
 	    pT->do_8bitraw = (!use_ucs);
 	    pT->pass_160_173_raw = (!use_ucs &&
-				    !(p_in->like8859 & UCT_R_8859SPECL)
-			      );
+				    !(p_in->like8859 & UCT_R_8859SPECL));
 	    pT->use_raw_char_in = (!pT->output_utf8 && cs_in == cs_out);
 	    pT->trans_from_uni = (use_ucs && !pT->do_8bitraw &&
 				  !pT->use_raw_char_in &&
@@ -149,46 +151,48 @@ PUBLIC void UCSetTransParams ARGS5(
 PUBLIC void UCTransParams_clear ARGS1(
     UCTransParams *,    pT)
 {
-	pT->transp = FALSE;
-	pT->do_cjk = FALSE;
-	pT->decode_utf8 = FALSE;
-	pT->output_utf8 = FALSE;
-	pT->do_8bitraw = FALSE;
-	pT->use_raw_char_in = FALSE;
-	pT->strip_raw_char_in = FALSE;
-	pT->pass_160_173_raw = FALSE;
-	pT->trans_to_uni = FALSE;
-	pT->trans_from_uni = FALSE;
+    pT->transp = FALSE;
+    pT->do_cjk = FALSE;
+    pT->decode_utf8 = FALSE;
+    pT->output_utf8 = FALSE;
+    pT->do_8bitraw = FALSE;
+    pT->use_raw_char_in = FALSE;
+    pT->strip_raw_char_in = FALSE;
+    pT->pass_160_173_raw = FALSE;
+    pT->trans_to_uni = FALSE;
+    pT->trans_from_uni = FALSE;
 }
 
-/* Given an output target HTStream* (can also be a HTStructured* via typecast),
-** the target stream's put_character method, and a unicode character, 
-** CPutUtf8_charstring() will either output the UTF8 encoding of the unicode
-** and return YES, or do nothing and return NO (if conversion would be
-** unnecessary or the unicode character is considered invalid).
-**
-** [Could be used more generally, but is currently only used for &#nnnnn 
-** stuff - generation of UTF8 from 8-bit encoded charsets not yet done
-** by SGML.c etc.]
-*/
+/*
+ *  Given an output target HTStream* (can also be a HTStructured* via
+ *  typecast), the target stream's put_character method, and a unicode
+ *  character,  CPutUtf8_charstring() will either output the UTF8
+ *  encoding of the unicode and return YES, or do nothing and return
+ *  NO (if conversion would be unnecessary or the unicode character is
+ *  considered invalid).
+ *
+ *  [Could be used more generally, but is currently only used for &#nnnnn 
+ *  stuff - generation of UTF8 from 8-bit encoded charsets not yet done
+ *  by SGML.c etc.]
+ */
 #define PUTC(ch) ((*myPutc)(target, (char)(ch)))
 #define PUTC2(ch) ((*myPutc)(target,(char)(0x80|(0x3f &(ch)))))
 
 PUBLIC BOOL UCPutUtf8_charstring ARGS3(
-    HTStream *,	target,
-    putc_func_t *,	myPutc,
-    long,	code)
+	HTStream *,	target,
+	putc_func_t *,	myPutc,
+	long,		code)
 {
     if (code < 128)
 	return NO;		/* indicate to caller we didn't handle it */
-    else if   (code <     0x800L) {
+    else if   (code < 0x800L) {
 	PUTC(0xc0 | (code>>6));
 	PUTC2(code);
-    } else if (code <   0x10000L) {
+    } else if (code < 0x10000L) {
 	PUTC(0xe0 | (code>>12));
 	PUTC2(code>>6);
 	PUTC2(code);
-    } else if (code <  0x200000L) {
+    } else if (code < 0x200000L) {
 	PUTC(0xf0 | (code>>18));
 	PUTC2(code>>12);
 	PUTC2(code>>6);
@@ -199,7 +203,7 @@ PUBLIC BOOL UCPutUtf8_charstring ARGS3(
 	PUTC2(code>>12);
 	PUTC2(code>>6);
 	PUTC2(code);
-    } else if (code<=0x7fffffffL) {
+    } else if (code <= 0x7fffffffL) {
 	PUTC(0xfc | (code>>30));
 	PUTC2(code>>24);
 	PUTC2(code>>18);
@@ -210,4 +214,3 @@ PUBLIC BOOL UCPutUtf8_charstring ARGS3(
 	return NO;
     return YES;
 }
-#endif /* EXP_CHARTRANS */
diff --git a/src/UCdomap.c b/src/UCdomap.c
index 473fe181..a443b7f4 100644
--- a/src/UCdomap.c
+++ b/src/UCdomap.c
@@ -1,32 +1,60 @@
 /*
  * UCmap.c
- * - K&R compatibility macros not (yet?) done -
+ *  =======
  *
  * Derived from code in the Linux kernel console driver.
  * The GNU Public Licence therefore applies, see 
  * the file COPYING in the about_lynx directory 
  * which should come with every Lynx distribution.
  *
- * [ original comment: -kw ]
+ *  [ original comment: - KW ]
  *
  * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
  * to font positions.
  *
  * aeb, 950210
  */
-
-#include "chrtrans/UCkd.h"
+#include "HTUtils.h"
 #include "tcp.h"
 #include "HTMLDTD.h"
-#include "HTAAUtil.h"		/* defines FREE */
-#include "HTAtom.h"		/* for use by UC_setup_LYCharSets_repl() */
+
 #include "LYGlobalDefs.h"
-#include "LYCharSets.h"
+#ifdef VMS
+#include "[.chrtrans]UCkd.h"
+#else
+#include "chrtrans/UCkd.h"
+#endif /* VMS */
 #include "UCdomap.h"
 #include "UCMap.h"
 #include "UCDefs.h"
+#include "LYCharSets.h"
 
-		/* Include hash tables & parameters */
+/*
+ *  Include hash tables & parameters.
+ */
+#ifdef VMS
+#include "[.chrtrans]def7_uni.h"
+#include "[.chrtrans]iso01_uni.h"
+#include "[.chrtrans]iso02_uni.h"
+#include "[.chrtrans]iso03_uni.h"
+#include "[.chrtrans]iso04_uni.h"
+#include "[.chrtrans]iso05_uni.h"
+#include "[.chrtrans]iso07_uni.h"
+#include "[.chrtrans]iso09_uni.h"
+#include "[.chrtrans]iso10_uni.h"
+#include "[.chrtrans]koi8r_uni.h"
+#include "[.chrtrans]cp437_uni.h"
+#include "[.chrtrans]cp850_uni.h"
+#include "[.chrtrans]cp852_uni.h"
+#include "[.chrtrans]cp1250_uni.h"
+#include "[.chrtrans]cp1252_uni.h"
+#include "[.chrtrans]utf8_uni.h"
+#include "[.chrtrans]rfc_suni.h"
+#include "[.chrtrans]mnemonic_suni.h"
+#ifdef NOTDEFINED 
+#include "[.chrtrans]mnem_suni.h"
+#endif /* NOTDEFINED */
+#else
 #include "chrtrans/def7_uni.h"
 #include "chrtrans/iso01_uni.h"
 #include "chrtrans/iso02_uni.h"
@@ -45,17 +73,26 @@
 #include "chrtrans/utf8_uni.h"
 #include "chrtrans/rfc_suni.h"
 #include "chrtrans/mnemonic_suni.h"
-/* #include "chrtrans/mnem_suni.h" */
+#ifdef NOTDEFINED
+#include "chrtrans/mnem_suni.h"
+#endif /* NOTDEFINED */
+#endif /* VMS */
 
-/* Some of the code below, and some of the comments, left in for
-   historical reasons.  Not all those tables below are currently
-   really needed (and what with all those hardwired codepoints), 
-   but let's keep them around for now, they may come in handy if we 
-   decide to make more extended use of the mechanisms (including e.g.
-   for chars < 127...)  - kw */
+#define FREE(x) if (x) {free(x); x = NULL;}
 
-static u16 translations[][256] = {
-  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
+/*
+ *  Some of the code below, and some of the comments, are left in for
+ *  historical reasons.  Not all those tables below are currently
+ *  really needed (and what with all those hardwired codepoints), 
+ *  but let's keep them around for now.  They may come in handy if we 
+ *  decide to make more extended use of the mechanisms (including e.g.
+ *  for chars < 127...).  - KW
+ */
+
+PRIVATE u16 translations[][256] = {
+  /*
+   *  8-bit Latin-1 mapped to Unicode -- trivial mapping.
+   */
   {
     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
@@ -90,7 +127,9 @@ static u16 translations[][256] = {
     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
   }, 
-  /* VT100 graphics mapped to Unicode */
+  /*
+   *  VT100 graphics mapped to Unicode.
+   */
   {
     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
@@ -125,7 +164,9 @@ static u16 translations[][256] = {
     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
   },
-  /* IBM Codepage 437 mapped to Unicode */
+  /*
+   *  IBM Codepage 437 mapped to Unicode.
+   */
   {
     0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
     0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
@@ -160,7 +201,9 @@ static u16 translations[][256] = {
     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
   }, 
-  /* User mapping -- default to codes for direct font mapping */
+  /*
+   *  User mapping -- default to codes for direct font mapping.
+   */
   {
     0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
     0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
@@ -203,13 +246,80 @@ static u16 *UC_translate = NULL;
 
 #define MAX_GLYPH 512		/* Max possible glyph value */
 
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+PRIVATE unsigned char * inv_translate = NULL;
+PRIVATE unsigned char inv_norm_transl[MAX_GLYPH];
+PRIVATE unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
 
+PRIVATE void set_inverse_transl PARAMS((
+	int		i));
+PRIVATE u16 *set_translate PARAMS((
+	int		m));
+#ifdef NOTDEFINED
+PRIVATE unsigned char inverse_translate PARAMS((int glyph));
+PRIVATE int con_set_trans_old PARAMS((unsigned char *arg));
+PRIVATE int con_get_trans_old PARAMS((unsigned char *arg));
+PRIVATE int con_set_trans_new PARAMS((u16 *arg));
+PRIVATE int con_get_trans_new PARAMS((u16 *arg));
+#endif /* NOTDEFINED */
+PRIVATE int UC_valid_UC_charset PARAMS((
+	int		UC_charset_hndl));
+PRIVATE void UC_con_set_trans PARAMS((
+	int		UC_charset_in_hndl,
+	int		Gn,
+	int		update_flag));
+PRIVATE int con_insert_unipair PARAMS((
+	u16 		unicode,
+	u16		fontpos));
+PRIVATE int con_insert_unipair_str PARAMS((
+	u16		unicode,
+	char *		replace_str));
 PRIVATE void con_clear_unimap NOPARAMS;
-
-PRIVATE void set_inverse_transl ARGS1(int, i)
+PRIVATE void con_clear_unimap_str NOPARAMS;
+#ifdef NOTDEFINED
+PRIVATE int con_set_unimap PARAMS((
+	u16			ct,
+	struct unipair *	list));
+#endif /* NOTDEFINED */
+PRIVATE void con_set_default_unimap NOPARAMS;
+PRIVATE int UC_con_set_unimap PARAMS((
+	int		UC_charset_out_hndl,
+	int		update_flag));
+PRIVATE int UC_con_set_unimap_str PARAMS((
+	u16			ct,
+	struct unipair_str *	list));
+#ifdef NOTDEFINED
+PRIVATE int con_get_unimap PARAMS((
+	u16			ct,
+	u16 *			uct,
+	struct unipair *	list));
+#endif /* NOTDEFINED */
+PRIVATE int conv_uni_to_pc PARAMS((
+	long			ucs));
+PRIVATE int conv_uni_to_str PARAMS((
+	char*		outbuf,
+	int		buflen,
+	long		ucs));
+PRIVATE void UCconsole_map_init NOPARAMS;
+PRIVATE int UC_MapGN PARAMS((
+	int		UChndl,
+	int		update_flag));
+PRIVATE int UC_FindGN_byMIME PARAMS((
+	char *		UC_MIMEcharset));
+PRIVATE void UCreset_allocated_LYCharSets NOPARAMS;
+PRIVATE void UCfree_allocated_LYCharSets NOPARAMS;
+PRIVATE char ** UC_setup_LYCharSets_repl PARAMS((
+	int		UC_charset_in_hndl,
+	int		lowest8));
+PRIVATE int UC_Register_with_LYCharSets PARAMS((
+	int		s,
+	char *		UC_MIMEcharset,
+	char *		UC_LYNXcharset,
+	int		lowest_eightbit));
+PRIVATE void UCcleanup_mem NOPARAMS;
+
+
+PRIVATE void set_inverse_transl ARGS1(
+	int,		i)
 {
 	int j, glyph;
 	u16 *p = translations[i];
@@ -235,7 +345,7 @@ PRIVATE void set_inverse_transl ARGS1(int, i)
 	}
 }
 
-u16 *set_translate ARGS1(int, m)
+PRIVATE u16 *set_translate ARGS1(int, m)
 {
 	if (!inverse_translations[m])
 		set_inverse_transl(m);
@@ -251,13 +361,16 @@ u16 *set_translate ARGS1(int, m)
  *    was active, or using Unicode.
  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
  */
-unsigned char inverse_translate(int glyph) {
-	if ( glyph < 0 || glyph >= MAX_GLYPH )
+PRIVATE unsigned char inverse_translate ARGS1(
+	int,		glyph)
+{
+    if (glyph < 0 || glyph >= MAX_GLYPH) {
 		return 0;
-	else
-		return ((inv_translate && inv_translate[glyph])
-			? inv_translate[glyph]
-			: (unsigned char)(glyph & 0xff));
+    } else {
+	return ((inv_translate && inv_translate[glyph]) ?
+				   inv_translate[glyph] :
+				   (unsigned char)(glyph & 0xff));
+    }
 }
 
 /*
@@ -302,7 +415,8 @@ int con_get_trans_old(unsigned char * arg)
 	return 0;
 }
 
-int con_set_trans_new(u16 * arg)
+PRIVATE int con_set_trans_new ARGS1(
+	u16 *,		arg)
 {
 	int i;
 	u16 *p = translations[USER_MAP];
@@ -319,7 +433,8 @@ int con_set_trans_new(u16 * arg)
 	return 0;
 }
 
-int con_get_trans_new(u16 * arg)
+PRIVATE int con_get_trans_new ARGS1(
+	u16 *		arg)
 {
 	int i;
 	u16 *p = translations[USER_MAP];
@@ -336,22 +451,22 @@ int con_get_trans_new(u16 * arg)
 }
 #endif /* NOTDEFINED */
 
-
-PRIVATE int
-UC_valid_UC_charset ARGS1(int, UC_charset_hndl)
+PRIVATE int UC_valid_UC_charset ARGS1(
+	int,		UC_charset_hndl)
 {
   return (UC_charset_hndl >= 0 && UC_charset_hndl < UCNumCharsets);
 }
 
-PRIVATE void
-UC_con_set_trans ARGS3(int, UC_charset_in_hndl, int, Gn, int, update_flag)
+PRIVATE void UC_con_set_trans ARGS3(
+	int,		UC_charset_in_hndl,
+	int,		Gn,
+	int,		update_flag)
 {
   int i, j;
   u16 *p;
   u16 *ptrans;
 
-  if (!UC_valid_UC_charset(UC_charset_in_hndl))
-    {
+    if (!UC_valid_UC_charset(UC_charset_in_hndl)) {
       if (TRACE)
 	fprintf(stderr,"UC_con_set_trans: Invalid charset handle %i.\n",
 		UC_charset_in_hndl);
@@ -363,23 +478,26 @@ UC_con_set_trans ARGS3(int, UC_charset_in_hndl, int, Gn, int, update_flag)
   if (p == UC_current_unitable) {    /* test whether pointers are equal */
     return;			/* nothing to be done */
   }
-  /* The font is always 256 characters - so far. */
-
+    /*
+     *  The font is always 256 characters - so far.
+     */
   con_clear_unimap();
 #endif
-  for ( i = 0 ; i < 256 ; i++ )
-    {
+    for (i = 0; i < 256; i++) {
       if ((j = UCInfo[UC_charset_in_hndl].unicount[i])) {
 	ptrans[i] = *p;
-	for ( ; j ; j-- )
+	    for (; j; j--) {
 	  p++;
       }
-      else
+	} else {
 	ptrans[i] = 0xfffd;
     }
-  if (update_flag)  
+    }
+    if (update_flag) {
     set_inverse_transl(Gn);    /* Update inverse translation for this one */
 }
+}
+
 /*
  * Unicode -> current font conversion 
  *
@@ -408,11 +526,12 @@ static char* **uni_pagedir_str[32] =
   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-u16 * UC_current_unitable = NULL;
-struct unimapdesc_str *UC_current_unitable_str = NULL;
+PRIVATE u16 * UC_current_unitable = NULL;
+PRIVATE struct unimapdesc_str *UC_current_unitable_str = NULL;
 
-PRIVATE int
-con_insert_unipair ARGS2(u16, unicode, u16, fontpos)
+PRIVATE int con_insert_unipair ARGS2(
+	u16, 		unicode,
+	u16,		fontpos)
 {
   int i, n;
   u16 **p1, *p2;
@@ -442,8 +561,9 @@ con_insert_unipair ARGS2(u16, unicode, u16, fontpos)
   return 0;
 }
  
-PRIVATE int
-con_insert_unipair_str ARGS2(u16, unicode, char *, replace_str)
+PRIVATE int con_insert_unipair_str ARGS2(
+	u16,		unicode,
+	char *,		replace_str)
 {
   int i, n;
   char ***p1, **p2;
@@ -480,16 +600,12 @@ con_clear_unimap NOARGS
   int i, j;
   u16 **p1;
   
-  for ( i = 0 ; i < 32 ; i++ )
-    {
-      if ( (p1 = uni_pagedir[i]) != NULL )
-	{
-	  for ( j = 0 ; j < 32 ; j++ )
-	    {
-	      if ( p1[j] )
-		free(p1[j]);
+    for (i = 0; i < 32; i++) {
+	if ((p1 = uni_pagedir[i]) != NULL) {
+	    for (j = 0; j < 32; j++) {
+		FREE(p1[j]);
 	    }
-	  free(p1);
+	    FREE(p1);
 	}
       uni_pagedir[i] = NULL;
     }
@@ -503,16 +619,12 @@ con_clear_unimap_str NOARGS
   int i, j;
   char ***p1;
   
-  for ( i = 0 ; i < 32 ; i++ )
-    {
-      if ( (p1 = uni_pagedir_str[i]) != NULL )
-	{
-	  for ( j = 0 ; j < 32 ; j++ )
-	    {
-	      if ( p1[j] )
-		free(p1[j]);
+    for (i = 0; i < 32; i++) {
+	if ((p1 = uni_pagedir_str[i]) != NULL) {
+	    for (j = 0; j < 32; j++) {
+		FREE(p1[j]);
 	    }
-	  free(p1);
+	    FREE(p1);
 	}
       uni_pagedir_str[i] = NULL;
     }
@@ -574,14 +686,14 @@ PUBLIC int UCLYhndl_HTFile_for_unrec = -1;
 PUBLIC int UCLYhndl_for_unspec = -1;
 PUBLIC int UCLYhndl_for_unrec = -1;
 
-PRIVATE int
-UC_con_set_unimap ARGS2(int, UC_charset_out_hndl, int, update_flag)
+PRIVATE int UC_con_set_unimap ARGS2(
+	int,		UC_charset_out_hndl,
+	int,		update_flag)
 {
   int i, j;
   u16 *p;
 
-  if (!UC_valid_UC_charset(UC_charset_out_hndl))
-    {
+    if (!UC_valid_UC_charset(UC_charset_out_hndl)) {
       if (TRACE)
 	fprintf(stderr,"UC_con_set_unimap: Invalid charset handle %i.\n",
 		UC_charset_out_hndl);
@@ -598,9 +710,11 @@ UC_con_set_unimap ARGS2(int, UC_charset_out_hndl, int, update_flag)
 
   con_clear_unimap();
 
-  for ( i = 0 ; i < 256 ; i++ )
-    for ( j = UCInfo[UC_charset_out_hndl].unicount[i] ; j ; j-- )
+    for (i = 0; i < 256; i++) {
+ 	for (j = UCInfo[UC_charset_out_hndl].unicount[i]; j; j--) {
       con_insert_unipair(*(p++), i);
+	}
+    }
 
   if (update_flag)
     for ( i = 0 ; i <= 3 ; i++ )
@@ -621,8 +735,13 @@ UC_con_set_unimap_str ARGS2(u16, ct, struct unipair_str *, list)
       list++;
     }
 
-     /* No inverse translations for replacement strings! */
-  if (!err) hashtable_str_contents_valid = 1;  
+    /* 
+     *  No inverse translations for replacement strings!
+     */
+    if (!err) {
+	hashtable_str_contents_valid = 1;  
+    }
+
   return err;
 }
 
@@ -656,8 +775,8 @@ con_get_unimap ARGS3(u16, ct, u16 *, uct, struct unipair *, list)
 }
 #endif
 
-int
-conv_uni_to_pc ARGS1(long, ucs) 
+PRIVATE int conv_uni_to_pc ARGS1(
+	long,		ucs) 
 {
   int h;
   u16 **p1, *p2;
@@ -688,9 +807,13 @@ conv_uni_to_pc ARGS1(long, ucs)
   return -4;		/* not found */
 }
 
-/* Note: contents of outbuf is not changes for negative return value! */
-PRIVATE int
-conv_uni_to_str ARGS3(char*, outbuf, int, buflen, long, ucs) 
+/*
+ *  Note: contents of outbuf is not changes for negative return value!
+ */
+PRIVATE int conv_uni_to_str ARGS3(
+	char*,		outbuf,
+	int,		buflen,
+	long,		ucs) 
 {
   char *h;
   char ***p1, **p2;
@@ -722,12 +845,16 @@ conv_uni_to_str ARGS3(char*, outbuf, int, buflen, long, ucs)
     strncpy (outbuf,h,(size_t) (buflen-1));
     return 1;     /* ok ! */
   }
-  return -4;		/* not found */
+
+    /*
+     *  Not found.
+     */
+    return -4;
 }
 
 PUBLIC int UCInitialized = 0;
 /*
- * [ original comment: - kw ]
+ *  [ original comment: - KW ]
  * This is called at sys_setup time, after memory and the console are
  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
  * from this function, hence the call from sys_setup.
@@ -739,12 +866,17 @@ UCconsole_map_init NOARGS
   UCInitialized = 1;
 }
 
-/* OK now, finally, some stuff that is more specifically for Lynx: - kw */
-
+/*
+ *  OK now, finally, some stuff that is more specifically for Lynx: - KW
+ */
+#ifdef NOTDEFINED
 PUBLIC int UCGetcharset_byMIMEname PARAMS((char * UC_MIMEcharset));
 PUBLIC int UCGetcharset_byLYNXname PARAMS((char * UC_LYNXcharset));
+#endif /* NOTDEFINED */
 
-PUBLIC int UCTransUniChar ARGS2(long, unicode, int, charset_out)
+PUBLIC int UCTransUniChar ARGS2(
+	long,		unicode,
+	int,		charset_out)
 {
   int rc;
   int UChndl_out;
@@ -756,18 +888,25 @@ PUBLIC int UCTransUniChar ARGS2(long, unicode, int, charset_out)
   ut = UCInfo[UChndl_out].unitable;
   if (ut != UC_current_unitable) {
     rc = UC_con_set_unimap(UChndl_out, 1);
-    if (rc < 0)
+	if (rc < 0) {
       return rc;
   }
+    }
   rc = conv_uni_to_pc(unicode);
   if (rc == -4)
     rc = conv_uni_to_pc(0xfffd);
   return rc;
 }
-/* returns string length, or negative value for error. */
   
-PUBLIC int UCTransUniCharStr ARGS5(char *, outbuf, int, buflen, long, unicode,
-			     int, charset_out, int, chk_single_flag)
+/*
+ *  Returns string length, or negative value for error.
+ */
+PUBLIC int UCTransUniCharStr ARGS5(
+	char *,		outbuf,
+	int,		buflen,
+	long,		unicode,
+	int,		charset_out,
+	int,		chk_single_flag)
 {
   int rc, src = 0, ignore_err;
   int UChndl_out;
@@ -784,13 +923,15 @@ if (buflen<2)
     ut = UCInfo[UChndl_out].unitable;
     if (ut != UC_current_unitable) {
       src = UC_con_set_unimap(UChndl_out, 1);
-      if (src < 0)
+	    if (src < 0) {
 	return src;
     }
+	}
     src = conv_uni_to_pc(unicode);
     if (src >= 32) {
       outbuf[0] = src; outbuf[1] = '\0';
-      return 1; }
+	    return 1;
+	}
   }
 
   repl = &(UCInfo[UChndl_out].replacedesc);
@@ -809,34 +950,41 @@ if (buflen<2)
     rc = conv_uni_to_pc(0xfffd);
     if (rc >= 32) {
       outbuf[0] = rc; outbuf[1] = '\0';
-      return 1; }
-    else return rc;
+	    return 1; 
+	}
+	return rc;
   }
   return -4;
 }
 
-int UC_lastautoGN = 0;
+PRIVATE int UC_lastautoGN = 0;
 
-PRIVATE int UC_MapGN ARGS2(int, UChndl, int, update_flag)
+PRIVATE int UC_MapGN ARGS2(
+	int,		UChndl,
+	int,		update_flag)
 {
   int i,Gn,found,lasthndl;
   found = 0;
   Gn = -1;
   for (i=0; i<4 && Gn<0; i++) { 
-    if (UC_GNhandles[i] < 0)
+	if (UC_GNhandles[i] < 0) {
+	    Gn = i;
+	} else if (UC_GNhandles[i] == UChndl) {
       Gn = i;
-    else if (UC_GNhandles[i] == UChndl)
-      {Gn = i; found = 1;}
+	    found = 1;
   }
-  if (found) return Gn;
+    }
+    if (found) 
+	return Gn;
   if (Gn >= 0) {
     UCInfo[UChndl].GN = Gn;
     UC_GNhandles[Gn] = UChndl;
-  }
-  else {
-    if (UC_lastautoGN == GRAF_MAP)
+    } else {
+	if (UC_lastautoGN == GRAF_MAP) {
       Gn = IBMPC_MAP;
-    else Gn = GRAF_MAP;
+	} else {
+	    Gn = GRAF_MAP;
+	}
     UC_lastautoGN = Gn;
     lasthndl = UC_GNhandles[Gn];
     UCInfo[lasthndl].GN = -1;
@@ -847,7 +995,10 @@ PRIVATE int UC_MapGN ARGS2(int, UChndl, int, update_flag)
   return Gn;
 }
   
-PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out)
+PUBLIC int UCTransChar ARGS3(
+	char,		ch_in,
+	int,		charset_in,
+	int,		charset_out)
 {
   int unicode, Gn;
   int rc;
@@ -858,27 +1009,33 @@ PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out)
 #ifndef UC_NO_SHORTCUTS
   if (charset_in == charset_out)
     return (unsigned char)ch_in;
-#endif
-  if (charset_in < 0) return -11;
+#endif /* UC_NO_SHORTCUTS */
+    if (charset_in < 0)
+	return -11;
   if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0)
     return -11;
   if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0)
     return -12;
   if (!UCInfo[UChndl_in].num_uni)
     return -11;
-  if ((Gn = UCInfo[UChndl_in].GN) < 0)
-    {Gn = UC_MapGN(UChndl_in,0); upd = 1;}
+    if ((Gn = UCInfo[UChndl_in].GN) < 0) {
+	Gn = UC_MapGN(UChndl_in,0);
+	upd = 1;
+    }
 
   ut = UCInfo[UChndl_out].unitable;
-  if (ut == UC_current_unitable) 
-    {if (upd) set_inverse_transl(Gn);}
-  else {
+    if (ut == UC_current_unitable) {
+	if (upd) {
+	    set_inverse_transl(Gn);
+	}
+    } else {
     rc = UC_con_set_unimap(UChndl_out, 1);
-    if (rc > 0)
+	if (rc > 0) {
       set_inverse_transl(Gn);
-    else if (rc < 0)
+	} else if (rc < 0) {
       return rc;
   }
+    }
   UC_translate = set_translate(Gn);
   unicode = UC_translate[(unsigned char)ch_in];
   rc = conv_uni_to_pc(unicode);
@@ -887,7 +1044,9 @@ PUBLIC int UCTransChar ARGS3(char, ch_in, int, charset_in, int, charset_out)
   return rc;
 }
 
-PUBLIC long int UCTransToUni ARGS2(char, ch_in, int, charset_in)
+PUBLIC long int UCTransToUni ARGS2(
+	char,		ch_in,
+	int,		charset_in)
 {
   int unicode, Gn;
   unsigned char ch_iu;
@@ -899,14 +1058,16 @@ PUBLIC long int UCTransToUni ARGS2(char, ch_in, int, charset_in)
     return ch_iu;
   if ((unsigned char)ch_in < 128)
     return ch_iu;
-#endif
-  if (charset_in < 0) return -11;
+#endif /* UC_NO_SHORTCUTS */
+    if (charset_in < 0)
+	return -11;
   if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0)
     return -11;
   if (!UCInfo[UChndl_in].num_uni)
     return -11;
-  if ((Gn = UCInfo[UChndl_in].GN) < 0)
-    {Gn = UC_MapGN(UChndl_in,1);}
+    if ((Gn = UCInfo[UChndl_in].GN) < 0) {
+	Gn = UC_MapGN(UChndl_in,1);
+    }
 
   UC_translate = set_translate(Gn);
   unicode = UC_translate[(unsigned char)ch_in];
@@ -925,11 +1086,13 @@ PUBLIC int UCReverseTransChar ARGS3(char, ch_out, int, charset_in, int, charset_
 #ifndef UC_NO_SHORTCUTS
   if (charset_in == charset_out)
     return ch_out;
-#endif
-  if (charset_in < 0) return -11;
+#endif /* UC_NO_SHORTCUTS */
+    if (charset_in < 0)
+	return -11;
   if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0)
     return -11;
-  if (charset_out < 0) return -12;
+    if (charset_out < 0)
+	return -12;
   if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0)
     return -12;
   if (!UCInfo[UChndl_in].num_uni)
@@ -940,23 +1103,32 @@ PUBLIC int UCReverseTransChar ARGS3(char, ch_out, int, charset_in, int, charset_
     if ((Gn = UCInfo[UChndl_in].GN) >= 0) {
       UC_translate = set_translate(Gn);
       rc = inv_translate[(unsigned int)ch_out];
-      if (rc >= 32) return rc;
+	    if (rc >= 32) {
+		return rc;
     }
-    else {
+	} else {
       Gn = UC_MapGN(UChndl_in,1);
       UC_translate = set_translate(Gn);
       rc = inv_translate[(unsigned int)ch_out];
-      if (rc >= 32) return rc;
+	    if (rc >= 32) {
+		return rc;
+	    }
     }
   }
   return UCTransChar(ch_out, charset_out, charset_in);
 }
-#endif
-
-/* returns string length, or negative value for error. */
+#endif /* UNUSED */
   
-PUBLIC int UCTransCharStr ARGS6(char *, outbuf, int,  buflen, char,  ch_in,
-			int,  charset_in, int,  charset_out, int,  chk_single_flag)
+/*
+ *  Returns string length, or negative value for error.
+ */
+PUBLIC int UCTransCharStr ARGS6(
+	char *,		outbuf,
+	int,		buflen,
+	char,		ch_in,
+	int,		charset_in,
+	int,		charset_out,
+	int,		chk_single_flag)
 {
   int unicode, Gn;
   int rc, src = 0, ignore_err;
@@ -969,10 +1141,13 @@ if (buflen<2)
   return -13;
 #ifndef UC_NO_SHORTCUTS
   if (chk_single_flag && charset_in == charset_out) {
-    outbuf[0] = ch_in; outbuf[1] = '\0';
-    return 1; }
-#endif
-  if (charset_in < 0) return -11;
+	outbuf[0] = ch_in;
+	outbuf[1] = '\0';
+	return 1;
+    }
+#endif /* UC_NO_SHORTCUTS */
+    if (charset_in < 0)
+	return -11;
   if ((UChndl_in = LYCharSet_UC[charset_in].UChndl) < 0)
     return -11;
   if ((UChndl_out = LYCharSet_UC[charset_out].UChndl) < 0)
@@ -987,19 +1162,21 @@ if (buflen<2)
 
   if (chk_single_flag) {
     ut = UCInfo[UChndl_out].unitable;
-    if (ut == UC_current_unitable) 
-      {if (upd) set_inverse_transl(Gn);}
-    else {
+	if (ut == UC_current_unitable) {
+	    if (upd) set_inverse_transl(Gn);
+	} else {
       src = UC_con_set_unimap(UChndl_out, 1);
-      if (src > 0)
+	    if (src > 0) {
 	set_inverse_transl(Gn);
-      else if (src < 0)
+	    } else if (src < 0) {
 	return src;
     }
+	}
     src = conv_uni_to_pc(unicode);
     if (src >= 32) {
       outbuf[0] = src; outbuf[1] = '\0';
-      return 1; }
+	    return 1;
+	}
   }
 
   repl = &(UCInfo[UChndl_out].replacedesc);
@@ -1018,97 +1195,124 @@ if (buflen<2)
     rc = conv_uni_to_pc(0xfffd);
     if (rc >= 32) {
       outbuf[0] = rc; outbuf[1] = '\0';
-      return 1; }
-    else return rc;
+	    return 1;
+	} else {
+	    return rc;
+	}
   }
   return -4;
 }
 
-PRIVATE int UC_FindGN_byMIME ARGS1(char *, UC_MIMEcharset)
+PRIVATE int UC_FindGN_byMIME ARGS1(
+	char *,		UC_MIMEcharset)
 {
   int i;
-  for (i=0; i<4; i++)
-    if (!strcmp(UC_MIMEcharset,UC_GNsetMIMEnames[i]))
+
+    for (i = 0; i < 4; i++) {
+	if (!strcmp(UC_MIMEcharset,UC_GNsetMIMEnames[i])) {
       return i;
+	}
+    }
   return -1;
 }
 
-PUBLIC int UCGetRawUniMode_byLYhndl ARGS1(int, i)
+PUBLIC int UCGetRawUniMode_byLYhndl ARGS1(
+	int,		i)
 {
-  if(i < 0) return 0;
+    if (i < 0)
+	return 0;
   return LYCharSet_UC[i].enc;
 }
 
-/* Currently the charset name has to match exactly -- not substring 
-   matching as was done before (see HTMIME.c, HTML.c).     */  
-PUBLIC int UCGetLYhndl_byMIME ARGS1(CONST char *,UC_MIMEcharset)
+/*
+ *  Currently the charset name has to match exactly -- not substring
+ *  matching as was done before (see HTMIME.c, HTML.c).
+ */
+PUBLIC int UCGetLYhndl_byMIME ARGS1(
+	CONST char *,	UC_MIMEcharset)
 {
   int i;
   int LYhndl = -1;
 
-  if (!UC_MIMEcharset || !(*UC_MIMEcharset)) return -1;
+    if (!UC_MIMEcharset || !(*UC_MIMEcharset))
+	return -1;
 
-  for (i=0; i<MAX_CHARSETS && i<LYNumCharsets &&
-                  LYchar_set_names[i] && LYhndl<0; i++)
+    for (i = 0;
+	 (i < MAXCHARSETS && i < LYNumCharsets &&
+          LYchar_set_names[i] && LYhndl < 0); i++) {
     if (LYCharSet_UC[i].MIMEname &&
 	!strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname)) {
       LYhndl = i;
     }
-  if (LYhndl < 0) {		/* not yet found, special treatment
-			 for several CJK charsets etc... cheating here
-			 Also recognize UTF-8 as synonym for UNICODE-1-1-UTF-8
-			 (The example file for now still uses the long name,
-			 so that's what will be used internally.) */
-      if (0==strcmp(UC_MIMEcharset, "utf-8"))
+    }
+    if (LYhndl < 0) {
+	/*
+	 *  Not yet found, special treatment for several CJK charsets etc...
+	 *  Cheating here.  Also recognize UTF-8 as synonym for
+	 *  UNICODE-1-1-UTF-8 (The example file for now still uses the
+	 *  long name, so that's what will be used internally.).
+	 */
+	if (!strcmp(UC_MIMEcharset, "utf-8")) {
 	  return UCGetLYhndl_byMIME("unicode-1-1-utf-8");
-      if (0==strncmp(UC_MIMEcharset, "iso-2022-jp", 11))
+	}
+	if (!strncmp(UC_MIMEcharset, "iso-2022-jp", 11)) {
 	  return UCGetLYhndl_byMIME("euc-jp");
-      else if (0==strcmp(UC_MIMEcharset, "euc-kr"))
+	} else if (!strcmp(UC_MIMEcharset, "euc-kr")) {
 	  return UCGetLYhndl_byMIME("iso-2022-kr");
-      else if (0==strcmp(UC_MIMEcharset, "gb2312"))
+	} else if (!strcmp(UC_MIMEcharset, "gb2312")) {
 	  return UCGetLYhndl_byMIME("iso-2022-cn");
-      else if (0==strcmp(UC_MIMEcharset, "euc-cn"))
+	} else if (!strcmp(UC_MIMEcharset, "euc-cn")) {
 	  return UCGetLYhndl_byMIME("iso-2022-cn");
-      else if (0==strcmp(UC_MIMEcharset, "koi-8")) /* accentsoft bogosity */
+	} else if (!strcmp(UC_MIMEcharset, "koi-8")) { /* accentsoft bogosity */
 	  return UCGetLYhndl_byMIME("koi8-r");
   }
+    }
   return LYhndl;        /* returns -1 if no charset found by that MIME name */
 }
 
-/* function UC_setup_LYCharSets_repl() tries to set up a subtable in
-   LYCharSets[] appropriate for this new charset, for compatibility
-   with the "old method".  Maybe not nice (maybe not evene necessary
-   any more), but it works (as far as it goes..).
-
-   We try to be conservative and only allocate new memory for this
-   if needed.  If not needed, just point to SevenBitApproximations[i].
-   [Could do the same for ISO_Latin1[] if it's identical to that, but
-    would make it even *more* messy than it already is...]
-   This the only function in this file that knows, or cares, about the
-   HTMLDTD or details of LYCharSets[] subtables (and therefore somewhat
-   violates the idea that this file should be independent of those).
-   As in other places, we rely on ISO_Latin1 being the *first* table
-   in LYCharSets.  - kw */
+/*
+ *  Function UC_setup_LYCharSets_repl() tries to set up a subtable in
+ *  LYCharSets[] appropriate for this new charset, for compatibility
+ *  with the "old method".  Maybe not nice (maybe not evene necessary
+ *  any more), but it works (as far as it goes..).
+ *
+ *  We try to be conservative and only allocate new memory for this
+ *  if needed.  If not needed, just point to SevenBitApproximations[i].
+ *  [Could do the same for ISO_Latin1[] if it's identical to that, but
+ *   would make it even *more* messy than it already is...]
+ *  This the only function in this file that knows, or cares, about the
+ *  HTMLDTD or details of LYCharSets[] subtables (and therefore somewhat
+ *  violates the idea that this file should be independent of those).
+ *  As in other places, we rely on ISO_Latin1 being the *first* table
+ *  in LYCharSets. - KW
+ */
 
-/* We need to remember which ones were allocated and which are static.*/
-static char** remember_allocated_LYCharSets[MAX_CHARSETS];
+/*
+ *  We need to remember which ones were allocated and which are static.
+ */
+PRIVATE char ** remember_allocated_LYCharSets[MAXCHARSETS];
 
 PRIVATE void UCreset_allocated_LYCharSets NOARGS
 {
 	int i=0;
-	for(;i<MAX_CHARSETS;i++)
+	for(;i<MAXCHARSETS;i++)
 	remember_allocated_LYCharSets[i]=NULL;
 }
 
 PRIVATE void UCfree_allocated_LYCharSets NOARGS
 {
     int i=0;
-    for(;i<MAX_CHARSETS;i++)
-    if(remember_allocated_LYCharSets[i]!=NULL)
+
+    for (; i < MAXCHARSETS; i++) {
+	if (remember_allocated_LYCharSets[i] != NULL) {
 	FREE(remember_allocated_LYCharSets[i]);
 }
+    }
+}
 
-PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, lowest8)
+PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(
+	int,		UC_charset_in_hndl,
+	int,		lowest8)
 {
   char ** ISO_Latin1 = LYCharSets[0];
   char **p;
@@ -1120,7 +1324,10 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low
   int i,j,changed;
   u16 k;
   u8 *ti;
-	/* create a temporary table for reverse lookup of latin1 codes: */
+
+    /*
+     *  Create a temporary table for reverse lookup of latin1 codes:
+     */
   tp = (char **) malloc(96 * sizeof(char *));
   if (!tp) return NULL;
   for (i=0; i<96; i++)
@@ -1135,75 +1342,97 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low
 
   pp = UCInfo[UC_charset_in_hndl].unitable;
 
-  /* Determine if we have any mapping of a Unicode in the range 160-255
-     to an allowed code point > 0x80 in our new charset...
-     Store any mappings found in ti[]. */
-  if (UCInfo[UC_charset_in_hndl].num_uni > 0)
-    for ( i = 0 ; i < 256 ; i++ )
-      {
+    /*
+     *  Determine if we have any mapping of a Unicode in the range 160-255
+     *  to an allowed code point > 0x80 in our new charset...
+     *  Store any mappings found in ti[].
+     */
+    if (UCInfo[UC_charset_in_hndl].num_uni > 0) {
+	for (i = 0; i < 256; i++) {
 	if ((j = UCInfo[UC_charset_in_hndl].unicount[i])) {
 	  if ((k = *pp) >= 160 && k < 256 && i >= lowest8) {
 	    ti[k-160] = i;
 	  }
-	  for ( ; j ; j-- )
+		for (; j; j--) {
 	    pp++;
 	}
       }
+	}
+    }
   {
     u16 ct;
     struct unipair_str *list;
     
-  /* Determine if we have any mapping of a Unicode in the range 160-255
-     to a replacement string for our new charset...
-     Store any mappings found in tp[]. */
+	/*
+	 *  Determine if we have any mapping of a Unicode in the range
+	 *  160-255 to a replacement string for our new charset...
+	 *  Store any mappings found in tp[].
+	 */
     ct = UCInfo[UC_charset_in_hndl].replacedesc.entry_ct;
     list = UCInfo[UC_charset_in_hndl].replacedesc.entries;
-    while( ct-- )
-      {
+	while (ct--) {
 	if ((k = list->unicode) >= 160 && k < 256) {
 	  tp[k-160] = list->replace_str;
 	}
 	list++;
       }
   }
-  /* Now allocate a new table compatible with LYCharSets[] 
-     and with the HTMLDTD for entitied.
-     We don't know yet whether we'll keep it around. */
+    /*
+     *  Now allocate a new table compatible with LYCharSets[] 
+     *  and with the HTMLDTD for entitied.
+     *  We don't know yet whether we'll keep it around. */
   p = prepl = (char **) malloc(HTML_dtd.number_of_entities * sizeof(char *));
   if (!p) {
-    FREE(tp); FREE(ti);
+	FREE(tp);
+	FREE(ti);
     return NULL;
   }
   changed = 0;
   for (i=0; i<HTML_dtd.number_of_entities; i++,p++) {
-      /* For each of those entities, we check what the "old method"
-	 ISO_Latin1[] mapping does with them.  If it is nothing we
-	 want to use, just point to the SevenBitApproximations[] string. */
+	/*
+	 *  For each of those entities, we check what the "old method"
+	 *  ISO_Latin1[] mapping does with them.  If it is nothing we
+	 *  want to use, just point to the SevenBitApproximations[] string.
+	 */
     s7 = SevenBitApproximations[i];
     s8 = ISO_Latin1[i];
     *p = s7;
     if (s8 && (unsigned char)(*s8) >= 160 && strlen(s8) == 1) {
-      /* We have an entity that is mapped to one valid eightbit latin1 char*/
+	    /*
+	     *  We have an entity that is mapped to
+	     *  one valid eightbit latin1 char.
+	     */
       if (ti[(unsigned char)(*s8) - 160] >= lowest8 &&
-	  !(s7[0] == ti[(unsigned char)(*s8) - 160] && s7[1] == '\0')) {
-	  /* ...which in turn is mapped, by our "new method", to another
-	     valid eightbit char for this new charset: either to itself... */
-	if (ti[(unsigned char)(*s8) - 160] == (unsigned char)(*s8))
+		!(s7[0] == ti[(unsigned char)(*s8) - 160] &&
+		s7[1] == '\0')) {
+		/*
+		 *  ...which in turn is mapped, by our "new method",
+		 *   to another valid eightbit char for this new
+		 *   charset: either to itself...
+		 */
+		if (ti[(unsigned char)(*s8) - 160] == (unsigned char)(*s8)) {
 	  *p = s8;
-	else {
-	    /*                                      ...or another byte... */ 
+		} else {
+		    /*
+		     *			      ...or another byte...
+		     */ 
 #ifdef NOTDEFINED
 	  *p = (char *)malloc(2*sizeof(char));
 	  if (!*p) {
-	    FREE(tp); FREE(ti); FREE(prepl);
+			FREE(tp);
+			FREE(ti);
+			FREE(prepl);
 	    return NULL;
 	  }
 	  (*p)[0] = ti[(unsigned char)(*s8) - 160];
 	  (*p)[1] = '\0';
 #else
-	  /* use this instead... make those buggers int HTAtoms, so
-	     they will be cleaned up at exit... all for the sake of
-	     preventing memory leaks, sigh */
+		    /*
+		     *  Use this instead... make those buggers
+		     *  int HTAtoms, so they will be cleaned up
+		     *  at exit... all for the sake of preventing
+		     *  memory leaks, sigh.
+		     */
 	  static char dummy[2];	/* one char dummy string */
 
 	  dummy[0] = ti[(unsigned char)(*s8) - 160];
@@ -1211,11 +1440,12 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low
 #endif /* ! NOTDEFINED */
 	}
 	changed = 1;
-      }
-      else if (tp[(unsigned char)(*s8) - 160] &&
-	       0!=strcmp(s7,tp[(unsigned char)(*s8) - 160])) {
-	  /* ...or which is mapped, by our "new method", to a replacement
-	     string for this new charset. */
+	    } else if (tp[(unsigned char)(*s8) - 160] &&
+		       strcmp(s7, tp[(unsigned char)(*s8) - 160])) {
+		/*
+		 *  ...or which is mapped, by our "new method",
+		 *  to a replacement string for this new charset.
+		 */
 	*p = tp[(unsigned char)(*s8) - 160];
 	changed = 1;
       }
@@ -1228,9 +1458,12 @@ PRIVATE char ** UC_setup_LYCharSets_repl ARGS2(int, UC_charset_in_hndl, int, low
   }
   return prepl;
 }
-/* "New method" meets "Old method" ... */
 
-PRIVATE int UC_Register_with_LYCharSets ARGS4(int, s,
+/*
+ *  "New method" meets "Old method" ...
+ */
+PRIVATE int UC_Register_with_LYCharSets ARGS4(
+	int,		s,
 				       char *, UC_MIMEcharset,
 				       char *, UC_LYNXcharset,
 				       int, lowest_eightbit)
@@ -1239,90 +1472,123 @@ PRIVATE int UC_Register_with_LYCharSets ARGS4(int, s,
   char ** repl;
 
   LYhndl = -1;
-  if (LYNumCharsets == 0) /* initialize here; so whoever changes
-			    LYCharSets.c doesn't have to count... */
-    for (i=0; (i<MAX_CHARSETS) && LYchar_set_names[i]; i++)
+    if (LYNumCharsets == 0) {
+	/*
+	 *  Initialize here; so whoever changes
+	 *  LYCharSets.c doesn't have to count...
+	 */
+	for (i = 0; (i < MAXCHARSETS) && LYchar_set_names[i]; i++) {
       LYNumCharsets = i+1;
+	}
+    }
 
-  /* Do different kinds of searches... after all, this is experimental...*/
-  for (i=0; i<MAX_CHARSETS && LYchar_set_names[i] && LYhndl<0; i++)
-    if (!strcmp(UC_LYNXcharset,LYchar_set_names[i]))
+    /*
+     *  Do different kinds of searches...
+     *  after all, this is experimental...
+     */
+    for (i = 0; i < MAXCHARSETS && LYchar_set_names[i] && LYhndl < 0; i++) {
+	if (!strcmp(UC_LYNXcharset,LYchar_set_names[i])) {
       LYhndl = i;
-  for (i=0; i<MAX_CHARSETS && LYchar_set_names[i] && LYhndl<0; i++)
+	}
+    }
+    for (i = 0; i < MAXCHARSETS && LYchar_set_names[i] && LYhndl < 0; i++) {
     if (LYCharSet_UC[i].MIMEname &&
-	!strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname))
+	    !strcmp(UC_MIMEcharset,LYCharSet_UC[i].MIMEname)) {
       LYhndl = i;
+	}
+    }
 
   if (LYhndl < 0) {		/* not found */
     found = 0;
-    if (LYNumCharsets >= MAX_CHARSETS) {
-      if (TRACE)
-      fprintf(stderr,"UC_Register_with_LYCharSets: Too many. Ignoring %s/%s.",
+    if (LYNumCharsets >= MAXCHARSETS) {
+	    if (TRACE) {
+		fprintf(stderr,
+		    "UC_Register_with_LYCharSets: Too many. Ignoring %s/%s.",
 	      UC_MIMEcharset,UC_LYNXcharset);
+	    }
       return -1;
     } 
-				/* add to LYCharSets.c lists */
-    LYhndl = LYNumCharsets;  LYNumCharsets ++;
+	/*
+	 *  Add to LYCharSets.c lists.
+	 */
+	LYhndl = LYNumCharsets;
+	LYNumCharsets ++;
     LYlowest_eightbit[LYhndl] = 999;
     LYCharSets[LYhndl] = SevenBitApproximations;
-				/* Hmm, try to be conservative here. */
+	/*
+	 *  Hmm, try to be conservative here.
+	 */
     LYchar_set_names[LYhndl] = UC_LYNXcharset;
     LYchar_set_names[LYhndl+1] = (char *) 0;
-		      /* Terminating NULL may be looked for by Lynx code */
-  } else found = 1;
-
+	/*
+	 *  Terminating NULL may be looked for by Lynx code.
+	 */
+    } else {
+	found = 1;
+    }
   LYCharSet_UC[LYhndl].UChndl = s;
 			   /* Can we just copy the pointer? Hope so... */
   LYCharSet_UC[LYhndl].MIMEname = UC_MIMEcharset;
   LYCharSet_UC[LYhndl].enc = UCInfo[s].enc;
 
-  /* @@@ We really SHOULD get more info from the table files, and set
-   relevant flags in the LYCharSet_UC[] entry with that info...
-   for now, let's try it without - kw */
-
-  if (lowest_eightbit < LYlowest_eightbit[LYhndl])
+    /*
+     *  @@@ We really SHOULD get more info from the table files,
+     *  and set relevant flags in the LYCharSet_UC[] entry with
+     *  that info...  For now, let's try it without. - KW
+     */
+    if (lowest_eightbit < LYlowest_eightbit[LYhndl]) {
     LYlowest_eightbit[LYhndl] = lowest_eightbit;
-  else if (lowest_eightbit > LYlowest_eightbit[LYhndl])
+    } else if (lowest_eightbit > LYlowest_eightbit[LYhndl]) {
     UCInfo[s].lowest_eight = LYlowest_eightbit[LYhndl];
+    }
 
   if (!found && LYhndl > 0) {
     repl = UC_setup_LYCharSets_repl(s,UCInfo[s].lowest_eight);
     if (repl) {
       LYCharSets[LYhndl] = repl;
-      /* remember to FREE at exit */
+	    /*
+	     *  Remember to FREE at exit.
+	     */
       remember_allocated_LYCharSets[LYhndl]=repl;
     }
   }
   return LYhndl;
 }
 
-
-/* This only sets up the structure - no initialization of the tables
+/*
+ *  This only sets up the structure - no initialization of the tables
  * is done here yet.
  */
-void UC_Charset_Setup ARGS8(char *, UC_MIMEcharset,
+PUBLIC void UC_Charset_Setup ARGS8(
+	char *,			UC_MIMEcharset,
 		      char *, UC_LYNXcharset,
-		      u8 *, unicount, u16 *, unitable, int,  nnuni,
-		      struct unimapdesc_str, replacedesc, int, lowest_eight,
+	u8 *,			unicount,
+	u16 *,			unitable,
+	int,			nnuni,
+	struct unimapdesc_str,	replacedesc,
+	int,			lowest_eight,
 		      int, UC_rawuni)
 {
   int s, Gn;
   int i, status = 0, found;
 
-  /* Get (new?) slot */
-
+    /*
+     *  Get (new?) slot.
+     */
   found = -1;  
   for (i=0; i<UCNumCharsets && found<0; i++) {
-    if (!strcmp(UCInfo[i].MIMEname,UC_MIMEcharset))
+	if (!strcmp(UCInfo[i].MIMEname,UC_MIMEcharset)) {
       found = i;
   }
-  if (found >= 0) s = found;
-  else {
-    if (UCNumCharsets >= MAX_CHARSETS)
-      {
-	if (TRACE)
+    }
+    if (found >= 0) {
+	s = found;
+    } else {
+	if (UCNumCharsets >= MAXCHARSETS) {
+	    if (TRACE) {
 	  fprintf(stderr,"UC_Charset_Setup: Too many. Ignoring %s/%s.",
 		  UC_MIMEcharset,UC_LYNXcharset);
+	    }
 	return;
       }
     s = UCNumCharsets;
@@ -1340,10 +1606,13 @@ void UC_Charset_Setup ARGS8(char *, UC_MIMEcharset,
   if (UC_rawuni == UCT_ENC_UTF8) lowest_eight = 128;  /* cheat here */
   UCInfo[s].lowest_eight = lowest_eight;
   UCInfo[s].enc = UC_rawuni;
-  UCInfo[s].LYhndl = UC_Register_with_LYCharSets(s, UC_MIMEcharset,
-					    UC_LYNXcharset, lowest_eight);
+    UCInfo[s].LYhndl = UC_Register_with_LYCharSets(s,
+						   UC_MIMEcharset,
+						   UC_LYNXcharset,
+						   lowest_eight);
   UCInfo[s].uc_status = status;
-  if (found < 0) UCNumCharsets++;
+    if (found < 0)
+	UCNumCharsets++;
   return;
 }
 
@@ -1353,9 +1622,10 @@ PRIVATE void UCcleanup_mem NOARGS
     UCfree_allocated_LYCharSets();
     con_clear_unimap_str();
     con_clear_unimap();
-    for (i=1; i<4; i++)		/* first one is static! */
+    for (i = 1; i < 4; i++) {	/* first one is static! */
 	FREE(inverse_translations[i]);
 }
+}
 
 PUBLIC void UCInit NOARGS
 {
@@ -1382,5 +1652,7 @@ PUBLIC void UCInit NOARGS
   UC_CHARSET_SETUP_unicode_1_1_utf_8;
   UC_CHARSET_SETUP_mnemonic_ascii_0;
   UC_CHARSET_SETUP_mnemonic;
-/*  UC_CHARSET_SETUP_mnem; */
+#ifdef NOTDEFINED
+    UC_CHARSET_SETUP_mnem;
+#endif /* NOTDEFINED */
 }
diff --git a/src/UCdomap.h b/src/UCdomap.h
index 0009f6eb..7ddd835a 100644
--- a/src/UCdomap.h
+++ b/src/UCdomap.h
@@ -1,5 +1,9 @@
+
+#ifndef UCDOMAP_H
+#define UCDOMAP_H
+
 /*
- * [old comments: - kw ]
+ *  [old comments: - KW ]
  * consolemap.h
  *
  * Interface between console.c, selection.c  and UCmap.c
@@ -9,26 +13,23 @@
 #define IBMPC_MAP 2
 #define USER_MAP 3
 
-#ifndef MAX_CHARSETS
-#define MAX_CHARSETS
+#ifndef MAXCHARSETS
+#define MAXCHARSETS
 #endif
 
-extern int hashtable_contents_valid;
-extern unsigned char inverse_translate PARAMS((int glyph));
-extern u16 *set_translate PARAMS((int m));
-extern int conv_uni_to_pc PARAMS((long ucs));
-
-extern int hashtable_str_contents_valid;   /* ??? probably no use... */
-
 /* Some conventions i try to follow (loosely):
    [a-z]* only internal, names from linux driver code.
    UC_* to be only known internally.
    UC[A-Z]* to be exported to other parts of Lynx. -kw
 */
-
-extern void UC_Charset_Setup PARAMS((char * UC_MIMEcharset, char * UC_LYNXcharset,
-		      u8 * unicount, u16 * unitable, int nnuni,
-		      struct unimapdesc_str replacedesc, int lowest_eight,
+extern void UC_Charset_Setup PARAMS((
+	char *			UC_MIMEcharset,
+	char *			UC_LYNXcharset,
+	u8 *			unicount,
+	u16 *			unitable,
+	int			nnuni,
+	struct unimapdesc_str	replacedesc,
+	int			lowest_eight,
 			     int UC_rawuni));
 
 char *UC_GNsetMIMEnames[4] =
@@ -48,11 +49,11 @@ struct UC_charset {
   int lowest_eight;
   int enc;
 };
-char * UC_charsetMIMEnames[MAX_CHARSETS];
 
-PUBLIC struct UC_charset UCInfo[MAX_CHARSETS];
+PUBLIC struct UC_charset UCInfo[MAXCHARSETS];
 
 PUBLIC int UCNumCharsets;
 
 extern void UCInit NOARGS;
 
+#endif /* UCDOMAP_H */
diff --git a/src/chrtrans/README.tables b/src/chrtrans/README.tables
index c9a86605..8e4366d1 100644
--- a/src/chrtrans/README.tables
+++ b/src/chrtrans/README.tables
@@ -2,13 +2,13 @@ The translation table files in this directory are _examples only_.
 They were collected from several sources (among them Linux kbd package, 
 ftp://dkuug.dk/, ftp://unicode.org/) and automatically comverted (if
 applicable), but not checked in detail.  The Unicode/UCS2 values
-for some of the RFC1345 Mnemonic codes are out of date, a cleanup and
+for some of the RFC 1345 Mnemonic codes are out of date, a cleanup and
 update would be needed for serious use (including removing the mappings
 from the "private zone" U+E000 etc.).
 
 More tranlation files can be easily provided (and new character entities
 added to HTMLDTD.c), this set is just to test whether the system works 
-in principle (and also how it behaves with of incomplete data...)
+in principle (and also how it behaves with incomplete data...)
 
 See the file README.format for a brief explanation of what's in the
 table files.
@@ -18,8 +18,10 @@ doesn't really matter.  The auxiliary program makeuctb (MAKE UniCode
 TaBle) is used to "compile" them into C header files, which can be
 included by UCdomap.c.
 
-Ideally this should be taken care of by the Makefiles..
-
+Ideally, this should be taken care of by the Makefiles.  On VMS, use
+build-chrtrans.com to compile and link makeuctb.exe and create the
+set of .h files from the current set of .tlb files.  Thereafter, use
+build-header.com to update particular .h files.
 
 To make a new chartrans table available to Lynx (and thereby make a new
 charset known to Lynx) you currently have to manually edit UCdomap.c, in
@@ -27,7 +29,11 @@ two places:
 
 a) Near the top, you will find a bunch of lines (some may be commented out)
   
+  #ifdef VMS
+  #include "[.chrtrans]<fn>.h"
+  #else
   #include "chrtrans/<fn>.h"
+  #endif /* VMS */
 
 Add or comment out as you wish. (But it's probably safest to leave the
 first one, referring to "chrtrans/iso01_uni.h", in place...)
@@ -50,5 +56,9 @@ named makefile.in before running ./configure, or makefile after running
 ./configure.  (That may be inconvenient, but I didn't want to depend
 on features than not all makes may have.)  Note that for recompiling
 Lynx, a `make clean' should not be necessary if you have *only* made
-changes to the files in src/chrtrans.
+changes to the files in src/chrtrans.  On VMS, add entries for new
+tables to build-chrtrans.com, but you can update the particular file
+with build-header.com, then use the top directory's build.com and
+answer 'n' to it's prompts about whether to update the WWWlibrary
+and chrtrans modules.
 
diff --git a/src/chrtrans/UCkd.h b/src/chrtrans/UCkd.h
index 2cc2ebdb..083afe49 100644
--- a/src/chrtrans/UCkd.h
+++ b/src/chrtrans/UCkd.h
@@ -1,19 +1,22 @@
 #ifndef _UC_KD_H
 #define _UC_KD_H
-#include <sys/types.h>
-
-/* NOTE: THE FOLLOWING #define MAY NEED ADJUSTMENT.
-   u16 should be an unsigned type of 16 bit length (two octets).
-   u8  should be an unsigned type of 8  bit length (one octet).
-   */
+#ifdef NOTDEFINED
+#include <sys/types.h>	/* Included via tcp.h. */
+#endif /* NOTDEFINED */
+
+/*
+ *  NOTE: THE FOLLOWING #define MAY NEED ADJUSTMENT.
+ *  u16 should be an unsigned type of 16 bit length (two octets).
+ *  u8  should be an unsigned type of 8  bit length (one octet).
+ */
 #ifndef u16
 #define u16 unsigned short
-#endif
+#endif /* u16 */
 
 
 #ifndef u8
 #define u8 unsigned char
-#endif
+#endif /* u8 */
 
 #ifdef NOTDEFINED
 struct consolefontdesc {
@@ -21,7 +24,7 @@ struct consolefontdesc {
 	u_short charheight;	/* scan lines per character (1-32) */
 	char *chardata;		/* font data in expanded form */
 };
-#endif
+#endif /* NOTDEFINED */
 typedef char scrnmap_t;
 #define		E_TABSZ		256
 
diff --git a/src/chrtrans/build-chrtrans.com b/src/chrtrans/build-chrtrans.com
new file mode 100644
index 00000000..b9a3d515
--- /dev/null
+++ b/src/chrtrans/build-chrtrans.com
@@ -0,0 +1,125 @@
+$ v = 'f$verify(0)'
+$!			BUILD-CHRTRANS.COM
+$!
+$!   Command file to build MAKEUCTB.EXE on VMS systems
+$!   and then use it to create the chrtrans header files.
+$!
+$!   28-Jun-1997	F.Macrides		macrides@sci.wfeb.edu
+$!	Initial version, for Lynx v2.7.1+fotemods
+$!
+$ ON CONTROL_Y THEN GOTO CLEANUP
+$ ON ERROR THEN GOTO CLEANUP
+$ CHRproc = f$environment("PROCEDURE")
+$ CHRwhere = f$parse(CHRproc,,,"DEVICE") + f$parse(CHRproc,,,"DIRECTORY")
+$!
+$ if p1 .nes. ""
+$   then
+$      CHRcc_opts = "/DEBUG/NOOPT"
+$      CHRlink_opts = "/DEBUG"
+$   else
+$      CHRcc_opts = ""
+$      CHRlink_opts = ""
+$ endif
+$!
+$ Compile_makeuctb:
+$!================
+$ v1 = f$verify(1)
+$!
+$!	Compile the Lynx [.SRC.CHRTRANS]makeuctb module.
+$!
+$  v1 = 'f$verify(0)'
+$ IF f$trnlnm("VAXCMSG") .eqs. "DECC$MSG" .or. -
+     f$trnlnm("DECC$CC_DEFAULT") .eqs. "/DECC" .or. -
+     f$trnlnm("DECC$CC_DEFAULT") .eqs. "/VAXC"
+$ THEN
+$  CHRcompiler := "DECC"
+$  v1 = f$verify(1)
+$! DECC:
+$  cc := cc/decc/prefix=all /nomember 'CHRcc_opts'-
+	   /INCLUDE=([-],[--],[--.WWW.Library.Implementation]) 
+$  v1 = 'f$verify(0)'
+$ ELSE
+$  IF f$search("gnu_cc:[000000]gcclib.olb") .nes. ""
+$  THEN
+$   CHRcompiler := "GNUC"
+$   v1 = f$verify(1)
+$! GNUC:
+$   cc := gcc 'cc_opts'/INCLUDE=([-],[--],[--.WWW.Library.Implementation]) 
+$   v1 = 'f$verify(0)'
+$  ELSE
+$   CHRcompiler := "VAXC"
+$   v1 = f$verify(1)
+$! VAXC:
+$   cc := cc 'cc_opts'/INCLUDE=([-],[--],[--.WWW.Library.Implementation]) 
+$   v1 = 'f$verify(0)'
+$  ENDIF
+$ ENDIF
+$!
+$ v1 = f$verify(1)
+$ cc makeuctb
+$ v1 = 'f$verify(0)'
+$!
+$ Link_makeuctb:
+$!=============
+$ v1 = f$verify(1)
+$!
+$!	Link the Lynx [.SRC.CHRTRANS]makeuctb module.
+$!
+$ link/exe=makeuctb.exe'link_opts' makeuctb, -
+sys$disk:[-]'CHRcompiler'.opt/opt
+$ v1 = 'f$verify(0)'
+$!
+$ Create_headers:
+$!==============
+$ v1 = f$verify(1)
+$!
+$!	Create the Lynx [.SRC.CHRTRANS] header files.
+$!
+$ makeuctb := $'CHRwhere'makeuctb
+$ define/user sys$output 'CHRwhere'iso01_uni.h
+$ makeuctb iso01_uni.tbl
+$ define/user sys$output 'CHRwhere'iso02_uni.h
+$ makeuctb iso02_uni.tbl
+$ define/user sys$output 'CHRwhere'def7_uni.h
+$ makeuctb def7_uni.tbl
+$ define/user sys$output 'CHRwhere'iso03_uni.h
+$ makeuctb iso03_uni.tbl
+$ define/user sys$output 'CHRwhere'iso04_uni.h
+$ makeuctb iso04_uni.tbl
+$ define/user sys$output 'CHRwhere'iso05_uni.h
+$ makeuctb iso05_uni.tbl
+$ define/user sys$output 'CHRwhere'iso07_uni.h
+$ makeuctb iso07_uni.tbl
+$ define/user sys$output 'CHRwhere'iso09_uni.h
+$ makeuctb iso09_uni.tbl
+$ define/user sys$output 'CHRwhere'iso10_uni.h
+$ makeuctb iso10_uni.tbl
+$ define/user sys$output 'CHRwhere'koi8r_uni.h
+$ makeuctb koi8r_uni.tbl
+$ define/user sys$output 'CHRwhere'cp437_uni.h
+$ makeuctb cp437_uni.tbl
+$ define/user sys$output 'CHRwhere'cp850_uni.h
+$ makeuctb cp850_uni.tbl
+$ define/user sys$output 'CHRwhere'cp852_uni.h
+$ makeuctb cp852_uni.tbl
+$ define/user sys$output 'CHRwhere'cp1250_uni.h
+$ makeuctb cp1250_uni.tbl
+$ define/user sys$output 'CHRwhere'cp1252_uni.h
+$ makeuctb cp1252_uni.tbl
+$ define/user sys$output 'CHRwhere'utf8_uni.h
+$ makeuctb utf8_uni.tbl
+$ define/user sys$output 'CHRwhere'mnemonic_suni.h
+$ makeuctb mnemonic_suni.tbl
+$ define/user sys$output 'CHRwhere'mnem_suni.h
+$ makeuctb mnem_suni.tbl
+$ define/user sys$output 'CHRwhere'rfc_suni.h
+$ makeuctb rfc_suni.tbl
+$ v1 = 'f$verify(0)'
+$ exit
+$!
+$ CLEANUP:
+$    v1 = 'f$verify(0)'
+$    write sys$output "Default directory:"
+$    show default
+$    v1 = f$verify(v)
+$ exit
diff --git a/src/chrtrans/build-header.com b/src/chrtrans/build-header.com
new file mode 100644
index 00000000..963825dd
--- /dev/null
+++ b/src/chrtrans/build-header.com
@@ -0,0 +1,37 @@
+$ v = 'f$verify(0)'
+$!			BUILD-HEADER.COM
+$!
+$!   Command file to use MAKEUCTB.EXE on VMS systems for creating
+$!   a chrtrans header (foo.h) file from a table (foo.tbl) file.
+$!   Use the file root as P1, e.g.:
+$!
+$!	$ @build-header iso05_uni
+$!
+$!   will create iso05_uni.h from iso05_uni.tbl.
+$!
+$!   28-Jun-1997	F.Macrides		macrides@sci.wfeb.edu
+$!	Initial version, for Lynx v2.7.1+fotemods
+$!
+$ ON CONTROL_Y THEN GOTO CLEANUP
+$ ON ERROR THEN GOTO CLEANUP
+$ CHRproc = f$environment("PROCEDURE")
+$ CHRwhere = f$parse(CHRproc,,,"DEVICE") + f$parse(CHRproc,,,"DIRECTORY")
+$!
+$ Create_header:
+$!=============
+$ v1 = f$verify(1)
+$!
+$!	Create a Lynx [.SRC.CHRTRANS] header file.
+$!
+$ makeuctb := $'CHRwhere'makeuctb
+$ define/user sys$output 'CHRwhere''P1'.h
+$ makeuctb 'P1'.tbl
+$ v1 = 'f$verify(0)'
+$ exit
+$!
+$ CLEANUP:
+$    v1 = 'f$verify(0)'
+$    write sys$output "Default directory:"
+$    show default
+$    v1 = f$verify(v)
+$ exit
diff --git a/src/chrtrans/makeuctb.c b/src/chrtrans/makeuctb.c
index f5f73066..95ba076d 100644
--- a/src/chrtrans/makeuctb.c
+++ b/src/chrtrans/makeuctb.c
@@ -1,18 +1,18 @@
 /*
- * makeuctb.c, derived from conmakehash.c
+ *  makeuctb.c, derived from conmakehash.c
  *
- * [ original comments: - kw ]
- * Create arrays for initializing the kernel folded tables (using a hash
- * table turned out to be to limiting...)  Unfortunately we can't simply
- * preinitialize the tables at compile time since kfree() cannot accept
- * memory not allocated by kmalloc(), and doing our own memory management
- * just for this seems like massive overkill.
+ *  [ original comments: - kw ]
+ *  Create arrays for initializing the kernel folded tables (using a hash
+ *  table turned out to be to limiting...)  Unfortunately we can't simply
+ *  preinitialize the tables at compile time since kfree() cannot accept
+ *  memory not allocated by kmalloc(), and doing our own memory management
+ *  just for this seems like massive overkill.
  *
- * Copyright (C) 1995 H. Peter Anvin
+ *  Copyright (C) 1995 H. Peter Anvin
  *
- * This program is a part of the Linux kernel, and may be freely
- * copied under the terms of the GNU General Public License (GPL),
- * version 2, or at your option any later version.
+ *  This program is a part of the Linux kernel, and may be freely
+ *  copied under the terms of the GNU General Public License (GPL),
+ *  version 2, or at your option any later version.
  */
 
 #ifdef NOTDEFINED
@@ -22,123 +22,143 @@
 #include <string.h>
 #include <ctype.h>
 #else
+#include "HTUtils.h"
 #include "tcp.h"
-#undef exit			/* don't try to use LYexit() */
-#endif
+/*
+ *  Don't try to use LYexit().
+ */
+#ifdef exit
+#undef exit
+#endif /* exit */
+#endif /* NODEFINED */
 
 #ifndef TOLOWER
 #define TOLOWER(c) (isupper((unsigned char)c) ? tolower((unsigned char)c) : (c))
-#endif /* ndef TOLOWER */
+#endif /* !TOLOWER */
 
 #include "UCkd.h"
 #include "UCDefs.h"
 
 #define MAX_FONTLEN 256
 
-/* We don't deal with UCS4 here... -kw */
+/*
+ *  We don't deal with UCS4 here. - KW
+ */
 typedef u16 unicode;
 
-PRIVATE void usage ARGS1(char *, argv0)
+PRIVATE void usage ARGS1(
+	char *,		argv0)
 {
-  fprintf(stderr, "Usage: \n");
-  fprintf(stderr, "        %s chartable [charsetmimename] [charsetdisplayname]\n", argv0);
-  fprintf(stderr, "Utility to convert .tbl into .h files for Lynx compilation.\n");
-  exit(EX_USAGE);
+    fprintf(stderr, "Usage: \n");
+    fprintf(stderr,
+	    "        %s chartable [charsetmimename] [charsetdisplayname]\n",
+	    argv0);
+    fprintf(stderr,
+	    "Utility to convert .tbl into .h files for Lynx compilation.\n");
+    exit(EX_USAGE);
 }
 
-PRIVATE int getunicode ARGS1(char **, p0)
+PRIVATE int getunicode ARGS1(
+	char **,	p0)
 {
-  char *p = *p0;
-
-  while (*p == ' ' || *p == '\t')
-    p++;
-  if (*p == '-')
-      return -2;
-  else if (*p != 'U' || p[1] != '+' ||
-      !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
-      !isxdigit(p[5]) || isxdigit(p[6]))
-    return -1;
-  *p0 = p+6;
-  return strtol(p+2,0,16);
+    char *p = *p0;
+
+    while (*p == ' ' || *p == '\t')
+	p++;
+	
+    if (*p == '-') {
+	return -2;
+    } else if (*p != 'U' || p[1] != '+' ||
+	       !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
+	       !isxdigit(p[5]) || isxdigit(p[6])) {
+	return -1;
+    }
+    *p0 = p+6;
+    return strtol((p + 2), 0, 16);
 }
 
+/*
+ *  Massive overkill, but who cares?
+ */
 unicode unitable[MAX_FONTLEN][255];
-				/* Massive overkill, but who cares? */
 int unicount[MAX_FONTLEN];
 
 struct unimapdesc_str themap_str = {0, NULL};
 
 char *tblname;
 
-PRIVATE void addpair_str ARGS2(char *, str, int, un)
+PRIVATE void addpair_str ARGS2(
+	char *,		str,
+	int,		un)
 {
-  int i;
-
-
-  if ( un <= 0xfffe )
-    {
-      /* Initialize the map for replacement strings */
-
-      if (!themap_str.entry_ct) {
-	themap_str.entries =
+   int i;
+
+    if (un <= 0xfffe) {
+	if (!themap_str.entry_ct) {
+	    /*
+	     *  Initialize the map for replacement strings.
+	     */
+	    themap_str.entries =
 	  (struct unipair_str *) malloc (2000 * sizeof (struct unipair_str));
-	    if (! themap_str.entries)
-	      {
+	    if (!themap_str.entries) {
 		fprintf(stderr,
 			"%s: Out of memory\n", tblname);
 		exit(EX_DATAERR);
-	      }
-      }
-
-      /* Check it isn't a duplicate */
-      
-      else for ( i = 0 ; i < themap_str.entry_ct ; i++ )
-	if ( themap_str.entries[i].unicode == un ) {
-	  themap_str.entries[i].replace_str = str;
-	  return;
+	    }
+	} else {
+	    /*
+	     *  Check that it isn't a duplicate.
+	     */
+	    for (i = 0 ; i < themap_str.entry_ct; i++) {
+		if (themap_str.entries[i].unicode == un ) {
+		    themap_str.entries[i].replace_str = str;
+		    return;
+		}
+	    }
 	}
 
-      /* Add to list */
-
-      if ( themap_str.entry_ct > 1999 )
-	{
-	  fprintf(stderr, "ERROR: Only 2000 unicode replacement strings permitted!\n");
-	  exit(EX_DATAERR);
+	/*
+	 *  Add to list.
+	 */
+	if (themap_str.entry_ct > 1999) {
+	    fprintf(stderr,
+		"ERROR: Only 2000 unicode replacement strings permitted!\n");
+	    exit(EX_DATAERR);
 	}
-
-      themap_str.entries[themap_str.entry_ct].unicode = un;
-      themap_str.entries[themap_str.entry_ct].replace_str = str;
-      themap_str.entry_ct++;
+	themap_str.entries[themap_str.entry_ct].unicode = un;
+	themap_str.entries[themap_str.entry_ct].replace_str = str;
+	themap_str.entry_ct++;
     }
-
-  /* otherwise: ignore */
+    /* otherwise: ignore */
 }
 
-PRIVATE void addpair ARGS2(int, fp, int, un)
+PRIVATE void addpair ARGS2(
+	int,	fp,
+	int,	un)
 {
-  int i;
-
-  if ( un <= 0xfffe )
-    {
-      /* Check it isn't a duplicate */
-
-      for ( i = 0 ; i < unicount[fp] ; i++ )
-	if ( unitable[fp][i] == un )
-	  return;
-
-      /* Add to list */
-
-      if ( unicount[fp] > 254 )
-	{
-	  fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
-	  exit(EX_DATAERR);
+    int i;
+
+    if (un <= 0xfffe) {
+	/*
+	 *  Check that it isn't a duplicate.
+	 */
+	for (i = 0; i < unicount[fp]; i++) {
+	    if (unitable[fp][i] == un) {
+		return;
+	    }
 	}
 
-      unitable[fp][unicount[fp]] = un;
-      unicount[fp]++;
+	/*
+	 *  Add to list.
+	 */
+	if (unicount[fp] > 254) {
+	    fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
+	    exit(EX_DATAERR);
+	}
+	unitable[fp][unicount[fp]] = un;
+	unicount[fp]++;
     }
-
-  /* otherwise: ignore */
+    /* otherwise: ignore */
 }
 
 char this_MIMEcharset[UC_MAXLEN_MIMECSNAME +1];
@@ -148,422 +168,463 @@ int this_isDefaultMap = -1;
 int RawUni = 0;
 int lowest_eight = 999;
 
-int main ARGS2(int, argc, char **, argv)
+PUBLIC int main ARGS2(
+	int,		argc,
+	char **,	argv)
 {
-  FILE *ctbl;
-  char buffer[65536];
-  int fontlen;
-  int i, nuni, nent;
-  int fp0, fp1, un0, un1;
-  char *p, *p1;
-  char *tbuf, ch;
-
-  if ( argc < 2 || argc > 4 )
-    usage(argv[0]);
-
-  if ( !strcmp(argv[1],"-") )
-    {
-      ctbl = stdin;
-      tblname = "stdin";
+    FILE *ctbl;
+    char buffer[65536];
+    int fontlen;
+    int i, nuni, nent;
+    int fp0, fp1, un0, un1;
+    char *p, *p1;
+    char *tbuf, ch;
+
+    if (argc < 2 || argc > 4) {
+	usage(argv[0]);
     }
-  else
-    {
-      ctbl = fopen(tblname = argv[1], "r");
-      if ( !ctbl )
-	{
-	  perror(tblname);
-	  exit(EX_NOINPUT);
+
+    if (!strcmp(argv[1], "-")) {
+	ctbl = stdin;
+	tblname = "stdin";
+    } else {
+	ctbl = fopen(tblname = argv[1], "r");
+	if (!ctbl) {
+	    perror(tblname);
+	    exit(EX_NOINPUT);
 	}
     }
 
-  /* For now we assume the default font is always 256 characters. */    
-  fontlen = 256;
+    /*
+     *  For now we assume the default font is always 256 characters.
+     */
+    fontlen = 256;
 
-  /* Initialize table */
-
-  for ( i = 0 ; i < fontlen ; i++ )
-    unicount[i] = 0;
+    /*
+     *  Initialize table.
+     */
+    for (i = 0; i < fontlen; i++) {
+	unicount[i] = 0;
+    }
 
-  /* Now we come to the tricky part.  Parse the input table. */
+    /*
+     *  Now we comes to the tricky part.  Parse the input table.
+     */
+    while (fgets(buffer, sizeof(buffer), ctbl) != NULL) {
+	if ((p = strchr(buffer, '\n')) != NULL) {
+	    *p = '\0';
+	} else {
+	    fprintf(stderr, "%s: Warning: line too long\n", tblname);
+	}
 
-  while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
-    {
-      if ( (p = strchr(buffer, '\n')) != NULL )
-	*p = '\0';
-      else
-	fprintf(stderr, "%s: Warning: line too long\n", tblname);
+	/*
+	 *  Syntax accepted:
+	 *	<fontpos>	<unicode> <unicode> ...
+	 *	<fontpos>	<unicode range> <unicode range> ...
+	 *	<fontpos>	idem
+	 *	<range>		idem
+	 *	<range>		<unicode range>
+	 *      <unicode>	:<replace>
+	 *      <unicode range>	:<replace>
+	 *
+	 *  where <range> ::= <fontpos>-<fontpos>
+	 *  and <unicode> ::= U+<h><h><h><h>
+	 *  and <h> ::= <hexadecimal digit>
+	 *  and <replace> any string not containing '\n' or '\0'
+	 */
+	p = buffer;
+	while (*p == ' ' || *p == '\t') {
+	    p++;
+	}
+	if (!(*p) || *p == '#') {
+	    /*
+	     *  Skip comment or blank line.
+	     */
+	    continue;
+	}
 
-      p = buffer;
+	switch (*p) {
+	    /*
+	     *  Raw Unicode?  I.e. needs some special
+	     *  processing.  One digit code.
+	     */
+	    case 'R':
+		p++;
+		while (*p == ' ' || *p == '\t') {
+	  	    p++;
+		}
+		RawUni = strtol(p,0,10);
+		continue;
 
-/*
- * Syntax accepted:
- *	<fontpos>	<unicode> <unicode> ...
- *	<fontpos>	<unicode range> <unicode range> ...
- *	<fontpos>	idem
- *	<range>		idem
- *	<range>		<unicode range>
- *      <unicode>	:<replace>
- *      <unicode range>	:<replace>
- *
- * where <range> ::= <fontpos>-<fontpos>
- * and <unicode> ::= U+<h><h><h><h>
- * and <h> ::= <hexadecimal digit>
- * and <replace> any string not containing '\n' or '\0'
- */
+	    /*
+	     *  Is this the default display font?
+	     */
+ 	    case 'D':
+		p++;
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
+		this_isDefaultMap = (*p == '1');
+		continue;
 
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (!*p || *p == '#')
-	continue;	/* skip comment or blank line */
+	    case 'M':
+		p++;
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
+		sscanf(p,"%40s",this_MIMEcharset);
+		continue;
 
-      switch (*p) {
-      case 'R':			/* Raw Unicode? I.e. needs some special
-				 processing.  One digit code. */
-	p++;
-	while (*p == ' ' || *p == '\t')
-	  p++;
-	RawUni = strtol(p,0,10);
-	continue;
+	    /*
+	     *  Display charset name for options screen.
+	     */
+	    case 'O':
+		p++;
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
+		for (i = 0; *p && i < UC_MAXLEN_LYNXCSNAME; p++, i++) {
+		    this_LYNXcharset[i] = *p;
+		}
+		this_LYNXcharset[i] = '\0';
+		continue;
+	}
 
-      case 'D':			/* Is this the default display font? */
-	p++;
-	while (*p == ' ' || *p == '\t')
-	  p++;
-	this_isDefaultMap = (*p == '1');
-	continue;
-      case 'M':
-	p++;
-	while (*p == ' ' || *p == '\t')
-	  p++;
-	sscanf(p,"%40s",this_MIMEcharset);
-	continue;
-      case 'O':            /* Display charset name for options screen */
-	p++;
-	while (*p == ' ' || *p == '\t')
-	  p++;
-	for (i=0; *p && i<UC_MAXLEN_LYNXCSNAME; p++,i++) 
-	  this_LYNXcharset[i] = *p;
-	this_LYNXcharset[i] = '\0';
-	continue;
-      }
-
-      if(*p == 'U')
-	{
-	  un0 = getunicode(&p);
-	  if (un0 < 0)
-	    {
-	      fprintf(stderr, "Bad input line: %s\n", buffer);
-	      exit(EX_DATAERR);
-	      fprintf(stderr,
-		      "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
-		      tblname, fp0, fp1);
-	      exit(EX_DATAERR);
+	if (*p == 'U') {
+	    un0 = getunicode(&p);
+	    if (un0 < 0) {
+		fprintf(stderr, "Bad input line: %s\n", buffer);
+		exit(EX_DATAERR);
+		fprintf(stderr,
+    "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
+			tblname, fp0, fp1);
+		exit(EX_DATAERR);
 	    }
-	  un1 = un0;
-	  while (*p == ' ' || *p == '\t')
-	    p++;
-	  if (*p == '-')
-	    {
-	      p++;
-	      while (*p == ' ' || *p == '\t')
+	    un1 = un0;
+	    while (*p == ' ' || *p == '\t') {
 		p++;
-	      un1 = getunicode(&p);
-	      if (un1 < 0 || un1 < un0)
-		{
-		  fprintf(stderr,
-			  "%s: Bad Unicode range U+%x-U+%x\n",
-			  tblname, un0, un1);
-		  fprintf(stderr, "Bad input line: %s\n", buffer);
-		  exit(EX_DATAERR);
-		}
-	      while (*p == ' ' || *p == '\t')
+	    }
+	    if (*p == '-') {
 		p++;
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
+		un1 = getunicode(&p);
+		if (un1 < 0 || un1 < un0) {
+		    fprintf(stderr,
+			    "%s: Bad Unicode range U+%x-U+%x\n",
+			    tblname, un0, un1);
+		    fprintf(stderr, "Bad input line: %s\n", buffer);
+		    exit(EX_DATAERR);
+		}
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
 	    }
-	  if (*p != ':')
-	    {
-	      fprintf(stderr, "No ':' where expected: %s\n", buffer);
-	      continue;
+	    if (*p != ':') {
+		fprintf(stderr, "No ':' where expected: %s\n", buffer);
+		continue;
 	    }
 
-	  tbuf = (char *) malloc (4*strlen(++p) + 1);
-	  if (!(p1 = tbuf))
-	    {
-	      fprintf(stderr,
-		      "%s: Out of memory\n", tblname);
-	      exit(EX_DATAERR);
+	    tbuf = (char *) malloc (4*strlen(++p) + 1);
+	    if (!(p1 = tbuf)) {
+		fprintf(stderr, "%s: Out of memory\n", tblname);
+		exit(EX_DATAERR);
 	    }
-	  for(ch = *p; (ch = *p) != '\0'; p++,p1++)
-	    {
-	      if ((unsigned char)ch < 32 || ch == '\\' || ch == '\"' ||
-		  (unsigned char)ch >= 127)
-		{
-		  sprintf(p1,"\\%.3o",(unsigned char)ch); 
-/*		  fprintf(stderr,"%s\n",tbuf); */
-		  p1 += 3;
+	    for (ch = *p; (ch = *p) != '\0'; p++, p1++) {
+		if ((unsigned char)ch < 32 || ch == '\\' || ch == '\"' ||
+		    (unsigned char)ch >= 127) {
+		    sprintf(p1, "\\%.3o", (unsigned char)ch); 
+/*		    fprintf(stderr, "%s\n", tbuf); */
+		    p1 += 3;
+		} else {
+		    *p1 = ch;
 		}
-	      else
-		*p1 = ch;
 	    }
-	  *p1 = '\0';
-	  for(i=un0; i<=un1; i++)
-/*	    printf("U+0x%x:%s\n",i,tbuf); */
-	    addpair_str(tbuf,i);
+	    *p1 = '\0';
+	    for (i = un0; i <= un1; i++) {
+/*		printf("U+0x%x:%s\n", i, tbuf); */
+		addpair_str(tbuf,i);
+	    }
 	    continue;
 	}
 	
-      fp0 = strtol(p, &p1, 0);
-      if (p1 == p)
-	{
-	  fprintf(stderr, "Bad input line: %s\n", buffer);
-	  exit(EX_DATAERR);
+	fp0 = strtol(p, &p1, 0);
+	if (p1 == p) {
+	    fprintf(stderr, "Bad input line: %s\n", buffer);
+	    exit(EX_DATAERR);
         }
-      p = p1;
+	p = p1;
 
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (*p == '-')
-	{
-	  p++;
-	  fp1 = strtol(p, &p1, 0);
-	  if (p1 == p)
-	    {
-	      fprintf(stderr, "Bad input line: %s\n", buffer);
-	      exit(EX_DATAERR);
+	while (*p == ' ' || *p == '\t') {
+	    p++;
+	}
+	if (*p == '-') {
+	    p++;
+	    fp1 = strtol(p, &p1, 0);
+	    if (p1 == p) {
+		fprintf(stderr, "Bad input line: %s\n", buffer);
+		exit(EX_DATAERR);
 	    }
-	  p = p1;
-        }
-      else
-	fp1 = 0;
+	    p = p1;
+        } else {
+	    fp1 = 0;
+	}
 
-      if ( fp0 < 0 || fp0 >= fontlen )
-	{
+	if (fp0 < 0 || fp0 >= fontlen) {
 	    fprintf(stderr,
 		    "%s: Glyph number (0x%x) larger than font length\n",
 		    tblname, fp0);
 	    exit(EX_DATAERR);
 	}
-      if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
-	{
+	if (fp1 && (fp1 < fp0 || fp1 >= fontlen)) {
 	    fprintf(stderr,
 		    "%s: Bad end of range (0x%x)\n",
 		    tblname, fp1);
 	    exit(EX_DATAERR);
 	}
 
-      if (fp1)
-	{
-	  /* we have a range; expect the word "idem" or a Unicode range of the
-	     same length */
-	  while (*p == ' ' || *p == '\t')
-	    p++;
-	  if (!strncmp(p, "idem", 4))
-	    {
-	      for (i=fp0; i<=fp1; i++)
-		addpair(i,i);
-	      p += 4;
-	    }
-	  else
-	    {
-	      un0 = getunicode(&p);
-	      while (*p == ' ' || *p == '\t')
+	if (fp1) {
+	    /*
+	     *  We have a range; expect the word "idem"
+	     *  or a Unicode range of the same length.
+	     */
+	    while (*p == ' ' || *p == '\t') {
 		p++;
-	      if (*p != '-')
-		{
-		  fprintf(stderr,
-"%s: Corresponding to a range of font positions, there should be a Unicode range\n",
-			  tblname);
-		  exit(EX_DATAERR);
+	    }
+	    if (!strncmp(p, "idem", 4)) {
+		for (i = fp0; i <= fp1; i++) {
+		    addpair(i,i);
+		}
+		p += 4;
+	    } else {
+		un0 = getunicode(&p);
+		while (*p == ' ' || *p == '\t') {
+		    p++;
+		}
+		if (*p != '-') {
+		    fprintf(stderr,
+			    "%s: Corresponding to a range of font positions,",
+			    tblname);
+		    fprintf(stderr,
+			    " there should be a Unicode range.\n");
+		    exit(EX_DATAERR);
 	        }
-	      p++;
-	      un1 = getunicode(&p);
-	      if (un0 < 0 || un1 < 0)
-		{
-		  fprintf(stderr,
-"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
-			  tblname, fp0, fp1);
-		  exit(EX_DATAERR);
+		p++;
+		un1 = getunicode(&p);
+		if (un0 < 0 || un1 < 0) {
+		    fprintf(stderr,
+     "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
+			    tblname, fp0, fp1);
+		    exit(EX_DATAERR);
 	        }
-	      if (un1 - un0 != fp1 - fp0)
-		{
-		  fprintf(stderr,
-"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n",
-			  tblname, un0, un1, fp0, fp1);
-		  exit(EX_DATAERR);
+		if (un1 - un0 != fp1 - fp0) {
+		    fprintf(stderr,
+			"%s: Unicode range U+%x-U+%x not of the same length",
+			    tblname, un0, un1);
+		    fprintf(stderr,
+			    " as font position range 0x%x-0x%x\n",
+			    fp0, fp1);
+		    exit(EX_DATAERR);
 	        }
-	      for(i=fp0; i<=fp1; i++)
-		addpair(i,un0-fp0+i);
+		for (i = fp0; i <= fp1; i++) {
+		    addpair(i,un0-fp0+i);
+		}
 	    }
-        }
-      else
-	{
-	    /* no range; expect a list of unicode values or unicode ranges
-	       for a single font position, or the word "idem" */
-
-	    while (*p == ' ' || *p == '\t')
+	} else {
+	    /*
+	     *  No range; expect a list of unicode values
+	     *  or unicode ranges for a single font position,
+	     *  or the word "idem"
+	     */
+	    while (*p == ' ' || *p == '\t') {
 		p++;
-	    if (!strncmp(p, "idem", 4))
-	    {
+	    }
+	    if (!strncmp(p, "idem", 4)) {
 		addpair(fp0,fp0);
 		p += 4;
 	    }
-	    while ( (un0 = getunicode(&p)) >= 0 ) {
+	    while ((un0 = getunicode(&p)) >= 0) {
 		addpair(fp0, un0);
-		while (*p == ' ' || *p == '\t')
+		while (*p == ' ' || *p == '\t') {
 		    p++;
+		}
 		if (*p == '-') {
 		    p++;
 		    un1 = getunicode(&p);
-		    if (un1 < un0)
-		    {
+		    if (un1 < un0) {
 			fprintf(stderr,
 				"%s: Bad Unicode range 0x%x-0x%x\n",
 				tblname, un0, un1);
 			exit(EX_DATAERR);
 		    }
-		    for(un0++; un0 <= un1; un0++)
+		    for (un0++; un0 <= un1; un0++) {
 			addpair(fp0, un0);
+		    }
 		}
 	    }
 	}
-      while (*p == ' ' || *p == '\t')
-	p++;
-      if (*p && *p != '#')
-	fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
+	while (*p == ' ' || *p == '\t') {
+	    p++;
+	}
+	if (*p && *p != '#') {
+	    fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
+	}
     }
 
-  /* Okay, we hit EOF, now output hash table */
-  
-  fclose(ctbl);
+    /*
+     *  Okay, we hit EOF, now output hash table.
+     */
+    fclose(ctbl);
   
 
-  /* Compute total size of Unicode list */
-  nuni = 0;
-  for ( i = 0 ; i < fontlen ; i++ )
-    nuni += unicount[i];
-
-  if (argc >=3 )
-    strncpy(this_MIMEcharset,argv[2],UC_MAXLEN_MIMECSNAME);
-  else if (!this_MIMEcharset || ! *this_MIMEcharset) {
-    strncpy(this_MIMEcharset,tblname,UC_MAXLEN_MIMECSNAME);
-    if ((p = strchr(this_MIMEcharset,'.')) != 0)
-      *p = '\0';
-  }
-  for (p=this_MIMEcharset; *p; p++)
-      *p = TOLOWER(*p);
-  if (argc >=4 )
-    strncpy(this_LYNXcharset,argv[3],UC_MAXLEN_LYNXCSNAME);
-  else if (!this_LYNXcharset || ! *this_LYNXcharset) {
-    strncpy(this_LYNXcharset,this_MIMEcharset,UC_MAXLEN_LYNXCSNAME);
-  }
-  if ((i=strlen(this_LYNXcharset)) < UC_LEN_LYNXCSNAME) {
-    for (;i<UC_LEN_LYNXCSNAME;i++) 
-      this_LYNXcharset[i] = ' ';
-    this_LYNXcharset[i] = '\0';
-  }
-/*
-  fprintf(stderr,"this_MIMEcharset: %s.\n",this_MIMEcharset);
-  fprintf(stderr,"this_LYNXcharset: %s.\n",this_LYNXcharset);
-*/
-  if (this_isDefaultMap == -1)
-    this_isDefaultMap = !strncmp(this_MIMEcharset,"iso-8859-1",10);
-  fprintf(stderr,"makeuctb: %s: %stranslation map",
-	  this_MIMEcharset, (this_isDefaultMap ? "default " : ""));
-  if (this_isDefaultMap == 1)
-    *id_append = '\0';
-  else
-  for (i=0,p=this_MIMEcharset; *p && (i < UC_MAXLEN_ID_APPEND-1); p++,i++)
-    id_append[i+1] = isalnum(*p) ? *p : '_';
-  id_append[i+1] = '\0';
-  fprintf(stderr," (%s).\n", id_append);
-
-
-  printf("\
+    /*
+     *  Compute total size of Unicode list.
+     */
+    nuni = 0;
+    for (i = 0 ; i < fontlen ; i++) {
+	nuni += unicount[i];
+    }
+
+    if (argc >= 3) {
+	strncpy(this_MIMEcharset,argv[2],UC_MAXLEN_MIMECSNAME);
+    } else if (!this_MIMEcharset || !(*this_MIMEcharset)) {
+	strncpy(this_MIMEcharset,tblname,UC_MAXLEN_MIMECSNAME);
+	if ((p = strchr(this_MIMEcharset,'.')) != 0) {
+	    *p = '\0';
+	}
+    }
+    for (p = this_MIMEcharset; *p; p++) {
+	*p = TOLOWER(*p);
+    }
+    if (argc >= 4) {
+	strncpy(this_LYNXcharset,argv[3],UC_MAXLEN_LYNXCSNAME);
+    } else if (!this_LYNXcharset || !(*this_LYNXcharset)) {
+	strncpy(this_LYNXcharset,this_MIMEcharset,UC_MAXLEN_LYNXCSNAME);
+    }
+    if ((i = strlen(this_LYNXcharset)) < UC_LEN_LYNXCSNAME) {
+	for (; i < UC_LEN_LYNXCSNAME; i++) {
+	    this_LYNXcharset[i] = ' ';
+	}
+	this_LYNXcharset[i] = '\0';
+    }
+#ifdef NOTDEFINED
+    fprintf(stderr,"this_MIMEcharset: %s.\n",this_MIMEcharset);
+    fprintf(stderr,"this_LYNXcharset: %s.\n",this_LYNXcharset);
+#endif /* NOTDEFINED */
+    if (this_isDefaultMap == -1) {
+	this_isDefaultMap = !strncmp(this_MIMEcharset,"iso-8859-1", 10);
+    }
+    fprintf(stderr,
+    	    "makeuctb: %s: %stranslation map",
+ 	    this_MIMEcharset, (this_isDefaultMap ? "default " : ""));
+    if (this_isDefaultMap == 1) {
+	*id_append = '\0';
+    } else {
+	for (i = 0, p = this_MIMEcharset;
+	     *p && (i < UC_MAXLEN_ID_APPEND-1);
+	     p++, i++) {
+	    id_append[i+1] = isalnum(*p) ? *p : '_';
+	}
+    }
+    id_append[i+1] = '\0';
+    fprintf(stderr, " (%s).\n", id_append);
+
+    printf("\
 /*\n\
- * uni_hash.tbl\n\
+ *  uni_hash.tbl\n\
  *\n\
- * Do not edit this file; it was automatically generated by\n\
+ *  Do not edit this file; it was automatically generated by\n\
  *\n\
- * %s %s\n\
+ *  %s %s\n\
  *\n\
  */\n\
 \n\
 static u8 dfont_unicount%s[%d] = \n\
 {\n\t", argv[0], argv[1], id_append, fontlen);
 
-  for ( i = 0 ; i < fontlen ; i++ )
-    {
-      if (i >= 128 && unicount[i] > 0 && i < lowest_eight)
-        lowest_eight = i;
-      printf("%3d", unicount[i]);
-      if ( i == fontlen-1 )
-        printf("\n};\n");
-      else if ( i % 8 == 7 )
-        printf(",\n\t");
-      else
-        printf(", ");
+    for (i = 0; i < fontlen; i++) {
+	if (i >= 128 && unicount[i] > 0 && i < lowest_eight) {
+	    lowest_eight = i;
+	}
+	printf("%3d", unicount[i]);
+	if (i == (fontlen - 1)) {
+	    printf("\n};\n");
+	} else if ((i % 8) == 7) {
+	    printf(",\n\t");
+	} else {
+	    printf(", ");
+	}
+    }
+
+    /*
+     *  If lowest_eightbit is anything else but 999,
+     *  this can't be 7-bit only.
+     */
+    if (lowest_eight != 999 && !RawUni) {
+	RawUni = UCT_ENC_8BIT;
     }
 
-  /* If lowest_eightbit is anything else but 999, this can't be 7-bit
-   * only. */
-  if (lowest_eight != 999 && !RawUni)
-    RawUni = UCT_ENC_8BIT;
-
-  if (nuni)
-    printf("\nstatic u16 dfont_unitable%s[%d] = \n{\n\t", id_append, nuni);
-  else
-    printf("\nstatic u16 dfont_unitable%s[1]; /* dummy */\n", id_append);
-
-  fp0 = 0;
-  nent = 0;
-  for ( i = 0 ; i < nuni ; i++ )
-    {
-       while ( nent >= unicount[fp0] )
-         {
-            fp0++;
-            nent = 0;
-         }
-       printf("0x%04x", unitable[fp0][nent++]);
-       if ( i == nuni-1 )
-         printf("\n};\n");
-       else if ( i % 8 == 7 )
-         printf(",\n\t");
-       else
-         printf(", ");
+    if (nuni) {
+	printf("\nstatic u16 dfont_unitable%s[%d] = \n{\n\t",
+	       id_append, nuni);
+    } else {
+	printf("\nstatic u16 dfont_unitable%s[1]; /* dummy */\n", id_append);
     }
 
-  if (themap_str.entry_ct)
-    printf("\n\
+    fp0 = 0;
+    nent = 0;
+    for (i = 0; i < nuni; i++) {
+	while (nent >= unicount[fp0]) {
+	    fp0++;
+	    nent = 0;
+	}
+	printf("0x%04x", unitable[fp0][nent++]);
+	if (i == (nuni - 1)) {
+	    printf("\n};\n");
+	} else if ((i % 8) == 7) {
+	    printf(",\n\t");
+	} else {
+	    printf(", ");
+	}
+    }
+
+    if (themap_str.entry_ct) {
+	printf("\n\
 static struct unipair_str repl_map%s[%d] = \n\
 {\n\t", id_append, themap_str.entry_ct);
-  else
-printf("\n\
+    } else {
+	printf("\n\
 /* static struct unipair_str repl_map%s[]; */\n", id_append);
+    }
     
-  for ( i = 0 ; i < themap_str.entry_ct ; i++ )
-    {
-      printf("{0x%x,\"%s\"}", themap_str.entries[i].unicode,
-                              themap_str.entries[i].replace_str);
-      if ( i == themap_str.entry_ct-1 )
-        printf("\n};\n");
-      else if ( i % 4 == 3 )
-        printf(",\n\t");
-      else
-        printf(", ");
+    for (i = 0; i < themap_str.entry_ct; i++) {
+	printf("{0x%x,\"%s\"}",
+	       themap_str.entries[i].unicode,
+	       themap_str.entries[i].replace_str);
+	if (i == (themap_str.entry_ct - 1)) {
+	    printf("\n};\n");
+	} else if ((i % 4) == 3) {
+	    printf(",\n\t");
+	} else {
+	    printf(", ");
+	}
     }
-  if (themap_str.entry_ct)
-    printf("\n\
+    if (themap_str.entry_ct) {
+	printf("\n\
 static struct unimapdesc_str dfont_replacedesc%s = {%d,repl_map%s};\n",
 id_append, themap_str.entry_ct, id_append);
-  else
-    printf("\n\
+    } else {
+	printf("\n\
 static struct unimapdesc_str dfont_replacedesc%s = {0,NULL};\n",id_append);
+    }
 
-  printf("#define UC_CHARSET_SETUP%s UC_Charset_Setup(\
+    printf("#define UC_CHARSET_SETUP%s UC_Charset_Setup(\
 \"%s\",\\\n\"%s\",\\\n\
 dfont_unicount%s,dfont_unitable%s,%i,\\\n\
 dfont_replacedesc%s,%i,%i)\n",
 id_append, this_MIMEcharset, this_LYNXcharset,
 id_append, id_append, nuni, id_append, lowest_eight, RawUni);
 
-  exit(EX_OK);
+    exit(EX_OK);
 }
diff --git a/src/chrtrans/mnemonic_suni.tbl b/src/chrtrans/mnemonic_suni.tbl
index d2f05d89..7f08408c 100644
--- a/src/chrtrans/mnemonic_suni.tbl
+++ b/src/chrtrans/mnemonic_suni.tbl
@@ -2,7 +2,7 @@
 Mmnemonic
 
 #Name as a Display Charset (used on Options screen)
-ORFC1345 Mnemonic
+ORFC 1345 Mnemonic
  
 # U+0020:&SP
 U+0021:!
diff --git a/src/descrip.mms b/src/descrip.mms
index 389514f0..6b1316a8 100644
--- a/src/descrip.mms
+++ b/src/descrip.mms
@@ -1,6 +1,9 @@
 !       Make LYNX hypertext browser under VMS
 !       =====================================
 !
+!	NOTE:  Use [.SRC.CHRTRANS]BUILD-CHRTRANS.COM to create the
+!	       chrtrans header files before using this descrip.mms.
+!
 ! History:
 !  1/1/93  creation at KU (Lou montulli@ukanaix.cc.ukans.edu). 
 !  4/12/93 (seb@lns61.tn.cornell.edu)
@@ -21,6 +24,7 @@
 !  07/26/95 FM Separated transport (TOPT) and compiler (COPT) option files.
 !  07/29/95 FM Added support for GNUC.
 !  02/29/96 FM Added LYMap.
+!  06/28/97 FM Added UCAuto, UCAux, and UCdomap.
 !
 ! Instructions:
 !       Use the correct command line for your TCP/IP implementation:
@@ -58,7 +62,7 @@ OBJS = 	DefaultStyle.obj, GridText.obj, HTAlert.obj, HTFWriter.obj, -
 	LYList.obj, LYMail.obj, LYMain.obj, LYMainLoop.obj, LYMap.obj, -
 	LYNews.obj, LYOptions.obj, LYPrint.obj, LYrcFile.obj, LYReadCFG.obj, -
 	LYSearch.obj, LYShowInfo.obj, LYStrings.obj, LYTraversal.obj, -
-	LYUpload.obj, LYUtils.obj
+	LYUpload.obj, LYUtils.obj, UCAuto.obj, UCAux.obj, UCdomap.obj
 
 .ifdef WIN_TCP
 TCP = WIN_TCP