(find-dired-filter): Propertize all text down to eob.
[bpt/emacs.git] / src / insdel.c
index 5bec29e..7f15f7d 100644 (file)
@@ -1,6 +1,6 @@
 /* Buffer insertion/deletion and gap motion for GNU Emacs.
-   Copyright (C) 1985, 86,93,94,95,97,98, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+                 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 #include <config.h>
@@ -79,23 +79,19 @@ static int check_markers_debug_flag;
 void
 check_markers ()
 {
-  register Lisp_Object tail;
+  register struct Lisp_Marker *tail;
   int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
 
-  tail = BUF_MARKERS (current_buffer);
-
-  while (! NILP (tail))
+  for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
     {
-      if (XMARKER (tail)->buffer->text != current_buffer->text)
+      if (tail->buffer->text != current_buffer->text)
        abort ();
-      if (XMARKER (tail)->charpos > Z)
+      if (tail->charpos > Z)
        abort ();
-      if (XMARKER (tail)->bytepos > Z_BYTE)
+      if (tail->bytepos > Z_BYTE)
        abort ();
-      if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (XMARKER (tail)->bytepos)))
+      if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (tail->bytepos)))
        abort ();
-
-      tail = XMARKER (tail)->chain;
     }
 }
 \f
@@ -350,11 +346,8 @@ adjust_markers_for_delete (from, from_byte, to, to_byte)
   register struct Lisp_Marker *m;
   register int charpos;
 
-  marker = BUF_MARKERS (current_buffer);
-
-  while (!NILP (marker))
+  for (m = BUF_MARKERS (current_buffer); m; m = m->next)
     {
-      m = XMARKER (marker);
       charpos = m->charpos;
 
       if (charpos > Z)
@@ -371,16 +364,19 @@ adjust_markers_for_delete (from, from_byte, to, to_byte)
       else if (charpos > from)
        {
          if (! m->insertion_type)
-           /* Normal markers will end up at the beginning of the
+           /* Normal markers will end up at the beginning of the
               re-inserted text after undoing a deletion, and must be
-              adjusted to move them to the correct place.  */ 
+              adjusted to move them to the correct place.  */
+             XSETMISC (marker, m);
            record_marker_adjustment (marker, from - charpos);
+           }
          else if (charpos < to)
-           /* Before-insertion markers will automatically move forward
+           /* Before-insertion markers will automatically move forward
               upon re-inserting the deleted text, so we have to arrange
               for them to move backward to the correct position.  */
+             XSETMISC (marker, m);
            record_marker_adjustment (marker, charpos - to);
-
+           }
          m->charpos = from;
          m->bytepos = from_byte;
        }
@@ -392,10 +388,9 @@ adjust_markers_for_delete (from, from_byte, to, to_byte)
             incorrectly make MARKER move forward, so we arrange for it
             to then move backward to the correct place at the beginning
             of the deleted region.  */
+         XSETMISC (marker, m);
          record_marker_adjustment (marker, to - from);
        }
-
-      marker = m->chain;
     }
 }
 
@@ -413,17 +408,13 @@ adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers)
      register int from, from_byte, to, to_byte;
      int before_markers;
 {
-  Lisp_Object marker;
+  struct Lisp_Marker *m;
   int adjusted = 0;
   int nchars = to - from;
   int nbytes = to_byte - from_byte;
 
-  marker = BUF_MARKERS (current_buffer);
-
-  while (!NILP (marker))
+  for (m = BUF_MARKERS (current_buffer); m; m = m->next)
     {
-      register struct Lisp_Marker *m = XMARKER (marker);
-
       /* In a single-byte buffer, a marker's two positions must be
         equal.  */
       if (Z == Z_BYTE)
@@ -447,14 +438,16 @@ adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers)
          m->bytepos += nbytes;
          m->charpos += nchars;
        }
