--- grep-2.5.1/src/grep.c.gofast	2004-02-26 13:17:39.000000000 +0000
+++ grep-2.5.1/src/grep.c	2004-02-26 13:17:39.000000000 +0000
@@ -186,7 +186,8 @@
 
 /* Functions we'll use to search. */
 static void (*compile) PARAMS ((char const *, size_t));
-static size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
+static size_t (*execute) PARAMS ((char const *, size_t, struct mb_cache *,
+				  size_t *, int));
 
 /* Like error, but suppress the diagnostic if requested.  */
 static void
@@ -516,7 +517,7 @@
 }
 
 static void
-prline (char const *beg, char const *lim, int sep)
+prline (char const *beg, char const *lim, int sep, struct mb_cache *mb_cache)
 {
   if (out_file)
     printf ("%s%c", filename, sep & filename_mask);
@@ -539,7 +540,8 @@
     {
       size_t match_size;
       size_t match_offset;
-      while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1))
+      while ((match_offset = (*execute) (beg, lim - beg, mb_cache,
+					 &match_size, 1))
 	  != (size_t) -1)
         {
 	  char const *b = beg + match_offset;
@@ -573,7 +575,8 @@
 	  int i;
 	  for (i = 0; i < lim - beg; i++)
 	    ibeg[i] = tolower (beg[i]);
-	  while ((match_offset = (*execute) (ibeg, ilim-ibeg, &match_size, 1))
+	  while ((match_offset = (*execute) (ibeg, ilim-ibeg, mb_cache,
+					     &match_size, 1))
 		 != (size_t) -1)
 	    {
 	      char const *b = beg + match_offset;
@@ -591,7 +594,8 @@
 	  lastout = lim;
 	  return;
 	}
-      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
+      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, mb_cache,
+						    &match_size, 1))
 	     != (size_t) -1)
 	{
 	  char const *b = beg + match_offset;
@@ -619,7 +623,7 @@
 /* Print pending lines of trailing context prior to LIM. Trailing context ends
    at the next matching line when OUTLEFT is 0.  */
 static void
-prpending (char const *lim)
+prpending (char const *lim, struct mb_cache *mb_cache)
 {
   if (!lastout)
     lastout = bufbeg;
@@ -629,9 +633,10 @@
       size_t match_size;
       --pending;
       if (outleft
-	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
+	  || (((*execute) (lastout, nl - lastout, mb_cache,
+			   &match_size, 0) == (size_t) -1)
 	      == !out_invert))
-	prline (lastout, nl + 1, '-');
+	prline (lastout, nl + 1, '-', mb_cache);
       else
 	pending = 0;
     }
@@ -640,7 +645,8 @@
 /* Print the lines between BEG and LIM.  Deal with context crap.
    If NLINESP is non-null, store a count of lines between BEG and LIM.  */
 static void
-prtext (char const *beg, char const *lim, int *nlinesp)
+prtext (char const *beg, char const *lim, int *nlinesp,
+	struct mb_cache *mb_cache)
 {
   static int used;		/* avoid printing "--" before any output */
   char const *bp, *p;
@@ -648,7 +654,7 @@
   int i, n;
 
   if (!out_quiet && pending > 0)
-    prpending (beg);
+    prpending (beg, mb_cache);
 
   p = beg;
 
@@ -672,7 +678,7 @@
 	{
 	  char const *nl = memchr (p, eol, beg - p);
 	  nl++;
-	  prline (p, nl, '-');
+	  prline (p, nl, '-', mb_cache);
 	  p = nl;
 	}
     }
@@ -685,7 +691,7 @@
 	  char const *nl = memchr (p, eol, lim - p);
 	  nl++;
 	  if (!out_quiet)
-	    prline (p, nl, ':');
+	    prline (p, nl, ':', mb_cache);
 	  p = nl;
 	}
       *nlinesp = n;
@@ -695,7 +701,7 @@
     }
   else
     if (!out_quiet)
-      prline (beg, lim, ':');
+      prline (beg, lim, ':', mb_cache);
 
   pending = out_quiet ? 0 : out_after;
   used = 1;
