emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: find-file-noselect needs save-match-data


From: Herbert Euler
Subject: Re: find-file-noselect needs save-match-data
Date: Fri, 29 Jun 2007 23:07:38 +0800

Just as a note aside: regular expressions like \(.\)\1 are possible,
so the match data _has_ to be stored somewhere, presumably.  This
might impact the attractiveness of the "C variable" implementation.

Fortunately we can solve this with providing another re_registers
variable.  I've almost finished it, but I got segmentation fault after
adding a DEFVAR_LISP in syms_of_search.  The segfault is triggered
by GC.  Any hint on how to solve it?  Thanks.

The crash goes away after I re-checked out the source from CVS.  Below
is the patches and the change-log entries I did for the two functions.
All patches are based on files in unicode 2 branch.  Please check
them.  If they are OK, I'll write document for them.  Thanks.

Regards,
Guanpeng Xu




Index: lisp/subr.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/subr.el,v
retrieving revision 1.360.2.68
diff -c -F '^[_a-zA-Z0-9$]+ *(' -r1.360.2.68 subr.el
*** lisp/subr.el        16 Jun 2007 22:31:38 -0000      1.360.2.68
--- lisp/subr.el        29 Jun 2007 14:26:21 -0000
*************** t (mix it with ordinary output), or a fi
*** 2667,2672 ****
--- 2667,2684 ----
            (looking-at (concat "\\(?:"  regexp "\\)\\'")))))
     (not (null pos))))

+ (defsubst looking-at-p (regexp)
+   "\
+ Same as `looking-at' except this function does not change the match data."
+   (let ((inhibit-changing-match-data t))
+     (looking-at regexp)))
+
+ (defsubst string-match-p (regexp string &optional start)
+   "\
+ Same as `string-match' except this function does not change the match data."
+   (let ((inhibit-changing-match-data t))
+     (string-match regexp string start)))
+
 (defun subregexp-context-p (regexp pos &optional start)
   "Return non-nil if POS is in a normal subregexp context in REGEXP.
 A subregexp context is one where a sub-regexp can appear.
Index: src/search.c
===================================================================
RCS file: /sources/emacs/emacs/src/search.c,v
retrieving revision 1.174.2.38
diff -c -F '^[_a-zA-Z0-9$]+ *(' -r1.174.2.38 search.c
*** src/search.c        11 Jun 2007 00:57:33 -0000      1.174.2.38
--- src/search.c        29 Jun 2007 14:26:27 -0000
***************
*** 60,73 ****
 struct regexp_cache *searchbuf_head;


! /* Every call to re_match, etc., must pass &search_regs as the regs
!    argument unless you can show it is unnecessary (i.e., if re_match
!    is certainly going to be called again before region-around-match
!    can be called).

    Since the registers are now dynamically allocated, we need to make
    sure not to refer to the Nth register before checking that it has
!    been allocated by checking search_regs.num_regs.

    The regex code keeps track of whether it has allocated the search
    buffer using bits in the re_pattern_buffer.  This means that whenever
--- 60,74 ----
 struct regexp_cache *searchbuf_head;


! /* Every call to re_match, etc., must pass &search_regs_nochange or
!    &search_regs as the regs argument unless you can show it is
!    unnecessary (i.e., if re_match is certainly going to be called
!    again before region-around-match can be called).

    Since the registers are now dynamically allocated, we need to make
    sure not to refer to the Nth register before checking that it has
!    been allocated by checking search_regs_nochange.num_regs, or
!    search_regs.num_regs.

    The regex code keeps track of whether it has allocated the search
    buffer using bits in the re_pattern_buffer.  This means that whenever
***************
*** 76,82 ****
    time you call a searching or matching function.  Therefore, we need
    to call re_set_registers after compiling a new pattern or after
    setting the match registers, so that the regex functions will be
!    able to free or re-allocate it properly.  */
 static struct re_registers search_regs;

 /* The buffer in which the last search was performed, or
--- 77,90 ----
    time you call a searching or matching function.  Therefore, we need
    to call re_set_registers after compiling a new pattern or after
    setting the match registers, so that the regex functions will be
!    able to free or re-allocate it properly.
!
!    We now have two families of searching or matching functions.
!    Functions in one family won't change the match data at Lisp level,
!    while functions in the other family will change it.  The variable
!    search_regs_nochange is used for the former family, and the
!    variable search_regs is used for the latter one.  */
! static struct re_registers search_regs_nochange;
 static struct re_registers search_regs;

 /* The buffer in which the last search was performed, or
***************
*** 93,98 ****
--- 101,115 ----

 Lisp_Object Vsearch_spaces_regexp;

+ /* If non-nil, the match data will not be changed during call to
+    searching or matching functions.  This variable is for internal use
+    only.  */
+ Lisp_Object Vinhibit_changing_match_data;
+
+ #define SEARCH_REGS_PTR (NILP (Vinhibit_changing_match_data)  \
+                        ? &search_regs                             \
+                        : &search_regs_nochange)
+
 static void set_search_regs ();
 static void save_search_regs ();
 static int simple_search ();
