(coded-charset-entity-reference-alist): Add setting for
[chise/xemacs-chise.git.1] / src / regex.c
index b3725da..6f27ce8 100644 (file)
@@ -6,6 +6,7 @@
    Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
    Copyright (C) 1995 Ben Wing.
+   Copyright (C) 1999,2000,2001 MORIOKA Tomohiko
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -119,6 +120,8 @@ complex_vars_of_regex (void)
 
 #else  /* not emacs */
 
+#define ABORT abort
+
 /* If we are not linking with Emacs proper,
    we can't use the relocating allocator
    even if config.h says that we can.  */
@@ -131,16 +134,19 @@ char *malloc ();
 char *realloc ();
 #endif
 
-#define charptr_emchar(str)            ((Emchar) (str)[0])
+/* Types normally included via lisp.h */
+#include <stddef.h> /* for ptrdiff_t */
 
-#if (LONGBITS > INTBITS)
-# define EMACS_INT long
-#else
-# define EMACS_INT int
+#ifdef REGEX_MALLOC
+#ifndef DECLARE_NOTHING
+#define DECLARE_NOTHING struct nosuchstruct
+#endif
 #endif
 
 typedef int Emchar;
 
+#define charptr_emchar(str)            ((Emchar) (str)[0])
+
 #define INC_CHARPTR(p) ((p)++)
 #define DEC_CHARPTR(p) ((p)--)
 
@@ -415,7 +421,7 @@ typedef enum
 
         /* Start remembering the text that is matched, for storing in a
            register.  Followed by one byte with the register number, in
-           the range 0 to one less than the pattern buffer's re_nsub
+           the range 1 to the pattern buffer's re_ngroups
            field.  Then followed by one byte with the number of groups
            inner to this one.  (This last has to be part of the
            start_memory only because we need it in the on_failure_jump
@@ -424,7 +430,7 @@ typedef enum
 
         /* Stop remembering the text that is matched and store it in a
            memory register.  Followed by one byte with the register
-           number, in the range 0 to one less than `re_nsub' in the
+           number, in the range 1 to `re_ngroups' in the
            pattern buffer, and one byte with the number of inner groups,
            just like `start_memory'.  (We need the number of inner
            groups here because we don't have any easy way of finding the
@@ -971,6 +977,7 @@ print_compiled_pattern (struct re_pattern_buffer *bufp)
     }
 
   printf ("re_nsub: %ld\t", (long)bufp->re_nsub);
+  printf ("re_ngroups: %ld\t", (long)bufp->re_ngroups);
   printf ("regs_alloc: %d\t", bufp->regs_allocated);
   printf ("can_be_null: %d\t", bufp->can_be_null);
   printf ("newline_anchor: %d\n", bufp->newline_anchor);
@@ -980,6 +987,20 @@ print_compiled_pattern (struct re_pattern_buffer *bufp)
   printf ("syntax: %d\n", bufp->syntax);
   /* Perhaps we should print the translate table?  */
   /* and maybe the category table? */
+
+  if (bufp->external_to_internal_register)
+    {
+      int i;
+
+      printf ("external_to_internal_register:\n");
+      for (i = 0; i <= bufp->re_nsub; i++)
+       {
+         if (i > 0)
+           printf (", ");
+         printf ("%d -> %d", i, bufp->external_to_internal_register[i]);
+       }
+      printf ("\n");
+    }
 }
 
 
