(RE_STRING_CHAR): New macro.
[gnulib.git] / regex.c
diff --git a/regex.c b/regex.c
index 809a7d2..711f7c7 100644 (file)
--- a/regex.c
+++ b/regex.c
@@ -37,9 +37,7 @@
 
 #ifdef emacs
 /* Converts the pointer to the char to BEG-based offset from the start.         */
-#define PTR_TO_OFFSET(d)                                               \
-       POS_AS_IN_BUFFER (MATCHING_IN_FIRST_STRING                      \
-                         ? (d) - string1 : (d) - (string2 - size1))
+#define PTR_TO_OFFSET(d) POS_AS_IN_BUFFER (POINTER_TO_OFFSET (d))
 #define POS_AS_IN_BUFFER(p) ((p) + (NILP (re_match_object) || BUFFERP (re_match_object)))
 #else
 #define PTR_TO_OFFSET(d) 0
@@ -83,6 +81,9 @@
 #define realloc xrealloc
 #define free xfree
 
+#define RE_STRING_CHAR(p, s) \
+  (multibyte ? (STRING_CHAR (p, s)) : (*(p)))
+
 #else  /* not emacs */
 
 /* If we are not linking with Emacs proper,
@@ -189,12 +190,16 @@ init_syntax_once ()
 #define SAME_CHARSET_P(c1, c2) (1)
 #define MULTIBYTE_FORM_LENGTH(p, s) (1)
 #define STRING_CHAR(p, s) (*(p))
+#define RE_STRING_CHAR STRING_CHAR
 #define STRING_CHAR_AND_LENGTH(p, s, actual_len) ((actual_len) = 1, *(p))
-#define GET_CHAR_AFTER_2(c, p, str1, end1, str2, end2) \
-  (c = ((p) == (end1) ? *(str2) : *(p)))
 #define GET_CHAR_BEFORE_2(c, p, str1, end1, str2, end2) \
   (c = ((p) == (str2) ? *((end1) - 1) : *((p) - 1)))
 #endif /* not emacs */
+
+#ifndef RE_TRANSLATE
+#define RE_TRANSLATE(TBL, C) ((unsigned char)(TBL)[C])
+#define RE_TRANSLATE_P(TBL) (TBL)
+#endif
 \f
 /* Get the interface, including the syntax bits.  */
 #include "regex.h"
@@ -434,6 +439,9 @@ char *alloca ();
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
+/* Type of source-pattern and string chars.  */
+typedef const unsigned char re_char;
+
 typedef char boolean;
 #define false 0
 #define true 1
@@ -518,13 +526,6 @@ typedef enum
           current string position when executed.  */
   on_failure_keep_string_jump,
 
-       /* Like `on_failure_jump', except that it assumes that the
-          pattern following it is mutually exclusive with the pattern
-          at the destination of the jump:  if one matches something,
-          the other won't match at all.
-          Always used via `on_failure_jump_smart'.  */
-  on_failure_jump_exclusive,
-
        /* Just like `on_failure_jump', except that it checks that we
           don't get stuck in an infinite loop (matching an empty string
           indefinitely).  */
@@ -533,8 +534,9 @@ typedef enum
         /* A smart `on_failure_jump' used for greedy * and + operators.
           It analyses the loop before which it is put and if the
           loop does not require backtracking, it changes itself to
-          `on_failure_jump_exclusive', else it just defaults to
-          changing itself into `on_failure_jump_loop'.  */
+          `on_failure_keep_string_jump' and short-circuits the loop,
+          else it just defaults to changing itself into `on_failure_jump'.
+          It assumes that it is pointing to just past a `jump'.  */
   on_failure_jump_smart,
 
        /* Followed by two-byte relative address and two-byte number n.
@@ -764,17 +766,17 @@ extract_number_and_incr (destination, source)
 /* It is useful to test things that ``must'' be true when debugging.  */
 #include <assert.h>
 
-static int debug = 0;
+static int debug = -100000;
 
 #define DEBUG_STATEMENT(e) e
-#define DEBUG_PRINT1(x) if (debug) printf (x)
-#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
-#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
-#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT1(x) if (debug > 0) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug > 0) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug > 0) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug > 0) printf (x1, x2, x3, x4)
 #define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)                          \
-  if (debug) print_partial_compiled_pattern (s, e)
+  if (debug > 0) print_partial_compiled_pattern (s, e)
 #define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)                 \
-  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+  if (debug > 0) print_double_string (w, s1, sz1, s2, sz2)
 
 
 /* Print the fastmap in human-readable form.  */
@@ -837,6 +839,10 @@ print_partial_compiled_pattern (start, end)
          printf ("/no_op");
          break;
 
+       case succeed:
+         printf ("/succeed");
+         break;
+
        case exactn:
          mcnt = *p++;
          printf ("/exactn/%d", mcnt);
@@ -869,9 +875,8 @@ print_partial_compiled_pattern (start, end)
          {
            register int c, last = -100;
            register int in_range = 0;
-           int length = *p & 0x7f;
-           int has_range_table = *p & 0x80;
-           int range_length = p[length + 2] + p[length + 3] * 0x100;
+           int length = CHARSET_BITMAP_SIZE (p - 1);
+           int has_range_table = CHARSET_RANGE_TABLE_EXISTS_P (p - 1);
 
            printf ("/charset [%s",
                    (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
@@ -901,20 +906,23 @@ print_partial_compiled_pattern (start, end)
                  last = c;
              }
 
-           p += 1 + length;
-
            if (in_range)
              putchar (last);
 
            putchar (']');
 
-           if (has_range_table)
-             printf ("has-range-table");
+           p += 1 + length;
 
-           /* ??? Should print the range table; for now,
-              just skip it.  */
            if (has_range_table)
-             p += 4 + 6 * range_length;
+             {
+               int count;
+               printf ("has-range-table");
+
+               /* ??? Should print the range table; for now, just skip it.  */
+               p += 2;         /* skip range table bits */
+               EXTRACT_NUMBER_AND_INCR (count, p);
+               p = CHARSET_RANGE_TABLE_END (p, count);
+             }
          }
          break;
 
@@ -936,11 +944,6 @@ print_partial_compiled_pattern (start, end)
          printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
          break;
 
-       case on_failure_jump_exclusive:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/on_failure_jump_exclusive to %d", p + mcnt - start);
-         break;
-
        case on_failure_jump_loop:
          extract_number_and_incr (&mcnt, &p);
          printf ("/on_failure_jump_loop to %d", p + mcnt - start);
@@ -959,19 +962,19 @@ print_partial_compiled_pattern (start, end)
        case succeed_n:
          extract_number_and_incr (&mcnt, &p);
          extract_number_and_incr (&mcnt2, &p);
-         printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+         printf ("/succeed_n to %d, %d times", p - 2 + mcnt - start, mcnt2);
          break;
 
        case jump_n:
          extract_number_and_incr (&mcnt, &p);
          extract_number_and_incr (&mcnt2, &p);
-         printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+         printf ("/jump_n to %d, %d times", p - 2 + mcnt - start, mcnt2);
          break;
 
        case set_number_at:
          extract_number_and_incr (&mcnt, &p);
          extract_number_and_incr (&mcnt2, &p);
-         printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+         printf ("/set_number_at location %d to %d", p - 2 + mcnt - start, mcnt2);
          break;
 
        case wordbound:
@@ -1072,9 +1075,9 @@ print_compiled_pattern (bufp)
 
 void
 print_double_string (where, string1, size1, string2, size2)
-    const char *where;
-    const char *string1;
-    const char *string2;
+    re_char *where;
+    re_char *string1;
+    re_char *string2;
     int size1;
     int size2;
 {
@@ -1229,7 +1232,7 @@ int re_max_failures = 4000;
 
 union fail_stack_elt
 {
-  unsigned char *pointer;
+   const unsigned char *pointer;
   unsigned int integer;
 };
 
@@ -1355,7 +1358,7 @@ typedef struct
 
 /* Used to examine the stack (to detect infinite loops).  */
 #define FAILURE_PAT(h) fail_stack.stack[(h) - 1].pointer
-#define FAILURE_STR(h) ((char*)fail_stack.stack[(h) - 2].pointer)
+#define FAILURE_STR(h) (fail_stack.stack[(h) - 2].pointer)
 #define NEXT_FAILURE_HANDLE(h) fail_stack.stack[(h) - 3].integer
 #define TOP_FAILURE_HANDLE() fail_stack.frame
 
@@ -1400,10 +1403,10 @@ do {                                                                    \
          || FAILURE_STR (failure) == NULL))                            \
     {                                                                  \
       assert (FAILURE_PAT (failure) >= bufp->buffer                    \
-             && FAILURE_PAT (failure) <= bufp->buffer + bufp->used);\
+             && FAILURE_PAT (failure) <= bufp->buffer + bufp->used);   \
       if (FAILURE_PAT (failure) == pat_cur)                            \
        goto fail;                                                      \
-      DEBUG_PRINT2 ("  Other pattern: %p\n", FAILURE_PAT (failure));\
+      DEBUG_PRINT2 ("  Other pattern: %p\n", FAILURE_PAT (failure));   \
       failure = NEXT_FAILURE_HANDLE(failure);                          \
     }                                                                  \
   DEBUG_PRINT2 ("  Other string: %p\n", FAILURE_STR (failure));                \
@@ -1490,7 +1493,7 @@ do {                                                                      \
   /* If the saved string location is NULL, it came from an             \
      on_failure_keep_string_jump opcode, and we want to throw away the \
      saved NULL, thus retaining our current position in the string.  */        \
-  str = (char *) POP_FAILURE_POINTER ();                               \
+  str = (re_char *) POP_FAILURE_POINTER ();                            \
   DEBUG_PRINT2 ("  Popping string %p: `", str);                                \
   DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);     \
   DEBUG_PRINT1 ("'\n");                                                        \
@@ -1512,10 +1515,20 @@ do {                                                                    \
 \f
 /* Subroutine declarations and macros for regex_compile.  */
 
