Merge changes from emacs-23 branch
[bpt/emacs.git] / src / search.c
index 682fa18..67323b3 100644 (file)
@@ -1,5 +1,5 @@
 /* String search routines for GNU Emacs.
-   Copyright (C) 1985-1987, 1993-1994, 1997-1999, 2001-2011
+   Copyright (C) 1985-1987, 1993-1994, 1997-1999, 2001-2012
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -53,10 +53,10 @@ struct regexp_cache
 };
 
 /* The instances of that struct.  */
-struct regexp_cache searchbufs[REGEXP_CACHE_SIZE];
+static struct regexp_cache searchbufs[REGEXP_CACHE_SIZE];
 
 /* The head of the linked list; points to the most recently used buffer.  */
-struct regexp_cache *searchbuf_head;
+static struct regexp_cache *searchbuf_head;
 
 
 /* Every call to re_match, etc., must pass &search_regs as the regs
@@ -83,12 +83,11 @@ static struct re_registers search_regs;
    Qnil if no searching has been done yet.  */
 static Lisp_Object last_thing_searched;
 
-/* error condition signaled when regexp compile_pattern fails */
+/* Error condition signaled when regexp compile_pattern fails.  */
+static Lisp_Object Qinvalid_regexp;
 
-Lisp_Object Qinvalid_regexp;
-
-/* Error condition used for failing searches */
-Lisp_Object Qsearch_failed;
+/* Error condition used for failing searches.  */
+static Lisp_Object Qsearch_failed;
 
 static void set_search_regs (EMACS_INT, EMACS_INT);
 static void save_search_regs (void);
@@ -368,7 +367,7 @@ data if you want to preserve them.  */)
 static Lisp_Object
 string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start, int posix)
 {
-  int val;
+  EMACS_INT val;
   struct re_pattern_buffer *bufp;
   EMACS_INT pos, pos_byte;
   int i;
@@ -468,10 +467,10 @@ matched by parenthesis constructs in the pattern.  */)
    and return the index of the match, or negative on failure.
    This does not clobber the match data.  */
 