@@ -991,7 +1012,7 @@ print_double_string (re_char *where, re_char *string1, int size1,
     printf ("(null)");
   else
     {
-      unsigned int this_char;
+      Element_count this_char;
 
       if (FIRST_STRING_P (where))
         {
@@ -1125,19 +1146,19 @@ static const char *re_error_msgid[] =
    when matching.  If this number is exceeded, we allocate more
    space, so it is not a hard limit.  */
 #ifndef INIT_FAILURE_ALLOC
-#define INIT_FAILURE_ALLOC 5
+#define INIT_FAILURE_ALLOC 20
 #endif
 
 /* Roughly the maximum number of failure points on the stack.  Would be
    exactly that if always used MAX_FAILURE_SPACE each time we failed.
    This is a variable only so users of regex can assign to it; we never
    change it ourselves.  */
-#if defined (MATCH_MAY_ALLOCATE)
+#if defined (MATCH_MAY_ALLOCATE) || defined (REGEX_MALLOC)
 /* 4400 was enough to cause a crash on Alpha OSF/1,
    whose default stack limit is 2mb.  */
-int re_max_failures = 20000;
+int re_max_failures = 40000;
 #else
-int re_max_failures = 2000;
+int re_max_failures = 4000;
 #endif
 
 union fail_stack_elt
@@ -1151,8 +1172,8 @@ typedef union fail_stack_elt fail_stack_elt_t;
 typedef struct
 {
   fail_stack_elt_t *stack;
-  size_t size;
-  size_t avail;                        /* Offset of next open position.  */
+  Element_count size;
+  Element_count avail;                 /* Offset of next open position.  */
 } fail_stack_type;
 
 #define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
@@ -1195,7 +1216,7 @@ typedef struct
    REGEX_REALLOCATE_STACK requires `destination' be declared.   */
 
 #define DOUBLE_FAIL_STACK(fail_stack)                                  \
-  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS             \
+  ((int) (fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS       \
    ? 0                                                                 \
    : ((fail_stack).stack = (fail_stack_elt_t *)                                \
         REGEX_REALLOCATE_STACK ((fail_stack).stack,                    \
@@ -1369,7 +1390,7 @@ do {                                                                      \
     + NUM_NONREG_ITEMS)
 
 /* How many items can still be added to the stack without overflowing it.  */
-#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+#define REMAINING_AVAIL_SLOTS ((int) ((fail_stack).size - (fail_stack).avail))
 
 
 /* Pops what PUSH_FAIL_STACK pushes.
@@ -1489,7 +1510,7 @@ typedef union
     {                                                                  \
       if (!set_regs_matched_done)                                      \
        {                                                               \
-         unsigned r;                                                   \
+         Element_count r;                                              \
          set_regs_matched_done = 1;                                    \
          for (r = lowest_active_reg; r <= highest_active_reg; r++)     \
            {                                                           \
@@ -1588,13 +1609,6 @@ static unsigned char reg_unset_dummy;
    when we use a character as a subscript we must make it unsigned.  */
 #define TRANSLATE(d) (TRANSLATE_P (translate) ? RE_TRANSLATE (d) : (d))
 
-#ifdef MULE
-
-#define TRANSLATE_EXTENDED_UNSAFE(emch) \
-  (TRANSLATE_P (translate) && emch < 0x80 ? RE_TRANSLATE (emch) : (emch))
-
-#endif
-
 /* Macros for outputting the compiled pattern into `buffer'.  */
 
 /* If the buffer isn't allocated when it comes in, use this.  */
@@ -1602,7 +1616,7 @@ static unsigned char reg_unset_dummy;
 
 /* Make sure we have at least N more bytes of space in buffer.  */
 #define GET_BUFFER_SPACE(n)                                            \
-    while (buf_end - bufp->buffer + (n) > bufp->allocated)             \
+    while (buf_end - bufp->buffer + (n) > (ptrdiff_t) bufp->allocated) \
       EXTEND_BUFFER ()
 
 /* Make sure we have one more byte of buffer space and then add C to it.  */
@@ -1697,6 +1711,7 @@ static unsigned char reg_unset_dummy;
    ignore the excess.  */
 typedef unsigned regnum_t;
 
+#define INIT_REG_TRANSLATE_SIZE 5
 
 /* Macros for the compile stack.  */
 
@@ -1847,7 +1862,7 @@ static register_info_type *reg_info_dummy;
 /* Make the register vectors big enough for NUM_REGS registers,
    but don't make them smaller.  */
 
-static
+static void
 regex_grow_registers (int num_regs)
 {
   if (num_regs > regs_allocated_size)
@@ -1880,7 +1895,9 @@ regex_grow_registers (int num_regs)
      `syntax' is set to SYNTAX;
      `used' is set to the length of the compiled pattern;
      `fastmap_accurate' is zero;
-     `re_nsub' is the number of subexpressions in PATTERN;
+     `re_ngroups' is the number of groups/subexpressions (including shy
+        groups) in PATTERN;
+     `re_nsub' is the number of non-shy groups in PATTERN;
      `not_bol' and `not_eol' are zero;
 
    The `fastmap' and `newline_anchor' fields are neither
@@ -1950,7 +1967,7 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
   DEBUG_PRINT1 ("\nCompiling pattern: ");
   if (debug)
     {
-      unsigned debug_count;
+      int debug_count;
 
       for (debug_count = 0; debug_count < size; debug_count++)
         putchar (pattern[debug_count]);
@@ -1978,6 +1995,25 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
 
   /* Always count groups, whether or not bufp->no_sub is set.  */
   bufp->re_nsub = 0;
+  bufp->re_ngroups = 0;
+
+  /* Allocate index translation array if needed. */
+  if (bufp->external_to_internal_register == 0)
+    {
+      bufp->external_to_internal_register_size = INIT_REG_TRANSLATE_SIZE;
+      RETALLOC (bufp->external_to_internal_register,
+               bufp->external_to_internal_register_size,
+               int);
+    }
+
+  /* Initialize translations to impossible value to aid debugging. */
+  {
+    int i;
+
+    bufp->external_to_internal_register[0] = 0;
+    for (i = 1; i < bufp->external_to_internal_register_size; i++)
+      bufp->external_to_internal_register[i] = (int) 0xDEADBEEF;
+  }
 
 #if !defined (emacs) && !defined (SYNTAX_TABLE)
   /* Initialize the syntax table.  */
@@ -2560,6 +2596,7 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
             handle_open:
               {
                 regnum_t r;
+               int shy = 0;
 
                 if (!(syntax & RE_NO_SHY_GROUPS)
                     && p != pend
@@ -2570,7 +2607,7 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
                     switch (c)
                       {
                       case ':': /* shy groups */
-                        r = MAX_REGNUM + 1;
+                        shy = 1;
                         break;
 
                       /* All others are reserved for future constructs. */
@@ -2578,11 +2615,34 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
                         FREE_STACK_RETURN (REG_BADPAT);
                       }
                   }
-                else
-                  {
-                    bufp->re_nsub++;
-                    r = ++regnum;
-                  }
+
+               r = ++regnum;
+               bufp->re_ngroups++;
+               if (!shy)
+                 /* Record the translation from capturing group index to
+                    register number, reallocating table as needed. */
+                 {
+                   bufp->re_nsub++;
+                   while (bufp->external_to_internal_register_size <=
+                          bufp->re_nsub)
+                     {
+                       int i;
+                       int old_size =
+                         bufp->external_to_internal_register_size;
+                       bufp->external_to_internal_register_size += 5;
+                       RETALLOC (bufp->external_to_internal_register,
+                                 bufp->external_to_internal_register_size,
+                                 int);
+                       /* debugging */
+                       for (i = old_size;
+                            i < bufp->external_to_internal_register_size; i++)
+                         bufp->external_to_internal_register[i] =
+                           (int) 0xDEADBEEF;
+                     }
+
+                   bufp->external_to_internal_register[bufp->re_nsub] =
+                     bufp->re_ngroups;
+                 }
 
                 if (COMPILE_STACK_FULL)
                   {
@@ -2606,7 +2666,10 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
                 /* We will eventually replace the 0 with the number of
                    groups inner to this one.  But do not push a
                    start_memory for groups beyond the last one we can
-                   represent in the compiled pattern.  */
+                   represent in the compiled pattern.
+                  #### bad bad bad.  this will fail in lots of ways, if we
+                  ever have to backtrack for these groups.
+               */
                 if (r <= MAX_REGNUM)
                   {
                     COMPILE_STACK_TOP.inner_group_offset
@@ -2836,7 +2899,7 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
                  else
                    { /* If the upper bound is > 1, we need to insert
                         more at the end of the loop.  */
-                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
+                     Memory_count nbytes = 10 + (upper_bound > 1) * 10;
 
                      GET_BUFFER_SPACE (nbytes);
 
@@ -2996,16 +3059,21 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
             case '1': case '2': case '3': case '4': case '5':
             case '6': case '7': case '8': case '9':
              {
-               regnum_t reg;
+               int reg;
+
                if (syntax & RE_NO_BK_REFS)
                  goto normal_char;
 
+               /* External register indexing. */
                reg = c - '0';
 
-               if (reg > regnum)
+               if (reg > bufp->re_nsub)
                  FREE_STACK_RETURN (REG_ESUBREG);
 
-               /* Can't back reference to a subexpression if inside of it.  */
+               /* Convert external to internal as soon as possible. */
+               reg = bufp->external_to_internal_register[reg];
+
+               /* Can't back reference to a subexpression if inside it. */
                if (group_in_compile_stack (compile_stack, reg))
                  goto normal_char;
 
@@ -3125,7 +3193,7 @@ regex_compile (re_char *pattern, int size, reg_syntax_t syntax,
      isn't necessary unless we're trying to avoid calling alloca in
      the search and match routines.  */
   {
-    int num_regs = bufp->re_nsub + 1;
+    int num_regs = bufp->re_ngroups + 1;
 
     /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
        is strictly greater than re_max_failures, the largest possible stack
@@ -3290,7 +3358,7 @@ static reg_errcode_t
 compile_range (re_char **p_ptr, re_char *pend, RE_TRANSLATE_TYPE translate,
               reg_syntax_t syntax, unsigned char *buf_end)
 {
-  unsigned this_char;
+  Element_count this_char;
 
   re_char *p = *p_ptr;
   int range_start, range_end;
@@ -3359,8 +3427,12 @@ compile_extended_range (re_char **p_ptr, re_char *pend,
      ranges entirely within the first 256 chars. */
 
   if ((range_start >= 0x100 || range_end >= 0x100)
-      && CHAR_LEADING_BYTE (range_start) !=
-      CHAR_LEADING_BYTE (range_end))
+#ifdef UTF2000
+      && CHAR_CHARSET_ID (range_start) != CHAR_CHARSET_ID (range_end)
+#else
+      && CHAR_LEADING_BYTE (range_start) != CHAR_LEADING_BYTE (range_end)
+#endif
+      )
     return REG_ERANGESPAN;
 
   /* As advertised, translations only work over the 0 - 0x7F range.
@@ -3646,25 +3718,36 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
          goto done;
 
 #ifdef emacs
-#if 0   /* Removed during syntax-table properties patch -- 2000/12/07 mct */
+#if 0  /* Removed during syntax-table properties patch -- 2000/12/07 mct */
         case syntaxspec:
          k = *p++;
 #endif
          matchsyntax:
 #ifdef MULE
+#ifdef UTF2000
+         for (j = 0; j < 0x80; j++)
+           if (SYNTAX_UNSAFE
+               (XCHAR_TABLE
+                (regex_emacs_buffer->syntax_table), j) ==
+               (enum syntaxcode) k)
+             fastmap[j] = 1;
+#else
          for (j = 0; j < 0x80; j++)
            if (SYNTAX_UNSAFE
                (XCHAR_TABLE
                 (regex_emacs_buffer->mirror_syntax_table), j) ==
                (enum syntaxcode) k)
              fastmap[j] = 1;
+#endif
          for (j = 0x80; j < 0xA0; j++)
            {
+#ifndef UTF2000
              if (LEADING_BYTE_PREFIX_P(j))
                /* too complicated to calculate this right */
                fastmap[j] = 1;
              else
                {
+#endif
                  int multi_p;
                  Lisp_Object cset;
 
@@ -3676,7 +3759,9 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
                          == Sword || multi_p)
                        fastmap[j] = 1;
                    }
+#ifndef UTF2000
                }
+#endif
            }
 #else /* not MULE */
          for (j = 0; j < (1 << BYTEWIDTH); j++)
@@ -3689,25 +3774,36 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
          break;
 
 
-#if 0   /* Removed during syntax-table properties patch -- 2000/12/07 mct */
+#if 0  /* Removed during syntax-table properties patch -- 2000/12/07 mct */
        case notsyntaxspec:
          k = *p++;
 #endif
          matchnotsyntax:
 #ifdef MULE
+#ifdef UTF2000
+         for (j = 0; j < 0x80; j++)
+           if (SYNTAX_UNSAFE
+               (XCHAR_TABLE
+                (regex_emacs_buffer->syntax_table), j) !=
+               (enum syntaxcode) k)
+             fastmap[j] = 1;
+#else
          for (j = 0; j < 0x80; j++)
            if (SYNTAX_UNSAFE
                (XCHAR_TABLE
                 (regex_emacs_buffer->mirror_syntax_table), j) !=
                (enum syntaxcode) k)
              fastmap[j] = 1;
+#endif
          for (j = 0x80; j < 0xA0; j++)
            {
+#ifndef UTF2000
              if (LEADING_BYTE_PREFIX_P(j))
                /* too complicated to calculate this right */
                fastmap[j] = 1;
              else
                {
+#endif
                  int multi_p;
                  Lisp_Object cset;
 
@@ -3719,7 +3815,9 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
                          != Sword || multi_p)
                        fastmap[j] = 1;
                    }
+#ifndef UTF2000
                }
+#endif
            }
 #else /* not MULE */
          for (j = 0; j < (1 << BYTEWIDTH); j++)
@@ -3749,7 +3847,7 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
        case at_dot:
        case after_dot:
           continue;
-#endif /* not emacs */
+#endif /* emacs */
 
 
         case no_op:
@@ -3858,7 +3956,7 @@ re_compile_fastmap (struct re_pattern_buffer *bufp)
 
 
        default:
-          abort (); /* We have listed all the cases.  */
+          ABORT (); /* We have listed all the cases.  */
         } /* switch *p++ */
 
       /* Getting here means we have found the possible starting
@@ -4022,7 +4120,7 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1,
 
 #ifdef REGEX_BEGLINE_CHECK
   {
-    int i = 0;
+    unsigned long i = 0;
 
     while (i < bufp->used)
       {
@@ -4111,10 +4209,12 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1,
                  {
 #ifdef MULE
                    Emchar buf_ch;
+                   Bufbyte str[MAX_EMCHAR_LEN];
 
                    buf_ch = charptr_emchar (d);
                    buf_ch = RE_TRANSLATE (buf_ch);
-                   if (buf_ch >= 0200 || fastmap[(unsigned char) buf_ch])
+                   set_charptr_emchar (str, buf_ch);
+                   if (buf_ch >= 0200 || fastmap[(unsigned char) *str])
                      break;
 #else
                    if (fastmap[(unsigned char)RE_TRANSLATE (*d)])
@@ -4239,9 +4339,15 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1,
 #define POS_AFTER_GAP_UNSAFE(d) ((d) == end1 ? string2 : (d))
 
 /* Test if CH is a word-constituent character. (XEmacs change) */
+#ifdef UTF2000
+#define WORDCHAR_P_UNSAFE(ch)                                     \
+  (SYNTAX_UNSAFE (XCHAR_TABLE (regex_emacs_buffer->syntax_table),  \
+                               ch) == Sword)
+#else
 #define WORDCHAR_P_UNSAFE(ch)                                             \
   (SYNTAX_UNSAFE (XCHAR_TABLE (regex_emacs_buffer->mirror_syntax_table),   \
                                ch) == Sword)
+#endif
 
 /* Free everything we malloc.  */
 #ifdef MATCH_MAY_ALLOCATE
@@ -4374,7 +4480,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 #endif
 #ifdef DEBUG
   static unsigned failure_id;
-  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+  int nfailure_points_pushed = 0, nfailure_points_popped = 0;
 #endif
 
 #ifdef REL_ALLOC
@@ -4386,11 +4492,11 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
   /* We fill all the registers internally, independent of what we
      return, for use in backreferences.  The number here includes
      an element for register zero.  */
-  unsigned num_regs = bufp->re_nsub + 1;
+  int num_regs = bufp->re_ngroups + 1;
 
   /* The currently active registers.  */
-  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
-  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+  int lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  int highest_active_reg = NO_HIGHEST_ACTIVE_REG;
 
   /* Information on the contents of registers. These are pointers into
      the input strings; they record just what was matched (on this
@@ -4472,7 +4578,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
      there are groups, we include space for register 0 (the whole
      pattern), even though we never use it, since it simplifies the
      array indexing.  We should fix this.  */
-  if (bufp->re_nsub)
+  if (bufp->re_ngroups)
     {
       regstart       = REGEX_TALLOC (num_regs, re_char *);
       regend         = REGEX_TALLOC (num_regs, re_char *);
@@ -4647,96 +4753,112 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
        succeed_label:
           DEBUG_PRINT1 ("Accepting match.\n");
 
-          /* If caller wants register contents data back, do it.  */
-          if (regs && !bufp->no_sub)
-           {
-              /* Have the register data arrays been allocated?  */
-              if (bufp->regs_allocated == REGS_UNALLOCATED)
-                { /* No.  So allocate them with malloc.  We need one
-                     extra element beyond `num_regs' for the `-1' marker
-                     GNU code uses.  */
-                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
-                  regs->start = TALLOC (regs->num_regs, regoff_t);
-                  regs->end = TALLOC (regs->num_regs, regoff_t);
-                  if (regs->start == NULL || regs->end == NULL)
-                   {
-                     FREE_VARIABLES ();
-                     return -2;
-                   }
-                  bufp->regs_allocated = REGS_REALLOCATE;
-                }
-              else if (bufp->regs_allocated == REGS_REALLOCATE)
-                { /* Yes.  If we need more elements than were already
-                     allocated, reallocate them.  If we need fewer, just
-                     leave it alone.  */
-                  if (regs->num_regs < num_regs + 1)
-                    {
-                      regs->num_regs = num_regs + 1;
-                      RETALLOC (regs->start, regs->num_regs, regoff_t);
-                      RETALLOC (regs->end, regs->num_regs, regoff_t);
-                      if (regs->start == NULL || regs->end == NULL)
-                       {
-                         FREE_VARIABLES ();
-                         return -2;
-                       }
-                    }
-                }
-              else
-               {
-                 /* These braces fend off a "empty body in an else-statement"
-                    warning under GCC when assert expands to nothing.  */
-                 assert (bufp->regs_allocated == REGS_FIXED);
-               }
+         {
+           /* If caller wants register contents data back, fill REGS.  */
+           int num_nonshy_regs = bufp->re_nsub + 1;
+           if (regs && !bufp->no_sub)
+             {
+               /* Have the register data arrays been allocated?  */
+               if (bufp->regs_allocated == REGS_UNALLOCATED)
+                 { /* No.  So allocate them with malloc.  We need one
+                      extra element beyond `num_regs' for the `-1' marker
+                      GNU code uses.  */
+                   regs->num_regs = MAX (RE_NREGS, num_nonshy_regs + 1);
+                   regs->start = TALLOC (regs->num_regs, regoff_t);
+                   regs->end = TALLOC (regs->num_regs, regoff_t);
+                   if (regs->start == NULL || regs->end == NULL)
+                     {
+                       FREE_VARIABLES ();
+                       return -2;
+                     }
+                   bufp->regs_allocated = REGS_REALLOCATE;
+                 }
+               else if (bufp->regs_allocated == REGS_REALLOCATE)
+                 { /* Yes.  If we need more elements than were already
+                      allocated, reallocate them.  If we need fewer, just
+                      leave it alone.  */
+                   if (regs->num_regs < num_nonshy_regs + 1)
+                     {
+                       regs->num_regs = num_nonshy_regs + 1;
+                       RETALLOC (regs->start, regs->num_regs, regoff_t);
+                       RETALLOC (regs->end, regs->num_regs, regoff_t);
+                       if (regs->start == NULL || regs->end == NULL)
+                         {
+                           FREE_VARIABLES ();
+                           return -2;
+                         }
+                     }
+                 }
+               else
+                 {
+                   /* The braces fend off a "empty body in an else-statement"
+                      warning under GCC when assert expands to nothing.  */
+                   assert (bufp->regs_allocated == REGS_FIXED);
+                 }
 
-              /* Convert the pointer data in `regstart' and `regend' to
-                 indices.  Register zero has to be set differently,
-                 since we haven't kept track of any info for it.  */
-              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)));
-                }
+               /* Convert the pointer data in `regstart' and `regend' to
+                  indices.  Register zero has to be set differently,
+                  since we haven't kept track of any info for it.  */
+               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)));
+                 }
 
-              /* Go through the first `min (num_regs, regs->num_regs)'
-                 registers, since that is all we initialized.  */
-             for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
-               {
-                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
-                    regs->start[mcnt] = regs->end[mcnt] = -1;
-                  else
-                    {
-                     regs->start[mcnt]
-                       = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
-                      regs->end[mcnt]
-                       = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
-                    }
-               }
+               /* Map over the NUM_NONSHY_REGS non-shy internal registers.
+                  Copy each into the corresponding external register.
+                  N.B. MCNT indexes external registers. */
+               for (mcnt = 1;
+                    mcnt < MIN (num_nonshy_regs, regs->num_regs);
+                    mcnt++)
+                 {
+                   int ireg = bufp->external_to_internal_register[mcnt];
+
+                   if (REG_UNSET (regstart[ireg]) || REG_UNSET (regend[ireg]))
+                     regs->start[mcnt] = regs->end[mcnt] = -1;
+                   else
+                     {
+                       regs->start[mcnt]
+                         = (regoff_t) POINTER_TO_OFFSET (regstart[ireg]);
+                       regs->end[mcnt]
+                         = (regoff_t) POINTER_TO_OFFSET (regend[ireg]);
+                     }
+                 }
+             } /* regs && !bufp->no_sub */
+
+           /* If we have regs and the regs structure has more elements than
+              were in the pattern, set the extra elements to -1.  If we
+              (re)allocated the registers, this is the case, because we
+              always allocate enough to have at least one -1 at the end.
+
+              We do this even when no_sub is set because some applications
+              (XEmacs) reuse register structures which may contain stale
+              information, and permit attempts to access those registers.
+
+              It would be possible to require the caller to do this, but we'd
+              have to change the API for this function to reflect that, and
+              audit all callers. */
+           if (regs && regs->num_regs > 0)
+             for (mcnt = num_nonshy_regs; mcnt < regs->num_regs; mcnt++)
+               regs->start[mcnt] = regs->end[mcnt] = -1;
+         }
 
-              /* If the regs structure we return has more elements than
-                 were in the pattern, set the extra elements to -1.  If
-                 we (re)allocated the registers, this is the case,
-                 because we always allocate enough to have at least one
-                 -1 at the end.  */
-              for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
-                regs->start[mcnt] = regs->end[mcnt] = -1;
-           } /* regs && !bufp->no_sub */
-
-          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
-                        nfailure_points_pushed, nfailure_points_popped,
-                        nfailure_points_pushed - nfailure_points_popped);
-          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
-
-          mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+         DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                       nfailure_points_pushed, nfailure_points_popped,
+                       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);
 
