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.c2
-rw-r--r--src/HTFWriter.c4
-rw-r--r--src/HTML.c16
-rw-r--r--src/LYCurses.c281
-rw-r--r--src/LYCurses.h33
-rw-r--r--src/LYExtern.c4
-rw-r--r--src/LYForms.c170
-rw-r--r--src/LYGlobalDefs.h4
-rw-r--r--src/LYHash.h3
-rw-r--r--src/LYKeymap.c547
-rw-r--r--src/LYKeymap.h20
-rw-r--r--src/LYMail.c9
-rw-r--r--src/LYMain.c40
-rw-r--r--src/LYMainLoop.c58
-rw-r--r--src/LYOptions.c157
-rw-r--r--src/LYStrings.c427
-rw-r--r--src/LYStrings.h10
-rw-r--r--src/LYStyle.c143
-rw-r--r--src/LYStyle.h4
-rw-r--r--src/LYUtils.c10
20 files changed, 1217 insertions, 725 deletions
diff --git a/src/GridText.c b/src/GridText.c
index 3c148609..5786b5cb 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -4432,7 +4432,7 @@ PUBLIC void _internal_HTC ARGS3(HText *,text, int,style, int,dir)
 	if (line->numstyles > 0 && dir == 0 &&
 	    line->styles[line->numstyles].direction &&
 	    line->styles[line->numstyles].style == style &&
-	    line->styles[line->numstyles].horizpos
+	    (int) line->styles[line->numstyles].horizpos
 	    == (int)line->size - ctrl_chars_on_this_line) {
 	    /*
 	     *  If this is an OFF change directly preceded by an
diff --git a/src/HTFWriter.c b/src/HTFWriter.c
index 6ea0dea1..653c2a9f 100644
--- a/src/HTFWriter.c
+++ b/src/HTFWriter.c
@@ -740,7 +740,7 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
 	    return(NULL);
 	}
 
-	if (((cp=strchr(pres->rep->name, ';')) != NULL) &&
+	if (((cp = strchr(pres->rep->name, ';')) != NULL) &&
 	    strstr((cp+1), "charset") != NULL) {
 	    _user_message(MSG_DOWNLOAD_OR_CANCEL, pres->rep->name);
 	} else if (*(pres->rep->name) != '\0')	{
@@ -749,7 +749,7 @@ PUBLIC HTStream* HTSaveToFile ARGS3(
 	    _statusline(CANNOT_DISPLAY_FILE_D_OR_C);
 	}
 
-	while(c != 'D') {
+	while (c != 'D' && c != 'C') {
 	    c = LYgetch_single();
 #ifdef VMS
 	    /*
diff --git a/src/HTML.c b/src/HTML.c
index c0fcf621..f346f2de 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -3204,7 +3204,7 @@ PRIVATE int HTML_start_element ARGS6(
 #else
 	/*Close an HREF-less NAMED-ed now if force_empty_hrefless_a was
 	    requested - VH*/
-	if (href == NULL && force_empty_hrefless_a) { 
+	if (href == NULL && force_empty_hrefless_a) {
 	    SET_SKIP_STACK(HTML_A);
 	    HTML_end_element(me, HTML_A, include);
 	}
@@ -5181,7 +5181,11 @@ PRIVATE int HTML_start_element ARGS6(
 	    /* text+file don't go in here */
 	    if ((UseALTasVALUE == TRUE) ||
 		(present && present[HTML_INPUT_VALUE] &&
-		 value[HTML_INPUT_VALUE] && *value[HTML_INPUT_VALUE])) {
+		 value[HTML_INPUT_VALUE] &&
+		(*value[HTML_INPUT_VALUE] ||
+		 (I.type && (!strcasecomp(I.type, "checkbox") ||
+			     !strcasecomp(I.type, "radio")))))) {
+
 		/*
 		 *  Convert any HTML entities or decimal escaping. - FM
 		 */
@@ -6731,11 +6735,11 @@ PRIVATE int HTML_end_element ARGS3(
 	 */
 	me->inA = FALSE;
 #ifdef MARK_HIDDEN_LINKS
-	if (hidden_link_marker && *hidden_link_marker && 
-		HText_isAnchorBlank(me->text, me->CurrentANum) ) {	    
-	    HText_appendText(me->text,hidden_link_marker);	
+	if (hidden_link_marker && *hidden_link_marker &&
+		HText_isAnchorBlank(me->text, me->CurrentANum) ) {
+	    HText_appendText(me->text,hidden_link_marker);
 	}
-#endif	
+#endif
 	UPDATE_STYLE;
 	if (me->inBoldA == TRUE && me->inBoldH == FALSE)
 	    HText_appendCharacter(me->text, LY_BOLD_END_CHAR);
diff --git a/src/LYCurses.c b/src/LYCurses.c
index d25d10c3..6991981d 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -198,48 +198,44 @@ PRIVATE void sl_suspend ARGS1(
 #endif /* SIGSTOP */
     return;
 }
+#endif /* USE_SLANG */
 
-#else  /* Not slang: */
-
-#ifdef VMS
 /*
-**  This function boxes windows with graphic characters for
-**  VMS curses.  Pass it the window, it's height, and it's
-**  width. - FM
+**  This function boxes windows for (n)curses.
 */
-PUBLIC void VMSbox ARGS3(
+PUBLIC void LYbox ARGS2(
 	WINDOW *,	win,
-	int,		height,
-	int,		width)
+	BOOLEAN,	formfield GCC_UNUSED)
 {
+#ifdef USE_SLANG
+    SLsmg_draw_box(win->top_y, win->left_x, win->height, win->width + 4);
+#else
+#ifdef VMS
+    /*
+     * This should work for VAX-C and DEC-C, since they both have the same
+     * win._max_y and win._max_x members -TD
+     *
+     * (originally VMSbox by FM)
+     */
     int i;
 
     wmove(win, 0, 0);
     waddstr(win, "\033)0\016l");
-    for (i = 1; i < width; i++)
+    for (i = 1; i < win->_max_x; i++)
 	waddch(win, 'q');
     waddch(win, 'k');
-    for (i = 1; i < height-1; i++) {
+    for (i = 1; i < win->_max_y-1; i++) {
 	wmove(win, i, 0);
 	waddch(win, 'x');
-	wmove(win, i, width-1);
+	wmove(win, i, win->_max_x-1);
 	waddch(win, 'x');
     }
     wmove(win, i, 0);
     waddch(win, 'm');
-    for (i = 1; i < width; i++)
+    for (i = 1; i < win->_max_x; i++)
 	waddch(win, 'q');
     waddstr(win, "j\017");
-}
-#else
-/*
-**  This function boxes windows for non-VMS (n)curses.
-**  Pass it the window. - FM
-*/
-PUBLIC void LYbox ARGS2(
-	WINDOW *,	win,
-	BOOLEAN,	formfield GCC_UNUSED)
-{
+#else /* !VMS */
     /*
      *	If the terminal is in UTF-8 mode, it probably cannot understand
      *	box drawing characters as (n)curses handles them.  (This may also
@@ -276,9 +272,10 @@ PUBLIC void LYbox ARGS2(
     if (formfield)
 	wcurses_css(win, "frame", ABS_OFF);
 #endif
-}
 #endif /* VMS */
+    wrefresh(win);
 #endif /* USE_SLANG */
+}
 
 #if defined(USE_COLOR_STYLE)
 /* Ok, explanation of the USE_COLOR_STYLE styles.  The basic styles (ie non
@@ -336,109 +333,108 @@ PUBLIC void curses_w_style ARGS3(
 {
 #if OMIT_SCN_KEEPING
 # define SPECIAL_STYLE /*(CSHASHSIZE+1) */ 88888
-  /* if TRACEs are not compiled in, this macro is redundant - we neend't valid
-    'ds' to stack off. */
+/* if TRACEs are not compiled in, this macro is redundant - we needn't valid
+'ds' to stack off. */
 #endif
 
-	int YP,XP;
+    int YP,XP;
 #if !OMIT_SCN_KEEPING
-	bucket* ds= (style == NOSTYLE ? &nostyle_bucket : &hashStyles[style]);
+    bucket* ds= (style == NOSTYLE ? &nostyle_bucket : &hashStyles[style]);
 #else
-	bucket* ds= (style == NOSTYLE ?	     &nostyle_bucket :
-		(style== SPECIAL_STYLE ? &special_bucket :&hashStyles[style]) );
+    bucket* ds= (style == NOSTYLE ?	     &nostyle_bucket :
+	    (style== SPECIAL_STYLE ? &special_bucket :&hashStyles[style]) );
 #endif
 
 
-	if (!ds->name)
-	{
-		CTRACE((tfp, "CSS.CS:Style %d not configured\n",style));
+    if (!ds->name) {
+	CTRACE((tfp, "CSS.CS:Style %d not configured\n",style));
 #if !OMIT_SCN_KEEPING
-		return;
+	return;
 #endif
-	}
+    }
 
-	CTRACE((tfp, "CSS.CS:<%s%s> (%d)\n",(dir?"":"/"),ds->name,ds->code));
+    CTRACE((tfp, "CSS.CS:<%s%s> (%d)\n",(dir?"":"/"),ds->name,ds->code));
 
-	getyx (win, YP, XP);
+    getyx (win, YP, XP);
 
-	if (style == s_normal && dir)
-	{
-		wattrset(win,A_NORMAL);
-		if (win==stdscr) cached_styles[YP][XP]=s_normal;
-		return;
-	}
+    if (style == s_normal && dir) {
+	wattrset(win,A_NORMAL);
+	if (win==stdscr) cached_styles[YP][XP]=s_normal;
+	return;
+    }
 
-	switch (dir)
-	{
-		/* ABS_OFF is the same as STACK_OFF for the moment */
-	case STACK_OFF:
-		if (last_colorattr_ptr) {
-		    int last_attr = last_styles[--last_colorattr_ptr];
-		    LYAttrset(win,last_attr,last_attr);
-		}
-		else
-			LYAttrset(win,A_NORMAL,-1);
-		return;
-
-	case STACK_ON: /* remember the current attributes */
-		if (last_colorattr_ptr > 127) {
-		    CTRACE((tfp,"........... %s (0x%x) %s\r\n",
-				"attribute cache FULL, dropping last",
-				last_styles[last_colorattr_ptr],
-				"in LynxChangeStyle(curses_w_style)"));
-		    last_colorattr_ptr--;
-		}
-		last_styles[last_colorattr_ptr++] = getattrs(stdscr);
-		/* don't cache style changes for active links */
+    switch (dir)
+    {
+	/* ABS_OFF is the same as STACK_OFF for the moment */
+    case STACK_OFF:
+	if (last_colorattr_ptr) {
+	    int last_attr = last_styles[--last_colorattr_ptr];
+	    LYAttrset(win,last_attr,last_attr);
+	}
+	else
+	    LYAttrset(win,A_NORMAL,-1);
+	break;
+
+    case STACK_ON: /* remember the current attributes */
+	if (last_colorattr_ptr > 127) {
+	    CTRACE((tfp,"........... %s (0x%x) %s\r\n",
+			"attribute cache FULL, dropping last",
+			last_styles[last_colorattr_ptr],
+			"in LynxChangeStyle(curses_w_style)"));
+	    last_colorattr_ptr--;
+	}
+	last_styles[last_colorattr_ptr++] = getattrs(stdscr);
+	/* don't cache style changes for active links */
 #if OMIT_SCN_KEEPING
-		/* since we don't compute the hcode to stack off in HTML.c, we
-		 * don't know whether this style is configured.  So, we
-		 * shouldn't simply return on stacking on on unconfigured
-		 * styles, we should push curr attrs on stack.  -HV
-		 */
-		if (!ds->name) return;
+	/* since we don't compute the hcode to stack off in HTML.c, we
+	 * don't know whether this style is configured.  So, we
+	 * shouldn't simply return on stacking on unconfigured
+	 * styles, we should push curr attrs on stack.  -HV
+	 */
+	if (!ds->name) break;
 #endif
-		if (style != s_alink)
-		{
-			CTRACE((tfp, "CACHED: <%s> @(%d,%d)\n", ds->name, YP, XP));
-			if (win==stdscr) cached_styles[YP][XP]=style;
-		}
-		LYAttrset(win, ds->color, ds->mono);
-		return;
-
-	case ABS_ON: /* change without remembering the previous style */
-		/* don't cache style changes for active links */
-		if (style != s_alink)
-		{
-			CTRACE((tfp, "CACHED: <%s> @(%d,%d)\n", ds->name, YP, XP));
-			if (win==stdscr) cached_styles[YP][XP]=style;
-		}
-		LYAttrset(win, ds->color, ds->mono);
-		return;
+	if (style != s_alink) {
+	    CTRACE((tfp, "CACHED: <%s> @(%d,%d)\n", ds->name, YP, XP));
+	    if (win == stdscr) cached_styles[YP][XP] = style;
 	}
+	LYAttrset(win, ds->color, ds->mono);
+	break;
+
+    case ABS_ON: /* change without remembering the previous style */
+	    /* don't cache style changes for active links */
+	if (style != s_alink) {
+	    CTRACE((tfp, "CACHED: <%s> @(%d,%d)\n", ds->name, YP, XP));
+	    if (win == stdscr) cached_styles[YP][XP] = style;
+	}
+	LYAttrset(win, ds->color, ds->mono);
+	break;
+    }
 }
 
 /*
  * wrapper function to set on-screen styles - RP
  */
-PUBLIC void wcurses_css ARGS3(WINDOW *,win,char*,name,int,dir)
-{
-	int try_again=1;
-	while (try_again)
-	{
-		int tmpHash=hash_code(name);
-		CTRACE((tfp, "CSSTRIM:trying to set [%s] style - ", name));
-		if (tmpHash==NOSTYLE) {
-			char *class=strrchr(name, '.');
-			CTRACE((tfp, "undefined, trimming at %p\n", class));
-			if (class)	*class='\0';
-			else		try_again=0;
-		} else {
-			CTRACE((tfp, "ok (%d)\n", hash_code(name)));
-			curses_w_style(win, hash_code(name), dir);
-			try_again=0;
-		}
+PUBLIC void wcurses_css ARGS3(
+    WINDOW *,	win,
+    char*,	name,
+    int,	dir)
+{
+    int try_again = 1;
+
+    while (try_again) {
+	int tmpHash = hash_code(name);
+	CTRACE((tfp, "CSSTRIM:trying to set [%s] style - ", name));
+	if (tmpHash == NOSTYLE) {
+	    char *class = strrchr(name, '.');
+	    CTRACE((tfp, "undefined, trimming at %p\n", class));
+	    if (class)	*class = '\0';
+	    else	try_again = 0;
+	} else {
+	    CTRACE((tfp, "ok (%d)\n", hash_code(name)));
+	    curses_w_style(win, hash_code(name), dir);
+	    try_again = 0;
 	}
+    }
 }
 
 PUBLIC void curses_css ARGS2(char *,name,int,dir)
@@ -1322,6 +1318,52 @@ PUBLIC void LYsubAttr ARGS1(
 #endif /* FANCY_CURSES */
 #endif /* VMS */
 
+/* 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
+ * handle 8-bit characters unlike addstr (though more info would be useful).
+ *
+ * We're blank-filling so that with SVr4 curses, it'll show the background
+ * color to a uniform width in the popup-menu.
+ */
+#ifndef USE_SLANG
+PUBLIC void LYpaddstr ARGS3(
+	WINDOW *,	the_window,
+	int,		width,
+	CONST char *,	the_string)
+{
+    width -= strlen(the_string);
+    waddstr(the_window, the_string);
+    while (width-- > 0)
+	waddstr(the_window, " ");
+}
+#endif
+
+PUBLIC WINDOW *LYstartPopup ARGS4(
+    int,	top_y,
+    int,	left_x,
+    int,	height,
+    int,	width)
+{
+    WINDOW *form_window = 0;
+#ifdef USE_SLANG
+    static WINDOW fake_window;
+    SLsmg_fill_region(top_y, left_x - 1, height, width + 4, ' ');
+    form_window = &fake_window;
+    form_window->top_y  = top_y;
+    form_window->left_x = left_x;
+    form_window->height = height;
+    form_window->width  = width;
+#else
+    if (!(form_window = newwin(height, width + 4, top_y, left_x - 1)) &&
+	!(form_window = newwin(height, 0, top_y, 0))) {
+	HTAlert(POPUP_FAILED);
+    } else {
+	LYsubwindow(form_window);
+    }
+#endif /* USE_SLANG */
+    return form_window;
+}
+
 PUBLIC void LYstartTargetEmphasis NOARGS
 {
 #ifdef USE_COLOR_STYLE
@@ -2040,3 +2082,32 @@ PUBLIC void lynx_stop_all_colors NOARGS
    stop_reverse ();
    stop_bold ();
 }
+
+/*
+ * 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
+ */
+PUBLIC void LYstowCursor ARGS3(
+    WINDOW *,	win,
+    int,	row,
+    int,	col)
+{
+#ifdef USE_SLANG
+    if (LYShowCursor)
+	SLsmg_gotorc(win->top_y + row, win->left_x + col);
+    else
+	LYHideCursor();
+    SLsmg_refresh();
+#else
+    if (LYShowCursor)
+	wmove(win, row, col);
+    else
+	LYHideCursor();
+    wrefresh(win);
+#endif /* USE_SLANG  */
+}
diff --git a/src/LYCurses.h b/src/LYCurses.h
index 21934a56..f7be0924 100644
--- a/src/LYCurses.h
+++ b/src/LYCurses.h
@@ -47,7 +47,15 @@
 
 #ifdef USE_SLANG
 #include <slang.h>
-#define WINDOW void
+
+#undef WINDOW
+typedef struct {
+    int	top_y;
+    int left_x;
+    int height;
+    int width;
+} WINDOW;
+
 #define waddstr(w,s) addstr(s)
 
 #ifndef ACS_UARROW  
@@ -158,10 +166,6 @@
 # endif /* VMS && __GNUC__ */
 #endif /* HAVE_CONFIG_H */
 
-#if defined(NCURSES) || defined(PDCURSES)
-extern void LYsubwindow PARAMS((WINDOW * param));
-#endif /* NCURSES */
-
 /*
  * PDCurses' mouse code does nothing in the DJGPP configuration.
  */
@@ -176,12 +180,17 @@ extern void LYsubwindow PARAMS((WINDOW * param));
 #define USE_MOUSE 1
 #endif
 
-#ifdef VMS
-extern void VMSbox PARAMS((WINDOW *win, int height, int width));
+#endif /* USE_SLANG */
+
+#ifdef USE_SLANG
+#define LYstopPopup() /* nothing */
 #else
+extern void LYsubwindow PARAMS((WINDOW * param));
+#define LYstopPopup() LYsubwindow(0)
+#endif /* NCURSES */
+
 extern void LYbox PARAMS((WINDOW *win, BOOLEAN formfield));
-#endif /* VMS */
-#endif /* USE_SLANG */
+extern WINDOW *LYstartPopup PARAMS((int top_y, int left_x, int height, int width));
 
 /*
  * Useful macros not in PDCurses or very old ncurses headers.
@@ -247,6 +256,7 @@ extern void LYstartTargetEmphasis NOPARAMS;
 extern void LYstopTargetEmphasis NOPARAMS;
 extern void LYtouchline PARAMS((int row));
 extern void LYwaddnstr PARAMS((WINDOW *w, CONST char *s, size_t len));
+extern void LYpaddstr PARAMS((WINDOW *w, int width, CONST char *s));
 
 #define LYaddstr(s)      LYwaddnstr(stdscr, s, strlen(s))
 #define LYaddnstr(s,len) LYwaddnstr(stdscr, s, len)
@@ -310,9 +320,6 @@ extern unsigned int Lynx_Color_Flags;
 /*
  *  Map some curses functions to slang functions.
  */
-#ifndef WINDOW
-#define WINDOW void
-#endif
 #define stdscr NULL
 #ifdef SLANG_MBCS_HACK
 extern int PHYSICAL_SLtt_Screen_Cols;
@@ -552,4 +559,6 @@ extern void lynx_stop_all_colors NOPARAMS;
 #define LYHideCursor() move((LYlines - 1), (LYcols - 2))
 #endif
 
+extern void LYstowCursor PARAMS((WINDOW * win, int row, int col));
+
 #endif /* LYCURSES_H */
diff --git a/src/LYExtern.c b/src/LYExtern.c
index 338cc42b..8cecb422 100644
--- a/src/LYExtern.c
+++ b/src/LYExtern.c
@@ -191,8 +191,8 @@ BOOL run_external ARGS2(
 
 #ifdef WIN_EX			/* 1998/01/26 (Mon) 09:16:13 */
     if (c == NULL) {
-	HTInfoMsg("Not external command exists");
-	return;
+	HTInfoMsg("External command is null");
+	return 0;
     }
 #endif
 
diff --git a/src/LYForms.c b/src/LYForms.c
index 11eb5125..f4b57b78 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -92,11 +92,11 @@ PUBLIC int change_form_link_ex ARGS8(
 		dummy = popup_options(form->num_value, form->select_list,
 				form_link->ly, form_link->lx, form->size,
 				form->size_l, form->disabled);
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#if CTRL_W_HACK != DO_NOTHING
 		if (!enable_scrollback)
 		    c = CTRL_W_HACK;  /* CTRL-W refresh without clearok */
 		else
-#endif /* FANCY_CURSES || USE_SLANG */
+#endif
 		    c = 12;  /* CTRL-L for repaint */
 		break;
 	    }
@@ -123,11 +123,11 @@ PUBLIC int change_form_link_ex ARGS8(
 		  */
 		form->value_cs = opt_ptr->value_cs;
 	    }
-#if defined(FANCY_CURSES) || defined(USE_SLANG)
+#if CTRL_W_HACK != DO_NOTHING
 	    if (!enable_scrollback)
 		c = CTRL_W_HACK;	 /* CTRL-W refresh without clearok */
 	    else
-#endif /* FANCY_CURSES || USE_SLANG */
+#endif
 		c = 12;	 /* CTRL-L for repaint */
 	    break;
 
@@ -445,14 +445,13 @@ again:
 
 	ch = LYgetch_input();
 #ifdef SUPPORT_MULTIBYTE_EDIT
-#ifdef WIN_EX
-	if (!refresh_mb && (EditBinding(ch) != LYE_CHAR))
-	    goto again;
-#else
-	if (!refresh_mb &&
-	    (EditBinding(ch) != LYE_CHAR) && (EditBinding(ch) != LYE_AIX))
-	    goto again;
+	if (!refresh_mb
+	 && (EditBinding(ch) != LYE_CHAR)
+#ifndef WIN_EX
+	 && (EditBinding(ch) != LYE_AIX)
 #endif
+	    )
+	    goto again;
 #endif /* SUPPORT_MULTIBYTE_EDIT */
 #ifdef VMS
 	if (HadVMSInterrupt) {
@@ -854,26 +853,29 @@ PRIVATE int get_popup_option_number ARGS2(
     return num;
 }
 
-/* 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
- * handle 8-bit characters unlike addstr (though more info would be useful).
- *
- * We're blank-filling so that with SVr4 curses, it'll show the background
- * color to a uniform width in the popup-menu.
- */
-#ifndef USE_SLANG
-PRIVATE void paddstr ARGS3(
-	WINDOW *,	the_window,
+PRIVATE void draw_option ARGS5(
+	WINDOW *,	win,
+	int,		entry,
 	int,		width,
-	char *,		the_string)
+	BOOL,		reversed,
+	OptionType *,	opt_ptr)
 {
-    width -= strlen(the_string);
-    waddstr(the_window, the_string);
-    while (width-- > 0)
-	waddstr(the_window, " ");
+#ifdef USE_SLANG
+    if (reversed)
+	SLsmg_gotorc((win->top_y + entry), win->left_x + 2);
+    SLsmg_gotorc(win->top_y + entry, win->left_x + 2);
+    SLsmg_write_nstring(opt_ptr->name, win->width);
+    if (reversed)
+	SLsmg_set_color(0);
+#else
+    wmove(win, entry, 2);
+    if (reversed)
+	wstart_reverse(win);
+    LYpaddstr(win, width, opt_ptr->name);
+    if (reversed)
+	wstop_reverse(win);
+#endif /* USE_SLANG */
 }
-#endif
-
 
 PRIVATE int popup_options ARGS7(
 	int,		cur_selection,
@@ -891,9 +893,7 @@ PRIVATE int popup_options ARGS7(
      */
     int c = 0, cmd = 0, i = 0, j = 0, rel = 0;
     int orig_selection = cur_selection;
-#ifndef USE_SLANG
     WINDOW * form_window;
-#endif /* !USE_SLANG */
     int num_options = 0, top, bottom, length = -1;
     OptionType * opt_ptr = list;
     int window_offset = 0;
@@ -1017,30 +1017,12 @@ 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
      */
-#ifdef USE_SLANG
-    if (width + 4 > SLtt_Screen_Cols) {
+    if (width + 4 > LYcols) {
 	lx = 1;
 	width = LYcols - 5; /* avoids a crash? - kw */
     }
-    SLsmg_fill_region(top, lx - 1, bottom - top, width + 4, ' ');
-#else
-    if (!(form_window = newwin(bottom - top, width + 4, top, lx - 1)) &&
-	!(form_window = newwin(bottom - top, 0, top, 0))) {
-	HTAlert(POPUP_FAILED);
+    if ((form_window = LYstartPopup(top, lx, bottom - top, width)) == 0)
 	return(orig_selection);
-    }
-    scrollok(form_window, TRUE);
-#ifdef PDCURSES
-    keypad(form_window, TRUE);
-#endif /* PDCURSES */
-#if defined(NCURSES) || defined(PDCURSES)
-    LYsubwindow(form_window);
-#endif
-#if defined(HAVE_GETBKGD) /* not defined in ncurses 1.8.7 */
-    wbkgd(form_window, getbkgd(stdscr));
-    wbkgdset(form_window, getbkgd(stdscr));
-#endif
-#endif /* USE_SLANG */
 
     /*
      *  Set up the window_offset for options.
@@ -1071,107 +1053,40 @@ redraw:
      */
     for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) {
 	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
-	    wmove(form_window, ((i + 1) - window_offset), 2);
-	    paddstr(form_window, width, opt_ptr->name);
-#endif /* USE_SLANG */
+	    draw_option(form_window, ((i + 1) - window_offset), width, FALSE, opt_ptr);
 	}
     }
-#ifdef USE_SLANG
-    SLsmg_draw_box(top, (lx - 1), (bottom - top), (width + 4));
-#else
-#ifdef VMS
-    VMSbox(form_window, (bottom - top), (width + 4));
-#else
     LYbox(form_window, TRUE);
-#endif /* VMS */
-    wrefresh(form_window);
-#endif /* USE_SLANG */
     opt_ptr = NULL;
 
     /*
      *  Loop on user input.
      */
     while (cmd != LYK_ACTIVATE) {
+	int row = ((i + 1) - window_offset);
 
 	/*
 	 *  Unreverse cur selection.
 	 */
 	if (opt_ptr != NULL) {
-#ifdef USE_SLANG
-	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
-	    SLsmg_write_nstring(opt_ptr->name, width);
-#else
-	    wmove(form_window, ((i + 1) - window_offset), 2);
-	    paddstr(form_window, width, opt_ptr->name);
-#endif /* USE_SLANG */
+	    draw_option(form_window, row, width, FALSE, opt_ptr);
 	}
 
 	opt_ptr = list;
 
 	for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next)
 	    ; /* null body */
+	row = ((i + 1) - window_offset);
 
-#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
-	wmove(form_window, ((i + 1) - window_offset), 2);
-#if defined(WIN_EX)	/* FIX */
-	wattron(form_window, A_REVERSE);
-#else
-	wstart_reverse(form_window);
-#endif
-	paddstr(form_window, width, opt_ptr->name);
-#if defined(WIN_EX)	/* FIX */
-	wattroff(form_window, A_REVERSE);
-#else
-	wstop_reverse(form_window);
-#endif
-	/*
-	 *  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  */
+	draw_option(form_window, row, width, TRUE, opt_ptr);
+	LYstowCursor(form_window, row, 1);
 
 	c = LYgetch_choice();
 	if (c == 7) {		/* Control-C or Control-G */
 	    cmd = LYK_QUIT;
 #ifndef USE_SLANG
 	} else if (c == MOUSE_KEY) {
-	    if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_selection)) < 0)
+	    if ((cmd = fancy_mouse(form_window, row, &cur_selection)) < 0)
 		goto redraw;
 	    if  (cmd == LYK_ACTIVATE)
 		break;
@@ -1852,12 +1767,7 @@ restore_popup_statusline:
 		break;
 	}
     }
-#ifndef USE_SLANG
-    delwin(form_window);
-#if defined(NCURSES) || defined(PDCURSES)
-    LYsubwindow(0);
-#endif
-#endif /* !USE_SLANG */
+    LYstopPopup();
 
     return(disabled ? orig_selection : cur_selection);
 }
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index faa41a86..3def0c78 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -215,7 +215,7 @@ extern int display_lines;	/* number of lines in the display */
 extern int dump_output_width;
 extern int keypad_mode;		/* NUMBERS_AS_ARROWS or LINKS_ARE_NUMBERED */
 extern int lynx_temp_subspace;
-extern int more;		/* is there more document to display? */
+extern BOOLEAN more;		/* is there more document to display? */
 extern int user_mode;		/* novice or advanced */
 extern int www_search_result;
 
@@ -405,7 +405,7 @@ extern BOOLEAN no_externals; 		/* don't allow the use of externals */
 extern BOOLEAN LYNoISMAPifUSEMAP;	/* Omit ISMAP link if MAP present? */
 extern int LYHiddenLinks;
 
-extern BOOL Old_DTD;
+extern BOOLEAN Old_DTD;
 
 #define MBM_V_MAXFILES  25		/* Max number of sub-bookmark files */
 /*
diff --git a/src/LYHash.h b/src/LYHash.h
index 383261f1..8fc83b8f 100644
--- a/src/LYHash.h
+++ b/src/LYHash.h
@@ -31,14 +31,13 @@ extern int hash_code PARAMS((char* string));
 extern bucket special_bucket;/*it's used when OMIT_SCN_KEEPING is 1 in HTML.c
     and LYCurses.c. */
 extern bucket nostyle_bucket;/*initialized properly - to be used in CTRACE when
-            NOSTYLE is passed as 'style' to curses_w_style */    
+            NOSTYLE is passed as 'style' to curses_w_style */
 
 extern int hash_code_lowercase_on_fly PARAMS((char* string));
 extern int hash_code_aggregate_char PARAMS((char c,int hash));
 extern int hash_code_aggregate_lower_str  PARAMS((char* c,int hash_was));
 
 extern int	s_alink, s_a, s_status,
-		s_label, s_value, s_high,
 		s_normal, s_alert, s_title,
 #ifdef USE_SCROLLBAR
 		s_sb_bar, s_sb_bg, s_sb_aa, s_sb_naa,
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 11c6156e..a94749b2 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -114,7 +114,7 @@ LYK_F_LINK_NUM,      LYK_1,          LYK_2,         LYK_3,
 LYK_4,               LYK_5,          LYK_6,         LYK_7,
 /* 4 */              /* 5 */         /* 6 */        /* 7 */
 
-LYK_8,               LYK_9,             0,          LYK_TRACE_LOG,
+LYK_8,               LYK_9,         LYK_COMMAND,    LYK_TRACE_LOG,
 /* 8 */              /* 9 */         /* : */        /* ; */
 
 LYK_UP_LINK,         LYK_INFO,     LYK_DOWN_LINK,   LYK_HELP,
@@ -625,129 +625,335 @@ LYK_TAG_LINK,      LYK_UPLOAD,         0,             0,
 };
 #endif /* DIRED_SUPPORT && OK_OVERRIDE */
 
-struct rmap {
-	CONST char *name;
-	CONST char *doc;
-};
-
+#define DATA(code, name, doc) { code, name, doc }
 /* The order of this array must match the LYKeymapCode enum in LYKeymap.h */
-PRIVATE struct rmap revmap[] = {
-{ "UNMAPPED",		NULL },
-{ "1",			NULL },
-{ "2",			NULL },
-{ "3",			NULL },
-{ "4",			NULL },
-{ "5",			NULL },
-{ "6",			NULL },
-{ "7",			NULL },
-{ "8",			NULL },
-{ "9",			NULL },
-{ "SOURCE",		"toggle source/presentation for current document" },
-{ "RELOAD",		"reload the current document" },
-{ "PIPE",		"pipe the current document to an external command" },
-{ "QUIT",		"quit the browser" },
-{ "ABORT",		"quit the browser unconditionally" },
-{ "NEXT_PAGE",		"view the next page of the document" },
-{ "PREV_PAGE",		"view the previous page of the document" },
-{ "UP_TWO",		"go back two lines in the document" },
-{ "DOWN_TWO",		"go forward two lines in the document" },
-{ "UP_HALF",		"go back half a page in the document" },
-{ "DOWN_HALF",		"go forward half a page in the document" },
-{ "REFRESH",		"refresh the screen to clear garbled text" },
-{ "HOME",		"go to the beginning of the current document" },
-{ "END",		"go to the end of the current document" },
-{ "FIRST_LINK",		"make the first link on the line current" },
-{ "LAST_LINK",		"make the last link on the line current" },
-{ "PREV_LINK",		"make the previous link current" },
-{ "NEXT_LINK",		"make the next link current" },
-{ "LPOS_PREV_LINK",	"make previous link current, same column for input" },
-{ "LPOS_NEXT_LINK",	"make next link current, same column for input" },
-{ "FASTBACKW_LINK",	"previous link or text area, only stops on links" },
-{ "FASTFORW_LINK",	"next link or text area, only stops on links" },
-{ "UP_LINK",		"move up the page to a previous link" },
-{ "DOWN_LINK",		"move down the page to another link" },
-{ "RIGHT_LINK",		"move right to another link" },
-{ "LEFT_LINK",		"move left to a previous link" },
-{ "HISTORY",		"display stack of currently-suspended documents" },
-{ "PREV_DOC",		"go back to the previous document" },
-{ "ACTIVATE",		"go to the document given by the current link" },
-{ "MOUSE_SUBMIT",	"follow current link, submit" }, /* not mapped */
-{ "GOTO",		"go to a document given as a URL" },
-{ "ECGOTO",		"edit the current document's URL and go to it" },
-{ "HELP",		"display help on using the browser" },
-{ "DWIMHELP",		"display help page that may depend on context" },
-{ "INDEX",		"display an index of potentially useful documents" },
-{ "NOCACHE",		"force submission of form or link with no-cache" },
-{ "INTERRUPT",		"interrupt network connection or transmission" },
-{ "MAIN_MENU",		"return to the first screen (home page)" },
-{ "OPTIONS",		"display and change option settings" },
-{ "INDEX_SEARCH",	"allow searching of an index" },
-{ "WHEREIS",		"search within the current document" },
-{ "NEXT",		"search for the next occurence" },
-{ "COMMENT",		"send a comment to the author of the current document" },
-{ "EDIT",		"edit the current document or a form's textarea" },
-{ "INFO",		"display information on the current document and link" },
-{ "PRINT",		"display choices for printing the current document" },
-{ "ADD_BOOKMARK",	"add to your personal bookmark list" },
-{ "DEL_BOOKMARK",	"delete from your personal bookmark list" },
-{ "VIEW_BOOKMARK",	"view your personal bookmark list" },
-{ "VLINKS",		"list links visited during the current Lynx session" },
-{ "SHELL",		"escape from the browser to the system" },
-{ "DOWNLOAD",		"download the current link to your computer" },
-{ "TRACE_TOGGLE",	"toggle tracing of browser operations" },
-{ "TRACE_LOG",		"view trace log if started in the current session" },
-{ "IMAGE_TOGGLE",	"toggle handling of all images as links" },
-{ "INLINE_TOGGLE",	"toggle pseudo-ALTs for inlines with no ALT string" },
-{ "HEAD",		"send a HEAD request for the current document or link" },
-{ "DO_NOTHING",		NULL },
-{ "TOGGLE_HELP",	"show other commands in the novice help menu" },
-{ "JUMP",		"go directly to a target document or action" },
-{ "KEYMAP",		"display the current key map" },
-{ "LIST",		"list the references (links) in the current document" },
-{ "TOOLBAR",		"go to Toolbar or Banner in the current document" },
-{ "HISTORICAL",		"toggle historical vs. valid/minimal comment parsing" },
-{ "MINIMAL",		"toggle minimal vs. valid comment parsing" },
-{ "SOFT_DQUOTES",	"toggle valid vs. soft double-quote parsing" },
-{ "RAW_TOGGLE",		"toggle raw 8-bit translations or CJK mode ON or OFF" },
-{ "COOKIE_JAR",		"examine the Cookie Jar" },
-{ "F_LINK_NUM",		"invoke the 'Follow link (or page) number:' prompt" },
-{ "CLEAR_AUTH",		"clear all authorization info for this session" },
-{ "SWITCH_DTD",		"switch between two ways of parsing HTML" },
-{ "ELGOTO",		"edit the current link's URL or ACTION and go to it" },
-{ "CHANGE_LINK",	"force reset of the current link on the page" },
-{ "DWIMEDIT",		"use external editor for context-dependent purpose" },
-{ "EDITTEXTAREA",	"use an external editor to edit a form's textarea" },
-{ "GROWTEXTAREA",	"add 5 new blank lines to the bottom of a textarea" },
-{ "INSERTFILE",		"insert file into a textarea (just above cursorline)" },
+PRIVATE Kcmd revmap[] = {
+    DATA(
+	LYK_UNKNOWN, "UNMAPPED",
+	NULL ),
+    DATA(
+	LYK_COMMAND, "COMMAND",
+	"prompt for, execute a command" ),
+    DATA(
+	LYK_1, "1",
+	NULL ),
+    DATA(
+	LYK_2, "2",
+	NULL ),
+    DATA(
+	LYK_3, "3",
+	NULL ),
+    DATA(
+	LYK_4, "4",
+	NULL ),
+    DATA(
+	LYK_5, "5",
+	NULL ),
+    DATA(
+	LYK_6, "6",
+	NULL ),
+    DATA(
+	LYK_7, "7",
+	NULL ),
+    DATA(
+	LYK_8, "8",
+	NULL ),
+    DATA(
+	LYK_9, "9",
+	NULL ),
+    DATA(
+	LYK_SOURCE, "SOURCE",
+	"toggle source/presentation for current document" ),
+    DATA(
+	LYK_RELOAD, "RELOAD",
+	"reload the current document" ),
+    DATA(
+	LYK_PIPE, "PIPE",
+	"pipe the current document to an external command" ),
+    DATA(
+	LYK_QUIT, "QUIT",
+	"quit the browser" ),
+    DATA(
+	LYK_ABORT, "ABORT",
+	"quit the browser unconditionally" ),
+    DATA(
+	LYK_NEXT_PAGE, "NEXT_PAGE",
+	"view the next page of the document" ),
+    DATA(
+	LYK_PREV_PAGE, "PREV_PAGE",
+	"view the previous page of the document" ),
+    DATA(
+	LYK_UP_TWO, "UP_TWO",
+	"go back two lines in the document" ),
+    DATA(
+	LYK_DOWN_TWO, "DOWN_TWO",
+	"go forward two lines in the document" ),
+    DATA(
+	LYK_UP_HALF, "UP_HALF",
+	"go back half a page in the document" ),
+    DATA(
+	LYK_DOWN_HALF, "DOWN_HALF",
+	"go forward half a page in the document" ),
+    DATA(
+	LYK_REFRESH, "REFRESH",
+	"refresh the screen to clear garbled text" ),
+    DATA(
+	LYK_HOME, "HOME",
+	"go to the beginning of the current document" ),
+    DATA(
+	LYK_END, "END",
+	"go to the end of the current document" ),
+    DATA(
+	LYK_FIRST_LINK, "FIRST_LINK",
+	"make the first link on the line current" ),
+    DATA(
+	LYK_LAST_LINK, "LAST_LINK",
+	"make the last link on the line current" ),
+    DATA(
+	LYK_PREV_LINK, "PREV_LINK",
+	"make the previous link current" ),
+    DATA(
+	LYK_NEXT_LINK, "NEXT_LINK",
+	"make the next link current" ),
+    DATA(
+	LYK_LPOS_PREV_LINK, "LPOS_PREV_LINK",
+	"make previous link current, same column for input" ),
+    DATA(
+	LYK_LPOS_NEXT_LINK, "LPOS_NEXT_LINK",
+	"make next link current, same column for input" ),
+    DATA(
+	LYK_FASTBACKW_LINK, "FASTBACKW_LINK",
+	"previous link or text area, only stops on links" ),
+    DATA(
+	LYK_FASTFORW_LINK, "FASTFORW_LINK",
+	"next link or text area, only stops on links" ),
+    DATA(
+	LYK_UP_LINK, "UP_LINK",
+	"move up the page to a previous link" ),
+    DATA(
+	LYK_DOWN_LINK, "DOWN_LINK",
+	"move down the page to another link" ),
+    DATA(
+	LYK_RIGHT_LINK, "RIGHT_LINK",
+	"move right to another link" ),
+    DATA(
+	LYK_LEFT_LINK, "LEFT_LINK",
+	"move left to a previous link" ),
+    DATA(
+	LYK_HISTORY, "HISTORY",
+	"display stack of currently-suspended documents" ),
+    DATA(
+	LYK_PREV_DOC, "PREV_DOC",
+	"go back to the previous document" ),
+    DATA(
+	LYK_ACTIVATE, "ACTIVATE",
+	"go to the document given by the current link" ),
+    DATA(
+	LYK_SUBMIT, "MOUSE_SUBMIT",
+	"DO NOT MAP:  follow current link, submit" ),
+    DATA(
+	LYK_GOTO, "GOTO",
+	"go to a document given as a URL" ),
+    DATA(
+	LYK_ECGOTO, "ECGOTO",
+	"edit the current document's URL and go to it" ),
+    DATA(
+	LYK_HELP, "HELP",
+	"display help on using the browser" ),
+    DATA(
+	LYK_DWIMHELP, "DWIMHELP",
+	"display help page that may depend on context" ),
+    DATA(
+	LYK_INDEX, "INDEX",
+	"display an index of potentially useful documents" ),
+    DATA(
+	LYK_NOCACHE, "NOCACHE",
+	"force submission of form or link with no-cache" ),
+    DATA(
+	LYK_INTERRUPT, "INTERRUPT",
+	"interrupt network connection or transmission" ),
+    DATA(
+	LYK_MAIN_MENU, "MAIN_MENU",
+	"return to the first screen (home page)" ),
+    DATA(
+	LYK_OPTIONS, "OPTIONS",
+	"display and change option settings" ),
+    DATA(
+	LYK_INDEX_SEARCH, "INDEX_SEARCH",
+	"allow searching of an index" ),
+    DATA(
+	LYK_WHEREIS, "WHEREIS",
+	"search within the current document" ),
+    DATA(
+	LYK_NEXT, "NEXT",
+	"search for the next occurence" ),
+    DATA(
+	LYK_COMMENT, "COMMENT",
+	"send a comment to the author of the current document" ),
+    DATA(
+	LYK_EDIT, "EDIT",
+	"edit the current document or a form's textarea" ),
+    DATA(
+	LYK_INFO, "INFO",
+	"display information on the current document and link" ),
+    DATA(
+	LYK_PRINT, "PRINT",
+	"display choices for printing the current document" ),
+    DATA(
+	LYK_ADD_BOOKMARK, "ADD_BOOKMARK",
+	"add to your personal bookmark list" ),
+    DATA(
+	LYK_DEL_BOOKMARK, "DEL_BOOKMARK",
+	"delete from your personal bookmark list" ),
+    DATA(
+	LYK_VIEW_BOOKMARK, "VIEW_BOOKMARK",
+	"view your personal bookmark list" ),
+    DATA(
+	LYK_VLINKS, "VLINKS",
+	"list links visited during the current Lynx session" ),
+    DATA(
+	LYK_SHELL, "SHELL",
+	"escape from the browser to the system" ),
+    DATA(
+	LYK_DOWNLOAD, "DOWNLOAD",
+	"download the current link to your computer" ),
+    DATA(
+	LYK_TRACE_TOGGLE, "TRACE_TOGGLE",
+	"toggle tracing of browser operations" ),
+    DATA(
+	LYK_TRACE_LOG, "TRACE_LOG",
+	"view trace log if started in the current session" ),
+    DATA(
+	LYK_IMAGE_TOGGLE, "IMAGE_TOGGLE",
+	"toggle handling of all images as links" ),
+    DATA(
+	LYK_INLINE_TOGGLE, "INLINE_TOGGLE",
+	"toggle pseudo-ALTs for inlines with no ALT string" ),
+    DATA(
+	LYK_HEAD, "HEAD",
+	"send a HEAD request for the current document or link" ),
+    DATA(
+	LYK_DO_NOTHING, "DO_NOTHING",
+	NULL ),
+    DATA(
+	LYK_TOGGLE_HELP, "TOGGLE_HELP",
+	"show other commands in the novice help menu" ),
+    DATA(
+	LYK_JUMP, "JUMP",
+	"go directly to a target document or action" ),
+    DATA(
+	LYK_KEYMAP, "KEYMAP",
+	"display the current key map" ),
+    DATA(
+	LYK_LIST, "LIST",
+	"list the references (links) in the current document" ),
+    DATA(
+	LYK_TOOLBAR, "TOOLBAR",
+	"go to Toolbar or Banner in the current document" ),
+    DATA(
+	LYK_HISTORICAL, "HISTORICAL",
+	"toggle historical vs.  valid/minimal comment parsing" ),
+    DATA(
+	LYK_MINIMAL, "MINIMAL",
+	"toggle minimal vs.  valid comment parsing" ),
+    DATA(
+	LYK_SOFT_DQUOTES, "SOFT_DQUOTES",
+	"toggle valid vs.  soft double-quote parsing" ),
+    DATA(
+	LYK_RAW_TOGGLE, "RAW_TOGGLE",
+	"toggle raw 8-bit translations or CJK mode ON or OFF" ),
+    DATA(
+	LYK_COOKIE_JAR, "COOKIE_JAR",
+	"examine the Cookie Jar" ),
+    DATA(
+	LYK_F_LINK_NUM, "F_LINK_NUM",
+	"invoke the 'Follow link (or page) number:' prompt" ),
+    DATA(
+	LYK_CLEAR_AUTH, "CLEAR_AUTH",
+	"clear all authorization info for this session" ),
+    DATA(
+	LYK_SWITCH_DTD, "SWITCH_DTD",
+	"switch between two ways of parsing HTML" ),
+    DATA(
+	LYK_ELGOTO, "ELGOTO",
+	"edit the current link's URL or ACTION and go to it" ),
+    DATA(
+	LYK_CHANGE_LINK, "CHANGE_LINK",
+	"force reset of the current link on the page" ),
+    DATA(
+	LYK_DWIMEDIT, "DWIMEDIT",
+	"use external editor for context-dependent purpose" ),
+    DATA(
+	LYK_EDIT_TEXTAREA, "EDITTEXTAREA",
+	"use an external editor to edit a form's textarea" ),
+    DATA(
+	LYK_GROW_TEXTAREA, "GROWTEXTAREA",
+	"add 5 new blank lines to the bottom of a textarea" ),
+    DATA(
+	LYK_INSERT_FILE, "INSERTFILE",
+	"insert file into a textarea (just above cursorline)" ),
 #ifdef EXP_ADDRLIST_PAGE
-{ "ADDRLIST",		"like LIST command, but always shows the links' URLs" },
+    DATA(
+	LYK_ADDRLIST, "ADDRLIST",
+	"like LIST command, but always shows the links' URLs" ),
 #endif
 #ifdef USE_EXTERNALS
-{ "EXTERN",		"run external program with url" },
+    DATA(
+	LYK_EXTERN, "EXTERN",
+	"run external program with url" ),
 #endif
 #ifdef VMS
-{ "DIRED_MENU",		"invoke File/Directory Manager, if available" },
+    DATA(
+	LYK_DIRED_MENU, "DIRED_MENU",
+	"invoke File/Directory Manager, if available" ),
 #else
 #ifdef DIRED_SUPPORT
-{ "DIRED_MENU",		"display a full menu of file operations" },
-{ "CREATE",		"create a new file or directory" },
-{ "REMOVE",		"remove a file or directory" },
-{ "MODIFY",		"modify the name or location of a file or directory" },
-{ "TAG_LINK",		"tag a file or directory for later action" },
-{ "UPLOAD",		"upload from your computer to the current directory" },
-{ "INSTALL",		"install file or tagged files into a system area" },
+    DATA(
+	LYK_DIRED_MENU, "DIRED_MENU",
+	"display a full menu of file operations" ),
+    DATA(
+	LYK_CREATE, "CREATE",
+	"create a new file or directory" ),
+    DATA(
+	LYK_REMOVE, "REMOVE",
+	"remove a file or directory" ),
+    DATA(
+	LYK_MODIFY, "MODIFY",
+	"modify the name or location of a file or directory" ),
+    DATA(
+	LYK_TAG_LINK, "TAG_LINK",
+	"tag a file or directory for later action" ),
+    DATA(
+	LYK_UPLOAD, "UPLOAD",
+	"upload from your computer to the current directory" ),
+    DATA(
+	LYK_INSTALL, "INSTALL",
+	"install file or tagged files into a system area" ),
 #endif /* DIRED_SUPPORT */
-#ifdef SH_EX		/* 1999/01/01 (Fri) 01:18:12 */
-{ "CHANGE_CENTER",	"toggle center alignment in HTML TABLE" },
-{ "TO_CLIPBOARD",	"link's URL to Clip Board" },
-{ "CHANGE_KCODE",	"Change Kanji code" },
+#ifdef SH_EX /* 1999/01/01 (Fri) 01:18:12 */
+    DATA(
+	LYK_CHG_CENTER, "CHANGE_CENTER",
+	"toggle center alignment in HTML TABLE" ),
+    DATA(
+	LYK_TO_CLIPBOARD, "TO_CLIPBOARD",
+	"link's URL to Clip Board" ),
+#endif
+#ifdef KANJI_CODE_OVERRIDE
+    DATA(
+	LYK_CHG_KCODE, "CHANGE_KCODE",
+	"Change Kanji code" ),
 #endif
 #endif /* VMS */
 #ifdef SUPPORT_CHDIR
- { "CHDIR",		"change current directory" },
+    DATA(
+	LYK_CHDIR, "CHDIR",
+	"change current directory" ),
 #endif
-{ NULL,			"" }
+    DATA(
+	LYK_UNKNOWN, NULL,
+	"" )
 };
+#undef DATA
 
 PRIVATE CONST struct {
     int key;
@@ -837,6 +1043,78 @@ PRIVATE struct emap ekmap[] = {
 #endif
 };
 
+/*
+ * Build a list of Lynx's commands, for use in the tab-completion in LYgetstr.
+ */
+PUBLIC HTList *LYcommandList NOARGS
+{
+    static HTList *myList = NULL;
+
+    if (myList == NULL) {
+	unsigned j;
+	myList = HTList_new();
+	for (j = 0; revmap[j].name != 0; j++) {
+	    if (revmap[j].doc != 0)
+		HTList_addObject(myList, revmap[j].name);
+	}
+    }
+    return myList;
+}
+
+/*
+ * Find the given keycode.
+ */
+PUBLIC Kcmd * LYKeycodeToKcmd ARGS1(
+	LYKeymapCode,	code)
+{
+    unsigned j;
+    Kcmd *result = 0;
+
+    if (code > LYK_UNKNOWN) {
+	for (j = 0; revmap[j].name != 0; j++) {
+	    if (revmap[j].code == code) {
+		result = revmap + j;
+		break;
+	    }
+	}
+    }
+    return result;
+}
+
+/*
+ * Find the given command-name, accepting an abbreviation if it is unique.
+ */
+PUBLIC Kcmd * LYStringToKcmd ARGS1(
+	CONST char *,	name)
+{
+    unsigned need = strlen(name);
+    unsigned j;
+    BOOL exact = FALSE;
+    Kcmd *result = 0;
+    Kcmd *maybe = 0;
+
+    if (name != 0 && *name != 0) {
+	for (j = 0; revmap[j].name != 0; j++) {
+	    if (!strcasecomp(revmap[j].name, name)) {
+		result = revmap + j;
+		break;
+	    } else if (!exact
+		&& !strncasecomp(revmap[j].name, name, need)) {
+		if (maybe == 0) {
+		    maybe = revmap + j;
+		} else {
+		    if (revmap[j].name[need] != 0
+		     && maybe->name[need] != 0) {
+			maybe = 0;
+			exact = TRUE;
+		    }
+		}
+	    }
+	}
+    }
+    return (result != 0) ? result : maybe;
+}
+
 PUBLIC char *LYKeycodeToString ARGS2 (
 	int,		c,
 	BOOLEAN,	upper8)
@@ -952,19 +1230,19 @@ PRIVATE char * format_binding ARGS2(
 	LYKeymap_t *,	table,
 	int,		i)
 {
-    unsigned the_key = table[i];
+    LYKeymap_t the_key = table[i];
     char *buf = 0;
     char *formatted;
+    Kcmd *rmap = LYKeycodeToKcmd(the_key);
 
-    if (the_key != 0
-     && the_key < TABLESIZE(revmap)
-     && revmap[the_key].name != 0
-     && revmap[the_key].doc != 0
+    if (rmap != 0
+     && rmap->name != 0
+     && rmap->doc != 0
      && (formatted = pretty_html(i-1)) != 0) {
 	HTSprintf0(&buf, "%-*s %-13s %s\n",
 		   PRETTY_LEN, formatted,
-		   revmap[the_key].name,
-		   revmap[the_key].doc);
+		   rmap->name,
+		   rmap->doc);
 	return buf;
     }
     return 0;
@@ -1016,23 +1294,14 @@ PRIVATE void print_binding ARGS3(
 
 /*
  *  Return lynxactioncode whose name is the string func.
- *  func must be present in the revmap table.
  *  returns -1 if not found. - kw
  */
 PUBLIC int lacname_to_lac ARGS1(
 	CONST char *,	func)
 {
-       int i;
-       struct rmap *mp;
+       Kcmd *mp = LYStringToKcmd(func);
 
-       if (func == NULL || *func == '\0')
-	       return (-1);
-       for (i = 0, mp = revmap; (*mp).name != NULL; mp++, i++) {
-               if (strcmp((*mp).name, func) == 0) {
-                       return i;
-               }
-       }
-       return (-1);
+       return (mp != 0) ? mp->code : -1;
 }
 
 /*
@@ -1136,8 +1405,8 @@ PRIVATE int LYLoadKeymap ARGS4 (
 	 *  Don't show CHANGE_LINK if mouse not enabled.
 	 */
 	if ((i >= 0200 || i <= ' ' || !isalpha(i-1)) &&
-	    strcmp(revmap[keymap[i]].name, "PIPE") &&
-	    (LYUseMouse || strcmp(revmap[keymap[i]].name, "CHANGE_LINK"))) {
+	    (keymap[i] != LYK_PIPE) &&
+	    (LYUseMouse || (keymap[i] != LYK_CHANGE_LINK))) {
 	    print_binding(target, i, FALSE);
 	}
     }
@@ -1163,7 +1432,6 @@ GLOBALDEF PUBLIC HTProtocol LYLynxKeymap = {"LYNXKEYMAP", LYLoadKeymap, 0};
  * for Dired mode, otherwise in the general keymap[] table.
  * If DIRED_SUPPORT or OK_OVERRIDE is not defined, don't do anything
  * when for_dired is requested.
- * func must be present in the revmap table.
  * returns lynxkeycode value != 0 if the mapping was made, 0 if not.
  */
 PUBLIC int remap ARGS3(
@@ -1171,8 +1439,7 @@ PUBLIC int remap ARGS3(
 	char *,		func,
 	BOOLEAN,	for_dired)
 {
-    int i;
-    struct rmap *mp;
+    Kcmd *mp;
     int c;
 
 #if !defined(DIRED_SUPPORT) || !defined(OK_OVERRIDE)
@@ -1197,16 +1464,14 @@ PUBLIC int remap ARGS3(
     }
     if (c + 1 >= KEYMAP_SIZE)
 	return 0;
-    for (i = 0, mp = revmap; (*mp).name != NULL; mp++, i++) {
-	if (strcmp((*mp).name, func) == 0) {
+    if ((mp = LYStringToKcmd(func)) != 0) {
 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
-	    if (for_dired)
-		key_override[c+1] = (char) i;
-	    else
+	if (for_dired)
+	    key_override[c+1] = mp->code;
+	else
 #endif
-		keymap[c+1] = (char) i;
-	    return (c ? c : LAC_TO_LKC0(i)); /* don't return 0, successful */
-	}
+	    keymap[c+1] = mp->code;
+	return (c ? c : LAC_TO_LKC0(mp->code)); /* don't return 0, successful */
     }
     return 0;
 }
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index c4f47672..b53e657f 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -1,11 +1,11 @@
 #ifndef LYKEYMAP_H
 #define LYKEYMAP_H
 
-#ifndef HTUTILS_H
 #include <HTUtils.h>
-#endif
+#include <HTList.h>
 
 extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int KeyName));
+extern HTList *LYcommandList NOPARAMS;
 extern char *LYKeycodeToString PARAMS((int c, BOOLEAN upper8));
 extern char *fmt_keys PARAMS((int lkc_first, int lkc_second));
 extern char *key_for_func PARAMS((int func));
@@ -111,10 +111,13 @@ extern LYKeymap_t key_override[];
 /*  Variables for holding and passing around lynxactioncodes are
  *  generally of type int, the types LYKeymap_t and LYKeymapCodes
  *  are currently only used for the definitions.  That could change. - kw
+ *
+ *  The values in this enum are indexed against the command names in the
+ *  'revmap[]' array in LYKeymap.c
  */
-/* The order of this enum must match the 'revmap[]' array in LYKeymap.c */
 typedef enum {
     LYK_UNKNOWN=0
+  , LYK_COMMAND
   , LYK_1
   , LYK_2
   , LYK_3
@@ -243,5 +246,16 @@ typedef enum {
 #endif
 } LYKeymapCode;
 
+/*
+ * Symbol table for internal commands.
+ */
+typedef struct {
+	LYKeymapCode code;
+	CONST char *name;
+	CONST char *doc;
+} Kcmd;
+
+extern Kcmd * LYKeycodeToKcmd PARAMS((LYKeymapCode code));
+extern Kcmd * LYStringToKcmd PARAMS((CONST char * name));
 
 #endif /* LYKEYMAP_H */
diff --git a/src/LYMail.c b/src/LYMail.c
index 7dd55aef..4a8d7d63 100644
--- a/src/LYMail.c
+++ b/src/LYMail.c
@@ -54,16 +54,15 @@ PRIVATE char *blat_cmd(
 
 #ifdef USE_ALT_BLAT_MAILER
 
-    HTSprintf0(&b_cmd, "%s %s -t %s -s \"%s\" %s %s %s %s %s",
+    HTSprintf0(&b_cmd, "%s %s -t \"%s\" -s \"%s\" %s%s%s%s",
 		mail_cmd,
 		filename,
 		address,
 		subject,
 		system_mail_flags,
-		ccaddr? "-c" : "",
+		ccaddr? " -c \"" : "",
 		ccaddr? ccaddr : "",
-		mail_addr? (mail_addr[0]? "-f" : "") : "",
-		mail_addr? (mail_addr[0]? mail_addr : "") : "");
+		ccaddr? "\"" : "");
 
 #else /* !USE_ALT_BLAT_MAILER */
 
@@ -1682,7 +1681,7 @@ PUBLIC void reply_by_mail ARGS4(
 	    if (HTConfirm(is_preparsed
 	    	? INC_PREPARSED_MSG_PROMPT
 		: INC_ORIG_MSG_PROMPT) == YES) {
-		print_wwwfile_to_fd(fd, !is_preparsed);
+		print_wwwfile_to_fd(fd, (BOOLEAN)!is_preparsed);
 	    }
 	}
 	LYCloseTempFP(fd);	/* Close the tmpfile. */
diff --git a/src/LYMain.c b/src/LYMain.c
index 31179bf2..0f082263 100644
--- a/src/LYMain.c
+++ b/src/LYMain.c
@@ -38,6 +38,8 @@
 #ifdef __DJGPP__
 #include <dos.h>
 #include <dpmi.h>
+#include <io.h>
+#include <sys/stat.h>
 #endif /* __DJGPP__ */
 
 #ifdef __EMX__
@@ -382,7 +384,7 @@ PUBLIC linkstruct links[MAXLINKS];
 PUBLIC histstruct history[MAXHIST];
 PUBLIC int nlinks = 0;		/* number of links in memory */
 PUBLIC int nhist = 0;		/* number of history entries */
-PUBLIC int more = FALSE;	/* is there more text to display? */
+PUBLIC BOOLEAN more = FALSE;	/* is there more text to display? */
 PUBLIC int InfoSecs;	/* Seconds to sleep() for Information messages */
 PUBLIC int MessageSecs; /* Seconds to sleep() for important Messages   */
 PUBLIC int AlertSecs;	/* Seconds to sleep() for HTAlert() messages   */
@@ -420,9 +422,9 @@ PUBLIC char *LYCookieSStrictCheckDomains = NULL; /* check strictly  */
 PUBLIC char *LYCookieSLooseCheckDomains = NULL;  /* check loosely   */
 PUBLIC char *LYCookieSQueryCheckDomains = NULL;  /* check w/a query */
 #ifdef EXP_PERSISTENT_COOKIES
-BOOLEAN persistent_cookies = FALSE; 	/* disabled by default! */
-PUBLIC char *LYCookieFile = NULL;	   /* cookie read file */
-PUBLIC char *LYCookieSaveFile = NULL;	   /* cookie save file */
+BOOLEAN persistent_cookies = FALSE;	/* disabled by default! */
+PUBLIC char *LYCookieFile = NULL;	/* cookie read file */
+PUBLIC char *LYCookieSaveFile = NULL;	/* cookie save file */
 #endif /* EXP_PERSISTENT_COOKIES */
 PUBLIC char *XLoadImageCommand = NULL;	/* Default image viewer for X */
 PUBLIC BOOLEAN LYNoISMAPifUSEMAP = FALSE; /* Omit ISMAP link if MAP present? */
@@ -438,7 +440,7 @@ PUBLIC BOOLEAN LYSeekFragAREAinCur = TRUE;
 PUBLIC BOOLEAN LYStripDotDotURLs = TRUE;	/* Try to fix ../ in some URLs? */
 PUBLIC BOOLEAN LYForceSSLCookiesSecure = FALSE;
 PUBLIC BOOLEAN LYNoCc = FALSE;
-PUBLIC BOOLEAN LYPreparsedSource = FALSE;	/* Show source as preparsed?	 */
+PUBLIC BOOLEAN LYPreparsedSource = FALSE;	/* Show source as preparsed? */
 PUBLIC BOOLEAN LYPrependBaseToSource = TRUE;
 PUBLIC BOOLEAN LYPrependCharsetToSource = TRUE;
 PUBLIC BOOLEAN LYQuitDefaultYes = QUIT_DEFAULT_YES;
@@ -662,6 +664,7 @@ PRIVATE void free_lynx_globals NOARGS
 	FREE(links[i].lname);
     }
     nlinks = 0;
+    HTList_delete(LYcommandList());
 
     return;
 }
@@ -1492,7 +1495,7 @@ PUBLIC int main ARGS2(
 #ifdef USE_PRETTYSRC
     if ( (!Old_DTD) != TRUE ) /* skip if they are already initialized -HV */
 #endif
-    HTSwitchDTD(!Old_DTD);
+    HTSwitchDTD((BOOLEAN)!Old_DTD);
 
     /*
      * Set up the proper character set with the desired
@@ -1657,20 +1660,14 @@ PUBLIC int main ARGS2(
      *	Check the -popup command line toggle. - FM
      */
     if (LYUseDefSelPop == FALSE) {
-	if (LYSelectPopups == TRUE)
-	    LYSelectPopups = FALSE;
-	else
-	    LYSelectPopups = TRUE;
+	LYSelectPopups = !LYSelectPopups;
     }
 
     /*
      *	Check the -show_cursor command line toggle. - FM
      */
     if (LYUseDefShoCur == FALSE) {
-	if (LYShowCursor == TRUE)
-	    LYShowCursor = FALSE;
-	else
-	    LYShowCursor = TRUE;
+	LYShowCursor = !LYShowCursor;
     }
 
     /*
@@ -1715,16 +1712,19 @@ PUBLIC int main ARGS2(
 
 #if defined (__DJGPP__)
     if (watt_debug)
-      dbug_init();
+	dbug_init();
     sock_init();
 
     __system_flags =
-	__system_emulate_chdir	      |	/* handle `cd' internally */
-	__system_handle_null_commands |	/* ignore cmds with no effect */
-	__system_allow_long_cmds      |	/* handle commands > 126 chars	 */
-	__system_use_shell	      |	/* use $SHELL if set */
-	__system_allow_multiple_cmds  |	/* allow `cmd1; cmd2; ...' */
+	__system_emulate_chdir	      | /* handle `cd' internally */
+	__system_handle_null_commands | /* ignore cmds with no effect */
+	__system_allow_long_cmds      | /* handle commands > 126 chars	 */
+	__system_use_shell	      | /* use $SHELL if set */
+	__system_allow_multiple_cmds  | /* allow `cmd1; cmd2; ...' */
 	__system_redirect;		/* redirect internally */
+
+    /* This speeds up stat() tremendously */
+    _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC |_STAT_DIRSIZE;
 #endif  /* __DJGPP__ */
 
     /* trap interrupts */
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index b7eaf53a..916d649a 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -1151,7 +1151,7 @@ gettext("Enctype multipart/form-data not yet supported!  Cannot submit."));
 				 links[curdoc.link].form->name,
 				 links[curdoc.link].form->value,
 				 FALSE,
-				 (real_cmd==LYK_SUBMIT ||
+				 (BOOLEAN)(real_cmd==LYK_SUBMIT ||
 				  real_cmd==LYK_NOCACHE ||
 				  real_cmd==LYK_DOWNLOAD ||
 				  real_cmd==LYK_HEAD));
@@ -1660,6 +1660,30 @@ PRIVATE void handle_LYK_CLEAR_AUTH ARGS2(
     }
 }
 
+PRIVATE int handle_LYK_COMMAND ARGS1(
+    char *,	user_input_buffer)
+{
+    int ch;
+    Kcmd *mp;
+    char *src, *tmp;
+
+    *user_input_buffer = 0;
+    _statusline(": ");
+    if (LYgetstr(user_input_buffer, VISIBLE, MAX_LINE, RECALL_CMD) >= 0) {
+	src = LYSkipBlanks(user_input_buffer);
+	tmp = LYSkipNonBlanks(src);
+	*tmp = 0;
+	ch = ((mp = LYStringToKcmd(src)) != 0) ? mp->code : 0;
+	CTRACE((tfp, "LYK_COMMAND(%s.%s) = %d\n", src, tmp, ch));
+	if (ch == 0) {
+	    return *src ? -1 : 0;
+	}
+	/* FIXME: reuse the rest of the buffer for parameters */
+	return ch;
+    }
+    return 0;
+}
+
 PRIVATE void handle_LYK_COMMENT ARGS4(
     BOOLEAN *,	refresh_screen,
     char **,	owner_address_p,
@@ -4422,7 +4446,7 @@ PRIVATE void handle_LYK_SWITCH_DTD NOARGS
     } /* end if no bypass */
 #endif
     Old_DTD = !Old_DTD;
-    HTSwitchDTD(!Old_DTD);
+    HTSwitchDTD((BOOLEAN) !Old_DTD);
     HTUserMsg(Old_DTD ? USING_DTD_0 : USING_DTD_1);
 #ifdef SOURCE_CACHE
     if (canreparse) {
@@ -5094,18 +5118,10 @@ PUBLIC void handle_LYK_CHDIR NOARGS
 	if (!no_dired_support
 	 && (lynx_edit_mode || (LYIsUIPage(curdoc.address, UIP_DIRED_MENU)))) {
 	    char buf2[LY_MAXPATH];
-	    char* tmp;
 	    char* addr = NULL;
 
-	    strcpy(buf2, p);
 	    Current_Dir(buf2);
-	    tmp = wwwName(buf2);
-
-	    StrAllocCopy(addr, "file://localhost");
-	    StrAllocCat(addr, tmp);
-	    if (tmp != buf2)
-	    /*since wwwName is nop on unix and allocates something on VMS and DOS*/
-		FREE(tmp);
+	    LYLocalFileToURL(&addr, buf2);
 
 	    newdoc.address = addr;
 	    newdoc.isHEAD = FALSE;
@@ -6748,6 +6764,9 @@ new_cmd:  /*
 	    follow_col = -1;
 
 	switch(cmd) {
+	case -1:
+	    HTUserMsg(COMMAND_UNKNOWN);
+	    break;
 	case 0: /* unmapped character */
 	default:
 	    if (curdoc.link >= 0 && curdoc.link < nlinks &&
@@ -6763,10 +6782,11 @@ new_cmd:  /*
 		} else
 #endif
 		    show_main_statusline(links[curdoc.link], FOR_INPUT);
-	    } else if (more)
+	    } else if (more) {
 		HTInfoMsg(MOREHELP);
-	    else
+	    } else {
 		HTInfoMsg(HELP);
+	    }
 	    show_help = TRUE;
 
 	    if (TRACE) {
@@ -6776,6 +6796,10 @@ new_cmd:  /*
 	    }
 	    break;
 
+	case LYK_COMMAND:
+	    cmd = handle_LYK_COMMAND(user_input_buffer);
+	    goto new_cmd;
+
 	case LYK_INTERRUPT:
 	    /*
 	     *	No network transmission to interrupt - 'til we multithread.
@@ -7543,14 +7567,6 @@ PRIVATE void show_main_statusline ARGS2(
 	_statusline(HELP);
     }
 
-#if 0	/* messages now produced in show_formlink_statusline - kw */
-#ifdef INACTIVE_INPUT_STYLE_VH
-    if (textinput_redrawn) {
-	_statusline(gettext("Inactive text input, activate to edit (e.g., press ENTER)"));
-    }
-#endif
-#endif
-
     /* turn off cursor since now it's probably on statusline -HV */
     /* But not if LYShowCursor is on.  -show_cursor may be used as a
      * workaround to avoid putting the cursor in the last position, for
diff --git a/src/LYOptions.c b/src/LYOptions.c
index b126cd0f..9beb653f 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -2164,6 +2164,37 @@ PRIVATE int get_popup_choice_number ARGS1(
 						   " " : ""), \
 			   (choice + 1), value)
 
+PRIVATE void draw_option ARGS7(
+    WINDOW *,		win,
+    int,		entry,
+    int,		width,
+    BOOLEAN,		reverse,
+    int,		num_choices,
+    int,		number,
+    CONST char *,	value)
+{
+    char Cnum[64];
+
+    FormatChoiceNum(Cnum, number, "");
+#ifdef USE_SLANG
+    SLsmg_gotorc(win->top_y + entry, (win->left_x + 2));
+    addstr(Cnum);
+    if (reverse)
+	SLsmg_set_color(2);
+    LYaddnstr(value, width);
+    if (reverse)
+	SLsmg_set_color(0);
+#else
+    wmove(win, entry, 2);
+    waddstr(win, Cnum);
+    if (reverse)
+	wstart_reverse(win);
+    LYpaddstr(win, width, value);
+    if (reverse)
+	wstop_reverse(win);
+#endif /* USE_SLANG */
+}
+
 /*
  *  This function offers the choices for values of an
  *  option via a popup window which functions like
@@ -2185,9 +2216,7 @@ PUBLIC int popup_choice ARGS7(
     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;
     unsigned width = 0;
     CONST char ** Cptr = choices;
@@ -2329,27 +2358,8 @@ PUBLIC int popup_choice ARGS7(
      *	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))) {
-	HTAlert(POPUP_FAILED);
+    if ((form_window = LYstartPopup(top, lx, bottom - top, Lnum + width)) == 0)
 	return(orig_choice);
-    }
-    scrollok(form_window, TRUE);
-#ifdef PDCURSES
-    keypad(form_window, TRUE);
-#endif /* PDCURSES */
-#if defined(NCURSES) || defined(PDCURSES)
-    LYsubwindow(form_window);
-#endif
-#if defined(HAVE_GETBKGD)/* not defined in ncurses 1.8.7 */
-    wbkgd(form_window, getbkgd(stdscr));
-    wbkgdset(form_window, getbkgd(stdscr));
-#endif
-#endif /* USE_SLANG */
 
     /*
      *	Clear the command line and write
@@ -2395,105 +2405,32 @@ redraw:
      */
     for (i = 0; i <= num_choices; i++) {
 	if (i >= window_offset && i - window_offset < length) {
-	    FormatChoiceNum(Cnum, i, "");
-#ifdef USE_SLANG
-	    SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2));
-	    addstr(Cnum);
-	    LYaddnstr(Cptr[i], width);
-#else
-	    wmove(form_window, ((i + 1) - window_offset), 2);
-	    wclrtoeol(form_window);
-	    waddstr(form_window, Cnum);
-	    LYwaddstr(form_window, Cptr[i]);
-#endif /* USE_SLANG */
+	    draw_option (form_window, ((i + 1) - window_offset), width, FALSE,
+			 num_choices, i, Cptr[i]);
 	}
     }
-#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
     LYbox(form_window, FALSE);
-#endif /* VMS */
-    wrefresh(form_window);
-#endif /* USE_SLANG */
     Cptr = NULL;
 
     /*
      *	Loop on user input.
      */
     while (cmd != LYK_ACTIVATE) {
+	int row = ((i + 1) - window_offset);
+
 	/*
 	 *  Unreverse cur choice.
 	 */
 	if (Cptr != NULL) {
-	    FormatChoiceNum(Cnum, i, "");
-#ifdef USE_SLANG
-	    SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
-	    addstr(Cnum);
-	    LYaddnstr(Cptr[i], width);
-#else
-	    wmove(form_window, ((i + 1) - window_offset), 2);
-	    waddstr(form_window, Cnum);
-	    LYwaddstr(form_window, Cptr[i]);
-#endif /* USE_SLANG */
+	    draw_option (form_window, row, width, FALSE,
+			 num_choices, i, Cptr[i]);
 	}
 	Cptr = choices;
 	i = cur_choice;
-	FormatChoiceNum(Cnum, i, "");
-#ifdef USE_SLANG
-	SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
-	addstr(Cnum);
-	SLsmg_set_color(2);
-	LYaddnstr(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);
-#if defined(WIN_EX)	/* 1997/10/18 (Sat) 00:10:51 */
-	wattron(form_window, A_REVERSE);
-#else
-	wstart_reverse(form_window);
-#endif
-	LYwaddstr(form_window, Cptr[i]);
-#if defined(WIN_EX)	/* 1997/10/18 (Sat) 00:10:58 */
-	wattroff(form_window, A_REVERSE);
-#else
-	wstop_reverse(form_window);
-#endif
-	/*
-	 *  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  */
+	row = ((i + 1) - window_offset);
+	draw_option (form_window, row, width, TRUE,
+		     num_choices, i, Cptr[i]);
+	LYstowCursor(form_window, row, 1);
 
 	term_options = FALSE;
 	c = LYgetch_choice();
@@ -2501,7 +2438,7 @@ redraw:
 	    cmd = LYK_QUIT;
 #ifndef USE_SLANG
 	} else if (c == MOUSE_KEY) {
-	    if ((cmd = fancy_mouse(form_window, i + 1 - window_offset, &cur_choice)) < 0)
+	    if ((cmd = fancy_mouse(form_window, row, &cur_choice)) < 0)
 		goto redraw;
 	    if  (cmd == LYK_ACTIVATE)
 		break;
@@ -3122,13 +3059,7 @@ restore_popup_statusline:
 	}
     }
     FREE(popup_status_msg);
-#ifndef USE_SLANG
-    touchwin(stdscr);
-    delwin(form_window);
-#if defined(NCURSES) || defined(PDCURSES)
-    LYsubwindow(0);
-#endif
-#endif /* !USE_SLANG */
+    LYstopPopup();
 
     if (disabled || term_options) {
 	_statusline("");
diff --git a/src/LYStrings.c b/src/LYStrings.c
index 723345d7..b8ed9f48 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -14,6 +14,7 @@
 #include <HTAlert.h>
 #include <HTString.h>
 #include <LYCharUtils.h>
+#include <HTList.h>
 #include <HTParse.h>
 #ifdef USE_MOUSE
 #include <LYMainLoop.h>
@@ -46,13 +47,7 @@ extern BOOL HTPassHighCtrlRaw;
 /*Allowing the user to press tab when entering URL to get the closest
   match in the closet*/
 #define LYClosetSize 100
-static char* LYCloset[LYClosetSize]; /* Closet with LYClosetSize shelves */
-static int LYClosetTop = 0;		/*Points to the next empty shelf */
-
-PRIVATE char *LYFindInCloset PARAMS((
-	char*		base));
-PRIVATE void LYAddToCloset PARAMS((
-	char*		str));
+static HTList *URL_edit_history;
 
 /* If you want to add mouse support for some new platform, it's fairly
 ** simple to do.  Once you've determined the X and Y coordinates of
@@ -259,6 +254,60 @@ PUBLIC int fancy_mouse ARGS3(
     return cmd;
 }
 
+/*
+ * Remove the oldest item in the closet
+ */
+PRIVATE void LYRemoveFromCloset NOARGS
+{
+    char *data = HTList_removeFirstObject(URL_edit_history);
+
+    if (data != 0)
+	FREE(data);
+}
+
+PUBLIC void LYOpenCloset NOARGS
+{
+    URL_edit_history = HTList_new();
+}
+
+PUBLIC void LYCloseCloset NOARGS
+{
+    while (!HTList_isEmpty(URL_edit_history) ) {
+	LYRemoveFromCloset();
+    }
+    HTList_delete(URL_edit_history);	/* should already be empty */
+}
+
+/*
+ * Strategy:  We begin at the top and search downwards.  We return the first
+ * match, i.e., the newest since we search from the top.  This should be made
+ * more intelligent, but works for now.
+ */
+PRIVATE char * LYFindInCloset ARGS1(char*, base)
+{
+    HTList *list = URL_edit_history;
+    char *data;
+    unsigned len = strlen(base);
+
+    while (!HTList_isEmpty(list)) {
+	data = HTList_nextObject(list);
+	if (!strncmp(base, data, len))
+	    return(data);
+    }
+
+    return(0);
+}
+
+PRIVATE void LYAddToCloset ARGS1(char*, str)
+{
+    char *data = NULL;
+
+    StrAllocCopy(data, str);
+    HTList_addObject(URL_edit_history, data);
+    while (HTList_count(URL_edit_history) > LYClosetSize)
+	LYRemoveFromCloset();
+}
+
 
 PRIVATE int XYdist ARGS5(
     int,	x1,
@@ -645,7 +694,6 @@ PUBLIC int LYmbcsstrlen ARGS3(
 #endif /* HAVE_KEYPAD */
 #endif /* !defined(GetChar) */
 
-#if defined(NCURSES) || defined(PDCURSES)
 /*
  * Workaround a bug in ncurses order-of-refresh by setting a pointer to
  * the topmost window that should be displayed.
@@ -653,14 +701,24 @@ PUBLIC int LYmbcsstrlen ARGS3(
  * FIXME: the associated call on 'keypad()' is not needed for Unix, but
  * something in the OS/2 EMX port requires it.
  */
+#ifndef USE_SLANG
 PRIVATE WINDOW *my_subwindow;
 
 PUBLIC void LYsubwindow ARGS1(WINDOW *, param)
 {
-#if !defined(WIN_EX)
-    if ((my_subwindow = param) != 0)
+    if ((my_subwindow = param) != 0) {
+#if defined(NCURSES) || defined(PDCURSES)
 	keypad(param, TRUE);
+#if defined(HAVE_GETBKGD) /* not defined in ncurses 1.8.7 */
+	wbkgd(my_subwindow, getbkgd(stdscr));
+	wbkgdset(my_subwindow, getbkgd(stdscr));
+#endif
 #endif
+	scrollok(my_subwindow, TRUE);
+    } else {
+	touchwin(stdscr);
+	delwin(my_subwindow);
+    }
 }
 #endif
 
@@ -3218,20 +3276,291 @@ PUBLIC void LYRefreshEdit ARGS1(
     refresh();
 }
 
+PRIVATE void reinsertEdit ARGS2(
+    EditFieldData *,	edit,
+    char *,		result)
+{
+    if (result != 0) {
+	LYEdit1(edit, '\0', LYE_ERASE, FALSE);
+	while (*result != '\0') {
+	    LYLineEdit(edit, (int)(*result), FALSE);
+	    result++;
+	}
+    }
+}
+
+PRIVATE HTList *whichRecall ARGS1(
+    RecallType,		recall)
+{
+    switch (recall) {
+    case RECALL_CMD:
+	return LYcommandList();
+    default:
+	return URL_edit_history;
+    }
+}
+
+PRIVATE int caselessCmpList ARGS2(
+    CONST void *,	a,
+    CONST void *,	b)
+{
+    return strcasecomp(*(CONST char *CONST *)a, *(CONST char *CONST *)b);
+}
+
+PRIVATE int normalCmpList ARGS2(
+    CONST void *,	a,
+    CONST void *,	b)
+{
+    return strcmp(*(CONST char *CONST *)a, *(CONST char *CONST *)b);
+}
+
+PRIVATE char **sortedList ARGS2(
+    HTList *,	list,
+    BOOL,	ignorecase)
+{
+    unsigned count = HTList_count(list);
+    unsigned n = 0;
+    char **result = calloc(count + 1, sizeof(char *));
+
+    if (result == 0) 
+	outofmem(__FILE__, "sortedList");
+
+    while (!HTList_isEmpty(list))
+	result[n++] = HTList_nextObject(list);
+    if (count > 1) {
+	qsort((char *)result, count, sizeof(*result),
+	      ignorecase ? caselessCmpList : normalCmpList);
+    }
+
+    return result;
+}
+
+PRIVATE int lengthOfList ARGS1(
+    char **,	list)
+{
+    int result = 0;
+
+    while (*list++ != 0)
+	result++;
+    return result;
+}
+
+PRIVATE int widestInList ARGS1(
+    char **,	list)
+{
+    int result = 0;
+    int check;
+
+    while (*list != 0) {
+	check = strlen(*list++);
+	if (check > result)
+	    result = check;
+    }
+    return result;
+}
+
+PRIVATE void draw_option ARGS5(
+	WINDOW *,	win,
+	int,		entry,
+	int,		width,
+	BOOL,		reversed,
+	char *,		value)
+{
+#ifdef USE_SLANG
+    if (reversed)
+	SLsmg_gotorc((win->top_y + entry), win->left_x + 2);
+    SLsmg_gotorc(win->top_y + entry, win->left_x + 2);
+    SLsmg_write_nstring(value, win->width);
+    if (reversed)
+	SLsmg_set_color(0);
+#else
+    wmove(win, entry, 2);
+    if (reversed)
+	wstart_reverse(win);
+    LYpaddstr(win, width, value);
+    if (reversed)
+	wstop_reverse(win);
+#endif /* USE_SLANG */
+}
+
+PRIVATE int LYgetMenuKeycode ARGS3(
+    WINDOW *,	win,
+    int,	row,
+    int *,	cur_selectionp)
+{
+    int cmd;
+    int c = LYgetch_choice();
+
+    if (c == 7) {		/* Control-C or Control-G */
+	cmd = LYK_QUIT;
+#ifndef USE_SLANG
+    } else if (c == MOUSE_KEY) {
+	cmd = fancy_mouse(win, row, cur_selectionp);
+#endif
+    } else {
+	cmd = LKC_TO_LAC(keymap,c);
+    }
+#ifdef VMS
+    if (HadVMSInterrupt) {
+	HadVMSInterrupt = FALSE;
+	cmd = LYK_QUIT;
+    }
+#endif /* VMS */
+    return cmd;
+}
+
+PRIVATE void completeFromPopup ARGS2(
+    EditFieldData *,	edit,
+    char **,		data)
+{
+    WINDOW *win;
+    int top;
+    int lx = 2;
+    int width = widestInList(data);
+    int num_options = lengthOfList(data);
+    int height = num_options + 2;
+    int i, row, length;
+    int cmd = LYK_UNKNOWN;
+    int window_offset = 0;
+    int cur_selection = 0;
+    int old_selection = -1;
+    int old_y, old_x;
+
+#ifdef USE_SLANG
+    old_y = SLsmg_get_row();
+    old_x = SLsmg_get_column();
+#else
+    getyx(stdscr, old_y, old_x);
+#endif
+
+    if (height > LYlines - 2)
+    	height = LYlines - 2;
+    length = height - 2;
+    top = LYlines - height - 1;
+
+    while (cur_selection < num_options
+     && strcasecomp(data[cur_selection], edit->buffer) < 0)
+	cur_selection++;
+    if (cur_selection + 1 - window_offset >= length) {
+	window_offset = cur_selection + 1 - length;
+    }
+
+    /* construct a popup window */
+    if ((win = LYstartPopup(top, lx, height, width)) != 0) {
+	/* handle events in the popup window */
+redraw:
+	LYbox(win, FALSE);
+	for (i = 0; i < num_options; i++) {
+	    row = ((i + 1) - window_offset);
+	    if (row >= 1 && row <= length)
+		draw_option(win, row, width, FALSE, data[i]);
+	}
+	old_selection = -1;
+
+	while (cmd != LYK_ACTIVATE) {
+
+	    if (old_selection >= 0
+	     && old_selection != cur_selection) {
+		row = ((old_selection + 1) - window_offset);
+		draw_option(win, row, width, FALSE, data[old_selection]);
+	    }
+	    old_selection = cur_selection;
+
+	    row = ((cur_selection + 1) - window_offset);
+	    draw_option(win, row, width, TRUE, data[cur_selection]);
+	    LYstowCursor(win, row, 1);
+	    cmd = LYgetMenuKeycode(win, row, &cur_selection);
+
+	    /* FIXME: this whole switch statement should be integrated with
+	     * the redundant logic in LYForms.c and LYOptions.c (there's no
+	     * point in having multiple copies of code that scroll through
+	     * a popup menu).
+	     */
+	    switch (cmd) {
+	    case -1:
+		goto redraw;
+
+	    case LYK_HOME:
+		cur_selection = 0;
+		if (window_offset > 0) {
+		    window_offset = 0;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_END:
+		cur_selection = num_options - 1;
+		if (window_offset != (num_options - length)) {
+		    window_offset = (num_options - length);
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_PREV_LINK:
+	    case LYK_LPOS_PREV_LINK:
+	    case LYK_FASTBACKW_LINK:
+	    case LYK_UP_LINK:
+		if (cur_selection > 0)
+		    cur_selection--;
+
+		/*
+		 *  Scroll the window up if necessary.
+		 */
+		if ((cur_selection - window_offset) < 0) {
+		    window_offset--;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_NEXT_LINK:
+	    case LYK_LPOS_NEXT_LINK:
+	    case LYK_FASTFORW_LINK:
+	    case LYK_DOWN_LINK:
+		if (cur_selection < num_options - 1)
+		    cur_selection++;
+		/*
+		 *  Scroll the window down if necessary
+		 */
+		if ((cur_selection - window_offset) >= length) {
+		    window_offset++;
+		    goto redraw;
+		}
+		break;
+
+	    case LYK_QUIT:
+	    case LYK_ABORT:
+	    case LYK_PREV_DOC:
+		cur_selection = -1;
+		cmd = LYK_ACTIVATE; /* to exit */
+		break;
+	    }
+	}
+	LYstopPopup();
+    }
+    if (cur_selection >= 0)
+	reinsertEdit(edit, data[cur_selection]);
+
+#ifdef USE_SLANG
+    SLsmg_gotorc(old_y, old_x);
+#else
+    wmove(stdscr, old_y, old_x);
+#endif
+}
+
 #define CurModif MyEdit.current_modifiers
 
 PUBLIC int LYgetstr ARGS4(
 	char *,		inputline,
 	int,		hidden,
 	size_t,		bufsize,
-	int,		recall)
+	RecallType,	recall)
 {
     int x, y, MaxStringSize;
     int ch;
-    int xlec;
+    int xlec = -2;
+    int last_xlec = -1;
     int last_xlkc = -1;
     EditFieldData MyEdit;
-    char *res;
 #ifdef SUPPORT_MULTIBYTE_EDIT
     BOOL refresh_mb = TRUE;
 #endif /* SUPPORT_MULTIBYTE_EDIT */
@@ -3278,7 +3607,7 @@ again:
 	    ch = 7;
 	}
 
-	if (recall && (ch == UPARROW || ch == DNARROW)) {
+	if (recall != NORECALL && (ch == UPARROW || ch == DNARROW)) {
 	    LYstrncpy(inputline, MyEdit.buffer, (int)bufsize);
 	    LYAddToCloset(MyEdit.buffer);
 	    return(ch);
@@ -3294,6 +3623,7 @@ again:
 	if (LKC_TO_LAC(keymap,ch) == LYK_REFRESH)
 	    goto again;
 #endif
+	last_xlec = xlec;
 	xlec = EditBinding(ch);
 	if ((xlec & LYE_DF) && !(xlec & LYE_FORM_LAC)) {
 	    last_xlkc = ch;
@@ -3315,18 +3645,15 @@ again:
 	    CurModif |= LKC_MOD2;
 	    break;
 	case LYE_TAB:
-	    ch = '\t';
-	    /* This used to fall through to the next case before
-	     tab completion was introduced */
-	    res = LYFindInCloset(MyEdit.buffer);
-	    if (res != 0) {
-		LYEdit1(&MyEdit, '\0', LYE_ERASE, FALSE);
-		while (*res != '\0') {
-		    LYLineEdit(&MyEdit, (int)(*res), FALSE);
-		    res++;
+	    if (xlec == last_xlec) {
+		HTList *list = whichRecall(recall);
+		if (!HTList_isEmpty(list)) {
+		    char **data = sortedList(list, recall == RECALL_CMD);
+		    completeFromPopup(&MyEdit, data);
+		    FREE(data);
 		}
 	    } else {
-		ch = '\0';
+		reinsertEdit(&MyEdit, LYFindInCloset(MyEdit.buffer));
 	    }
 	    break;
 
@@ -3554,58 +3881,6 @@ PUBLIC char * LYno_attr_char_case_strstr ARGS2(
     return(NULL);
 }
 
-PUBLIC void LYOpenCloset NOARGS
-{
-    /* We initialize the list-looka-like, i.e., the Closet */
-    int i = 0;
-    while(i < LYClosetSize){
-	LYCloset[i] = NULL;
-	i = i + 1;
-    }
-    LYClosetTop = 0;
-}
-
-PUBLIC void LYCloseCloset NOARGS
-{
-    int i = 0;
-
-    /* Clean up the list-looka-like, i.e., the Closet */
-    while (i < LYClosetSize){
-	FREE(LYCloset[i]);
-	i = i + 1;
-    }
-}
-
-/*
- * Strategy:  We begin at the top and search downwards.  We return the first
- * match, i.e., the newest since we search from the top.  This should be made
- * more intelligent, but works for now.
- */
-PRIVATE char * LYFindInCloset ARGS1(char*, base)
-{
-    int shelf;
-    unsigned len = strlen(base);
-
-    shelf = (LYClosetTop - 1 + LYClosetSize) % LYClosetSize;
-
-    while (LYCloset[shelf] != NULL){
-	if (!strncmp(base, LYCloset[shelf], len)) {
-	    return(LYCloset[shelf]);
-	}
-	shelf = (shelf - 1 + LYClosetSize) % LYClosetSize;
-    }
-    return(0);
-}
-
-PRIVATE void LYAddToCloset ARGS1(char*, str)
-{
-    LYCloset[LYClosetTop] = NULL;
-    StrAllocCopy(LYCloset[LYClosetTop], str);
-
-    LYClosetTop = (LYClosetTop + 1) % LYClosetSize;
-    FREE(LYCloset[LYClosetTop]);
-}
-
 /*
  *  LYno_attr_char_strstr will find the first occurrence of the
  *  string pointed to by tarptr in the string pointed to by chptr.
diff --git a/src/LYStrings.h b/src/LYStrings.h
index 32aeed8c..1d2f9131 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -3,6 +3,12 @@
 
 #include <LYCurses.h>
 
+typedef enum {
+    NORECALL = 0
+    , RECALL
+    , RECALL_CMD
+} RecallType;
+
 /*  UPPER8(ch1,ch2) is an extension of (TOUPPER(ch1) - TOUPPER(ch2))  */
 extern int UPPER8  PARAMS((
 	int		ch1,
@@ -26,7 +32,7 @@ extern int LYgetstr PARAMS((
 	char *		inputline,
 	int		hidden,
 	size_t		bufsize,
-	int		recall));
+	RecallType	recall));
 extern char *LYstrsep PARAMS((
 	char **		stringp,
 	CONST char *	delim));
@@ -156,8 +162,6 @@ extern void base64_encode PARAMS((char * dest, char * src, int len));
 
 #define VISIBLE  0
 #define HIDDEN   1
-#define NORECALL 0
-#define RECALL   1
 
 #ifdef EXP_ALT_BINDINGS
 /*  Enable code implementing additional, mostly emacs-like, line-editing
diff --git a/src/LYStyle.c b/src/LYStyle.c
index 517e1832..42c98a67 100644
--- a/src/LYStyle.c
+++ b/src/LYStyle.c
@@ -1,6 +1,6 @@
 /* character level styles for Lynx
  * (c) 1996 Rob Partington -- donated to the Lyncei (if they want it :-)
- * @Id: LYStyle.c 1.36 Fri, 23 Jun 2000 08:15:08 -0700 dickey @
+ * @Id: LYStyle.c 1.37 Sun, 16 Jul 2000 20:16:13 -0700 dickey @
  */
 #include <HTUtils.h>
 #include <HTML.h>
@@ -25,9 +25,11 @@
 
 #ifdef USE_COLOR_STYLE
 
+PRIVATE void style_initialiseHashTable NOPARAMS;
+
 /* stack of attributes during page rendering */
 PUBLIC int last_styles[128];
-PUBLIC int last_colorattr_ptr=0;
+PUBLIC int last_colorattr_ptr = 0;
 
 PUBLIC bucket hashStyles[CSHASHSIZE];
 PUBLIC bucket special_bucket =
@@ -63,7 +65,6 @@ static char *Mono_Strings[7] =
 
 /* Remember the hash codes for common elements */
 PUBLIC int	s_alink  = NOSTYLE, s_a     = NOSTYLE, s_status = NOSTYLE,
-		s_label  = NOSTYLE, s_value = NOSTYLE, s_high   = NOSTYLE,
 		s_normal = NOSTYLE, s_alert = NOSTYLE, s_title  = NOSTYLE,
 #ifdef USE_SCROLLBAR
 		s_sb_bar = NOSTYLE, s_sb_bg = NOSTYLE,
@@ -80,7 +81,10 @@ PRIVATE unsigned char our_pairs[2][MAX_COLOR][MAX_COLOR];
 PRIVATE void parse_attributes ARGS5(char*,mono,char*,fg,char*,bg,int,style,char*,element)
 {
     int i;
-    int mA = 0, fA = default_fg, bA = default_bg, cA = A_NORMAL;
+    int mA = 0;
+    short fA = default_fg;
+    short bA = default_bg;
+    int cA = A_NORMAL;
     int newstyle = hash_code(element);
 
     CTRACE((tfp, "CSS(PA):style d=%d / h=%d, e=%s\n", style, newstyle,element));
@@ -329,43 +333,54 @@ PRIVATE void free_colorstylestuff NOARGS
  */
 PRIVATE void initialise_default_stylesheet NOARGS
 {
+    static CONST char *table[] = {
+	"a:bold:green",
+	"alert:bold:yellow:red",
+	"alink:reverse:yellow:black",
+	"label:normal:magenta",
+	"status:reverse:yellow:blue",
+	"title:normal:magenta",
+	"whereis:reverse+underline:magenta:cyan"
+    };
+    unsigned n;
+    char temp[80];
+    for (n = 0; n < TABLESIZE(table); n++) {
+	parse_style(strcpy(temp, table[n]));
+    }
 }
 
 /* Set all the buckets in the hash table to be empty */
-PUBLIC void style_initialiseHashTable NOARGS
+PRIVATE void style_initialiseHashTable NOARGS
 {
-	int i;
-	static int firsttime = 1;
+    int i;
+    static int firsttime = 1;
 
-	for (i = 0; i <CSHASHSIZE; i++)
-	{
-	    if (firsttime)
-		hashStyles[i].name = NULL;
-	    else
-		FREE(hashStyles[i].name);
-	    hashStyles[i].color = -1;
-	    hashStyles[i].cattr = -1;
-	    hashStyles[i].mono  = -1;
-	}
-	if (firsttime) {
-	    firsttime = 0;
+    for (i = 0; i <CSHASHSIZE; i++)
+    {
+	if (firsttime)
+	    hashStyles[i].name = NULL;
+	else
+	    FREE(hashStyles[i].name);
+	hashStyles[i].color = 0;
+	hashStyles[i].cattr = 0;
+	hashStyles[i].mono  = 0;
+    }
+    if (firsttime) {
+	firsttime = 0;
 #ifdef LY_FIND_LEAKS
-	    atexit(free_colorstylestuff);
+	atexit(free_colorstylestuff);
 #endif
-	}
-	s_high   = hash_code("high");
-	s_alink  = hash_code("alink");
-	s_value  = hash_code("value");
-	s_label  = hash_code("label");
-	s_a      = hash_code("a");
-	s_status = hash_code("status");
-	s_alert  = hash_code("alert");
-	s_title  = hash_code("title");
+    }
+    s_alink  = hash_code("alink");
+    s_a      = hash_code("a");
+    s_status = hash_code("status");
+    s_alert  = hash_code("alert");
+    s_title  = hash_code("title");
 #ifdef USE_SCROLLBAR
-	s_sb_bar = hash_code("scroll.bar");
-	s_sb_bg  = hash_code("scroll.back");
-	s_sb_aa  = hash_code("scroll.arrow");
-	s_sb_naa = hash_code("scroll.noarrow");
+    s_sb_bar = hash_code("scroll.bar");
+    s_sb_bg  = hash_code("scroll.back");
+    s_sb_aa  = hash_code("scroll.arrow");
+    s_sb_naa = hash_code("scroll.noarrow");
 #endif
 }
 
@@ -377,33 +392,35 @@ HTList *lss_styles = NULL;
 
 PUBLIC void parse_userstyles NOARGS
 {
-	char *name;
-	HTList *cur = lss_styles;
-	colorPairs = 0;
-	style_initialiseHashTable();
+    char *name;
+    HTList *cur = lss_styles;
 
-	/* set our styles to be the same as vanilla-curses-lynx */
-	initialise_default_stylesheet();
+    colorPairs = 0;
+    style_initialiseHashTable();
 
-	while ((name = HTList_nextObject(cur)) != NULL)
-	{
-		CTRACE((tfp, "LSS:%s\n", name ? name : "!?! empty !?!"));
-		if (name != NULL)
-		    parse_style(name);
+    /* set our styles to be the same as vanilla-curses-lynx */
+    if (HTList_isEmpty(cur)) {
+	initialise_default_stylesheet();
+    } else {
+	while ((name = HTList_nextObject(cur)) != NULL) {
+	    CTRACE((tfp, "LSS:%s\n", name ? name : "!?! empty !?!"));
+	    if (name != NULL)
+		parse_style(name);
 	}
+    }
 }
 
 
 /* Add a STYLE: option line to our list */
-PUBLIC void HStyle_addStyle ARGS1(char*,buffer)
+PRIVATE void HStyle_addStyle ARGS1(char*,buffer)
 {
-	char *name = NULL;
-	StrAllocCopy(name, buffer);
-	if (lss_styles == NULL)
-		lss_styles = HTList_new();
-	strtolower(name);
-	CTRACE((tfp, "READCSS:%s\n", name ? name : "!?! empty !?!"));
-	HTList_addObject (lss_styles, name);
+    char *name = NULL;
+    StrAllocCopy(name, buffer);
+    if (lss_styles == NULL)
+	lss_styles = HTList_new();
+    strtolower(name);
+    CTRACE((tfp, "READCSS:%s\n", name ? name : "!?! empty !?!"));
+    HTList_addObject (lss_styles, name);
 }
 
 PUBLIC void style_deleteStyleList NOARGS
@@ -415,18 +432,6 @@ PUBLIC void style_deleteStyleList NOARGS
     lss_styles = NULL;
 }
 
-char* default_stylesheet[] = {
-	"a:bold", "em:bold", "strong:bold", "b:bold", "i:bold",
-	"alink:reverse", "status:reverse", NULL
-};
-
-PUBLIC void style_defaultStyleSheet NOARGS
-{
-	int i;
-	for (i = 0; default_stylesheet[i]; i++)
-		HStyle_addStyle(default_stylesheet[i]);
-}
-
 PRIVATE int style_readFromFileREC ARGS2(char*, file, int, toplevel)
 {
     FILE *fh;
@@ -440,13 +445,13 @@ PRIVATE int style_readFromFileREC ARGS2(char*, file, int, toplevel)
     if (!fh)
     {
 	/* this should probably be an alert or something */
-	CTRACE((tfp, "CSS:Can't open style file '%s', using defaults\n", file));
+	CTRACE((tfp, "CSS:Can't open style file %s, using defaults\n", file));
 	return -1;
     }
 
     if (toplevel) {
-      style_initialiseHashTable();
-      style_deleteStyleList();
+	style_initialiseHashTable();
+	style_deleteStyleList();
     }
 
     while (LYSafeGets(&buffer, fh) != NULL)
@@ -459,10 +464,6 @@ PRIVATE int style_readFromFileREC ARGS2(char*, file, int, toplevel)
 	else if (buffer[0] != '#' && (len = strlen(buffer)) > 0)
 	    HStyle_addStyle(buffer);
     }
-    /* the default styles are added after the user styles in order
-    ** that they come before them  <grin>  RP
-    */
-    /*	style_defaultStyleSheet(); */
 
     fclose (fh);
     if (toplevel && LYCursesON)
diff --git a/src/LYStyle.h b/src/LYStyle.h
index 6df504cf..253ec986 100644
--- a/src/LYStyle.h
+++ b/src/LYStyle.h
@@ -16,12 +16,8 @@ extern HTCharStyle displayStyles[DSTYLE_ELEMENTS];
 extern int lynx_has_color;
 
 /* Set all the buckets in the hash table to be empty */
-extern void style_initialiseHashTable NOPARAMS;
-
 extern void parse_userstyles NOPARAMS;
 
-extern void HStyle_addStyle PARAMS((char* buffer));
-
 extern void style_deleteStyleList NOPARAMS;
 
 extern void style_defaultStyleSheet NOPARAMS;
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 5a298057..896ff407 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -4385,7 +4385,7 @@ PUBLIC void LYConvertToURL ARGS2(
 #endif /* DOSPATH */
 
     *AllocatedString = NULL;  /* so StrAllocCopy doesn't free it */
-    StrAllocCopy(*AllocatedString,"file://localhost");
+    StrAllocCopy(*AllocatedString, "file://localhost");
 
     if (*old_string != '/') {
 	char *fragment = NULL;
@@ -4551,7 +4551,7 @@ have_VMS_URL:
 	    chk = GetFullPathNameA(old_string, MAX_PATH + 1,
 			fullpath, &filepart);
 	    if (chk != 0) {
-		StrAllocCopy(temp, HTDOS_wwwName(fullpath));
+		StrAllocCopy(temp, wwwName(fullpath));
 		StrAllocCat(*AllocatedString, temp);
 		FREE(temp);
 		CTRACE((tfp, "Converted '%s' to '%s'\n",
@@ -4607,11 +4607,7 @@ have_VMS_URL:
 	     */
 #if defined (DOSPATH) || defined (__EMX__) || defined (WIN_EX)
 	    if (old_string[1] != ':' && old_string[1] != '|') {
-#ifdef DOSPATH
-		StrAllocCopy(temp, HTDOS_wwwName(curdir));
-#else
 		StrAllocCopy(temp, wwwName(curdir));
-#endif
 		LYAddHtmlSep(&temp);
 		LYstrncpy(curdir, temp, (sizeof(curdir) - 1));
 		StrAllocCat(temp, old_string);
@@ -7184,6 +7180,8 @@ PUBLIC void LYLocalFileToURL ARGS2(
     if (!LYIsHtmlSep(*leaf))
 	LYAddHtmlSep(target);
     StrAllocCat(*target, leaf);
+    if (leaf != source)
+    	FREE(leaf);
 }
 
 #ifdef NOTDEFINED