(U+6215): Apply new conventions for glyph granularity.
[chise/xemacs-chise.git.1] / src / search.c
index 45f00e3..7ca50a6 100644 (file)
@@ -1,6 +1,7 @@
 /* String search routines for XEmacs.
    Copyright (C) 1985, 1986, 1987, 1992-1995 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
+   Copyright (C) 1999,2000,2001 MORIOKA Tomohiko
 
 This file is part of XEmacs.
 
@@ -108,6 +109,7 @@ Lisp_Object Vforward_word_regexp, Vbackward_word_regexp;
 Lisp_Object Vskip_chars_range_table;
 
 static void set_search_regs (struct buffer *buf, Bufpos beg, Charcount len);
+static void clear_unused_search_regs (struct re_registers *regp, int no_sub);
 static void save_search_regs (void);
 static Bufpos simple_search (struct buffer *buf, Bufbyte *base_pat,
                             Bytecount len, Bytind pos, Bytind lim,
@@ -772,6 +774,7 @@ find_before_next_newline (struct buffer *buf, Bufpos from, Bufpos to, int count)
   return pos;
 }
 \f
+/* This function synched with FSF 21.1 */
 static Lisp_Object
 skip_chars (struct buffer *buf, int forwardp, int syntaxp,
            Lisp_Object string, Lisp_Object lim)
@@ -785,8 +788,12 @@ skip_chars (struct buffer *buf, int forwardp, int syntaxp,
   int negate = 0;
   REGISTER int i;
 #ifndef emacs
+#ifdef UTF2000
+  Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->syntax_table);
+#else
   Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->mirror_syntax_table);
 #endif
+#endif
   Bufpos limit;
 
   if (NILP (lim))
