Replace bcopy, bzero, bcmp by memcpy, memmove, memset, memcmp
[bpt/emacs.git] / src / regex.c
index 125a338..b563d93 100644 (file)
@@ -3,7 +3,7 @@
    internationalization features.)
 
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006, 2007
+                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
                  Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    that make sense only in Emacs. */
 #ifdef emacs
 
+# include <setjmp.h>
 # include "lisp.h"
 # include "buffer.h"
 
 # define SYNTAX_ENTRY_VIA_PROPERTY
 
 # include "syntax.h"
-# include "charset.h"
+# include "character.h"
 # include "category.h"
 
 # ifdef malloc
 # define POS_AS_IN_BUFFER(p) ((p) + (NILP (re_match_object) || BUFFERP (re_match_object)))
 
 # define RE_MULTIBYTE_P(bufp) ((bufp)->multibyte)
-# define RE_STRING_CHAR(p, s) \
-  (multibyte ? (STRING_CHAR (p, s)) : (*(p)))
-# define RE_STRING_CHAR_AND_LENGTH(p, s, len) \
-  (multibyte ? (STRING_CHAR_AND_LENGTH (p, s, len)) : ((len) = 1, *(p)))
-
-/* Set C a (possibly multibyte) character before P.  P points into a
-   string which is the virtual concatenation of STR1 (which ends at
-   END1) or STR2 (which ends at END2).  */
-# define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2)               \
-  do {                                                                 \
-    if (multibyte)                                                     \
-       {                                                               \
-        re_char *dtemp = (p) == (str2) ? (end1) : (p);                 \
-        re_char *dlimit = ((p) > (str2) && (p) <= (end2)) ? (str2) : (str1); \
-        re_char *d0 = dtemp;                                           \
-        PREV_CHAR_BOUNDARY (d0, dlimit);                               \
-        c = STRING_CHAR (d0, dtemp - d0);                              \
-       }                                                               \
-     else                                                              \
-       (c = ((p) == (str2) ? (end1) : (p))[-1]);                       \
+# define RE_TARGET_MULTIBYTE_P(bufp) ((bufp)->target_multibyte)
+# define RE_STRING_CHAR(p, multibyte) \
+  (multibyte ? (STRING_CHAR (p)) : (*(p)))
+# define RE_STRING_CHAR_AND_LENGTH(p, len, multibyte) \
+  (multibyte ? (STRING_CHAR_AND_LENGTH (p, len)) : ((len) = 1, *(p)))
+
+# define RE_CHAR_TO_MULTIBYTE(c) UNIBYTE_TO_CHAR (c)
+
+# define RE_CHAR_TO_UNIBYTE(c) CHAR_TO_BYTE_SAFE (c)
+
+/* Set C a (possibly converted to multibyte) character before P.  P
+   points into a string which is the virtual concatenation of STR1
+   (which ends at END1) or STR2 (which ends at END2).  */
+# define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2)                    \
+  do {                                                                      \
+    if (target_multibyte)                                                   \
+      {                                                                             \
+       re_char *dtemp = (p) == (str2) ? (end1) : (p);                       \
+       re_char *dlimit = ((p) > (str2) && (p) <= (end2)) ? (str2) : (str1); \
+       while (dtemp-- > dlimit && !CHAR_HEAD_P (*dtemp));                   \
+       c = STRING_CHAR (dtemp);                                             \
+      }                                                                             \
+    else                                                                    \
+      {                                                                             \
+       (c = ((p) == (str2) ? (end1) : (p))[-1]);                            \
+       (c) = RE_CHAR_TO_MULTIBYTE (c);                                      \
+      }                                                                             \
   } while (0)
 
+/* Set C a (possibly converted to multibyte) character at P, and set
+   LEN to the byte length of that character.  */
+# define GET_CHAR_AFTER(c, p, len)             \
+  do {                                         \
+    if (target_multibyte)                      \
+      (c) = STRING_CHAR_AND_LENGTH (p, len);   \
+    else                                       \
+      {                                                \
+       (c) = *p;                               \
+       len = 1;                                \
+       (c) = RE_CHAR_TO_MULTIBYTE (c);         \
+      }                                                \
+   } while (0)
 
 #else  /* not emacs */
 
@@ -227,37 +248,16 @@ xrealloc (block, size)
 # endif
 # define realloc xrealloc
 
-/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
-   If nothing else has been done, use the method below.  */
-# ifdef INHIBIT_STRING_HEADER
-#  if !(defined HAVE_BZERO && defined HAVE_BCOPY)
-#   if !defined bzero && !defined bcopy
-#    undef INHIBIT_STRING_HEADER
-#   endif
+/* This is the normal way of making sure we have memcpy, memcmp and memset.  */
+# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
+#  include <string.h>
+# else
+#  include <strings.h>
+#  ifndef memcmp
+#   define memcmp(s1, s2, n)   bcmp (s1, s2, n)
 #  endif
-# endif
-
-/* This is the normal way of making sure we have memcpy, memcmp and bzero.
-   This is used in most programs--a few other programs avoid this
-   by defining INHIBIT_STRING_HEADER.  */
-# ifndef INHIBIT_STRING_HEADER
-#  if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
-#   include <string.h>
-#   ifndef bzero
-#    ifndef _LIBC
-#     define bzero(s, n)       (memset (s, '\0', n), (s))
-#    else
-#     define bzero(s, n)       __bzero (s, n)
-#    endif
-#   endif
-#  else
-#   include <strings.h>
-#   ifndef memcmp
-#    define memcmp(s1, s2, n)  bcmp (s1, s2, n)
-#   endif
-#   ifndef memcpy
-#    define memcpy(d, s, n)    (bcopy (s, d, n), (d))
-#   endif
+#  ifndef memcpy
+#   define memcpy(d, s, n)     (bcopy (s, d, n), (d))
 #  endif
 # endif
 
@@ -266,32 +266,36 @@ xrealloc (block, size)
 /* Sword must be nonzero for the wordchar pattern commands in re_match_2.  */
 enum syntaxcode { Swhitespace = 0, Sword = 1, Ssymbol = 2 };
 
-# ifdef SWITCH_ENUM_BUG
-#  define SWITCH_ENUM_CAST(x) ((int)(x))
-# else
 #  define SWITCH_ENUM_CAST(x) (x)
-# endif
 
 /* Dummy macros for non-Emacs environments.  */
-# define BASE_LEADING_CODE_P(c) (0)
 # define CHAR_CHARSET(c) 0
 # define CHARSET_LEADING_CODE_BASE(c) 0
 # define MAX_MULTIBYTE_LENGTH 1
 # define RE_MULTIBYTE_P(x) 0
+# define RE_TARGET_MULTIBYTE_P(x) 0
 # define WORD_BOUNDARY_P(c1, c2) (0)
 # define CHAR_HEAD_P(p) (1)
 # define SINGLE_BYTE_CHAR_P(c) (1)
 # define SAME_CHARSET_P(c1, c2) (1)
-# define MULTIBYTE_FORM_LENGTH(p, s) (1)
+# define BYTES_BY_CHAR_HEAD(p) (1)
 # define PREV_CHAR_BOUNDARY(p, limit) ((p)--)
-# define STRING_CHAR(p, s) (*(p))
-# define RE_STRING_CHAR STRING_CHAR
+# define STRING_CHAR(p) (*(p))
+# define RE_STRING_CHAR(p, multibyte) STRING_CHAR (p)
 # define CHAR_STRING(c, s) (*(s) = (c), 1)
-# define STRING_CHAR_AND_LENGTH(p, s, actual_len) ((actual_len) = 1, *(p))
-# define RE_STRING_CHAR_AND_LENGTH STRING_CHAR_AND_LENGTH
+# define STRING_CHAR_AND_LENGTH(p, actual_len) ((actual_len) = 1, *(p))
+# define RE_STRING_CHAR_AND_LENGTH(p, len, multibyte) STRING_CHAR_AND_LENGTH (p, len)
+# define RE_CHAR_TO_MULTIBYTE(c) (c)
+# define RE_CHAR_TO_UNIBYTE(c) (c)
 # define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \
   (c = ((p) == (str2) ? *((end1) - 1) : *((p) - 1)))
+# define GET_CHAR_AFTER(c, p, len)     \
+  (c = *p, len = 1)
 # define MAKE_CHAR(charset, c1, c2) (c1)
+# define BYTE8_TO_CHAR(c) (c)
+# define CHAR_BYTE8_P(c) (0)
+# define CHAR_LEADING_CODE(c) (c)
+
 #endif /* not emacs */
 
 #ifndef RE_TRANSLATE
@@ -439,7 +443,7 @@ init_syntax_once ()
    if (done)
      return;
 
-   bzero (re_syntax_table, sizeof re_syntax_table);
+   memset (re_syntax_table, 0, sizeof re_syntax_table);
 
    for (c = 0; c < CHAR_SET_SIZE; ++c)
      if (ISALNUM (c))
@@ -497,7 +501,7 @@ init_syntax_once ()
 #  ifdef __GNUC__
 #   define alloca __builtin_alloca
 #  else /* not __GNUC__ */
-#   if HAVE_ALLOCA_H
+#   ifdef HAVE_ALLOCA_H
 #    include <alloca.h>
 #   endif /* HAVE_ALLOCA_H */
 #  endif /* not __GNUC__ */
@@ -1296,8 +1300,7 @@ reg_syntax_t re_syntax_options;
    defined in regex.h.  We return the old syntax.  */
 
 reg_syntax_t
-re_set_syntax (syntax)
-     reg_syntax_t syntax;
+re_set_syntax (reg_syntax_t syntax)
 {
   reg_syntax_t ret = re_syntax_options;
 
@@ -1310,8 +1313,7 @@ WEAK_ALIAS (__re_set_syntax, re_set_syntax)
 static re_char *whitespace_regexp;
 
 void
-re_set_whitespace_regexp (regexp)
-     const char *regexp;
+re_set_whitespace_regexp (const char *regexp)
 {
   whitespace_regexp = (re_char *) regexp;
 }
@@ -1731,7 +1733,7 @@ static int analyse_first _RE_ARGS ((re_char *p, re_char *pend,
   do {                                                                 \
     int len;                                                           \
     if (p == pend) return REG_EEND;                                    \
-    c = RE_STRING_CHAR_AND_LENGTH (p, pend - p, len);                  \
+    c = RE_STRING_CHAR_AND_LENGTH (p, len, multibyte);                 \
     p += len;                                                          \
   } while (0)
 
@@ -1826,8 +1828,10 @@ static int analyse_first _RE_ARGS ((re_char *p, re_char *pend,
    being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
 #if __BOUNDED_POINTERS__
 # define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated)
-# define MOVE_BUFFER_POINTER(P) \
-  (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr)
+# define MOVE_BUFFER_POINTER(P)                                        \
+  (__ptrlow (P) = new_buffer + (__ptrlow (P) - old_buffer),    \
+   SET_HIGH_BOUND (P),                                         \
+   __ptrvalue (P) = new_buffer + (__ptrvalue (P) - old_buffer))
 # define ELSE_EXTEND_BUFFER_HIGH_BOUND         \
   else                                         \
     {                                          \
@@ -1841,12 +1845,12 @@ static int analyse_first _RE_ARGS ((re_char *p, re_char *pend,
        SET_HIGH_BOUND (pending_exact);         \
     }
 #else
-# define MOVE_BUFFER_POINTER(P) (P) += incr
+# define MOVE_BUFFER_POINTER(P) ((P) = new_buffer + ((P) - old_buffer))
 # define ELSE_EXTEND_BUFFER_HIGH_BOUND
 #endif
 #define EXTEND_BUFFER()                                                        \
   do {                                                                 \
-    re_char *old_buffer = bufp->buffer;                                        \
+    unsigned char *old_buffer = bufp->buffer;                          \
     if (bufp->allocated == MAX_BUF_SIZE)                               \
       return REG_ESIZE;                                                        \
     bufp->allocated <<= 1;                                             \
@@ -1858,7 +1862,7 @@ static int analyse_first _RE_ARGS ((re_char *p, re_char *pend,
     /* If the buffer moved, move all the pointers into it.  */         \
     if (old_buffer != bufp->buffer)                                    \
       {                                                                        \
-       int incr = bufp->buffer - old_buffer;                           \
+       unsigned char *new_buffer = bufp->buffer;                       \
        MOVE_BUFFER_POINTER (b);                                        \
        MOVE_BUFFER_POINTER (begalt);                                   \
        if (fixup_alt_jump)                                             \
@@ -1942,10 +1946,10 @@ struct range_table_work_area
 
 #define EXTEND_RANGE_TABLE(work_area, n)                               \
   do {                                                                 \
-    if (((work_area)->used + (n)) * sizeof (int) > (work_area)->allocated) \
+    if (((work_area).used + (n)) * sizeof (int) > (work_area).allocated) \
       {                                                                        \
-        extend_range_table_work_area (work_area);                      \
-        if ((work_area)->table == 0)                                   \
+        extend_range_table_work_area (&work_area);                     \
+        if ((work_area).table == 0)                                    \
           return (REG_ESPACE);                                         \
       }                                                                        \
   } while (0)
@@ -1962,15 +1966,12 @@ struct range_table_work_area
 #define BIT_UPPER      0x10
 #define BIT_MULTIBYTE  0x20
 
-/* Set a range START..END to WORK_AREA.
-   The range is passed through TRANSLATE, so START and END
-   should be untranslated.  */
-#define SET_RANGE_TABLE_WORK_AREA(work_area, start, end)               \
+/* Set a range (RANGE_START, RANGE_END) to WORK_AREA.  */
+#define SET_RANGE_TABLE_WORK_AREA(work_area, range_start, range_end)   \
   do {                                                                 \
-    int tem;                                                           \
-    tem = set_image_of_range (&work_area, start, end, translate);      \
-    if (tem > 0)                                                       \
-      FREE_STACK_RETURN (tem);                                         \
+    EXTEND_RANGE_TABLE ((work_area), 2);                               \
+    (work_area).table[(work_area).used++] = (range_start);             \
+    (work_area).table[(work_area).used++] = (range_end);               \
   } while (0)
 
 /* Free allocated memory for WORK_AREA.  */
@@ -1990,6 +1991,113 @@ struct range_table_work_area
 #define SET_LIST_BIT(c) (b[((c)) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH))
 
 
+#ifdef emacs
+
+/* Store characters in the range FROM to TO in the bitmap at B (for
+   ASCII and unibyte characters) and WORK_AREA (for multibyte
+   characters) while translating them and paying attention to the
+   continuity of translated characters.
+
+   Implementation note: It is better to implement these fairly big
+   macros by a function, but it's not that easy because macros called
+   in this macro assume various local variables already declared.  */
+
+/* Both FROM and TO are ASCII characters.  */
+
+#define SETUP_ASCII_RANGE(work_area, FROM, TO)                 \
+  do {                                                         \
+    int C0, C1;                                                        \
+                                                               \
+    for (C0 = (FROM); C0 <= (TO); C0++)                                \
+      {                                                                \
+       C1 = TRANSLATE (C0);                                    \
+       if (! ASCII_CHAR_P (C1))                                \
+         {                                                     \
+           SET_RANGE_TABLE_WORK_AREA ((work_area), C1, C1);    \
+           if ((C1 = RE_CHAR_TO_UNIBYTE (C1)) < 0)             \
+             C1 = C0;                                          \
+         }                                                     \
+       SET_LIST_BIT (C1);                                      \
+      }                                                                \
+  } while (0)
+
+
+/* Both FROM and TO are unibyte characters (0x80..0xFF).  */
+
+#define SETUP_UNIBYTE_RANGE(work_area, FROM, TO)                              \
+  do {                                                                        \
+    int C0, C1, C2, I;                                                        \
+    int USED = RANGE_TABLE_WORK_USED (work_area);                             \
+                                                                              \
+    for (C0 = (FROM); C0 <= (TO); C0++)                                               \
+      {                                                                               \
+       C1 = RE_CHAR_TO_MULTIBYTE (C0);                                        \
+       if (CHAR_BYTE8_P (C1))                                                 \
+         SET_LIST_BIT (C0);                                                   \
+       else                                                                   \
+         {                                                                    \
+           C2 = TRANSLATE (C1);                                               \
+           if (C2 == C1                                                       \
+               || (C1 = RE_CHAR_TO_UNIBYTE (C2)) < 0)                         \
+             C1 = C0;                                                         \
+           SET_LIST_BIT (C1);                                                 \
+           for (I = RANGE_TABLE_WORK_USED (work_area) - 2; I >= USED; I -= 2) \
+             {                                                                \
+               int from = RANGE_TABLE_WORK_ELT (work_area, I);                \
+               int to = RANGE_TABLE_WORK_ELT (work_area, I + 1);              \
+                                                                              \
+               if (C2 >= from - 1 && C2 <= to + 1)                            \
+                 {                                                            \
+                   if (C2 == from - 1)                                        \
+                     RANGE_TABLE_WORK_ELT (work_area, I)--;                   \
+                   else if (C2 == to + 1)                                     \
+                     RANGE_TABLE_WORK_ELT (work_area, I + 1)++;               \
+                   break;                                                     \
+                 }                                                            \
+             }                                                                \
+           if (I < USED)                                                      \
+             SET_RANGE_TABLE_WORK_AREA ((work_area), C2, C2);                 \
+         }                                                                    \
+      }                                                                               \
+  } while (0)
+
+
+/* Both FROM and TO are multibyte characters.  */
+
+#define SETUP_MULTIBYTE_RANGE(work_area, FROM, TO)                        \
+  do {                                                                    \
+    int C0, C1, C2, I, USED = RANGE_TABLE_WORK_USED (work_area);          \
+                                                                          \
+    SET_RANGE_TABLE_WORK_AREA ((work_area), (FROM), (TO));                \
+    for (C0 = (FROM); C0 <= (TO); C0++)                                           \
+      {                                                                           \
+       C1 = TRANSLATE (C0);                                               \
+       if ((C2 = RE_CHAR_TO_UNIBYTE (C1)) >= 0                            \
+           || (C1 != C0 && (C2 = RE_CHAR_TO_UNIBYTE (C0)) >= 0))          \
+         SET_LIST_BIT (C2);                                               \
+       if (C1 >= (FROM) && C1 <= (TO))                                    \
+         continue;                                                        \
+       for (I = RANGE_TABLE_WORK_USED (work_area) - 2; I >= USED; I -= 2) \
+         {                                                                \
+           int from = RANGE_TABLE_WORK_ELT (work_area, I);                \
+           int to = RANGE_TABLE_WORK_ELT (work_area, I + 1);              \
+                                                                          \
+           if (C1 >= from - 1 && C1 <= to + 1)                            \
+             {                                                            \
+               if (C1 == from - 1)                                        \
+                 RANGE_TABLE_WORK_ELT (work_area, I)--;                   \
+               else if (C1 == to + 1)                                     \
+                 RANGE_TABLE_WORK_ELT (work_area, I + 1)++;               \
+               break;                                                     \
+             }                                                            \
+         }                                                                \
+       if (I < USED)                                                      \
+         SET_RANGE_TABLE_WORK_AREA ((work_area), C1, C1);                 \
+      }                                                                           \
+  } while (0)
+
+#endif /* emacs */
+
 /* Get the next unsigned number in the uncompiled pattern.  */
 #define GET_UNSIGNED_NUMBER(num)                                       \
   do {                                                                 \
@@ -2018,8 +2126,7 @@ struct range_table_work_area
 
 /* Map a string to the char class it names (if any).  */
 re_wctype_t
-re_wctype (str)
-     re_char *str;
+re_wctype (const re_char *str)
 {
   const char *string = str;
   if      (STREQ (string, "alnum"))    return RECC_ALNUM;
@@ -2044,9 +2151,7 @@ re_wctype (str)
 
 /* True if CH is in the char class CC.  */
 boolean
-re_iswctype (ch, cc)
-     int ch;
-     re_wctype_t cc;
+re_iswctype (int ch, re_wctype_t cc)
 {
   switch (cc)
     {
@@ -2076,8 +2181,7 @@ re_iswctype (ch, cc)
 /* Return a bit-pattern to use in the range-table bits to match multibyte
    chars of class CC.  */
 static int
-re_wctype_to_bit (cc)
-     re_wctype_t cc;
+re_wctype_to_bit (re_wctype_t cc)
 {
   switch (cc)
     {
@@ -2101,8 +2205,7 @@ re_wctype_to_bit (cc)
 /* Actually extend the space in WORK_AREA.  */
 
 static void
-extend_range_table_work_area (work_area)
-     struct range_table_work_area *work_area;
+extend_range_table_work_area (struct range_table_work_area *work_area)
 {
   work_area->allocated += 16 * sizeof (int);
   if (work_area->table)
@@ -2113,6 +2216,7 @@ extend_range_table_work_area (work_area)
       = (int *) malloc (work_area->allocated);
 }
 
+#if 0
 #ifdef emacs
 
 /* Carefully find the ranges of codes that are equivalent
@@ -2268,7 +2372,7 @@ set_image_of_range_1 (work_area, start, end, translate)
 
 #endif /* emacs */
 
-/* Record the the image of the range start..end when passed through
+/* Record the image of the range start..end when passed through
    TRANSLATE.  This is not necessarily TRANSLATE(start)..TRANSLATE(end)
    and is not even necessarily contiguous.
    Normally we approximate it with the smallest contiguous range that contains
@@ -2345,6 +2449,7 @@ set_image_of_range (work_area, start, end, translate)
 
   return -1;
 }
+#endif /* 0 */
 \f
 #ifndef MATCH_MAY_ALLOCATE
 
@@ -2424,11 +2529,7 @@ do {                                                                     \
   } while (0)
 
 static reg_errcode_t
-regex_compile (pattern, size, syntax, bufp)
-     re_char *pattern;
-     size_t size;
-     reg_syntax_t syntax;
-     struct re_pattern_buffer *bufp;
+regex_compile (const re_char *pattern, size_t size, reg_syntax_t syntax, struct re_pattern_buffer *bufp)
 {
   /* We fetch characters from PATTERN here.  */
   register re_wchar_t c, c1;
@@ -2483,6 +2584,9 @@ regex_compile (pattern, size, syntax, bufp)
   /* If the object matched can contain multibyte characters.  */
   const boolean multibyte = RE_MULTIBYTE_P (bufp);
 
+  /* If a target of matching can contain multibyte characters.  */
+  const boolean target_multibyte = RE_TARGET_MULTIBYTE_P (bufp);
+
   /* Nonzero if we have pushed down into a subpattern.  */
   int in_subpattern = 0;
 
@@ -2823,7 +2927,7 @@ regex_compile (pattern, size, syntax, bufp)
            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
 
            /* Clear the whole map.  */
-           bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+           memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH);
 
            /* charset_not matches newline according to a syntax bit.  */
            if ((re_opcode_t) b[-2] == charset_not
@@ -2835,6 +2939,7 @@ regex_compile (pattern, size, syntax, bufp)
              {
                boolean escaped_char = false;
                const unsigned char *p2 = p;
+               re_wchar_t ch, c2;
 
                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
 
@@ -2861,10 +2966,6 @@ regex_compile (pattern, size, syntax, bufp)
                      break;
                  }
 
-               /* What should we do for the character which is
-                  greater than 0x7F, but not BASE_LEADING_CODE_P?
-                  XXX */
-
                /* See if we're at the beginning of a possible character
                   class.  */
 
@@ -2901,8 +3002,8 @@ regex_compile (pattern, size, syntax, bufp)
                       them).  */
                    if (c == ':' && *p == ']')
                      {
-                       re_wchar_t ch;
                        re_wctype_t cc;
+                       int limit;
 
                        cc = re_wctype (str);
 
@@ -2915,6 +3016,15 @@ regex_compile (pattern, size, syntax, bufp)
 
                         if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
 
+#ifndef emacs
+                       for (ch = 0; ch < (1 << BYTEWIDTH); ++ch)
+                         if (re_iswctype (btowc (ch), cc))
+                           {
+                             c = TRANSLATE (ch);
+                             if (c < (1 << BYTEWIDTH))
+                               SET_LIST_BIT (c);
+                           }
+#else  /* emacs */
                        /* Most character classes in a multibyte match
                           just set a flag.  Exceptions are is_blank,
                           is_digit, is_cntrl, and is_xdigit, since
@@ -2922,18 +3032,32 @@ regex_compile (pattern, size, syntax, bufp)
                           don't need to handle them for multibyte.
                           They are distinguished by a negative wctype.  */
 
-                       if (multibyte)
-                         SET_RANGE_TABLE_WORK_AREA_BIT (range_table_work,
-                                                        re_wctype_to_bit (cc));
+                       /* Setup the gl_state object to its buffer-defined
+                          value.  This hardcodes the buffer-global
+                          syntax-table for ASCII chars, while the other chars
+                          will obey syntax-table properties.  It's not ideal,
+                          but it's the way it's been done until now.  */
+                       SETUP_BUFFER_SYNTAX_TABLE ();
 
-                        for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
+                       for (ch = 0; ch < 256; ++ch)
                          {
-                           int translated = TRANSLATE (ch);
-                           if (translated < (1 << BYTEWIDTH)
-                               && re_iswctype (btowc (ch), cc))
-                             SET_LIST_BIT (translated);
+                           c = RE_CHAR_TO_MULTIBYTE (ch);
+                           if (! CHAR_BYTE8_P (c)
+                               && re_iswctype (c, cc))
+                             {
+                               SET_LIST_BIT (ch);
+                               c1 = TRANSLATE (c);
+                               if (c1 == c)
+                                 continue;
+                               if (ASCII_CHAR_P (c1))
+                                 SET_LIST_BIT (c1);
+                               else if ((c1 = RE_CHAR_TO_UNIBYTE (c1)) >= 0)
+                                 SET_LIST_BIT (c1);
+                             }
                          }
-
+                       SET_RANGE_TABLE_WORK_AREA_BIT
+                         (range_table_work, re_wctype_to_bit (cc));
+#endif /* emacs */
                        /* In most cases the matching rule for char classes
                           only uses the syntax table for multibyte chars,
                           so that the content of the syntax-table it is not
@@ -2966,64 +3090,63 @@ regex_compile (pattern, size, syntax, bufp)
 
                    /* Fetch the character which ends the range. */
                    PATFETCH (c1);
-
-                   if (SINGLE_BYTE_CHAR_P (c))
-                     {
-                       if (! SINGLE_BYTE_CHAR_P (c1))
-                         {
-                           /* Handle a range starting with a
-                              character of less than 256, and ending
-                              with a character of not less than 256.
-                              Split that into two ranges, the low one
-                              ending at 0377, and the high one
-                              starting at the smallest character in
-                              the charset of C1 and ending at C1.  */
-                           int charset = CHAR_CHARSET (c1);
-                           re_wchar_t c2 = MAKE_CHAR (charset, 0, 0);
-
-                           SET_RANGE_TABLE_WORK_AREA (range_table_work,
-                                                      c2, c1);
-                           c1 = 0377;
-                         }
-                     }
-                   else if (!SAME_CHARSET_P (c, c1))
-                     FREE_STACK_RETURN (REG_ERANGEX);
+#ifdef emacs
+                   if (CHAR_BYTE8_P (c1)
+                       && ! ASCII_CHAR_P (c) && ! CHAR_BYTE8_P (c))
+                     /* Treat the range from a multibyte character to
+                        raw-byte character as empty.  */
+                     c = c1 + 1;
+#endif /* emacs */
                  }
                else
                  /* Range from C to C. */
                  c1 = c;
 
-               /* Set the range ... */
-               if (SINGLE_BYTE_CHAR_P (c))
-                 /* ... into bitmap.  */
+               if (c > c1)
                  {
-                   re_wchar_t this_char;
-                   re_wchar_t range_start = c, range_end = c1;
-
-                   /* If the start is after the end, the range is empty.  */
-                   if (range_start > range_end)
+                   if (syntax & RE_NO_EMPTY_RANGES)
+                     FREE_STACK_RETURN (REG_ERANGEX);
+                   /* Else, repeat the loop.  */
+                 }
+               else
+                 {
+#ifndef emacs
+                   /* Set the range into bitmap */
+                   for (; c <= c1; c++)
                      {
-                       if (syntax & RE_NO_EMPTY_RANGES)
-                         FREE_STACK_RETURN (REG_ERANGE);
-                       /* Else, repeat the loop.  */
+                       ch = TRANSLATE (c);
+                       if (ch < (1 << BYTEWIDTH))
+                         SET_LIST_BIT (ch);
                      }
-                   else
+#else  /* emacs */
+                   if (c < 128)
                      {
-                       for (this_char = range_start; this_char <= range_end;
-                            this_char++)
+                       ch = MIN (127, c1);
+                       SETUP_ASCII_RANGE (range_table_work, c, ch);
+                       c = ch + 1;
+                       if (CHAR_BYTE8_P (c1))
+                         c = BYTE8_TO_CHAR (128);
+                     }
+                   if (c <= c1)
+                     {
+                       if (CHAR_BYTE8_P (c))
+                         {
+                           c = CHAR_TO_BYTE8 (c);
+                           c1 = CHAR_TO_BYTE8 (c1);
+                           for (; c <= c1; c++)
+                             SET_LIST_BIT (c);
+                         }
+                       else if (multibyte)
+                         {
+                           SETUP_MULTIBYTE_RANGE (range_table_work, c, c1);
+                         }
+                       else
                          {
-                           int translated = TRANSLATE (this_char);
-                           if (translated < (1 << BYTEWIDTH))
-                             SET_LIST_BIT (translated);
-                           else
-                             SET_RANGE_TABLE_WORK_AREA
-                               (range_table_work, translated, translated);
+                           SETUP_UNIBYTE_RANGE (range_table_work, c, c1);
                          }
                      }
+#endif /* emacs */
                  }
-               else
-                 /* ... into range table.  */
-                 SET_RANGE_TABLE_WORK_AREA (range_table_work, c, c1);
              }
 
            /* Discard any (non)matching list bytes that are all 0 at the
@@ -3634,12 +3757,25 @@ regex_compile (pattern, size, syntax, bufp)
          {
            int len;
 
-           c = TRANSLATE (c);
            if (multibyte)
-             len = CHAR_STRING (c, b);
+             {
+               c = TRANSLATE (c);
+               len = CHAR_STRING (c, b);
+               b += len;
+             }
            else
-             *b = c, len = 1;
-           b += len;
+             {
+               c1 = RE_CHAR_TO_MULTIBYTE (c);
+               if (! CHAR_BYTE8_P (c1))
+                 {
+                   re_wchar_t c2 = TRANSLATE (c1);
+
+                   if (c1 != c2 && (c1 = RE_CHAR_TO_UNIBYTE (c2)) >= 0)
+                     c = c1;
+                 }
+               *b++ = c;
+               len = 1;
+             }
            (*pending_exact) += len;
          }
 
@@ -3707,10 +3843,7 @@ regex_compile (pattern, size, syntax, bufp)
 /* Store OP at LOC followed by two-byte integer parameter ARG.  */
 
 static void
-store_op1 (op, loc, arg)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg;
+store_op1 (re_opcode_t op, unsigned char *loc, int arg)
 {
   *loc = (unsigned char) op;
   STORE_NUMBER (loc + 1, arg);
@@ -3720,10 +3853,7 @@ store_op1 (op, loc, arg)
 /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
 
 static void
-store_op2 (op, loc, arg1, arg2)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg1, arg2;
+store_op2 (re_opcode_t op, unsigned char *loc, int arg1, int arg2)
 {
   *loc = (unsigned char) op;
   STORE_NUMBER (loc + 1, arg1);
@@ -3735,11 +3865,7 @@ store_op2 (op, loc, arg1, arg2)
    for OP followed by two-byte integer parameter ARG.  */
 
 static void
-insert_op1 (op, loc, arg, end)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg;
-    unsigned char *end;
+insert_op1 (re_opcode_t op, unsigned char *loc, int arg, unsigned char *end)
 {
   register unsigned char *pfrom = end;
   register unsigned char *pto = end + 3;
@@ -3754,11 +3880,7 @@ insert_op1 (op, loc, arg, end)
 /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
 
 static void
-insert_op2 (op, loc, arg1, arg2, end)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg1, arg2;
-    unsigned char *end;
+insert_op2 (re_opcode_t op, unsigned char *loc, int arg1, int arg2, unsigned char *end)
 {
   register unsigned char *pfrom = end;
   register unsigned char *pto = end + 5;
@@ -3775,9 +3897,7 @@ insert_op2 (op, loc, arg1, arg2, end)
    least one character before the ^.  */
 
 static boolean
-at_begline_loc_p (pattern, p, syntax)
-    re_char *pattern, *p;
-    reg_syntax_t syntax;
+at_begline_loc_p (const re_char *pattern, const re_char *p, reg_syntax_t syntax)
 {
   re_char *prev = p - 2;
   boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
@@ -3799,9 +3919,7 @@ at_begline_loc_p (pattern, p, syntax)
    at least one character after the $, i.e., `P < PEND'.  */
 
 static boolean
-at_endline_loc_p (p, pend, syntax)
-    re_char *p, *pend;
-    reg_syntax_t syntax;
+at_endline_loc_p (const re_char *p, const re_char *pend, reg_syntax_t syntax)
 {
   re_char *next = p;
   boolean next_backslash = *next == '\\';
@@ -3821,9 +3939,7 @@ at_endline_loc_p (p, pend, syntax)
    false if it's not.  */
 
 static boolean
-group_in_compile_stack (compile_stack, regnum)
-    compile_stack_type compile_stack;
-    regnum_t regnum;
+group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
 {
   int this_element;
 
@@ -3847,10 +3963,7 @@ group_in_compile_stack (compile_stack, regnum)
    Return -1 if fastmap was not updated accurately.  */
 
 static int
-analyse_first (p, pend, fastmap, multibyte)
-     re_char *p, *pend;
-     char *fastmap;
-     const int multibyte;
+analyse_first (const re_char *p, const re_char *pend, char *fastmap, const int multibyte)
 {
   int j, k;
   boolean not;
@@ -3909,14 +4022,20 @@ analyse_first (p, pend, fastmap, multibyte)
        case exactn:
          if (fastmap)
            {
-             int c = RE_STRING_CHAR (p + 1, pend - p);
-             /* When fast-scanning, the fastmap can be indexed either with
-                a char (smaller than 256) or with the first byte of
-                a char's byte sequence.  So we have to conservatively add
-                both to the table.  */
-             if (SINGLE_BYTE_CHAR_P (c))
-               fastmap[c] = 1;
+             /* If multibyte is nonzero, the first byte of each
+                character is an ASCII or a leading code.  Otherwise,
+                each byte is a character.  Thus, this works in both
+                cases. */
              fastmap[p[1]] = 1;
+             if (! multibyte)
+               {
+                 /* For the case of matching this unibyte regex
+                    against multibyte, we must set a leading code of
+                    the corresponding multibyte character.  */
+                 int c = RE_CHAR_TO_MULTIBYTE (p[1]);
+
+                 fastmap[CHAR_LEADING_CODE (c)] = 1;
+               }
            }
          break;
 
@@ -3929,18 +4048,14 @@ analyse_first (p, pend, fastmap, multibyte)
 
 
        case charset_not:
-         /* Chars beyond end of bitmap are possible matches.
-            All the single-byte codes can occur in multibyte buffers.
-            So any that are not listed in the charset
-            are possible matches, even in multibyte buffers.  */
          if (!fastmap) break;
-         /* We don't need to mark LEADING_CODE_8_BIT_CONTROL specially
-            because it will automatically be set when needed by virtue of
-            being larger than the highest char of its charset (0xbf) but
-            smaller than (1<<BYTEWIDTH).  */
-         for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH;
-              j < (1 << BYTEWIDTH); j++)
-           fastmap[j] = 1;
+         {
+           /* Chars beyond end of bitmap are possible matches.  */
+           for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH;
+                j < (1 << BYTEWIDTH); j++)
+             fastmap[j] = 1;
+         }
+
          /* Fallthrough */
        case charset:
          if (!fastmap) break;
@@ -3948,28 +4063,24 @@ analyse_first (p, pend, fastmap, multibyte)
          for (j = CHARSET_BITMAP_SIZE (&p[-1]) * BYTEWIDTH - 1, p++;
               j >= 0; j--)
            if (!!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) ^ not)
-             {
-               fastmap[j] = 1;
-#ifdef emacs
-               if (j >= 0x80 && j < 0xa0)
-                 fastmap[LEADING_CODE_8_BIT_CONTROL] = 1;
-#endif
-             }
+             fastmap[j] = 1;
 
-         if ((not && multibyte)
-             /* Any character set can possibly contain a character
+#ifdef emacs
+         if (/* Any leading code can possibly start a character
                 which doesn't match the specified set of characters.  */
-             || (CHARSET_RANGE_TABLE_EXISTS_P (&p[-2])
-                 && CHARSET_RANGE_TABLE_BITS (&p[-2]) != 0))
-           /* If we can match a character class, we can match
-              any character set.  */
+             not
+             ||
+             /* If we can match a character class, we can match any
+                multibyte characters.  */
+             (CHARSET_RANGE_TABLE_EXISTS_P (&p[-2])
+              && CHARSET_RANGE_TABLE_BITS (&p[-2]) != 0))
+
            {
-           set_fastmap_for_multibyte_characters:
              if (match_any_multibyte_characters == false)
                {
-                 for (j = 0x80; j < 0xA0; j++) /* XXX */
-                   if (BASE_LEADING_CODE_P (j))
-                     fastmap[j] = 1;
+                 for (j = MIN_MULTIBYTE_LEADING_CODE;
+                      j <= MAX_MULTIBYTE_LEADING_CODE; j++)
+                   fastmap[j] = 1;
                  match_any_multibyte_characters = true;
                }
            }
@@ -3977,9 +4088,10 @@ analyse_first (p, pend, fastmap, multibyte)
          else if (!not && CHARSET_RANGE_TABLE_EXISTS_P (&p[-2])
                   && match_any_multibyte_characters == false)
            {
-             /* Set fastmap[I] 1 where I is a base leading code of each
-                multibyte character in the range table. */
+             /* Set fastmap[I] to 1 where I is a leading code of each
+                multibyte characer in the range table. */
              int c, count;
+             unsigned char lc1, lc2;
 
              /* Make P points the range table.  `+ 2' is to skip flag
                 bits for a character class.  */
@@ -3987,14 +4099,19 @@ analyse_first (p, pend, fastmap, multibyte)
 
              /* Extract the number of ranges in range table into COUNT.  */
              EXTRACT_NUMBER_AND_INCR (count, p);
-             for (; count > 0; count--, p += 2 * 3) /* XXX */
+             for (; count > 0; count--, p += 3)
                {
-                 /* Extract the start of each range.  */
+                 /* Extract the start and end of each range.  */
+                 EXTRACT_CHARACTER (c, p);
+                 lc1 = CHAR_LEADING_CODE (c);
+                 p += 3;
                  EXTRACT_CHARACTER (c, p);
-                 j = CHAR_CHARSET (c);
-                 fastmap[CHARSET_LEADING_CODE_BASE (j)] = 1;
+                 lc2 = CHAR_LEADING_CODE (c);
+                 for (j = lc1; j <= lc2; j++)
+                   fastmap[j] = 1;
                }
            }
+#endif
          break;
 
        case syntaxspec:
@@ -4017,14 +4134,19 @@ analyse_first (p, pend, fastmap, multibyte)
          if (!fastmap) break;
          not = (re_opcode_t)p[-1] == notcategoryspec;
          k = *p++;
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
+         for (j = (1 << BYTEWIDTH); j >= 0; j--)
            if ((CHAR_HAS_CATEGORY (j, k)) ^ not)
              fastmap[j] = 1;
 
-         if (multibyte)
-           /* Any character set can possibly contain a character
-              whose category is K (or not).  */
-           goto set_fastmap_for_multibyte_characters;
+         /* Any leading code can possibly start a character which
+            has or doesn't has the specified category.  */
+         if (match_any_multibyte_characters == false)
+           {
+             for (j = MIN_MULTIBYTE_LEADING_CODE;
+                  j <= MAX_MULTIBYTE_LEADING_CODE; j++)
+               fastmap[j] = 1;
+             match_any_multibyte_characters = true;
+           }
          break;
 
       /* All cases after this match the empty string.  These end with
@@ -4153,15 +4275,14 @@ analyse_first (p, pend, fastmap, multibyte)
    Returns 0 if we succeed, -2 if an internal error.   */
 
 int
-re_compile_fastmap (bufp)
-     struct re_pattern_buffer *bufp;
+re_compile_fastmap (struct re_pattern_buffer *bufp)
 {
   char *fastmap = bufp->fastmap;
   int analysis;
 
   assert (fastmap && bufp->buffer);
 
-  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  memset (fastmap, 0, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
   bufp->fastmap_accurate = 1;      /* It will be when we're done.  */
 
   analysis = analyse_first (bufp->buffer, bufp->buffer + bufp->used,
@@ -4184,11 +4305,7 @@ re_compile_fastmap (bufp)
    freeing the old data.  */
 
 void
-re_set_registers (bufp, regs, num_regs, starts, ends)
-    struct re_pattern_buffer *bufp;
-    struct re_registers *regs;
-    unsigned num_regs;
-    regoff_t *starts, *ends;
+re_set_registers (struct re_pattern_buffer *bufp, struct re_registers *regs, unsigned int num_regs, regoff_t *starts, regoff_t *ends)
 {
   if (num_regs)
     {
@@ -4212,11 +4329,7 @@ WEAK_ALIAS (__re_set_registers, re_set_registers)
    doesn't let you say where to stop matching. */
 
 int
-re_search (bufp, string, size, startpos, range, regs)
-     struct re_pattern_buffer *bufp;
-     const char *string;
-     int size, startpos, range;
-     struct re_registers *regs;
+re_search (struct re_pattern_buffer *bufp, const char *string, int size, int startpos, int range, struct re_registers *regs)
 {
   return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
                      regs, size);
@@ -4257,14 +4370,7 @@ WEAK_ALIAS (__re_search, re_search)
    stack overflow).  */
 
 int
-re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
-     struct re_pattern_buffer *bufp;
-     const char *str1, *str2;
-     int size1, size2;
-     int startpos;
-     int range;
-     struct re_registers *regs;
-     int stop;
+re_search_2 (struct re_pattern_buffer *bufp, const char *str1, int size1, const char *str2, int size2, int startpos, int range, struct re_registers *regs, int stop)
 {
   int val;
   re_char *string1 = (re_char*) str1;
@@ -4274,9 +4380,8 @@ re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
   int total_size = size1 + size2;
   int endpos = startpos + range;
   boolean anchored_start;
-
-  /* Nonzero if we have to concern multibyte character.  */
-  const boolean multibyte = RE_MULTIBYTE_P (bufp);
+  /* Nonzero if we are searching multibyte string.  */
+  const boolean multibyte = RE_TARGET_MULTIBYTE_P (bufp);
 
   /* Check for out-of-range STARTPOS.  */
   if (startpos < 0 || startpos > total_size)
@@ -4319,7 +4424,7 @@ re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
   anchored_start = (bufp->buffer[0] == begline);
 
 #ifdef emacs
-  gl_state.object = re_match_object;
+  gl_state.object = re_match_object; /* Used by SYNTAX_TABLE_BYTE_TO_CHAR. */
   {
     int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (startpos));
 
@@ -4370,74 +4475,75 @@ re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
                      {
                        int buf_charlen;
 
-                       buf_ch = STRING_CHAR_AND_LENGTH (d, range - lim,
-                                                        buf_charlen);
-
+                       buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
                        buf_ch = RE_TRANSLATE (translate, buf_ch);
-                       if (buf_ch >= 0400
-                           || fastmap[buf_ch])
+                       if (fastmap[CHAR_LEADING_CODE (buf_ch)])
                          break;
 
                        range -= buf_charlen;
                        d += buf_charlen;
                      }
                  else
-                   {
-                     /* Convert *d to integer to shut up GCC's
-                        whining about comparison that is always
-                        true.  */
-                     int di = *d;
-
-                     while (range > lim
-                            && !fastmap[RE_TRANSLATE (translate, di)])
-                       {
-                         di = *(++d);
-                         range--;
-                       }
-                   }
-               }
-             else
-               do
-                 {
-                   re_char *d_start = d;
-                   while (range > lim && !fastmap[*d])
+                   while (range > lim)
                      {
+                       register re_wchar_t ch, translated;
+
+                       buf_ch = *d;
+                       ch = RE_CHAR_TO_MULTIBYTE (buf_ch);
+                       translated = RE_TRANSLATE (translate, ch);
+                       if (translated != ch
+                           && (ch = RE_CHAR_TO_UNIBYTE (translated)) >= 0)
+                         buf_ch = ch;
+                       if (fastmap[buf_ch])
+                         break;
                        d++;
                        range--;
                      }
-#ifdef emacs
-                   if (multibyte && range > lim)
+               }
+             else
+               {
+                 if (multibyte)
+                   while (range > lim)
                      {
-                       /* Check that we are at the beginning of a char.  */
-                       int at_boundary;
-                       AT_CHAR_BOUNDARY_P (at_boundary, d, d_start);
-                       if (at_boundary)
+                       int buf_charlen;
+
+                       buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
+                       if (fastmap[CHAR_LEADING_CODE (buf_ch)])
                          break;
-                       else
-                         { /* We have matched an internal byte of a char
-                              rather than the leading byte, so it's a false
-                              positive: we should keep scanning.  */
-                           d++; range--;
-                         }
+                       range -= buf_charlen;
+                       d += buf_charlen;
                      }
-                   else
-#endif
-                     break;
-                 } while (1);
-
+                 else
+                   while (range > lim && !fastmap[*d])
+                     {
+                       d++;
+                       range--;
+                     }
+               }
              startpos += irange - range;
            }
          else                          /* Searching backwards.  */
            {
-             int room = (startpos >= size1
-                         ? size2 + size1 - startpos
-                         : size1 - startpos);
-             buf_ch = RE_STRING_CHAR (d, room);
-             buf_ch = TRANSLATE (buf_ch);
-
-             if (! (buf_ch >= 0400
-                    || fastmap[buf_ch]))
-               goto advance;
+             if (multibyte)
+               {
+                 buf_ch = STRING_CHAR (d);
+                 buf_ch = TRANSLATE (buf_ch);
+                 if (! fastmap[CHAR_LEADING_CODE (buf_ch)])
+                   goto advance;
+               }
+             else
+               {
+                 register re_wchar_t ch, translated;
+
+                 buf_ch = *d;
+                 ch = RE_CHAR_TO_MULTIBYTE (buf_ch);
+                 translated = TRANSLATE (ch);
+                 if (translated != ch
+                     && (ch = RE_CHAR_TO_UNIBYTE (translated)) >= 0)
+                   buf_ch = ch;
+                 if (! fastmap[TRANSLATE (buf_ch)])
+                   goto advance;
+               }
            }
        }
 
@@ -4465,7 +4571,7 @@ re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
            {
              re_char *p = POS_ADDR_VSTRING (startpos);
              re_char *pend = STOP_ADDR_VSTRING (startpos);
-             int len = MULTIBYTE_FORM_LENGTH (p, pend - p);
+             int len = BYTES_BY_CHAR_HEAD (*p);
 
              range -= len;
              if (range < 0)
@@ -4598,8 +4704,7 @@ static int bcmp_translate _RE_ARGS((re_char *s1, re_char *s2,
 /* If the operation is a match against one or more chars,
    return a pointer to the next operation, else return NULL.  */
 static re_char *
-skip_one_char (p)
-     re_char *p;
+skip_one_char (const re_char *p)
 {
   switch (SWITCH_ENUM_CAST (*p++))
     {
@@ -4641,8 +4746,7 @@ skip_one_char (p)
 
 /* Jump over non-matching operations.  */
 static re_char *
-skip_noops (p, pend)
-     re_char *p, *pend;
+skip_noops (const re_char *p, const re_char *pend)
 {
   int mcnt;
   while (p < pend)
@@ -4669,9 +4773,7 @@ skip_noops (p, pend)
 
 /* Non-zero if "p1 matches something" implies "p2 fails".  */
 static int
-mutually_exclusive_p (bufp, p1, p2)
-     struct re_pattern_buffer *bufp;
-     re_char *p1, *p2;
+mutually_exclusive_p (struct re_pattern_buffer *bufp, const re_char *p1, const re_char *p2)
 {
   re_opcode_t op2;
   const boolean multibyte = RE_MULTIBYTE_P (bufp);
@@ -4711,11 +4813,11 @@ mutually_exclusive_p (bufp, p1, p2)
       {
        register re_wchar_t c
          = (re_opcode_t) *p2 == endline ? '\n'
-         : RE_STRING_CHAR (p2 + 2, pend - p2 - 2);
+         : RE_STRING_CHAR (p2 + 2, multibyte);
 
        if ((re_opcode_t) *p1 == exactn)
          {
-           if (c != RE_STRING_CHAR (p1 + 2, pend - p1 - 2))
+           if (c != RE_STRING_CHAR (p1 + 2, multibyte))
              {
                DEBUG_PRINT3 ("  '%c' != '%c' => fast loop.\n", c, p1[2]);
                return 1;
@@ -4729,7 +4831,7 @@ mutually_exclusive_p (bufp, p1, p2)
 
            /* Test if C is listed in charset (or charset_not)
               at `p1'.  */
-           if (SINGLE_BYTE_CHAR_P (c))
+           if (! multibyte || IS_REAL_ASCII (c))
              {
                if (c < CHARSET_BITMAP_SIZE (p1) * BYTEWIDTH
                    && p1[2 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
@@ -4772,9 +4874,10 @@ mutually_exclusive_p (bufp, p1, p2)
             size of bitmap table of P1 is extracted by
             using macro `CHARSET_BITMAP_SIZE'.
 
-            Since we know that all the character listed in
-            P2 is ASCII, it is enough to test only bitmap
-            table of P1.  */
+            In a multibyte case, we know that all the character
+            listed in P2 is ASCII.  In a unibyte case, P1 has only a
+            bitmap table.  So, in both cases, it is enough to test
+            only the bitmap table of P1.  */
 
          if ((re_opcode_t) *p1 == charset)
            {
@@ -4908,19 +5011,13 @@ Lisp_Object re_match_object;
    matched substring.  */
 
 int
-re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
-     struct re_pattern_buffer *bufp;
-     const char *string1, *string2;
-     int size1, size2;
-     int pos;
-     struct re_registers *regs;
-     int stop;
+re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, const char *string2, int size2, int pos, struct re_registers *regs, int stop)
 {
   int result;
 
 #ifdef emacs
   int charpos;
-  gl_state.object = re_match_object;
+  gl_state.object = re_match_object; /* Used by SYNTAX_TABLE_BYTE_TO_CHAR. */
   charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (pos));
   SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1);
 #endif
@@ -4932,16 +5029,11 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
 }
 WEAK_ALIAS (__re_match_2, re_match_2)
 
+
 /* This is a separate function so that we can force an alloca cleanup
    afterwards.  */
 static int
-re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
-     struct re_pattern_buffer *bufp;
-     re_char *string1, *string2;
-     int size1, size2;
-     int pos;
-     struct re_registers *regs;
-     int stop;
+re_match_2_internal (struct re_pattern_buffer *bufp, const re_char *string1, int size1, const re_char *string2, int size2, int pos, struct re_registers *regs, int stop)
 {
   /* General temporaries.  */
   int mcnt;
@@ -4968,12 +5060,15 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
   re_char *p = bufp->buffer;
   re_char *pend = p + bufp->used;
 
-  /* We use this to map every character in the string.  */
+  /* We use this to map every character in the string. */
   RE_TRANSLATE_TYPE translate = bufp->translate;
 
-  /* Nonzero if we have to concern multibyte character.  */
+  /* Nonzero if BUFP is setup from a multibyte regex.  */
   const boolean multibyte = RE_MULTIBYTE_P (bufp);
 
+  /* Nonzero if STRING1/STRING2 are multibyte.  */
+  const boolean target_multibyte = RE_TARGET_MULTIBYTE_P (bufp);
+
   /* Failure point stack.  Each place that can handle a failure further
      down the line pushes a failure point on this stack.  It consists of
      regstart, and regend for all registers corresponding to
@@ -5325,63 +5420,98 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
          /* Remember the start point to rollback upon failure.  */
          dfail = d;
 
+#ifndef emacs
          /* This is written out as an if-else so we don't waste time
             testing `translate' inside the loop.  */
          if (RE_TRANSLATE_P (translate))
-           {
-             if (multibyte)
-               do
+           do
+             {
+               PREFETCH ();
+               if (RE_TRANSLATE (translate, *d) != *p++)
+                 {
+                   d = dfail;
+                   goto fail;
+                 }
+               d++;
+             }
+           while (--mcnt);
+         else
+           do
+             {
+               PREFETCH ();
+               if (*d++ != *p++)
                  {
-                   int pat_charlen, buf_charlen;
-                   unsigned int pat_ch, buf_ch;
+                   d = dfail;
+                   goto fail;
+                 }
+             }
+           while (--mcnt);
+#else  /* emacs */
+         /* The cost of testing `translate' is comparatively small.  */
+         if (target_multibyte)
+           do
+             {
+               int pat_charlen, buf_charlen;
+               int pat_ch, buf_ch;
 
-                   PREFETCH ();
-                   pat_ch = STRING_CHAR_AND_LENGTH (p, pend - p, pat_charlen);
-                   buf_ch = STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen);
+               PREFETCH ();
+               if (multibyte)
+                 pat_ch = STRING_CHAR_AND_LENGTH (p, pat_charlen);
+               else
+                 {
+                   pat_ch = RE_CHAR_TO_MULTIBYTE (*p);
+                   pat_charlen = 1;
+                 }
+               buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
 
-                   if (RE_TRANSLATE (translate, buf_ch)
-                       != pat_ch)
-                     {
-                       d = dfail;
-                       goto fail;
-                     }
+               if (TRANSLATE (buf_ch) != pat_ch)
+                 {
+                   d = dfail;
+                   goto fail;
+                 }
+
+               p += pat_charlen;
+               d += buf_charlen;
+               mcnt -= pat_charlen;
+             }
+           while (mcnt > 0);
+         else
+           do
+             {
+               int pat_charlen, buf_charlen;
+               int pat_ch, buf_ch;
 
-                   p += pat_charlen;
-                   d += buf_charlen;
-                   mcnt -= pat_charlen;
+               PREFETCH ();
+               if (multibyte)
+                 {
+                   pat_ch = STRING_CHAR_AND_LENGTH (p, pat_charlen);
+                   pat_ch = RE_CHAR_TO_UNIBYTE (pat_ch);
                  }
-               while (mcnt > 0);
-             else
-               do
+               else
                  {
-                   /* Avoid compiler whining about comparison being
-                      always true.  */
-                   int di;
-
-                   PREFETCH ();
-                   di = *d;
-                   if (RE_TRANSLATE (translate, di) != *p++)
-                     {
-                       d = dfail;
-                       goto fail;
-                     }
-                   d++;
+                   pat_ch = *p;
+                   pat_charlen = 1;
                  }
-               while (--mcnt);
-           }
-         else
-           {
-             do
-               {
-                 PREFETCH ();
-                 if (*d++ != *p++)
-                   {
-                     d = dfail;
-                     goto fail;
-                   }
-               }
-             while (--mcnt);
-           }
+               buf_ch = RE_CHAR_TO_MULTIBYTE (*d);
+               if (! CHAR_BYTE8_P (buf_ch))
+                 {
+                   buf_ch = TRANSLATE (buf_ch);
+                   buf_ch = RE_CHAR_TO_UNIBYTE (buf_ch);
+                   if (buf_ch < 0)
+                     buf_ch = *d;
+                 }
+               else
+                 buf_ch = *d;
+               if (buf_ch != pat_ch)
+                 {
+                   d = dfail;
+                   goto fail;
+                 }
+               p += pat_charlen;
+               d++;
+             }
+           while (--mcnt);
+#endif
          break;
 
 
@@ -5394,7 +5524,8 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            DEBUG_PRINT1 ("EXECUTING anychar.\n");
 
            PREFETCH ();
-           buf_ch = RE_STRING_CHAR_AND_LENGTH (d, dend - d, buf_charlen);
+           buf_ch = RE_STRING_CHAR_AND_LENGTH (d, buf_charlen,
+                                               target_multibyte);
            buf_ch = TRANSLATE (buf_ch);
 
            if ((!(bufp->syntax & RE_DOT_NEWLINE)
@@ -5427,6 +5558,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
               in the initial byte-length of the command.  */
            int count = 0;
 
+           /* Whether matching against a unibyte character.  */
+           boolean unibyte_char = false;
+
            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
 
            range_table_exists = CHARSET_RANGE_TABLE_EXISTS_P (&p[-1]);
@@ -5438,10 +5572,38 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              }
 
            PREFETCH ();
-           c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len);
-           c = TRANSLATE (c); /* The character to match.  */
+           c = RE_STRING_CHAR_AND_LENGTH (d, len, target_multibyte);
+           if (target_multibyte)
+             {
+               int c1;
+
+               c = TRANSLATE (c);
+               c1 = RE_CHAR_TO_UNIBYTE (c);
+               if (c1 >= 0)
+                 {
+                   unibyte_char = true;
+                   c = c1;
+                 }
+             }
+           else
+             {
+               int c1 = RE_CHAR_TO_MULTIBYTE (c);
+
+               if (! CHAR_BYTE8_P (c1))
+                 {
+                   c1 = TRANSLATE (c1);
+                   c1 = RE_CHAR_TO_UNIBYTE (c1);
+                   if (c1 >= 0)
+                     {
+                       unibyte_char = true;
+                       c = c1;
+                     }
+                 }
+               else
+                 unibyte_char = true;
+             }
 
-           if (SINGLE_BYTE_CHAR_P (c))
+           if (unibyte_char && c < (1 << BYTEWIDTH))
              {                 /* Lookup bitmap.  */
                /* Cast to `unsigned' instead of `unsigned char' in
                   case the bit list is a full 32 bytes long.  */
@@ -5581,7 +5743,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                /* Compare that many; failure if mismatch, else move
                   past them.  */
                if (RE_TRANSLATE_P (translate)
-                   ? bcmp_translate (d, d2, mcnt, translate, multibyte)
+                   ? bcmp_translate (d, d2, mcnt, translate, target_multibyte)
                    : memcmp (d, d2, mcnt))
                  {
                    d = dfail;
@@ -5604,7 +5766,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            }
          else
            {
-             unsigned char c;
+             unsigned c;
              GET_CHAR_BEFORE_2 (c, d, string1, end1, string2, end2);
              if (c == '\n')
                break;
@@ -5871,6 +6033,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                 is the character at D, and S2 is the syntax of C2.  */
              re_wchar_t c1, c2;
              int s1, s2;
+             int dummy;
 #ifdef emacs
              int offset = PTR_TO_OFFSET (d - 1);
              int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset);
@@ -5882,7 +6045,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
 #endif
              PREFETCH_NOLIMIT ();
-             c2 = RE_STRING_CHAR (d, dend - d);
+             GET_CHAR_AFTER (c2, d, dummy);
              s2 = SYNTAX (c2);
 
              if (/* Case 2: Only one of S1 and S2 is Sword.  */
@@ -5911,13 +6074,14 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                 is the character at D, and S2 is the syntax of C2.  */
              re_wchar_t c1, c2;
              int s1, s2;
+             int dummy;
 #ifdef emacs
              int offset = PTR_TO_OFFSET (d);
              int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset);
              UPDATE_SYNTAX_TABLE (charpos);
 #endif
              PREFETCH ();
-             c2 = RE_STRING_CHAR (d, dend - d);
+             GET_CHAR_AFTER (c2, d, dummy);
              s2 = SYNTAX (c2);
 
              /* Case 2: S2 is not Sword. */
@@ -5955,6 +6119,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                 is the character at D, and S2 is the syntax of C2.  */
              re_wchar_t c1, c2;
              int s1, s2;
+             int dummy;
 #ifdef emacs
              int offset = PTR_TO_OFFSET (d) - 1;
              int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (offset);
@@ -5971,9 +6136,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              if (!AT_STRINGS_END (d))
                {
                  PREFETCH_NOLIMIT ();
-                 c2 = RE_STRING_CHAR (d, dend - d);
+                 GET_CHAR_AFTER (c2, d, dummy);
 #ifdef emacs
-                 UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
+                 UPDATE_SYNTAX_TABLE_FORWARD (charpos);
 #endif
                  s2 = SYNTAX (c2);
 
@@ -6005,7 +6170,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              UPDATE_SYNTAX_TABLE (charpos);
 #endif
              PREFETCH ();
-             c2 = RE_STRING_CHAR (d, dend - d);
+             c2 = RE_STRING_CHAR (d, target_multibyte);
              s2 = SYNTAX (c2);
 
              /* Case 2: S2 is neither Sword nor Ssymbol. */
@@ -6058,7 +6223,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              if (!AT_STRINGS_END (d))
                {
                  PREFETCH_NOLIMIT ();
-                 c2 = RE_STRING_CHAR (d, dend - d);
+                 c2 = RE_STRING_CHAR (d, target_multibyte);
 #ifdef emacs
                  UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
 #endif
@@ -6088,8 +6253,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            int len;
            re_wchar_t c;
 
-           c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len);
-
+           GET_CHAR_AFTER (c, d, len);
            if ((SYNTAX (c) != (enum syntaxcode) mcnt) ^ not)
              goto fail;
            d += len;
@@ -6125,8 +6289,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            int len;
            re_wchar_t c;
 
-           c = RE_STRING_CHAR_AND_LENGTH (d, dend - d, len);
-
+           GET_CHAR_AFTER (c, d, len);
            if ((!CHAR_HAS_CATEGORY (c, mcnt)) ^ not)
              goto fail;
            d += len;
@@ -6201,11 +6364,8 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
    bytes; nonzero otherwise.  */
 
 static int
-bcmp_translate (s1, s2, len, translate, multibyte)
-     re_char *s1, *s2;
-     register int len;
-     RE_TRANSLATE_TYPE translate;
-     const int multibyte;
+bcmp_translate (const re_char *s1, const re_char *s2, register int len,
+               RE_TRANSLATE_TYPE translate, const int target_multibyte)
 {
   register re_char *p1 = s1, *p2 = s2;
   re_char *p1_end = s1 + len;
@@ -6218,8 +6378,8 @@ bcmp_translate (s1, s2, len, translate, multibyte)
       int p1_charlen, p2_charlen;
       re_wchar_t p1_ch, p2_ch;
 
-      p1_ch = RE_STRING_CHAR_AND_LENGTH (p1, p1_end - p1, p1_charlen);
-      p2_ch = RE_STRING_CHAR_AND_LENGTH (p2, p2_end - p2, p2_charlen);
+      GET_CHAR_AFTER (p1_ch, p1, p1_charlen);
+      GET_CHAR_AFTER (p2_ch, p2, p2_charlen);
 
       if (RE_TRANSLATE (translate, p1_ch)
          != RE_TRANSLATE (translate, p2_ch))
@@ -6246,17 +6406,10 @@ bcmp_translate (s1, s2, len, translate, multibyte)
    We call regex_compile to do the actual compilation.  */
 
 const char *
-re_compile_pattern (pattern, length, bufp)
-     const char *pattern;
-     size_t length;
-     struct re_pattern_buffer *bufp;
+re_compile_pattern (const char *pattern, size_t length, struct re_pattern_buffer *bufp)
 {
   reg_errcode_t ret;
 
-#ifdef emacs
-  gl_state.current_syntax_table = current_buffer->syntax_table;
-#endif
-
   /* GNU code is written to assume at least RE_NREGS registers will be set
      (and at least one extra will be -1).  */
   bufp->regs_allocated = REGS_UNALLOCATED;
@@ -6586,20 +6739,17 @@ void
 regfree (preg)
     regex_t *preg;
 {
-  if (preg->buffer != NULL)
-    free (preg->buffer);
+  free (preg->buffer);
   preg->buffer = NULL;
 
   preg->allocated = 0;
   preg->used = 0;
 
-  if (preg->fastmap != NULL)
-    free (preg->fastmap);
+  free (preg->fastmap);
   preg->fastmap = NULL;
   preg->fastmap_accurate = 0;
 
-  if (preg->translate != NULL)
-    free (preg->translate);
+  free (preg->translate);
   preg->translate = NULL;
 }
 WEAK_ALIAS (__regfree, regfree)