-static void store_op1 (), store_op2 ();
-static void insert_op1 (), insert_op2 ();
-static boolean at_begline_loc_p (), at_endline_loc_p ();
-static boolean group_in_compile_stack ();
+static void store_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc, int arg));
+static void store_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+                               int arg1, int arg2));
+static void insert_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+                                int arg, unsigned char *end));
+static void insert_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+                               int arg1, int arg2, unsigned char *end));
+static boolean at_begline_loc_p _RE_ARGS((const unsigned char *pattern,
+                                         const unsigned char *p,
+                                         reg_syntax_t syntax));
+static boolean at_endline_loc_p _RE_ARGS((const unsigned char *p,
+                                         const unsigned char *pend,
+                                         reg_syntax_t syntax));
+static unsigned char *skip_one_char _RE_ARGS((unsigned char *p));
 
 /* Fetch the next character in the uncompiled pattern---translating it
    if necessary.  Also cast from a signed character in the constant
@@ -1523,8 +1536,8 @@ static boolean group_in_compile_stack ();
    as an array index (in, e.g., `translate').  */
 #ifndef PATFETCH
 #define PATFETCH(c)                                                    \
-  do {if (p == pend) return REG_EEND;                                  \
-    c = (unsigned char) *p++;                                          \
+  do {                                                                 \
+    PATFETCH_RAW (c);                                                  \
     if (RE_TRANSLATE_P (translate)) c = RE_TRANSLATE (translate, c);   \
   } while (0)
 #endif
@@ -1533,7 +1546,7 @@ static boolean group_in_compile_stack ();
    translation.         */
 #define PATFETCH_RAW(c)                                                        \
   do {if (p == pend) return REG_EEND;                                  \
-    c = (unsigned char) *p++;                                          \
+    c = *p++;                                                          \
   } while (0)
 
 /* Go backwards one character in the pattern.  */
@@ -1546,8 +1559,7 @@ static boolean group_in_compile_stack ();
    when we use a character as a subscript we must make it unsigned.  */
 #ifndef TRANSLATE
 #define TRANSLATE(d) \
-  (RE_TRANSLATE_P (translate) \
-   ? (unsigned) RE_TRANSLATE (translate, (unsigned) (d)) : (d))
+  (RE_TRANSLATE_P (translate) ? RE_TRANSLATE (translate, (d)) : (d))
 #endif
 
 
@@ -1758,7 +1770,7 @@ struct range_table_work_area
 
 /* Get the next unsigned number in the uncompiled pattern.  */
 #define GET_UNSIGNED_NUMBER(num)                                       \
 { if (p != pend)                                                     \
do { if (p != pend)                                                   \
      {                                                                 \
        PATFETCH (c);                                                   \
        while (ISDIGIT (c))                                             \
@@ -1771,7 +1783,7 @@ struct range_table_work_area
           PATFETCH (c);                                                \
         }                                                              \
        }                                                               \
-    }
+    } while (0)
 
 #define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
 
@@ -1785,6 +1797,12 @@ struct range_table_work_area
     || STREQ (string, "word")                                          \
     || STREQ (string, "ascii") || STREQ (string, "nonascii")           \
     || STREQ (string, "unibyte") || STREQ (string, "multibyte"))
+
+/* QUIT is only used on NTemacs.  */
+#if !defined (WINDOWSNT) || !defined (emacs)
+#undef QUIT
+#define QUIT
+#endif
 \f
 #ifndef MATCH_MAY_ALLOCATE
 
@@ -1802,8 +1820,8 @@ static fail_stack_type fail_stack;
    but never make them smaller.         */
 static int regs_allocated_size;
 
-static const char **    regstart, **     regend;
-static const char **best_regstart, **best_regend;
+static re_char **     regstart, **     regend;
+static re_char **best_regstart, **best_regend;
 
 /* Make the register vectors big enough for NUM_REGS registers,
    but don't make them smaller.         */
@@ -1814,10 +1832,10 @@ regex_grow_registers (num_regs)
 {
   if (num_regs > regs_allocated_size)
     {
-      RETALLOC_IF (regstart,    num_regs, const char *);
-      RETALLOC_IF (regend,      num_regs, const char *);
-      RETALLOC_IF (best_regstart, num_regs, const char *);
-      RETALLOC_IF (best_regend,         num_regs, const char *);
+      RETALLOC_IF (regstart,    num_regs, re_char *);
+      RETALLOC_IF (regend,      num_regs, re_char *);
+      RETALLOC_IF (best_regstart, num_regs, re_char *);
+      RETALLOC_IF (best_regend,         num_regs, re_char *);
 
       regs_allocated_size = num_regs;
     }
@@ -1825,6 +1843,10 @@ regex_grow_registers (num_regs)
 
 #endif /* not MATCH_MAY_ALLOCATE */
 \f
+static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type
+                                                compile_stack,
+                                                regnum_t regnum));
+
 /* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
    Returns one of error codes defined in `regex.h', or zero for success.
 
@@ -1862,7 +1884,7 @@ do {                                                                      \
 
 static reg_errcode_t
 regex_compile (pattern, size, syntax, bufp)
-     const char *pattern;
+     re_char *pattern;
      int size;
      reg_syntax_t syntax;
      struct re_pattern_buffer *bufp;
@@ -1873,7 +1895,7 @@ regex_compile (pattern, size, syntax, bufp)
   register unsigned int c, c1;
 
   /* A random temporary spot in PATTERN.  */
-  const char *p1;
+  re_char *p1;
 
   /* Points to the end of the buffer, where we should append.  */
   register unsigned char *b;
@@ -1884,11 +1906,11 @@ regex_compile (pattern, size, syntax, bufp)
   /* Points to the current (ending) position in the pattern.  */
 #ifdef AIX
   /* `const' makes AIX compiler fail.  */