@@ -705,7 +711,7 @@
    between matching lines if OUT_INVERT is true).  Return a count of
    lines printed. */
 static int
-grepbuf (char const *beg, char const *lim)
+grepbuf (char const *beg, char const *lim, struct mb_cache *mb_cache)
 {
   int nlines, n;
   register char const *p;
@@ -714,7 +720,8 @@
 
   nlines = 0;
   p = beg;
-  while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
+  while ((match_offset = (*execute) (p, lim - p, mb_cache,
+				     &match_size, 0)) != (size_t) -1)
     {
       char const *b = p + match_offset;
       char const *endp = b + match_size;
@@ -723,7 +730,7 @@
 	break;
       if (!out_invert)
 	{
-	  prtext (b, endp, (int *) 0);
+	  prtext (b, endp, (int *) 0, mb_cache);
 	  nlines++;
           outleft--;
 	  if (!outleft || done_on_match)
@@ -736,7 +743,7 @@
 	}
       else if (p < b)
 	{
-	  prtext (p, b, &n);
+	  prtext (p, b, &n, mb_cache);
 	  nlines += n;
           outleft -= n;
 	  if (!outleft)
@@ -746,7 +753,7 @@
     }
   if (out_invert && p < lim)
     {
-      prtext (p, lim, &n);
+      prtext (p, lim, &n, mb_cache);
       nlines += n;
       outleft -= n;
     }
@@ -766,7 +773,9 @@
   char *beg;
   char *lim;
   char eol = eolbyte;
+  struct mb_cache mb_cache;
 
+  memset (&mb_cache, 0, sizeof (mb_cache));
   if (!reset (fd, file, stats))
     return 0;
 
@@ -833,9 +842,9 @@
       if (beg < lim)
 	{
 	  if (outleft)
-	    nlines += grepbuf (beg, lim);
+	    nlines += grepbuf (beg, lim, &mb_cache);
 	  if (pending)
-	    prpending (lim);
+	    prpending (lim, &mb_cache);
 	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
 	    goto finish_grep;
 	}
@@ -863,6 +872,11 @@
 	totalcc = add_count (totalcc, buflim - bufbeg - save);
       if (out_line)
 	nlscan (beg);
+      if (mb_cache.wcs_buf)
+	free (mb_cache.wcs_buf);
+      if (mb_cache.mblen_buf)
+	free (mb_cache.mblen_buf);
+      memset (&mb_cache, 0, sizeof (mb_cache));
       if (! fillbuf (save, stats))
 	{
 	  if (! is_EISDIR (errno, file))
@@ -874,9 +888,9 @@
     {
       *buflim++ = eol;
       if (outleft)
-	nlines += grepbuf (bufbeg + save - residue, buflim);
+	nlines += grepbuf (bufbeg + save - residue, buflim, &mb_cache);
       if (pending)
-        prpending (buflim);
+        prpending (buflim, &mb_cache);
     }
 
  finish_grep:
@@ -884,6 +898,11 @@
   out_quiet -= not_text;
   if ((not_text & ~out_quiet) && nlines != 0)
     printf (_("Binary file %s matches\n"), filename);
+
+  if (mb_cache.wcs_buf)
+    free (mb_cache.wcs_buf);
+  if (mb_cache.mblen_buf)
+    free (mb_cache.mblen_buf);
   return nlines;
 }
 
--- grep-2.5.1/src/grep.h.gofast	2001-03-04 05:39:41.000000000 +0000
+++ grep-2.5.1/src/grep.h	2004-02-26 13:17:39.000000000 +0000
@@ -20,6 +20,8 @@
 # define __attribute__(x)
 #endif
 
+#include "mbcache.h"
+
 /* Grep.c expects the matchers vector to be terminated
    by an entry with a NULL compile, and to contain at least
    an entry named "default". */
@@ -28,7 +30,8 @@
 {
   char name[8];
   void (*compile) PARAMS ((char const *, size_t));
-  size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
+  size_t (*execute) PARAMS ((char const *, size_t, struct mb_cache *,
+			     size_t *, int));
 } const matchers[];
 
 /* Exported from fgrepmat.c, egrepmat.c, grepmat.c.  */
--- grep-2.5.1/src/search.c	2004-10-13 17:17:09.929706014 +0100
+++ grep-2.5.1/src/search.c	2004-10-13 17:44:21.470690774 +0100
@@ -71,17 +71,27 @@
 static int kwset_exact_matches;
 
 #if defined(MBS_SUPPORT)
-static char* check_multibyte_string PARAMS ((char const *buf, size_t size));
+/* For Fexecute: we might be able to elide multibyte processing. */
+static int pattern_contains_multibyte = 0;
+#endif
+
+#if defined(MBS_SUPPORT)
+static char* check_multibyte_string PARAMS ((char const *buf, size_t size,
+					     struct mb_cache *,
+					     char const *orig_buf));
 #endif
 static void kwsinit PARAMS ((void));
 static void kwsmusts PARAMS ((void));
 static void Gcompile PARAMS ((char const *, size_t));
 static void Ecompile PARAMS ((char const *, size_t));
-static size_t EGexecute PARAMS ((char const *, size_t, size_t *, int ));
+static size_t EGexecute PARAMS ((char const *, size_t, struct mb_cache *,
+				 size_t *, int ));
 static void Fcompile PARAMS ((char const *, size_t));
-static size_t Fexecute PARAMS ((char const *, size_t, size_t *, int));
+static size_t Fexecute PARAMS ((char const *, size_t, struct mb_cache *,
+				size_t *, int));
 static void Pcompile PARAMS ((char const *, size_t ));
-static size_t Pexecute PARAMS ((char const *, size_t, size_t *, int));
+static size_t Pexecute PARAMS ((char const *, size_t, struct mb_cache *,
+				size_t *, int));
 
 void
 dfaerror (char const *mesg)
@@ -147,35 +157,66 @@
    are not singlebyte character nor the first byte of a multibyte
    character.  Caller must free the array.  */
 static char*
-check_multibyte_string(char const *buf, size_t size)
+check_multibyte_string(char const *buf, size_t size, struct mb_cache *mb_cache,
+		       char const *orig_buf)
 {
   char *mb_properties = xmalloc(size);
   mbstate_t cur_state;
   wchar_t wc;
   int i;
   memset(&cur_state, 0, sizeof(mbstate_t));
-  memset(mb_properties, 0, sizeof(char)*size);
-  for (i = 0; i < size ;)
-    {
-      size_t mbclen;
-      mbclen = mbrtowc(&wc, buf + i, size - i, &cur_state);
 
-      if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
+  if (mb_cache && mb_cache->mblen_buf &&
+      orig_buf > mb_cache->orig_buf &&
+      (orig_buf + size) <= (mb_cache->orig_buf + mb_cache->len))
+    {
+      /* The cache can help us. */
+      memcpy (mb_properties,
+	      mb_cache->mblen_buf + (orig_buf - mb_cache->orig_buf),
+	      size);
+    
+    }
+  else
+    {
+      memset(mb_properties, 0, sizeof(char)*size);
+      for (i = 0; i < size ;)
 	{
-	  /* An invalid sequence, or a truncated multibyte character.
-	     We treat it as a singlebyte character.  */
-	  mbclen = 1;
+	  size_t mbclen;
+	  mbclen = mbrtowc(&wc, buf + i, size - i, &cur_state);
+
+	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
+	    {
+	      /* An invalid sequence, or a truncated multibyte character.
+		 We treat it as a singlebyte character.  */
+	      mbclen = 1;
+	    }
+	  else if (match_icase)
+	    {
+	      if (iswupper((wint_t)wc))
+		{
+		  wc = towlower((wint_t)wc);
+		  wcrtomb(buf + i, wc, &cur_state);
+		}
+	    }
+	  mb_properties[i] = mbclen;
+	  i += mbclen;
 	}
-      else if (match_icase)
+
+      /* Now populate the cache. */
+      if (mb_cache)
 	{
-	  if (iswupper((wint_t)wc))
+	  if (mb_cache->wcs_buf)
 	    {
-	      wc = towlower((wint_t)wc);
-	      wcrtomb(buf + i, wc, &cur_state);
+	      free (mb_cache->wcs_buf);
+	      mb_cache->wcs_buf = NULL;
 	    }
+	  if (mb_cache->mblen_buf)
+	    free (mb_cache->mblen_buf);
+	  mb_cache->len = size;
+	  mb_cache->orig_buf = orig_buf;
+	  mb_cache->mblen_buf = xmalloc (size);
+	  memcpy (mb_cache->mblen_buf, mb_properties, size);
 	}
-      mb_properties[i] = mbclen;
-      i += mbclen;
     }
 
   return mb_properties;
@@ -342,9 +383,11 @@
 }
 
 static size_t
-EGexecute (char const *buf, size_t size, size_t *match_size, int exact)
+EGexecute (char const *buf, size_t size, struct mb_cache *mb_cache,
+	   size_t *match_size, int exact)
 {
   register char const *buflim, *beg, *end;
+  char const *orig_buf = buf;
   char eol = eolbyte;
   int backref, start, len;
   struct kwsmatch kwsm;
@@ -360,7 +403,7 @@
           buf = case_buf;
         }
       if (kwset)
-        mb_properties = check_multibyte_string(buf, size);
+        mb_properties = check_multibyte_string(buf, size, mb_cache, orig_buf);
     }
 #endif /* MBS_SUPPORT */
 
@@ -389,13 +432,13 @@
 		--beg;
 	      if (kwsm.index < kwset_exact_matches)
 		goto success_in_beg_and_end;
-	      if (dfaexec (&dfa, beg, end - beg, &backref) == (size_t) -1)
+	      if (dfaexec (&dfa, beg, end - beg, &backref, mb_cache) == (size_t) -1)
 		continue;
 	    }
 	  else
 	    {
 	      /* No good fixed strings; start with DFA. */
-	      size_t offset = dfaexec (&dfa, beg, buflim - beg, &backref);
+	      size_t offset = dfaexec (&dfa, beg, buflim - beg, &backref, mb_cache);
 	      if (offset == (size_t) -1)
 		break;
 	      /* Narrow down to the line we've found. */
@@ -503,13 +546,25 @@
 Fcompile (char const *pattern, size_t size)
 {
   char const *beg, *lim, *err;
+#ifdef MBS_SUPPORT
+  mbstate_t ps;
+  memset (&ps, '\0', sizeof (mbstate_t));
+#endif
 
   kwsinit ();
   beg = pattern;
   do
     {
       for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
-	;
+	{
+#ifdef MBS_SUPPORT
+	  if (!pattern_contains_multibyte && match_icase)
+	    pattern_contains_multibyte = 1;
+	  if (!pattern_contains_multibyte &&
+	      mbrlen (lim, size - (lim - pattern), &ps) != 1)
+	    pattern_contains_multibyte = 1;
+#endif
+	}
       if ((err = kwsincr (kwset, beg, lim - beg)) != 0)
 	error (2, 0, err);
       if (lim < pattern + size)
@@ -523,16 +578,18 @@
 }
 
 static size_t
-Fexecute (char const *buf, size_t size, size_t *match_size, int exact)
+Fexecute (char const *buf, size_t size, struct mb_cache *mb_cache,
+	  size_t *match_size, int exact)
 {
   register char const *beg, *try, *end;
+  char const *orig_buf = buf;
   register size_t len;
   char eol = eolbyte;
   struct kwsmatch kwsmatch;
   size_t ret_val;
 #ifdef MBS_SUPPORT
   char *mb_properties = NULL;
-  if (MB_CUR_MAX > 1)
+  if (pattern_contains_multibyte && MB_CUR_MAX > 1)
     {
       if (match_icase)
         {
@@ -540,7 +597,7 @@
           memcpy(case_buf, buf, size);
           buf = case_buf;
         }
-      mb_properties = check_multibyte_string(buf, size);
+      mb_properties = check_multibyte_string(buf, size, mb_cache, orig_buf);
     }
 #endif /* MBS_SUPPORT */
 
@@ -550,7 +607,8 @@
       if (offset == (size_t) -1)
 	goto failure;
 #ifdef MBS_SUPPORT
-      if (MB_CUR_MAX > 1 && mb_properties[offset+beg-buf] == 0)
+      if (pattern_contains_multibyte &&
+	  MB_CUR_MAX > 1 && mb_properties[offset+beg-buf] == 0)
 	continue; /* It is a part of multibyte character.  */
 #endif /* MBS_SUPPORT */
       beg += offset;
@@ -598,7 +656,7 @@
 
  failure:
 #ifdef MBS_SUPPORT
-  if (MB_CUR_MAX > 1)
+  if (pattern_contains_multibyte && MB_CUR_MAX > 1)
     {
       if (match_icase)
         free((char *) buf);
@@ -619,7 +677,7 @@
  success_in_beg_and_len:
   *match_size = len;
 #ifdef MBS_SUPPORT
-  if (MB_CUR_MAX > 1)
+  if (pattern_contains_multibyte && MB_CUR_MAX > 1)
     {
       if (mb_properties)
 	free (mb_properties);
@@ -704,7 +762,8 @@
 }
 
 static size_t
-Pexecute (char const *buf, size_t size, size_t *match_size, int exact)
+Pexecute (char const *buf, size_t size, struct mb_cache *mb_cache,
+	  size_t *match_size, int exact)
 {
 #if !HAVE_LIBPCRE
   abort ();
--- grep-2.5.1/src/dfa.c.gofast	2004-02-26 13:17:39.000000000 +0000
+++ grep-2.5.1/src/dfa.c	2004-02-26 13:17:39.000000000 +0000
@@ -2747,7 +2747,8 @@
    match needs to be verified by a backtracking matcher.  Otherwise
    we store a 0 in *backref. */
 size_t
-dfaexec (struct dfa *d, char const *begin, size_t size, int *backref)
+dfaexec (struct dfa *d, char const *begin, size_t size, int *backref,
+	 struct mb_cache *mb_cache)
 {
   register int s;	/* Current state. */
   register unsigned char const *p; /* Current input character. */
@@ -2779,43 +2780,79 @@
 #ifdef MBS_SUPPORT
   if (MB_CUR_MAX > 1)
     {
-      int remain_bytes, i;
       buf_begin = begin;
       buf_end = end;
-
-      /* initialize mblen_buf, and inputwcs.  */
-      MALLOC(mblen_buf, unsigned char, end - (unsigned char const *)begin + 2);
-      MALLOC(inputwcs, wchar_t, end - (unsigned char const *)begin + 2);
-      memset(&mbs, 0, sizeof(mbstate_t));
-      remain_bytes = 0;
-      for (i = 0; i < end - (unsigned char const *)begin + 1; i++)
+      if (mb_cache && mb_cache->mblen_buf && mb_cache->wcs_buf &&
+	  begin > mb_cache->orig_buf &&
+	  (begin + size) <= (mb_cache->orig_buf + mb_cache->len))
+	{
+	  /* The cache can help us. */
+	  MALLOC(mblen_buf, unsigned char, size + 2);
+	  MALLOC(inputwcs, wchar_t, size + 2);
+	  memcpy (mblen_buf,
+		  mb_cache->mblen_buf + (begin - mb_cache->orig_buf),
+		  (size + 2) * sizeof (unsigned char));
+	  memcpy (inputwcs,
+		  mb_cache->wcs_buf + (begin - mb_cache->orig_buf),
+		  (size + 2) * sizeof (wchar_t));
+	  mblen_buf[size + 1] = 0;
+	  inputwcs[size + 1] = 0;
+	}
+      else
 	{
-	  if (remain_bytes == 0)
+	  int remain_bytes, i;
+
+	  /* initialize mblen_buf, and inputwcs.  */
+	  MALLOC(mblen_buf, unsigned char, end - (unsigned char const *)begin + 2);
+	  MALLOC(inputwcs, wchar_t, end - (unsigned char const *)begin + 2);
+	  memset(&mbs, 0, sizeof(mbstate_t));
+	  remain_bytes = 0;
+	  for (i = 0; i < end - (unsigned char const *)begin + 1; i++)
 	    {
-	      remain_bytes
-		= mbrtowc(inputwcs + i, begin + i,
-			  end - (unsigned char const *)begin - i + 1, &mbs);
-	      if (remain_bytes <= 1)
+	      if (remain_bytes == 0)
 		{
-		  remain_bytes = 0;
-		  inputwcs[i] = (wchar_t)begin[i];
-		  mblen_buf[i] = 0;
+		  remain_bytes
+		    = mbrtowc(inputwcs + i, begin + i,
+			      end - (unsigned char const *)begin - i + 1, &mbs);
+		  if (remain_bytes <= 1)
+		    {
+		      remain_bytes = 0;
+		      inputwcs[i] = (wchar_t)begin[i];
+		      mblen_buf[i] = 0;
+		    }
+		  else
+		    {
+		      mblen_buf[i] = remain_bytes;
+		      remain_bytes--;
+		    }
 		}
 	      else
 		{
 		  mblen_buf[i] = remain_bytes;
+		  inputwcs[i] = 0;
 		  remain_bytes--;
 		}
 	    }
-	  else
+	  mblen_buf[i] = 0;
+	  inputwcs[i] = 0; /* sentinel */
+
+	  if (mb_cache)
 	    {
-	      mblen_buf[i] = remain_bytes;
-	      inputwcs[i] = 0;
-	      remain_bytes--;
+	      /* Populate the cache. */
+	      mb_cache->len = size;
+	      mb_cache->orig_buf = begin;
+	      if (mb_cache->mblen_buf)
+		      free (mb_cache->mblen_buf);
+	      if (mb_cache->wcs_buf)
+		      free (mb_cache->wcs_buf);
+	      MALLOC(mb_cache->mblen_buf, unsigned char, size + 2);
+	      MALLOC(mb_cache->wcs_buf, wchar_t, size + 2);
+	      memcpy (mb_cache->mblen_buf, mblen_buf,
+		      (size + 2) * sizeof (unsigned char));
+	      memcpy (mb_cache->wcs_buf, inputwcs,
+		      (size + 2) * sizeof (wchar_t));
 	    }
 	}
-      mblen_buf[i] = 0;
-      inputwcs[i] = 0; /* sentinel */
     }
 #endif /* MBS_SUPPORT */
 
--- /dev/null	2004-02-23 21:02:56.000000000 +0000
+++ grep-2.5.1/src/mbcache.h	2004-02-26 13:17:39.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef MB_CACHE_DEFINED
+#define MB_CACHE_DEFINED
+struct mb_cache
+{
+  size_t len;
+  const char *orig_buf; /* not the only reference; do not free */
+  wchar_t *wcs_buf;
+  unsigned char *mblen_buf;
+};
+#endif
--- grep-2.5.1/src/dfa.h.gofast	2001-03-07 04:11:27.000000000 +0000
+++ grep-2.5.1/src/dfa.h	2004-02-26 13:17:39.000000000 +0000
@@ -22,6 +22,8 @@
    In addition to clobbering modularity, we eat up valuable
    name space. */
 
+#include "mbcache.h"
+
 #ifdef __STDC__
 # ifndef _PTR_T
 # define _PTR_T
@@ -403,7 +405,8 @@
    order to verify backreferencing; otherwise the flag will be cleared.
    Returns (size_t) -1 if no match is found, or the offset of the first
    character after the first & shortest matching string in the buffer. */
-extern size_t dfaexec PARAMS ((struct dfa *, char const *, size_t, int *));
+extern size_t dfaexec PARAMS ((struct dfa *, char const *, size_t, int *,
+			       struct mb_cache *));
 
 /* Free the storage held by the components of a struct dfa. */
 extern void dfafree PARAMS ((struct dfa *));
