about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorThomas E. Dickey <dickey@invisible-island.net>2008-09-07 23:00:47 -0400
committerThomas E. Dickey <dickey@invisible-island.net>2008-09-07 23:00:47 -0400
commit67b10f416009d4334c0a494a46235d284675fa2d (patch)
tree0518bc3cfb3858b18de7b76d6634262249447862
parentb027e6c551e944c3de2c6a41958afbdfcbb9e942 (diff)
downloadlynx-snapshots-67b10f416009d4334c0a494a46235d284675fa2d.tar.gz
snapshot of project "lynx", label v2-8-7dev_9j
-rw-r--r--CHANGES3
-rw-r--r--src/GridText.c186
-rw-r--r--src/HTForms.h12
-rw-r--r--src/LYCurses.c48
-rw-r--r--src/LYEditmap.c19
-rw-r--r--src/LYMainLoop.c75
-rw-r--r--src/LYStrings.c14
-rw-r--r--src/LYStrings.h4
-rw-r--r--src/LYUtils.c14
9 files changed, 126 insertions, 249 deletions
diff --git a/CHANGES b/CHANGES
index 26ac5d99..b75c4a0d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,9 +1,10 @@
--- $LynxId: CHANGES,v 1.295 2008/09/05 00:30:55 tom Exp $
+-- $LynxId: CHANGES,v 1.296 2008/09/07 17:00:23 tom Exp $
 ===============================================================================
 Changes since Lynx 2.8 release
 ===============================================================================
 
 2008-0?-?? (2.8.7dev.10)
+* modify external editing of TEXTAREA to not do tab-conversion -TD
 * modify LYhighlight() to limit display of multicolumn characters -TD
 * rewrite LYRefreshEdit(), to display multibyte/multicolumn characters properly
   when using wide-character curses -TD
diff --git a/src/GridText.c b/src/GridText.c
index 9d7ec48e..0acce669 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: GridText.c,v 1.151 2008/09/06 14:40:45 tom Exp $
+ * $LynxId: GridText.c,v 1.153 2008/09/07 22:38:54 tom Exp $
  *
  *		Character grid hypertext object
  *		===============================