-
-      marker = m->chain;
     }
 
   /* Adjusting only markers whose insertion-type is t may result in
-     disordered overlays in the slot `overlays_before'.  */
+     - disordered start and end in overlays, and 
+     - disordered overlays in the slot `overlays_before' of current_buffer.  */
   if (adjusted)
-    fix_overlays_before (current_buffer, from, to);
+    {
+      fix_start_end_in_overlays(from, to);
+      fix_overlays_before (current_buffer, from, to);
+    }
 }
 
 /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
@@ -490,15 +483,13 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
                            new_chars, new_bytes)
      int from, from_byte, old_chars, old_bytes, new_chars, new_bytes;
 {
-  Lisp_Object marker = BUF_MARKERS (current_buffer);
+  register struct Lisp_Marker *m;
   int prev_to_byte = from_byte + old_bytes;
   int diff_chars = new_chars - old_chars;
   int diff_bytes = new_bytes - old_bytes;
 
-  while (!NILP (marker))
+  for (m = BUF_MARKERS (current_buffer); m; m = m->next)
     {
-      register struct Lisp_Marker *m = XMARKER (marker);
-
       if (m->bytepos >= prev_to_byte)
        {
          m->charpos += diff_chars;
@@ -509,8 +500,6 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
          m->charpos = from;
          m->bytepos = from_byte;
        }
-
-      marker = m->chain;
     }
 
   CHECK_MARKERS ();
@@ -536,7 +525,7 @@ make_gap_larger (nbytes_added)
      That won't work because so many places use `int'.
 
      Make sure we don't introduce overflows in the calculation.  */
-     
+
   if (Z_BYTE - BEG_BYTE + GAP_SIZE
       >= (((EMACS_INT) 1 << (min (VALBITS, BITS_PER_INT) - 1)) - 1
          - nbytes_added))
@@ -573,7 +562,7 @@ make_gap_larger (nbytes_added)
 }
 
 
-/* Make the gap NBYTES_REMOVED bytes shorted.  */
+/* Make the gap NBYTES_REMOVED bytes shorter.  */
 
 void
 make_gap_smaller (nbytes_removed)
@@ -654,7 +643,7 @@ make_gap (nbytes_added)
 int
 copy_text (from_addr, to_addr, nbytes,
           from_multibyte, to_multibyte)
-     unsigned char *from_addr;
+     const unsigned char *from_addr;
      unsigned char *to_addr;
      int nbytes;
      int from_multibyte, to_multibyte;