-int
+EMACS_INT
 fast_string_match (Lisp_Object regexp, Lisp_Object string)
 {
-  int val;
+  EMACS_INT val;
   struct re_pattern_buffer *bufp;
 
   bufp = compile_pattern (regexp, 0, Qnil,
@@ -491,10 +490,10 @@ fast_string_match (Lisp_Object regexp, Lisp_Object string)
    This does not clobber the match data.
    We assume that STRING contains single-byte characters.  */
 
-int
+EMACS_INT
 fast_c_string_match_ignore_case (Lisp_Object regexp, const char *string)
 {
-  int val;
+  EMACS_INT val;
   struct re_pattern_buffer *bufp;
   size_t len = strlen (string);
 
@@ -511,10 +510,10 @@ fast_c_string_match_ignore_case (Lisp_Object regexp, const char *string)
 
 /* Like fast_string_match but ignore case.  */
 
-int
+EMACS_INT
 fast_string_match_ignore_case (Lisp_Object regexp, Lisp_Object string)
 {
-  int val;
+  EMACS_INT val;
   struct re_pattern_buffer *bufp;
 
   bufp = compile_pattern (regexp, 0, Vascii_canon_table,
@@ -643,7 +642,7 @@ newline_cache_on_off (struct buffer *buf)
 
 EMACS_INT
 scan_buffer (register int target, EMACS_INT start, EMACS_INT end,
-            EMACS_INT count, int *shortage, int allow_quit)
+            EMACS_INT count, EMACS_INT *shortage, int allow_quit)
 {
   struct region_cache *newline_cache;
   int direction;
@@ -683,7 +682,7 @@ scan_buffer (register int target, EMACS_INT start, EMACS_INT end,
            to see where we can avoid some scanning.  */
         if (target == '\n' && newline_cache)
           {
-            EMACS_INT next_change;
+            ptrdiff_t next_change;
             immediate_quit = 0;
             while (region_cache_forward
                    (current_buffer, newline_cache, start_byte, &next_change))
@@ -726,8 +725,8 @@ scan_buffer (register int target, EMACS_INT start, EMACS_INT end,
                  the region from start to cursor is free of them. */
               if (target == '\n' && newline_cache)
                 know_region_cache (current_buffer, newline_cache,
-                                   start_byte + scan_start - base,
-                                   start_byte + cursor - base);
+                                   BYTE_TO_CHAR (start_byte + scan_start - base),
+                                   BYTE_TO_CHAR (start_byte + cursor - base));
 
               /* Did we find the target character?  */
               if (cursor < ceiling_addr)
@@ -755,7 +754,7 @@ scan_buffer (register int target, EMACS_INT start, EMACS_INT end,
         /* Consult the newline cache, if appropriate.  */
         if (target == '\n' && newline_cache)
           {
-            EMACS_INT next_change;
+            ptrdiff_t next_change;
             immediate_quit = 0;
             while (region_cache_backward
                    (current_buffer, newline_cache, start_byte, &next_change))
@@ -792,8 +791,8 @@ scan_buffer (register int target, EMACS_INT start, EMACS_INT end,
                  the region from after the cursor to start is free of them.  */
               if (target == '\n' && newline_cache)
                 know_region_cache (current_buffer, newline_cache,
-                                   start_byte + cursor - base,
-                                   start_byte + scan_start - base);
+                                   BYTE_TO_CHAR (start_byte + cursor - base),
+                                   BYTE_TO_CHAR (start_byte + scan_start - base));
 
               /* Did we find the target character?  */
               if (cursor >= ceiling_addr)
@@ -933,7 +932,7 @@ scan_newline (EMACS_INT start, EMACS_INT start_byte,
 EMACS_INT
 find_next_newline_no_quit (EMACS_INT from, EMACS_INT cnt)
 {
-  return scan_buffer ('\n', from, 0, cnt, (int *) 0, 0);
+  return scan_buffer ('\n', from, 0, cnt, (EMACS_INT *) 0, 0);
 }
 
 /* Like find_next_newline, but returns position before the newline,
@@ -943,7 +942,7 @@ find_next_newline_no_quit (EMACS_INT from, EMACS_INT cnt)
 EMACS_INT
 find_before_next_newline (EMACS_INT from, EMACS_INT to, EMACS_INT cnt)
 {
-  int shortage;
+  EMACS_INT shortage;
   EMACS_INT pos = scan_buffer ('\n', from, to, cnt, &shortage, 1);
 
   if (shortage == 0)
@@ -958,9 +957,9 @@ static Lisp_Object
 search_command (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror,
                Lisp_Object count, int direction, int RE, int posix)
 {
-  register int np;
+  register EMACS_INT np;
   EMACS_INT lim, lim_byte;
-  int n = direction;
+  EMACS_INT n = direction;
 
   if (!NILP (count))
     {
@@ -1303,7 +1302,7 @@ search_buffer (Lisp_Object string, EMACS_INT pos, EMACS_INT pos_byte,
             checking if we can use boyer-moore search.  If TRT is
             non-nil, we can use boyer-moore search only if TRT can be
             represented by the byte array of 256 elements.  For that,
-            all non-ASCII case-equivalents of all case-senstive
+            all non-ASCII case-equivalents of all case-sensitive
             characters in STRING must belong to the same charset and
             row.  */
 
@@ -1674,7 +1673,6 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
   int translate_prev_byte1 = 0;
   int translate_prev_byte2 = 0;
   int translate_prev_byte3 = 0;
-  int translate_prev_byte4 = 0;
 
   /* The general approach is that we are going to maintain that we know
      the first (closest to the present position, in whatever direction
@@ -1730,11 +1728,7 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
        {
          translate_prev_byte2 = str[cblen - 3];
          if (cblen > 3)
-           {
-             translate_prev_byte3 = str[cblen - 4];
-             if (cblen > 4)
-               translate_prev_byte4 = str[cblen - 5];
-           }
+           translate_prev_byte3 = str[cblen - 4];
        }
     }
 
@@ -1765,7 +1759,7 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
                ch = -1;
            }
 
-         if (ch >= 0200)
+         if (ch >= 0200 && multibyte)
            j = (ch & 0x3F) | 0200;
          else
            j = *ptr;
@@ -1784,7 +1778,7 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
              while (1)
                {
                  TRANSLATE (ch, inverse_trt, ch);
-                 if (ch >= 0200)
+                 if (ch >= 0200 && multibyte)
                    j = (ch & 0x3F) | 0200;
                  else
                    j = ch;
@@ -1897,7 +1891,7 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
                               || CHAR_HEAD_P (cursor[1]))
                              && (CHAR_HEAD_P (cursor[0])
                                  /* Check if this is the last byte of
-                                    a translable character.  */
+                                    a translatable character.  */
                                  || (translate_prev_byte1 == cursor[-1]
                                      && (CHAR_HEAD_P (translate_prev_byte1)
                                          || (translate_prev_byte2 == cursor[-2]
@@ -1996,7 +1990,7 @@ boyer_moore (EMACS_INT n, unsigned char *base_pat,
                           || CHAR_HEAD_P (ptr[1]))
                          && (CHAR_HEAD_P (ptr[0])
                              /* Check if this is the last byte of a
-                                translable character.  */
+                                translatable character.  */
                              || (translate_prev_byte1 == ptr[-1]
                                  && (CHAR_HEAD_P (translate_prev_byte1)
                                      || (translate_prev_byte2 == ptr[-2]
@@ -2083,15 +2077,18 @@ set_search_regs (EMACS_INT beg_byte, EMACS_INT nbytes)
   XSETBUFFER (last_thing_searched, current_buffer);
 }
 \f
-/* Given STRING, a string of words separated by word delimiters,
-   compute a regexp that matches those exact words separated by
-   arbitrary punctuation.  If LAX is nonzero, the end of the string
-   need not match a word boundary unless it ends in whitespace.  */
-
-static Lisp_Object
-wordify (Lisp_Object string, int lax)
+DEFUN ("word-search-regexp", Fword_search_regexp, Sword_search_regexp, 1, 2, 0,
+       doc: /* Return a regexp which matches words, ignoring punctuation.
+Given STRING, a string of words separated by word delimiters,
+compute a regexp that matches those exact words separated by
+arbitrary punctuation.  If LAX is non-nil, the end of the string
+need not match a word boundary unless it ends in whitespace.
+
+Used in `word-search-forward', `word-search-backward',
+`word-search-forward-lax', `word-search-backward-lax'.  */)
+  (Lisp_Object string, Lisp_Object lax)
 {
-  register unsigned char *p, *o;
+  register unsigned char *o;
   register EMACS_INT i, i_byte, len, punct_count = 0, word_count = 0;
   Lisp_Object val;
   int prev_c = 0;
@@ -2099,7 +2096,6 @@ wordify (Lisp_Object string, int lax)
   int whitespace_at_end;
 
   CHECK_STRING (string);
-  p = SDATA (string);
   len = SCHARS (string);
 
   for (i = 0, i_byte = 0; i < len; )
@@ -2111,7 +2107,7 @@ wordify (Lisp_Object string, int lax)
       if (SYNTAX (c) != Sword)
        {
          punct_count++;
-         if (i > 0 && SYNTAX (prev_c) == Sword)
+         if (SYNTAX (prev_c) == Sword)
            word_count++;
        }
 
@@ -2124,13 +2120,14 @@ wordify (Lisp_Object string, int lax)
       whitespace_at_end = 0;
     }
   else
-    whitespace_at_end = 1;
-
-  if (!word_count)
-    return empty_unibyte_string;
+    {
+      whitespace_at_end = 1;
+      if (!word_count)
+       return empty_unibyte_string;
+    }
 
   adjust = - punct_count + 5 * (word_count - 1)
-    + ((lax && !whitespace_at_end) ? 2 : 4);
+    + ((!NILP (lax) && !whitespace_at_end) ? 2 : 4);
   if (STRING_MULTIBYTE (string))
     val = make_uninit_multibyte_string (len + adjust,
                                        SBYTES (string)
@@ -2155,7 +2152,7 @@ wordify (Lisp_Object string, int lax)
          memcpy (o, SDATA (string) + i_byte_orig, i_byte - i_byte_orig);
          o += i_byte - i_byte_orig;
        }
-      else if (i > 0 && SYNTAX (prev_c) == Sword && --word_count)
+      else if (SYNTAX (prev_c) == Sword && --word_count)
        {
          *o++ = '\\';
          *o++ = 'W';
@@ -2167,7 +2164,7 @@ wordify (Lisp_Object string, int lax)
       prev_c = c;
     }
 
-  if (!lax || whitespace_at_end)
+  if (NILP (lax) || whitespace_at_end)
     {
       *o++ = '\\';
       *o++ = 'b';
@@ -2222,10 +2219,14 @@ An optional second argument bounds the search; it is a buffer position.
 The match found must not extend before that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
-Optional fourth argument is repeat count--search for successive occurrences.  */)
+Optional fourth argument is repeat count--search for successive occurrences.
+
+Relies on the function `word-search-regexp' to convert a sequence
+of words in STRING to a regexp used to search words without regard
+to punctuation.  */)
   (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
 {
-  return search_command (wordify (string, 0), bound, noerror, count, -1, 1, 0);
+  return search_command (Fword_search_regexp (string, Qnil), bound, noerror, count, -1, 1, 0);
 }
 
 DEFUN ("word-search-forward", Fword_search_forward, Sword_search_forward, 1, 4,
@@ -2236,10 +2237,14 @@ An optional second argument bounds the search; it is a buffer position.
 The match found must not extend after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
-Optional fourth argument is repeat count--search for successive occurrences.  */)
+Optional fourth argument is repeat count--search for successive occurrences.
+
+Relies on the function `word-search-regexp' to convert a sequence
+of words in STRING to a regexp used to search words without regard
+to punctuation.  */)
   (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
 {
-  return search_command (wordify (string, 0), bound, noerror, count, 1, 1, 0);
+  return search_command (Fword_search_regexp (string, Qnil), bound, noerror, count, 1, 1, 0);
 }
 
 DEFUN ("word-search-backward-lax", Fword_search_backward_lax, Sword_search_backward_lax, 1, 4,
@@ -2254,10 +2259,14 @@ An optional second argument bounds the search; it is a buffer position.
 The match found must not extend before that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
-Optional fourth argument is repeat count--search for successive occurrences.  */)
+Optional fourth argument is repeat count--search for successive occurrences.
+
+Relies on the function `word-search-regexp' to convert a sequence
+of words in STRING to a regexp used to search words without regard
+to punctuation.  */)
   (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
 {
-  return search_command (wordify (string, 1), bound, noerror, count, -1, 1, 0);
+  return search_command (Fword_search_regexp (string, Qt), bound, noerror, count, -1, 1, 0);
 }
 
 DEFUN ("word-search-forward-lax", Fword_search_forward_lax, Sword_search_forward_lax, 1, 4,
@@ -2272,10 +2281,14 @@ An optional second argument bounds the search; it is a buffer position.
 The match found must not extend after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
-Optional fourth argument is repeat count--search for successive occurrences.  */)
+Optional fourth argument is repeat count--search for successive occurrences.
+
+Relies on the function `word-search-regexp' to convert a sequence
+of words in STRING to a regexp used to search words without regard
+to punctuation.  */)
   (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
 {
-  return search_command (wordify (string, 1), bound, noerror, count, 1, 1, 0);
+  return search_command (Fword_search_regexp (string, Qt), bound, noerror, count, 1, 1, 0);
 }
 
 DEFUN ("re-search-backward", Fre_search_backward, Sre_search_backward, 1, 4,
@@ -2289,6 +2302,10 @@ The match found must start at or after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
 Optional fourth argument is repeat count--search for successive occurrences.
+
+Search case-sensitivity is determined by the value of the variable
+`case-fold-search', which see.
+
 See also the functions `match-beginning', `match-end', `match-string',
 and `replace-match'.  */)
   (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
@@ -2305,6 +2322,10 @@ The match found must not extend after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
 Optional fourth argument is repeat count--search for successive occurrences.
+
+Search case-sensitivity is determined by the value of the variable
+`case-fold-search', which see.
+
 See also the functions `match-beginning', `match-end', `match-string',
 and `replace-match'.  */)
   (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
@@ -2324,6 +2345,10 @@ The match found must start at or after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
 Optional fourth argument is repeat count--search for successive occurrences.
+
+Search case-sensitivity is determined by the value of the variable
+`case-fold-search', which see.
+
 See also the functions `match-beginning', `match-end', `match-string',
 and `replace-match'.  */)
   (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
@@ -2341,6 +2366,10 @@ The match found must not extend after that position.
 Optional third argument, if t, means if fail just return nil (no error).
   If not nil and not t, move to limit of search and return nil.
 Optional fourth argument is repeat count--search for successive occurrences.
+
+Search case-sensitivity is determined by the value of the variable
+`case-fold-search', which see.
+
 See also the functions `match-beginning', `match-end', `match-string',
 and `replace-match'.  */)
   (Lisp_Object regexp, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count)
@@ -2393,7 +2422,7 @@ since only regular expressions have distinguished subexpressions.  */)
   int some_uppercase;
   int some_nonuppercase_initial;
   register int c, prevc;
-  int sub;
+  ptrdiff_t sub;
   EMACS_INT opoint, newpoint;
 
   CHECK_STRING (newtext);
@@ -2412,9 +2441,9 @@ since only regular expressions have distinguished subexpressions.  */)
   else
     {
       CHECK_NUMBER (subexp);
-      sub = XINT (subexp);
-      if (sub < 0 || sub >= search_regs.num_regs)
+      if (! (0 <= XINT (subexp) && XINT (subexp) < search_regs.num_regs))
        args_out_of_range (subexp, make_number (search_regs.num_regs));
+      sub = XINT (subexp);
     }
 
   if (NILP (string))
@@ -2529,7 +2558,7 @@ since only regular expressions have distinguished subexpressions.  */)
          /* We build up the substituted string in ACCUM.  */
          Lisp_Object accum;
          Lisp_Object middle;
-         int length = SBYTES (newtext);
+         EMACS_INT length = SBYTES (newtext);
 
          accum = Qnil;
 
@@ -2629,15 +2658,17 @@ since only regular expressions have distinguished subexpressions.  */)
      perform substitution on the replacement string.  */
   if (NILP (literal))
     {
-      EMACS_INT length = SBYTES (newtext);
+      ptrdiff_t length = SBYTES (newtext);
       unsigned char *substed;
-      EMACS_INT substed_alloc_size, substed_len;
+      ptrdiff_t substed_alloc_size, substed_len;
       int buf_multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
       int str_multibyte = STRING_MULTIBYTE (newtext);
       int really_changed = 0;
 
-      substed_alloc_size = length * 2 + 100;
-      substed = (unsigned char *) xmalloc (substed_alloc_size + 1);
+      substed_alloc_size = ((STRING_BYTES_BOUND - 100) / 2 < length
+                           ? STRING_BYTES_BOUND
+                           : length * 2 + 100);
+      substed = (unsigned char *) xmalloc (substed_alloc_size);
       substed_len = 0;
 
       /* Go thru NEWTEXT, producing the actual text to insert in
@@ -2648,8 +2679,8 @@ since only regular expressions have distinguished subexpressions.  */)
        {
          unsigned char str[MAX_MULTIBYTE_LENGTH];
          const unsigned char *add_stuff = NULL;
-         EMACS_INT add_len = 0;
-         int idx = -1;
+         ptrdiff_t add_len = 0;
+         ptrdiff_t idx = -1;
 
          if (str_multibyte)
            {
@@ -2712,7 +2743,7 @@ since only regular expressions have distinguished subexpressions.  */)
             set up ADD_STUFF and ADD_LEN to point to it.  */
          if (idx >= 0)
            {
-             EMACS_INT begbyte = CHAR_TO_BYTE (search_regs.start[idx]);
+             ptrdiff_t begbyte = CHAR_TO_BYTE (search_regs.start[idx]);
              add_len = CHAR_TO_BYTE (search_regs.end[idx]) - begbyte;
              if (search_regs.start[idx] < GPT && GPT < search_regs.end[idx])
                move_gap (search_regs.start[idx]);
@@ -2723,12 +2754,11 @@ since only regular expressions have distinguished subexpressions.  */)
             is invariably ADD_LEN bytes starting at ADD_STUFF.  */
 
          /* Make sure SUBSTED is big enough.  */
-         if (substed_len + add_len >= substed_alloc_size)
-           {
-             substed_alloc_size = substed_len + add_len + 500;
-             substed = (unsigned char *) xrealloc (substed,
-                                                   substed_alloc_size + 1);
-           }
+         if (substed_alloc_size - substed_len < add_len)
+           substed =
+             xpalloc (substed, &substed_alloc_size,
+                      add_len - (substed_alloc_size - substed_len),
+                      STRING_BYTES_BOUND, 1);
 
          /* Now add to the end of SUBSTED.  */
          if (add_stuff)
@@ -2801,7 +2831,7 @@ since only regular expressions have distinguished subexpressions.  */)
 static Lisp_Object
 match_limit (Lisp_Object num, int beginningp)
 {
-  register int n;
+  EMACS_INT n;
 
   CHECK_NUMBER (num);
   n = XINT (num);
@@ -2885,7 +2915,7 @@ Return value is undefined if the last search failed.  */)
   len = 0;
   for (i = 0; i < search_regs.num_regs; i++)
     {
-      int start = search_regs.start[i];
+      EMACS_INT start = search_regs.start[i];
       if (start >= 0)
        {
          if (EQ (last_thing_searched, Qt)
@@ -2962,7 +2992,7 @@ LIST should have been created by calling `match-data' previously.
 If optional arg RESEAT is non-nil, make markers on LIST point nowhere.  */)
   (register Lisp_Object list, Lisp_Object reseat)
 {
-  register int i;
+  ptrdiff_t i;
   register Lisp_Object marker;
 
   if (running_asynch_code)
@@ -2976,31 +3006,21 @@ If optional arg RESEAT is non-nil, make markers on LIST point nowhere.  */)
 
   /* Allocate registers if they don't already exist.  */
   {
-    int length = XFASTINT (Flength (list)) / 2;
+    ptrdiff_t length = XFASTINT (Flength (list)) / 2;
 
     if (length > search_regs.num_regs)
       {
-       if (search_regs.num_regs == 0)
-         {
-           search_regs.start
-             = (regoff_t *) xmalloc (length * sizeof (regoff_t));
-           search_regs.end
-             = (regoff_t *) xmalloc (length * sizeof (regoff_t));
-         }
-       else
-         {
-           search_regs.start
-             = (regoff_t *) xrealloc (search_regs.start,
-                                      length * sizeof (regoff_t));
-           search_regs.end
-             = (regoff_t *) xrealloc (search_regs.end,
-                                      length * sizeof (regoff_t));
-         }
-
-       for (i = search_regs.num_regs; i < length; i++)
+       ptrdiff_t num_regs = search_regs.num_regs;
+       search_regs.start =
+         xpalloc (search_regs.start, &num_regs, length - num_regs,
+                  min (PTRDIFF_MAX, UINT_MAX), sizeof (regoff_t));
+       search_regs.end =
+         xrealloc (search_regs.end, num_regs * sizeof (regoff_t));
+
+       for (i = search_regs.num_regs; i < num_regs; i++)
          search_regs.start[i] = -1;
 
-       search_regs.num_regs = length;
+       search_regs.num_regs = num_regs;
       }
 
     for (i = 0; CONSP (list); i++)
@@ -3130,7 +3150,7 @@ record_unwind_save_match_data (void)
                         Fmatch_data (Qnil, Qnil, Qnil));
 }
 
-/* Quote a string to inactivate reg-expr chars */
+/* Quote a string to deactivate reg-expr chars */
 
 DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0,
        doc: /* Return a regexp string which matches exactly STRING and nothing else.  */)
@@ -3186,10 +3206,8 @@ syms_of_search (void)
     }
   searchbuf_head = &searchbufs[0];
 
-  Qsearch_failed = intern_c_string ("search-failed");
-  staticpro (&Qsearch_failed);
-  Qinvalid_regexp = intern_c_string ("invalid-regexp");
-  staticpro (&Qinvalid_regexp);
+  DEFSYM (Qsearch_failed, "search-failed");
+  DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
        pure_cons (Qsearch_failed, pure_cons (Qerror, Qnil)));
@@ -3229,6 +3247,7 @@ is to bind it with `let' around a small expression.  */);
   defsubr (&Sposix_string_match);
   defsubr (&Ssearch_forward);
   defsubr (&Ssearch_backward);
+  defsubr (&Sword_search_regexp);
   defsubr (&Sword_search_forward);
   defsubr (&Sword_search_backward);
   defsubr (&Sword_search_forward_lax);