-  char *p = pattern;
+  unsigned char *p = pattern;
 #else
-  const char *p = pattern;
+  re_char *p = pattern;
 #endif
-  const char *pend = pattern + size;
+  re_char *pend = pattern + size;
 
   /* How to translate the characters in the pattern.  */
   RE_TRANSLATE_TYPE translate = bufp->translate;
@@ -1909,7 +1931,7 @@ regex_compile (pattern, size, syntax, bufp)
 
   /* Place in the uncompiled pattern (i.e., the {) to
      which to go back if the interval is invalid.  */
-  const char *beg_interval;
+  re_char *beg_interval;
 
   /* Address of the place where a forward jump should go to the end of
      the containing expression.         Each alternative of an `or' -- except the
@@ -1925,9 +1947,9 @@ regex_compile (pattern, size, syntax, bufp)
   struct range_table_work_area range_table_work;
 
 #ifdef DEBUG
-  /* debug = 1; */
+  debug++;
   DEBUG_PRINT1 ("\nCompiling pattern: ");
-  if (debug)
+  if (debug > 0)
     {
       unsigned debug_count;
 
@@ -2047,12 +2069,9 @@ regex_compile (pattern, size, syntax, bufp)
            }
 
          {
-           /* Are we optimizing this jump?  */
-           boolean keep_string_p = false;
-
            /* 1 means zero (many) matches is allowed.  */
-           char zero_times_ok = 0, many_times_ok = 0;
-           char greedy = 1;
+           boolean zero_times_ok = 0, many_times_ok = 0;
+           boolean greedy = 1;
 
            /* If there is a sequence of repetition chars, collapse it
               down to just one (the right one).  We can't combine
@@ -2100,73 +2119,60 @@ regex_compile (pattern, size, syntax, bufp)
                  }
 
                /* If we get here, we found another repeat character.  */
-              }
+             }
 
            /* Star, etc. applied to an empty pattern is equivalent
               to an empty pattern.  */
-           if (!laststart)
+           if (!laststart || laststart == b)
              break;
 
            /* Now we know whether or not zero matches is allowed
               and also whether or not two or more matches is allowed.  */
            if (greedy)
              {
-           if (many_times_ok)
-             { /* More than one repetition is allowed, so put in at the
-                  end a backward relative jump from `b' to before the next
-                  jump we're going to put in below (which jumps from
-                  laststart to after this jump).
-
-                  But if we are at the `*' in the exact sequence `.*\n',
-                  insert an unconditional jump backwards to the .,
-                  instead of the beginning of the loop.  This way we only
-                  push a failure point once, instead of every time
-                  through the loop.  */
-               assert (p - 1 > pattern);
-
-               /* Allocate the space for the jump.  */
-               GET_BUFFER_SPACE (3);
-
-               /* We know we are not at the first character of the pattern,
-                  because laststart was nonzero.  And we've already
-                  incremented `p', by the way, to be the character after
-                  the `*'.  Do we have to do something analogous here
-                  for null bytes, because of RE_DOT_NOT_NULL?  */
-               if (TRANSLATE ((unsigned char)*(p - 2)) == TRANSLATE ('.')
-                   && zero_times_ok
-                   && p < pend
-                   && TRANSLATE ((unsigned char)*p) == TRANSLATE ('\n')
-                   && !(syntax & RE_DOT_NEWLINE))
-                 { /* We have .*\n.  */
-                   STORE_JUMP (jump, b, laststart);
-                   keep_string_p = true;
+               if (many_times_ok)
+                 {
+                   boolean simple = skip_one_char (laststart) == b;
+                   unsigned int startoffset = 0;
+                   assert (skip_one_char (laststart) <= b);
+                   
+                   if (!zero_times_ok && simple)
+                     { /* Since simple * loops can be made faster by using
+                          on_failure_keep_string_jump, we turn simple P+
+                          into PP* if P is simple.  */
+                       unsigned char *p1, *p2;
+                       startoffset = b - laststart;
+                       GET_BUFFER_SPACE (startoffset);
+                       p1 = b; p2 = laststart;
+                       while (p2 < p1)
+                         *b++ = *p2++;
+                       zero_times_ok = 1;
+                     }
+
+                   GET_BUFFER_SPACE (6);
+                   if (!zero_times_ok)
+                     /* A + loop.  */
+                     STORE_JUMP (on_failure_jump_loop, b, b + 6);
+                   else
+                     /* Simple * loops can use on_failure_keep_string_jump
+                        depending on what follows.  But since we don't know
+                        that yet, we leave the decision up to
+                        on_failure_jump_smart.  */
+                     INSERT_JUMP (simple ? on_failure_jump_smart
+                                  : on_failure_jump_loop,
+                                  laststart + startoffset, b + 6);
+                   b += 3;
+                   STORE_JUMP (jump, b, laststart + startoffset);
+                   b += 3;
                  }
                else
-                 STORE_JUMP (jump, b, laststart - 3);
-               
-               /* We've added more stuff to the buffer.  */
-               b += 3;
-             }
-
-           /* On failure, jump from laststart to b + 3, which will be the
-              end of the buffer after this jump is inserted.  */
-           GET_BUFFER_SPACE (3);
-           if (!zero_times_ok)
-             {
-               assert (many_times_ok);
-               INSERT_JUMP (on_failure_jump_smart, b - 3, b + 3);
-               pending_exact = 0;
-               b += 3;
-             }
-           else
-             {
-               INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
-                            : !many_times_ok ?
-                            on_failure_jump : on_failure_jump_smart,
-                            laststart, b + 3);
-               pending_exact = 0;
-               b += 3;
-             }
+                 {
+                   /* A simple ? pattern.  */
+                   assert (zero_times_ok);
+                   GET_BUFFER_SPACE (3);
+                   INSERT_JUMP (on_failure_jump, laststart, b + 3);
+                   b += 3;
+                 }
              }
            else                /* not greedy */
              { /* I wish the greedy and non-greedy cases could be merged. */
@@ -2199,6 +2205,7 @@ regex_compile (pattern, size, syntax, bufp)
                  }
              }
          }
+         pending_exact = 0;
          break;
 
 
@@ -2587,41 +2594,41 @@ regex_compile (pattern, size, syntax, bufp)
                    regnum++;
                  }
 
-             if (COMPILE_STACK_FULL)
-               {
-                 RETALLOC (compile_stack.stack, compile_stack.size << 1,
-                           compile_stack_elt_t);
-                 if (compile_stack.stack == NULL) return REG_ESPACE;
+               if (COMPILE_STACK_FULL)
+                 {
+                   RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                             compile_stack_elt_t);
+                   if (compile_stack.stack == NULL) return REG_ESPACE;
 
-                 compile_stack.size <<= 1;
-               }
+                   compile_stack.size <<= 1;
+                 }
 
-             /* These are the values to restore when we hit end of this
-                group.  They are all relative offsets, so that if the
-                whole pattern moves because of realloc, they will still
-                be valid.  */
-             COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
-             COMPILE_STACK_TOP.fixup_alt_jump
-               = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
-             COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
-             COMPILE_STACK_TOP.regnum = shy ? -regnum : regnum;
-
-             /* Do not push a
-                start_memory for groups beyond the last one we can
-                represent in the compiled pattern.  */
-             if (regnum <= MAX_REGNUM && !shy)
-               BUF_PUSH_2 (start_memory, regnum);
-
-             compile_stack.avail++;
-
-             fixup_alt_jump = 0;
-             laststart = 0;
-             begalt = b;
-             /* If we've reached MAX_REGNUM groups, then this open
-                won't actually generate any code, so we'll have to
-                clear pending_exact explicitly.  */
-             pending_exact = 0;
-             break;
+               /* These are the values to restore when we hit end of this
+                  group.        They are all relative offsets, so that if the
+                  whole pattern moves because of realloc, they will still
+                  be valid.  */
+               COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+               COMPILE_STACK_TOP.fixup_alt_jump
+                 = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+               COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+               COMPILE_STACK_TOP.regnum = shy ? -regnum : regnum;
+
+               /* Do not push a
+                  start_memory for groups beyond the last one we can
+                  represent in the compiled pattern.  */
+               if (regnum <= MAX_REGNUM && !shy)
+                 BUF_PUSH_2 (start_memory, regnum);
+
+               compile_stack.avail++;
+
+               fixup_alt_jump = 0;
+               laststart = 0;
+               begalt = b;
+               /* If we've reached MAX_REGNUM groups, then this open
+                  won't actually generate any code, so we'll have to
+                  clear pending_exact explicitly.  */
+               pending_exact = 0;
+               break;
              }
 
            case ')':