@@ -723,7 +712,7 @@ copy_text (from_addr, to_addr, nbytes,
 
 int
 count_size_as_multibyte (ptr, nbytes)
-     unsigned char *ptr;
+     const unsigned char *ptr;
      int nbytes;
 {
   int i;
@@ -755,14 +744,15 @@ count_size_as_multibyte (ptr, nbytes)
 
 void
 insert (string, nbytes)
-     register unsigned char *string;
+     register const unsigned char *string;
      register int nbytes;
 {
   if (nbytes > 0)
     {
-      int opoint = PT;
-      insert_1 (string, nbytes, 0, 1, 0);
-      signal_after_change (opoint, 0, PT - opoint);
+      int len = chars_in_text (string, nbytes), opoint;
+      insert_1_both (string, len, nbytes, 0, 1, 0);
+      opoint = PT - len;
+      signal_after_change (opoint, 0, len);
       update_compositions (opoint, PT, CHECK_BORDER);
     }
 }
@@ -771,14 +761,15 @@ insert (string, nbytes)
 
 void
 insert_and_inherit (string, nbytes)
-     register unsigned char *string;
+     register const unsigned char *string;
      register int nbytes;
 {
   if (nbytes > 0)
     {
-      int opoint = PT;
-      insert_1 (string, nbytes, 1, 1, 0);
-      signal_after_change (opoint, 0, PT - opoint);
+      int len = chars_in_text (string, nbytes), opoint;
+      insert_1_both (string, len, nbytes, 1, 1, 0);
+      opoint = PT - len;
+      signal_after_change (opoint, 0, len);
       update_compositions (opoint, PT, CHECK_BORDER);
     }
 }
@@ -807,7 +798,7 @@ insert_char (c)
 
 void
 insert_string (s)
-     char *s;
+     const char *s;
 {
   insert (s, strlen (s));
 }
@@ -819,15 +810,15 @@ insert_string (s)
 
 void
 insert_before_markers (string, nbytes)
-     unsigned char *string;
+     const unsigned char *string;
      register int nbytes;
 {
   if (nbytes > 0)
     {
-      int opoint = PT;
-
-      insert_1 (string, nbytes, 0, 1, 1);
-      signal_after_change (opoint, 0, PT - opoint);
+      int len = chars_in_text (string, nbytes), opoint;
+      insert_1_both (string, len, nbytes, 0, 1, 1);
+      opoint = PT - len;
+      signal_after_change (opoint, 0, len);
       update_compositions (opoint, PT, CHECK_BORDER);
     }
 }
@@ -836,15 +827,15 @@ insert_before_markers (string, nbytes)
 
 void
 insert_before_markers_and_inherit (string, nbytes)
-     unsigned char *string;
+     const unsigned char *string;
      register int nbytes;
 {
   if (nbytes > 0)
     {
-      int opoint = PT;
-
-      insert_1 (string, nbytes, 1, 1, 1);
-      signal_after_change (opoint, 0, PT - opoint);
+      int len = chars_in_text (string, nbytes), opoint;
+      insert_1_both (string, len, nbytes, 1, 1, 1);
+      opoint = PT - len;
+      signal_after_change (opoint, 0, len);
       update_compositions (opoint, PT, CHECK_BORDER);
     }
 }
@@ -853,7 +844,7 @@ insert_before_markers_and_inherit (string, nbytes)
 
 void
 insert_1 (string, nbytes, inherit, prepare, before_markers)
-     register unsigned char *string;
+     register const unsigned char *string;
      register int nbytes;
      int inherit, prepare, before_markers;
 {
@@ -871,12 +862,12 @@ insert_1 (string, nbytes, inherit, prepare, before_markers)
 
 int
 count_combining_before (string, length, pos, pos_byte)
-     unsigned char *string;
+     const unsigned char *string;
      int length;
      int pos, pos_byte;
 {
   int len, combining_bytes;
-  unsigned char *p;
+  const unsigned char *p;
 
   if (NILP (current_buffer->enable_multibyte_characters))
     return 0;
@@ -918,7 +909,7 @@ count_combining_before (string, length, pos, pos_byte)
 
 int
 count_combining_after (string, length, pos, pos_byte)
-     unsigned char *string;
+     const unsigned char *string;
      int length;
      int pos, pos_byte;
 {
@@ -984,13 +975,13 @@ count_combining_after (string, length, pos, pos_byte)
 
 void
 insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
-     register unsigned char *string;
+     register const unsigned char *string;
      register int nchars, nbytes;
      int inherit, prepare, before_markers;
 {
   if (nchars == 0)
     return;
-  
+
   if (NILP (current_buffer->enable_multibyte_characters))
     nchars = nbytes;
 
@@ -1016,6 +1007,7 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
      will add up to the right stuff in the undo list.  */
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   bcopy (string, GPT_ADDR, nbytes);
 
@@ -1068,6 +1060,10 @@ insert_from_string (string, pos, pos_byte, length, length_byte, inherit)
      int inherit;
 {
   int opoint = PT;
+
+  if (SCHARS (string) == 0)
+    return;
+
   insert_from_string_1 (string, pos, pos_byte, length, length_byte,
                        inherit, 0);
   signal_after_change (opoint, 0, PT - opoint);
@@ -1085,6 +1081,10 @@ insert_from_string_before_markers (string, pos, pos_byte,
      int inherit;
 {
   int opoint = PT;
+
+  if (SCHARS (string) == 0)
+    return;
+
   insert_from_string_1 (string, pos, pos_byte, length, length_byte,
                        inherit, 1);
   signal_after_change (opoint, 0, PT - opoint);
@@ -1111,7 +1111,7 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
     outgoing_nbytes = nchars;
   else if (! STRING_MULTIBYTE (string))
     outgoing_nbytes
-      = count_size_as_multibyte (&XSTRING (string)->data[pos_byte],
+      = count_size_as_multibyte (SDATA (string) + pos_byte,
                                 nbytes);
 
   GCPRO1 (string);
@@ -1128,7 +1128,7 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
 
   /* Copy the string text into the buffer, perhaps converting
      between single-byte and multibyte.  */
-  copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes,
+  copy_text (SDATA (string) + pos_byte, GPT_ADDR, nbytes,
             STRING_MULTIBYTE (string),
             ! NILP (current_buffer->enable_multibyte_characters));
 
@@ -1145,6 +1145,7 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
 
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
   GPT += nchars;
@@ -1169,11 +1170,11 @@ insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
 
   offset_intervals (current_buffer, PT, nchars);
 
-  intervals = XSTRING (string)->intervals;
+  intervals = STRING_INTERVALS (string);
   /* Get the intervals for the part of the string we are inserting.  */
-  if (nbytes < STRING_BYTES (XSTRING (string)))
+  if (nbytes < SBYTES (string))
     intervals = copy_intervals (intervals, pos, nchars);
-                              
+
   /* Insert those intervals.  */
   graft_intervals_into_buffer (intervals, PT, nchars,
                               current_buffer, inherit);
@@ -1239,13 +1240,13 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
 
       if (chunk < incoming_nbytes)
        outgoing_after_gap
-         = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, 
+         = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf,
                                                       from_byte + chunk),
                                     incoming_nbytes - chunk);
 
       outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
     }
-  
+
   /* Make sure point-max won't overflow after this insertion.  */
   XSETINT (temp, outgoing_nbytes + Z);
   if (outgoing_nbytes + Z != XINT (temp))
@@ -1296,6 +1297,7 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
 
   record_insert (PT, nchars);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
   GPT += nchars;
@@ -1329,7 +1331,7 @@ insert_from_buffer_1 (buf, from, nchars, inherit)
        from += nchars;
       intervals = copy_intervals (intervals, from, nchars);
     }
-                              
+
   /* Insert those intervals.  */
   graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
 
@@ -1358,8 +1360,8 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
 
   if (STRINGP (prev_text))
     {
-      nchars_del = XSTRING (prev_text)->size;
-      nbytes_del = STRING_BYTES (XSTRING (prev_text));
+      nchars_del = SCHARS (prev_text);
+      nbytes_del = SBYTES (prev_text);
     }
 
   /* Update various buffer positions for the new text.  */
@@ -1404,6 +1406,7 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte)
   if (len == 0)
     evaporate_overlays (from);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 }
 
 /* Like adjust_after_replace, but doesn't require PREV_TEXT.
@@ -1454,6 +1457,7 @@ adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del, len, len_b
   if (len == 0)
     evaporate_overlays (from);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 }
 
 /* Record undo information, adjust markers and position keepers for an
@@ -1475,7 +1479,7 @@ adjust_after_insert (from, from_byte, to, to_byte, newlen)
   Z -= len; Z_BYTE -= len_byte;
   adjust_after_replace (from, from_byte, Qnil, newlen, len_byte);
 }
-
+\f
 /* Replace the text from character positions FROM to TO with NEW,
    If PREPARE is nonzero, call prepare_to_modify_buffer.
    If INHERIT, the newly inserted text should inherit text properties
@@ -1493,8 +1497,8 @@ replace_range (from, to, new, prepare, inherit, markers)
      Lisp_Object new;
      int from, to, prepare, inherit, markers;
 {
-  int inschars = XSTRING (new)->size;
-  int insbytes = STRING_BYTES (XSTRING (new));
+  int inschars = SCHARS (new);
+  int insbytes = SBYTES (new);
   int from_byte, to_byte;
   int nbytes_del, nchars_del;
   register Lisp_Object temp;
@@ -1539,7 +1543,7 @@ replace_range (from, to, new, prepare, inherit, markers)
     outgoing_insbytes = inschars;
   else if (! STRING_MULTIBYTE (new))
     outgoing_insbytes
-      = count_size_as_multibyte (XSTRING (new)->data, insbytes);
+      = count_size_as_multibyte (SDATA (new), insbytes);
 
   /* Make sure point-max won't overflow after this insertion.  */
   XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
@@ -1567,7 +1571,7 @@ replace_range (from, to, new, prepare, inherit, markers)
   Z_BYTE -= nbytes_del;
   GPT = from;
   GPT_BYTE = from_byte;
-  *(GPT_ADDR) = 0;             /* Put an anchor.  */
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
 
   if (GPT_BYTE < GPT)
     abort ();
@@ -1582,7 +1586,7 @@ replace_range (from, to, new, prepare, inherit, markers)
 
   /* Copy the string text into the buffer, perhaps converting
      between single-byte and multibyte.  */
-  copy_text (XSTRING (new)->data, GPT_ADDR, insbytes,
+  copy_text (SDATA (new), GPT_ADDR, insbytes,
             STRING_MULTIBYTE (new),
             ! NILP (current_buffer->enable_multibyte_characters));
 
@@ -1629,7 +1633,7 @@ replace_range (from, to, new, prepare, inherit, markers)
 
   /* Get the intervals for the part of the string we are inserting--
      not including the combined-before bytes.  */
-  intervals = XSTRING (new)->intervals;
+  intervals = STRING_INTERVALS (new);
   /* Insert those intervals.  */
   graft_intervals_into_buffer (intervals, from, inschars,
                               current_buffer, inherit);
@@ -1646,12 +1650,134 @@ replace_range (from, to, new, prepare, inherit, markers)
   CHECK_MARKERS ();
 
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
   UNGCPRO;
 
   signal_after_change (from, nchars_del, GPT - from);
   update_compositions (from, GPT, CHECK_BORDER);
 }
 \f
+/* Replace the text from character positions FROM to TO with
+   the text in INS of length INSCHARS.
+   Keep the text properties that applied to the old characters
+   (extending them to all the new chars if there are more new chars).
+
+   Note that this does not yet handle markers quite right.
+
+   If MARKERS is nonzero, relocate markers.
+
+   Unlike most functions at this level, never call
+   prepare_to_modify_buffer and never call signal_after_change.  */
+
+void
+replace_range_2 (from, from_byte, to, to_byte, ins, inschars, insbytes, markers)
+     int from, from_byte, to, to_byte;
+     char *ins;
+     int inschars, insbytes, markers;
+{
+  int nbytes_del, nchars_del;
+  Lisp_Object temp;
+
+  CHECK_MARKERS ();
+
+  nchars_del = to - from;
+  nbytes_del = to_byte - from_byte;
+
+  if (nbytes_del <= 0 && insbytes == 0)
+    return;
+
+  /* Make sure point-max won't overflow after this insertion.  */
+  XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
+  if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
+    error ("Maximum buffer size exceeded");
+
+  /* Make sure the gap is somewhere in or next to what we are deleting.  */
+  if (from > GPT)
+    gap_right (from, from_byte);
+  if (to < GPT)
+    gap_left (to, to_byte, 0);
+
+  GAP_SIZE += nbytes_del;
+  ZV -= nchars_del;
+  Z -= nchars_del;
+  ZV_BYTE -= nbytes_del;
+  Z_BYTE -= nbytes_del;
+  GPT = from;
+  GPT_BYTE = from_byte;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  if (GPT - BEG < BEG_UNCHANGED)
+    BEG_UNCHANGED = GPT - BEG;
+  if (Z - GPT < END_UNCHANGED)
+    END_UNCHANGED = Z - GPT;
+
+  if (GAP_SIZE < insbytes)
+    make_gap (insbytes - GAP_SIZE);
+
+  /* Copy the replacement text into the buffer.  */
+  bcopy (ins, GPT_ADDR, insbytes);
+
+#ifdef BYTE_COMBINING_DEBUG
+  /* We have copied text into the gap, but we have not marked
+     it as part of the buffer.  So we can use the old FROM and FROM_BYTE
+     here, for both the previous text and the following text.
+     Meanwhile, GPT_ADDR does point to
+     the text that has been stored by copy_text.  */
+  if (count_combining_before (GPT_ADDR, insbytes, from, from_byte)
+      || count_combining_after (GPT_ADDR, insbytes, from, from_byte))
+    abort ();
+#endif
+
+  GAP_SIZE -= insbytes;
+  GPT += inschars;
+  ZV += inschars;
+  Z += inschars;
+  GPT_BYTE += insbytes;
+  ZV_BYTE += insbytes;
+  Z_BYTE += insbytes;
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
+
+  if (GPT_BYTE < GPT)
+    abort ();
+
+  /* Adjust the overlay center as needed.  This must be done after
+     adjusting the markers that bound the overlays.  */
+  if (nchars_del != inschars)
+    {
+      adjust_overlays_for_insert (from, inschars);
+      adjust_overlays_for_delete (from + inschars, nchars_del);
+    }
+
+  /* Adjust markers for the deletion and the insertion.  */
+  if (markers
+      && ! (nchars_del == 1 && inschars == 1 && nbytes_del == insbytes))
+    adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+                               inschars, insbytes);
+
+  offset_intervals (current_buffer, from, inschars - nchars_del);
+
+  /* Relocate point as if it were a marker.  */
+  if (from < PT && (nchars_del != inschars || nbytes_del != insbytes))
+    {
+      if (PT < to)
+       /* PT was within the deleted text.  Move it to FROM.  */
+       adjust_point (from - PT, from_byte - PT_BYTE);
+      else
+       adjust_point (inschars - nchars_del, insbytes - nbytes_del);
+    }
+
+  if (insbytes == 0)
+    evaporate_overlays (from);
+
+  CHECK_MARKERS ();
+
+  MODIFF++;
+  CHARS_MODIFF = MODIFF;
+}
+\f
 /* Delete characters in current buffer
    from FROM up to (but not including) TO.
    If TO comes before FROM, we delete nothing.  */
@@ -1831,6 +1957,7 @@ del_range_2 (from, from_byte, to, to_byte, ret_string)
   if (! EQ (current_buffer->undo_list, Qt))
     record_delete (from, deletion);
   MODIFF++;
+  CHARS_MODIFF = MODIFF;
 
   /* Relocate point as if it were a marker.  */
   if (from < PT)
@@ -1850,7 +1977,7 @@ del_range_2 (from, from_byte, to, to_byte, ret_string)
   Z -= nchars_del;
   GPT = from;
   GPT_BYTE = from_byte;
-  *(GPT_ADDR) = 0;             /* Put an anchor.  */
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
 
   if (GPT_BYTE < GPT)
     abort ();
@@ -1871,12 +1998,15 @@ del_range_2 (from, from_byte, to, to_byte, ret_string)
    character positions START to END.  This checks the read-only
    properties of the region, calls the necessary modification hooks,
    and warns the next redisplay that it should pay attention to that
-   area.  */
+   area.
+
+   If PRESERVE_CHARS_MODIFF is non-zero, do not update CHARS_MODIFF.
+   Otherwise set CHARS_MODIFF to the new value of MODIFF.  */
 
 void
-modify_region (buffer, start, end)
+modify_region (buffer, start, end, preserve_chars_modiff)
      struct buffer *buffer;
-     int start, end;
+     int start, end, preserve_chars_modiff;
 {
   struct buffer *old_buffer = current_buffer;
 
@@ -1890,6 +2020,8 @@ modify_region (buffer, start, end)
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
   MODIFF++;
+  if (! preserve_chars_modiff)
+    CHARS_MODIFF = MODIFF;
 
   buffer->point_before_scroll = Qnil;
 
@@ -1912,6 +2044,8 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
      int start, end;
      int *preserve_ptr;
 {
+  struct buffer *base_buffer;
+
   if (!NILP (current_buffer->read_only))
     Fbarf_if_buffer_read_only ();
 
@@ -1930,27 +2064,33 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
          GCPRO1 (preserve_marker);
          verify_interval_modification (current_buffer, start, end);
          *preserve_ptr = marker_position (preserve_marker);
-         unchain_marker (preserve_marker);
+         unchain_marker (XMARKER (preserve_marker));
          UNGCPRO;
        }
       else
        verify_interval_modification (current_buffer, start, end);
     }
 
+  /* For indirect buffers, use the base buffer to check clashes.  */
+  if (current_buffer->base_buffer != 0)
+    base_buffer = current_buffer->base_buffer;
+  else
+    base_buffer = current_buffer;
+
 #ifdef CLASH_DETECTION
-  if (!NILP (current_buffer->file_truename)
+  if (!NILP (base_buffer->file_truename)
       /* Make binding buffer-file-name to nil effective.  */
-      && !NILP (current_buffer->filename)
+      && !NILP (base_buffer->filename)
       && SAVE_MODIFF >= MODIFF)
-    lock_file (current_buffer->file_truename);
+    lock_file (base_buffer->file_truename);
 #else
   /* At least warn if this file has changed on disk since it was visited.  */
-  if (!NILP (current_buffer->filename)
+  if (!NILP (base_buffer->filename)
       && SAVE_MODIFF >= MODIFF
       && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
-      && !NILP (Ffile_exists_p (current_buffer->filename)))
+      && !NILP (Ffile_exists_p (base_buffer->filename)))
     call1 (intern ("ask-user-about-supersession-threat"),
-          current_buffer->filename);
+          base_buffer->filename);
 #endif /* not CLASH_DETECTION */
 
   signal_before_change (start, end, preserve_ptr);
@@ -1978,7 +2118,7 @@ prepare_to_modify_buffer (start, end, preserve_ptr)
   if (! NILP (preserve_marker))                                        \
     {                                                          \
       *preserve_ptr = marker_position (preserve_marker);       \
-      unchain_marker (preserve_marker);                                \
+      unchain_marker (XMARKER (preserve_marker));              \
     }
 
 #define PRESERVE_START_END                     \
@@ -2075,8 +2215,7 @@ signal_before_change (start_int, end_int, preserve_ptr)
       UNGCPRO;
     }
 
-  if (!NILP (current_buffer->overlays_before)
-      || !NILP (current_buffer->overlays_after))
+  if (current_buffer->overlays_before || current_buffer->overlays_after)
     {
       PRESERVE_VALUE;
       report_overlay_modification (FETCH_START, FETCH_END, 0,
@@ -2110,8 +2249,8 @@ signal_after_change (charpos, lendel, lenins)
      just record the args that we were going to use.  */
   if (! NILP (Vcombine_after_change_calls)
       && NILP (Vbefore_change_functions)
-      && NILP (current_buffer->overlays_before)
-      && NILP (current_buffer->overlays_after))
+      && !current_buffer->overlays_before
+      && !current_buffer->overlays_after)
     {
       Lisp_Object elt;
 
@@ -2129,7 +2268,7 @@ signal_after_change (charpos, lendel, lenins)
       return;
     }
 
-  if (!NILP (combine_after_change_list)) 
+  if (!NILP (combine_after_change_list))
     Fcombine_after_change_execute ();
 
   if (!NILP (Vafter_change_functions))
@@ -2176,8 +2315,7 @@ signal_after_change (charpos, lendel, lenins)
       UNGCPRO;
     }
 
-  if (!NILP (current_buffer->overlays_before)
-      || !NILP (current_buffer->overlays_after))
+  if (current_buffer->overlays_before || current_buffer->overlays_after)
     report_overlay_modification (make_number (charpos),
                                 make_number (charpos + lenins),
                                 1,
@@ -2205,7 +2343,7 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
        doc: /* This function is for use internally in `combine-after-change-calls'.  */)
      ()
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   int beg, end, change;
   int begpos, endpos;
   Lisp_Object tail;
@@ -2213,6 +2351,17 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
   if (NILP (combine_after_change_list))
     return Qnil;
 
+  /* It is rare for combine_after_change_buffer to be invalid, but
+     possible.  It can happen when combine-after-change-calls is
+     non-nil, and insertion calls a file handler (e.g. through
+     lock_file) which scribbles into a temp file -- cyd  */
+  if (!BUFFERP (combine_after_change_buffer)
+      || NILP (XBUFFER (combine_after_change_buffer)->name))
+    {
+      combine_after_change_list = Qnil;
+      return Qnil;
+    }
+
   record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
 
   Fset_buffer (combine_after_change_buffer);
@@ -2260,7 +2409,7 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
      that was changed.  */
   begpos = BEG + beg;
   endpos = Z - end;
-  
+
   /* We are about to handle these, so discard them.  */
   combine_after_change_list = Qnil;
 
@@ -2278,6 +2427,7 @@ void
 syms_of_insdel ()
 {
   staticpro (&combine_after_change_list);
+  staticpro (&combine_after_change_buffer);
   combine_after_change_list = Qnil;
   combine_after_change_buffer = Qnil;
 
@@ -2298,3 +2448,6 @@ as well as hooks attached to text properties and overlays.  */);
 
   defsubr (&Scombine_after_change_execute);
 }
+
+/* arch-tag: 9b34b886-47d7-465e-a234-299af411b23d
+   (do not change this comment) */