@@ -842,6 +849,7 @@ skip_chars (struct buffer *buf, int forwardp, int syntaxp,
            {
              Emchar cend;
 
+             /* Skip over the dash.  */
              p++;
              if (p == pend) break;
              cend = charptr_emchar (p);
@@ -866,6 +874,7 @@ skip_chars (struct buffer *buf, int forwardp, int syntaxp,
        }
     }
 
+  /* #### Not in FSF 21.1 */
   if (syntaxp && fastmap['-'] != 0)
     fastmap[' '] = 1;
 
@@ -879,36 +888,48 @@ skip_chars (struct buffer *buf, int forwardp, int syntaxp,
 
   {
     Bufpos start_point = BUF_PT (buf);
+    Bufpos pos = start_point;
+    Bytind pos_byte = BI_BUF_PT (buf);
 
     if (syntaxp)
       {
-       SETUP_SYNTAX_CACHE_FOR_BUFFER (buf, BUF_PT (buf), forwardp ? 1 : -1);
+       SETUP_SYNTAX_CACHE_FOR_BUFFER (buf, pos, forwardp ? 1 : -1);
        /* All syntax designators are normal chars so nothing strange
           to worry about */
        if (forwardp)
          {
-           while (BUF_PT (buf) < limit
-                  && fastmap[(unsigned char)
-                              syntax_code_spec
-                             [(int) SYNTAX_FROM_CACHE (syntax_table,
-                                                       BUF_FETCH_CHAR
-                                                       (buf, BUF_PT (buf)))]])
-             {
-               BUF_SET_PT (buf, BUF_PT (buf) + 1);
-               UPDATE_SYNTAX_CACHE_FORWARD (BUF_PT (buf));
-             }
+           if (pos < limit)
+             while (fastmap[(unsigned char)
+                            syntax_code_spec
+                            [(int) SYNTAX_FROM_CACHE
+                             (syntax_table,
+                              BI_BUF_FETCH_CHAR (buf, pos_byte))]])
+               {
+                 pos++;
+                 INC_BYTIND (buf, pos_byte);
+                 if (pos >= limit)
+                   break;
+                 UPDATE_SYNTAX_CACHE_FORWARD (pos);
+               }
          }
        else
          {
-           while (BUF_PT (buf) > limit
-                  && fastmap[(unsigned char)
-                              syntax_code_spec
-                             [(int) SYNTAX_FROM_CACHE (syntax_table,
-                                                       BUF_FETCH_CHAR
-                                                       (buf, BUF_PT (buf) - 1))]])
+           while (pos > limit)
              {
-               BUF_SET_PT (buf, BUF_PT (buf) - 1);
-               UPDATE_SYNTAX_CACHE_BACKWARD (BUF_PT (buf) - 1);
+               Bufpos savepos = pos_byte;
+               pos--;
+               DEC_BYTIND (buf, pos_byte);
+               UPDATE_SYNTAX_CACHE_BACKWARD (pos);
+               if (!fastmap[(unsigned char)
+                            syntax_code_spec
+                            [(int) SYNTAX_FROM_CACHE
+                             (syntax_table,
+                              BI_BUF_FETCH_CHAR (buf, pos_byte))]])
+                 {
+                   pos++;
+                   pos_byte = savepos;
+                   break;
+                 }
              }
          }
       }
@@ -916,36 +937,47 @@ skip_chars (struct buffer *buf, int forwardp, int syntaxp,
       {
        if (forwardp)
          {
-           while (BUF_PT (buf) < limit)
+           while (pos < limit)
              {
-               Emchar ch = BUF_FETCH_CHAR (buf, BUF_PT (buf));
+               Emchar ch = BI_BUF_FETCH_CHAR (buf, pos_byte);
                if ((ch < 0400) ? fastmap[ch] :
                    (NILP (Fget_range_table (make_int (ch),
                                             Vskip_chars_range_table,
                                             Qnil))
                     == negate))
-                 BUF_SET_PT (buf, BUF_PT (buf) + 1);
+                 {
+                   pos++;
+                   INC_BYTIND (buf, pos_byte);
+                 }
                else
                  break;
              }
          }
        else
          {
-           while (BUF_PT (buf) > limit)
+           while (pos > limit)
              {
-               Emchar ch = BUF_FETCH_CHAR (buf, BUF_PT (buf) - 1);
+               Bufpos prev_pos_byte = pos_byte;
+               Emchar ch;
+
+               DEC_BYTIND (buf, prev_pos_byte);
+               ch = BI_BUF_FETCH_CHAR (buf, prev_pos_byte);
                if ((ch < 0400) ? fastmap[ch] :
-                   (NILP (Fget_range_table (make_int (ch),
-                                            Vskip_chars_range_table,
-                                            Qnil))
-                    == negate))
-                 BUF_SET_PT (buf, BUF_PT (buf) - 1);
-                else
-                  break;
+                     (NILP (Fget_range_table (make_int (ch),
+                                              Vskip_chars_range_table,
+                                              Qnil))
+                      == negate))
+                 {
+                   pos--;
+                   pos_byte = prev_pos_byte;
+                 }
+               else
+                 break;
              }
          }
       }
     QUIT;
+    BOTH_BUF_SET_PT (buf, pos, pos_byte);
     return make_int (BUF_PT (buf) - start_point);
   }
 }
@@ -1057,7 +1089,7 @@ search_command (Lisp_Object string, Lisp_Object limit, Lisp_Object noerror,
       if (!EQ (noerror, Qt))
        {
          if (lim < BUF_BEGV (buf) || lim > BUF_ZV (buf))
-           abort ();
+           ABORT ();
          BUF_SET_PT (buf, lim);
          return Qnil;
 #if 0 /* This would be clean, but maybe programs depend on
@@ -1070,7 +1102,7 @@ search_command (Lisp_Object string, Lisp_Object limit, Lisp_Object noerror,
     }
 
   if (np < BUF_BEGV (buf) || np > BUF_ZV (buf))
-    abort ();
+    ABORT ();
 
   BUF_SET_PT (buf, np);
 
@@ -1087,6 +1119,7 @@ trivial_regexp_p (Lisp_Object regexp)
     {
       switch (*s++)
        {
+       /* ']' doesn't appear here because it's only special after ] */
        case '.': case '*': case '+': case '?': case '[': case '^': case '$':
          return 0;
        case '\\':
@@ -1096,7 +1129,7 @@ trivial_regexp_p (Lisp_Object regexp)
            {
            case '|': case '(': case ')': case '`': case '\'': case 'b':
            case 'B': case '<': case '>': case 'w': case 'W': case 's':
-           case 'S': case '=':
+           case 'S': case '=': case '{': case '}':
 #ifdef MULE
            /* 97/2/25 jhod Added for category matches */
            case 'c': case 'C':
@@ -1146,10 +1179,11 @@ search_buffer (struct buffer *buf, Lisp_Object string, Bufpos bufpos,
   if (len == 0)
     {
       set_search_regs (buf, bufpos, 0);
+      clear_unused_search_regs (&search_regs, 0);
       return bufpos;
     }
 
-  /* Searching 0 times means don't move.  */
+  /* Searching 0 times means noop---don't move, don't touch registers.  */
   if (n == 0)
     return bufpos;
 
@@ -1196,6 +1230,8 @@ search_buffer (struct buffer *buf, Lisp_Object string, Bufpos bufpos,
                    search_regs.start[i] += j;
                    search_regs.end[i] += j;
                  }
+             /* re_match (called from re_search et al) does this for us */
+             /* clear_unused_search_regs (search_regs, bufp->no_sub);   */
              XSETBUFFER (last_thing_searched, buf);
              /* Set pos to the new position. */
              pos = search_regs.start[0];
@@ -1233,6 +1269,8 @@ search_buffer (struct buffer *buf, Lisp_Object string, Bufpos bufpos,
                    search_regs.start[i] += j;
                    search_regs.end[i] += j;
                  }
+             /* re_match (called from re_search et al) does this for us */
+             /* clear_unused_search_regs (search_regs, bufp->no_sub);   */
              XSETBUFFER (last_thing_searched, buf);
              /* Set pos to the new position. */
              pos = search_regs.end[0];
@@ -1285,7 +1323,11 @@ search_buffer (struct buffer *buf, Lisp_Object string, Bufpos bufpos,
            {
              /* Keep track of which character set row
                 contains the characters that need translation.  */
+#ifdef UTF2000
+             int charset_base_code = c >> 6;
+#else
              int charset_base_code = c & ~CHAR_FIELD3_MASK;
+#endif
              if (charset_base == -1)
                charset_base = charset_base_code;
              else if (charset_base != charset_base_code)
@@ -1433,6 +1475,7 @@ simple_search (struct buffer *buf, Bufbyte *base_pat, Bytecount len_byte,
          end = bytind_to_bufpos (buf, idx + buf_len);
        }
       set_search_regs (buf, beg, end - beg);
+      clear_unused_search_regs (&search_regs, 0);
 
       return retval;
     }
@@ -1584,7 +1627,11 @@ boyer_moore (struct buffer *buf, Bufbyte *base_pat, Bytecount len,
              while (!BUFBYTE_FIRST_BYTE_P (*charstart))
                charstart--;
              untranslated = charptr_emchar (charstart);
+#ifdef UTF2000
+             if (charset_base == (untranslated >> 6))
+#else
              if (charset_base == (untranslated & ~CHAR_FIELD3_MASK))
+#endif
                {
                  ch = TRANSLATE (trt, untranslated);
                  if (!BUFBYTE_FIRST_BYTE_P (*ptr))
@@ -1794,6 +1841,7 @@ boyer_moore (struct buffer *buf, Bufbyte *base_pat, Bytecount len,
                    Bufpos bufend = bytind_to_bufpos (buf, bytstart + len);
 
                    set_search_regs (buf, bufstart, bufend - bufstart);
+                   clear_unused_search_regs (&search_regs, 0);
                  }
 
                  if ((n -= direction) != 0)
@@ -1883,6 +1931,7 @@ boyer_moore (struct buffer *buf, Bufbyte *base_pat, Bytecount len,
                    Bufpos bufend = bytind_to_bufpos (buf, bytstart + len);
 
                    set_search_regs (buf, bufstart, bufend - bufstart);
+                   clear_unused_search_regs (&search_regs, 0);
                  }
 
                  if ((n -= direction) != 0)
@@ -1902,8 +1951,8 @@ boyer_moore (struct buffer *buf, Bufbyte *base_pat, Bytecount len,
   return bytind_to_bufpos (buf, pos);
 }
 
-/* Record beginning BEG and end BEG + LEN
-   for a match just found in the current buffer.  */
+/* Record the whole-match data (beginning BEG and end BEG + LEN) and the
+   buffer for a match just found.  */
 
 static void
 set_search_regs (struct buffer *buf, Bufpos beg, Charcount len)
@@ -1923,6 +1972,24 @@ set_search_regs (struct buffer *buf, Bufpos beg, Charcount len)
   XSETBUFFER (last_thing_searched, buf);
 }
 
+/* Clear unused search registers so match data will be null.
+   REGP is a pointer to the register structure to clear, usually the global
+   search_regs.
+   NO_SUB is the number of subexpressions to allow for.  (Does not count
+   the whole match, ie, for a string search NO_SUB == 0.)
+   It is an error if NO_SUB > REGP.num_regs - 1. */
+
+static void
+clear_unused_search_regs (struct re_registers *regp, int no_sub)
+{
+  /* This function has been Mule-ized. */
+  int i;
+
+  assert (no_sub >= 0 && no_sub < regp->num_regs);
+  for (i = no_sub + 1; i < regp->num_regs; i++)
+    regp->start[i] = regp->end[i] = -1;
+}
+
 \f
 /* Given a string of words separated by word delimiters,
    compute a regexp that matches those exact words
@@ -1934,7 +2001,11 @@ wordify (Lisp_Object buffer, Lisp_Object string)
   Charcount i, len;
   EMACS_INT punct_count = 0, word_count = 0;
   struct buffer *buf = decode_buffer (buffer, 0);
+#ifdef UTF2000
+  Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->syntax_table);
+#else
   Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->mirror_syntax_table);
+#endif
 
   CHECK_STRING (string);
   len = XSTRING_CHAR_LENGTH (string);
@@ -2245,6 +2316,11 @@ the buffer to be used for syntax-table and case-table lookup and
 defaults to the current buffer.  When fourth argument is not a string,
 the buffer that the match occurred in has automatically been remembered
 and you do not need to specify it.
+
+When fourth argument is nil, STRBUFFER specifies a subexpression of
+the match.  It says to replace just that subexpression instead of the
+whole match.  This is useful only after a regular expression search or
+match since only regular expressions have distinguished subexpressions.
 */
        (replacement, fixedcase, literal, string, strbuffer))
 {
@@ -2264,6 +2340,7 @@ and you do not need to specify it.
   Lisp_Object buffer;
   int_dynarr *ul_action_dynarr = 0;
   int_dynarr *ul_pos_dynarr = 0;
+  int sub = 0;
   int speccount;
 
   CHECK_STRING (replacement);
@@ -2284,13 +2361,24 @@ and you do not need to specify it.
     }
   else
     {
+      if (!NILP (strbuffer))
+       {
+         CHECK_INT (strbuffer);
+         sub = XINT (strbuffer);
+         if (sub < 0 || sub >= (int) search_regs.num_regs)
+           args_out_of_range (strbuffer, make_int (search_regs.num_regs));
+       }
       if (!BUFFERP (last_thing_searched))
        error ("last thing matched was not a buffer");
       buffer = last_thing_searched;
       buf = XBUFFER (buffer);
     }
 
+#ifdef UTF2000
+  syntax_table = XCHAR_TABLE (buf->syntax_table);
+#else
   syntax_table = XCHAR_TABLE (buf->mirror_syntax_table);
+#endif
 
   case_action = nochange;      /* We tried an initialization */
                                /* but some C compilers blew it */
@@ -2300,11 +2388,11 @@ and you do not need to specify it.
 
   if (NILP (string))
     {
-      if (search_regs.start[0] < BUF_BEGV (buf)
-         || search_regs.start[0] > search_regs.end[0]
-         || search_regs.end[0] > BUF_ZV (buf))
-       args_out_of_range (make_int (search_regs.start[0]),
-                          make_int (search_regs.end[0]));
+      if (search_regs.start[sub] < BUF_BEGV (buf)
+         || search_regs.start[sub] > search_regs.end[sub]
+         || search_regs.end[sub] > BUF_ZV (buf))
+       args_out_of_range (make_int (search_regs.start[sub]),
+                          make_int (search_regs.end[sub]));
     }
   else
     {
@@ -2319,7 +2407,7 @@ and you do not need to specify it.
     {
       /* Decide how to casify by examining the matched text. */
 
-      last = search_regs.end[0];
+      last = search_regs.end[sub];
       prevc = '\n';
       case_action = all_caps;
 
@@ -2330,7 +2418,7 @@ and you do not need to specify it.
       some_nonuppercase_initial = 0;
       some_uppercase = 0;
 
-      for (pos = search_regs.start[0]; pos < last; pos++)
+      for (pos = search_regs.start[sub]; pos < last; pos++)
        {
          if (NILP (string))
            c = BUF_FETCH_CHAR (buf, pos);
@@ -2546,8 +2634,8 @@ and you do not need to specify it.
       return concat3 (before, replacement, after);
     }
 
-  mc_count = begin_multiple_change (buf, search_regs.start[0],
-                                   search_regs.end[0]);
+  mc_count = begin_multiple_change (buf, search_regs.start[sub],
+                                   search_regs.end[sub]);
 
   /* begin_multiple_change() records an unwind-protect, so we need to
      record this value now. */
@@ -2557,7 +2645,7 @@ and you do not need to specify it.
      delete the original text.  This means that markers at the
      beginning or end of the original will float to the corresponding
      position in the replacement.  */
-  BUF_SET_PT (buf, search_regs.start[0]);
+  BUF_SET_PT (buf, search_regs.start[sub]);
   if (!NILP (literal))
     Finsert (1, &replacement);
   else
@@ -2568,11 +2656,21 @@ and you do not need to specify it.
       GCPRO1 (replacement);
       for (strpos = 0; strpos < stlen; strpos++)
        {
-         Charcount offset = BUF_PT (buf) - search_regs.start[0];
+         /* on the first iteration assert(offset==0),
+            exactly complementing BUF_SET_PT() above.
+            During the loop, it keeps track of the amount inserted.
+          */
+         Charcount offset = BUF_PT (buf) - search_regs.start[sub];
 
          c = string_char (XSTRING (replacement), strpos);
          if (c == '\\' && strpos < stlen - 1)
            {
+             /* XXX FIXME: replacing just a substring non-literally
+                using backslash refs to the match looks dangerous.  But
+                <15366.18513.698042.156573@ns.caldera.de> from Torsten Duwe
+                <duwe@caldera.de> claims Finsert_buffer_substring already
+                handles this correctly.
+             */
              c = string_char (XSTRING (replacement), ++strpos);
              if (c == '&')
                Finsert_buffer_substring
@@ -2615,9 +2713,9 @@ and you do not need to specify it.
       UNGCPRO;
     }
 
-  inslen = BUF_PT (buf) - (search_regs.start[0]);
-  buffer_delete_range (buf, search_regs.start[0] + inslen, search_regs.end[0] +
-                      inslen, 0);
+  inslen = BUF_PT (buf) - (search_regs.start[sub]);
+  buffer_delete_range (buf, search_regs.start[sub] + inslen,
+                      search_regs.end[sub] +  inslen, 0);
 
   if (case_action == all_caps)
     Fupcase_region (make_int (BUF_PT (buf) - inslen),
@@ -2679,9 +2777,9 @@ match_limit (Lisp_Object num, int beginningp)
 
   CHECK_INT (num);
   n = XINT (num);
-  if (n < 0 || n >= search_regs.num_regs)
+  if (n < 0 || search_regs.num_regs <= 0)
     args_out_of_range (num, make_int (search_regs.num_regs));
-  if (search_regs.num_regs == 0 ||
+  if (n >= search_regs.num_regs ||
       search_regs.start[n] < 0)
     return Qnil;
   return make_int (beginningp ? search_regs.start[n] : search_regs.end[n]);
@@ -2760,7 +2858,7 @@ to hold all the values, and if INTEGERS is non-nil, no consing is done.
            }
          else
            /* last_thing_searched must always be Qt, a buffer, or Qnil.  */
-           abort ();
+           ABORT ();
 
          len = i;
        }