@@ -2735,7 +2742,7 @@ regex_compile (pattern, size, syntax, bufp)
                /* If got here, then the syntax allows intervals.  */
 
                /* At least (most) this many matches must be made.  */
-               int lower_bound = -1, upper_bound = -1;
+               int lower_bound = 0, upper_bound = -1;
 
                beg_interval = p - 1;
 
@@ -3077,13 +3084,13 @@ regex_compile (pattern, size, syntax, bufp)
   bufp->used = b - bufp->buffer;
 
 #ifdef DEBUG
-  if (debug)
+  if (debug > 0)
     {
       re_compile_fastmap (bufp);
       DEBUG_PRINT1 ("\nCompiled pattern: \n");
       print_compiled_pattern (bufp);
-      /* debug = 0; */
     }
+  debug--;
 #endif /* DEBUG */
 
 #ifndef MATCH_MAY_ALLOCATE
@@ -3189,10 +3196,10 @@ insert_op2 (op, loc, arg1, arg2, end)
 
 static boolean
 at_begline_loc_p (pattern, p, syntax)
-    const char *pattern, *p;
+    const unsigned char *pattern, *p;
     reg_syntax_t syntax;
 {
-  const char *prev = p - 2;
+  const unsigned char *prev = p - 2;
   boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
 
   return
@@ -3208,12 +3215,12 @@ at_begline_loc_p (pattern, p, syntax)
 
 static boolean
 at_endline_loc_p (p, pend, syntax)
-    const char *p, *pend;
-    int syntax;
+    const unsigned char *p, *pend;
+    reg_syntax_t syntax;
 {
-  const char *next = p;
+  const unsigned char *next = p;
   boolean next_backslash = *next == '\\';
-  const char *next_next = p + 1 < pend ? p + 1 : 0;
+  const unsigned char *next_next = p + 1 < pend ? p + 1 : 0;
 
   return
        /* Before a subexpression?  */
@@ -3279,9 +3286,11 @@ re_compile_fastmap (bufp)
   unsigned char *p = pattern;
   register unsigned char *pend = pattern + size;
 
+#if defined (REL_ALLOC) && defined (REGEX_MALLOC)
   /* This holds the pointer to the failure stack, when
      it is allocated relocatably.  */
   fail_stack_elt_t *failure_stack_ptr;
+#endif
 
   /* Assume that each path through the pattern can be null until
      proven otherwise. We set this false at the bottom of switch
@@ -3344,7 +3353,7 @@ re_compile_fastmap (bufp)
              /* Reset for next path.  */
              path_can_be_null = true;
 
-             p = POP_PATTERN_OP ();
+             p = (unsigned char*) POP_PATTERN_OP ();
 
              continue;
            }
@@ -3636,7 +3645,6 @@ re_compile_fastmap (bufp)
            {
            case on_failure_jump:
            case on_failure_keep_string_jump:
-           case on_failure_jump_exclusive:
            case on_failure_jump_loop:
            case on_failure_jump_smart:
              p++;
@@ -3650,7 +3658,6 @@ re_compile_fastmap (bufp)
 
        case on_failure_jump:
        case on_failure_keep_string_jump:
-       case on_failure_jump_exclusive:
        case on_failure_jump_loop:
        case on_failure_jump_smart:
        handle_on_failure_jump:
@@ -3814,9 +3821,9 @@ re_search (bufp, string, size, startpos, range, regs)
    stack overflow).  */
 
 int
-re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+re_search_2 (bufp, str1, size1, str2, size2, startpos, range, regs, stop)
      struct re_pattern_buffer *bufp;
-     const char *string1, *string2;
+     const char *str1, *str2;
      int size1, size2;
      int startpos;
      int range;
@@ -3824,6 +3831,8 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
      int stop;
 {
   int val;
+  re_char *string1 = (re_char*) str1;
+  re_char *string2 = (re_char*) str2;
   register char *fastmap = bufp->fastmap;
   register RE_TRANSLATE_TYPE translate = bufp->translate;
   int total_size = size1 + size2;
@@ -3878,8 +3887,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
 #ifdef emacs
   gl_state.object = re_match_object;
   {
-    int adjpos = NILP (re_match_object) || BUFFERP (re_match_object);
-    int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (startpos + adjpos);
+    int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (startpos));
 
     SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1);
   }
@@ -3907,7 +3915,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
         the first null string.  */
       if (fastmap && startpos < total_size && !bufp->can_be_null)
        {
-         register const char *d;
+         register re_char *d;
          register unsigned int buf_ch;
 
          d = POS_ADDR_VSTRING (startpos);
@@ -3942,15 +3950,14 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
                      }
                  else
                    while (range > lim
-                          && !fastmap[(unsigned char)
-                                      RE_TRANSLATE (translate, (unsigned char) *d)])
+                          && !fastmap[RE_TRANSLATE (translate, *d)])
                      {
                        d++;
                        range--;
                      }
                }
              else