*************** looking_at_1 (string, posix)
*** 280,285 ****
--- 297,303 ----
   int s1, s2;
   register int i;
   struct re_pattern_buffer *bufp;
+   struct re_registers *regs = SEARCH_REGS_PTR;

   if (running_asynch_code)
     save_search_regs ();
*************** looking_at_1 (string, posix)
*** 289,295 ****
     = current_buffer->case_eqv_table;

   CHECK_STRING (string);
!   bufp = compile_pattern (string, &search_regs,
                          (!NILP (current_buffer->case_fold_search)
                           ? current_buffer->case_canon_table : Qnil),
                          posix,
--- 307,313 ----
     = current_buffer->case_eqv_table;

   CHECK_STRING (string);
!   bufp = compile_pattern (string, regs,
                          (!NILP (current_buffer->case_fold_search)
                           ? current_buffer->case_canon_table : Qnil),
                          posix,
*************** looking_at_1 (string, posix)
*** 320,326 ****
   re_match_object = Qnil;

   i = re_match_2 (bufp, (char *) p1, s1, (char *) p2, s2,
!                 PT_BYTE - BEGV_BYTE, &search_regs,
                  ZV_BYTE - BEGV_BYTE);
   immediate_quit = 0;

--- 338,344 ----
   re_match_object = Qnil;

   i = re_match_2 (bufp, (char *) p1, s1, (char *) p2, s2,
!                 PT_BYTE - BEGV_BYTE, regs,
                  ZV_BYTE - BEGV_BYTE);
   immediate_quit = 0;

*************** looking_at_1 (string, posix)
*** 329,341 ****

   val = (0 <= i ? Qt : Qnil);
   if (i >= 0)
!     for (i = 0; i < search_regs.num_regs; i++)
!       if (search_regs.start[i] >= 0)
        {
!         search_regs.start[i]
!           = BYTE_TO_CHAR (search_regs.start[i] + BEGV_BYTE);
!         search_regs.end[i]
!           = BYTE_TO_CHAR (search_regs.end[i] + BEGV_BYTE);
        }
   XSETBUFFER (last_thing_searched, current_buffer);
   return val;
--- 347,357 ----

   val = (0 <= i ? Qt : Qnil);
   if (i >= 0)
!     for (i = 0; i < regs->num_regs; i++)
!       if (regs->start[i] >= 0)
        {
!         regs->start[i] = BYTE_TO_CHAR (regs->start[i] + BEGV_BYTE);
!         regs->end[i] = BYTE_TO_CHAR (regs->end[i] + BEGV_BYTE);
        }
   XSETBUFFER (last_thing_searched, current_buffer);
   return val;
*************** string_match_1 (regexp, string, start, p
*** 373,378 ****
--- 389,395 ----
   struct re_pattern_buffer *bufp;
   int pos, pos_byte;
   int i;
+   struct re_registers *regs = SEARCH_REGS_PTR;

   if (running_asynch_code)
     save_search_regs ();
*************** string_match_1 (regexp, string, start, p
*** 399,405 ****
   XCHAR_TABLE (current_buffer->case_canon_table)->extras[2]
     = current_buffer->case_eqv_table;

!   bufp = compile_pattern (regexp, &search_regs,
                          (!NILP (current_buffer->case_fold_search)
                           ? current_buffer->case_canon_table : Qnil),
                          posix,
--- 416,422 ----
   XCHAR_TABLE (current_buffer->case_canon_table)->extras[2]
     = current_buffer->case_eqv_table;

!   bufp = compile_pattern (regexp, regs,
                          (!NILP (current_buffer->case_fold_search)
                           ? current_buffer->case_canon_table : Qnil),
                          posix,
*************** string_match_1 (regexp, string, start, p
*** 410,429 ****
   val = re_search (bufp, (char *) SDATA (string),
                   SBYTES (string), pos_byte,
                   SBYTES (string) - pos_byte,
!                  &search_regs);
   immediate_quit = 0;
   last_thing_searched = Qt;
   if (val == -2)
     matcher_overflow ();
   if (val < 0) return Qnil;

!   for (i = 0; i < search_regs.num_regs; i++)
!     if (search_regs.start[i] >= 0)
       {
!       search_regs.start[i]
!         = string_byte_to_char (string, search_regs.start[i]);
!       search_regs.end[i]
!         = string_byte_to_char (string, search_regs.end[i]);
       }

   return make_number (string_byte_to_char (string, val));
--- 427,444 ----
   val = re_search (bufp, (char *) SDATA (string),
                   SBYTES (string), pos_byte,
                   SBYTES (string) - pos_byte,
!                  regs);
   immediate_quit = 0;
   last_thing_searched = Qt;
   if (val == -2)
     matcher_overflow ();
   if (val < 0) return Qnil;

!   for (i = 0; i < regs->num_regs; i++)
!     if (regs->start[i] >= 0)
       {
!       regs->start[i] = string_byte_to_char (string, regs->start[i]);
!       regs->end[i] = string_byte_to_char (string, regs->end[i]);
       }

   return make_number (string_byte_to_char (string, val));
*************** search_buffer (string, pos, pos_byte, li
*** 1059,1064 ****
--- 1074,1080 ----
   int len = SCHARS (string);
   int len_byte = SBYTES (string);
   register int i;
+   struct re_registers *regs = SEARCH_REGS_PTR;

   if (running_asynch_code)
     save_search_regs ();
*************** search_buffer (string, pos, pos_byte, li
*** 1077,1083 ****
       int s1, s2;
       struct re_pattern_buffer *bufp;

!       bufp = compile_pattern (string, &search_regs, trt, posix,
                              !NILP 
(current_buffer->enable_multibyte_characters));

       immediate_quit = 1;      /* Quit immediately if user types ^G,
--- 1093,1099 ----
       int s1, s2;
       struct re_pattern_buffer *bufp;

!       bufp = compile_pattern (string, regs, trt, posix,
                              !NILP 
(current_buffer->enable_multibyte_characters));

       immediate_quit = 1;      /* Quit immediately if user types ^G,
*************** search_buffer (string, pos, pos_byte, li
*** 1110,1116 ****
          int val;
          val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
                             pos_byte - BEGV_BYTE, lim_byte - pos_byte,
!                            &search_regs,
                             /* Don't allow match past current point */
                             pos_byte - BEGV_BYTE);
          if (val == -2)
--- 1126,1132 ----
          int val;
          val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
                             pos_byte - BEGV_BYTE, lim_byte - pos_byte,
!                            regs,
                             /* Don't allow match past current point */
                             pos_byte - BEGV_BYTE);
          if (val == -2)
*************** search_buffer (string, pos, pos_byte, li
*** 1119,1136 ****
            }
          if (val >= 0)
            {
!             pos_byte = search_regs.start[0] + BEGV_BYTE;
!             for (i = 0; i < search_regs.num_regs; i++)
!               if (search_regs.start[i] >= 0)
                  {
!                   search_regs.start[i]
!                     = BYTE_TO_CHAR (search_regs.start[i] + BEGV_BYTE);
!                   search_regs.end[i]
!                     = BYTE_TO_CHAR (search_regs.end[i] + BEGV_BYTE);
                  }
              XSETBUFFER (last_thing_searched, current_buffer);
              /* Set pos to the new position. */
!             pos = search_regs.start[0];
            }
          else
            {
--- 1135,1150 ----
            }
          if (val >= 0)
            {
!             pos_byte = regs->start[0] + BEGV_BYTE;
!             for (i = 0; i < regs->num_regs; i++)
!               if (regs->start[i] >= 0)
                  {
!                   regs->start[i] = BYTE_TO_CHAR (regs->start[i] + BEGV_BYTE);
!                   regs->end[i] = BYTE_TO_CHAR (regs->end[i] + BEGV_BYTE);
                  }
              XSETBUFFER (last_thing_searched, current_buffer);
              /* Set pos to the new position. */
!             pos = regs->start[0];
            }
          else
            {
*************** search_buffer (string, pos, pos_byte, li
*** 1144,1150 ****
          int val;
          val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
                             pos_byte - BEGV_BYTE, lim_byte - pos_byte,
!                            &search_regs,
                             lim_byte - BEGV_BYTE);
          if (val == -2)
            {
--- 1158,1164 ----
          int val;
          val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2,
                             pos_byte - BEGV_BYTE, lim_byte - pos_byte,
!                            regs,
                             lim_byte - BEGV_BYTE);
          if (val == -2)
            {
*************** search_buffer (string, pos, pos_byte, li
*** 1152,1168 ****
            }
          if (val >= 0)
            {
!             pos_byte = search_regs.end[0] + BEGV_BYTE;
!             for (i = 0; i < search_regs.num_regs; i++)
!               if (search_regs.start[i] >= 0)
                  {
!                   search_regs.start[i]
!                     = BYTE_TO_CHAR (search_regs.start[i] + BEGV_BYTE);
!                   search_regs.end[i]
!                     = BYTE_TO_CHAR (search_regs.end[i] + BEGV_BYTE);
                  }
              XSETBUFFER (last_thing_searched, current_buffer);
!             pos = search_regs.end[0];
            }
          else
            {
--- 1166,1180 ----
            }
          if (val >= 0)
            {
!             pos_byte = regs->end[0] + BEGV_BYTE;
!             for (i = 0; i < regs->num_regs; i++)
!               if (regs->start[i] >= 0)
                  {
!                   regs->start[i] = BYTE_TO_CHAR (regs->start[i] + BEGV_BYTE);
!                   regs->end[i] = BYTE_TO_CHAR (regs->end[i] + BEGV_BYTE);
                  }
              XSETBUFFER (last_thing_searched, current_buffer);
!             pos = regs->end[0];
            }
          else
            {
*************** boyer_moore (n, base_pat, len, len_byte,
*** 1616,1621 ****
--- 1628,1634 ----
   register int i, j;
   unsigned char *pat, *pat_end;
   int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
+   struct re_registers *regs = SEARCH_REGS_PTR;

   unsigned char simple_translate[0400];
   /* These are set to the preceding bytes of a byte to be translated
*************** boyer_moore (n, base_pat, len, len_byte,
*** 1919,1925 ****
                    cursor += dirlen; /* to resume search */
                  else
                    return ((direction > 0)
!                           ? search_regs.end[0] : search_regs.start[0]);
                }
              else
                cursor += stride_for_teases; /* <sigh> we lose -  */
--- 1932,1938 ----
                    cursor += dirlen; /* to resume search */
                  else
                    return ((direction > 0)
!                           ? regs->end[0] : regs->start[0]);
                }
              else
                cursor += stride_for_teases; /* <sigh> we lose -  */
*************** boyer_moore (n, base_pat, len, len_byte,
*** 1995,2001 ****
                    pos_byte += dirlen; /* to resume search */
                  else
                    return ((direction > 0)
!                           ? search_regs.end[0] : search_regs.start[0]);
                }
              else
                pos_byte += stride_for_teases;
--- 2008,2014 ----
                    pos_byte += dirlen; /* to resume search */
                  else
                    return ((direction > 0)
!                           ? regs->end[0] : regs->start[0]);
                }
              else
                pos_byte += stride_for_teases;
*************** set_search_regs (beg_byte, nbytes)
*** 2017,2041 ****
      int beg_byte, nbytes;
 {
   int i;

   /* Make sure we have registers in which to store
      the match position.  */
!   if (search_regs.num_regs == 0)
     {
!       search_regs.start = (regoff_t *) xmalloc (2 * sizeof (regoff_t));
!       search_regs.end = (regoff_t *) xmalloc (2 * sizeof (regoff_t));
!       search_regs.num_regs = 2;
     }

   /* Clear out the other registers.  */
!   for (i = 1; i < search_regs.num_regs; i++)
     {
!       search_regs.start[i] = -1;
!       search_regs.end[i] = -1;
     }

!   search_regs.start[0] = BYTE_TO_CHAR (beg_byte);
!   search_regs.end[0] = BYTE_TO_CHAR (beg_byte + nbytes);
   XSETBUFFER (last_thing_searched, current_buffer);
 }

--- 2030,2055 ----
      int beg_byte, nbytes;
 {
   int i;
+   struct re_registers *regs = SEARCH_REGS_PTR;

   /* Make sure we have registers in which to store
      the match position.  */
!   if (regs->num_regs == 0)
     {
!       regs->start = (regoff_t *) xmalloc (2 * sizeof (regoff_t));
!       regs->end = (regoff_t *) xmalloc (2 * sizeof (regoff_t));
!       regs->num_regs = 2;
     }

   /* Clear out the other registers.  */
!   for (i = 1; i < regs->num_regs; i++)
     {
!       regs->start[i] = -1;
!       regs->end[i] = -1;
     }

!   regs->start[0] = BYTE_TO_CHAR (beg_byte);
!   regs->end[0] = BYTE_TO_CHAR (beg_byte + nbytes);
   XSETBUFFER (last_thing_searched, current_buffer);
 }

*************** DEFUN ("set-match-data", Fset_match_data
*** 2998,3004 ****
 }

 /* If non-zero the match data have been saved in saved_search_regs
!    during the execution of a sentinel or filter. */
 static int search_regs_saved;
 static struct re_registers saved_search_regs;
 static Lisp_Object saved_last_thing_searched;
--- 3012,3022 ----
 }

 /* If non-zero the match data have been saved in saved_search_regs
!    during the execution of a sentinel or filter.  The value of
!    saved_search_regs is copied from and recovered to search_regs
!    rather than search_regs_nochange, since the value of
!    search_regs_nochange is intended to not be used and to be
!    discarded.  */
 static int search_regs_saved;
 static struct re_registers saved_search_regs;
 static Lisp_Object saved_last_thing_searched;
*************** syms_of_search ()
*** 3145,3150 ****
--- 3163,3175 ----
A value of nil (which is the normal value) means treat spaces literally. */);
   Vsearch_spaces_regexp = Qnil;

+ DEFVAR_LISP ("inhibit-changing-match-data", &Vinhibit_changing_match_data,
+       doc: /* Internal use only.
+ If non-nil, the match data will not be changed during call to searching or
+ matching functions, such as `looking-at', `string-match', `re-search-forward'
+ etc.  */);
+   Vinhibit_changing_match_data = Qnil;
+
   defsubr (&Slooking_at);
   defsubr (&Sposix_looking_at);
   defsubr (&Sstring_match);




2007-06-30  Guanpeng Xu  <address@hidden>

        * subr.el (looking-at-p, string-match-p): New functions.

2007-06-30  Guanpeng Xu  <address@hidden>

        * search.c (search_regs_nochange, Vinhibit_changing_match_data):
        New variables.
        (SEARCH_REGS_PTR): New macro.
        (looking_at_1): Don't chang match data at Lisp level if
        Vinhibit_changing_match_data is not nil.
        (string_match_1, search_buffer, boyer_moore, set_search_regs):
        Likewise.
        (syms_of_search): Add entry of Vinhibit_changing_match_data and
        set it to nil.

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/





reply via email to

[Prev in Thread] Current Thread [Next in Thread]