about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorThomas E. Dickey <dickey@invisible-island.net>1998-12-16 22:06:07 -0500
committerThomas E. Dickey <dickey@invisible-island.net>1998-12-16 22:06:07 -0500
commit10f6c5df5fbd3e8a2be8a0640035680235b3f8a3 (patch)
treef46df4582b5b527aff7ed4294e065bc5b6076a33 /src
parent08fc6e5c6582f05f43c968931b04d698cf7abc86 (diff)
downloadlynx-snapshots-10f6c5df5fbd3e8a2be8a0640035680235b3f8a3.tar.gz
snapshot of project "lynx", label v2-8-2dev_10
Diffstat (limited to 'src')
-rw-r--r--src/GridText.c450
-rw-r--r--src/HTInit.c93
-rw-r--r--src/HTML.c19
-rw-r--r--src/LYCookie.c237
-rw-r--r--src/LYGetFile.c3
-rw-r--r--src/LYHistory.c8
-rw-r--r--src/LYKeymap.c19
-rw-r--r--src/LYKeymap.h5
-rw-r--r--src/LYMainLoop.c16
-rw-r--r--src/LYOptions.c9
-rw-r--r--src/LYOptions.h7
-rw-r--r--src/LYStrings.c262
-rw-r--r--src/chrtrans/caselower.h737
-rw-r--r--src/chrtrans/makefile.dos5
-rw-r--r--src/makefile.in2
15 files changed, 1595 insertions, 277 deletions
diff --git a/src/GridText.c b/src/GridText.c
index f31d8d1f..2fee3cb9 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -1680,7 +1680,9 @@ PRIVATE void split_line ARGS2(
     int HeadTrim = 0;
     int SpecialAttrChars = 0;
     int TailTrim = 0;
+    int s;
 
+#define DEBUG_SPLITLINE
     /*
      *  Make new line.
      */
@@ -1700,108 +1702,24 @@ PRIVATE void split_line ARGS2(
     CTRACE(tfp,"   bold_on=%d, underline_on=%d\n", bold_on, underline_on);
 #endif
 
+    if (split > previous->size) {
+	CTRACE(tfp,
+	       "*** split_line: split==%d greater than last_line->size==%d !\n",
+	       split, previous->size);
+	if (split > MAX_LINE) {
+	    split = previous->size;
+	    if ((cp = strrchr(previous->data, ' ')) &&
+		cp - previous->data > 1)
+		split = cp - previous->data;
+	    CTRACE(tfp, "                split adjusted to %d.\n", split);
+	}
+    }
+
     text->Lines++;
 
     previous->next->prev = line;
     line->prev = previous;
     line->next = previous->next;
-#if defined(USE_COLOR_STYLE)
-#define LastStyle (previous->numstyles-1)
-    line->numstyles = 0;
-    inew = MAX_STYLES_ON_LINE - 1;
-    spare = previous->numstyles;
-    while (previous->numstyles && inew >= 0) {
-	if (previous->numstyles >= 2 &&
-	    previous->styles[LastStyle].style
-	    == previous->styles[previous->numstyles-2].style &&
-	    previous->styles[LastStyle].horizpos
-	    == previous->styles[previous->numstyles-2].horizpos &&
-	    ((previous->styles[LastStyle].direction == STACK_OFF &&
-	      previous->styles[previous->numstyles-2].direction == STACK_ON) ||
-	     (previous->styles[LastStyle].direction == ABS_OFF &&
-	      previous->styles[previous->numstyles-2].direction == ABS_ON) ||
-	     (previous->styles[LastStyle].direction == ABS_ON &&
-	      previous->styles[previous->numstyles-2].direction == ABS_OFF)
-		)) {
-	    /*
-	     *  Discard pairs of ON/OFF for the same color style, but only
-	     *  if they appear at the same position. - kw
-	     */
-	    previous->numstyles -= 2;
-	    if (spare > previous->numstyles)
-		spare = previous->numstyles;
-	} else if (spare > 0 && previous->styles[spare - 1].direction &&
-		   previous->numstyles < MAX_STYLES_ON_LINE) {
-	    /*
-	     *  The index variable spare walks backwards through the
-	     *  list of color style changes on the previous line, trying
-	     *  to find an ON change which isn't followed by a
-	     *  corresponding OFF.  When it finds one, the missing OFF
-	     *  change is appended to the end, and an ON change is added
-	     *  at the beginning of the current line.  The OFF change
-	     *  appended to the previous line may get removed again in
-	     *  the next iteration. - kw
-	     */
-	    line->styles[inew].horizpos = 0;
-	    line->styles[inew].direction = ON;
-	    line->styles[inew].style = previous->styles[spare - 1].style;
-	    inew --;
-	    line->numstyles ++;
-	    previous->styles[previous->numstyles].style = line->styles[inew + 1].style;
-
-	    previous->styles[previous->numstyles].direction = ABS_OFF;
-	    previous->styles[previous->numstyles].horizpos = previous->size;
-	    previous->numstyles++;
-	    spare --;
-	} else if (spare >= 2 &&
-		   previous->styles[spare - 1].style == previous->styles[spare - 2].style &&
-		   ((previous->styles[spare - 1].direction == STACK_OFF &&
-		     previous->styles[spare - 2].direction == STACK_ON) ||
-		    (previous->styles[spare - 1].direction == ABS_OFF &&
-		     previous->styles[spare - 2].direction == ABS_ON) ||
-		    (previous->styles[spare - 1].direction == STACK_ON &&
-		     previous->styles[spare - 2].direction == STACK_OFF) ||
-		    (previous->styles[spare - 1].direction == ABS_ON &&
-		     previous->styles[spare - 2].direction == ABS_OFF)
-		       )) {
-	       /*
-		*  Skip pairs of adjacent ON/OFF or OFF/ON changes.
-		*/
-	    spare -= 2;
-	} else if (spare && !previous->styles[spare - 1].direction) {
-	    /*
-	     *  Found an OFF change not part of a matched pair.
-	     *  Assume it is safer to leave whatever comes before
-	     *  it on the previous line alone.  Setting spare to 0
-	     *  ensures that it won't be used in a following
-	     *  iteration. - kw
-	     */
-	    spare = 0;
-	} else {
-	    /*
-	     *  Nothing applied, so we are done with the loop. - kw
-	     */
-	    break;
-	}
-    }
-    if (previous->numstyles > 0 && previous->styles[LastStyle].direction) {
-
-	CTRACE(tfp, "%s\n%s%s\n",
-		    "........... Too many character styles on line:",
-		    "........... ", previous->data);
-    }
-    if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) {
-	int n;
-	inew ++;
-	for (n = 0; n < line->numstyles; n++)
-		line->styles[n] = line->styles[n + inew];
-    } else
-	if (line->numstyles == 0)
-	/* FIXME: RJP - shouldn't use 0xffffffff for largest integer */
-	line->styles[0].horizpos = 0xffffffff;
-    if (previous->numstyles == 0)
-	previous->styles[0].horizpos = 0xffffffff;
-#endif /*USE_COLOR_STYLE*/
     previous->next = line;
     text->last_line = line;
     line->size = 0;
@@ -1866,15 +1784,13 @@ PRIVATE void split_line ARGS2(
 	     * Make sure our global flag is correct. - FM
 	     */
 	    underline_on = NO;
-	    if (split) {
-		for (i = (split-1); i >= 0; i--) {
-		    if (prevdata[i] == LY_UNDERLINE_END_CHAR) {
-			break;
-		    }
-		    if (prevdata[i] == LY_UNDERLINE_START_CHAR) {
-			underline_on = YES;
-			break;
-		    }
+	    for (i = (split-1); i >= 0; i--) {
+		if (prevdata[i] == LY_UNDERLINE_END_CHAR) {
+		    break;
+		}
+		if (prevdata[i] == LY_UNDERLINE_START_CHAR) {
+		    underline_on = YES;
+		    break;
 		}
 	    }
 	    /*
@@ -1911,15 +1827,13 @@ PRIVATE void split_line ARGS2(
 	 *  sure that our global flag is correct. - FM
 	 */
 	bold_on = NO;
-	if (split) {
-	    for (i = (split - 1); i >= 0; i--) {
-		if (prevdata[i] == LY_BOLD_END_CHAR) {
-		    break;
-		}
-		if (prevdata[i] == LY_BOLD_START_CHAR) {
-		    bold_on = YES;
-		    break;
-		}
+	for (i = (split - 1); i >= 0; i--) {
+	    if (prevdata[i] == LY_BOLD_END_CHAR) {
+		break;
+	    }
+	    if (prevdata[i] == LY_BOLD_START_CHAR) {
+		bold_on = YES;
+		break;
 	    }
 	}
 	/*
@@ -1979,6 +1893,151 @@ PRIVATE void split_line ARGS2(
 	previous->size--;
 	TailTrim++;
     }
+    /*
+     *  s is the effective split position, given by either a non-zero
+     *  value of split or by the size of the previous line before
+     *  trimming. - kw
+     */
+    if (split == 0) {
+	s = previous->size + TailTrim; /* the original size */
+    } else {
+	s = split;
+    }
+#ifdef DEBUG_SPLITLINE
+#ifdef DEBUG_APPCH
+    if (s != (int)split)
+#endif
+	CTRACE(tfp,"GridText: split_line(%d [now:%d]) called\n", split, s);
+#endif
+
+#if defined(USE_COLOR_STYLE)
+#define LastStyle (previous->numstyles-1)
+    line->numstyles = 0;
+    inew = MAX_STYLES_ON_LINE - 1;
+    /*
+     *  Color style changes after the split position + possible trimmed
+     *  head characters are transferred to the new line.  Ditto for changes
+     *  within the trimming region, but be stop when we reach an OFF change.
+     *  The second while loop below may then handle remaining changes. - kw
+     */
+    while (previous->numstyles && inew >= 0) {
+	if (previous->styles[LastStyle].horizpos > s + HeadTrim) {
+	    line->styles[inew].horizpos =
+		previous->styles[LastStyle].horizpos
+		- (s + HeadTrim) + SpecialAttrChars;
+	    line->styles[inew].direction = previous->styles[LastStyle].direction;
+	    line->styles[inew].style = previous->styles[LastStyle].style;
+	    inew --;
+	    line->numstyles ++;
+	    previous->numstyles --;
+	} else if (previous->styles[LastStyle].horizpos > s - TailTrim &&
+		   (previous->styles[LastStyle].direction == STACK_ON ||
+		    previous->styles[LastStyle].direction == ABS_ON)) {
+	    line->styles[inew].horizpos =
+		(previous->styles[LastStyle].horizpos < s) ?
+		0 : SpecialAttrChars;
+	    line->styles[inew].direction = previous->styles[LastStyle].direction;
+	    line->styles[inew].style = previous->styles[LastStyle].style;
+	    inew --;
+	    line->numstyles ++;
+	    previous->numstyles --;
+	} else
+	    break;
+    }
+    spare = previous->numstyles;
+    while (previous->numstyles && inew >= 0) {
+	if (previous->numstyles >= 2 &&
+	    previous->styles[LastStyle].style
+	    == previous->styles[previous->numstyles-2].style &&
+	    previous->styles[LastStyle].horizpos
+	    == previous->styles[previous->numstyles-2].horizpos &&
+	    ((previous->styles[LastStyle].direction == STACK_OFF &&
+	      previous->styles[previous->numstyles-2].direction == STACK_ON) ||
+	     (previous->styles[LastStyle].direction == ABS_OFF &&
+	      previous->styles[previous->numstyles-2].direction == ABS_ON) ||
+	     (previous->styles[LastStyle].direction == ABS_ON &&
+	      previous->styles[previous->numstyles-2].direction == ABS_OFF)
+		)) {
+	    /*
+	     *  Discard pairs of ON/OFF for the same color style, but only
+	     *  if they appear at the same position. - kw
+	     */
+	    previous->numstyles -= 2;
+	    if (spare > previous->numstyles)
+		spare = previous->numstyles;
+	} else if (spare > 0 && previous->styles[spare - 1].direction &&
+		   previous->numstyles < MAX_STYLES_ON_LINE) {
+	    /*
+	     *  The index variable spare walks backwards through the
+	     *  list of color style changes on the previous line, trying
+	     *  to find an ON change which isn't followed by a
+	     *  corresponding OFF.  When it finds one, the missing OFF
+	     *  change is appended to the end, and an ON change is added
+	     *  at the beginning of the current line.  The OFF change
+	     *  appended to the previous line may get removed again in
+	     *  the next iteration. - kw
+	     */
+	    line->styles[inew].horizpos = 0;
+	    line->styles[inew].direction = ON;
+	    line->styles[inew].style = previous->styles[spare - 1].style;
+	    inew --;
+	    line->numstyles ++;
+	    previous->styles[previous->numstyles].style = line->styles[inew + 1].style;
+
+	    previous->styles[previous->numstyles].direction = ABS_OFF;
+	    previous->styles[previous->numstyles].horizpos = previous->size;
+	    previous->numstyles++;
+	    spare --;
+	} else if (spare >= 2 &&
+		   previous->styles[spare - 1].style == previous->styles[spare - 2].style &&
+		   ((previous->styles[spare - 1].direction == STACK_OFF &&
+		     previous->styles[spare - 2].direction == STACK_ON) ||
+		    (previous->styles[spare - 1].direction == ABS_OFF &&
+		     previous->styles[spare - 2].direction == ABS_ON) ||
+		    (previous->styles[spare - 1].direction == STACK_ON &&
+		     previous->styles[spare - 2].direction == STACK_OFF) ||
+		    (previous->styles[spare - 1].direction == ABS_ON &&
+		     previous->styles[spare - 2].direction == ABS_OFF)
+		       )) {
+	       /*
+		*  Skip pairs of adjacent ON/OFF or OFF/ON changes.
+		*/
+	    spare -= 2;
+	} else if (spare && !previous->styles[spare - 1].direction) {
+	    /*
+	     *  Found an OFF change not part of a matched pair.
+	     *  Assume it is safer to leave whatever comes before
+	     *  it on the previous line alone.  Setting spare to 0
+	     *  ensures that it won't be used in a following
+	     *  iteration. - kw
+	     */
+	    spare = 0;
+	} else {
+	    /*
+	     *  Nothing applied, so we are done with the loop. - kw
+	     */
+	    break;
+	}
+    }
+    if (previous->numstyles > 0 && previous->styles[LastStyle].direction) {
+
+	CTRACE(tfp, "%s\n%s%s\n",
+		    "........... Too many character styles on line:",
+		    "........... ", previous->data);
+    }
+    if (line->numstyles > 0 && line->numstyles < MAX_STYLES_ON_LINE) {
+	int n;
+	inew ++;
+	for (n = 0; n < line->numstyles; n++)
+		line->styles[n] = line->styles[n + inew];
+    } else
+	if (line->numstyles == 0)
+	/* FIXME: RJP - shouldn't use 0xffffffff for largest integer */
+	line->styles[0].horizpos = 0xffffffff;
+    if (previous->numstyles == 0)
+	previous->styles[0].horizpos = 0xffffffff;
+#endif /*USE_COLOR_STYLE*/
+
     temp = (HTLine *)LY_CALLOC(1, LINE_SIZE(previous->size));
     if (temp == NULL)
 	outofmem(__FILE__, "split_line_2");
@@ -2041,20 +2100,152 @@ PRIVATE void split_line ARGS2(
      *  If we split the line, adjust the anchor
      *  structure values for the new line. - FM
      */
-    if (split > 0) {
-	for (a = text->first_anchor; a; a = a->next) {
+
+    if (split > 0 || s > 0) {		/* if not completely empty */
+	TextAnchor * prev_a = NULL;
+	for (a = text->first_anchor; a; prev_a = a, a = a->next) {
 	    if (a->line_num == CurLine) {
-		if ((unsigned)a->line_pos >= split) {
-		    a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
-		    a->line_pos -= (split - SpecialAttrChars + HeadTrim);
-		    a->line_num = text->Lines;
-		} else if ((a->link_type & HYPERTEXT_ANCHOR) &&
-			   (unsigned)(a->line_pos + a->extent) >= split) {
-		    a->extent -= (TailTrim + HeadTrim);
-		    if (a->extent < 0) {
-			a->extent = 0;
+		int old_e = a->extent;
+		int a0 = a->line_pos, a1 = a->line_pos + a->extent;
+		int S, d, new_pos, new_ext;
+		if (a->link_type == INPUT_ANCHOR) {
+		    if (a->line_pos >= s) {
+			a->start += (1 + SpecialAttrChars - HeadTrim - TailTrim);
+			a->line_pos -= (s - SpecialAttrChars + HeadTrim);
+			a->line_num = text->Lines;
 		    }
+		    continue;
+		}
+		if (a0 < s - TailTrim && a1 <= s - TailTrim) {
+		    continue;	/* unaffected, leave it where it is. */
 		}
+		S = s + a->start - a->line_pos;
+		d = S - s;	/* == a->start - a->line_pos */
+		new_ext = old_e = a->extent;
+
+		if (!old_e &&
+		    (!a->number || a->show_anchor) &&
+		    a0 <= s + HeadTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,1);
+#endif
+		    /*
+		     *  It is meant to be empty, and/or endAnchor
+		     *  has seen it and recognized it as empty.
+		     */
+		    new_pos = (a0 <= s) ? s - TailTrim :
+			s - TailTrim + 1;
+		    if (prev_a && new_pos + d < prev_a->start) {
+			if (prev_a->start <= S - TailTrim + 1 + SpecialAttrChars)
+			    new_pos = prev_a->start - d;
+			else
+			    new_pos = s - TailTrim + 1 + SpecialAttrChars;
+		    }
+		} else if (old_e &&
+		     a0 >= s - TailTrim && a0 <= s + HeadTrim &&
+		     a1 <= s + HeadTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,2);
+#endif
+		    /*
+		     *  endAnchor has seen it, it is effectively empty
+		     *  after our trimming, but endAnchor has for some
+		     *  reason not recognized this.  In other words,
+		     *  this should not happen.
+		     *  Should we not adjust the extent and let it "leak"
+		     *  into the new line?
+		     */
+		    new_pos = (a0 < s) ? s - TailTrim :
+			s - TailTrim + 1;
+		    if (prev_a && new_pos + d < prev_a->start) {
+			if (prev_a->start <= S - TailTrim + 1 + SpecialAttrChars)
+			    new_pos = prev_a->start - d;
+			else
+			    new_pos = s - TailTrim + 1 + SpecialAttrChars;
+		    }
+		    new_ext = 0;
+		} else if (a0 >= s + HeadTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,3);
+#endif
+		    /*
+		     *  Completely after split, just shift.
+		     */
+		    new_pos = a0 - TailTrim + 1 - HeadTrim + SpecialAttrChars;
+		} else if (!old_e) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,4);
+#endif
+		    /*
+		     *  No extent set, we may still be growing it.
+		     */
+		    new_pos = s - TailTrim + 1 + SpecialAttrChars;
+
+		    /*
+		     *  Ok, it's neither empty, nor is it completely
+		     *  before or after the split region (including trimmed
+		     *  stuff).  So the anchor is either being split in
+		     *  the middle, with stuff remaining on both lines,
+		     *  or something is being nibbled off, either at
+		     *  the end (anchor stays on previous line) or at
+		     *  the beginning (anchor is on new line).  Let's
+		     *  try in that order.
+		     */
+		} else if (a0 < s - TailTrim &&
+			   a1 > s + HeadTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,5);
+#endif
+		    new_pos = a0;
+		    new_ext = old_e - TailTrim - HeadTrim + SpecialAttrChars;
+		} else if (a0 < s - TailTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,6);
+#endif
+		    new_pos = a0;
+		    new_ext = s - TailTrim - a0;
+		} else if (a1 > s + HeadTrim) {
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "anchor %d case %d: ",
+		       a->number,7);
+#endif
+		    new_pos = s - TailTrim + 1 + SpecialAttrChars;
+		    new_ext = old_e - (s + HeadTrim - a0);
+		} else {
+		    CTRACE(tfp, "split_line anchor %d line %d: This should not happen!\n",
+			   a->number, a->line_num);
+		    CTRACE(tfp,
+			   "anchor %d: (T,H,S)=(%d,%d,%d); (line,start,pos,ext):(%d,%d,%d,%d)!\n",
+			   a->number,
+			   TailTrim,HeadTrim,SpecialAttrChars,
+			   a->line_num,a->start,a->line_pos,a->extent);
+		    continue;
+		}
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, "(T,H,S)=(%d,%d,%d); (line,start,pos,ext):(%d,%d,%d,%d",
+		       TailTrim,HeadTrim,SpecialAttrChars,
+		       a->line_num,a->start,a->line_pos,a->extent);
+#endif
+		if (new_pos != a->line_pos)
+		    a->start = new_pos + d;
+		if (new_pos > s - TailTrim) {
+		    new_pos -= s - TailTrim + 1;
+		    a->line_num = text->Lines;
+		}
+		a->line_pos = new_pos;
+		a->extent = new_ext;
+
+#ifdef DEBUG_SPLITLINE
+		CTRACE(tfp, ")->(%d,%d,%d,%d)\n",
+		       a->line_num,a->start,a->line_pos,a->extent);
+#endif
+
 	    }
 	}
     }
@@ -2177,6 +2368,7 @@ PUBLIC void HText_appendCharacter ARGS2(
 	    CTRACE(tfp, "add(%c) %d/%d\n", ch,
 		   HTisDocumentSource(), HTOutputFormat != WWW_SOURCE);
 	}
+	FREE(special);
     } /* trace only */
 #endif /* DEBUG_APPCH */
 
@@ -3467,9 +3659,9 @@ re_parse:
 	     *  The last line is probably still not finished. - kw
 	     */
 	    if (cur_line >= text->Lines)
-	        break;
+		break;
 	    if (anchor_ptr->start >= text->chars - 1)
-	        break;
+		break;
 	    /*
 	     *  Also skip this anchor if it looks like HText_endAnchor
 	     *  is not yet done with it. - kw
@@ -6548,6 +6740,7 @@ PUBLIC int HText_beginInput ARGS3(
 
     a->start = text->chars + text->last_line->size;
     a->inUnderline = underline;
+    a->line_num = text->Lines;
     a->line_pos = text->last_line->size;
 
 
@@ -6907,6 +7100,7 @@ PUBLIC int HText_beginInput ARGS3(
 	     */
 	    HText_appendCharacter(text, '[');
 	a->start = text->chars + text->last_line->size;
+	a->line_num = text->Lines;
 	a->line_pos = text->last_line->size;
     }
 