-               while (range > lim && !fastmap[(unsigned char) *d])
+               while (range > lim && !fastmap[*d])
                  {
                    d++;
                    range--;
@@ -3960,11 +3967,9 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
            }
          else                          /* Searching backwards.  */
            {
-             int room = (size1 == 0 || startpos >= size1
-                         ? size2 + size1 - startpos
-                         : size1 - startpos);
-
-             buf_ch = STRING_CHAR (d, room);
+             buf_ch = STRING_CHAR (d, (startpos >= size1
+                                       ? size2 + size1 - startpos
+                                       : size1 - startpos));
              if (RE_TRANSLATE_P (translate))
                buf_ch = RE_TRANSLATE (translate, buf_ch);
 
@@ -4001,10 +4006,8 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
          /* Update STARTPOS to the next character boundary.  */
          if (multibyte)
            {
-             const unsigned char *p
-               = (const unsigned char *) POS_ADDR_VSTRING (startpos);
-             const unsigned char *pend
-               = (const unsigned char *) STOP_ADDR_VSTRING (startpos);
+             re_char *p = POS_ADDR_VSTRING (startpos);
+             re_char *pend = STOP_ADDR_VSTRING (startpos);
              int len = MULTIBYTE_FORM_LENGTH (p, pend - p);
 
              range -= len;
@@ -4026,8 +4029,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
          /* Update STARTPOS to the previous character boundary.  */
          if (multibyte)
            {
-             const unsigned char *p
-               = (const unsigned char *) POS_ADDR_VSTRING (startpos);
+             re_char *p = POS_ADDR_VSTRING (startpos);
              int len = 0;
 
              /* Find the head of multibyte form.  */
@@ -4064,10 +4066,6 @@ static int bcmp_translate ();
    ? ((regoff_t) ((ptr) - string1))            \
    : ((regoff_t) ((ptr) - string2 + size1)))
 
-/* Macros for dealing with the split strings in re_match_2.  */
-
-#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
-
 /* Call before fetching a character with *d.  This switches over to
    string2 if necessary.  */
 #define PREFETCH()                                                     \
@@ -4133,11 +4131,54 @@ static int bcmp_translate ();
 \f
 /* Optimization routines.  */
 
+/* If the operation is a match against one or more chars,
+   return a pointer to the next operation, else return NULL.  */
+static unsigned char *
+skip_one_char (p)
+     unsigned char *p;
+{
+  switch (SWITCH_ENUM_CAST (*p++))
+    {
+    case anychar:
+      break;
+      
+    case exactn:
+      p += *p + 1;
+      break;
+
+    case charset_not:
+    case charset:
+      if (CHARSET_RANGE_TABLE_EXISTS_P (p - 1))
+       {
+         int mcnt;
+         p = CHARSET_RANGE_TABLE (p - 1);
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);
+         p = CHARSET_RANGE_TABLE_END (p, mcnt);
+       }
+      else
+       p += 1 + CHARSET_BITMAP_SIZE (p - 1);
+      break;
+      
+#ifdef emacs
+    case syntaxspec:
+    case notsyntaxspec:
+    case categoryspec:
+    case notcategoryspec:
+#endif /* emacs */
+      p++;
+      break;
+
+    default:
+      p = NULL;
+    }
+  return p;
+}
+
+
 /* Jump over non-matching operations.  */
 static unsigned char *
-skip_noops (p, pend, memory)
+skip_noops (p, pend)
      unsigned char *p, *pend;
-     int memory;
 {
   int mcnt;
   while (p < pend)
@@ -4145,8 +4186,6 @@ skip_noops (p, pend, memory)
       switch (SWITCH_ENUM_CAST ((re_opcode_t) *p))
        {
        case start_memory:
-         if (!memory)
-           return p;
        case stop_memory:
          p += 2; break;
        case no_op:
@@ -4170,100 +4209,97 @@ mutually_exclusive_p (bufp, p1, p2)
      struct re_pattern_buffer *bufp;
      unsigned char *p1, *p2;
 {
-  int multibyte = bufp->multibyte;
+  re_opcode_t op2;
+  const boolean multibyte = bufp->multibyte;
   unsigned char *pend = bufp->buffer + bufp->used;
 
-  assert (p1 >= bufp->buffer && p1 <= pend
+  assert (p1 >= bufp->buffer && p1 < pend
          && p2 >= bufp->buffer && p2 <= pend);
 
   /* Skip over open/close-group commands.
      If what follows this loop is a ...+ construct,
      look at what begins its body, since we will have to
      match at least one of that.  */
-  p2 = skip_noops (p2, pend, 1);
-  /* The same skip can be done for p1, except that skipping over
-     start_memory is not a good idea (if there's a group inside
-     the loop delimited by on_failure_jump_exclusive, then it
-     can't optimize the push away (it still works properly, but
-     slightly slower rather than faster)).  */
-  p1 = skip_noops (p1, pend, 0);
-
-  /* If we're at the end of the pattern, we can change.  */
-  if (p2 == pend)
+  p2 = skip_noops (p2, pend);
+  /* The same skip can be done for p1, except that this function
+     is only used in the case where p1 is a simple match operator.  */
+  /* p1 = skip_noops (p1, pend); */
+
+  assert (p1 >= bufp->buffer && p1 < pend
+         && p2 >= bufp->buffer && p2 <= pend);
+
+  op2 = p2 == pend ? succeed : *p2;
+
+  switch (SWITCH_ENUM_CAST (op2))
     {
-      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p1))
+    case succeed:
+    case endbuf:
+      /* If we're at the end of the pattern, we can change.  */
+      if (skip_one_char (p1))
        {
-       case anychar:
-       case charset_not:
-       case charset:
-       case exactn:
          DEBUG_PRINT1 ("  End of pattern: fast loop.\n");
          return 1;
-       default:
-         return 0;
        }
-    }
-
-  else if ((re_opcode_t) *p2 == exactn
-          || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
-    {
-      register unsigned int c
-       = *p2 == (unsigned char) endline ? '\n' : p2[2];
+      break;
+      
+    case endline:
+      if (!bufp->newline_anchor)
+       break;
+      /* Fallthrough */
+    case exactn:
+      {
+       register unsigned int c
+         = (re_opcode_t) *p2 == endline ? '\n'
+         : RE_STRING_CHAR(p2 + 2, pend - p2 - 2);
 
-      if ((re_opcode_t) *p1 == exactn)
-       {
-         if (!(multibyte /* && (c != '\n') */
-               && BASE_LEADING_CODE_P (c))
-             ? c != p1[2]
-             : (STRING_CHAR (&p2[2], pend - &p2[2])
-                != STRING_CHAR (&p1[2], pend - &p1[2])))
-           {
-             DEBUG_PRINT3 ("  '%c' != '%c' => fast loop.\n", c, p1[2]);
-             return 1;
-           }
-       }
+       if ((re_opcode_t) *p1 == exactn)
+         {
+           if (c != RE_STRING_CHAR (p1 + 2, pend - p1 - 2))
+             {
+               DEBUG_PRINT3 ("  '%c' != '%c' => fast loop.\n", c, p1[2]);
+               return 1;
+             }
+         }
 
-      else if ((re_opcode_t) *p1 == charset
-              || (re_opcode_t) *p1 == charset_not)
-       {
-         int not = (re_opcode_t) *p1 == charset_not;
+       else if ((re_opcode_t) *p1 == charset
+                || (re_opcode_t) *p1 == charset_not)
+         {
+           int not = (re_opcode_t) *p1 == charset_not;
 
-         if (multibyte /* && (c != '\n') */
-             && BASE_LEADING_CODE_P (c))
-           c = STRING_CHAR (&p2[2], pend - &p2[2]);
+           /* Test if C is listed in charset (or charset_not)
+              at `p1'.  */
+           if (SINGLE_BYTE_CHAR_P (c))
+             {
+               if (c < CHARSET_BITMAP_SIZE (p1) * BYTEWIDTH
+                   && p1[2 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+                 not = !not;
+             }
+           else if (CHARSET_RANGE_TABLE_EXISTS_P (p1))
+             CHARSET_LOOKUP_RANGE_TABLE (not, c, p1);
 
-         /* Test if C is listed in charset (or charset_not)
-            at `p1'.  */
-         if (SINGLE_BYTE_CHAR_P (c))
-           {
-             if (c < CHARSET_BITMAP_SIZE (p1) * BYTEWIDTH
-                 && p1[2 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
-               not = !not;
-           }
-         else if (CHARSET_RANGE_TABLE_EXISTS_P (p1))
-           CHARSET_LOOKUP_RANGE_TABLE (not, c, p1);
+           /* `not' is equal to 1 if c would match, which means
+              that we can't change to pop_failure_jump.  */
+           if (!not)
+             {
+               DEBUG_PRINT1 ("  No match => fast loop.\n");
+               return 1;
+             }
+         }
+       else if ((re_opcode_t) *p1 == anychar
+                && c == '\n')
+         {
+           DEBUG_PRINT1 ("   . != \\n => fast loop.\n");
+           return 1;
+         }
+      }
+      break;
 
-         /* `not' is equal to 1 if c would match, which means
-            that we can't change to pop_failure_jump.  */
-         if (!not)
-           {
-             DEBUG_PRINT1 ("    No match => fast loop.\n");
-             return 1;
-           }
-       }
-      else if ((re_opcode_t) *p1 == anychar
-              && c == '\n')
-       {
-         DEBUG_PRINT1 ("   . != \\n => fast loop.\n");
-         return 1;
-       }
-    }
-  else if ((re_opcode_t) *p2 == charset
-          || (re_opcode_t) *p2 == charset_not)
-    {
-      if ((re_opcode_t) *p1 == exactn)
-       /* Reuse the code above.  */
-       return mutually_exclusive_p (bufp, p2, p1);
+    case charset:
+    case charset_not:
+      {
+       if ((re_opcode_t) *p1 == exactn)
+         /* Reuse the code above.  */
+         return mutually_exclusive_p (bufp, p2, p1);
 
 
       /* It is hard to list up all the character in charset
@@ -4312,13 +4348,39 @@ mutually_exclusive_p (bufp, p1, p2)
                           && ((p2[2 + idx] & ~ p1[2 + idx]) == 0))))
                  break;
 
-             if (idx == p2[1])
-               {
-                 DEBUG_PRINT1 ("        No match => fast loop.\n");
-                 return 1;
-               }
-           }
-       }
+               if (idx == p2[1])
+                 {
+                   DEBUG_PRINT1 ("      No match => fast loop.\n");
+                   return 1;
+                 }
+             }
+         }
+      }
+      
+#ifdef emacs
+    case wordend:
+    case notsyntaxspec:
+      return ((re_opcode_t) *p1 == syntaxspec
+             && p1[1] == (op2 == wordend ? Sword : p2[1]));
+
+    case wordbeg:
+    case syntaxspec:
+      return ((re_opcode_t) *p1 == notsyntaxspec
+             && p1[1] == (op2 == wordend ? Sword : p2[1]));
+
+    case wordbound:
+      return (((re_opcode_t) *p1 == notsyntaxspec
+              || (re_opcode_t) *p1 == syntaxspec)
+             && p1[1] == Sword);
+
+    case categoryspec:
+      return ((re_opcode_t) *p1 == notcategoryspec && p1[1] == p2[1]);
+    case notcategoryspec:
+      return ((re_opcode_t) *p1 == categoryspec && p1[1] == p2[1]);
+#endif /* emacs */
+
+    default:
+      ;
     }
 
   /* Safe default.  */
@@ -4377,9 +4439,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
 
 #ifdef emacs
   int charpos;
-  int adjpos = NILP (re_match_object) || BUFFERP (re_match_object);
   gl_state.object = re_match_object;
-  charpos = SYNTAX_TABLE_BYTE_TO_CHAR (pos + adjpos);
+  charpos = SYNTAX_TABLE_BYTE_TO_CHAR (POS_AS_IN_BUFFER (pos));
   SETUP_SYNTAX_TABLE_FOR_OBJECT (re_match_object, charpos, 1);
 #endif
 
@@ -4394,7 +4455,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
 static int
 re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      struct re_pattern_buffer *bufp;
-     const char *string1, *string2;
+     re_char *string1, *string2;
      int size1, size2;
      int pos;
      struct re_registers *regs;
@@ -4402,17 +4463,24 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
 {
   /* General temporaries.  */
   int mcnt;
+  boolean not;
   unsigned char *p1;
 
   /* Just past the end of the corresponding string.  */
-  const char *end1, *end2;
+  re_char *end1, *end2;
 
   /* Pointers into string1 and string2, just past the last characters in
      each to consider matching.         */
-  const char *end_match_1, *end_match_2;
+  re_char *end_match_1, *end_match_2;
 
   /* Where we are in the data, and the end of the current string.  */
-  const char *d, *dend;
+  re_char *d, *dend;
+
+  /* Used sometimes to remember where we were before starting matching
+     an operator so that we can go back in case of failure.  This "atomic"
+     behavior of matching opcodes is indispensable to the correctness
+     of the on_failure_keep_string_jump optimization.  */
+  re_char *dfail;
 
   /* Where we are in the pattern, and the end of the pattern.  */
   unsigned char *p = bufp->buffer;
@@ -4439,9 +4507,11 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
   unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
 #endif
 
+#if defined (REL_ALLOC) && defined (REGEX_MALLOC)
   /* This holds the pointer to the failure stack, when
      it is allocated relocatably.  */
   fail_stack_elt_t *failure_stack_ptr;
+#endif
 
   /* We fill all the registers internally, independent of what we
      return, for use in backreferences.         The number here includes
@@ -4456,7 +4526,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      stopped matching the regnum-th subexpression.  (The zeroth register
      keeps track of what the whole pattern matches.)  */
 #ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
-  const char **regstart, **regend;
+  re_char **regstart, **regend;
 #endif
 
   /* The following record the register info as found in the above
@@ -4465,7 +4535,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      turn happens only if we have not yet matched the entire string. */
   unsigned best_regs_set = false;
 #ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
-  const char **best_regstart, **best_regend;
+  re_char **best_regstart, **best_regend;
 #endif
 
   /* Logically, this is `best_regend[0]'.  But we don't want to have to
@@ -4476,7 +4546,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      the end of the best match so far in a separate variable.  We
      initialize this to NULL so that when we backtrack the first time
      and need to test it, it's not garbage.  */
-  const char *match_end = NULL;
+  re_char *match_end = NULL;
 
 #ifdef DEBUG
   /* Counts the total number of registers pushed.  */
@@ -4495,10 +4565,10 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      array indexing.  We should fix this.  */
   if (bufp->re_nsub)
     {
-      regstart = REGEX_TALLOC (num_regs, const char *);
-      regend = REGEX_TALLOC (num_regs, const char *);
-      best_regstart = REGEX_TALLOC (num_regs, const char *);
-      best_regend = REGEX_TALLOC (num_regs, const char *);
+      regstart = REGEX_TALLOC (num_regs, re_char *);
+      regend = REGEX_TALLOC (num_regs, re_char *);
+      best_regstart = REGEX_TALLOC (num_regs, re_char *);
+      best_regend = REGEX_TALLOC (num_regs, re_char *);
 
       if (!(regstart && regend && best_regstart && best_regend))
        {
@@ -4525,9 +4595,16 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
      start_memory/stop_memory has been seen for. Also initialize the
      register information struct.  */
   for (mcnt = 1; mcnt < num_regs; mcnt++)
+    regstart[mcnt] = regend[mcnt] = REG_UNSET_VALUE;
+
+  /* Shorten strings to `stop'.  */
+  if (stop <= size1)
     {
-      regstart[mcnt] = regend[mcnt] = REG_UNSET_VALUE;
+      size1 = stop;
+      size2 = 0;
     }
+  else if (stop <= size1 + size2)
+    size2 = stop - size1;
 
   /* We move `string1' into `string2' if the latter's empty -- but not if
      `string1' is null.         */
@@ -4542,16 +4619,8 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
   end2 = string2 + size2;
 
   /* Compute where to stop matching, within the two strings.  */
-  if (stop <= size1)
-    {
-      end_match_1 = string1 + stop;
-      end_match_2 = string2;
-    }
-  else
-    {
-      end_match_1 = end1;
-      end_match_2 = string2 + stop - size1;
-    }
+  end_match_1 = end1;
+  end_match_2 = end2;
 
   /* `p' scans through the pattern as `d' scans through the data.
      `dend' is the end of the input string that `d' points within.  `d'
@@ -4594,7 +4663,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              /* 1 if this match ends in the same string (string1 or string2)
                 as the best previous match.  */
              boolean same_str_p = (FIRST_STRING_P (match_end)
-                                   == MATCHING_IN_FIRST_STRING);
+                                   == FIRST_STRING_P (d));
              /* 1 if this match is the best seen so far.  */
              boolean best_match_p;
 
@@ -4603,7 +4672,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              if (same_str_p)
                best_match_p = d > match_end;
              else
-               best_match_p = !MATCHING_IN_FIRST_STRING;
+               best_match_p = !FIRST_STRING_P (d);
 
              DEBUG_PRINT1 ("backtracking.\n");
 
@@ -4702,9 +4771,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              if (regs->num_regs > 0)
                {
                  regs->start[0] = pos;
-                 regs->end[0] = (MATCHING_IN_FIRST_STRING
-                                 ? ((regoff_t) (d - string1))
-                                 : ((regoff_t) (d - string2 + size1)));
+                 regs->end[0] = POINTER_TO_OFFSET (d);
                }
 
              /* Go through the first `min (num_regs, regs->num_regs)'
@@ -4736,9 +4803,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                        nfailure_points_pushed - nfailure_points_popped);
          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
 
-         mcnt = d - pos - (MATCHING_IN_FIRST_STRING
-                           ? string1
-                           : string2 - size1);
+         mcnt = POINTER_TO_OFFSET (d) - pos;
 
          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
 
@@ -4766,6 +4831,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
          mcnt = *p++;
          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
 
+         /* Remember the start point to rollback upon failure.  */
+         dfail = d;
+
          /* This is written out as an if-else so we don't waste time
             testing `translate' inside the loop.  */
          if (RE_TRANSLATE_P (translate))
@@ -4783,7 +4851,10 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
 
                    if (RE_TRANSLATE (translate, buf_ch)
                        != pat_ch)
-                     goto fail;
+                     {
+                       d = dfail;
+                       goto fail;
+                     }
 
                    p += pat_charlen;
                    d += buf_charlen;
@@ -4795,9 +4866,11 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                do
                  {
                    PREFETCH ();
-                   if ((unsigned char) RE_TRANSLATE (translate, (unsigned char) *d)
-                       != (unsigned char) *p++)
-                     goto fail;
+                   if (RE_TRANSLATE (translate, *d) != *p++)
+                     {
+                       d = dfail;
+                       goto fail;
+                     }
                    d++;
                  }
                while (--mcnt);
@@ -4807,7 +4880,11 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              do
                {
                  PREFETCH ();
-                 if (*d++ != (char) *p++) goto fail;
+                 if (*d++ != *p++)
+                   {
+                     d = dfail;
+                     goto fail;
+                   }
                }
              while (--mcnt);
            }
@@ -4830,7 +4907,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            else
 #endif /* not emacs */
              {
-               buf_ch = (unsigned char) *d;
+               buf_ch = *d;
                buf_charlen = 1;
              }
 
@@ -4869,7 +4946,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
 
            PREFETCH ();
-           c = (unsigned char) *d;
+           c = *d;
 
            range_table_exists = CHARSET_RANGE_TABLE_EXISTS_P (&p[-1]);
 
@@ -4982,7 +5059,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
           followed by the numeric value of <digit> as the register number.  */
        case duplicate:
          {
-           register const char *d2, *dend2;
+           register re_char *d2, *dend2;
            int regno = *p++;   /* Get which register to match against.  */
            DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
 
@@ -4993,6 +5070,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            /* Where in input to try to start matching.  */
            d2 = regstart[regno];
 
+           /* Remember the start point to rollback upon failure.  */
+           dfail = d;
+
            /* Where to stop matching; if both the place to start and
               the place to stop matching are in the same string, then
               set to the place to stop, otherwise, for now have to use
@@ -5033,7 +5113,10 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                if (RE_TRANSLATE_P (translate)
                    ? bcmp_translate (d, d2, mcnt, translate)
                    : bcmp (d, d2, mcnt))
-                 goto fail;
+                 {
+                   d = dfail;
+                   goto fail;
+                 }
                d += mcnt, d2 += mcnt;
              }
          }
@@ -5116,32 +5199,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
          PUSH_FAILURE_POINT (p - 3, NULL);
          break;
 
-       case on_failure_jump_exclusive:
-         EXTRACT_NUMBER_AND_INCR (mcnt, p);
-         DEBUG_PRINT3 ("EXECUTING on_failure_jump_exclusive %d (to %p):\n",
-                       mcnt, p + mcnt);
-
-         if (! FAIL_STACK_EMPTY ()
-             && FAILURE_PAT (TOP_FAILURE_HANDLE ()) == (p - 3)
-             && fail_stack.avail == fail_stack.frame)
-           {
-             /* We are trying to push failure F2 onto the stack but there
-                is already a failure F1 pushed from the same instruction.
-                Between F1 and now, something has matched (else this is an
-                improper use of on_failure_jump_exclusive), so that we know
-                that the fail-destination of F1 cannot match, hence we can
-                pop F1 before pushing F2.  Instead of doing this pop/push,
-                we manually turn F1 into F2.
-                `fail_stack.avail == fail_stack.frame' makes sure
-                that popping F1 doesn't involve registers, else
-                this optimization cannot be done so trivially.  */
-             assert (FAILURE_STR (TOP_FAILURE_HANDLE ()) != d);
-             FAILURE_STR (TOP_FAILURE_HANDLE ()) = d;
-           }
-         else
-           PUSH_FAILURE_POINT (p - 3, d);
-         break;
 
+         /* Simple loop detecting on_failure_jump:  just check on the
+            failure stack if the same spot was already hit earlier.  */
        case on_failure_jump_loop:
        on_failure:
          EXTRACT_NUMBER_AND_INCR (mcnt, p);
@@ -5166,11 +5226,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
           the repetition text and either the following jump or
           pop_failure_jump back to this on_failure_jump.  */
        case on_failure_jump:
-
-#if defined (WINDOWSNT) && defined (emacs)
          QUIT;
-#endif
-
          EXTRACT_NUMBER_AND_INCR (mcnt, p);
          DEBUG_PRINT3 ("EXECUTING on_failure_jump %d (to %p):\n",
                        mcnt, p + mcnt);
@@ -5178,17 +5234,15 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
          PUSH_FAILURE_POINT (p -3, d);
          break;
 
-       /* This operation is used for greedy * and +.
+       /* This operation is used for greedy *.
           Compare the beginning of the repeat with what in the
           pattern follows its end. If we can establish that there
           is nothing that they would both match, i.e., that we
           would have to backtrack because of (as in, e.g., `a*a')
           then we can use a non-backtracking loop based on
-          on_failure_jump_exclusive instead of on_failure_jump_loop.  */
+          on_failure_keep_string_jump instead of on_failure_jump.  */
        case on_failure_jump_smart:
-#if defined (WINDOWSNT) && defined (emacs)
          QUIT;
-#endif
          EXTRACT_NUMBER_AND_INCR (mcnt, p);
          DEBUG_PRINT3 ("EXECUTING on_failure_jump_smart %d (to %p).\n",
                        mcnt, p + mcnt);
@@ -5199,29 +5253,34 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
            p -= 3;             /* Reset so that we will re-execute the
                                   instruction once it's been changed. */
 
-           /* DEBUG_STATEMENT (debug = 1); */
+           EXTRACT_NUMBER (mcnt, p2 - 2);
+
+           /* Ensure this is a indeed the trivial kind of loop
+              we are expecting.  */
+           assert (skip_one_char (p1) == p2 - 3);
+           assert ((re_opcode_t) p2[-3] == jump && p2 + mcnt == p);
+           DEBUG_STATEMENT (debug += 2);
            if (mutually_exclusive_p (bufp, p1, p2))
              {
                /* Use a fast `on_failure_keep_string_jump' loop.  */
-               *p = (unsigned char) on_failure_jump_exclusive;
-               /* STORE_NUMBER (p2 - 2, mcnt + 3); */
+               DEBUG_PRINT1 ("  smart exclusive => fast loop.\n");
+               *p = (unsigned char) on_failure_keep_string_jump;
+               STORE_NUMBER (p2 - 2, mcnt + 3);
              }
            else
              {
                /* Default to a safe `on_failure_jump' loop.  */
                DEBUG_PRINT1 ("  smart default => slow loop.\n");
-               *p = (unsigned char) on_failure_jump_loop;
+               *p = (unsigned char) on_failure_jump;
              }
-           /* DEBUG_STATEMENT (debug = 0); */
+           DEBUG_STATEMENT (debug -= 2);
          }
          break;
 
        /* Unconditionally jump (without popping any failure points).  */
        case jump:
        unconditional_jump:
-#if defined (WINDOWSNT) && defined (emacs)
          QUIT;
-#endif
          EXTRACT_NUMBER_AND_INCR (mcnt, p);    /* Get the amount to jump.  */
          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
          p += mcnt;                            /* Do the jump.  */
@@ -5282,31 +5341,33 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
          }
 
        case wordbound:
-         DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+       case notwordbound:
+         not = (re_opcode_t) *(p - 1) == notwordbound;
+         DEBUG_PRINT2 ("EXECUTING %swordbound.\n", not?"not":"");
 
-         /* We SUCCEED in one of the following cases: */
+         /* We SUCCEED (or FAIL) in one of the following cases: */
 
          /* Case 1: D is at the beginning or the end of string.  */
          if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
-           break;
+           not = !not;
          else
            {
              /* C1 is the character before D, S1 is the syntax of C1, C2
                 is the character at D, and S2 is the syntax of C2.  */
              int c1, c2, s1, s2;
-             int pos1 = PTR_TO_OFFSET (d - 1);
-             int charpos;
-
-             GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
-             GET_CHAR_AFTER_2 (c2, d, string1, end1, string2, end2);
 #ifdef emacs
-             charpos = SYNTAX_TABLE_BYTE_TO_CHAR (pos1);
+             int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (PTR_TO_OFFSET (d - 1));
              UPDATE_SYNTAX_TABLE (charpos);
 #endif
+             /* FIXME: This does a STRING_CHAR even for unibyte buffers.  */
+             GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
              s1 = SYNTAX (c1);
 #ifdef emacs
              UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
 #endif
+             PREFETCH ();
+             /* FIXME: This does a STRING_CHAR even for unibyte buffers.  */
+             c2 = STRING_CHAR (d, dend - d);
              s2 = SYNTAX (c2);
 
              if (/* Case 2: Only one of S1 and S2 is Sword.  */
@@ -5314,46 +5375,12 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
                  /* Case 3: Both of S1 and S2 are Sword, and macro
                     WORD_BOUNDARY_P (C1, C2) returns nonzero.  */
                  || ((s1 == Sword) && WORD_BOUNDARY_P (c1, c2)))
+               not = !not;
+           }
+         if (not)
            break;
-       }
-         goto fail;
-
-      case notwordbound:
-         DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
-
-         /* We FAIL in one of the following cases: */
-
-         /* Case 1: D is at the beginning or the end of string.  */
-         if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
-           goto fail;
          else
-           {
-             /* C1 is the character before D, S1 is the syntax of C1, C2
-                is the character at D, and S2 is the syntax of C2.  */
-             int c1, c2, s1, s2;
-             int pos1 = PTR_TO_OFFSET (d - 1);
-             int charpos;
-
-             GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
-             GET_CHAR_AFTER_2 (c2, d, string1, end1, string2, end2);
-#ifdef emacs
-             charpos = SYNTAX_TABLE_BYTE_TO_CHAR (pos1);
-             UPDATE_SYNTAX_TABLE (charpos);
-#endif
-             s1 = SYNTAX (c1);
-#ifdef emacs
-             UPDATE_SYNTAX_TABLE_FORWARD (charpos + 1);
-#endif
-             s2 = SYNTAX (c2);
-
-             if (/* Case 2: Only one of S1 and S2 is Sword.  */
-                 ((s1 == Sword) != (s2 == Sword))
-                 /* Case 3: Both of S1 and S2 are Sword, and macro
-                    WORD_BOUNDARY_P (C1, C2) returns nonzero.  */
-                 || ((s1 == Sword) && WORD_BOUNDARY_P (c1, c2)))
            goto fail;
-       }
-         break;
 
        case wordbeg:
          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
@@ -5362,20 +5389,19 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
 
          /* Case 1: D is at the end of string.  */
          if (AT_STRINGS_END (d))
-         goto fail;
+           goto fail;
          else
            {
              /* C1 is the character before D, S1 is the syntax of C1, C2
                 is the character at D, and S2 is the syntax of C2.  */
              int c1, c2, s1, s2;
-             int pos1 = PTR_TO_OFFSET (d);
-             int charpos;
-
-             GET_CHAR_AFTER_2 (c2, d, string1, end1, string2, end2);
 #ifdef emacs
-             charpos = SYNTAX_TABLE_BYTE_TO_CHAR (pos1);
+             int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (PTR_TO_OFFSET (d));
              UPDATE_SYNTAX_TABLE (charpos);
 #endif
+             PREFETCH ();
+             /* FIXME: This does a STRING_CHAR even for unibyte buffers.  */
+             c2 = STRING_CHAR (d, dend - d);
              s2 = SYNTAX (c2);
        
              /* Case 2: S2 is not Sword. */
@@ -5412,14 +5438,11 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              /* C1 is the character before D, S1 is the syntax of C1, C2
                 is the character at D, and S2 is the syntax of C2.  */
              int c1, c2, s1, s2;
-             int pos1 = PTR_TO_OFFSET (d);
-             int charpos;
-
-             GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
 #ifdef emacs
-             charpos = SYNTAX_TABLE_BYTE_TO_CHAR (pos1 - 1);
+             int charpos = SYNTAX_TABLE_BYTE_TO_CHAR (PTR_TO_OFFSET (d) - 1);
              UPDATE_SYNTAX_TABLE (charpos);
 #endif
+             GET_CHAR_BEFORE_2 (c1, d, string1, end1, string2, end2);
              s1 = SYNTAX (c1);
 
              /* Case 2: S1 is not Sword.  */
@@ -5429,7 +5452,9 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              /* Case 3: D is not at the end of string ... */
              if (!AT_STRINGS_END (d))
                {
-                 GET_CHAR_AFTER_2 (c2, d, string1, end1, string2, end2);
+                 PREFETCH ();
+                 /* FIXME: This does a STRING_CHAR even for unibyte buffers.  */
+                 c2 = STRING_CHAR (d, dend - d);
 #ifdef emacs
                  UPDATE_SYNTAX_TABLE_FORWARD (charpos);
 #endif
@@ -5446,19 +5471,19 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
 #ifdef emacs
        case before_dot:
          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
-         if (PTR_BYTE_POS ((unsigned char *) d) >= PT_BYTE)
+         if (PTR_BYTE_POS (d) >= PT_BYTE)
            goto fail;
          break;
 
        case at_dot:
          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
-         if (PTR_BYTE_POS ((unsigned char *) d) != PT_BYTE)
+         if (PTR_BYTE_POS (d) != PT_BYTE)
            goto fail;
          break;
 
        case after_dot:
          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
-         if (PTR_BYTE_POS ((unsigned char *) d) <= PT_BYTE)
+         if (PTR_BYTE_POS (d) <= PT_BYTE)
            goto fail;
          break;
 
@@ -5587,12 +5612,10 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
 
     /* We goto here if a matching operation fails. */
     fail:
-#if defined (WINDOWSNT) && defined (emacs)
       QUIT;
-#endif
       if (!FAIL_STACK_EMPTY ())
        {
-         char *str;
+         re_char *str;
          unsigned char *pat;
          /* A restart point is known.  Restore to that state.  */
           DEBUG_PRINT1 ("\nFAIL:\n");
@@ -5603,14 +5626,6 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
              assert (str == NULL);
              goto continue_failure_jump;
 
-           case on_failure_jump_exclusive:
-             /* If something has matched, the alternative will not match,
-                so we might as well keep popping right away.  */
-             if (0 /* d != str && d != string2 */) /* Don't bother.  -sm */
-               /* (d == string2 && str == end1) => (d =~ str) */
-               goto fail;
-             /* Fallthrough */
-
            case on_failure_jump_loop:
            case on_failure_jump:
            case succeed_n:
@@ -5661,6 +5676,7 @@ bcmp_translate (s1, s2, len, translate)
       int p1_charlen, p2_charlen;
       int p1_ch, p2_ch;
 
+      /* FIXME: This assumes `multibyte = true'.  */
       p1_ch = STRING_CHAR_AND_LENGTH (p1, p1_end - p1, p1_charlen);
       p2_ch = STRING_CHAR_AND_LENGTH (p2, p2_end - p2, p2_charlen);