-          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+         DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
 
-          FREE_VARIABLES ();
-          return mcnt;
-        }
+         FREE_VARIABLES ();
+         return mcnt;
+       }
 
       /* Otherwise match next pattern command.  */
       switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
@@ -4854,7 +4976,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 
            REGEX_PREFETCH ();
            c = charptr_emchar ((const Bufbyte *) d);
-           c = TRANSLATE_EXTENDED_UNSAFE (c); /* The character to match.  */
+           c = TRANSLATE (c); /* The character to match.  */
 
            if (EQ (Qt, unified_range_table_lookup (p, c, Qnil)))
              not_p = !not_p;
@@ -5037,7 +5159,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 
                   if (EVER_MATCHED_SOMETHING (reg_info[*p]))
                    {
-                     unsigned r;
+                     int r;
 
                       EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
 
@@ -5065,11 +5187,15 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 
 
        /* \<digit> has been turned into a `duplicate' command which is
-           followed by the numeric value of <digit> as the register number.  */
+           followed by the numeric value of <digit> as the register number.
+          (Already passed through external-to-internal-register mapping,
+          so it refers to the actual group number, not the non-shy-only
+          numbering used in the external world.) */
         case duplicate:
          {
            REGISTER re_char *d2, *dend2;
-           int regno = *p++;   /* Get which register to match against.  */
+           /* Get which register to match against.  */
+           int regno = *p++;
            DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
 
            /* Can't back reference a group which we've never matched.  */
@@ -5422,7 +5548,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
                actual values.  Otherwise, we will restore only one
                register from the stack, since lowest will == highest in
                `pop_failure_point'.  */
-            unsigned dummy_low_reg, dummy_high_reg;
+            int dummy_low_reg, dummy_high_reg;
             unsigned char *pdummy;
             re_char *sdummy = NULL;
 
@@ -5535,40 +5661,65 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
        matchwordbound:
          {
            /* XEmacs change */
-           int result;
-           if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
-             result = 1;
-           else
-             {
-               re_char *d_before = POS_BEFORE_GAP_UNSAFE (d);
-               re_char *d_after = POS_AFTER_GAP_UNSAFE (d);
-
-               /* emch1 is the character before d, syn1 is the syntax of emch1,
-                  emch2 is the character at d, and syn2 is the syntax of emch2. */
-               Emchar emch1, emch2;
-               int syn1, syn2;
+           /* Straightforward and (I hope) correct implementation.
+              Probably should be optimized by arranging to compute
+              pos only once. */
+           /* emch1 is the character before d, syn1 is the syntax of
+              emch1, emch2 is the character at d, and syn2 is the
+              syntax of emch2. */
+           Emchar emch1, emch2;
+           /* GCC isn't smart enough to see these are initialized if used. */
+           int syn1 = 0, syn2 = 0;
+           re_char *d_before, *d_after;
+           int result,
+               at_beg = AT_STRINGS_BEG (d),
+               at_end = AT_STRINGS_END (d);
 #ifdef emacs
-               int pos_before;
+           int xpos;
 #endif
 
-               DEC_CHARPTR (d_before);
-               emch1 = charptr_emchar (d_before);
-               emch2 = charptr_emchar (d_after);
-
+           if (at_beg && at_end)
+             {
+               result = 0;
+             }
+           else
+             {
+               if (!at_beg)
+                 {
+                   d_before = POS_BEFORE_GAP_UNSAFE (d);
+                   DEC_CHARPTR (d_before);
+                   emch1 = charptr_emchar (d_before);
 #ifdef emacs
-               pos_before = SYNTAX_CACHE_BYTE_TO_CHAR (PTR_TO_OFFSET (d)) - 1;
-               UPDATE_SYNTAX_CACHE (pos_before);
+                   xpos = SYNTAX_CACHE_BYTE_TO_CHAR (PTR_TO_OFFSET (d)) - 1;
+                   UPDATE_SYNTAX_CACHE (xpos);
 #endif
-               syn1 = SYNTAX_FROM_CACHE (XCHAR_TABLE (regex_emacs_buffer->mirror_syntax_table),
-                                         emch1);
+                   syn1 = SYNTAX_FROM_CACHE
+                            (XCHAR_TABLE (regex_emacs_buffer
+                                          ->mirror_syntax_table),
+                             emch1);
+                 }
+               if (!at_end)
+                 {
+                   d_after = POS_AFTER_GAP_UNSAFE (d);
+                   emch2 = charptr_emchar (d_after);
 #ifdef emacs
-               UPDATE_SYNTAX_CACHE_FORWARD (pos_before + 1);
+                   xpos = SYNTAX_CACHE_BYTE_TO_CHAR (PTR_TO_OFFSET (d));
+                   UPDATE_SYNTAX_CACHE_FORWARD (xpos + 1);
 #endif
-               syn2 = SYNTAX_FROM_CACHE (XCHAR_TABLE (regex_emacs_buffer->mirror_syntax_table),
-                                         emch2);
+                   syn2 = SYNTAX_FROM_CACHE
+                            (XCHAR_TABLE (regex_emacs_buffer
+                                          ->mirror_syntax_table),
+                             emch2);
+                 }
 
-               result = ((syn1 == Sword) != (syn2 == Sword));
+               if (at_beg)
+                 result = (syn2 == Sword);
+               else if (at_end)
+                 result = (syn1 == Sword);
+               else
+                 result = ((syn1 == Sword) != (syn2 == Sword));
              }
+
            if (result == should_succeed)
              break;
            goto fail;
@@ -5708,8 +5859,13 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 #endif
 
            emch = charptr_emchar ((const Bufbyte *) d);
-           matches = (SYNTAX_FROM_CACHE (regex_emacs_buffer->mirror_syntax_table,
+#ifdef UTF2000
+           matches = (SYNTAX_FROM_CACHE (XCHAR_TABLE (regex_emacs_buffer->syntax_table),
                        emch) == (enum syntaxcode) mcnt);
+#else
+           matches = (SYNTAX_FROM_CACHE (XCHAR_TABLE (regex_emacs_buffer->mirror_syntax_table),
+                       emch) == (enum syntaxcode) mcnt);
+#endif
            INC_CHARPTR (d);
            if (matches != should_succeed)
              goto fail;
@@ -5774,7 +5930,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 #endif /* emacs */
 
         default:
-          abort ();
+          ABORT ();
        }
       continue;  /* Successfully executed one pattern command; keep going.  */
 
@@ -5851,7 +6007,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1,
 
 static re_bool
 group_match_null_string_p (unsigned char **p, unsigned char *end,
-                          register_info_type *reg_info)
+                          register_info_type *register_info)
 {
   int mcnt;
   /* Point to after the args to the start_memory.  */
@@ -5900,7 +6056,7 @@ group_match_null_string_p (unsigned char **p, unsigned char *end,
                      its number.  */
 
                   if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
-                                                     reg_info))
+                                                     register_info))
                     return false;
 
                   /* Move to right after this alternative, including the
@@ -5929,7 +6085,7 @@ group_match_null_string_p (unsigned char **p, unsigned char *end,
                  the length of the alternative.  */
               EXTRACT_NUMBER (mcnt, p1 - 2);
 
-              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+              if (!alt_match_null_string_p (p1, p1 + mcnt, register_info))
                 return false;
 
               p1 += mcnt;      /* Get past the n-th alternative.  */
@@ -5944,7 +6100,7 @@ group_match_null_string_p (unsigned char **p, unsigned char *end,
 
 
         default:
-          if (!common_op_match_null_string_p (&p1, end, reg_info))
+          if (!common_op_match_null_string_p (&p1, end, register_info))
             return false;
         }
     } /* while p1 < end */
@@ -5959,7 +6115,7 @@ group_match_null_string_p (unsigned char **p, unsigned char *end,
 
 static re_bool
 alt_match_null_string_p (unsigned char *p, unsigned char *end,
-                        register_info_type *reg_info)
+                        register_info_type *register_info)
 {
   int mcnt;
   unsigned char *p1 = p;
@@ -5979,7 +6135,7 @@ alt_match_null_string_p (unsigned char *p, unsigned char *end,
           break;
 
        default:
-          if (!common_op_match_null_string_p (&p1, end, reg_info))
+          if (!common_op_match_null_string_p (&p1, end, register_info))
             return false;
         }
     }  /* while p1 < end */
@@ -5995,7 +6151,7 @@ alt_match_null_string_p (unsigned char *p, unsigned char *end,
 
 static re_bool
 common_op_match_null_string_p (unsigned char **p, unsigned char *end,
-                              register_info_type *reg_info)
+                              register_info_type *register_info)
 {
   int mcnt;
   re_bool ret;
@@ -6023,13 +6179,14 @@ common_op_match_null_string_p (unsigned char **p, unsigned char *end,
     case start_memory:
       reg_no = *p1;
       assert (reg_no > 0 && reg_no <= MAX_REGNUM);
-      ret = group_match_null_string_p (&p1, end, reg_info);
+      ret = group_match_null_string_p (&p1, end, register_info);
 
       /* Have to set this here in case we're checking a group which
          contains a group and a back reference to it.  */
 
-      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
-        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+      if (REG_MATCH_NULL_STRING_P (register_info[reg_no]) ==
+         MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (register_info[reg_no]) = ret;
 
       if (!ret)
         return false;
@@ -6060,7 +6217,7 @@ common_op_match_null_string_p (unsigned char **p, unsigned char *end,
       break;
 
     case duplicate:
-      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+      if (!REG_MATCH_NULL_STRING_P (register_info[*p1]))
         return false;
       break;
 
@@ -6222,6 +6379,8 @@ re_exec (const char *s)
      `newline_anchor' to REG_NEWLINE being set in CFLAGS;
      `fastmap' and `fastmap_accurate' to zero;
      `re_nsub' to the number of subexpressions in PATTERN.
+     (non-shy of course.  POSIX probably doesn't know about
+     shy ones, and in any case they should be invisible.)
 
    PATTERN is the address of the pattern string.
 
@@ -6264,7 +6423,7 @@ regcomp (regex_t *preg, const char *pattern, int cflags)
 
   if (cflags & REG_ICASE)
     {
-      unsigned i;
+      int i;
 
       preg->translate = (char *) malloc (CHAR_SET_SIZE);
       if (preg->translate == NULL)
@@ -6317,7 +6476,7 @@ regcomp (regex_t *preg, const char *pattern, int cflags)
    We return 0 if we find a match and REG_NOMATCH if not.  */
 
 int
-regexec (const regex_t *preg, const char *string, size_t nmatch,
+regexec (const regex_t *preg, const char *string, Element_count nmatch,
         regmatch_t pmatch[], int eflags)
 {
   int ret;
@@ -6355,7 +6514,7 @@ regexec (const regex_t *preg, const char *string, size_t nmatch,
     {
       if (ret >= 0)
         {
-          unsigned r;
+          Element_count r;
 
           for (r = 0; r < nmatch; r++)
             {
@@ -6377,19 +6536,21 @@ regexec (const regex_t *preg, const char *string, size_t nmatch,
 /* Returns a message corresponding to an error code, ERRCODE, returned
    from either regcomp or regexec.   We don't use PREG here.  */
 
-size_t
-regerror (int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+Memory_count
+regerror (int errcode, const regex_t *preg, char *errbuf,
+         Memory_count errbuf_size)
 {
   const char *msg;
-  size_t msg_size;
+  Memory_count msg_size;
 
   if (errcode < 0
-      || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0])))
+      || (size_t) errcode >= (sizeof (re_error_msgid)
+                             / sizeof (re_error_msgid[0])))
     /* Only error codes returned by the rest of the code should be passed
        to this routine.  If we are given anything else, or if other regex
        code generates an invalid error code, then the program has a bug.
        Dump core so we can fix it.  */
-    abort ();
+    ABORT ();
 
   msg = gettext (re_error_msgid[errcode]);