1 /* Buffer insertion/deletion and gap motion for GNU Emacs. -*- coding: utf-8 -*-
2    Copyright (C) 1985-1986, 1993-1995, 1997-2021 Free Software
3    Foundation, Inc.
4 
5 This file is part of GNU Emacs.
6 
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11 
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
19 
20 
21 #include <config.h>
22 
23 #include <intprops.h>
24 
25 #include "lisp.h"
26 #include "composite.h"
27 #include "intervals.h"
28 #include "character.h"
29 #include "buffer.h"
30 #include "window.h"
31 #include "region-cache.h"
32 #include "pdumper.h"
33 
34 static void insert_from_string_1 (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t,
35 				  ptrdiff_t, bool, bool);
36 static void insert_from_buffer_1 (struct buffer *, ptrdiff_t, ptrdiff_t, bool);
37 static void gap_left (ptrdiff_t, ptrdiff_t, bool);
38 static void gap_right (ptrdiff_t, ptrdiff_t);
39 
40 /* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT)
41    describing changes which happened while combine_after_change_calls
42    was non-nil.  We use this to decide how to call them
43    once the deferral ends.
44 
45    In each element.
46    BEG-UNCHANGED is the number of chars before the changed range.
47    END-UNCHANGED is the number of chars after the changed range,
48    and CHANGE-AMOUNT is the number of characters inserted by the change
49    (negative for a deletion).  */
50 static Lisp_Object combine_after_change_list;
51 
52 /* Buffer which combine_after_change_list is about.  */
53 static Lisp_Object combine_after_change_buffer;
54 
55 static void signal_before_change (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
56 
57 /* Also used in marker.c to enable expensive marker checks.  */
58 
59 #ifdef MARKER_DEBUG
60 
61 static void
check_markers(void)62 check_markers (void)
63 {
64   struct Lisp_Marker *tail;
65   bool multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
66 
67   for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
68     {
69       if (tail->buffer->text != current_buffer->text)
70 	emacs_abort ();
71       if (tail->charpos > Z)
72 	emacs_abort ();
73       if (tail->bytepos > Z_BYTE)
74 	emacs_abort ();
75       if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (tail->bytepos)))
76 	emacs_abort ();
77     }
78 }
79 
80 #else /* not MARKER_DEBUG */
81 
82 #define check_markers() do { } while (0)
83 
84 #endif /* MARKER_DEBUG */
85 
86 /* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
87    Note that this can quit!  */
88 
89 void
move_gap_both(ptrdiff_t charpos,ptrdiff_t bytepos)90 move_gap_both (ptrdiff_t charpos, ptrdiff_t bytepos)
91 {
92   eassert (charpos == BYTE_TO_CHAR (bytepos)
93 	   && bytepos == CHAR_TO_BYTE (charpos));
94   if (bytepos < GPT_BYTE)
95     gap_left (charpos, bytepos, 0);
96   else if (bytepos > GPT_BYTE)
97     gap_right (charpos, bytepos);
98 }
99 
100 /* Move the gap to a position less than the current GPT.
101    BYTEPOS describes the new position as a byte position,
102    and CHARPOS is the corresponding char position.
103    If NEWGAP, then don't update beg_unchanged and end_unchanged.  */
104 
105 static void
gap_left(ptrdiff_t charpos,ptrdiff_t bytepos,bool newgap)106 gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, bool newgap)
107 {
108   unsigned char *to, *from;
109   ptrdiff_t i;
110   ptrdiff_t new_s1;
111 
112   if (!newgap)
113     BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
114 
115   i = GPT_BYTE;
116   to = GAP_END_ADDR;
117   from = GPT_ADDR;
118   new_s1 = GPT_BYTE; /* May point in the middle of multibyte sequences.  */
119 
120   /* Now copy the characters.  To move the gap down,
121      copy characters up.  */
122 
123   while (1)
124     {
125       /* I gets number of characters left to copy.  */
126       i = new_s1 - bytepos;
127       if (i == 0)
128 	break;
129       /* If a quit is requested, stop copying now.
130 	 Change BYTEPOS to be where we have actually moved the gap to.
131 	 Note that this cannot happen when we are called to make the
132 	 gap larger or smaller, since make_gap_larger and
133 	 make_gap_smaller set inhibit-quit.  */
134       if (QUITP)
135 	{
136           /* FIXME: This can point in the middle of a multibyte character.  */
137 	  bytepos = new_s1;
138 	  charpos = BYTE_TO_CHAR (bytepos);
139 	  break;
140 	}
141       /* Move at most 32000 chars before checking again for a quit.  */
142       /* FIXME: This 32KB chunk size dates back to before 1991.
143          Maybe we should bump it to reflect the >1000x increase
144          in memory size and bandwidth since that time.
145          Is it even worthwhile checking `quit` within this loop?
146          Especially since make_gap_smaller/larger binds inhibit-quit anyway!  */
147       if (i > 32000)
148 	i = 32000;
149       new_s1 -= i;
150       from -= i, to -= i;
151       memmove (to, from, i);
152     }
153 
154   /* Adjust buffer data structure, to put the gap at BYTEPOS.
155      BYTEPOS is where the loop above stopped, which may be what
156      was specified or may be where a quit was detected.  */
157   GPT_BYTE = bytepos;
158   GPT = charpos;
159   eassert (charpos <= bytepos);
160   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
161   maybe_quit ();
162 }
163 
164 /* Move the gap to a position greater than the current GPT.
165    BYTEPOS describes the new position as a byte position,
166    and CHARPOS is the corresponding char position.  */
167 
168 static void
gap_right(ptrdiff_t charpos,ptrdiff_t bytepos)169 gap_right (ptrdiff_t charpos, ptrdiff_t bytepos)
170 {
171   register unsigned char *to, *from;
172   register ptrdiff_t i;
173   ptrdiff_t new_s1; /* May point in the middle of multibyte sequences.  */
174 
175   BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
176 
177   i = GPT_BYTE;
178   from = GAP_END_ADDR;
179   to = GPT_ADDR;
180   new_s1 = GPT_BYTE;
181 
182   /* Now copy the characters.  To move the gap up,
183      copy characters down.  */
184 
185   while (1)
186     {
187       /* I gets number of characters left to copy.  */
188       i = bytepos - new_s1;
189       if (i == 0)
190 	break;
191       /* If a quit is requested, stop copying now.
192 	 Change BYTEPOS to be where we have actually moved the gap to.
193 	 Note that this cannot happen when we are called to make the
194 	 gap larger or smaller, since make_gap_larger and
195 	 make_gap_smaller set inhibit-quit.  */
196       if (QUITP)
197 	{
198           /* FIXME: This can point in the middle of a multibyte character.  */
199 	  bytepos = new_s1;
200 	  charpos = BYTE_TO_CHAR (bytepos);
201 	  break;
202 	}
203       /* Move at most 32000 chars before checking again for a quit.  */
204       if (i > 32000)
205 	i = 32000;
206       new_s1 += i;
207       memmove (to, from, i);
208       from += i, to += i;
209     }
210 
211   GPT = charpos;
212   GPT_BYTE = bytepos;
213   eassert (charpos <= bytepos);
214   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
215   maybe_quit ();
216 }
217 
218 /* If the selected window's old pointm is adjacent or covered by the
219    region from FROM to TO, unsuspend auto hscroll in that window.  */
220 
221 static void
adjust_suspend_auto_hscroll(ptrdiff_t from,ptrdiff_t to)222 adjust_suspend_auto_hscroll (ptrdiff_t from, ptrdiff_t to)
223 {
224   if (WINDOWP (selected_window))
225     {
226       struct window *w = XWINDOW (selected_window);
227 
228       if (BUFFERP (w->contents)
229 	  && XBUFFER (w->contents) == current_buffer
230 	  && XMARKER (w->old_pointm)->charpos >= from
231 	  && XMARKER (w->old_pointm)->charpos <= to)
232 	w->suspend_auto_hscroll = 0;
233     }
234 }
235 
236 
237 /* Adjust all markers for a deletion
238    whose range in bytes is FROM_BYTE to TO_BYTE.
239    The range in charpos is FROM to TO.
240 
241    This function assumes that the gap is adjacent to
242    or inside of the range being deleted.  */
243 
244 void
adjust_markers_for_delete(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte)245 adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte,
246 			   ptrdiff_t to, ptrdiff_t to_byte)
247 {
248   struct Lisp_Marker *m;
249   ptrdiff_t charpos;
250 
251   adjust_suspend_auto_hscroll (from, to);
252   for (m = BUF_MARKERS (current_buffer); m; m = m->next)
253     {
254       charpos = m->charpos;
255       eassert (charpos <= Z);
256 
257       /* If the marker is after the deletion,
258 	 relocate by number of chars / bytes deleted.  */
259       if (charpos > to)
260 	{
261 	  m->charpos -= to - from;
262 	  m->bytepos -= to_byte - from_byte;
263 	}
264       /* Here's the case where a marker is inside text being deleted.  */
265       else if (charpos > from)
266 	{
267 	  m->charpos = from;
268 	  m->bytepos = from_byte;
269 	}
270     }
271 }
272 
273 
274 /* Adjust markers for an insertion that stretches from FROM / FROM_BYTE
275    to TO / TO_BYTE.  We have to relocate the charpos of every marker
276    that points after the insertion (but not their bytepos).
277 
278    When a marker points at the insertion point,
279    we advance it if either its insertion-type is t
280    or BEFORE_MARKERS is true.  */
281 
282 static void
adjust_markers_for_insert(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,bool before_markers)283 adjust_markers_for_insert (ptrdiff_t from, ptrdiff_t from_byte,
284 			   ptrdiff_t to, ptrdiff_t to_byte, bool before_markers)
285 {
286   struct Lisp_Marker *m;
287   bool adjusted = 0;
288   ptrdiff_t nchars = to - from;
289   ptrdiff_t nbytes = to_byte - from_byte;
290 
291   adjust_suspend_auto_hscroll (from, to);
292   for (m = BUF_MARKERS (current_buffer); m; m = m->next)
293     {
294       eassert (m->bytepos >= m->charpos
295 	       && m->bytepos - m->charpos <= Z_BYTE - Z);
296 
297       if (m->bytepos == from_byte)
298 	{
299 	  if (m->insertion_type || before_markers)
300 	    {
301 	      m->bytepos = to_byte;
302 	      m->charpos = to;
303 	      if (m->insertion_type)
304 		adjusted = 1;
305 	    }
306 	}
307       else if (m->bytepos > from_byte)
308 	{
309 	  m->bytepos += nbytes;
310 	  m->charpos += nchars;
311 	}
312     }
313 
314   /* Adjusting only markers whose insertion-type is t may result in
315      - disordered start and end in overlays, and
316      - disordered overlays in the slot `overlays_before' of current_buffer.  */
317   if (adjusted)
318     {
319       fix_start_end_in_overlays (from, to);
320       fix_overlays_before (current_buffer, from, to);
321     }
322 }
323 
324 /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
325 
326    This is used only when the value of point changes due to an insert
327    or delete; it does not represent a conceptual change in point as a
328    marker.  In particular, point is not crossing any interval
329    boundaries, so there's no need to use the usual SET_PT macro.  In
330    fact it would be incorrect to do so, because either the old or the
331    new value of point is out of sync with the current set of
332    intervals.  */
333 
334 static void
adjust_point(ptrdiff_t nchars,ptrdiff_t nbytes)335 adjust_point (ptrdiff_t nchars, ptrdiff_t nbytes)
336 {
337   SET_BUF_PT_BOTH (current_buffer, PT + nchars, PT_BYTE + nbytes);
338   /* In a single-byte buffer, the two positions must be equal.  */
339   eassert (PT_BYTE >= PT && PT_BYTE - PT <= ZV_BYTE - ZV);
340 }
341 
342 /* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
343    length OLD_CHARS (OLD_BYTES) to a new text of length NEW_CHARS
344    (NEW_BYTES).  It is assumed that OLD_CHARS > 0, i.e., this is not
345    an insertion.  */
346 
347 static void
adjust_markers_for_replace(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t old_chars,ptrdiff_t old_bytes,ptrdiff_t new_chars,ptrdiff_t new_bytes)348 adjust_markers_for_replace (ptrdiff_t from, ptrdiff_t from_byte,
349 			    ptrdiff_t old_chars, ptrdiff_t old_bytes,
350 			    ptrdiff_t new_chars, ptrdiff_t new_bytes)
351 {
352   register struct Lisp_Marker *m;
353   ptrdiff_t prev_to_byte = from_byte + old_bytes;
354   ptrdiff_t diff_chars = new_chars - old_chars;
355   ptrdiff_t diff_bytes = new_bytes - old_bytes;
356 
357   adjust_suspend_auto_hscroll (from, from + old_chars);
358   for (m = BUF_MARKERS (current_buffer); m; m = m->next)
359     {
360       if (m->bytepos >= prev_to_byte)
361 	{
362 	  m->charpos += diff_chars;
363 	  m->bytepos += diff_bytes;
364 	}
365       else if (m->bytepos > from_byte)
366 	{
367 	  m->charpos = from;
368 	  m->bytepos = from_byte;
369 	}
370     }
371 
372   check_markers ();
373 }
374 
375 /* Starting at POS (BYTEPOS), find the byte position corresponding to
376    ENDPOS, which could be either before or after POS.  */
377 static ptrdiff_t
count_bytes(ptrdiff_t pos,ptrdiff_t bytepos,ptrdiff_t endpos)378 count_bytes (ptrdiff_t pos, ptrdiff_t bytepos, ptrdiff_t endpos)
379 {
380   eassert (BEG_BYTE <= bytepos && bytepos <= Z_BYTE
381 	   && BEG <= endpos && endpos <= Z);
382 
383   if (pos <= endpos)
384     for ( ; pos < endpos; pos++)
385       INC_POS (bytepos);
386   else
387     for ( ; pos > endpos; pos--)
388       DEC_POS (bytepos);
389 
390   return bytepos;
391 }
392 
393 /* Adjust byte positions of markers when their character positions
394    didn't change.  This is used in several places that replace text,
395    but keep the character positions of the markers unchanged -- the
396    byte positions could still change due to different numbers of bytes
397    in the new text.
398 
399    FROM (FROM_BYTE) and TO (TO_BYTE) specify the region of text where
400    changes have been done.  TO_Z, if non-zero, means all the markers
401    whose positions are after TO should also be adjusted.  */
402 void
adjust_markers_bytepos(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,int to_z)403 adjust_markers_bytepos (ptrdiff_t from, ptrdiff_t from_byte,
404 			ptrdiff_t to, ptrdiff_t to_byte, int to_z)
405 {
406   register struct Lisp_Marker *m;
407   ptrdiff_t beg = from, begbyte = from_byte;
408 
409   adjust_suspend_auto_hscroll (from, to);
410 
411   if (Z == Z_BYTE || (!to_z && to == to_byte))
412     {
413       /* Make sure each affected marker's bytepos is equal to
414 	 its charpos.  */
415       for (m = BUF_MARKERS (current_buffer); m; m = m->next)
416 	{
417 	  if (m->bytepos > from_byte
418 	      && (to_z || m->bytepos <= to_byte))
419 	    m->bytepos = m->charpos;
420 	}
421     }
422   else
423     {
424       for (m = BUF_MARKERS (current_buffer); m; m = m->next)
425 	{
426 	  /* Recompute each affected marker's bytepos.  */
427 	  if (m->bytepos > from_byte
428 	      && (to_z || m->bytepos <= to_byte))
429 	    {
430 	      if (m->charpos < beg
431 		  && beg - m->charpos > m->charpos - from)
432 		{
433 		  beg = from;
434 		  begbyte = from_byte;
435 		}
436 	      m->bytepos = count_bytes (beg, begbyte, m->charpos);
437 	      beg = m->charpos;
438 	      begbyte = m->bytepos;
439 	    }
440 	}
441     }
442 
443   /* Make sure cached charpos/bytepos is invalid.  */
444   clear_charpos_cache (current_buffer);
445 }
446 
447 
448 void
buffer_overflow(void)449 buffer_overflow (void)
450 {
451   error ("Maximum buffer size exceeded");
452 }
453 
454 /* Make the gap NBYTES_ADDED bytes longer.  */
455 
456 static void
make_gap_larger(ptrdiff_t nbytes_added)457 make_gap_larger (ptrdiff_t nbytes_added)
458 {
459   Lisp_Object tem;
460   ptrdiff_t real_gap_loc;
461   ptrdiff_t real_gap_loc_byte;
462   ptrdiff_t old_gap_size;
463   ptrdiff_t current_size = Z_BYTE - BEG_BYTE + GAP_SIZE;
464 
465   if (BUF_BYTES_MAX - current_size < nbytes_added)
466     buffer_overflow ();
467 
468   /* If we have to get more space, get enough to last a while;
469      but do not exceed the maximum buffer size.  */
470   nbytes_added = min (nbytes_added + GAP_BYTES_DFL,
471 		      BUF_BYTES_MAX - current_size);
472 
473   enlarge_buffer_text (current_buffer, nbytes_added);
474 
475   /* Prevent quitting in gap_left.  We cannot allow a quit there,
476      because that would leave the buffer text in an inconsistent
477      state, with 2 gap holes instead of just one.  */
478   tem = Vinhibit_quit;
479   Vinhibit_quit = Qt;
480 
481   real_gap_loc = GPT;
482   real_gap_loc_byte = GPT_BYTE;
483   old_gap_size = GAP_SIZE;
484 
485   /* Call the newly allocated space a gap at the end of the whole space.  */
486   GPT = Z + GAP_SIZE;
487   GPT_BYTE = Z_BYTE + GAP_SIZE;
488   GAP_SIZE = nbytes_added;
489 
490   /* Move the new gap down to be consecutive with the end of the old one.  */
491   gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1);
492 
493   /* Now combine the two into one large gap.  */
494   GAP_SIZE += old_gap_size;
495   GPT = real_gap_loc;
496   GPT_BYTE = real_gap_loc_byte;
497 
498   /* Put an anchor.  */
499   *(Z_ADDR) = 0;
500 
501   Vinhibit_quit = tem;
502 }
503 
504 #if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
505 
506 /* Make the gap NBYTES_REMOVED bytes shorter.  */
507 
508 static void
make_gap_smaller(ptrdiff_t nbytes_removed)509 make_gap_smaller (ptrdiff_t nbytes_removed)
510 {
511   Lisp_Object tem;
512   ptrdiff_t real_gap_loc;
513   ptrdiff_t real_gap_loc_byte;
514   ptrdiff_t real_Z;
515   ptrdiff_t real_Z_byte;
516   ptrdiff_t real_beg_unchanged;
517   ptrdiff_t new_gap_size;
518 
519   /* Make sure the gap is at least GAP_BYTES_MIN bytes.  */
520   if (GAP_SIZE - nbytes_removed < GAP_BYTES_MIN)
521     nbytes_removed = GAP_SIZE - GAP_BYTES_MIN;
522 
523   /* Prevent quitting in gap_right.  We cannot allow a quit there,
524      because that would leave the buffer text in an inconsistent
525      state, with 2 gap holes instead of just one.  */
526   tem = Vinhibit_quit;
527   Vinhibit_quit = Qt;
528 
529   real_gap_loc = GPT;
530   real_gap_loc_byte = GPT_BYTE;
531   new_gap_size = GAP_SIZE - nbytes_removed;
532   real_Z = Z;
533   real_Z_byte = Z_BYTE;
534   real_beg_unchanged = BEG_UNCHANGED;
535 
536   /* Pretend that the last unwanted part of the gap is the entire gap,
537      and that the first desired part of the gap is part of the buffer
538      text.  */
539   memset (GPT_ADDR, 0, new_gap_size);
540   GPT += new_gap_size;
541   GPT_BYTE += new_gap_size;
542   Z += new_gap_size;
543   Z_BYTE += new_gap_size;
544   GAP_SIZE = nbytes_removed;
545 
546   /* Move the unwanted pretend gap to the end of the buffer.  */
547   gap_right (Z, Z_BYTE);
548 
549   enlarge_buffer_text (current_buffer, -nbytes_removed);
550 
551   /* Now restore the desired gap.  */
552   GAP_SIZE = new_gap_size;
553   GPT = real_gap_loc;
554   GPT_BYTE = real_gap_loc_byte;
555   Z = real_Z;
556   Z_BYTE = real_Z_byte;
557   BEG_UNCHANGED = real_beg_unchanged;
558 
559   /* Put an anchor.  */
560   *(Z_ADDR) = 0;
561 
562   Vinhibit_quit = tem;
563 }
564 
565 #endif /* USE_MMAP_FOR_BUFFERS || REL_ALLOC || DOUG_LEA_MALLOC */
566 
567 void
make_gap(ptrdiff_t nbytes_added)568 make_gap (ptrdiff_t nbytes_added)
569 {
570   if (nbytes_added >= 0)
571     /* With set-buffer-multibyte on a large buffer, we can end up growing the
572      * buffer *many* times.  Avoid an O(N^2) behavior by increasing by an
573      * amount at least proportional to the size of the buffer.
574      * On my test (a 223.9MB zip file on a Thinkpad T61):
575      * With /5    =>  24s
576      * With /32   =>  25s
577      * With /64   =>  26s
578      * With /128  =>  28s
579      * With /1024 =>  51s
580      * With /4096 => 131s
581      * With /∞    => gave up after 858s
582      * Of course, ideally we should never call set-buffer-multibyte on
583      * a non-empty buffer (e.g. use buffer-swap-text instead).
584      * We chose /64 because it already brings almost the best performance while
585      * limiting the potential wasted memory to 1.5%.  */
586     make_gap_larger (max (nbytes_added, (Z - BEG) / 64));
587 #if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
588   else
589     make_gap_smaller (-nbytes_added);
590 #endif
591 }
592 
593 /* Add NBYTES to B's gap.  It's enough to temporarily
594    fake current_buffer and avoid real switch to B.  */
595 
596 void
make_gap_1(struct buffer * b,ptrdiff_t nbytes)597 make_gap_1 (struct buffer *b, ptrdiff_t nbytes)
598 {
599   struct buffer *oldb = current_buffer;
600 
601   current_buffer = b;
602   make_gap (nbytes);
603   current_buffer = oldb;
604 }
605 
606 /* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
607    FROM_MULTIBYTE says whether the incoming text is multibyte.
608    TO_MULTIBYTE says whether to store the text as multibyte.
609    If FROM_MULTIBYTE != TO_MULTIBYTE, we convert.
610 
611    Return the number of bytes stored at TO_ADDR.  */
612 
613 ptrdiff_t
copy_text(const unsigned char * from_addr,unsigned char * to_addr,ptrdiff_t nbytes,bool from_multibyte,bool to_multibyte)614 copy_text (const unsigned char *from_addr, unsigned char *to_addr,
615 	   ptrdiff_t nbytes, bool from_multibyte, bool to_multibyte)
616 {
617   if (from_multibyte == to_multibyte)
618     {
619       memcpy (to_addr, from_addr, nbytes);
620       return nbytes;
621     }
622   else if (from_multibyte)
623     {
624       ptrdiff_t nchars = 0;
625       ptrdiff_t bytes_left = nbytes;
626 
627       while (bytes_left > 0)
628 	{
629 	  int thislen, c;
630 	  c = STRING_CHAR_AND_LENGTH (from_addr, thislen);
631 	  if (! ASCII_CHAR_P (c))
632 	    c &= 0xFF;
633 	  *to_addr++ = c;
634 	  from_addr += thislen;
635 	  bytes_left -= thislen;
636 	  nchars++;
637 	}
638       return nchars;
639     }
640   else
641     {
642       unsigned char *initial_to_addr = to_addr;
643 
644       /* Convert single-byte to multibyte.  */
645       while (nbytes > 0)
646 	{
647 	  int c = *from_addr++;
648 
649 	  if (!ASCII_CHAR_P (c))
650 	    {
651 	      c = BYTE8_TO_CHAR (c);
652 	      to_addr += CHAR_STRING (c, to_addr);
653 	      nbytes--;
654 	    }
655 	  else
656 	    /* Special case for speed.  */
657 	    *to_addr++ = c, nbytes--;
658 	}
659       return to_addr - initial_to_addr;
660     }
661 }
662 
663 /* Insert a string of specified length before point.
664    This function judges multibyteness based on
665    enable_multibyte_characters in the current buffer;
666    it never converts between single-byte and multibyte.
667 
668    DO NOT use this for the contents of a Lisp string or a Lisp buffer!
669    prepare_to_modify_buffer could relocate the text.  */
670 
671 void
insert(const char * string,ptrdiff_t nbytes)672 insert (const char *string, ptrdiff_t nbytes)
673 {
674   if (nbytes > 0)
675     {
676       ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
677       insert_1_both (string, len, nbytes, 0, 1, 0);
678       opoint = PT - len;
679       signal_after_change (opoint, 0, len);
680       update_compositions (opoint, PT, CHECK_BORDER);
681     }
682 }
683 
684 /* Likewise, but inherit text properties from neighboring characters.  */
685 
686 void
insert_and_inherit(const char * string,ptrdiff_t nbytes)687 insert_and_inherit (const char *string, ptrdiff_t nbytes)
688 {
689   if (nbytes > 0)
690     {
691       ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
692       insert_1_both (string, len, nbytes, 1, 1, 0);
693       opoint = PT - len;
694       signal_after_change (opoint, 0, len);
695       update_compositions (opoint, PT, CHECK_BORDER);
696     }
697 }
698 
699 /* Insert the character C before point.  Do not inherit text properties.  */
700 
701 void
insert_char(int c)702 insert_char (int c)
703 {
704   unsigned char str[MAX_MULTIBYTE_LENGTH];
705   int len;
706 
707   if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
708     len = CHAR_STRING (c, str);
709   else
710     {
711       len = 1;
712       str[0] = c;
713     }
714 
715   insert ((char *) str, len);
716 }
717 
718 /* Insert the NUL-terminated string S before point.  */
719 
720 void
insert_string(const char * s)721 insert_string (const char *s)
722 {
723   insert (s, strlen (s));
724 }
725 
726 /* Like `insert' except that all markers pointing at the place where
727    the insertion happens are adjusted to point after it.
728    Don't use this function to insert part of a Lisp string,
729    since gc could happen and relocate it.  */
730 
731 void
insert_before_markers(const char * string,ptrdiff_t nbytes)732 insert_before_markers (const char *string, ptrdiff_t nbytes)
733 {
734   if (nbytes > 0)
735     {
736       ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
737       insert_1_both (string, len, nbytes, 0, 1, 1);
738       opoint = PT - len;
739       signal_after_change (opoint, 0, len);
740       update_compositions (opoint, PT, CHECK_BORDER);
741     }
742 }
743 
744 /* Likewise, but inherit text properties from neighboring characters.  */
745 
746 void
insert_before_markers_and_inherit(const char * string,ptrdiff_t nbytes)747 insert_before_markers_and_inherit (const char *string,
748 				   ptrdiff_t nbytes)
749 {
750   if (nbytes > 0)
751     {
752       ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
753       insert_1_both (string, len, nbytes, 1, 1, 1);
754       opoint = PT - len;
755       signal_after_change (opoint, 0, len);
756       update_compositions (opoint, PT, CHECK_BORDER);
757     }
758 }
759 
760 #ifdef BYTE_COMBINING_DEBUG
761 
762 /* See if the bytes before POS/POS_BYTE combine with bytes
763    at the start of STRING to form a single character.
764    If so, return the number of bytes at the start of STRING
765    which combine in this way.  Otherwise, return 0.  */
766 
767 int
count_combining_before(const unsigned char * string,ptrdiff_t length,ptrdiff_t pos,ptrdiff_t pos_byte)768 count_combining_before (const unsigned char *string, ptrdiff_t length,
769 			ptrdiff_t pos, ptrdiff_t pos_byte)
770 {
771   int len, combining_bytes;
772   const unsigned char *p;
773 
774   if (NILP (current_buffer->enable_multibyte_characters))
775     return 0;
776 
777   /* At first, we can exclude the following cases:
778 	(1) STRING[0] can't be a following byte of multibyte sequence.
779 	(2) POS is the start of the current buffer.
780 	(3) A character before POS is not a multibyte character.  */
781   if (length == 0 || CHAR_HEAD_P (*string)) /* case (1) */
782     return 0;
783   if (pos_byte == BEG_BYTE)	/* case (2) */
784     return 0;
785   len = 1;
786   p = BYTE_POS_ADDR (pos_byte - 1);
787   while (! CHAR_HEAD_P (*p)) p--, len++;
788   if (! LEADING_CODE_P (*p)) /* case (3) */
789     return 0;
790 
791   combining_bytes = BYTES_BY_CHAR_HEAD (*p) - len;
792   if (combining_bytes <= 0)
793     /* The character preceding POS is, complete and no room for
794        combining bytes (combining_bytes == 0), or an independent 8-bit
795        character (combining_bytes < 0).  */
796     return 0;
797 
798   /* We have a combination situation.  Count the bytes at STRING that
799      may combine.  */
800   p = string + 1;
801   while (!CHAR_HEAD_P (*p) && p < string + length)
802     p++;
803 
804   return (combining_bytes < p - string ? combining_bytes : p - string);
805 }
806 
807 /* See if the bytes after POS/POS_BYTE combine with bytes
808    at the end of STRING to form a single character.
809    If so, return the number of bytes after POS/POS_BYTE
810    which combine in this way.  Otherwise, return 0.  */
811 
812 int
count_combining_after(const unsigned char * string,ptrdiff_t length,ptrdiff_t pos,ptrdiff_t pos_byte)813 count_combining_after (const unsigned char *string,
814 		       ptrdiff_t length, ptrdiff_t pos, ptrdiff_t pos_byte)
815 {
816   ptrdiff_t opos_byte = pos_byte;
817   ptrdiff_t i;
818   ptrdiff_t bytes;
819   unsigned char *bufp;
820 
821   if (NILP (current_buffer->enable_multibyte_characters))
822     return 0;
823 
824   /* At first, we can exclude the following cases:
825 	(1) The last byte of STRING is an ASCII.
826 	(2) POS is the last of the current buffer.
827 	(3) A character at POS can't be a following byte of multibyte
828 	    character.  */
829   if (length > 0 && ASCII_CHAR_P (string[length - 1])) /* case (1) */
830     return 0;
831   if (pos_byte == Z_BYTE)	/* case (2) */
832     return 0;
833   bufp = BYTE_POS_ADDR (pos_byte);
834   if (CHAR_HEAD_P (*bufp))	/* case (3) */
835     return 0;
836 
837   i = length - 1;
838   while (i >= 0 && ! CHAR_HEAD_P (string[i]))
839     {
840       i--;
841     }
842   if (i < 0)
843     {
844       /* All characters in STRING are not character head.  We must
845 	 check also preceding bytes at POS.  We are sure that the gap
846 	 is at POS.  */
847       unsigned char *p = BEG_ADDR;
848       i = pos_byte - 2;
849       while (i >= 0 && ! CHAR_HEAD_P (p[i]))
850 	i--;
851       if (i < 0 || !LEADING_CODE_P (p[i]))
852 	return 0;
853 
854       bytes = BYTES_BY_CHAR_HEAD (p[i]);
855       return (bytes <= pos_byte - 1 - i + length
856 	      ? 0
857 	      : bytes - (pos_byte - 1 - i + length));
858     }
859   if (!LEADING_CODE_P (string[i]))
860     return 0;
861 
862   bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
863   bufp++, pos_byte++;
864   while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
865 
866   return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
867 }
868 
869 #endif
870 
871 
872 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
873    starting at STRING.  INHERIT non-zero means inherit the text
874    properties from neighboring characters; zero means inserted text
875    will have no text properties.  PREPARE non-zero means call
876    prepare_to_modify_buffer, which checks that the region is not
877    read-only, and calls before-change-function and any modification
878    properties the text may have.  BEFORE_MARKERS non-zero means adjust
879    all markers that point at the insertion place to point after it.  */
880 
881 void
insert_1_both(const char * string,ptrdiff_t nchars,ptrdiff_t nbytes,bool inherit,bool prepare,bool before_markers)882 insert_1_both (const char *string,
883 	       ptrdiff_t nchars, ptrdiff_t nbytes,
884 	       bool inherit, bool prepare, bool before_markers)
885 {
886   if (nchars == 0)
887     return;
888 
889   if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
890     nchars = nbytes;
891 
892   if (prepare)
893     /* Do this before moving and increasing the gap,
894        because the before-change hooks might move the gap
895        or make it smaller.  */
896     prepare_to_modify_buffer (PT, PT, NULL);
897 
898   if (PT != GPT)
899     move_gap_both (PT, PT_BYTE);
900   if (GAP_SIZE < nbytes)
901     make_gap (nbytes - GAP_SIZE);
902 
903 #ifdef BYTE_COMBINING_DEBUG
904   if (count_combining_before (string, nbytes, PT, PT_BYTE)
905       || count_combining_after (string, nbytes, PT, PT_BYTE))
906     emacs_abort ();
907 #endif
908 
909   /* Record deletion of the surrounding text that combines with
910      the insertion.  This, together with recording the insertion,
911      will add up to the right stuff in the undo list.  */
912   record_insert (PT, nchars);
913   modiff_incr (&MODIFF);
914   CHARS_MODIFF = MODIFF;
915 
916   memcpy (GPT_ADDR, string, nbytes);
917 
918   GAP_SIZE -= nbytes;
919   GPT += nchars;
920   ZV += nchars;
921   Z += nchars;
922   GPT_BYTE += nbytes;
923   ZV_BYTE += nbytes;
924   Z_BYTE += nbytes;
925   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
926 
927   eassert (GPT <= GPT_BYTE);
928 
929   /* The insert may have been in the unchanged region, so check again.  */
930   if (Z - GPT < END_UNCHANGED)
931     END_UNCHANGED = Z - GPT;
932 
933   adjust_overlays_for_insert (PT, nchars);
934   adjust_markers_for_insert (PT, PT_BYTE,
935 			     PT + nchars, PT_BYTE + nbytes,
936 			     before_markers);
937 
938   offset_intervals (current_buffer, PT, nchars);
939 
940   if (!inherit && buffer_intervals (current_buffer))
941     set_text_properties (make_fixnum (PT), make_fixnum (PT + nchars),
942 			 Qnil, Qnil, Qnil);
943 
944   adjust_point (nchars, nbytes);
945 
946   check_markers ();
947 }
948 
949 /* Insert the part of the text of STRING, a Lisp object assumed to be
950    of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes)
951    starting at position POS / POS_BYTE.  If the text of STRING has properties,
952    copy them into the buffer.
953 
954    It does not work to use `insert' for this, because a GC could happen
955    before we copy the stuff into the buffer, and relocate the string
956    without insert noticing.  */
957 
958 void
insert_from_string(Lisp_Object string,ptrdiff_t pos,ptrdiff_t pos_byte,ptrdiff_t length,ptrdiff_t length_byte,bool inherit)959 insert_from_string (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
960 		    ptrdiff_t length, ptrdiff_t length_byte, bool inherit)
961 {
962   ptrdiff_t opoint = PT;
963 
964   if (SCHARS (string) == 0)
965     return;
966 
967   insert_from_string_1 (string, pos, pos_byte, length, length_byte,
968 			inherit, 0);
969   signal_after_change (opoint, 0, PT - opoint);
970   update_compositions (opoint, PT, CHECK_BORDER);
971 }
972 
973 /* Like `insert_from_string' except that all markers pointing
974    at the place where the insertion happens are adjusted to point after it.  */
975 
976 void
insert_from_string_before_markers(Lisp_Object string,ptrdiff_t pos,ptrdiff_t pos_byte,ptrdiff_t length,ptrdiff_t length_byte,bool inherit)977 insert_from_string_before_markers (Lisp_Object string,
978 				   ptrdiff_t pos, ptrdiff_t pos_byte,
979 				   ptrdiff_t length, ptrdiff_t length_byte,
980 				   bool inherit)
981 {
982   ptrdiff_t opoint = PT;
983 
984   if (SCHARS (string) == 0)
985     return;
986 
987   insert_from_string_1 (string, pos, pos_byte, length, length_byte,
988 			inherit, 1);
989   signal_after_change (opoint, 0, PT - opoint);
990   update_compositions (opoint, PT, CHECK_BORDER);
991 }
992 
993 /* Subroutine of the insertion functions above.  */
994 
995 static void
insert_from_string_1(Lisp_Object string,ptrdiff_t pos,ptrdiff_t pos_byte,ptrdiff_t nchars,ptrdiff_t nbytes,bool inherit,bool before_markers)996 insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
997 		      ptrdiff_t nchars, ptrdiff_t nbytes,
998 		      bool inherit, bool before_markers)
999 {
1000   ptrdiff_t outgoing_nbytes = nbytes;
1001   INTERVAL intervals;
1002 
1003   /* Make OUTGOING_NBYTES describe the text
1004      as it will be inserted in this buffer.  */
1005 
1006   if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1007     outgoing_nbytes = nchars;
1008   else if (! STRING_MULTIBYTE (string))
1009     outgoing_nbytes
1010       = count_size_as_multibyte (SDATA (string) + pos_byte,
1011 				 nbytes);
1012 
1013   /* Do this before moving and increasing the gap,
1014      because the before-change hooks might move the gap
1015      or make it smaller.  */
1016   prepare_to_modify_buffer (PT, PT, NULL);
1017 
1018   if (PT != GPT)
1019     move_gap_both (PT, PT_BYTE);
1020   if (GAP_SIZE < outgoing_nbytes)
1021     make_gap (outgoing_nbytes - GAP_SIZE);
1022 
1023   /* Copy the string text into the buffer, perhaps converting
1024      between single-byte and multibyte.  */
1025   copy_text (SDATA (string) + pos_byte, GPT_ADDR, nbytes,
1026 	     STRING_MULTIBYTE (string),
1027 	     ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1028 
1029 #ifdef BYTE_COMBINING_DEBUG
1030   /* We have copied text into the gap, but we have not altered
1031      PT or PT_BYTE yet.  So we can pass PT and PT_BYTE
1032      to these functions and get the same results as we would
1033      have got earlier on.  Meanwhile, PT_ADDR does point to
1034      the text that has been stored by copy_text.  */
1035   if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
1036       || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
1037     emacs_abort ();
1038 #endif
1039 
1040   record_insert (PT, nchars);
1041   modiff_incr (&MODIFF);
1042   CHARS_MODIFF = MODIFF;
1043 
1044   GAP_SIZE -= outgoing_nbytes;
1045   GPT += nchars;
1046   ZV += nchars;
1047   Z += nchars;
1048   GPT_BYTE += outgoing_nbytes;
1049   ZV_BYTE += outgoing_nbytes;
1050   Z_BYTE += outgoing_nbytes;
1051   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1052 
1053   eassert (GPT <= GPT_BYTE);
1054 
1055   /* The insert may have been in the unchanged region, so check again.  */
1056   if (Z - GPT < END_UNCHANGED)
1057     END_UNCHANGED = Z - GPT;
1058 
1059   adjust_overlays_for_insert (PT, nchars);
1060   adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
1061 			     PT_BYTE + outgoing_nbytes,
1062 			     before_markers);
1063 
1064   offset_intervals (current_buffer, PT, nchars);
1065 
1066   intervals = string_intervals (string);
1067   /* Get the intervals for the part of the string we are inserting.  */
1068   if (nbytes < SBYTES (string))
1069     intervals = copy_intervals (intervals, pos, nchars);
1070 
1071   /* Insert those intervals.  */
1072   graft_intervals_into_buffer (intervals, PT, nchars,
1073 			       current_buffer, inherit);
1074 
1075   adjust_point (nchars, outgoing_nbytes);
1076 
1077   check_markers ();
1078 }
1079 
1080 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
1081    starting at GAP_END_ADDR - NBYTES (if text_at_gap_tail) and at
1082    GPT_ADDR (if not text_at_gap_tail).
1083    Contrary to insert_from_gap, this does not invalidate any cache,
1084    nor update any markers, nor record any buffer modification information
1085    of any sort.  */
1086 void
insert_from_gap_1(ptrdiff_t nchars,ptrdiff_t nbytes,bool text_at_gap_tail)1087 insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
1088 {
1089   eassert (NILP (BVAR (current_buffer, enable_multibyte_characters))
1090            ? nchars == nbytes : nchars <= nbytes);
1091 
1092   GAP_SIZE -= nbytes;
1093   if (! text_at_gap_tail)
1094     {
1095       GPT += nchars;
1096       GPT_BYTE += nbytes;
1097     }
1098   ZV += nchars;
1099   Z += nchars;
1100   ZV_BYTE += nbytes;
1101   Z_BYTE += nbytes;
1102 
1103   /* Put an anchor to ensure multi-byte form ends at gap.  */
1104   if (GAP_SIZE > 0) *(GPT_ADDR) = 0;
1105   eassert (GPT <= GPT_BYTE);
1106 }
1107 
1108 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
1109    starting at GAP_END_ADDR - NBYTES (if text_at_gap_tail) and at
1110    GPT_ADDR (if not text_at_gap_tail).  */
1111 
1112 void
insert_from_gap(ptrdiff_t nchars,ptrdiff_t nbytes,bool text_at_gap_tail)1113 insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
1114 {
1115   ptrdiff_t ins_charpos = GPT, ins_bytepos = GPT_BYTE;
1116 
1117   if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1118     nchars = nbytes;
1119 
1120   /* No need to call prepare_to_modify_buffer, since this is called
1121      from places that replace some region with a different text, so
1122      prepare_to_modify_buffer was already called by the deletion part
1123      of this dance.  */
1124   invalidate_buffer_caches (current_buffer, GPT, GPT);
1125   record_insert (GPT, nchars);
1126   modiff_incr (&MODIFF);
1127 
1128   insert_from_gap_1 (nchars, nbytes, text_at_gap_tail);
1129 
1130   adjust_overlays_for_insert (ins_charpos, nchars);
1131   adjust_markers_for_insert (ins_charpos, ins_bytepos,
1132 			     ins_charpos + nchars, ins_bytepos + nbytes, 0);
1133 
1134   if (buffer_intervals (current_buffer))
1135     {
1136       offset_intervals (current_buffer, ins_charpos, nchars);
1137       graft_intervals_into_buffer (NULL, ins_charpos, nchars,
1138 				   current_buffer, 0);
1139     }
1140 
1141   if (ins_charpos < PT)
1142     adjust_point (nchars, nbytes);
1143 
1144   check_markers ();
1145 }
1146 
1147 /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
1148    current buffer.  If the text in BUF has properties, they are absorbed
1149    into the current buffer.
1150 
1151    It does not work to use `insert' for this, because a malloc could happen
1152    and relocate BUF's text before the copy happens.  */
1153 
1154 void
insert_from_buffer(struct buffer * buf,ptrdiff_t charpos,ptrdiff_t nchars,bool inherit)1155 insert_from_buffer (struct buffer *buf,
1156 		    ptrdiff_t charpos, ptrdiff_t nchars, bool inherit)
1157 {
1158   ptrdiff_t opoint = PT;
1159 
1160   insert_from_buffer_1 (buf, charpos, nchars, inherit);
1161   signal_after_change (opoint, 0, PT - opoint);
1162   update_compositions (opoint, PT, CHECK_BORDER);
1163 }
1164 
1165 static void
insert_from_buffer_1(struct buffer * buf,ptrdiff_t from,ptrdiff_t nchars,bool inherit)1166 insert_from_buffer_1 (struct buffer *buf,
1167 		      ptrdiff_t from, ptrdiff_t nchars, bool inherit)
1168 {
1169   ptrdiff_t chunk, chunk_expanded;
1170   ptrdiff_t from_byte = buf_charpos_to_bytepos (buf, from);
1171   ptrdiff_t to_byte = buf_charpos_to_bytepos (buf, from + nchars);
1172   ptrdiff_t incoming_nbytes = to_byte - from_byte;
1173   ptrdiff_t outgoing_nbytes = incoming_nbytes;
1174   INTERVAL intervals;
1175 
1176   if (nchars == 0)
1177     return;
1178 
1179   /* Make OUTGOING_NBYTES describe the text
1180      as it will be inserted in this buffer.  */
1181 
1182   if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1183     outgoing_nbytes = nchars;
1184   else if (NILP (BVAR (buf, enable_multibyte_characters)))
1185     {
1186       ptrdiff_t outgoing_before_gap = 0;
1187       ptrdiff_t outgoing_after_gap = 0;
1188 
1189       if (from < BUF_GPT (buf))
1190 	{
1191 	  chunk =  BUF_GPT_BYTE (buf) - from_byte;
1192 	  if (chunk > incoming_nbytes)
1193 	    chunk = incoming_nbytes;
1194 	  outgoing_before_gap
1195 	    = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
1196 				       chunk);
1197 	}
1198       else
1199 	chunk = 0;
1200 
1201       if (chunk < incoming_nbytes)
1202 	outgoing_after_gap
1203 	  = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf,
1204 						       from_byte + chunk),
1205 				     incoming_nbytes - chunk);
1206 
1207       outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
1208     }
1209 
1210   /* Do this before moving and increasing the gap,
1211      because the before-change hooks might move the gap
1212      or make it smaller.  */
1213   prepare_to_modify_buffer (PT, PT, NULL);
1214 
1215   if (PT != GPT)
1216     move_gap_both (PT, PT_BYTE);
1217   if (GAP_SIZE < outgoing_nbytes)
1218     make_gap (outgoing_nbytes - GAP_SIZE);
1219 
1220   if (from < BUF_GPT (buf))
1221     {
1222       chunk = BUF_GPT_BYTE (buf) - from_byte;
1223       if (chunk > incoming_nbytes)
1224 	chunk = incoming_nbytes;
1225       /* Record number of output bytes, so we know where
1226 	 to put the output from the second copy_text.  */
1227       chunk_expanded
1228 	= copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
1229 		     GPT_ADDR, chunk,
1230 		     ! NILP (BVAR (buf, enable_multibyte_characters)),
1231 		     ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1232     }
1233   else
1234     chunk_expanded = chunk = 0;
1235 
1236   if (chunk < incoming_nbytes)
1237     copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
1238 	       GPT_ADDR + chunk_expanded, incoming_nbytes - chunk,
1239 	       ! NILP (BVAR (buf, enable_multibyte_characters)),
1240 	       ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1241 
1242 #ifdef BYTE_COMBINING_DEBUG
1243   /* We have copied text into the gap, but we have not altered
1244      PT or PT_BYTE yet.  So we can pass PT and PT_BYTE
1245      to these functions and get the same results as we would
1246      have got earlier on.  Meanwhile, GPT_ADDR does point to
1247      the text that has been stored by copy_text.  */
1248   if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
1249       || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
1250     emacs_abort ();
1251 #endif
1252 
1253   record_insert (PT, nchars);
1254   modiff_incr (&MODIFF);
1255   CHARS_MODIFF = MODIFF;
1256 
1257   GAP_SIZE -= outgoing_nbytes;
1258   GPT += nchars;
1259   ZV += nchars;
1260   Z += nchars;
1261   GPT_BYTE += outgoing_nbytes;
1262   ZV_BYTE += outgoing_nbytes;
1263   Z_BYTE += outgoing_nbytes;
1264   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1265 
1266   eassert (GPT <= GPT_BYTE);
1267 
1268   /* The insert may have been in the unchanged region, so check again.  */
1269   if (Z - GPT < END_UNCHANGED)
1270     END_UNCHANGED = Z - GPT;
1271 
1272   adjust_overlays_for_insert (PT, nchars);
1273   adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
1274 			     PT_BYTE + outgoing_nbytes,
1275 			     0);
1276 
1277   offset_intervals (current_buffer, PT, nchars);
1278 
1279   /* Get the intervals for the part of the string we are inserting.  */
1280   intervals = buffer_intervals (buf);
1281   if (nchars < BUF_Z (buf) - BUF_BEG (buf))
1282     {
1283       if (buf == current_buffer && PT <= from)
1284 	from += nchars;
1285       intervals = copy_intervals (intervals, from, nchars);
1286     }
1287 
1288   /* Insert those intervals.  */
1289   graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
1290 
1291   adjust_point (nchars, outgoing_nbytes);
1292 }
1293 
1294 /* Record undo information and adjust markers and position keepers for
1295    a replacement of a text PREV_TEXT at FROM to a new text of LEN
1296    chars (LEN_BYTE bytes) which resides in the gap just after
1297    GPT_ADDR.
1298 
1299    PREV_TEXT nil means the new text was just inserted.  */
1300 
1301 static void
adjust_after_replace(ptrdiff_t from,ptrdiff_t from_byte,Lisp_Object prev_text,ptrdiff_t len,ptrdiff_t len_byte)1302 adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
1303 		      Lisp_Object prev_text, ptrdiff_t len, ptrdiff_t len_byte)
1304 {
1305   ptrdiff_t nchars_del = 0, nbytes_del = 0;
1306 
1307 #ifdef BYTE_COMBINING_DEBUG
1308   if (count_combining_before (GPT_ADDR, len_byte, from, from_byte)
1309       || count_combining_after (GPT_ADDR, len_byte, from, from_byte))
1310     emacs_abort ();
1311 #endif
1312 
1313   if (STRINGP (prev_text))
1314     {
1315       nchars_del = SCHARS (prev_text);
1316       nbytes_del = SBYTES (prev_text);
1317     }
1318 
1319   /* Update various buffer positions for the new text.  */
1320   GAP_SIZE -= len_byte;
1321   ZV += len; Z += len;
1322   ZV_BYTE += len_byte; Z_BYTE += len_byte;
1323   GPT += len; GPT_BYTE += len_byte;
1324   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1325 
1326   if (nchars_del > 0)
1327     adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1328 				len, len_byte);
1329   else
1330     adjust_markers_for_insert (from, from_byte,
1331 			       from + len, from_byte + len_byte, 0);
1332 
1333   if (nchars_del > 0)
1334     record_delete (from, prev_text, false);
1335   record_insert (from, len);
1336 
1337   if (len > nchars_del)
1338     adjust_overlays_for_insert (from, len - nchars_del);
1339   else if (len < nchars_del)
1340     adjust_overlays_for_delete (from, nchars_del - len);
1341 
1342   offset_intervals (current_buffer, from, len - nchars_del);
1343 
1344   if (from < PT)
1345     adjust_point (len - nchars_del, len_byte - nbytes_del);
1346 
1347   /* As byte combining will decrease Z, we must check this again.  */
1348   if (Z - GPT < END_UNCHANGED)
1349     END_UNCHANGED = Z - GPT;
1350 
1351   check_markers ();
1352 
1353   if (len == 0)
1354     evaporate_overlays (from);
1355   modiff_incr (&MODIFF);
1356   CHARS_MODIFF = MODIFF;
1357 }
1358 
1359 /* Record undo information, adjust markers and position keepers for an
1360    insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE).  The
1361    text already exists in the current buffer but character length (TO
1362    - FROM) may be incorrect, the correct length is NEWLEN.  */
1363 
1364 void
adjust_after_insert(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,ptrdiff_t newlen)1365 adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1366 		     ptrdiff_t to, ptrdiff_t to_byte, ptrdiff_t newlen)
1367 {
1368   ptrdiff_t len = to - from, len_byte = to_byte - from_byte;
1369 
1370   if (GPT != to)
1371     move_gap_both (to, to_byte);
1372   GAP_SIZE += len_byte;
1373   GPT -= len; GPT_BYTE -= len_byte;
1374   ZV -= len; ZV_BYTE -= len_byte;
1375   Z -= len; Z_BYTE -= len_byte;
1376   adjust_after_replace (from, from_byte, Qnil, newlen, len_byte);
1377 }
1378 
1379 /* Replace the text from character positions FROM to TO with NEW,
1380    If PREPARE, call prepare_to_modify_buffer.
1381    If INHERIT, the newly inserted text should inherit text properties
1382    from the surrounding non-deleted text.
1383    If ADJUST_MATCH_DATA, then adjust the match data before calling
1384    signal_after_change.  */
1385 
1386 /* Note that this does not yet handle markers quite right.
1387    Also it needs to record a single undo-entry that does a replacement
1388    rather than a separate delete and insert.
1389    That way, undo will also handle markers properly.
1390 
1391    But if MARKERS is 0, don't relocate markers.  */
1392 
1393 void
replace_range(ptrdiff_t from,ptrdiff_t to,Lisp_Object new,bool prepare,bool inherit,bool markers,bool adjust_match_data)1394 replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1395                bool prepare, bool inherit, bool markers,
1396                bool adjust_match_data)
1397 {
1398   ptrdiff_t inschars = SCHARS (new);
1399   ptrdiff_t insbytes = SBYTES (new);
1400   ptrdiff_t from_byte, to_byte;
1401   ptrdiff_t nbytes_del, nchars_del;
1402   INTERVAL intervals;
1403   ptrdiff_t outgoing_insbytes = insbytes;
1404   Lisp_Object deletion;
1405 
1406   check_markers ();
1407 
1408   deletion = Qnil;
1409 
1410   if (prepare)
1411     {
1412       ptrdiff_t range_length = to - from;
1413       prepare_to_modify_buffer (from, to, &from);
1414       to = from + range_length;
1415     }
1416 
1417   /* Make args be valid.  */
1418   if (from < BEGV)
1419     from = BEGV;
1420   if (to > ZV)
1421     to = ZV;
1422 
1423   from_byte = CHAR_TO_BYTE (from);
1424   to_byte = CHAR_TO_BYTE (to);
1425 
1426   nchars_del = to - from;
1427   nbytes_del = to_byte - from_byte;
1428 
1429   if (nbytes_del <= 0 && insbytes == 0)
1430     return;
1431 
1432   /* Make OUTGOING_INSBYTES describe the text
1433      as it will be inserted in this buffer.  */
1434 
1435   if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1436     outgoing_insbytes = inschars;
1437   else if (! STRING_MULTIBYTE (new))
1438     outgoing_insbytes
1439       = count_size_as_multibyte (SDATA (new), insbytes);
1440 
1441   /* Make sure the gap is somewhere in or next to what we are deleting.  */
1442   if (from > GPT)
1443     gap_right (from, from_byte);
1444   if (to < GPT)
1445     gap_left (to, to_byte, 0);
1446 
1447   /* Even if we don't record for undo, we must keep the original text
1448      because we may have to recover it because of inappropriate byte
1449      combining.  */
1450   if (! EQ (BVAR (current_buffer, undo_list), Qt))
1451     deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
1452 
1453   GAP_SIZE += nbytes_del;
1454   ZV -= nchars_del;
1455   Z -= nchars_del;
1456   ZV_BYTE -= nbytes_del;
1457   Z_BYTE -= nbytes_del;
1458   GPT = from;
1459   GPT_BYTE = from_byte;
1460   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1461 
1462   eassert (GPT <= GPT_BYTE);
1463 
1464   if (GPT - BEG < BEG_UNCHANGED)
1465     BEG_UNCHANGED = GPT - BEG;
1466   if (Z - GPT < END_UNCHANGED)
1467     END_UNCHANGED = Z - GPT;
1468 
1469   if (GAP_SIZE < outgoing_insbytes)
1470     make_gap (outgoing_insbytes - GAP_SIZE);
1471 
1472   /* Copy the string text into the buffer, perhaps converting
1473      between single-byte and multibyte.  */
1474   copy_text (SDATA (new), GPT_ADDR, insbytes,
1475 	     STRING_MULTIBYTE (new),
1476 	     ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1477 
1478 #ifdef BYTE_COMBINING_DEBUG
1479   /* We have copied text into the gap, but we have not marked
1480      it as part of the buffer.  So we can use the old FROM and FROM_BYTE
1481      here, for both the previous text and the following text.
1482      Meanwhile, GPT_ADDR does point to
1483      the text that has been stored by copy_text.  */
1484   if (count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte)
1485       || count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte))
1486     emacs_abort ();
1487 #endif
1488 
1489   /* Record the insertion first, so that when we undo,
1490      the deletion will be undone first.  Thus, undo
1491      will insert before deleting, and thus will keep
1492      the markers before and after this text separate.  */
1493   if (!NILP (deletion))
1494     {
1495       record_insert (from + SCHARS (deletion), inschars);
1496       record_delete (from, deletion, false);
1497     }
1498 
1499   GAP_SIZE -= outgoing_insbytes;
1500   GPT += inschars;
1501   ZV += inschars;
1502   Z += inschars;
1503   GPT_BYTE += outgoing_insbytes;
1504   ZV_BYTE += outgoing_insbytes;
1505   Z_BYTE += outgoing_insbytes;
1506   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1507 
1508   eassert (GPT <= GPT_BYTE);
1509 
1510   /* Adjust markers for the deletion and the insertion.  */
1511   if (markers)
1512     adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1513 				inschars, outgoing_insbytes);
1514   else
1515     {
1516       /* The character positions of the markers remain intact, but we
1517 	 still need to update their byte positions, because the
1518 	 deleted and the inserted text might have multibyte sequences
1519 	 which make the original byte positions of the markers
1520 	 invalid.  */
1521       adjust_markers_bytepos (from, from_byte, from + inschars,
1522 			      from_byte + outgoing_insbytes, 1);
1523     }
1524 
1525   /* Adjust the overlay center as needed.  This must be done after
1526      adjusting the markers that bound the overlays.  */
1527   adjust_overlays_for_delete (from, nchars_del);
1528   adjust_overlays_for_insert (from, inschars);
1529 
1530   offset_intervals (current_buffer, from, inschars - nchars_del);
1531 
1532   /* Get the intervals for the part of the string we are inserting--
1533      not including the combined-before bytes.  */
1534   intervals = string_intervals (new);
1535   /* Insert those intervals.  */
1536   graft_intervals_into_buffer (intervals, from, inschars,
1537 			       current_buffer, inherit);
1538 
1539   /* Relocate point as if it were a marker.  */
1540   if (from < PT)
1541     adjust_point ((from + inschars - (PT < to ? PT : to)),
1542 		  (from_byte + outgoing_insbytes
1543 		   - (PT_BYTE < to_byte ? PT_BYTE : to_byte)));
1544 
1545   if (outgoing_insbytes == 0)
1546     evaporate_overlays (from);
1547 
1548   check_markers ();
1549 
1550   modiff_incr (&MODIFF);
1551   CHARS_MODIFF = MODIFF;
1552 
1553   if (adjust_match_data)
1554     update_search_regs (from, to, from + SCHARS (new));
1555 
1556   signal_after_change (from, nchars_del, GPT - from);
1557   update_compositions (from, GPT, CHECK_BORDER);
1558 }
1559 
1560 /* Replace the text from character positions FROM to TO with
1561    the text in INS of length INSCHARS.
1562    Keep the text properties that applied to the old characters
1563    (extending them to all the new chars if there are more new chars).
1564 
1565    Note that this does not yet handle markers quite right.
1566 
1567    If MARKERS, relocate markers.
1568 
1569    Unlike most functions at this level, never call
1570    prepare_to_modify_buffer and never call signal_after_change.  */
1571 
1572 void
replace_range_2(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,const char * ins,ptrdiff_t inschars,ptrdiff_t insbytes,bool markers)1573 replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
1574 		 ptrdiff_t to, ptrdiff_t to_byte,
1575 		 const char *ins, ptrdiff_t inschars, ptrdiff_t insbytes,
1576 		 bool markers)
1577 {
1578   ptrdiff_t nbytes_del, nchars_del;
1579 
1580   check_markers ();
1581 
1582   nchars_del = to - from;
1583   nbytes_del = to_byte - from_byte;
1584 
1585   if (nbytes_del <= 0 && insbytes == 0)
1586     return;
1587 
1588   /* Make sure the gap is somewhere in or next to what we are deleting.  */
1589   if (from > GPT)
1590     gap_right (from, from_byte);
1591   if (to < GPT)
1592     gap_left (to, to_byte, 0);
1593 
1594   GAP_SIZE += nbytes_del;
1595   ZV -= nchars_del;
1596   Z -= nchars_del;
1597   ZV_BYTE -= nbytes_del;
1598   Z_BYTE -= nbytes_del;
1599   GPT = from;
1600   GPT_BYTE = from_byte;
1601   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1602 
1603   eassert (GPT <= GPT_BYTE);
1604 
1605   if (GPT - BEG < BEG_UNCHANGED)
1606     BEG_UNCHANGED = GPT - BEG;
1607   if (Z - GPT < END_UNCHANGED)
1608     END_UNCHANGED = Z - GPT;
1609 
1610   if (GAP_SIZE < insbytes)
1611     make_gap (insbytes - GAP_SIZE);
1612 
1613   /* Copy the replacement text into the buffer.  */
1614   memcpy (GPT_ADDR, ins, insbytes);
1615 
1616 #ifdef BYTE_COMBINING_DEBUG
1617   /* We have copied text into the gap, but we have not marked
1618      it as part of the buffer.  So we can use the old FROM and FROM_BYTE
1619      here, for both the previous text and the following text.
1620      Meanwhile, GPT_ADDR does point to
1621      the text that has been stored by copy_text.  */
1622   if (count_combining_before (GPT_ADDR, insbytes, from, from_byte)
1623       || count_combining_after (GPT_ADDR, insbytes, from, from_byte))
1624     emacs_abort ();
1625 #endif
1626 
1627   GAP_SIZE -= insbytes;
1628   GPT += inschars;
1629   ZV += inschars;
1630   Z += inschars;
1631   GPT_BYTE += insbytes;
1632   ZV_BYTE += insbytes;
1633   Z_BYTE += insbytes;
1634   if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
1635 
1636   eassert (GPT <= GPT_BYTE);
1637 
1638   /* Adjust markers for the deletion and the insertion.  */
1639   if (! (nchars_del == 1 && inschars == 1 && nbytes_del == insbytes))
1640     {
1641       if (markers)
1642 	adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1643 				    inschars, insbytes);
1644       else
1645 	{
1646 	  /* The character positions of the markers remain intact, but
1647 	     we still need to update their byte positions, because the
1648 	     deleted and the inserted text might have multibyte
1649 	     sequences which make the original byte positions of the
1650 	     markers invalid.  */
1651 	  adjust_markers_bytepos (from, from_byte, from + inschars,
1652 				  from_byte + insbytes, 1);
1653 	}
1654     }
1655 
1656   /* Adjust the overlay center as needed.  This must be done after
1657      adjusting the markers that bound the overlays.  */
1658   if (nchars_del != inschars)
1659     {
1660       adjust_overlays_for_insert (from, inschars);
1661       adjust_overlays_for_delete (from + inschars, nchars_del);
1662     }
1663 
1664   offset_intervals (current_buffer, from, inschars - nchars_del);
1665 
1666   /* Relocate point as if it were a marker.  */
1667   if (from < PT && (nchars_del != inschars || nbytes_del != insbytes))
1668     {
1669       if (PT < to)
1670 	/* PT was within the deleted text.  Move it to FROM.  */
1671 	adjust_point (from - PT, from_byte - PT_BYTE);
1672       else
1673 	adjust_point (inschars - nchars_del, insbytes - nbytes_del);
1674     }
1675 
1676   if (insbytes == 0)
1677     evaporate_overlays (from);
1678 
1679   check_markers ();
1680 
1681   modiff_incr (&MODIFF);
1682   CHARS_MODIFF = MODIFF;
1683 }
1684 
1685 /* Delete characters in current buffer
1686    from FROM up to (but not including) TO.
1687    If TO comes before FROM, we delete nothing.  */
1688 
1689 void
del_range(ptrdiff_t from,ptrdiff_t to)1690 del_range (ptrdiff_t from, ptrdiff_t to)
1691 {
1692   del_range_1 (from, to, 1, 0);
1693 }
1694 
1695 /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
1696    RET_STRING says to return the deleted text. */
1697 
1698 Lisp_Object
del_range_1(ptrdiff_t from,ptrdiff_t to,bool prepare,bool ret_string)1699 del_range_1 (ptrdiff_t from, ptrdiff_t to, bool prepare, bool ret_string)
1700 {
1701   ptrdiff_t from_byte, to_byte;
1702   Lisp_Object deletion;
1703 
1704   /* Make args be valid */
1705   if (from < BEGV)
1706     from = BEGV;
1707   if (to > ZV)
1708     to = ZV;
1709 
1710   if (to <= from)
1711     return Qnil;
1712 
1713   if (prepare)
1714     {
1715       ptrdiff_t range_length = to - from;
1716       prepare_to_modify_buffer (from, to, &from);
1717       to = min (ZV, from + range_length);
1718     }
1719 
1720   from_byte = CHAR_TO_BYTE (from);
1721   to_byte = CHAR_TO_BYTE (to);
1722 
1723   deletion = del_range_2 (from, from_byte, to, to_byte, ret_string);
1724   signal_after_change (from, to - from, 0);
1725   update_compositions (from, from, CHECK_HEAD);
1726   return deletion;
1727 }
1728 
1729 /* Like del_range_1 but args are byte positions, not char positions.  */
1730 
1731 void
del_range_byte(ptrdiff_t from_byte,ptrdiff_t to_byte)1732 del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte)
1733 {
1734   ptrdiff_t from, to;
1735 
1736   /* Make args be valid.  */
1737   if (from_byte < BEGV_BYTE)
1738     from_byte = BEGV_BYTE;
1739   if (to_byte > ZV_BYTE)
1740     to_byte = ZV_BYTE;
1741 
1742   if (to_byte <= from_byte)
1743     return;
1744 
1745   from = BYTE_TO_CHAR (from_byte);
1746   to = BYTE_TO_CHAR (to_byte);
1747 
1748   {
1749     ptrdiff_t old_from = from, old_to = Z - to;
1750     ptrdiff_t range_length = to - from;
1751     prepare_to_modify_buffer (from, to, &from);
1752     to = from + range_length;
1753 
1754     if (old_from != from)
1755       from_byte = CHAR_TO_BYTE (from);
1756     if (to > ZV)
1757       {
1758 	to = ZV;
1759 	to_byte = ZV_BYTE;
1760       }
1761     else if (old_to == Z - to)
1762       to_byte = CHAR_TO_BYTE (to);
1763   }
1764 
1765   del_range_2 (from, from_byte, to, to_byte, 0);
1766   signal_after_change (from, to - from, 0);
1767   update_compositions (from, from, CHECK_HEAD);
1768 }
1769 
1770 /* Like del_range_1, but positions are specified both as charpos
1771    and bytepos.  */
1772 
1773 void
del_range_both(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,bool prepare)1774 del_range_both (ptrdiff_t from, ptrdiff_t from_byte,
1775 		ptrdiff_t to, ptrdiff_t to_byte, bool prepare)
1776 {
1777   /* Make args be valid */
1778   if (from_byte < BEGV_BYTE)
1779     from_byte = BEGV_BYTE;
1780   if (to_byte > ZV_BYTE)
1781     to_byte = ZV_BYTE;
1782 
1783   if (to_byte <= from_byte)
1784     return;
1785 
1786   if (from < BEGV)
1787     from = BEGV;
1788   if (to > ZV)
1789     to = ZV;
1790 
1791   if (prepare)
1792     {
1793       ptrdiff_t old_from = from, old_to = Z - to;
1794       ptrdiff_t range_length = to - from;
1795       prepare_to_modify_buffer (from, to, &from);
1796       to = from + range_length;
1797 
1798       if (old_from != from)
1799 	from_byte = CHAR_TO_BYTE (from);
1800       if (to > ZV)
1801 	{
1802 	  to = ZV;
1803 	  to_byte = ZV_BYTE;
1804 	}
1805       else if (old_to == Z - to)
1806 	to_byte = CHAR_TO_BYTE (to);
1807     }
1808 
1809   del_range_2 (from, from_byte, to, to_byte, 0);
1810   signal_after_change (from, to - from, 0);
1811   update_compositions (from, from, CHECK_HEAD);
1812 }
1813 
1814 /* Delete a range of text, specified both as character positions
1815    and byte positions.  FROM and TO are character positions,
1816    while FROM_BYTE and TO_BYTE are byte positions.
1817    If RET_STRING, the deleted area is returned as a string.  */
1818 
1819 Lisp_Object
del_range_2(ptrdiff_t from,ptrdiff_t from_byte,ptrdiff_t to,ptrdiff_t to_byte,bool ret_string)1820 del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
1821 	     ptrdiff_t to, ptrdiff_t to_byte, bool ret_string)
1822 {
1823   ptrdiff_t nbytes_del, nchars_del;
1824   Lisp_Object deletion;
1825 
1826   check_markers ();
1827 
1828   nchars_del = to - from;
1829   nbytes_del = to_byte - from_byte;
1830 
1831   /* Make sure the gap is somewhere in or next to what we are deleting.  */
1832   if (from > GPT)
1833     gap_right (from, from_byte);
1834   if (to < GPT)
1835     gap_left (to, to_byte, 0);
1836 
1837 #ifdef BYTE_COMBINING_DEBUG
1838   if (count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
1839 			      Z_BYTE - to_byte, from, from_byte))
1840     emacs_abort ();
1841 #endif
1842 
1843   if (ret_string || ! EQ (BVAR (current_buffer, undo_list), Qt))
1844     deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
1845   else
1846     deletion = Qnil;
1847 
1848   /* Record marker adjustments, and text deletion into undo
1849      history.  */
1850   record_delete (from, deletion, true);
1851 
1852   /* Relocate all markers pointing into the new, larger gap to point
1853      at the end of the text before the gap.  */
1854   adjust_markers_for_delete (from, from_byte, to, to_byte);
1855 
1856   modiff_incr (&MODIFF);
1857   CHARS_MODIFF = MODIFF;
1858 
1859   /* Relocate point as if it were a marker.  */
1860   if (from < PT)
1861     adjust_point (from - (PT < to ? PT : to),
1862 		  from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte));
1863 
1864   offset_intervals (current_buffer, from, - nchars_del);
1865 
1866   /* Adjust the overlay center as needed.  This must be done after
1867      adjusting the markers that bound the overlays.  */
1868   adjust_overlays_for_delete (from, nchars_del);
1869 
1870   GAP_SIZE += nbytes_del;
1871   ZV_BYTE -= nbytes_del;
1872   Z_BYTE -= nbytes_del;
1873   ZV -= nchars_del;
1874   Z -= nchars_del;
1875   GPT = from;
1876   GPT_BYTE = from_byte;
1877   if (GAP_SIZE > 0 && !current_buffer->text->inhibit_shrinking)
1878     /* Put an anchor, unless called from decode_coding_object which
1879        needs to access the previous gap contents.  */
1880     *(GPT_ADDR) = 0;
1881 
1882   eassert (GPT <= GPT_BYTE);
1883 
1884   if (GPT - BEG < BEG_UNCHANGED)
1885     BEG_UNCHANGED = GPT - BEG;
1886   if (Z - GPT < END_UNCHANGED)
1887     END_UNCHANGED = Z - GPT;
1888 
1889   check_markers ();
1890 
1891   evaporate_overlays (from);
1892 
1893   return deletion;
1894 }
1895 
1896 /* Call this if you're about to change the text of current buffer
1897    from character positions START to END.  This checks the read-only
1898    properties of the region, calls the necessary modification hooks,
1899    and warns the next redisplay that it should pay attention to that
1900    area.  */
1901 
1902 void
modify_text(ptrdiff_t start,ptrdiff_t end)1903 modify_text (ptrdiff_t start, ptrdiff_t end)
1904 {
1905   prepare_to_modify_buffer (start, end, NULL);
1906 
1907   BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end);
1908   if (MODIFF <= SAVE_MODIFF)
1909     record_first_change ();
1910   modiff_incr (&MODIFF);
1911   CHARS_MODIFF = MODIFF;
1912 
1913   bset_point_before_scroll (current_buffer, Qnil);
1914 }
1915 
1916 /* Signal that we are about to make a change that may result in new
1917    undo information.
1918  */
1919 static void
run_undoable_change(void)1920 run_undoable_change (void)
1921 {
1922   if (EQ (BVAR (current_buffer, undo_list), Qt))
1923     return;
1924 
1925   call0 (Qundo_auto__undoable_change);
1926 }
1927 
1928 /* Check that it is okay to modify the buffer between START and END,
1929    which are char positions.
1930 
1931    Run the before-change-function, if any.  If intervals are in use,
1932    verify that the text to be modified is not read-only, and call
1933    any modification properties the text may have.
1934 
1935    If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1936    by holding its value temporarily in a marker.
1937 
1938    This function runs Lisp, which means it can GC, which means it can
1939    compact buffers, including the current buffer being worked on here.
1940    So don't you dare calling this function while manipulating the gap,
1941    or during some other similar "critical section".  */
1942 
1943 void
prepare_to_modify_buffer_1(ptrdiff_t start,ptrdiff_t end,ptrdiff_t * preserve_ptr)1944 prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end,
1945 			    ptrdiff_t *preserve_ptr)
1946 {
1947   struct buffer *base_buffer;
1948   Lisp_Object temp;
1949 
1950   XSETFASTINT (temp, start);
1951   if (!NILP (BVAR (current_buffer, read_only)))
1952     Fbarf_if_buffer_read_only (temp);
1953 
1954   /* If we're about to modify a buffer the contents of which come from
1955      a dump file, copy the contents to private storage first so we
1956      don't take a COW fault on the buffer text and keep it around
1957      forever.  */
1958   if (pdumper_object_p (BEG_ADDR))
1959     enlarge_buffer_text (current_buffer, 0);
1960   eassert (!pdumper_object_p (BEG_ADDR));
1961 
1962   run_undoable_change();
1963 
1964   bset_redisplay (current_buffer);
1965 
1966   if (buffer_intervals (current_buffer))
1967     {
1968       if (preserve_ptr)
1969 	{
1970 	  Lisp_Object preserve_marker;
1971 	  preserve_marker = Fcopy_marker (make_fixnum (*preserve_ptr), Qnil);
1972 	  verify_interval_modification (current_buffer, start, end);
1973 	  *preserve_ptr = marker_position (preserve_marker);
1974 	  unchain_marker (XMARKER (preserve_marker));
1975 	}
1976       else
1977 	verify_interval_modification (current_buffer, start, end);
1978     }
1979 
1980   /* For indirect buffers, use the base buffer to check clashes.  */
1981   if (current_buffer->base_buffer != 0)
1982     base_buffer = current_buffer->base_buffer;
1983   else
1984     base_buffer = current_buffer;
1985 
1986   if (inhibit_modification_hooks)
1987     return;
1988 
1989   if (!NILP (BVAR (base_buffer, file_truename))
1990       /* Make binding buffer-file-name to nil effective.  */
1991       && !NILP (BVAR (base_buffer, filename))
1992       && SAVE_MODIFF >= MODIFF)
1993     lock_file (BVAR (base_buffer, file_truename));
1994 
1995   /* If `select-active-regions' is non-nil, save the region text.  */
1996   /* FIXME: Move this to Elisp (via before-change-functions).  */
1997   if (!NILP (BVAR (current_buffer, mark_active))
1998       && XMARKER (BVAR (current_buffer, mark))->buffer
1999       && NILP (Vsaved_region_selection)
2000       && (EQ (Vselect_active_regions, Qonly)
2001 	  ? EQ (CAR_SAFE (Vtransient_mark_mode), Qonly)
2002 	  : (!NILP (Vselect_active_regions)
2003 	     && !NILP (Vtransient_mark_mode))))
2004     Vsaved_region_selection
2005       = call1 (Vregion_extract_function, Qnil);
2006 
2007   signal_before_change (start, end, preserve_ptr);
2008   Fset (Qdeactivate_mark, Qt);
2009 }
2010 
2011 /* Like above, but called when we know that the buffer text
2012    will be modified and region caches should be invalidated.  */
2013 
2014 void
prepare_to_modify_buffer(ptrdiff_t start,ptrdiff_t end,ptrdiff_t * preserve_ptr)2015 prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
2016 			  ptrdiff_t *preserve_ptr)
2017 {
2018   prepare_to_modify_buffer_1 (start, end, preserve_ptr);
2019   invalidate_buffer_caches (current_buffer, start, end);
2020 }
2021 
2022 /* Invalidate the caches maintained by the buffer BUF, if any, for the
2023    region between buffer positions START and END.  */
2024 void
invalidate_buffer_caches(struct buffer * buf,ptrdiff_t start,ptrdiff_t end)2025 invalidate_buffer_caches (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
2026 {
2027   /* Indirect buffers usually have their caches set to NULL, but we
2028      need to consider the caches of their base buffer.  */
2029   if (buf->base_buffer)
2030     buf = buf->base_buffer;
2031   /* The bidi_paragraph_cache must be invalidated first, because doing
2032      so might need to use the newline_cache (via find_newline_no_quit,
2033      see below).  */
2034   if (buf->bidi_paragraph_cache)
2035     {
2036       if (start > BUF_BEG (buf))
2037 	{
2038 	  /* If we are deleting or replacing characters, we could
2039 	     create a paragraph start, because all of the characters
2040 	     from START to the beginning of START's line are
2041 	     whitespace.  Therefore, we must extend the region to be
2042 	     invalidated up to the newline before START.  Similarly,
2043 	     if we are inserting characters immediately after a
2044 	     newline, we could create a paragraph start if the
2045 	     inserted characters start with a newline.  */
2046 	  ptrdiff_t line_beg = start;
2047 	  ptrdiff_t start_byte = buf_charpos_to_bytepos (buf, start);
2048 	  int prev_char = BUF_FETCH_BYTE (buf, start_byte - 1);
2049 
2050 	  if ((start == end) == (prev_char == '\n'))
2051 	    {
2052 	      struct buffer *old = current_buffer;
2053 
2054 	      set_buffer_internal (buf);
2055 
2056 	      line_beg = find_newline_no_quit (start, start_byte, -1,
2057 					       &start_byte);
2058 	      set_buffer_internal (old);
2059 	    }
2060 	  start = line_beg - (line_beg > BUF_BEG (buf));
2061 	}
2062       invalidate_region_cache (buf,
2063 			       buf->bidi_paragraph_cache,
2064 			       start - BUF_BEG (buf), BUF_Z (buf) - end);
2065     }
2066   if (buf->newline_cache)
2067     invalidate_region_cache (buf,
2068                              buf->newline_cache,
2069                              start - BUF_BEG (buf), BUF_Z (buf) - end);
2070   if (buf->width_run_cache)
2071     invalidate_region_cache (buf,
2072                              buf->width_run_cache,
2073                              start - BUF_BEG (buf), BUF_Z (buf) - end);
2074 }
2075 
2076 /* These macros work with an argument named `preserve_ptr'
2077    and a local variable named `preserve_marker'.  */
2078 
2079 #define PRESERVE_VALUE							\
2080   if (preserve_ptr && NILP (preserve_marker))				\
2081     preserve_marker = Fcopy_marker (make_fixnum (*preserve_ptr), Qnil)
2082 
2083 #define RESTORE_VALUE						\
2084   if (! NILP (preserve_marker))					\
2085     {								\
2086       *preserve_ptr = marker_position (preserve_marker);	\
2087       unchain_marker (XMARKER (preserve_marker));		\
2088     }
2089 
2090 #define PRESERVE_START_END			\
2091   if (NILP (start_marker))			\
2092     start_marker = Fcopy_marker (start, Qnil);	\
2093   if (NILP (end_marker))			\
2094     end_marker = Fcopy_marker (end, Qnil);
2095 
2096 #define FETCH_START				\
2097   (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
2098 
2099 #define FETCH_END				\
2100   (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
2101 
2102 /* Set a variable to nil if an error occurred.
2103    Don't change the variable if there was no error.
2104    VAL is a cons-cell (VARIABLE . NO-ERROR-FLAG).
2105    VARIABLE is the variable to maybe set to nil.
2106    NO-ERROR-FLAG is nil if there was an error,
2107    anything else meaning no error (so this function does nothing).  */
2108 struct rvoe_arg
2109 {
2110   Lisp_Object *location;
2111   bool errorp;
2112 };
2113 
2114 static void
reset_var_on_error(void * ptr)2115 reset_var_on_error (void *ptr)
2116 {
2117   struct rvoe_arg *p = ptr;
2118   if (p->errorp)
2119     *p->location = Qnil;
2120 }
2121 
2122 /* Signal a change to the buffer immediately before it happens.
2123    START_INT and END_INT are the bounds of the text to be changed.
2124 
2125    If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
2126    by holding its value temporarily in a marker.  */
2127 
2128 static void
signal_before_change(ptrdiff_t start_int,ptrdiff_t end_int,ptrdiff_t * preserve_ptr)2129 signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int,
2130 		      ptrdiff_t *preserve_ptr)
2131 {
2132   Lisp_Object start, end;
2133   Lisp_Object start_marker, end_marker;
2134   Lisp_Object preserve_marker;
2135   ptrdiff_t count = SPECPDL_INDEX ();
2136   struct rvoe_arg rvoe_arg;
2137 
2138   start = make_fixnum (start_int);
2139   end = make_fixnum (end_int);
2140   preserve_marker = Qnil;
2141   start_marker = Qnil;
2142   end_marker = Qnil;
2143 
2144   specbind (Qinhibit_modification_hooks, Qt);
2145 
2146   /* If buffer is unmodified, run a special hook for that case.  The
2147    check for Vfirst_change_hook is just a minor optimization.  */
2148   if (SAVE_MODIFF >= MODIFF
2149       && !NILP (Vfirst_change_hook))
2150     {
2151       PRESERVE_VALUE;
2152       PRESERVE_START_END;
2153       run_hook (Qfirst_change_hook);
2154     }
2155 
2156   /* Now run the before-change-functions if any.  */
2157   if (!NILP (Vbefore_change_functions))
2158     {
2159       rvoe_arg.location = &Vbefore_change_functions;
2160       rvoe_arg.errorp = 1;
2161 
2162       PRESERVE_VALUE;
2163       PRESERVE_START_END;
2164 
2165       /* Mark before-change-functions to be reset to nil in case of error.  */
2166       record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
2167 
2168       /* Actually run the hook functions.  */
2169       CALLN (Frun_hook_with_args, Qbefore_change_functions,
2170 	     FETCH_START, FETCH_END);
2171 
2172       /* There was no error: unarm the reset_on_error.  */
2173       rvoe_arg.errorp = 0;
2174     }
2175 
2176   if (buffer_has_overlays ())
2177     {
2178       PRESERVE_VALUE;
2179       report_overlay_modification (FETCH_START, FETCH_END, 0,
2180 				   FETCH_START, FETCH_END, Qnil);
2181     }
2182 
2183   if (! NILP (start_marker))
2184     detach_marker (start_marker);
2185   if (! NILP (end_marker))
2186     detach_marker (end_marker);
2187   RESTORE_VALUE;
2188 
2189   unbind_to (count, Qnil);
2190 }
2191 
2192 /* Signal a change immediately after it happens.
2193    CHARPOS is the character position of the start of the changed text.
2194    LENDEL is the number of characters of the text before the change.
2195    (Not the whole buffer; just the part that was changed.)
2196    LENINS is the number of characters in that part of the text
2197    after the change.  */
2198 
2199 void
signal_after_change(ptrdiff_t charpos,ptrdiff_t lendel,ptrdiff_t lenins)2200 signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
2201 {
2202   ptrdiff_t count = SPECPDL_INDEX ();
2203   struct rvoe_arg rvoe_arg;
2204   Lisp_Object tmp, save_insert_behind_hooks, save_insert_in_from_hooks;
2205 
2206   if (inhibit_modification_hooks)
2207     return;
2208 
2209   /* If we are deferring calls to the after-change functions
2210      and there are no before-change functions,
2211      just record the args that we were going to use.  */
2212   if (! NILP (Vcombine_after_change_calls)
2213       /* It's OK to defer after-changes even if syntax-ppss-flush-cache
2214        * is on before-change-functions, which is common enough to be worth
2215        * adding a special case for it.  */
2216       && (NILP (Vbefore_change_functions)
2217           || (CONSP (Vbefore_change_functions)
2218               && EQ (Qt, XCAR (Vbefore_change_functions))
2219               && NILP (Fdefault_value (Qbefore_change_functions))
2220               && CONSP (tmp = XCDR (Vbefore_change_functions))
2221               && NILP (XCDR (tmp))
2222               && EQ (XCAR (tmp), Qsyntax_ppss_flush_cache)))
2223       && !buffer_has_overlays ())
2224     {
2225       Lisp_Object elt;
2226 
2227       if (!NILP (combine_after_change_list)
2228 	  && current_buffer != XBUFFER (combine_after_change_buffer))
2229 	Fcombine_after_change_execute ();
2230 
2231       elt = list3i (charpos - BEG, Z - (charpos - lendel + lenins),
2232 		    lenins - lendel);
2233       combine_after_change_list
2234 	= Fcons (elt, combine_after_change_list);
2235       combine_after_change_buffer = Fcurrent_buffer ();
2236 
2237       return;
2238     }
2239 
2240   /* Save and restore the insert-*-hooks, because other hooks like
2241      after-change-functions, called below, could clobber them if they
2242      manipulate text properties.  */
2243   save_insert_behind_hooks = interval_insert_behind_hooks;
2244   save_insert_in_from_hooks = interval_insert_in_front_hooks;
2245 
2246   if (!NILP (combine_after_change_list))
2247     Fcombine_after_change_execute ();
2248 
2249   specbind (Qinhibit_modification_hooks, Qt);
2250 
2251   if (!NILP (Vafter_change_functions))
2252     {
2253       rvoe_arg.location = &Vafter_change_functions;
2254       rvoe_arg.errorp = 1;
2255 
2256       /* Mark after-change-functions to be reset to nil in case of error.  */
2257       record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
2258 
2259       /* Actually run the hook functions.  */
2260       CALLN (Frun_hook_with_args, Qafter_change_functions,
2261 	     make_fixnum (charpos), make_fixnum (charpos + lenins),
2262 	     make_fixnum (lendel));
2263 
2264       /* There was no error: unarm the reset_on_error.  */
2265       rvoe_arg.errorp = 0;
2266     }
2267 
2268   interval_insert_behind_hooks = save_insert_behind_hooks;
2269   interval_insert_in_front_hooks = save_insert_in_from_hooks;
2270 
2271   if (buffer_has_overlays ())
2272     report_overlay_modification (make_fixnum (charpos),
2273 				 make_fixnum (charpos + lenins),
2274 				 1,
2275 				 make_fixnum (charpos),
2276 				 make_fixnum (charpos + lenins),
2277 				 make_fixnum (lendel));
2278 
2279   /* After an insertion, call the text properties
2280      insert-behind-hooks or insert-in-front-hooks.  */
2281   if (lendel == 0)
2282     report_interval_modification (make_fixnum (charpos),
2283 				  make_fixnum (charpos + lenins));
2284 
2285   unbind_to (count, Qnil);
2286 }
2287 
2288 static void
Fcombine_after_change_execute_1(Lisp_Object val)2289 Fcombine_after_change_execute_1 (Lisp_Object val)
2290 {
2291   Vcombine_after_change_calls = val;
2292 }
2293 
2294 DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
2295        Scombine_after_change_execute, 0, 0, 0,
2296        doc: /* This function is for use internally in the function `combine-after-change-calls'.  */)
2297   (void)
2298 {
2299   ptrdiff_t count = SPECPDL_INDEX ();
2300   ptrdiff_t beg, end, change;
2301   ptrdiff_t begpos, endpos;
2302   Lisp_Object tail;
2303 
2304   if (NILP (combine_after_change_list))
2305     return Qnil;
2306 
2307   /* It is rare for combine_after_change_buffer to be invalid, but
2308      possible.  It can happen when combine-after-change-calls is
2309      non-nil, and insertion calls a file name handler (e.g. through
2310      lock_file) which scribbles into a temp file -- cyd  */
2311   if (!BUFFERP (combine_after_change_buffer)
2312       || !BUFFER_LIVE_P (XBUFFER (combine_after_change_buffer)))
2313     {
2314       combine_after_change_list = Qnil;
2315       return Qnil;
2316     }
2317 
2318   record_unwind_current_buffer ();
2319 
2320   Fset_buffer (combine_after_change_buffer);
2321 
2322   /* # chars unchanged at beginning of buffer.  */
2323   beg = Z - BEG;
2324   /* # chars unchanged at end of buffer.  */
2325   end = beg;
2326   /* Total amount of insertion (negative for deletion).  */
2327   change = 0;
2328 
2329   /* Scan the various individual changes,
2330      accumulating the range info in BEG, END and CHANGE.  */
2331   for (tail = combine_after_change_list; CONSP (tail);
2332        tail = XCDR (tail))
2333     {
2334       Lisp_Object elt;
2335       ptrdiff_t thisbeg, thisend, thischange;
2336 
2337       /* Extract the info from the next element.  */
2338       elt = XCAR (tail);
2339       if (! CONSP (elt))
2340 	continue;
2341       thisbeg = XFIXNUM (XCAR (elt));
2342 
2343       elt = XCDR (elt);
2344       if (! CONSP (elt))
2345 	continue;
2346       thisend = XFIXNUM (XCAR (elt));
2347 
2348       elt = XCDR (elt);
2349       if (! CONSP (elt))
2350 	continue;
2351       thischange = XFIXNUM (XCAR (elt));
2352 
2353       /* Merge this range into the accumulated range.  */
2354       change += thischange;
2355       if (thisbeg < beg)
2356 	beg = thisbeg;
2357       if (thisend < end)
2358 	end = thisend;
2359     }
2360 
2361   /* Get the current start and end positions of the range
2362      that was changed.  */
2363   begpos = BEG + beg;
2364   endpos = Z - end;
2365 
2366   /* We are about to handle these, so discard them.  */
2367   combine_after_change_list = Qnil;
2368 
2369   /* Now run the after-change functions for real.
2370      Turn off the flag that defers them.  */
2371   record_unwind_protect (Fcombine_after_change_execute_1,
2372 			 Vcombine_after_change_calls);
2373   signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
2374   update_compositions (begpos, endpos, CHECK_ALL);
2375 
2376   return unbind_to (count, Qnil);
2377 }
2378 
2379 void
syms_of_insdel(void)2380 syms_of_insdel (void)
2381 {
2382   staticpro (&combine_after_change_list);
2383   staticpro (&combine_after_change_buffer);
2384   combine_after_change_list = Qnil;
2385   combine_after_change_buffer = Qnil;
2386 
2387   DEFSYM (Qundo_auto__undoable_change, "undo-auto--undoable-change");
2388   DEFSYM (Qsyntax_ppss_flush_cache, "syntax-ppss-flush-cache");
2389 
2390   DEFVAR_LISP ("combine-after-change-calls", Vcombine_after_change_calls,
2391 	       doc: /* Used internally by the function `combine-after-change-calls' macro.  */);
2392   Vcombine_after_change_calls = Qnil;
2393 
2394   DEFVAR_BOOL ("inhibit-modification-hooks", inhibit_modification_hooks,
2395 	       doc: /* Non-nil means don't run any of the hooks that respond to buffer changes.
2396 This affects `before-change-functions' and `after-change-functions',
2397 as well as hooks attached to text properties and overlays.
2398 Setting this variable non-nil also inhibits file locks and checks
2399 whether files are locked by another Emacs session, as well as
2400 handling of the active region per `select-active-regions'.
2401 
2402 To delay change hooks during a series of changes, use
2403 `combine-change-calls' or `combine-after-change-calls' instead of
2404 binding this variable.
2405 
2406 See also the info node `(elisp) Change Hooks'.  */);
2407   inhibit_modification_hooks = 0;
2408   DEFSYM (Qinhibit_modification_hooks, "inhibit-modification-hooks");
2409 
2410   defsubr (&Scombine_after_change_execute);
2411 }
2412