@@ -11995,102 +11995,6 @@ BOOL HText_AreDifferent(HTParentAnchor *anchor,
     (LYtrimInputFields ? isspace(c) : ((c) == '\r' || (c) == '\n'))
 
 /*
- * Cleanup new lines coming into a TEXTAREA from an external editor, or a
- * file, such that they are in a suitable format for TEXTAREA rendering,
- * display, and manipulation.  That means trimming off trailing whitespace
- * from the line, expanding TABS into SPACES, and substituting a printable
- * character for control chars, and the like.
- *
- * --KED 02/24/99
- */
-static void cleanup_line_for_textarea(char *line,
-				      int len)
-{
-    char tbuf[MAX_LINE];
-
-    char *cp;
-    char *p;
-    char *s;
-    int i;
-    int n;
-
-    /*
-     * Whack off trailing whitespace from the line.
-     */
-    for (i = len, p = line + (len - 1); i != 0; p--, i--) {
-	if (CanTrimTextArea(UCH(*p)))
-	    *p = '\0';
-	else
-	    break;
-    }
-
-    if (strlen(line) != 0) {
-	/*
-	 * Expand any tab's, since they won't render properly in a TEXTAREA.
-	 *
-	 * [Is that "by spec", or just a "lynxism"?  As may be, it seems that
-	 * such chars may cause other problems, too ...  with cursor movement,
-	 * submit'ing, etc.  Probably needs looking into more deeply.]
-	 */
-	p = line;
-	s = tbuf;
-
-	while (*p) {
-	    if ((cp = strchr(p, '\t')) != 0) {
-		i = cp - p;
-		s = (strncpy(s, p, i)) + i;
-		n = TABSTOP - (i % TABSTOP);
-		s = (strncpy(s, SPACES, n)) + n;
-		p += (i + 1);
-
-	    } else {
-
-		strcpy(s, p);
-		break;
-	    }
-	}
-
-	/*
-	 * Replace control chars with something printable.  Note that char
-	 * substitution above 0x7f is dependent on the charset being used,
-	 * and then only applies to the contiguous run of char values that
-	 * are between 0x80, and the 1st real high-order-bit-set character,
-	 * as specified by the charset.  In general (ie, for many character
-	 * sets), that usually means the so-called "C1 control chars" that
-	 * range from 0x80 thru 0x9f.  For EBCDIC machines, we only trim the
-	 * (control) chars below a space (x'40').
-	 *
-	 * The assumption in all this is that the charset used in the editor,
-	 * is compatible with the charset specified in lynx.
-	 *
-	 * [At some point in time, when/if lynx ever supports multibyte chars
-	 * internally (eg, UCS-2, UCS-4, UTF-16, etc), this kind of thing may
-	 * well cause problems.  But then, supporting such char sets will
-	 * require massive changes in (most) all parts of the lynx code, so
-	 * until then, we do the rational thing with char values that would
-	 * otherwise foul the display, if left alone.  If you're implementing
-	 * multibyte character set support, consider yourself to have been
-	 * warned.]
-	 */
-	for (p = line, s = tbuf; *s != '\0'; p++, s++) {
-#ifndef EBCDIC
-	    *p = ((UCH(*s) < UCH(' ')) ||
-		  (UCH(*s) == UCH('\177')) ||
-		  ((UCH(*s) > UCH('\177')) &&
-		   (UCH(*s) <
-		    UCH(LYlowest_eightbit[current_char_set]))))
-		? (char) SPLAT : *s;
-#else
-	    *p = (UCH(*s) < UCH(' ')) ? SPLAT : *s;
-#endif
-	}
-	*p = '\0';
-    }
-
-    return;
-}
-
-/*
  * Re-render the text of a tagged ("[123]") HTLine (arg1), with the tag
  * number incremented by some value (arg5).  The re-rendered string may
  * be allowed to expand in the event of a tag width change (eg, 99 -> 100)
@@ -12630,6 +12534,28 @@ static void update_subsequent_anchors(int newlines,
 }
 
 /*
+ * Check if the given anchor is a TEXTAREA belonging to the given form.
+ *
+ * KED's note -
+ * [Finding the TEXTAREA we're actually *in* with these attributes isn't
+ * foolproof.  The form number isn't unique to a given TEXTAREA, and there
+ * *could* be TEXTAREA's with the same "name".  If that should ever be true,
+ * we'll actually get the data from the *1st* TEXTAREA in the page that
+ * matches.  We should probably assign a unique id to each TEXTAREA in a page,
+ * and match on that, to avoid this (potential) problem.
+ *
+ * Since the odds of "false matches" *actually* happening in real life seem
+ * rather small though, we'll hold off doing this, for a rainy day ...]
+ */
+static BOOLEAN IsFormsTextarea(FormInfo * form, TextAnchor *anchor_ptr)
+{
+    return ((anchor_ptr->link_type == INPUT_ANCHOR) &&
+	    (anchor_ptr->input_field->type == F_TEXTAREA_TYPE) &&
+	    (anchor_ptr->input_field->number == form->number) &&
+	    !strcmp(anchor_ptr->input_field->name, form->name));
+}
+
+/*
  * Transfer the initial contents of a TEXTAREA to a temp file, invoke the
  * user's editor on that file, then transfer the contents of the resultant
  * edited file back into the TEXTAREA (expanding the size of the area, if
@@ -12663,8 +12589,6 @@ int HText_ExtEditForm(LinkInfo * form_link)
     int line_cnt = 1;
 
     FormInfo *form = form_link->l_form;
-    char *areaname = form->name;
-    int form_num = form->number;
 
     HTLine *htline = NULL;
 
@@ -12690,27 +12614,12 @@ int HText_ExtEditForm(LinkInfo * form_link)
     /*
      * Begin at the beginning, to find 1st anchor in the TEXTAREA, then
      * write all of its lines (anchors) out to the edit temp file.
-     *
-     * [Finding the TEXTAREA we're actually *in* with these attributes
-     * isn't foolproof.  The form_num isn't unique to a given TEXTAREA,
-     * and there *could* be TEXTAREA's with the same "name".  If that
-     * should ever be true, we'll actually get the data from the *1st*
-     * TEXTAREA in the page that matches.  We should probably assign
-     * a unique id to each TEXTAREA in a page, and match on that, to
-     * avoid this (potential) problem.
-     *
-     * Since the odds of "false matches" *actually* happening in real
-     * life seem rather small though, we'll hold off doing this, for a
-     * rainy day ...]
      */
     anchor_ptr = HTMainText->first_anchor;
 
     while (anchor_ptr) {
 
-	if ((anchor_ptr->link_type == INPUT_ANCHOR) &&
-	    (anchor_ptr->input_field->type == F_TEXTAREA_TYPE) &&
-	    (anchor_ptr->input_field->number == form_num) &&
-	    !strcmp(anchor_ptr->input_field->name, areaname)) {
+	if (IsFormsTextarea(form, anchor_ptr)) {
 
 	    if (firstanchor) {
 		firstanchor = FALSE;
@@ -12734,7 +12643,7 @@ int HText_ExtEditForm(LinkInfo * form_link)
     }
     LYCloseTempFP(fp);
 
-    CTRACE((tfp, "GridText: TEXTAREA name=|%s| dumped to tempfile\n", areaname));
+    CTRACE((tfp, "GridText: TEXTAREA name=|%s| dumped to tempfile\n", form->name));
     CTRACE((tfp, "GridText: invoking editor (%s) on tempfile\n", editor));
 
     /*
@@ -12901,8 +12810,6 @@ int HText_ExtEditForm(LinkInfo * form_link)
 	strncat(line, lp, len);
 	*(line + len0 + len) = '\0';
 
-	cleanup_line_for_textarea(line, len0 + len);
-
 	/*
 	 * If there are more lines in the edit buffer than were in the
 	 * original TEXTAREA, we need to add a new line/anchor, continuing
@@ -12986,8 +12893,6 @@ void HText_ExpandTextarea(LinkInfo * form_link, int newlines)
     BOOLEAN firstanchor = TRUE;
 
     FormInfo *form = form_link->l_form;
-    char *areaname = form->name;
-    int form_num = form->number;
 
     HTLine *htline = NULL;
 
@@ -13002,27 +12907,12 @@ void HText_ExpandTextarea(LinkInfo * form_link, int newlines)
     /*
      * Begin at the beginning, to find the TEXTAREA, then on to find
      * the last line (anchor) in it.
-     *
-     * [Finding the TEXTAREA we're actually *in* with these attributes
-     * isn't foolproof.  The form_num isn't unique to a given TEXTAREA,
-     * and there *could* be TEXTAREA's with the same "name".  If that
-     * should ever be true, we'll actually expand the *1st* TEXTAREA
-     * in the page that matches.  We should probably assign a unique
-     * id to each TEXTAREA in a page, and match on that, to avoid this
-     * (potential) problem.
-     *
-     * Since the odds of "false matches" *actually* happening in real
-     * life seem rather small though, we'll hold off doing this, for a
-     * rainy day ...]
      */
     anchor_ptr = HTMainText->first_anchor;
 
     while (anchor_ptr) {
 
-	if ((anchor_ptr->link_type == INPUT_ANCHOR) &&
-	    (anchor_ptr->input_field->type == F_TEXTAREA_TYPE) &&
-	    (anchor_ptr->input_field->number == form_num) &&
-	    !strcmp(anchor_ptr->input_field->name, areaname)) {
+	if (IsFormsTextarea(form, anchor_ptr)) {
 
 	    if (firstanchor)
 		firstanchor = FALSE;
@@ -13053,7 +12943,7 @@ void HText_ExpandTextarea(LinkInfo * form_link, int newlines)
     }
 
     CTRACE((tfp, "GridText: %d blank line(s) added to TEXTAREA name=|%s|\n",
-	    newlines, areaname));
+	    newlines, form->name));
 
     /*
      * We need to adjust various things in all anchor bearing lines
@@ -13091,8 +12981,6 @@ int HText_InsertFile(LinkInfo * form_link)
     BOOLEAN truncalert = FALSE;
 
     FormInfo *form = form_link->l_form;
-    char *areaname = form->name;
-    int form_num = form->number;
 
     HTLine *htline = NULL;
 
@@ -13179,28 +13067,12 @@ int HText_InsertFile(LinkInfo * form_link)
     /*
      * Begin at the beginning, to find the TEXTAREA we're in, then
      * the current cursorline.
-     *
-     * [Finding the TEXTAREA we're actually *in* with these attributes
-     * isn't foolproof.  The form_num isn't unique to a given TEXTAREA,
-     * and there *could* be TEXTAREA's with the same "name".  If that
-     * should ever be true, we'll actually insert data into the *1st*
-     * TEXTAREA in the page that matches.  We should probably assign
-     * a unique id to each TEXTAREA in a page, and match on that, to
-     * avoid this (potential) problem.
-     *
-     * Since the odds of "false matches" *actually* happening in real
-     * life seem rather small though, we'll hold off doing this, for a
-     * rainy day ...]
      */
     anchor_ptr = HTMainText->first_anchor;
 
     while (anchor_ptr) {
 
-	if ((anchor_ptr->link_type == INPUT_ANCHOR) &&
-	    (anchor_ptr->input_field->type == F_TEXTAREA_TYPE) &&
-	    (anchor_ptr->input_field->number == form_num) &&
-	    !strcmp(anchor_ptr->input_field->name, areaname)) {
-
+	if (IsFormsTextarea(form, anchor_ptr)) {
 	    if (anchor_ptr->line_num == entry_line)
 		break;
 	}
@@ -13334,8 +13206,6 @@ int HText_InsertFile(LinkInfo * form_link)
 	strncpy(line, lp, len);
 	*(line + len) = '\0';
 
-	cleanup_line_for_textarea(line, len);
-
 	/*
 	 * If not the first line from the insert file, we need to add
 	 * a new line/anchor, continuing on until the buffer is empty.
diff --git a/src/HTForms.h b/src/HTForms.h
index 4cca9484..de4ae372 100644
--- a/src/HTForms.h
+++ b/src/HTForms.h
@@ -1,5 +1,5 @@
 /*
- * $LynxId: HTForms.h,v 1.25 2008/09/06 15:46:41 tom Exp $
+ * $LynxId: HTForms.h,v 1.26 2008/09/07 16:35:26 tom Exp $
  */
 #ifndef HTFORMS_H
 #define HTFORMS_H
@@ -136,11 +136,11 @@ extern "C" {
 	F_KEYGEN_TYPE
     } FieldTypes;
 
-#define F_TEXTLIKE(type) ((type)==F_TEXT_TYPE ||\
-			  (type)==F_TEXT_SUBMIT_TYPE ||\
-			  (type)==F_PASSWORD_TYPE ||\
-			  (type)==F_FILE_TYPE ||\
-			  (type)==F_TEXTAREA_TYPE)
+#define F_TEXTLIKE(type) ((type) == F_TEXT_TYPE || \
+			  (type) == F_TEXT_SUBMIT_TYPE || \
+			  (type) == F_PASSWORD_TYPE || \
+			  (type) == F_FILE_TYPE || \
+			  (type) == F_TEXTAREA_TYPE)
 
 #define WWW_FORM_LINK_TYPE  1
 #define WWW_LINK_TYPE   2
diff --git a/src/LYCurses.c b/src/LYCurses.c
index f7dd6022..d5516872 100644
--- a/src/LYCurses.c
+++ b/src/LYCurses.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYCurses.c,v 1.133 2008/07/01 23:55:27 tom Exp $ */
+/* $LynxId: LYCurses.c,v 1.135 2008/09/07 22:03:52 tom Exp $ */
 #include <HTUtils.h>
 #include <HTAlert.h>
 
@@ -1864,6 +1864,10 @@ void LYwaddnstr(WINDOW * w GCC_UNUSED,
 		const char *src,
 		size_t len)
 {
+    int y0, x0;
+    int y, x;
+    size_t inx;
+
 #ifdef USE_CURSES_PADS
     /*
      * If we've configured to use pads for left/right scrolling, that can
@@ -1877,13 +1881,11 @@ void LYwaddnstr(WINDOW * w GCC_UNUSED,
      * simplify things, e.g., in case the string contains multibyte or
      * multicolumn characters.
      */
-    int y0, x0;
-
     getyx(LYwin, y0, x0);
 
     if (LYuseCursesPads
-	&& (LYwin == w)		/* popups do not wrap */
-	&&LYshiftWin == 0
+	&& (LYwin == w)
+	&& (LYshiftWin == 0)
 	&& LYwideLines == FALSE
 	&& ((int) len > (LYcolLimit - x0))
 	&& (x0 < LYcolLimit)) {
@@ -1908,25 +1910,26 @@ void LYwaddnstr(WINDOW * w GCC_UNUSED,
      */
 #ifdef USE_COLOR_STYLE
     if (TRACE) {
-	int y, x;
-
 	LYGetYX(y, x);
 	CTRACE2(TRACE_STYLE, (tfp, "[%2d,%2d] LYwaddnstr(%.*s, %u)\n",
 			      y, x, (int) len, src, (unsigned) len));
     }
 #endif
-    /*
-     * There's no guarantee that a library won't temporarily write on its input.
-     * Be safe and copy it when we have const-data.
-     */
-    while ((int) len > 0) {
-	char temp[MAX_LINE];
-	size_t use = (len >= MAX_LINE) ? MAX_LINE - 1 : len;
+    LYGetYX(y0, x0);
 
-	memcpy(temp, src, use);
-	temp[use] = 0;
-	waddstr(w, temp);
-	len -= use;
+    for (inx = 0; inx < len; ++inx) {
+	/*
+	 * Do tab-expansion relative to the base of the string (rather than
+	 * the screen) so that tabs in a TEXTAREA will look right.
+	 */
+	if (src[inx] == '\t') {
+	    LYGetYX(y, x);
+	    while ((++x - x0) % 8)
+		waddch(w, ' ');
+	    waddch(w, ' ');
+	} else {
+	    waddch(w, UCH(src[inx]));
+	}
     }
 }
 
@@ -1989,12 +1992,15 @@ int LYstrExtent(const char *string, int len, int maxCells)
 }
 
 /*
- * A simple call that relies upon the coincidence that multicell characters
- * use at least as many bytes as cells.
+ * Return the number of cells in the first 'len' bytes of the string.
+ *
+ * This relies upon the coincidence that multicell characters use at least as
+ * many bytes as cells.  But we have to account for tab, which can use 8, and
+ * control characters which use 2.
  */
 int LYstrExtent2(const char *string, int len)
 {
-    return LYstrExtent(string, len, len);
+    return LYstrExtent(string, len, 8 * len);
 }
 
 /*
diff --git a/src/LYEditmap.c b/src/LYEditmap.c
index cf8c3ec8..04fdee7f 100644
--- a/src/LYEditmap.c
+++ b/src/LYEditmap.c
@@ -1,6 +1,9 @@
-/* LYEditMap.c
-   Keybindings for line and form editting.
-*/
+/*
+ * $LynxId: LYEditmap.c,v 1.27 2008/09/07 23:00:47 tom Exp $
+ *
+ * LYEditMap.c
+ * Keybindings for line and form editting.
+ */
 
 #include <HTUtils.h>
 #include <LYGlobalDefs.h>
@@ -993,7 +996,7 @@ int EditBinding(int xlkc)
     } else if (xlkc & LKC_MOD3) {
 	xleac = LKC_TO_LEC_M3(c);
     } else {
-	xleac = UCH(LYLineEditors[current_lineedit][c]);
+	xleac = UCH(CurrentLineEditor()[c]);
     }
 #endif
     /*
@@ -1001,7 +1004,7 @@ int EditBinding(int xlkc)
      * look that up now; otherwise we are already done.  - kw
      */
     if (xleac == LYE_UNMOD) {
-	editaction = LYLineEditors[current_lineedit][c];
+	editaction = CurrentLineEditor()[c];
     } else {
 	editaction = xleac;
     }
@@ -1093,7 +1096,7 @@ int LYKeyForEditAction(int lec)
     int editaction, i;
 
     for (i = FIRST_I; i >= 0; i = NEXT_I(i, KEYMAP_SIZE - 2)) {
-	editaction = LYLineEditors[current_lineedit][i];
+	editaction = CurrentLineEditor()[i];
 	if (editaction == lec) {
 #ifdef NOT_ASCII
 	    if (i < 256) {
@@ -1128,7 +1131,7 @@ int LYEditKeyForAction(int lac,
     if (pmodkey)
 	*pmodkey = -1;
     for (i = FIRST_I; i >= 0; i = NEXT_I(i, KEYMAP_SIZE - 2)) {
-	editaction = LYLineEditors[current_lineedit][i];
+	editaction = CurrentLineEditor()[i];
 #ifdef NOT_ASCII
 	if (i < 256) {
 	    c = FROMASCII(i);
@@ -1165,7 +1168,7 @@ int LYEditKeyForAction(int lac,
 #ifdef EXP_ALT_BINDINGS
     if (mod3found >= 0) {
 	for (i = mod3found; i >= 0; i = NEXT_I(i, LAST_MOD3_LKC)) {
-	    editaction = LYLineEditors[current_lineedit][i];
+	    editaction = CurrentLineEditor()[i];
 	    if (!(editaction & LYE_DF))
 		continue;
 	    editaction = Mod3Binding[i];
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 1e2cadb4..d7e0cde3 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYMainLoop.c,v 1.150 2008/02/17 19:14:40 Paul.B.Mahol Exp $ */
+/* $LynxId: LYMainLoop.c,v 1.152 2008/09/07 16:28:33 tom Exp $ */
 #include <HTUtils.h>
 #include <HTAccess.h>
 #include <HTParse.h>
@@ -48,6 +48,10 @@
 #include <HTCJK.h>
 #endif
 
+#define LinkIsTextarea(linkNumber) \
+		(links[linkNumber].type == WWW_FORM_LINK_TYPE && \
+		 links[linkNumber].l_form->type == F_TEXTAREA_TYPE)
+
 #ifdef KANJI_CODE_OVERRIDE
 char *str_kcode(HTkcode code)
 {
@@ -2342,8 +2346,7 @@ static int handle_LYK_DWIMEDIT(int *cmd,
      * rather than attempting to edit the html source document.  KED
      */
     if (nlinks > 0 &&
-	links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+	LinkIsTextarea(curdoc.link)) {
 	*cmd = LYK_EDIT_TEXTAREA;
 	return 2;
     }
@@ -2566,8 +2569,7 @@ static void handle_LYK_EDIT_TEXTAREA(BOOLEAN *refresh_screen,
     /*
      * See if the current link is in a form TEXTAREA.
      */
-    else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	     links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+    else if (LinkIsTextarea(curdoc.link)) {
 
 	/* stop screen */
 	stop_curses();
@@ -2722,32 +2724,27 @@ static BOOLEAN handle_LYK_FASTBACKW_LINK(int *cmd,
 	 * If in textarea, move to first link or textarea group before it if
 	 * there is one on this screen.  - kw
 	 */
-	if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	    links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+	if (LinkIsTextarea(curdoc.link)) {
 	    int thisgroup = links[curdoc.link].l_form->number;
 	    char *thisname = links[curdoc.link].l_form->name;
 
 	    if (curdoc.link > 0 &&
-		!(links[0].type == WWW_FORM_LINK_TYPE &&
-		  links[0].l_form->type == F_TEXTAREA_TYPE &&
+		!(LinkIsTextarea(0) &&
 		  links[0].l_form->number == thisgroup &&
 		  sametext(links[0].l_form->name, thisname))) {
 		do
 		    nextlink--;
 		while
-		    (links[nextlink].type == WWW_FORM_LINK_TYPE &&
-		     links[nextlink].l_form->type == F_TEXTAREA_TYPE &&
+		    (LinkIsTextarea(nextlink) &&
 		     links[nextlink].l_form->number == thisgroup &&
 		     sametext(links[nextlink].l_form->name, thisname));
 		samepage = 1;
 
 	    } else if (!more_text && LYGetNewline() == 1 &&
-		       (links[0].type == WWW_FORM_LINK_TYPE &&
-			links[0].l_form->type == F_TEXTAREA_TYPE &&
+		       (LinkIsTextarea(0) &&
 			links[0].l_form->number == thisgroup &&
 			sametext(links[0].l_form->name, thisname)) &&
-		       !(links[nlinks - 1].type == WWW_FORM_LINK_TYPE &&
-			 links[nlinks - 1].l_form->type == F_TEXTAREA_TYPE &&
+		       !(LinkIsTextarea(nlinks - 1) &&
 			 links[nlinks - 1].l_form->number == thisgroup &&
 			 sametext(links[nlinks - 1].l_form->name, thisname))) {
 		nextlink = nlinks - 1;
@@ -2773,21 +2770,18 @@ static BOOLEAN handle_LYK_FASTBACKW_LINK(int *cmd,
 	 * - kw
 	 */
 	if (nextlink > 0 &&
-	    links[nextlink].type == WWW_FORM_LINK_TYPE &&
-	    links[nextlink].l_form->type == F_TEXTAREA_TYPE) {
+	    LinkIsTextarea(nextlink)) {
 	    int thisgroup = links[nextlink].l_form->number;
 	    char *thisname = links[nextlink].l_form->name;
 
-	    if (links[0].type == WWW_FORM_LINK_TYPE &&
-		links[0].l_form->type == F_TEXTAREA_TYPE &&
+	    if (LinkIsTextarea(0) &&
 		links[0].l_form->number == thisgroup &&
 		sametext(links[0].l_form->name, thisname)) {
 		nextlink = 0;
 	    } else
 		while
 		    (nextlink > 1 &&
-		     links[nextlink - 1].type == WWW_FORM_LINK_TYPE &&
-		     links[nextlink - 1].l_form->type == F_TEXTAREA_TYPE &&
+		     LinkIsTextarea(nextlink - 1) &&
 		     links[nextlink - 1].l_form->number == thisgroup &&
 		     sametext(links[nextlink - 1].l_form->name, thisname)) {
 		    nextlink--;
@@ -2829,21 +2823,18 @@ static void handle_LYK_FASTFORW_LINK(int *old_c,
 	 * If in textarea, move to first link or field after it if there is one
 	 * on this screen.  - kw
 	 */
-	if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	    links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+	if (LinkIsTextarea(curdoc.link)) {
 	    int thisgroup = links[curdoc.link].l_form->number;
 	    char *thisname = links[curdoc.link].l_form->name;
 
 	    if (curdoc.link < nlinks - 1 &&
-		!(links[nlinks - 1].type == WWW_FORM_LINK_TYPE &&
-		  links[nlinks - 1].l_form->type == F_TEXTAREA_TYPE &&
+		!(LinkIsTextarea(nlinks - 1) &&
 		  links[nlinks - 1].l_form->number == thisgroup &&
 		  sametext(links[nlinks - 1].l_form->name, thisname))) {
 		do
 		    nextlink++;
 		while
-		    (links[nextlink].type == WWW_FORM_LINK_TYPE &&
-		     links[nextlink].l_form->type == F_TEXTAREA_TYPE &&
+		    (LinkIsTextarea(nextlink) &&
 		     links[nextlink].l_form->number == thisgroup &&
 		     sametext(links[nextlink].l_form->name, thisname));
 		samepage = 1;
@@ -2953,8 +2944,7 @@ static void handle_LYK_GROW_TEXTAREA(BOOLEAN *refresh_screen)
     /*
      * See if the current link is in a form TEXTAREA.
      */
-    if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+    if (LinkIsTextarea(curdoc.link)) {
 
 	HText_ExpandTextarea(&links[curdoc.link], TEXTAREA_EXPAND_SIZE);
 
@@ -3367,8 +3357,7 @@ static void handle_LYK_INSERT_FILE(BOOLEAN *refresh_screen,
     /*
      * See if the current link is in a form TEXTAREA.
      */
-    if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	links[curdoc.link].l_form->type == F_TEXTAREA_TYPE) {
+    if (LinkIsTextarea(curdoc.link)) {
 
 	/*
 	 * Reject attempts to use this for gaining access to local files when
@@ -3862,8 +3851,7 @@ static void handle_LYK_NEXT_LINK(int c,
 	/*
 	 * Move to different textarea if TAB in textarea.
 	 */
-	if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-	    links[curdoc.link].l_form->type == F_TEXTAREA_TYPE &&
+	if (LinkIsTextarea(curdoc.link) &&
 	    c == '\t') {
 	    int thisgroup = links[curdoc.link].l_form->number;
 	    char *thisname = links[curdoc.link].l_form->name;
@@ -3871,8 +3859,7 @@ static void handle_LYK_NEXT_LINK(int c,
 	    do
 		curdoc.link++;
 	    while ((curdoc.link < nlinks - 1) &&
-		   links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-		   links[curdoc.link].l_form->type == F_TEXTAREA_TYPE &&
+		   LinkIsTextarea(curdoc.link) &&
 		   links[curdoc.link].l_form->number == thisgroup &&
 		   sametext(links[curdoc.link].l_form->name, thisname));
 	} else {
@@ -6604,8 +6591,7 @@ int mainloop(void)
 			c = DO_NOTHING;
 		    }
 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
-		} else if ((links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-			    links[curdoc.link].l_form->type == F_TEXTAREA_TYPE)
+		} else if (LinkIsTextarea(curdoc.link)
 			   && textfields_need_activation
 			   && !links[curdoc.link].l_form->disabled
 			   && peek_mouse_link() < 0 &&
@@ -6616,8 +6602,7 @@ int mainloop(void)
 			      LKC_TO_LAC(keymap, real_c) == LYK_LPOS_NEXT_LINK ||
 			      LKC_TO_LAC(keymap, real_c) == LYK_DOWN_LINK) &&
 			     ((curdoc.link < nlinks - 1 &&
-			       links[curdoc.link + 1].type == WWW_FORM_LINK_TYPE
-			       && links[curdoc.link + 1].l_form->type == F_TEXTAREA_TYPE
+			       LinkIsTextarea(curdoc.link + 1)
 			       && (links[curdoc.link].l_form->number ==
 				   links[curdoc.link + 1].l_form->number)
 			       && strcmp(links[curdoc.link].l_form->name,
@@ -6629,8 +6614,7 @@ int mainloop(void)
 			      LKC_TO_LAC(keymap, real_c) == LYK_LPOS_PREV_LINK ||
 			      LKC_TO_LAC(keymap, real_c) == LYK_UP_LINK) &&
 			     ((curdoc.link > 0 &&
-			       links[curdoc.link - 1].type == WWW_FORM_LINK_TYPE
-			       && links[curdoc.link - 1].l_form->type == F_TEXTAREA_TYPE
+			       LinkIsTextarea(curdoc.link - 1)
 			       && (links[curdoc.link].l_form->number ==
 				   links[curdoc.link - 1].l_form->number) &&
 			       strcmp(links[curdoc.link].l_form->name,
@@ -6664,19 +6648,16 @@ int mainloop(void)
 			 * "readability" (such as it is).  Caveat emptor to
 			 * anyone trying to change it.]
 			 */
-			if ((links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
-			     links[curdoc.link].l_form->type == F_TEXTAREA_TYPE)
+			if (LinkIsTextarea(curdoc.link)
 			    && ((curdoc.link == nlinks - 1 &&
 				 !(more_text &&
 				   HText_TAHasMoreLines(curdoc.link, 1)))
 				||
 				((curdoc.link < nlinks - 1) &&
-				 !(links[curdoc.link + 1].type == WWW_FORM_LINK_TYPE
-				   && links[curdoc.link + 1].l_form->type == F_TEXTAREA_TYPE))
+				 !LinkIsTextarea(curdoc.link + 1))
 				||
 				((curdoc.link < nlinks - 1) &&
-				 ((links[curdoc.link + 1].type == WWW_FORM_LINK_TYPE
-				   && links[curdoc.link + 1].l_form->type == F_TEXTAREA_TYPE)
+				 (LinkIsTextarea(curdoc.link + 1)
 				  && ((links[curdoc.link].l_form->number !=
 				       links[curdoc.link + 1].l_form->number) ||
 				      (strcmp(links[curdoc.link].l_form->name,
diff --git a/src/LYStrings.c b/src/LYStrings.c
index 1eb5c2d9..4b86571d 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYStrings.c,v 1.155 2008/09/06 15:01:28 tom Exp $ */
+/* $LynxId: LYStrings.c,v 1.157 2008/09/07 22:09:02 tom Exp $ */
 #include <HTUtils.h>
 #include <HTCJK.h>
 #include <UCAux.h>
@@ -3586,7 +3586,7 @@ static void remember_column(EDREC * edit, int offset)
 
 #if defined(USE_SLANG)
     y0 = 0;
-    x0 = offset;
+    x0 = SLsmg_get_column();
 #elif defined(USE_CURSES_PADS)
     getyx(LYwin, y0, x0);
 #else
@@ -3834,6 +3834,16 @@ void LYRefreshEdit(EDREC * edit)
 		    !(LYCharSet_UC[current_char_set].like8859
 		      & UCT_R_8859SPECL))))) {
 		LYaddch(' ');
+	    } else if (str[i] == '\t') {
+		int col = edit->offset2col[i] - StartX;
+
+		/*
+		 * Like LYwaddnstr(), expand tabs from the beginning of the
+		 * field.
+		 */
+		while (++col % 8)
+		    LYaddch(' ');
+		LYaddch(' ');
 	    } else {
 		LYaddch(UCH(str[i]));
 	    }
diff --git a/src/LYStrings.h b/src/LYStrings.h
index a42ec557..a9992a49 100644
--- a/src/LYStrings.h
+++ b/src/LYStrings.h
@@ -1,5 +1,5 @@
 /*
- * $LynxId: LYStrings.h,v 1.68 2008/09/06 14:07:46 tom Exp $
+ * $LynxId: LYStrings.h,v 1.69 2008/09/07 22:59:14 tom Exp $
  */
 #ifndef LYSTRINGS_H
 #define LYSTRINGS_H
@@ -345,6 +345,8 @@ extern "C" {
     extern LYEditCode *LYLineEditors[];
     extern const char *LYLineeditHelpURLs[];
 
+#define CurrentLineEditor() LYLineEditors[current_lineedit]
+
     extern const char *LYLineeditHelpURL(void);
 
     extern int escape_bound;
diff --git a/src/LYUtils.c b/src/LYUtils.c
index 6bdf302b..3674d302 100644
--- a/src/LYUtils.c
+++ b/src/LYUtils.c
@@ -1,4 +1,6 @@
-/* $LynxId: LYUtils.c,v 1.173 2008/09/06 14:35:56 tom Exp $ */
+/*
+ * $LynxId: LYUtils.c,v 1.175 2008/09/07 17:58:37 tom Exp $
+ */
 #include <HTUtils.h>
 #include <HTTCP.h>
 #include <HTParse.h>
@@ -982,16 +984,17 @@ static int find_cached_style(int cur,
 		    s = GetCachedStyle(LYP, x);
 		    if (s != 0) {
 			SetCachedStyle(LYP, LXP, s);
-			CTRACE((tfp, "found %d, x_offset=%d.\n", s, x - LXP));
+			CTRACE2(TRACE_STYLE,
+				(tfp, "found %d, x_offset=%d.\n", s, x - LXP));
 			break;
 		    }
 		}
 		if (s == 0) {
-		    CTRACE((tfp, "not found, assume <a>.\n"));
+		    CTRACE2(TRACE_STYLE, (tfp, "not found, assume <a>.\n"));
 		    s = s_a;
 		}
 	    } else {
-		CTRACE((tfp, "found %d.\n", s));
+		CTRACE2(TRACE_STYLE, (tfp, "found %d.\n", s));
 	    }
 	} else {
 	    CTRACE2(TRACE_STYLE,
@@ -1045,7 +1048,8 @@ void LYhighlight(int flag,
 	cur = 0;
     }
 
-    CTRACE((tfp, "LYhighlight %s %d [%d]:%s\n",
+    CTRACE((tfp, "LYhighlight at(%2d,%2d) %s %d [%d]:%s\n",
+	    links[cur].ly, links[cur].lx,
 	    (flag
 	     ? "on"
 	     : "off"),