diff --git a/src/HTInit.c b/src/HTInit.c
index 74403779..222a581f 100644
--- a/src/HTInit.c
+++ b/src/HTInit.c
@@ -471,6 +471,52 @@ PRIVATE void BuildCommand ARGS5(
     *to = '\0';
 }
 
+#define RTR_forget      0
+#define RTR_lookup      1
+#define RTR_add         2
+
+PRIVATE int RememberTestResult ARGS3(
+	int,		mode,
+	char *,		cmd,
+	int,		result)
+{
+    struct cmdlist_s {
+	char *cmd;
+	int result;
+	struct cmdlist_s *next;
+    };
+    static struct cmdlist_s *cmdlist = NULL;
+    struct cmdlist_s *cur;
+
+    switch(mode) {
+	case RTR_forget:
+	    while(cmdlist) {
+		cur = cmdlist->next;
+		FREE(cmdlist->cmd);
+		FREE(cmdlist);
+		cmdlist = cur;
+	    }
+	    break;
+	case RTR_lookup:
+	    for(cur = cmdlist; cur; cur = cur->next)
+		if(!strcmp(cmd, cur->cmd))
+		    return cur->result;
+	    return -1;
+	case RTR_add:
+	    cur = calloc(1, sizeof(struct cmdlist_s));
+	    cur->next = cmdlist;
+	    cur->cmd = (char *)malloc(strlen(cmd) + 1);
+	    if(cur->cmd)
+		strcpy(cur->cmd, cmd);
+	    else
+		ExitWithError("Out of memory");
+	    cur->result = result;
+	    cmdlist = cur;
+	    break;
+    }
+    return 0;
+}
+
 PRIVATE int PassesTest ARGS1(
 	struct MailcapEntry *,	mc)
 {
@@ -528,28 +574,32 @@ PRIVATE int PassesTest ARGS1(
 	return(-1 == 0);
     }
 
-    /*
-     *  Build the command and execute it.
-     */
-    if (strchr(mc->testcommand, '%')) {
-	if (LYOpenTemp(TmpFileName, HTML_SUFFIX, "w") == 0)
-	    ExitWithError(CANNOT_OPEN_TEMP);
-	LYCloseTemp(TmpFileName);
-    } else {
-	/* We normally don't need a temp file name - kw */
-	TmpFileName[0] = '\0';
+    result = RememberTestResult(RTR_lookup, mc->testcommand, 0);
+    if(result == -1) {
+	/*
+	 *  Build the command and execute it.
+	 */
+	if (strchr(mc->testcommand, '%')) {
+	    if (LYOpenTemp(TmpFileName, HTML_SUFFIX, "w") == 0)
+		ExitWithError(CANNOT_OPEN_TEMP);
+	    LYCloseTemp(TmpFileName);
+	} else {
+	    /* We normally don't need a temp file name - kw */
+	    TmpFileName[0] = '\0';
+	}
+	cmd = (char *)malloc(1024);
+	if (!cmd)
+	    ExitWithError(MEMORY_EXHAUSTED_ABORT);
+	BuildCommand(&cmd, 1024,
+		     mc->testcommand,
+		     TmpFileName,
+		     strlen(TmpFileName));
+	CTRACE(tfp, "PassesTest: Executing test command: %s\n", cmd);
+	result = LYSystem(cmd);
+	FREE(cmd);
+	LYRemoveTemp(TmpFileName);
+	RememberTestResult(RTR_add, mc->testcommand, result ? 1 : 0);
     }
-    cmd = (char *)malloc(1024);
-    if (!cmd)
-	ExitWithError(MEMORY_EXHAUSTED_ABORT);
-    BuildCommand(&cmd, 1024,
-		 mc->testcommand,
-		 TmpFileName,
-		 strlen(TmpFileName));
-    CTRACE(tfp, "PassesTest: Executing test command: %s\n", cmd);
-    result = LYSystem(cmd);
-    FREE(cmd);
-    LYRemoveTemp(TmpFileName);
 
     /*
      *  Free the test command as well since
@@ -584,6 +634,7 @@ PRIVATE int ProcessMailcapFile ARGS1(
 	ProcessMailcapEntry(fp, &mc);
     }
     fclose(fp);
+    RememberTestResult(RTR_forget, NULL, 0);
     return(0 == 0);
 }
 
diff --git a/src/HTML.c b/src/HTML.c
index 6c3ff556..fa12456d 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -11,7 +11,6 @@
 **   Being Overidden
 **
 */
-#define DICKEY_TEST
 
 #include <HTUtils.h>
 
@@ -5217,10 +5216,7 @@ PRIVATE void HTML_start_element ARGS6(
 
     } /* end switch */
 
-#if defined(DICKEY_TEST)
-    if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY)
-#endif
-    {
+    if (HTML_dtd.tags[ElementNumber].contents != SGML_EMPTY) {
 	if (me->skip_stack > 0) {
 	    CTRACE(tfp, "HTML:begin_element: internal call (level %d), leaving on stack - %s\n",
 			me->skip_stack, me->sp->style->name);
@@ -5250,9 +5246,12 @@ PRIVATE void HTML_start_element ARGS6(
 	me->sp[0].tag_number = ElementNumber;
     }
 
-#if defined(DICKEY_TEST) && defined(USE_COLOR_STYLE)
-/* end empty tags straight away */
-	if (HTML_dtd.tags[ElementNumber].contents == SGML_EMPTY)
+#if defined(USE_COLOR_STYLE)
+/* end really empty tags straight away */
+#define REALLY_EMPTY(e) ((HTML_dtd.tags[e].contents == SGML_EMPTY) && \
+			 !(HTML_dtd.tags[e].flags & Tgf_nreie))
+
+	if (REALLY_EMPTY(element_number))
 	{
 		CTRACE(tfp, "STYLE:begin_element:ending EMPTY element style\n");
 #if !defined(USE_HASH)
@@ -6651,9 +6650,7 @@ End_Object:
 	CTRACE(tfp, "CSS:%s (trimmed %s, END_ELEMENT)\n", Style_className, tmp);
     }
 
-#if defined(DICKEY_TEST)
-    if (HTML_dtd.tags[element_number].contents != SGML_EMPTY)
-#endif
+    if (!REALLY_EMPTY(element_number))
     {
 	CTRACE(tfp, "STYLE:end_element: ending non-EMPTY style\n");
 #if !defined(USE_HASH)
diff --git a/src/LYCookie.c b/src/LYCookie.c
index 4c0053cc..869f3d8d 100644
--- a/src/LYCookie.c
+++ b/src/LYCookie.c
@@ -16,7 +16,20 @@
 **   ftp://ds.internic.net/internet-drafts/draft-ietf-http-state-man-mec-03.txt
 **		- FM					1997-08-02
 **
+**	Partially checked against:
+**   http://www.ietf.org/internet-drafts/draft-ietf-http-state-man-mec-10.txt
+**		- kw					1998-12-11
+**
 **  TO DO: (roughly in order of decreasing priority)
+      * Persistent cookies are still experimental.  Presently cookies
+	lose many pieces of information that distinguish
+	version 1 from version 0 cookies.  There is no easy way around
+	that with the current cookie file format.  Ports are currently
+	not stored persistently at all which is clearly wrong.
+      * We currently don't do anything special for unverifiable
+	transactions to third-party hosts.
+      * We currently don't use effective host names or check for
+	Domain=.local.
       * Hex escaping isn't considered at all.  Any semi-colons, commas,
 	or spaces actually in cookie names or values (i.e., not serving
 	as punctuation for the overall Set-Cookie value) should be hex
@@ -92,7 +105,6 @@ struct _cookie {
     int flags;	   /* Various flags */
     time_t expires;/* The time when this cookie expires */
     BOOL quoted;   /* Was a value quoted in the Set-Cookie header? */
-    BOOL from_file; /* Was this cookie loaded from the file jar? - RP */
 };
 typedef struct _cookie cookie;
 
@@ -101,7 +113,7 @@ typedef struct _cookie cookie;
 #define COOKIE_FLAG_EXPIRES_SET 4  /* If set, an expiry date was set */
 #define COOKIE_FLAG_DOMAIN_SET 8   /* If set, an non-default domain was set */
 #define COOKIE_FLAG_PATH_SET 16    /* If set, an non-default path was set */
-#define COOKIE_FLAG_PERSISTENT 32  /* If set, this cookie was persistent */
+#define COOKIE_FLAG_FROM_FILE 32  /* If set, this cookie was persistent */
 
 struct _HTStream
 {
@@ -177,6 +189,7 @@ PRIVATE void LYCookieJar_free NOARGS
 	    FREE(de->domain);
 	    HTList_delete(de->cookie_list);
 	    de->cookie_list = NULL;
+	    FREE(dl->object);
 	}
 	dl = dl->next;
     }
@@ -203,9 +216,9 @@ PRIVATE BOOLEAN host_matches ARGS2(
 
     /*
      *	The following will pass a "dotted tail" match to "a.b.c.e"
-     *	as described in Section 2 of the -05 draft.
+     *	as described in Section 2 of draft-ietf-http-state-man-mec-10.txt.
      */
-    if (*B == '.') {
+    if (*B == '.' && B[1] != '\0' && B[1] != '.' && *A != '.') {
 	int diff = (strlen(A) - strlen(B));
 	if (diff > 0) {
 	    if (!strcmp((A + diff), B))
@@ -385,7 +398,7 @@ PRIVATE void store_cookie ARGS3(
 	de = (domain_entry *)calloc(1, sizeof(domain_entry));
 	if (de == NULL)
 	    outofmem(__FILE__, "store_cookie");
-#ifdef EXP_PERSISTENT_COOKIES
+#if 0	/* was: ifdef EXP_PERSISTENT_COOKIES */
 	/*
 	 * Ok, this is a problem.  The first cookie for a domain
 	 * effectively sets the policy for that whole domain - for
@@ -396,7 +409,7 @@ PRIVATE void store_cookie ARGS3(
 	 * and the path in conjunction makes more sense?  - RP
 	 */
 	if (persistent_cookies
-	 && (co->flags & COOKIE_FLAG_PERSISTENT))
+	 && (co->flags & COOKIE_FLAG_FROM_FILE))
 	    de->bv = FROM_FILE;
 	else
 #endif
@@ -419,7 +432,7 @@ PRIVATE void store_cookie ARGS3(
 	 */
 	if ((c2 != NULL) &&
 	    (c2->flags & COOKIE_FLAG_EXPIRES_SET) &&
-	    c2->expires < now) {
+	    c2->expires <= now) {
 	    HTList_removeObject(cookie_list, c2);
 	    freeCookie(c2);
 	    c2 = NULL;
@@ -438,7 +451,23 @@ PRIVATE void store_cookie ARGS3(
 	    total_cookies--;
 	    Replacement = TRUE;
 
-	} else if ((c2) && (c2->pathlen) > (co->pathlen)) {
+	} else if ((c2) && (c2->pathlen) >= (co->pathlen)) {
+	    /*
+	     *  This comparison determines the (tentative) position
+	     *  of the new cookie in the list such that it comes
+	     *  before existing cookies with a less specific path,
+	     *  but after existing cookies of equal (or greater)
+	     *  path length.  Thus it should normally preserve
+	     *  the order of new cookies with the same path as
+	     *  they are received, although this is not required.
+	     *  From RFC 2109 4.3.4:
+
+   If multiple cookies satisfy the criteria above, they are ordered in
+   the Cookie header such that those with more specific Path
+   attributes precede those with less specific.  Ordering with respect
+   to other attributes (e.g., Domain) is unspecified.
+
+	     */
 	    pos++;
 	}
 	hl = next;
@@ -447,7 +476,7 @@ PRIVATE void store_cookie ARGS3(
     /*
      *	Don't bother to add the cookie if it's already expired.
      */
-    if ((co->flags & COOKIE_FLAG_EXPIRES_SET) && co->expires < now) {
+    if ((co->flags & COOKIE_FLAG_EXPIRES_SET) && co->expires <= now) {
 	freeCookie(co);
 	co = NULL;
 
@@ -487,26 +516,21 @@ PRIVATE void store_cookie ARGS3(
     /*
      *	Get confirmation if we need it, and add cookie
      *	if confirmed or 'allow' is set to always. - FM
+     *
+     *  Cookies read from file are accepted without confirmation
+     *  prompting.  (Prompting may actually not be possible if
+     *  LYLoadCookies is called before curses is setup.)  Maybe
+     *  this should instead depend on LYSetCookies and/or
+     *  LYCookieAcceptDomains and/or LYCookieRejectDomains and/or
+     *  LYAcceptAllCookies and/or some other settings. -kw
      */
-    } else if (HTConfirmCookie(de, hostname, co->name, co->value)) {
-
-#ifdef EXP_PERSISTENT_COOKIES
+    } else if ((persistent_cookies && (co->flags & COOKIE_FLAG_FROM_FILE))
+	       || HTConfirmCookie(de, hostname, co->name, co->value)) {
 	/*
-	 * If the cookie domain came from persistent cookie file,
-	 * we want to add new cookies to the end of the cookie list
-	 * to maintain their order for servers that need cookies in
-	 * a particular order.  This is a hack.
+	 * Insert the new cookie so that more specific paths (longer
+	 * pathlen) come first in the list. - kw
 	 */
-	if (persistent_cookies) {
-	    if ((de->bv = FROM_FILE) != 0) {
-		HTList_appendObject(cookie_list, co);
-	    } else {
-		HTList_insertObjectAt(cookie_list, co, pos);
-	    }
-	}
-#else
 	HTList_insertObjectAt(cookie_list, co, pos);
-#endif /* EXP_PERSISTENT_COOKIES */
 	total_cookies++;
     } else {
 	freeCookie(co);
@@ -542,7 +566,7 @@ PRIVATE char * scan_cookie_sublist ARGS6(
 			    (long)hl,
 			    (co->name ? co->name : "(no name)"),
 			    (co->value ? co->value : "(no value)"));
-	    CTRACE(tfp, "%s %s %d %s %s %d%s\n",
+	    CTRACE(tfp, "\t%s %s %d %s %s %d%s\n",
 			    hostname,
 			    (co->domain ? co->domain : "(no domain)"),
 			    host_matches(hostname, co->domain),
@@ -555,7 +579,7 @@ PRIVATE char * scan_cookie_sublist ARGS6(
 	 *  Check if this cookie has expired, and if so, delete it.
 	 */
 	if (((co) && (co->flags & COOKIE_FLAG_EXPIRES_SET)) &&
-	    co->expires < now) {
+	    co->expires <= now) {
 	    HTList_removeObject(sublist, co);
 	    freeCookie(co);
 	    co = NULL;
@@ -708,6 +732,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
     int NumCookies = 0;
     BOOL MaxAgeAttrSet = FALSE;
     BOOL Quoted = FALSE;
+    BOOLEAN invalidport = FALSE;
 
     if (!(SetCookie && *SetCookie) &&
 	!(SetCookie2 && *SetCookie2)) {
@@ -1052,7 +1077,10 @@ PRIVATE void LYProcessSetCookies ARGS6(
 			    *cp == ',' || *cp == ' ')) {
 			cp++;
 		    }
-		    if (*cp == '\0') {
+		    if (*cp == '\0' && !port_matches(port, value)) {
+			invalidport = TRUE;
+			known_attr = YES;
+		    } else if (*cp == '\0') {
 			StrAllocCopy(cur_cookie->PortList, value);
 			length += strlen(cur_cookie->PortList);
 			known_attr = YES;
@@ -1112,7 +1140,6 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		known_attr = YES;
 		if ((cur_cookie != NULL && !MaxAgeAttrSet) &&
 		     !(cur_cookie->flags & COOKIE_FLAG_EXPIRES_SET)) {
-		    known_attr = YES;
 		    if (value) {
 			cur_cookie->flags |= COOKIE_FLAG_EXPIRES_SET;
 			cur_cookie->expires = LYmktime(value, FALSE);
@@ -1145,7 +1172,8 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		 *  If we've started a cookie, and it's not too big,
 		 *  save it in the CombinedCookies list. - FM
 		 */
-		if (length <= max_cookies_buffer && cur_cookie != NULL) {
+		if (length <= max_cookies_buffer && cur_cookie != NULL &&
+		    !invalidport) {
 		    /*
 		     *	Assume version 1 if not set to that or higher. - FM
 		     */
@@ -1161,7 +1189,12 @@ PRIVATE void LYProcessSetCookies ARGS6(
 				(cur_cookie->value ?
 				 cur_cookie->value : "[no value]"));
 		    CTRACE(tfp,
-			   "                     due to excessive length!\n");
+			   invalidport ?
+			   "                     due to excessive length!\n"
+			 : "                     due to invalid port!\n");
+		    if (invalidport) {
+			NumCookies --;
+		    }
 		    freeCookie(cur_cookie);
 		    cur_cookie = NULL;
 		}
@@ -1169,6 +1202,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		 *  Start a new cookie. - FM
 		 */
 		cur_cookie = newCookie();
+		invalidport = FALSE;
 		length = 0;
 		NumCookies++;
 		MemAllocCopy(&(cur_cookie->name), attr_start, attr_end);
@@ -1193,12 +1227,12 @@ PRIVATE void LYProcessSetCookies ARGS6(
      */
     if (NumCookies <= max_cookies_domain
      && length <= max_cookies_buffer
-     && cur_cookie != NULL) {
+     && cur_cookie != NULL && !invalidport) {
 	if (cur_cookie->version < 1) {
 	    cur_cookie->version = 1;
 	}
 	HTList_appendObject(CombinedCookies, cur_cookie);
-    } else if (cur_cookie != NULL) {
+    } else if (cur_cookie != NULL && !invalidport) {
 	CTRACE(tfp, "LYProcessSetCookies: Rejecting Set-Cookie2: %s=%s\n",
 		    (cur_cookie->name ? cur_cookie->name : "[no name]"),
 		    (cur_cookie->value ? cur_cookie->value : "[no value]"));
@@ -1211,6 +1245,14 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		    (NumCookies > max_cookies_domain ? "number!\n" : "!\n"));
 	freeCookie(cur_cookie);
 	cur_cookie = NULL;
+    } else if (cur_cookie != NULL) {			/* invalidport */
+	CTRACE(tfp, "LYProcessSetCookies: Rejecting Set-Cookie2: %s=%s\n",
+		    (cur_cookie->name ? cur_cookie->name : "[no name]"),
+		    (cur_cookie->value ? cur_cookie->value : "[no value]"));
+	CTRACE(tfp, "                     due to invalid port!\n");
+	NumCookies --;
+	freeCookie(cur_cookie);
+	cur_cookie = NULL;
     }
 
     /*
@@ -1536,7 +1578,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 			    *cp == ',' || *cp == ' ')) {
 			cp++;
 		    }
-		    if (*cp == '\0') {
+		    if (*cp == '\0' && port_matches(port, value)) {
 			StrAllocCopy(cur_cookie->PortList, value);
 			length += strlen(cur_cookie->PortList);
 			known_attr = YES;
@@ -1559,7 +1601,7 @@ PRIVATE void LYProcessSetCookies ARGS6(
 		    /*
 		     *	Don't process a repeat version. - FM
 		     */
-		    cur_cookie->version < 0) {
+		    cur_cookie->version < 1) {
 		    int temp = strtol(value, NULL, 10);
 		    if (errno != -ERANGE) {
 			cur_cookie->version = temp;
@@ -1839,7 +1881,7 @@ PUBLIC char * LYCookie ARGS4(
 		HTList_delete(de->cookie_list);
 		de->cookie_list = NULL;
 		HTList_removeObject(domain_list, de);
-		de = NULL;
+		FREE(de);
 	    }
 	}
 	hl = next;
@@ -1847,21 +1889,12 @@ PUBLIC char * LYCookie ARGS4(
     if (header)
 	return(header);
 
-    /*
-     *	If we didn't set a header, perhaps all the cookies have
-     *	expired and we deleted the last of them above, so check
-     *	if we should delete and NULL the domain_list. - FM
-     */
-    if (domain_list) {
-	if (HTList_isEmpty(domain_list)) {
-	    HTList_delete(domain_list);
-	    domain_list = NULL;
-	}
-    }
     return(NULL);
 }
 
 #ifdef EXP_PERSISTENT_COOKIES
+PRIVATE int number_of_file_cookies = 0;
+
 /* rjp - experiment cookie loading */
 PUBLIC void LYLoadCookies ARGS1 (
 	char *,		cookie_file)
@@ -1891,6 +1924,7 @@ PUBLIC void LYLoadCookies ARGS1 (
 
     CTRACE(tfp, "LYLoadCookies: reading cookies from %s\n", cookie_file);
 
+    number_of_file_cookies = 0;
     while (!feof(cookie_handle)) {
 	cookie *moo;
 	unsigned i = 0;
@@ -1901,9 +1935,13 @@ PUBLIC void LYLoadCookies ARGS1 (
 	j = fgets(buf, sizeof(buf)-1, cookie_handle);
 
 	if((j == NULL) || (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '#')) {
+	    if (j == NULL && ferror(cookie_handle))
+		break;
 	    continue;
 	}
 
+	number_of_file_cookies ++;
+
 	/*
 	 * Strip out the newline that fgets() puts at the end of a
 	 * cookie.
@@ -1929,7 +1967,7 @@ PUBLIC void LYLoadCookies ARGS1 (
 	tok_out = LYstrsep(&tok_ptr, "\t");
 	for (tok_loop = 0; tok_out && tok_values[tok_loop].s; tok_loop++) {
 	    CTRACE(tfp, "\t%d:%p:%p:[%s]\n",
-	        tok_loop, tok_values[tok_loop].s, tok_out, tok_out);
+		tok_loop, tok_values[tok_loop].s, tok_out, tok_out);
 	    LYstrncpy(tok_values[tok_loop].s, tok_out, tok_values[tok_loop].n);
 	    /*
 	     * It looks like strtok ignores a leading delimiter,
@@ -1957,13 +1995,51 @@ PUBLIC void LYLoadCookies ARGS1 (
 	StrAllocCopy(moo->name, name);
 	StrAllocCopy(moo->value, value);
 	moo->pathlen = strlen(moo->path);
-	moo->flags |= COOKIE_FLAG_PERSISTENT;
+	/*
+	 *  Justification for following flags:
+	 *  COOKIE_FLAG_FROM_FILE    So we know were it comes from.
+	 *  COOKIE_FLAG_EXPIRES_SET  It must have had an explicit
+	 *			     expiration originally, otherwise
+	 *			     it would not be in the file.
+	 *  COOKIE_FLAG_DOMAN_SET,   We don't know whether these were
+	 *   COOKIE_FLAG_PATH_SET    explicit or implicit, but this
+	 *			     only matters for sending version 1
+	 *			     cookies; the cookies read from the
+	 *			     file are currently treated all like
+	 *			     version 0 (we don't set moo->version)
+	 *			     so $Domain= and $Path= will normally
+	 *			     not be sent to the server.  But if
+	 *			     these cookies somehow get mixed with
+	 *			     new version 1 cookies we may end up
+	 *			     sending version 1 to the server, and
+	 *			     in that case we should send $Domain
+	 *			     and $Path.  The state-man-mec drafts
+	 *			     and RFC 2109 say that $Domain and
+	 *			     $Path SHOULD be omitted if they were
+	 *			     not given explicitly, but not that
+	 *			     they MUST be omitted.
+	 *			     See 8.2 Cookie Spoofing in draft -10
+	 *			     for a good reason to send them.
+	 *			     However, an explicit domain should be
+	 *			     now prefixed with a dot (unless it is
+	 *			     for a single host), so we check for
+	 *			     that.
+	 *  COOKIE_FLAG_SECURE	     Should have "FALSE" for normal,
+	 *			     otherwise set it.
+	 */
+	moo->flags |= COOKIE_FLAG_FROM_FILE | COOKIE_FLAG_EXPIRES_SET |
+	    		COOKIE_FLAG_PATH_SET;
+	if (domain[0] == '.')
+	    moo->flags |= COOKIE_FLAG_DOMAIN_SET;
+	if (secure[0] != 'F')
+	    moo->flags |= COOKIE_FLAG_SECURE;
+	/* @@@ Should we set port to 443 if secure is set? @@@ */
 	moo->expires = expires;
 	/*
 	 * I don't like using this to store the cookies because it's
 	 * designed to store cookies that have been received from an
 	 * HTTP request, not from a persistent cookie jar.  Hence the
-	 * mucking about with the COOKIE_FLAG_PERSISTENT above. - RP
+	 * mucking about with the COOKIE_FLAG_FROM_FILE above. - RP
 	 */
 	store_cookie(moo, domain, path);
     }
@@ -1986,11 +2062,16 @@ PUBLIC void LYStoreCookies ARGS1 (
     /*
      *	Check whether we have something to do. - FM
      */
-    if (HTList_isEmpty(domain_list)) {
-	/* No cookies, so don't bother updating the file */
+    if (HTList_isEmpty(domain_list) &&
+	number_of_file_cookies == 0) {
+	/* No cookies now, and haven't read any,
+	 * so don't bother updating the file.
+	 */
 	return;
     }
 
+    CTRACE(tfp, "LYStoreCookies: save cookies to %s on exit\n", cookie_file);
+
     cookie_handle = LYNewTxtFile (cookie_file);
     for (dl = domain_list; dl != NULL; dl = dl->next) {
 	de = dl->object;
@@ -2011,7 +2092,7 @@ PUBLIC void LYStoreCookies ARGS1 (
 	case (QUERY_USER):
 	    HTSprintf0(&buf, COOKIES_ALLOWED_VIA_PROMPT);
 	    break;
-	case (FROM_FILE):
+	case (FROM_FILE):	/* not used any more - kw */
 	    HTSprintf0(&buf, gettext("(From Cookie Jar)"));
 	    break;
 	}
@@ -2028,12 +2109,26 @@ PUBLIC void LYStoreCookies ARGS1 (
 	    if ((co = (cookie *)cl->object) == NULL)
 		continue;
 
-	    CTRACE(tfp, "LYStoreCookies: %ld cf %ld\n", (long) now, (long) co->expires);
+	    CTRACE(tfp, "LYStoreCookies: %ld cf %ld ", (long) now, (long) co->expires);
+
+	    if ((co->flags & COOKIE_FLAG_DISCARD)) {
+		CTRACE(tfp, "not stored - DISCARD\n");
+		continue;
+	    } else if (!(co->flags & COOKIE_FLAG_EXPIRES_SET)) {
+		CTRACE(tfp, "not stored - no expiration time\n");
+		continue;
+	    } else if (co->expires <= now) {
+		CTRACE(tfp, "not stored - EXPIRED\n");
+		continue;
+	    }
+
 	    fprintf(cookie_handle, "%s\t%s\t%s\t%s\t%ld\t%s\t%s\n",
 		de->domain,
 		"FALSE", co->path,
 		co->flags & COOKIE_FLAG_SECURE ? "TRUE" : "FALSE",
 		(long) co->expires, co->name, co->value);
+
+	    CTRACE(tfp, "STORED\n");
 	}
     }
     fclose(cookie_handle);
@@ -2081,7 +2176,7 @@ PRIVATE int LYHandleCookies ARGS4 (
     /*
      *	Check whether we have something to do. - FM
      */
-    if (domain_list == NULL) {
+    if (HTList_isEmpty(domain_list)) {
 	HTProgress(COOKIE_JAR_IS_EMPTY);
 	sleep(MessageSecs);
 	return(HT_NO_DATA);
@@ -2120,6 +2215,7 @@ PRIVATE int LYHandleCookies ARGS4 (
 		 */
 		continue;
 	    if (!strcmp(domain, de->domain)) {
+		FREE(domain);
 		/*
 		 *  We found the domain.  Check
 		 *  whether a lynxID is present. - FM
@@ -2159,7 +2255,7 @@ PRIVATE int LYHandleCookies ARGS4 (
 				HTList_delete(de->cookie_list);
 				de->cookie_list = NULL;
 				HTList_removeObject(domain_list, de);
-				de = NULL;
+				FREE(de);
 				HTProgress(DOMAIN_EATEN);
 			    } else {
 				HTProgress(COOKIE_EATEN);
@@ -2194,7 +2290,7 @@ PRIVATE int LYHandleCookies ARGS4 (
 				 *  Set to accept all cookies
 				 *  from this domain. - FM
 				 */
-				de->bv = QUERY_USER;
+				de->bv = ACCEPT_ALWAYS;
 				HTUserMsg2(ALWAYS_ALLOWING_COOKIES,
 					      de->domain);
 				return(HT_NO_DATA);
@@ -2218,7 +2314,7 @@ PRIVATE int LYHandleCookies ARGS4 (
 				    HTList_delete(de->cookie_list);
 				    de->cookie_list = NULL;
 				    HTList_removeObject(domain_list, de);
-				    de = NULL;
+				    FREE(de);
 				    HTProgress(DOMAIN_EATEN);
 				    sleep(MessageSecs);
 				    break;
@@ -2258,7 +2354,7 @@ Delete_all_cookies_in_domain:
 				    HTList_delete(de->cookie_list);
 				    de->cookie_list = NULL;
 				    HTList_removeObject(domain_list, de);
-				    de = NULL;
+				    FREE(de);
 				    HTProgress(DOMAIN_EATEN);
 				    sleep(MessageSecs);
 				}
@@ -2298,14 +2394,14 @@ Delete_all_cookies_in_domain:
 	}
 	if (HTList_isEmpty(domain_list)) {
 	    /*
-	     *	There are no more domains left,
-	     *	so delete the domain_list. - FM
+	     *	There are no more domains left.
+	     *	Don't delete the domain_list, otherwise
+	     *  atexit may be called multiple times. - kw
 	     */
-	    HTList_delete(domain_list);
-	    domain_list = NULL;
 	    HTProgress(ALL_COOKIES_EATEN);
 	    sleep(MessageSecs);
 	}
+	FREE(domain);
 	return(HT_NO_DATA);
     }
 
@@ -2336,7 +2432,7 @@ Delete_all_cookies_in_domain:
     (*target->isa->put_block)(target, buf, strlen(buf));
     HTSprintf0(&buf, "<h1>%s (%s)%s<a href=\"%s%s\">%s</a></h1>\n",
 	LYNX_NAME, LYNX_VERSION,
-        HELP_ON_SEGMENT,
+	HELP_ON_SEGMENT,
 	helpfilepath, COOKIE_JAR_HELP, COOKIE_JAR_TITLE);
     (*target->isa->put_block)(target, buf, strlen(buf));
 
@@ -2372,7 +2468,9 @@ Delete_all_cookies_in_domain:
 		HTSprintf0(&buf, COOKIES_ALLOWED_VIA_PROMPT);
 		break;
 	    case (FROM_FILE):
+#if 0 /* not used any more - kw */
 		HTSprintf0(&buf, COOKIES_READ_FROM_FILE);
+#endif
 		break;
 	}
 	(*target->isa->put_block)(target, buf, strlen(buf));
@@ -2410,6 +2508,11 @@ Delete_all_cookies_in_domain:
 	    FREE(value);
 	    (*target->isa->put_block)(target, buf, strlen(buf));
 
+	    if (co->flags & COOKIE_FLAG_FROM_FILE) {
+		HTSprintf0(&buf, "%s\n", gettext("(from a previous session)"));
+		(*target->isa->put_block)(target, buf, strlen(buf));
+	    }
+
 	    /*
 	     *	Show the path, port, secure and discard setting. - FM
 	     */
@@ -2467,12 +2570,10 @@ Delete_all_cookies_in_domain:
 	     */
 	    HTSprintf0(&buf, "<DD><EM>%s</EM> %s%s",
 	    		 gettext("Maximum Gobble Date:"),
-			 ((co->expires > 0 &&
-			   !(co->flags & COOKIE_FLAG_DISCARD))
+			 ((co->flags & COOKIE_FLAG_EXPIRES_SET)
 					    ?
 			ctime(&co->expires) : END_OF_SESSION),
-			 ((co->expires > 0 &&
-			   !(co->flags & COOKIE_FLAG_DISCARD))
+			 ((co->flags & COOKIE_FLAG_EXPIRES_SET)
 					    ?
 					 "" : "\n"));
 	    (*target->isa->put_block)(target, buf, strlen(buf));
diff --git a/src/LYGetFile.c b/src/LYGetFile.c
index 5ea77c2e..64109c8a 100644
--- a/src/LYGetFile.c
+++ b/src/LYGetFile.c
@@ -354,7 +354,8 @@ Try_Redirected_URL:
 			 *  Bug puts slash on end if none is in the string.
 			 */
 			char *last_slash = strrchr(doc->address,'/');
-			if (last_slash-doc->address==strlen(doc->address)-1)
+			if (last_slash - doc->address
+			 == (int)strlen(doc->address) - 1)
 			    doc->address[strlen(doc->address)-1] = '\0';
 
 			p = doc->address;
diff --git a/src/LYHistory.c b/src/LYHistory.c
index 874099e2..494d6152 100644
--- a/src/LYHistory.c
+++ b/src/LYHistory.c
@@ -394,6 +394,10 @@ PUBLIC int showhistory ARGS1(
 	if (history[x].title != NULL) {
 	    StrAllocCopy(Title, history[x].title);
 	    LYEntify(&Title, TRUE);
+	    LYTrimLeading(Title);
+	    LYTrimTrailing(Title);
+	    if (*Title == '\0')
+		StrAllocCopy(Title , gettext("(no title)"));
 	} else {
 	    StrAllocCopy(Title, gettext("(no title)"));
 	}
@@ -542,6 +546,10 @@ PUBLIC int LYShowVisitedLinks ARGS1(
 	if (vl->title != NULL && *vl->title != '\0') {
 	    StrAllocCopy(Title, vl->title);
 	    LYEntify(&Title, TRUE);
+	    LYTrimLeading(Title);
+	    LYTrimTrailing(Title);
+	    if (*Title == '\0')
+		StrAllocCopy(Title , gettext("(no title)"));
 	} else {
 	    StrAllocCopy(Title , gettext("(no title)"));
 	}
diff --git a/src/LYKeymap.c b/src/LYKeymap.c
index 2d01e830..852799e9 100644
--- a/src/LYKeymap.c
+++ b/src/LYKeymap.c
@@ -41,7 +41,7 @@ struct _HTStream
 /* the character gets 1 added to it before lookup,
  * so that EOF maps to 0
  */
-unsigned short keymap[] = {
+unsigned short keymap[KEYMAP_SIZE] = {
 
 0,
 /* EOF */
@@ -362,7 +362,7 @@ LYK_DO_NOTHING,
    0,                  0,              0,             0,
    0,                  0,              0,             0,
    /* 290...293 */
-   0,                  0,              0,             0,
+   LYK_CHANGE_LINK,    0,              0,             0,
 };
 
 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
@@ -372,7 +372,7 @@ LYK_DO_NOTHING,
  * allowed at compile time.
  */
 
-unsigned short key_override[TABLESIZE(keymap)] = {
+unsigned short key_override[KEYMAP_SIZE] = {
 
     0,
 /* EOF */
@@ -606,6 +606,7 @@ PRIVATE struct rmap revmap[] = {
 { "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" },
 #ifdef USE_EXTERNALS
 { "EXTERN",		"run external program with url" },
 #endif
@@ -664,6 +665,8 @@ PRIVATE char *pretty ARGS1 (int, c)
 		sprintf(buf, "^%c", c|0100);
 	else if (c >= 0400 && (c - 0400) < (int) TABLESIZE(funckey))
 		sprintf(buf, "%s", funckey[c-0400]);
+	else if (c >= 0400)
+		sprintf(buf, "%#x", c);
 	else
 		return 0;
 
@@ -745,11 +748,11 @@ PRIVATE int LYLoadKeymap ARGS4 (
 			  i-' ');  /* uppercase mapping is different */
 	}
     }
-    for (i = 1; i < (int) TABLESIZE(keymap); i++) {
+    for (i = 1; i < KEYMAP_SIZE; i++) {
 	/*
 	 *  LYK_PIPE not implemented yet.
 	 */
-	if ((i > (int) TABLESIZE(keymap) || i <= ' ' || !isalpha(i-1)) &&
+	if ((i >= 0400 || i <= ' ' || !isalpha(i-1)) &&
 	    strcmp(revmap[keymap[i]].name, "PIPE")) {
 	    print_binding(target, buf, i);
 	}
@@ -926,7 +929,7 @@ PUBLIC int lookup_keymap ARGS1(
 {
     size_t i;
 
-    for (i = 1; i < TABLESIZE(keymap); i++) {
+    for (i = 1; i < KEYMAP_SIZE; i++) {
 	if (LYisNonAlnumKeyname(i, func)) {
 	    return i;
 	}
@@ -961,7 +964,7 @@ PUBLIC BOOL LYisNonAlnumKeyname ARGS2(
 {
     if ((ch >= '0' && ch <= '9') ||
         (ch >= 'A' && ch <= 'z') ||
-	ch < 0 || ch > 269)
+	ch < 0 || ch >= KEYMAP_SIZE)
 	return (FALSE);
 
     return(keymap[ch+1] == key_name);
@@ -976,7 +979,7 @@ PUBLIC int LYReverseKeymap ARGS1(
 {
     int i;
 
-    for (i = 1; i < (int) TABLESIZE(keymap); i++) {
+    for (i = 1; i < KEYMAP_SIZE; i++) {
 	if (keymap[i] == key_name) {
 	    return(i - 1);
 	}
diff --git a/src/LYKeymap.h b/src/LYKeymap.h
index a1acced8..2fc192e8 100644
--- a/src/LYKeymap.h
+++ b/src/LYKeymap.h
@@ -17,7 +17,8 @@ extern void set_numbers_as_arrows NOPARAMS;
 extern void set_vi_keys NOPARAMS;
 extern void set_vms_keys NOPARAMS;
 
-extern unsigned short keymap[]; /* main keymap matrix */
+#define KEYMAP_SIZE 661
+extern unsigned short keymap[KEYMAP_SIZE]; /* main keymap matrix */
 
 #ifdef EXP_KEYBOARD_LAYOUT
 extern int current_layout;
@@ -138,4 +139,6 @@ extern unsigned short key_override[];
 #define       LYK_FORM_DOWN     83
 #endif /* NOT_USED */
 
+#define LYK_CHANGE_LINK         90	/* FIXME: make these an enum */
+
 #endif /* LYKEYMAP_H */
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index c38a5d4b..1b5b2739 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -166,6 +166,18 @@ PRIVATE BOOLEAN LYReopenTracelog ARGS1(BOOLEAN *, trace_flag_ptr)
     return TRUE;
 }
 
+PRIVATE void do_change_link ARGS1(
+	char *,		prev_target)
+{
+    /* Is there a mouse-clicked link waiting? */
+    int mouse_tmp = get_mouse_link();
+    /* If yes, use it as the link */
+    if (mouse_tmp != -1) {
+	highlight(OFF, curdoc.link, prev_target);
+	curdoc.link = mouse_tmp;
+    }
+}
+
 /*
  *  Here's where we do all the work.
  *  mainloop is basically just a big switch dependent on the users input.
@@ -2461,6 +2473,10 @@ new_cmd:  /*
 	    }
 	    break;
 
+	case LYK_CHANGE_LINK:
+	    do_change_link(prev_target);
+	    break;
+
 	case LYK_RIGHT_LINK:
 	    if (curdoc.link<nlinks-1 &&
 			links[curdoc.link].ly == links[curdoc.link+1].ly) {
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 6ac5fa41..7b76c618 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -33,13 +33,6 @@ PRIVATE int boolean_choice PARAMS((
 	int		line,
 	int		column,
 	char ** 	choices));
-PRIVATE int popup_choice PARAMS((
-	int		cur_choice,
-	int		line,
-	int		column,
-	char ** 	choices,
-	int		i_length,
-	int		disabled));
 
 #define MAXCHOICES 10
 
@@ -2217,7 +2210,7 @@ PRIVATE int get_popup_choice_number ARGS1(
  *  option via a popup window which functions like
  *  that for selection of options in a form. - FM
  */
-PRIVATE int popup_choice ARGS6(
+PUBLIC int popup_choice ARGS6(
 	int,		cur_choice,
 	int,		line,
 	int,		column,
diff --git a/src/LYOptions.h b/src/LYOptions.h
index c8fdccbd..5fab617d 100644
--- a/src/LYOptions.h
+++ b/src/LYOptions.h
@@ -6,6 +6,13 @@
 extern BOOLEAN term_options; /* for LYgetstr() */
 
 extern void edit_bookmarks NOPARAMS;
+extern  int popup_choice PARAMS((
+	int		cur_choice,
+	int		line,
+	int		column,
+	char ** 	choices,
+	int		i_length,
+	int		disabled));
 
 #ifndef NO_OPTION_FORMS
 extern int postoptions PARAMS((document *newdoc));
diff --git a/src/LYStrings.c b/src/LYStrings.c
index ac24013a..f02c22c5 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -11,6 +11,7 @@
 #include <LYNews.h>
 #include <LYOptions.h>
 #include <LYCharSets.h>
+#include <HTAlert.h>
 #include <HTString.h>
 
 #ifdef DJGPP_KEYHANDLER
@@ -157,6 +158,24 @@ PUBLIC int fancy_mouse ARGS3(
     return cmd;
 }
 
+PRIVATE int XYdist ARGS5(
+    int,	x1,
+    int,	y1,
+    int,	x2,
+    int,	y2,
+    int,	dx2)
+{
+    int xerr = x2 - x1, yerr = y2 - y1;
+
+    if (xerr < 0)
+	xerr = x1 - x2 - dx2;
+    if (xerr < 0)
+	xerr = 0;
+    if (yerr < 0)
+	yerr = -yerr;
+    return xerr + yerr;
+}
+
 /* Given X and Y coordinates of a mouse event, set mouse_link to the
 ** index of the corresponding hyperlink, or set mouse_link to -1 if no
 ** link matches the event.  Returns -1 if no link matched the click,
@@ -164,7 +183,10 @@ PUBLIC int fancy_mouse ARGS3(
 ** link.
 **/
 
-PRIVATE int set_clicked_link ARGS3(int,x,int,y,int,code)
+PRIVATE int set_clicked_link ARGS3(
+    int,	x,
+    int,	y,
+    int,	code)
 {
     int left = 6;
     int right = LYcols-6;
@@ -183,6 +205,8 @@ PRIVATE int set_clicked_link ARGS3(int,x,int,y,int,code)
 	else if (x > right) c = '\b';
 	else c = PGUP;
     } else {
+	int mouse_err = -1, cur_err;
+
 	/* Loop over the links and see if we can get a match */
 	for (i = 0; i < nlinks; i++) {
 	    int len, lx = links[i].lx, is_text = 0;
@@ -199,26 +223,41 @@ PRIVATE int set_clicked_link ARGS3(int,x,int,y,int,code)
 		len = strlen(links[i].hightext );
 
 	    /* Check the first line of the link */
-	    if ( links[i].hightext != NULL &&
-		links[i].ly == y && (x - lx) < len && (x >= lx)) {
-		int cury, curx;
-
-		if (code != FOR_INPUT
-		    /* Do not pick up the current input field */
-		    || !(LYGetYX(cury,curx),
-			 (cury == y && (curx >= lx) && ((curx - lx) <= len)))) {
-		    if (is_text)
-			have_levent = 1;
+	    if ( links[i].hightext != NULL) {
+		cur_err = XYdist(x, y, links[i].lx, links[i].ly, len);
+		if (cur_err == 0) {
+		    int cury, curx;
+
+		    if (code != FOR_INPUT
+			/* Do not pick up the current input field */
+			|| !(LYGetYX(cury,curx),
+			     (cury == y && (curx >= lx) && ((curx - lx) <= len)))) {
+			if (is_text)
+			    have_levent = 1;
+			mouse_link = i;
+		    } else
+			mouse_link = -1;
+		    mouse_err = 0;
+		    break;
+		} else if (cur_err < mouse_err) {
+		    mouse_err = cur_err;
 		    mouse_link = i;
 		}
-		break;
 	    }
 	    /* Check the second line */
-	    if (links[i].hightext2 != NULL &&
-		1+links[i].ly == y &&
-		(x - links[i].hightext2_offset) < (int)strlen(links[i].hightext2) ) {
-		mouse_link = i;
-		break;
+	    if (links[i].hightext2 != NULL) {
+		cur_err = XYdist(x, y,
+				 links[i].hightext2_offset,
+				 links[i].ly+1,
+				 strlen(links[i].hightext2));
+		if (cur_err == 0) {
+		    mouse_link = i;
+		    mouse_err = 0;
+		    break;
+		} else if (cur_err < mouse_err) {
+		    mouse_err = cur_err;
+		    mouse_link = i;
+		}
 	    }
 	}
 	/*
@@ -226,8 +265,12 @@ PRIVATE int set_clicked_link ARGS3(int,x,int,y,int,code)
 	 * LYK_ACTIVATE We expect to find LYK_ACTIVATE (it's usually mapped to
 	 * the Enter key).
 	 */
-	if (mouse_link >= 0)
-	    c = lookup_keymap(LYK_ACTIVATE);
+	if (mouse_link >= 0) {
+	    if (mouse_err == 0)
+		c = lookup_keymap(LYK_ACTIVATE);
+	    else if (mouse_err >= 0)
+		c = lookup_keymap(LYK_CHANGE_LINK);
+	}
     }
     return c;
 }
@@ -911,6 +954,89 @@ PUBLIC int lynx_initialize_keymaps NOARGS
 
 #endif				       /* USE_KEYMAPS */
 
+#ifdef NCURSES_MOUSE_VERSION
+PRIVATE int LYmouse_menu ARGS3(int, x, int, y, int, atlink)
+{
+    char *choices[] = {
+	"Quit",
+	"Home page",
+	"Previous document",
+	"Beginning of document",
+	"Page up",
+	"Half page up",
+	"Two lines up",
+	"History",
+	"Help",
+	"Do nothing (refresh)",
+	"Load again",
+	"Edit URL and load",
+	"Show info",
+	"Search",
+	"Print",
+	"Two lines down",
+	"Half page down",
+	"Page down",
+	"End of document",
+	"Bookmarks",
+ 	"Cookie jar",
+	"Search index",
+	"Set Options",
+	NULL
+    };
+    char *choices_link[] = {
+	"Help",
+	"Do nothing",
+	"Activate this link",
+	"Show info",
+	"Download",
+	NULL
+    };
+    int actions[] = {
+	LYK_ABORT,
+	LYK_MAIN_MENU,
+	LYK_PREV_DOC,
+	LYK_HOME,
+	LYK_PREV_PAGE,
+	LYK_UP_HALF,
+	LYK_UP_TWO,
+	LYK_HISTORY,
+	LYK_HELP,
+	LYK_REFRESH,
+	LYK_RELOAD,
+	LYK_ECGOTO,
+	LYK_INFO,
+	LYK_WHEREIS,
+	LYK_PRINT,
+	LYK_DOWN_TWO,
+	LYK_DOWN_HALF,
+	LYK_NEXT_PAGE,
+	LYK_END,
+	LYK_VIEW_BOOKMARK,
+ 	LYK_COOKIE_JAR,
+	LYK_INDEX_SEARCH,
+	LYK_OPTIONS
+    };
+    int actions_link[] = {
+	LYK_HELP,
+	LYK_REFRESH,
+	LYK_ACTIVATE,
+	LYK_INFO,
+	LYK_DOWNLOAD
+    };
+    int c;
+
+    /* Somehow the mouse is over the number instead of being over the
+       name, so we decrease x. */
+    c = popup_choice((atlink ? 2 : 9) - 1, y, (x >= 5 ? x-5 : 0),
+		     (atlink ? choices_link : choices),
+		     (atlink
+		      ? (sizeof(actions_link)/sizeof(int))
+		      : (sizeof(actions)/sizeof(int))), FALSE);
+
+    return atlink ? (actions_link[c]) : (actions[c]);
+}
+#endif
+
 #if defined(USE_KEYMAPS) && defined(USE_SLANG)
 
 /* We cannot guarantee the type for 'GetChar', and should not use a cast. */
@@ -1274,6 +1400,23 @@ re_read:
 			c = LYReverseKeymap(LYK_MAIN_MENU);
 		} else if (event.bstate & BUTTON3_CLICKED) {
 		    c = LYReverseKeymap (LYK_PREV_DOC);
+		} else if (event.bstate & BUTTON2_CLICKED) {
+		    int atlink;
+
+		    c = set_clicked_link(event.x, event.y, code);
+		    atlink = c == LYReverseKeymap (LYK_ACTIVATE);
+		    if (!atlink)
+			mouse_link = -1; /* Forget about approx stuff. */
+
+		    c = LYmouse_menu(event.x, event.y, atlink);
+		    if (c == LYK_ACTIVATE && mouse_link == -1) {
+			HTAlert("No link chosen");
+			c = LYK_DO_NOTHING;
+			c = LYK_REFRESH; /* refresh() below does not work... */
+		    }
+		    c = LYReverseKeymap(c);
+		    lynx_force_repaint();
+		    refresh();
 		}
 		if (code == FOR_INPUT && mouse_link == -1) {
 		    ungetmouse(&event);	/* Caller will process this. */
@@ -1369,12 +1512,7 @@ re_read:
     }
 #endif /* USE_SLANG && __DJGPP__ && !DJGPP_KEYHANDLER && !USE_KEYMAPS */
 
-#if (defined(__DJGPP__) || defined(_WINDOWS))
-    if (c > 659)
-#else
-    if (c > DO_NOTHING)
-#endif /* __DJGPP__ || _WINDOWS */
-    {
+    if ((c+1) >= KEYMAP_SIZE) {
 	/*
 	 *  Don't return raw values for KEYPAD symbols which we may have
 	 *  missed in the switch above if they are obviously invalid when
@@ -2425,6 +2563,44 @@ PUBLIC char * SNACat ARGS3(
     return *dest;
 }
 
+#include <caselower.h>
+
+/*
+ * Returns lowercase equivalent for unicode,
+ * transparent output if no equivalent found.
+ */
+PRIVATE long UniToLowerCase ARGS1(long, upper)
+{
+    size_t i, high, low;
+    long diff = 0;
+
+    /*
+     *	Make check for sure.
+     */
+    if (upper <= 0)
+	return(upper);
+
+    /*
+     *	Try unicode_to_lower_case[].
+     */
+    low = 0;
+    high = sizeof(unicode_to_lower_case)/sizeof(unicode_to_lower_case[0]);
+    while (low < high) {
+	/*
+	**  Binary search.
+	*/
+	i = (low + (high-low)/2);
+	diff = (unicode_to_lower_case[i].upper - upper);
+	if (diff < 0)
+	    low = i+1;
+	if (diff > 0)
+	    high = i;
+	if (diff == 0)
+	    return (unicode_to_lower_case[i].lower);
+    }
+
+    return(upper); /* if we came here */
+}
 
 /*
 **   UPPER8 ?
@@ -2432,11 +2608,40 @@ PUBLIC char * SNACat ARGS3(
 **
 **   It was realized that case-insensitive user search
 **   got information about upper/lower mapping from TOUPPER
-**   (precisely from "(TOUPPER(a) - TOUPPER(b))==0").
-**   This function depends on locale in its 8bit mapping
-**   and usually fails with DOS/WINDOWS display charsets
+**   (precisely from "(TOUPPER(a) - TOUPPER(b))==0")
+**   and depends on locale in its 8bit mapping. -
+**   Usually fails with DOS/WINDOWS display charsets
 **   as well as on non-UNIX systems.
 **
+**   So use unicode case mapping.
+*/
+PUBLIC int UPPER8 ARGS2(int,ch1, int,ch2)
+{
+
+    /* case-insensitive match for us-ascii */
+    if ((unsigned char)TOASCII(ch1) < 128 && (unsigned char)TOASCII(ch2) < 128)
+	return(TOUPPER(ch1) - TOUPPER(ch2));
+
+    /* case-insensitive match for upper half */
+    if ((unsigned char)TOASCII(ch1) > 127 &&  /* S/390 -- gil -- 2066 */
+	(unsigned char)TOASCII(ch2) > 127)
+    {
+	if (DisplayCharsetMatchLocale)
+	   return(TOUPPER(ch1) - TOUPPER(ch2)); /* old-style */
+	else
+	{
+	long uni_ch1 = UCTransToUni(ch1, current_char_set);
+	long uni_ch2 = UCTransToUni(ch2, current_char_set);
+	return(UniToLowerCase(uni_ch1) - UniToLowerCase(uni_ch2));
+	}
+    }
+
+    return(-10);  /* mismatch, if we come to here */
+}
+
+
+#ifdef NOTUSED
+/*
 **   We extend this function for 8bit letters
 **   using Lynx internal chartrans feature:
 **   we assume that upper/lower case letters
@@ -2496,3 +2701,4 @@ PUBLIC int UPPER8 ARGS2(int,ch1, int,ch2)
 
     return(-10);  /* mismatch, if we come to here */
 }
+#endif /* NOTUSED */
diff --git a/src/chrtrans/caselower.h b/src/chrtrans/caselower.h
new file mode 100644
index 00000000..df42c073
--- /dev/null
+++ b/src/chrtrans/caselower.h
@@ -0,0 +1,737 @@
+/*
+  Lynx uses this info for 8bit case-insensitive user search.
+
+  This table is generated from Unicode Character Database, Version 2.1.5
+  available from ftp.unicode.org, and looks as natural way to get case mapping
+  equivalents for unicodes.  (well, too much characters the cost of 3 Kb only).
+  Few words from the original README.txt quoted:
+
+
+UNICODE 2.1 CHARACTER DATABASE
+
+Copyright (c) 1991-1998 Unicode, Inc.
+All Rights reserved.
+
+
+CASE MAPPINGS
+
+The case mapping is an informative, default mapping. Certain languages, such
+as Turkish, German, French, or Greek may have small deviations from the
+default mappings listed in the Unicode Character Database.
+
+ */
+
+
+typedef struct {
+	long upper;
+	long lower;
+} unipair;
+
+static CONST unipair unicode_to_lower_case[] =
+{
+  {0x0041, 0x0061},  /* LATIN CAPITAL LETTER A */
+  {0x0042, 0x0062},  /* LATIN CAPITAL LETTER B */
+  {0x0043, 0x0063},  /* LATIN CAPITAL LETTER C */
+  {0x0044, 0x0064},  /* LATIN CAPITAL LETTER D */
+  {0x0045, 0x0065},  /* LATIN CAPITAL LETTER E */
+  {0x0046, 0x0066},  /* LATIN CAPITAL LETTER F */
+  {0x0047, 0x0067},  /* LATIN CAPITAL LETTER G */
+  {0x0048, 0x0068},  /* LATIN CAPITAL LETTER H */
+  {0x0049, 0x0069},  /* LATIN CAPITAL LETTER I */
+  {0x004A, 0x006A},  /* LATIN CAPITAL LETTER J */
+  {0x004B, 0x006B},  /* LATIN CAPITAL LETTER K */
+  {0x004C, 0x006C},  /* LATIN CAPITAL LETTER L */
+  {0x004D, 0x006D},  /* LATIN CAPITAL LETTER M */
+  {0x004E, 0x006E},  /* LATIN CAPITAL LETTER N */
+  {0x004F, 0x006F},  /* LATIN CAPITAL LETTER O */
+  {0x0050, 0x0070},  /* LATIN CAPITAL LETTER P */
+  {0x0051, 0x0071},  /* LATIN CAPITAL LETTER Q */
+  {0x0052, 0x0072},  /* LATIN CAPITAL LETTER R */
+  {0x0053, 0x0073},  /* LATIN CAPITAL LETTER S */
+  {0x0054, 0x0074},  /* LATIN CAPITAL LETTER T */
+  {0x0055, 0x0075},  /* LATIN CAPITAL LETTER U */
+  {0x0056, 0x0076},  /* LATIN CAPITAL LETTER V */
+  {0x0057, 0x0077},  /* LATIN CAPITAL LETTER W */
+  {0x0058, 0x0078},  /* LATIN CAPITAL LETTER X */
+  {0x0059, 0x0079},  /* LATIN CAPITAL LETTER Y */
+  {0x005A, 0x007A},  /* LATIN CAPITAL LETTER Z */
+  {0x00C0, 0x00E0},  /* LATIN CAPITAL LETTER A WITH GRAVE */
+  {0x00C1, 0x00E1},  /* LATIN CAPITAL LETTER A WITH ACUTE */
+  {0x00C2, 0x00E2},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+  {0x00C3, 0x00E3},  /* LATIN CAPITAL LETTER A WITH TILDE */
+  {0x00C4, 0x00E4},  /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+  {0x00C5, 0x00E5},  /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+  {0x00C6, 0x00E6},  /* LATIN CAPITAL LETTER AE */
+  {0x00C7, 0x00E7},  /* LATIN CAPITAL LETTER C WITH CEDILLA */
+  {0x00C8, 0x00E8},  /* LATIN CAPITAL LETTER E WITH GRAVE */
+  {0x00C9, 0x00E9},  /* LATIN CAPITAL LETTER E WITH ACUTE */
+  {0x00CA, 0x00EA},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+  {0x00CB, 0x00EB},  /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+  {0x00CC, 0x00EC},  /* LATIN CAPITAL LETTER I WITH GRAVE */
+  {0x00CD, 0x00ED},  /* LATIN CAPITAL LETTER I WITH ACUTE */
+  {0x00CE, 0x00EE},  /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+  {0x00CF, 0x00EF},  /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+  {0x00D0, 0x00F0},  /* LATIN CAPITAL LETTER ETH */
+  {0x00D1, 0x00F1},  /* LATIN CAPITAL LETTER N WITH TILDE */
+  {0x00D2, 0x00F2},  /* LATIN CAPITAL LETTER O WITH GRAVE */
+  {0x00D3, 0x00F3},  /* LATIN CAPITAL LETTER O WITH ACUTE */
+  {0x00D4, 0x00F4},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+  {0x00D5, 0x00F5},  /* LATIN CAPITAL LETTER O WITH TILDE */
+  {0x00D6, 0x00F6},  /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+  {0x00D8, 0x00F8},  /* LATIN CAPITAL LETTER O WITH STROKE */
+  {0x00D9, 0x00F9},  /* LATIN CAPITAL LETTER U WITH GRAVE */
+  {0x00DA, 0x00FA},  /* LATIN CAPITAL LETTER U WITH ACUTE */
+  {0x00DB, 0x00FB},  /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+  {0x00DC, 0x00FC},  /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+  {0x00DD, 0x00FD},  /* LATIN CAPITAL LETTER Y WITH ACUTE */
+  {0x00DE, 0x00FE},  /* LATIN CAPITAL LETTER THORN */
+  {0x0100, 0x0101},  /* LATIN CAPITAL LETTER A WITH MACRON */
+  {0x0102, 0x0103},  /* LATIN CAPITAL LETTER A WITH BREVE */
+  {0x0104, 0x0105},  /* LATIN CAPITAL LETTER A WITH OGONEK */
+  {0x0106, 0x0107},  /* LATIN CAPITAL LETTER C WITH ACUTE */
+  {0x0108, 0x0109},  /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+  {0x010A, 0x010B},  /* LATIN CAPITAL LETTER C WITH DOT ABOVE */
+  {0x010C, 0x010D},  /* LATIN CAPITAL LETTER C WITH CARON */
+  {0x010E, 0x010F},  /* LATIN CAPITAL LETTER D WITH CARON */
+  {0x0110, 0x0111},  /* LATIN CAPITAL LETTER D WITH STROKE */
+  {0x0112, 0x0113},  /* LATIN CAPITAL LETTER E WITH MACRON */
+  {0x0114, 0x0115},  /* LATIN CAPITAL LETTER E WITH BREVE */
+  {0x0116, 0x0117},  /* LATIN CAPITAL LETTER E WITH DOT ABOVE */
+  {0x0118, 0x0119},  /* LATIN CAPITAL LETTER E WITH OGONEK */
+  {0x011A, 0x011B},  /* LATIN CAPITAL LETTER E WITH CARON */
+  {0x011C, 0x011D},  /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+  {0x011E, 0x011F},  /* LATIN CAPITAL LETTER G WITH BREVE */
+  {0x0120, 0x0121},  /* LATIN CAPITAL LETTER G WITH DOT ABOVE */
+  {0x0122, 0x0123},  /* LATIN CAPITAL LETTER G WITH CEDILLA */
+  {0x0124, 0x0125},  /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+  {0x0126, 0x0127},  /* LATIN CAPITAL LETTER H WITH STROKE */
+  {0x0128, 0x0129},  /* LATIN CAPITAL LETTER I WITH TILDE */
+  {0x012A, 0x012B},  /* LATIN CAPITAL LETTER I WITH MACRON */
+  {0x012C, 0x012D},  /* LATIN CAPITAL LETTER I WITH BREVE */
+  {0x012E, 0x012F},  /* LATIN CAPITAL LETTER I WITH OGONEK */
+  {0x0130, 0x0069},  /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+  {0x0132, 0x0133},  /* LATIN CAPITAL LIGATURE IJ */
+  {0x0134, 0x0135},  /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+  {0x0136, 0x0137},  /* LATIN CAPITAL LETTER K WITH CEDILLA */
+  {0x0139, 0x013A},  /* LATIN CAPITAL LETTER L WITH ACUTE */
+  {0x013B, 0x013C},  /* LATIN CAPITAL LETTER L WITH CEDILLA */
+  {0x013D, 0x013E},  /* LATIN CAPITAL LETTER L WITH CARON */
+  {0x013F, 0x0140},  /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */
+  {0x0141, 0x0142},  /* LATIN CAPITAL LETTER L WITH STROKE */
+  {0x0143, 0x0144},  /* LATIN CAPITAL LETTER N WITH ACUTE */
+  {0x0145, 0x0146},  /* LATIN CAPITAL LETTER N WITH CEDILLA */
+  {0x0147, 0x0148},  /* LATIN CAPITAL LETTER N WITH CARON */
+  {0x014A, 0x014B},  /* LATIN CAPITAL LETTER ENG */
+  {0x014C, 0x014D},  /* LATIN CAPITAL LETTER O WITH MACRON */
+  {0x014E, 0x014F},  /* LATIN CAPITAL LETTER O WITH BREVE */
+  {0x0150, 0x0151},  /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+  {0x0152, 0x0153},  /* LATIN CAPITAL LIGATURE OE */
+  {0x0154, 0x0155},  /* LATIN CAPITAL LETTER R WITH ACUTE */
+  {0x0156, 0x0157},  /* LATIN CAPITAL LETTER R WITH CEDILLA */
+  {0x0158, 0x0159},  /* LATIN CAPITAL LETTER R WITH CARON */
+  {0x015A, 0x015B},  /* LATIN CAPITAL LETTER S WITH ACUTE */
+  {0x015C, 0x015D},  /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+  {0x015E, 0x015F},  /* LATIN CAPITAL LETTER S WITH CEDILLA */
+  {0x0160, 0x0161},  /* LATIN CAPITAL LETTER S WITH CARON */
+  {0x0162, 0x0163},  /* LATIN CAPITAL LETTER T WITH CEDILLA */
+  {0x0164, 0x0165},  /* LATIN CAPITAL LETTER T WITH CARON */
+  {0x0166, 0x0167},  /* LATIN CAPITAL LETTER T WITH STROKE */
+  {0x0168, 0x0169},  /* LATIN CAPITAL LETTER U WITH TILDE */
+  {0x016A, 0x016B},  /* LATIN CAPITAL LETTER U WITH MACRON */
+  {0x016C, 0x016D},  /* LATIN CAPITAL LETTER U WITH BREVE */
+  {0x016E, 0x016F},  /* LATIN CAPITAL LETTER U WITH RING ABOVE */
+  {0x0170, 0x0171},  /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+  {0x0172, 0x0173},  /* LATIN CAPITAL LETTER U WITH OGONEK */
+  {0x0174, 0x0175},  /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
+  {0x0176, 0x0177},  /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
+  {0x0178, 0x00FF},  /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+  {0x0179, 0x017A},  /* LATIN CAPITAL LETTER Z WITH ACUTE */
+  {0x017B, 0x017C},  /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+  {0x017D, 0x017E},  /* LATIN CAPITAL LETTER Z WITH CARON */
+  {0x0181, 0x0253},  /* LATIN CAPITAL LETTER B WITH HOOK */
+  {0x0182, 0x0183},  /* LATIN CAPITAL LETTER B WITH TOPBAR */
+  {0x0184, 0x0185},  /* LATIN CAPITAL LETTER TONE SIX */
+  {0x0186, 0x0254},  /* LATIN CAPITAL LETTER OPEN O */
+  {0x0187, 0x0188},  /* LATIN CAPITAL LETTER C WITH HOOK */
+  {0x0189, 0x0256},  /* LATIN CAPITAL LETTER AFRICAN D */
+  {0x018A, 0x0257},  /* LATIN CAPITAL LETTER D WITH HOOK */
+  {0x018B, 0x018C},  /* LATIN CAPITAL LETTER D WITH TOPBAR */
+  {0x018E, 0x01DD},  /* LATIN CAPITAL LETTER REVERSED E */
+  {0x018F, 0x0259},  /* LATIN CAPITAL LETTER SCHWA */
+  {0x0190, 0x025B},  /* LATIN CAPITAL LETTER OPEN E */
+  {0x0191, 0x0192},  /* LATIN CAPITAL LETTER F WITH HOOK */
+  {0x0193, 0x0260},  /* LATIN CAPITAL LETTER G WITH HOOK */
+  {0x0194, 0x0263},  /* LATIN CAPITAL LETTER GAMMA */
+  {0x0196, 0x0269},  /* LATIN CAPITAL LETTER IOTA */
+  {0x0197, 0x0268},  /* LATIN CAPITAL LETTER I WITH STROKE */
+  {0x0198, 0x0199},  /* LATIN CAPITAL LETTER K WITH HOOK */
+  {0x019C, 0x026F},  /* LATIN CAPITAL LETTER TURNED M */
+  {0x019D, 0x0272},  /* LATIN CAPITAL LETTER N WITH LEFT HOOK */
+  {0x019F, 0x0275},  /* LATIN CAPITAL LETTER O WITH MIDDLE TILDE */
+  {0x01A0, 0x01A1},  /* LATIN CAPITAL LETTER O WITH HORN */
+  {0x01A2, 0x01A3},  /* LATIN CAPITAL LETTER OI */
+  {0x01A4, 0x01A5},  /* LATIN CAPITAL LETTER P WITH HOOK */
+  {0x01A7, 0x01A8},  /* LATIN CAPITAL LETTER TONE TWO */
+  {0x01A9, 0x0283},  /* LATIN CAPITAL LETTER ESH */
+  {0x01AC, 0x01AD},  /* LATIN CAPITAL LETTER T WITH HOOK */
+  {0x01AE, 0x0288},  /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK */
+  {0x01AF, 0x01B0},  /* LATIN CAPITAL LETTER U WITH HORN */
+  {0x01B1, 0x028A},  /* LATIN CAPITAL LETTER UPSILON */
+  {0x01B2, 0x028B},  /* LATIN CAPITAL LETTER V WITH HOOK */
+  {0x01B3, 0x01B4},  /* LATIN CAPITAL LETTER Y WITH HOOK */
+  {0x01B5, 0x01B6},  /* LATIN CAPITAL LETTER Z WITH STROKE */
+  {0x01B7, 0x0292},  /* LATIN CAPITAL LETTER EZH */
+  {0x01B8, 0x01B9},  /* LATIN CAPITAL LETTER EZH REVERSED */
+  {0x01BC, 0x01BD},  /* LATIN CAPITAL LETTER TONE FIVE */
+  {0x01C4, 0x01C6},  /* LATIN CAPITAL LETTER DZ WITH CARON */
+  {0x01C5, 0x01C6},  /* LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON */
+  {0x01C7, 0x01C9},  /* LATIN CAPITAL LETTER LJ */
+  {0x01C8, 0x01C9},  /* LATIN CAPITAL LETTER L WITH SMALL LETTER J */
+  {0x01CA, 0x01CC},  /* LATIN CAPITAL LETTER NJ */
+  {0x01CB, 0x01CC},  /* LATIN CAPITAL LETTER N WITH SMALL LETTER J */
+  {0x01CD, 0x01CE},  /* LATIN CAPITAL LETTER A WITH CARON */
+  {0x01CF, 0x01D0},  /* LATIN CAPITAL LETTER I WITH CARON */
+  {0x01D1, 0x01D2},  /* LATIN CAPITAL LETTER O WITH CARON */
+  {0x01D3, 0x01D4},  /* LATIN CAPITAL LETTER U WITH CARON */
+  {0x01D5, 0x01D6},  /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON */
+  {0x01D7, 0x01D8},  /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE */
+  {0x01D9, 0x01DA},  /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON */
+  {0x01DB, 0x01DC},  /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE */
+  {0x01DE, 0x01DF},  /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */
+  {0x01E0, 0x01E1},  /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON */
+  {0x01E2, 0x01E3},  /* LATIN CAPITAL LETTER AE WITH MACRON */
+  {0x01E4, 0x01E5},  /* LATIN CAPITAL LETTER G WITH STROKE */
+  {0x01E6, 0x01E7},  /* LATIN CAPITAL LETTER G WITH CARON */
+  {0x01E8, 0x01E9},  /* LATIN CAPITAL LETTER K WITH CARON */
+  {0x01EA, 0x01EB},  /* LATIN CAPITAL LETTER O WITH OGONEK */
+  {0x01EC, 0x01ED},  /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON */
+  {0x01EE, 0x01EF},  /* LATIN CAPITAL LETTER EZH WITH CARON */
+  {0x01F1, 0x01F3},  /* LATIN CAPITAL LETTER DZ */
+  {0x01F2, 0x01F3},  /* LATIN CAPITAL LETTER D WITH SMALL LETTER Z */
+  {0x01F4, 0x01F5},  /* LATIN CAPITAL LETTER G WITH ACUTE */
+  {0x01FA, 0x01FB},  /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */
+  {0x01FC, 0x01FD},  /* LATIN CAPITAL LETTER AE WITH ACUTE */
+  {0x01FE, 0x01FF},  /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */
+  {0x0200, 0x0201},  /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE */
+  {0x0202, 0x0203},  /* LATIN CAPITAL LETTER A WITH INVERTED BREVE */
+  {0x0204, 0x0205},  /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE */
+  {0x0206, 0x0207},  /* LATIN CAPITAL LETTER E WITH INVERTED BREVE */
+  {0x0208, 0x0209},  /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE */
+  {0x020A, 0x020B},  /* LATIN CAPITAL LETTER I WITH INVERTED BREVE */
+  {0x020C, 0x020D},  /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE */
+  {0x020E, 0x020F},  /* LATIN CAPITAL LETTER O WITH INVERTED BREVE */
+  {0x0210, 0x0211},  /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE */
+  {0x0212, 0x0213},  /* LATIN CAPITAL LETTER R WITH INVERTED BREVE */
+  {0x0214, 0x0215},  /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE */
+  {0x0216, 0x0217},  /* LATIN CAPITAL LETTER U WITH INVERTED BREVE */
+  {0x0386, 0x03AC},  /* GREEK CAPITAL LETTER ALPHA WITH TONOS */
+  {0x0388, 0x03AD},  /* GREEK CAPITAL LETTER EPSILON WITH TONOS */
+  {0x0389, 0x03AE},  /* GREEK CAPITAL LETTER ETA WITH TONOS */
+  {0x038A, 0x03AF},  /* GREEK CAPITAL LETTER IOTA WITH TONOS */
+  {0x038C, 0x03CC},  /* GREEK CAPITAL LETTER OMICRON WITH TONOS */
+  {0x038E, 0x03CD},  /* GREEK CAPITAL LETTER UPSILON WITH TONOS */
+  {0x038F, 0x03CE},  /* GREEK CAPITAL LETTER OMEGA WITH TONOS */
+  {0x0391, 0x03B1},  /* GREEK CAPITAL LETTER ALPHA */
+  {0x0392, 0x03B2},  /* GREEK CAPITAL LETTER BETA */
+  {0x0393, 0x03B3},  /* GREEK CAPITAL LETTER GAMMA */
+  {0x0394, 0x03B4},  /* GREEK CAPITAL LETTER DELTA */
+  {0x0395, 0x03B5},  /* GREEK CAPITAL LETTER EPSILON */
+  {0x0396, 0x03B6},  /* GREEK CAPITAL LETTER ZETA */
+  {0x0397, 0x03B7},  /* GREEK CAPITAL LETTER ETA */
+  {0x0398, 0x03B8},  /* GREEK CAPITAL LETTER THETA */
+  {0x0399, 0x03B9},  /* GREEK CAPITAL LETTER IOTA */
+  {0x039A, 0x03BA},  /* GREEK CAPITAL LETTER KAPPA */
+  {0x039B, 0x03BB},  /* GREEK CAPITAL LETTER LAMDA */
+  {0x039C, 0x03BC},  /* GREEK CAPITAL LETTER MU */
+  {0x039D, 0x03BD},  /* GREEK CAPITAL LETTER NU */
+  {0x039E, 0x03BE},  /* GREEK CAPITAL LETTER XI */
+  {0x039F, 0x03BF},  /* GREEK CAPITAL LETTER OMICRON */
+  {0x03A0, 0x03C0},  /* GREEK CAPITAL LETTER PI */
+  {0x03A1, 0x03C1},  /* GREEK CAPITAL LETTER RHO */
+  {0x03A3, 0x03C3},  /* GREEK CAPITAL LETTER SIGMA */
+  {0x03A4, 0x03C4},  /* GREEK CAPITAL LETTER TAU */
+  {0x03A5, 0x03C5},  /* GREEK CAPITAL LETTER UPSILON */
+  {0x03A6, 0x03C6},  /* GREEK CAPITAL LETTER PHI */
+  {0x03A7, 0x03C7},  /* GREEK CAPITAL LETTER CHI */
+  {0x03A8, 0x03C8},  /* GREEK CAPITAL LETTER PSI */
+  {0x03A9, 0x03C9},  /* GREEK CAPITAL LETTER OMEGA */
+  {0x03AA, 0x03CA},  /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+  {0x03AB, 0x03CB},  /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+  {0x03E2, 0x03E3},  /* COPTIC CAPITAL LETTER SHEI */
+  {0x03E4, 0x03E5},  /* COPTIC CAPITAL LETTER FEI */
+  {0x03E6, 0x03E7},  /* COPTIC CAPITAL LETTER KHEI */
+  {0x03E8, 0x03E9},  /* COPTIC CAPITAL LETTER HORI */
+  {0x03EA, 0x03EB},  /* COPTIC CAPITAL LETTER GANGIA */
+  {0x03EC, 0x03ED},  /* COPTIC CAPITAL LETTER SHIMA */
+  {0x03EE, 0x03EF},  /* COPTIC CAPITAL LETTER DEI */
+  {0x0401, 0x0451},  /* CYRILLIC CAPITAL LETTER IO */
+  {0x0402, 0x0452},  /* CYRILLIC CAPITAL LETTER DJE */
+  {0x0403, 0x0453},  /* CYRILLIC CAPITAL LETTER GJE */
+  {0x0404, 0x0454},  /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+  {0x0405, 0x0455},  /* CYRILLIC CAPITAL LETTER DZE */
+  {0x0406, 0x0456},  /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+  {0x0407, 0x0457},  /* CYRILLIC CAPITAL LETTER YI */
+  {0x0408, 0x0458},  /* CYRILLIC CAPITAL LETTER JE */
+  {0x0409, 0x0459},  /* CYRILLIC CAPITAL LETTER LJE */
+  {0x040A, 0x045A},  /* CYRILLIC CAPITAL LETTER NJE */
+  {0x040B, 0x045B},  /* CYRILLIC CAPITAL LETTER TSHE */
+  {0x040C, 0x045C},  /* CYRILLIC CAPITAL LETTER KJE */
+  {0x040E, 0x045E},  /* CYRILLIC CAPITAL LETTER SHORT U */
+  {0x040F, 0x045F},  /* CYRILLIC CAPITAL LETTER DZHE */
+  {0x0410, 0x0430},  /* CYRILLIC CAPITAL LETTER A */
+  {0x0411, 0x0431},  /* CYRILLIC CAPITAL LETTER BE */
+  {0x0412, 0x0432},  /* CYRILLIC CAPITAL LETTER VE */
+  {0x0413, 0x0433},  /* CYRILLIC CAPITAL LETTER GHE */
+  {0x0414, 0x0434},  /* CYRILLIC CAPITAL LETTER DE */
+  {0x0415, 0x0435},  /* CYRILLIC CAPITAL LETTER IE */
+  {0x0416, 0x0436},  /* CYRILLIC CAPITAL LETTER ZHE */
+  {0x0417, 0x0437},  /* CYRILLIC CAPITAL LETTER ZE */
+  {0x0418, 0x0438},  /* CYRILLIC CAPITAL LETTER I */
+  {0x0419, 0x0439},  /* CYRILLIC CAPITAL LETTER SHORT I */
+  {0x041A, 0x043A},  /* CYRILLIC CAPITAL LETTER KA */
+  {0x041B, 0x043B},  /* CYRILLIC CAPITAL LETTER EL */
+  {0x041C, 0x043C},  /* CYRILLIC CAPITAL LETTER EM */
+  {0x041D, 0x043D},  /* CYRILLIC CAPITAL LETTER EN */
+  {0x041E, 0x043E},  /* CYRILLIC CAPITAL LETTER O */
+  {0x041F, 0x043F},  /* CYRILLIC CAPITAL LETTER PE */
+  {0x0420, 0x0440},  /* CYRILLIC CAPITAL LETTER ER */
+  {0x0421, 0x0441},  /* CYRILLIC CAPITAL LETTER ES */
+  {0x0422, 0x0442},  /* CYRILLIC CAPITAL LETTER TE */
+  {0x0423, 0x0443},  /* CYRILLIC CAPITAL LETTER U */
+  {0x0424, 0x0444},  /* CYRILLIC CAPITAL LETTER EF */
+  {0x0425, 0x0445},  /* CYRILLIC CAPITAL LETTER HA */
+  {0x0426, 0x0446},  /* CYRILLIC CAPITAL LETTER TSE */
+  {0x0427, 0x0447},  /* CYRILLIC CAPITAL LETTER CHE */
+  {0x0428, 0x0448},  /* CYRILLIC CAPITAL LETTER SHA */
+  {0x0429, 0x0449},  /* CYRILLIC CAPITAL LETTER SHCHA */
+  {0x042A, 0x044A},  /* CYRILLIC CAPITAL LETTER HARD SIGN */
+  {0x042B, 0x044B},  /* CYRILLIC CAPITAL LETTER YERU */
+  {0x042C, 0x044C},  /* CYRILLIC CAPITAL LETTER SOFT SIGN */
+  {0x042D, 0x044D},  /* CYRILLIC CAPITAL LETTER E */
+  {0x042E, 0x044E},  /* CYRILLIC CAPITAL LETTER YU */
+  {0x042F, 0x044F},  /* CYRILLIC CAPITAL LETTER YA */
+  {0x0460, 0x0461},  /* CYRILLIC CAPITAL LETTER OMEGA */
+  {0x0462, 0x0463},  /* CYRILLIC CAPITAL LETTER YAT */
+  {0x0464, 0x0465},  /* CYRILLIC CAPITAL LETTER IOTIFIED E */
+  {0x0466, 0x0467},  /* CYRILLIC CAPITAL LETTER LITTLE YUS */
+  {0x0468, 0x0469},  /* CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS */
+  {0x046A, 0x046B},  /* CYRILLIC CAPITAL LETTER BIG YUS */
+  {0x046C, 0x046D},  /* CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS */
+  {0x046E, 0x046F},  /* CYRILLIC CAPITAL LETTER KSI */
+  {0x0470, 0x0471},  /* CYRILLIC CAPITAL LETTER PSI */
+  {0x0472, 0x0473},  /* CYRILLIC CAPITAL LETTER FITA */
+  {0x0474, 0x0475},  /* CYRILLIC CAPITAL LETTER IZHITSA */
+  {0x0476, 0x0477},  /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */
+  {0x0478, 0x0479},  /* CYRILLIC CAPITAL LETTER UK */
+  {0x047A, 0x047B},  /* CYRILLIC CAPITAL LETTER ROUND OMEGA */
+  {0x047C, 0x047D},  /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO */
+  {0x047E, 0x047F},  /* CYRILLIC CAPITAL LETTER OT */
+  {0x0480, 0x0481},  /* CYRILLIC CAPITAL LETTER KOPPA */
+  {0x0490, 0x0491},  /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
+  {0x0492, 0x0493},  /* CYRILLIC CAPITAL LETTER GHE WITH STROKE */
+  {0x0494, 0x0495},  /* CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK */
+  {0x0496, 0x0497},  /* CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */
+  {0x0498, 0x0499},  /* CYRILLIC CAPITAL LETTER ZE WITH DESCENDER */
+  {0x049A, 0x049B},  /* CYRILLIC CAPITAL LETTER KA WITH DESCENDER */
+  {0x049C, 0x049D},  /* CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */
+  {0x049E, 0x049F},  /* CYRILLIC CAPITAL LETTER KA WITH STROKE */
+  {0x04A0, 0x04A1},  /* CYRILLIC CAPITAL LETTER BASHKIR KA */
+  {0x04A2, 0x04A3},  /* CYRILLIC CAPITAL LETTER EN WITH DESCENDER */
+  {0x04A4, 0x04A5},  /* CYRILLIC CAPITAL LIGATURE EN GHE */
+  {0x04A6, 0x04A7},  /* CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK */
+  {0x04A8, 0x04A9},  /* CYRILLIC CAPITAL LETTER ABKHASIAN HA */
+  {0x04AA, 0x04AB},  /* CYRILLIC CAPITAL LETTER ES WITH DESCENDER */
+  {0x04AC, 0x04AD},  /* CYRILLIC CAPITAL LETTER TE WITH DESCENDER */
+  {0x04AE, 0x04AF},  /* CYRILLIC CAPITAL LETTER STRAIGHT U */
+  {0x04B0, 0x04B1},  /* CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */
+  {0x04B2, 0x04B3},  /* CYRILLIC CAPITAL LETTER HA WITH DESCENDER */
+  {0x04B4, 0x04B5},  /* CYRILLIC CAPITAL LIGATURE TE TSE */
+  {0x04B6, 0x04B7},  /* CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */
+  {0x04B8, 0x04B9},  /* CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */
+  {0x04BA, 0x04BB},  /* CYRILLIC CAPITAL LETTER SHHA */
+  {0x04BC, 0x04BD},  /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE */
+  {0x04BE, 0x04BF},  /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER */
+  {0x04C1, 0x04C2},  /* CYRILLIC CAPITAL LETTER ZHE WITH BREVE */
+  {0x04C3, 0x04C4},  /* CYRILLIC CAPITAL LETTER KA WITH HOOK */
+  {0x04C7, 0x04C8},  /* CYRILLIC CAPITAL LETTER EN WITH HOOK */
+  {0x04CB, 0x04CC},  /* CYRILLIC CAPITAL LETTER KHAKASSIAN CHE */
+  {0x04D0, 0x04D1},  /* CYRILLIC CAPITAL LETTER A WITH BREVE */
+  {0x04D2, 0x04D3},  /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS */
+  {0x04D4, 0x04D5},  /* CYRILLIC CAPITAL LIGATURE A IE */
+  {0x04D6, 0x04D7},  /* CYRILLIC CAPITAL LETTER IE WITH BREVE */
+  {0x04D8, 0x04D9},  /* CYRILLIC CAPITAL LETTER SCHWA */
+  {0x04DA, 0x04DB},  /* CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS */
+  {0x04DC, 0x04DD},  /* CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS */
+  {0x04DE, 0x04DF},  /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS */
+  {0x04E0, 0x04E1},  /* CYRILLIC CAPITAL LETTER ABKHASIAN DZE */
+  {0x04E2, 0x04E3},  /* CYRILLIC CAPITAL LETTER I WITH MACRON */
+  {0x04E4, 0x04E5},  /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS */
+  {0x04E6, 0x04E7},  /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS */
+  {0x04E8, 0x04E9},  /* CYRILLIC CAPITAL LETTER BARRED O */
+  {0x04EA, 0x04EB},  /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS */
+  {0x04EE, 0x04EF},  /* CYRILLIC CAPITAL LETTER U WITH MACRON */
+  {0x04F0, 0x04F1},  /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS */
+  {0x04F2, 0x04F3},  /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE */
+  {0x04F4, 0x04F5},  /* CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS */
+  {0x04F8, 0x04F9},  /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS */
+  {0x0531, 0x0561},  /* ARMENIAN CAPITAL LETTER AYB */
+  {0x0532, 0x0562},  /* ARMENIAN CAPITAL LETTER BEN */
+  {0x0533, 0x0563},  /* ARMENIAN CAPITAL LETTER GIM */
+  {0x0534, 0x0564},  /* ARMENIAN CAPITAL LETTER DA */
+  {0x0535, 0x0565},  /* ARMENIAN CAPITAL LETTER ECH */
+  {0x0536, 0x0566},  /* ARMENIAN CAPITAL LETTER ZA */
+  {0x0537, 0x0567},  /* ARMENIAN CAPITAL LETTER EH */
+  {0x0538, 0x0568},  /* ARMENIAN CAPITAL LETTER ET */
+  {0x0539, 0x0569},  /* ARMENIAN CAPITAL LETTER TO */
+  {0x053A, 0x056A},  /* ARMENIAN CAPITAL LETTER ZHE */
+  {0x053B, 0x056B},  /* ARMENIAN CAPITAL LETTER INI */
+  {0x053C, 0x056C},  /* ARMENIAN CAPITAL LETTER LIWN */
+  {0x053D, 0x056D},  /* ARMENIAN CAPITAL LETTER XEH */
+  {0x053E, 0x056E},  /* ARMENIAN CAPITAL LETTER CA */
+  {0x053F, 0x056F},  /* ARMENIAN CAPITAL LETTER KEN */
+  {0x0540, 0x0570},  /* ARMENIAN CAPITAL LETTER HO */
+  {0x0541, 0x0571},  /* ARMENIAN CAPITAL LETTER JA */
+  {0x0542, 0x0572},  /* ARMENIAN CAPITAL LETTER GHAD */
+  {0x0543, 0x0573},  /* ARMENIAN CAPITAL LETTER CHEH */
+  {0x0544, 0x0574},  /* ARMENIAN CAPITAL LETTER MEN */
+  {0x0545, 0x0575},  /* ARMENIAN CAPITAL LETTER YI */
+  {0x0546, 0x0576},  /* ARMENIAN CAPITAL LETTER NOW */
+  {0x0547, 0x0577},  /* ARMENIAN CAPITAL LETTER SHA */
+  {0x0548, 0x0578},  /* ARMENIAN CAPITAL LETTER VO */
+  {0x0549, 0x0579},  /* ARMENIAN CAPITAL LETTER CHA */
+  {0x054A, 0x057A},  /* ARMENIAN CAPITAL LETTER PEH */
+  {0x054B, 0x057B},  /* ARMENIAN CAPITAL LETTER JHEH */
+  {0x054C, 0x057C},  /* ARMENIAN CAPITAL LETTER RA */
+  {0x054D, 0x057D},  /* ARMENIAN CAPITAL LETTER SEH */
+  {0x054E, 0x057E},  /* ARMENIAN CAPITAL LETTER VEW */
+  {0x054F, 0x057F},  /* ARMENIAN CAPITAL LETTER TIWN */
+  {0x0550, 0x0580},  /* ARMENIAN CAPITAL LETTER REH */
+  {0x0551, 0x0581},  /* ARMENIAN CAPITAL LETTER CO */
+  {0x0552, 0x0582},  /* ARMENIAN CAPITAL LETTER YIWN */
+  {0x0553, 0x0583},  /* ARMENIAN CAPITAL LETTER PIWR */
+  {0x0554, 0x0584},  /* ARMENIAN CAPITAL LETTER KEH */
+  {0x0555, 0x0585},  /* ARMENIAN CAPITAL LETTER OH */
+  {0x0556, 0x0586},  /* ARMENIAN CAPITAL LETTER FEH */
+  {0x10A0, 0x10D0},  /* GEORGIAN CAPITAL LETTER AN */
+  {0x10A1, 0x10D1},  /* GEORGIAN CAPITAL LETTER BAN */
+  {0x10A2, 0x10D2},  /* GEORGIAN CAPITAL LETTER GAN */
+  {0x10A3, 0x10D3},  /* GEORGIAN CAPITAL LETTER DON */
+  {0x10A4, 0x10D4},  /* GEORGIAN CAPITAL LETTER EN */
+  {0x10A5, 0x10D5},  /* GEORGIAN CAPITAL LETTER VIN */
+  {0x10A6, 0x10D6},  /* GEORGIAN CAPITAL LETTER ZEN */
+  {0x10A7, 0x10D7},  /* GEORGIAN CAPITAL LETTER TAN */
+  {0x10A8, 0x10D8},  /* GEORGIAN CAPITAL LETTER IN */
+  {0x10A9, 0x10D9},  /* GEORGIAN CAPITAL LETTER KAN */
+  {0x10AA, 0x10DA},  /* GEORGIAN CAPITAL LETTER LAS */
+  {0x10AB, 0x10DB},  /* GEORGIAN CAPITAL LETTER MAN */
+  {0x10AC, 0x10DC},  /* GEORGIAN CAPITAL LETTER NAR */
+  {0x10AD, 0x10DD},  /* GEORGIAN CAPITAL LETTER ON */
+  {0x10AE, 0x10DE},  /* GEORGIAN CAPITAL LETTER PAR */
+  {0x10AF, 0x10DF},  /* GEORGIAN CAPITAL LETTER ZHAR */
+  {0x10B0, 0x10E0},  /* GEORGIAN CAPITAL LETTER RAE */
+  {0x10B1, 0x10E1},  /* GEORGIAN CAPITAL LETTER SAN */
+  {0x10B2, 0x10E2},  /* GEORGIAN CAPITAL LETTER TAR */
+  {0x10B3, 0x10E3},  /* GEORGIAN CAPITAL LETTER UN */
+  {0x10B4, 0x10E4},  /* GEORGIAN CAPITAL LETTER PHAR */
+  {0x10B5, 0x10E5},  /* GEORGIAN CAPITAL LETTER KHAR */
+  {0x10B6, 0x10E6},  /* GEORGIAN CAPITAL LETTER GHAN */
+  {0x10B7, 0x10E7},  /* GEORGIAN CAPITAL LETTER QAR */
+  {0x10B8, 0x10E8},  /* GEORGIAN CAPITAL LETTER SHIN */
+  {0x10B9, 0x10E9},  /* GEORGIAN CAPITAL LETTER CHIN */
+  {0x10BA, 0x10EA},  /* GEORGIAN CAPITAL LETTER CAN */
+  {0x10BB, 0x10EB},  /* GEORGIAN CAPITAL LETTER JIL */
+  {0x10BC, 0x10EC},  /* GEORGIAN CAPITAL LETTER CIL */
+  {0x10BD, 0x10ED},  /* GEORGIAN CAPITAL LETTER CHAR */
+  {0x10BE, 0x10EE},  /* GEORGIAN CAPITAL LETTER XAN */
+  {0x10BF, 0x10EF},  /* GEORGIAN CAPITAL LETTER JHAN */
+  {0x10C0, 0x10F0},  /* GEORGIAN CAPITAL LETTER HAE */
+  {0x10C1, 0x10F1},  /* GEORGIAN CAPITAL LETTER HE */
+  {0x10C2, 0x10F2},  /* GEORGIAN CAPITAL LETTER HIE */
+  {0x10C3, 0x10F3},  /* GEORGIAN CAPITAL LETTER WE */
+  {0x10C4, 0x10F4},  /* GEORGIAN CAPITAL LETTER HAR */
+  {0x10C5, 0x10F5},  /* GEORGIAN CAPITAL LETTER HOE */
+  {0x1E00, 0x1E01},  /* LATIN CAPITAL LETTER A WITH RING BELOW */
+  {0x1E02, 0x1E03},  /* LATIN CAPITAL LETTER B WITH DOT ABOVE */
+  {0x1E04, 0x1E05},  /* LATIN CAPITAL LETTER B WITH DOT BELOW */
+  {0x1E06, 0x1E07},  /* LATIN CAPITAL LETTER B WITH LINE BELOW */
+  {0x1E08, 0x1E09},  /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE */
+  {0x1E0A, 0x1E0B},  /* LATIN CAPITAL LETTER D WITH DOT ABOVE */
+  {0x1E0C, 0x1E0D},  /* LATIN CAPITAL LETTER D WITH DOT BELOW */
+  {0x1E0E, 0x1E0F},  /* LATIN CAPITAL LETTER D WITH LINE BELOW */
+  {0x1E10, 0x1E11},  /* LATIN CAPITAL LETTER D WITH CEDILLA */
+  {0x1E12, 0x1E13},  /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW */
+  {0x1E14, 0x1E15},  /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE */
+  {0x1E16, 0x1E17},  /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE */
+  {0x1E18, 0x1E19},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW */
+  {0x1E1A, 0x1E1B},  /* LATIN CAPITAL LETTER E WITH TILDE BELOW */
+  {0x1E1C, 0x1E1D},  /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE */
+  {0x1E1E, 0x1E1F},  /* LATIN CAPITAL LETTER F WITH DOT ABOVE */
+  {0x1E20, 0x1E21},  /* LATIN CAPITAL LETTER G WITH MACRON */
+  {0x1E22, 0x1E23},  /* LATIN CAPITAL LETTER H WITH DOT ABOVE */
+  {0x1E24, 0x1E25},  /* LATIN CAPITAL LETTER H WITH DOT BELOW */
+  {0x1E26, 0x1E27},  /* LATIN CAPITAL LETTER H WITH DIAERESIS */
+  {0x1E28, 0x1E29},  /* LATIN CAPITAL LETTER H WITH CEDILLA */
+  {0x1E2A, 0x1E2B},  /* LATIN CAPITAL LETTER H WITH BREVE BELOW */
+  {0x1E2C, 0x1E2D},  /* LATIN CAPITAL LETTER I WITH TILDE BELOW */
+  {0x1E2E, 0x1E2F},  /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE */
+  {0x1E30, 0x1E31},  /* LATIN CAPITAL LETTER K WITH ACUTE */
+  {0x1E32, 0x1E33},  /* LATIN CAPITAL LETTER K WITH DOT BELOW */
+  {0x1E34, 0x1E35},  /* LATIN CAPITAL LETTER K WITH LINE BELOW */
+  {0x1E36, 0x1E37},  /* LATIN CAPITAL LETTER L WITH DOT BELOW */
+  {0x1E38, 0x1E39},  /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON */
+  {0x1E3A, 0x1E3B},  /* LATIN CAPITAL LETTER L WITH LINE BELOW */
+  {0x1E3C, 0x1E3D},  /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW */
+  {0x1E3E, 0x1E3F},  /* LATIN CAPITAL LETTER M WITH ACUTE */
+  {0x1E40, 0x1E41},  /* LATIN CAPITAL LETTER M WITH DOT ABOVE */
+  {0x1E42, 0x1E43},  /* LATIN CAPITAL LETTER M WITH DOT BELOW */
+  {0x1E44, 0x1E45},  /* LATIN CAPITAL LETTER N WITH DOT ABOVE */
+  {0x1E46, 0x1E47},  /* LATIN CAPITAL LETTER N WITH DOT BELOW */
+  {0x1E48, 0x1E49},  /* LATIN CAPITAL LETTER N WITH LINE BELOW */
+  {0x1E4A, 0x1E4B},  /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW */
+  {0x1E4C, 0x1E4D},  /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE */
+  {0x1E4E, 0x1E4F},  /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS */
+  {0x1E50, 0x1E51},  /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE */
+  {0x1E52, 0x1E53},  /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE */
+  {0x1E54, 0x1E55},  /* LATIN CAPITAL LETTER P WITH ACUTE */
+  {0x1E56, 0x1E57},  /* LATIN CAPITAL LETTER P WITH DOT ABOVE */
+  {0x1E58, 0x1E59},  /* LATIN CAPITAL LETTER R WITH DOT ABOVE */
+  {0x1E5A, 0x1E5B},  /* LATIN CAPITAL LETTER R WITH DOT BELOW */
+  {0x1E5C, 0x1E5D},  /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON */
+  {0x1E5E, 0x1E5F},  /* LATIN CAPITAL LETTER R WITH LINE BELOW */
+  {0x1E60, 0x1E61},  /* LATIN CAPITAL LETTER S WITH DOT ABOVE */
+  {0x1E62, 0x1E63},  /* LATIN CAPITAL LETTER S WITH DOT BELOW */
+  {0x1E64, 0x1E65},  /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE */
+  {0x1E66, 0x1E67},  /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE */
+  {0x1E68, 0x1E69},  /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE */
+  {0x1E6A, 0x1E6B},  /* LATIN CAPITAL LETTER T WITH DOT ABOVE */
+  {0x1E6C, 0x1E6D},  /* LATIN CAPITAL LETTER T WITH DOT BELOW */
+  {0x1E6E, 0x1E6F},  /* LATIN CAPITAL LETTER T WITH LINE BELOW */
+  {0x1E70, 0x1E71},  /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW */
+  {0x1E72, 0x1E73},  /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW */
+  {0x1E74, 0x1E75},  /* LATIN CAPITAL LETTER U WITH TILDE BELOW */
+  {0x1E76, 0x1E77},  /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW */
+  {0x1E78, 0x1E79},  /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE */
+  {0x1E7A, 0x1E7B},  /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS */
+  {0x1E7C, 0x1E7D},  /* LATIN CAPITAL LETTER V WITH TILDE */
+  {0x1E7E, 0x1E7F},  /* LATIN CAPITAL LETTER V WITH DOT BELOW */
+  {0x1E80, 0x1E81},  /* LATIN CAPITAL LETTER W WITH GRAVE */
+  {0x1E82, 0x1E83},  /* LATIN CAPITAL LETTER W WITH ACUTE */
+  {0x1E84, 0x1E85},  /* LATIN CAPITAL LETTER W WITH DIAERESIS */
+  {0x1E86, 0x1E87},  /* LATIN CAPITAL LETTER W WITH DOT ABOVE */
+  {0x1E88, 0x1E89},  /* LATIN CAPITAL LETTER W WITH DOT BELOW */
+  {0x1E8A, 0x1E8B},  /* LATIN CAPITAL LETTER X WITH DOT ABOVE */
+  {0x1E8C, 0x1E8D},  /* LATIN CAPITAL LETTER X WITH DIAERESIS */
+  {0x1E8E, 0x1E8F},  /* LATIN CAPITAL LETTER Y WITH DOT ABOVE */
+  {0x1E90, 0x1E91},  /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX */
+  {0x1E92, 0x1E93},  /* LATIN CAPITAL LETTER Z WITH DOT BELOW */
+  {0x1E94, 0x1E95},  /* LATIN CAPITAL LETTER Z WITH LINE BELOW */
+  {0x1EA0, 0x1EA1},  /* LATIN CAPITAL LETTER A WITH DOT BELOW */
+  {0x1EA2, 0x1EA3},  /* LATIN CAPITAL LETTER A WITH HOOK ABOVE */
+  {0x1EA4, 0x1EA5},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */
+  {0x1EA6, 0x1EA7},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */
+  {0x1EA8, 0x1EA9},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
+  {0x1EAA, 0x1EAB},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */
+  {0x1EAC, 0x1EAD},  /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
+  {0x1EAE, 0x1EAF},  /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */
+  {0x1EB0, 0x1EB1},  /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */
+  {0x1EB2, 0x1EB3},  /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */
+  {0x1EB4, 0x1EB5},  /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE */
+  {0x1EB6, 0x1EB7},  /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */
+  {0x1EB8, 0x1EB9},  /* LATIN CAPITAL LETTER E WITH DOT BELOW */
+  {0x1EBA, 0x1EBB},  /* LATIN CAPITAL LETTER E WITH HOOK ABOVE */
+  {0x1EBC, 0x1EBD},  /* LATIN CAPITAL LETTER E WITH TILDE */
+  {0x1EBE, 0x1EBF},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */
+  {0x1EC0, 0x1EC1},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */
+  {0x1EC2, 0x1EC3},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
+  {0x1EC4, 0x1EC5},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */
+  {0x1EC6, 0x1EC7},  /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
+  {0x1EC8, 0x1EC9},  /* LATIN CAPITAL LETTER I WITH HOOK ABOVE */
+  {0x1ECA, 0x1ECB},  /* LATIN CAPITAL LETTER I WITH DOT BELOW */
+  {0x1ECC, 0x1ECD},  /* LATIN CAPITAL LETTER O WITH DOT BELOW */
+  {0x1ECE, 0x1ECF},  /* LATIN CAPITAL LETTER O WITH HOOK ABOVE */
+  {0x1ED0, 0x1ED1},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */
+  {0x1ED2, 0x1ED3},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */
+  {0x1ED4, 0x1ED5},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
+  {0x1ED6, 0x1ED7},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */
+  {0x1ED8, 0x1ED9},  /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
+  {0x1EDA, 0x1EDB},  /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE */
+  {0x1EDC, 0x1EDD},  /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE */
+  {0x1EDE, 0x1EDF},  /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */
+  {0x1EE0, 0x1EE1},  /* LATIN CAPITAL LETTER O WITH HORN AND TILDE */
+  {0x1EE2, 0x1EE3},  /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */
+  {0x1EE4, 0x1EE5},  /* LATIN CAPITAL LETTER U WITH DOT BELOW */
+  {0x1EE6, 0x1EE7},  /* LATIN CAPITAL LETTER U WITH HOOK ABOVE */
+  {0x1EE8, 0x1EE9},  /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE */
+  {0x1EEA, 0x1EEB},  /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE */
+  {0x1EEC, 0x1EED},  /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */
+  {0x1EEE, 0x1EEF},  /* LATIN CAPITAL LETTER U WITH HORN AND TILDE */
+  {0x1EF0, 0x1EF1},  /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */
+  {0x1EF2, 0x1EF3},  /* LATIN CAPITAL LETTER Y WITH GRAVE */
+  {0x1EF4, 0x1EF5},  /* LATIN CAPITAL LETTER Y WITH DOT BELOW */
+  {0x1EF6, 0x1EF7},  /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE */
+  {0x1EF8, 0x1EF9},  /* LATIN CAPITAL LETTER Y WITH TILDE */
+  {0x1F08, 0x1F00},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI */
+  {0x1F09, 0x1F01},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA */
+  {0x1F0A, 0x1F02},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA */
+  {0x1F0B, 0x1F03},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA */
+  {0x1F0C, 0x1F04},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA */
+  {0x1F0D, 0x1F05},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA */
+  {0x1F0E, 0x1F06},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI */
+  {0x1F0F, 0x1F07},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI */
+  {0x1F18, 0x1F10},  /* GREEK CAPITAL LETTER EPSILON WITH PSILI */
+  {0x1F19, 0x1F11},  /* GREEK CAPITAL LETTER EPSILON WITH DASIA */
+  {0x1F1A, 0x1F12},  /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA */
+  {0x1F1B, 0x1F13},  /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA */
+  {0x1F1C, 0x1F14},  /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA */
+  {0x1F1D, 0x1F15},  /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA */
+  {0x1F28, 0x1F20},  /* GREEK CAPITAL LETTER ETA WITH PSILI */
+  {0x1F29, 0x1F21},  /* GREEK CAPITAL LETTER ETA WITH DASIA */
+  {0x1F2A, 0x1F22},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA */
+  {0x1F2B, 0x1F23},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA */
+  {0x1F2C, 0x1F24},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA */
+  {0x1F2D, 0x1F25},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA */
+  {0x1F2E, 0x1F26},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI */
+  {0x1F2F, 0x1F27},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI */
+  {0x1F38, 0x1F30},  /* GREEK CAPITAL LETTER IOTA WITH PSILI */
+  {0x1F39, 0x1F31},  /* GREEK CAPITAL LETTER IOTA WITH DASIA */
+  {0x1F3A, 0x1F32},  /* GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA */
+  {0x1F3B, 0x1F33},  /* GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA */
+  {0x1F3C, 0x1F34},  /* GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA */
+  {0x1F3D, 0x1F35},  /* GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA */
+  {0x1F3E, 0x1F36},  /* GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI */
+  {0x1F3F, 0x1F37},  /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI */
+  {0x1F48, 0x1F40},  /* GREEK CAPITAL LETTER OMICRON WITH PSILI */
+  {0x1F49, 0x1F41},  /* GREEK CAPITAL LETTER OMICRON WITH DASIA */
+  {0x1F4A, 0x1F42},  /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA */
+  {0x1F4B, 0x1F43},  /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA */
+  {0x1F4C, 0x1F44},  /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA */
+  {0x1F4D, 0x1F45},  /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA */
+  {0x1F59, 0x1F51},  /* GREEK CAPITAL LETTER UPSILON WITH DASIA */
+  {0x1F5B, 0x1F53},  /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA */
+  {0x1F5D, 0x1F55},  /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA */
+  {0x1F5F, 0x1F57},  /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI */
+  {0x1F68, 0x1F60},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI */
+  {0x1F69, 0x1F61},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA */
+  {0x1F6A, 0x1F62},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA */
+  {0x1F6B, 0x1F63},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA */
+  {0x1F6C, 0x1F64},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA */
+  {0x1F6D, 0x1F65},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA */
+  {0x1F6E, 0x1F66},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI */
+  {0x1F6F, 0x1F67},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI */
+  {0x1F88, 0x1F80},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
+  {0x1F89, 0x1F81},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
+  {0x1F8A, 0x1F82},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+  {0x1F8B, 0x1F83},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+  {0x1F8C, 0x1F84},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+  {0x1F8D, 0x1F85},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+  {0x1F8E, 0x1F86},  /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1F8F, 0x1F87},  /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1F98, 0x1F90},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI */
+  {0x1F99, 0x1F91},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI */
+  {0x1F9A, 0x1F92},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+  {0x1F9B, 0x1F93},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+  {0x1F9C, 0x1F94},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+  {0x1F9D, 0x1F95},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+  {0x1F9E, 0x1F96},  /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1F9F, 0x1F97},  /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1FA8, 0x1FA0},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
+  {0x1FA9, 0x1FA1},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
+  {0x1FAA, 0x1FA2},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+  {0x1FAB, 0x1FA3},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+  {0x1FAC, 0x1FA4},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+  {0x1FAD, 0x1FA5},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+  {0x1FAE, 0x1FA6},  /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1FAF, 0x1FA7},  /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+  {0x1FB8, 0x1FB0},  /* GREEK CAPITAL LETTER ALPHA WITH VRACHY */
+  {0x1FB9, 0x1FB1},  /* GREEK CAPITAL LETTER ALPHA WITH MACRON */
+  {0x1FBA, 0x1F70},  /* GREEK CAPITAL LETTER ALPHA WITH VARIA */
+  {0x1FBB, 0x1F71},  /* GREEK CAPITAL LETTER ALPHA WITH OXIA */
+  {0x1FBC, 0x1FB3},  /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
+  {0x1FC8, 0x1F72},  /* GREEK CAPITAL LETTER EPSILON WITH VARIA */
+  {0x1FC9, 0x1F73},  /* GREEK CAPITAL LETTER EPSILON WITH OXIA */
+  {0x1FCA, 0x1F74},  /* GREEK CAPITAL LETTER ETA WITH VARIA */
+  {0x1FCB, 0x1F75},  /* GREEK CAPITAL LETTER ETA WITH OXIA */
+  {0x1FCC, 0x1FC3},  /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
+  {0x1FD8, 0x1FD0},  /* GREEK CAPITAL LETTER IOTA WITH VRACHY */
+  {0x1FD9, 0x1FD1},  /* GREEK CAPITAL LETTER IOTA WITH MACRON */
+  {0x1FDA, 0x1F76},  /* GREEK CAPITAL LETTER IOTA WITH VARIA */
+  {0x1FDB, 0x1F77},  /* GREEK CAPITAL LETTER IOTA WITH OXIA */
+  {0x1FE8, 0x1FE0},  /* GREEK CAPITAL LETTER UPSILON WITH VRACHY */
+  {0x1FE9, 0x1FE1},  /* GREEK CAPITAL LETTER UPSILON WITH MACRON */
+  {0x1FEA, 0x1F7A},  /* GREEK CAPITAL LETTER UPSILON WITH VARIA */
+  {0x1FEB, 0x1F7B},  /* GREEK CAPITAL LETTER UPSILON WITH OXIA */
+  {0x1FEC, 0x1FE5},  /* GREEK CAPITAL LETTER RHO WITH DASIA */
+  {0x1FF8, 0x1F78},  /* GREEK CAPITAL LETTER OMICRON WITH VARIA */
+  {0x1FF9, 0x1F79},  /* GREEK CAPITAL LETTER OMICRON WITH OXIA */
+  {0x1FFA, 0x1F7C},  /* GREEK CAPITAL LETTER OMEGA WITH VARIA */
+  {0x1FFB, 0x1F7D},  /* GREEK CAPITAL LETTER OMEGA WITH OXIA */
+  {0x1FFC, 0x1FF3},  /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
+  {0x2160, 0x2170},  /* ROMAN NUMERAL ONE */
+  {0x2161, 0x2171},  /* ROMAN NUMERAL TWO */
+  {0x2162, 0x2172},  /* ROMAN NUMERAL THREE */
+  {0x2163, 0x2173},  /* ROMAN NUMERAL FOUR */
+  {0x2164, 0x2174},  /* ROMAN NUMERAL FIVE */
+  {0x2165, 0x2175},  /* ROMAN NUMERAL SIX */
+  {0x2166, 0x2176},  /* ROMAN NUMERAL SEVEN */
+  {0x2167, 0x2177},  /* ROMAN NUMERAL EIGHT */
+  {0x2168, 0x2178},  /* ROMAN NUMERAL NINE */
+  {0x2169, 0x2179},  /* ROMAN NUMERAL TEN */
+  {0x216A, 0x217A},  /* ROMAN NUMERAL ELEVEN */
+  {0x216B, 0x217B},  /* ROMAN NUMERAL TWELVE */
+  {0x216C, 0x217C},  /* ROMAN NUMERAL FIFTY */
+  {0x216D, 0x217D},  /* ROMAN NUMERAL ONE HUNDRED */
+  {0x216E, 0x217E},  /* ROMAN NUMERAL FIVE HUNDRED */
+  {0x216F, 0x217F},  /* ROMAN NUMERAL ONE THOUSAND */
+  {0x24B6, 0x24D0},  /* CIRCLED LATIN CAPITAL LETTER A */
+  {0x24B7, 0x24D1},  /* CIRCLED LATIN CAPITAL LETTER B */
+  {0x24B8, 0x24D2},  /* CIRCLED LATIN CAPITAL LETTER C */
+  {0x24B9, 0x24D3},  /* CIRCLED LATIN CAPITAL LETTER D */
+  {0x24BA, 0x24D4},  /* CIRCLED LATIN CAPITAL LETTER E */
+  {0x24BB, 0x24D5},  /* CIRCLED LATIN CAPITAL LETTER F */
+  {0x24BC, 0x24D6},  /* CIRCLED LATIN CAPITAL LETTER G */
+  {0x24BD, 0x24D7},  /* CIRCLED LATIN CAPITAL LETTER H */
+  {0x24BE, 0x24D8},  /* CIRCLED LATIN CAPITAL LETTER I */
+  {0x24BF, 0x24D9},  /* CIRCLED LATIN CAPITAL LETTER J */
+  {0x24C0, 0x24DA},  /* CIRCLED LATIN CAPITAL LETTER K */
+  {0x24C1, 0x24DB},  /* CIRCLED LATIN CAPITAL LETTER L */
+  {0x24C2, 0x24DC},  /* CIRCLED LATIN CAPITAL LETTER M */
+  {0x24C3, 0x24DD},  /* CIRCLED LATIN CAPITAL LETTER N */
+  {0x24C4, 0x24DE},  /* CIRCLED LATIN CAPITAL LETTER O */
+  {0x24C5, 0x24DF},  /* CIRCLED LATIN CAPITAL LETTER P */
+  {0x24C6, 0x24E0},  /* CIRCLED LATIN CAPITAL LETTER Q */
+  {0x24C7, 0x24E1},  /* CIRCLED LATIN CAPITAL LETTER R */
+  {0x24C8, 0x24E2},  /* CIRCLED LATIN CAPITAL LETTER S */
+  {0x24C9, 0x24E3},  /* CIRCLED LATIN CAPITAL LETTER T */
+  {0x24CA, 0x24E4},  /* CIRCLED LATIN CAPITAL LETTER U */
+  {0x24CB, 0x24E5},  /* CIRCLED LATIN CAPITAL LETTER V */
+  {0x24CC, 0x24E6},  /* CIRCLED LATIN CAPITAL LETTER W */
+  {0x24CD, 0x24E7},  /* CIRCLED LATIN CAPITAL LETTER X */
+  {0x24CE, 0x24E8},  /* CIRCLED LATIN CAPITAL LETTER Y */
+  {0x24CF, 0x24E9},  /* CIRCLED LATIN CAPITAL LETTER Z */
+  {0xFF21, 0xFF41},  /* FULLWIDTH LATIN CAPITAL LETTER A */
+  {0xFF22, 0xFF42},  /* FULLWIDTH LATIN CAPITAL LETTER B */
+  {0xFF23, 0xFF43},  /* FULLWIDTH LATIN CAPITAL LETTER C */
+  {0xFF24, 0xFF44},  /* FULLWIDTH LATIN CAPITAL LETTER D */
+  {0xFF25, 0xFF45},  /* FULLWIDTH LATIN CAPITAL LETTER E */
+  {0xFF26, 0xFF46},  /* FULLWIDTH LATIN CAPITAL LETTER F */
+  {0xFF27, 0xFF47},  /* FULLWIDTH LATIN CAPITAL LETTER G */
+  {0xFF28, 0xFF48},  /* FULLWIDTH LATIN CAPITAL LETTER H */
+  {0xFF29, 0xFF49},  /* FULLWIDTH LATIN CAPITAL LETTER I */
+  {0xFF2A, 0xFF4A},  /* FULLWIDTH LATIN CAPITAL LETTER J */
+  {0xFF2B, 0xFF4B},  /* FULLWIDTH LATIN CAPITAL LETTER K */
+  {0xFF2C, 0xFF4C},  /* FULLWIDTH LATIN CAPITAL LETTER L */
+  {0xFF2D, 0xFF4D},  /* FULLWIDTH LATIN CAPITAL LETTER M */
+  {0xFF2E, 0xFF4E},  /* FULLWIDTH LATIN CAPITAL LETTER N */
+  {0xFF2F, 0xFF4F},  /* FULLWIDTH LATIN CAPITAL LETTER O */
+  {0xFF30, 0xFF50},  /* FULLWIDTH LATIN CAPITAL LETTER P */
+  {0xFF31, 0xFF51},  /* FULLWIDTH LATIN CAPITAL LETTER Q */
+  {0xFF32, 0xFF52},  /* FULLWIDTH LATIN CAPITAL LETTER R */
+  {0xFF33, 0xFF53},  /* FULLWIDTH LATIN CAPITAL LETTER S */
+  {0xFF34, 0xFF54},  /* FULLWIDTH LATIN CAPITAL LETTER T */
+  {0xFF35, 0xFF55},  /* FULLWIDTH LATIN CAPITAL LETTER U */
+  {0xFF36, 0xFF56},  /* FULLWIDTH LATIN CAPITAL LETTER V */
+  {0xFF37, 0xFF57},  /* FULLWIDTH LATIN CAPITAL LETTER W */
+  {0xFF38, 0xFF58},  /* FULLWIDTH LATIN CAPITAL LETTER X */
+  {0xFF39, 0xFF59},  /* FULLWIDTH LATIN CAPITAL LETTER Y */
+  {0xFF3A, 0xFF5A}   /* FULLWIDTH LATIN CAPITAL LETTER Z */
+};
\ No newline at end of file
diff --git a/src/chrtrans/makefile.dos b/src/chrtrans/makefile.dos
index 57c45dfc..dba0d787 100644
--- a/src/chrtrans/makefile.dos
+++ b/src/chrtrans/makefile.dos
@@ -14,9 +14,10 @@ CFLAGS = $(MCFLAGS)
 CC = gcc
 MCFLAGS = -O3 -DDOSPATH -DNO_TTYTYP \
 -I. \
--I../../WWW/library/implement \
+-I../../WWW/Library/Implementation \
 -I../../djgpp/tcplib/include \
--I../../djgpp/tcplib/include/tcp
+-I../../djgpp/tcplib/include/tcp \
+-I../..
 
 .SUFFIXES: .tbl
 #
diff --git a/src/makefile.in b/src/makefile.in
index 2b7c5d46..0136a49f 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -99,7 +99,7 @@ do_chartrans_stuff:
 		CC="$(CC)" tables
 
 lint:
-	$(LINT) $(LINTOPTS) $(CPP_OPTS) *.c  > $(top_builddir)
+	$(LINT) $(LINTOPTS) $(CPP_OPTS) *.c  > $(top_builddir)/lint.lynx
 
 clean:
 	rm -f lynx$x core *.[ob] *.bak