Fixes: debbugs:12042
[emacs.git] / src / insdel.c
blob2074916cfdeb7774128df90c28bbae1ed258a301
1 /* Buffer insertion/deletion and gap motion for GNU Emacs.
2 Copyright (C) 1985-1986, 1993-1995, 1997-2012
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include <setjmp.h>
24 #include <intprops.h>
26 #include "lisp.h"
27 #include "intervals.h"
28 #include "character.h"
29 #include "buffer.h"
30 #include "window.h"
31 #include "blockinput.h"
32 #include "region-cache.h"
34 static void insert_from_string_1 (Lisp_Object string,
35 ptrdiff_t pos, ptrdiff_t pos_byte,
36 ptrdiff_t nchars, ptrdiff_t nbytes,
37 int inherit, int before_markers);
38 static void insert_from_buffer_1 (struct buffer *buf,
39 ptrdiff_t from, ptrdiff_t nchars,
40 int inherit);
41 static void gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, int newgap);
42 static void gap_right (ptrdiff_t charpos, ptrdiff_t bytepos);
44 /* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT)
45 describing changes which happened while combine_after_change_calls
46 was nonzero. We use this to decide how to call them
47 once the deferral ends.
49 In each element.
50 BEG-UNCHANGED is the number of chars before the changed range.
51 END-UNCHANGED is the number of chars after the changed range,
52 and CHANGE-AMOUNT is the number of characters inserted by the change
53 (negative for a deletion). */
54 static Lisp_Object combine_after_change_list;
56 /* Buffer which combine_after_change_list is about. */
57 static Lisp_Object combine_after_change_buffer;
59 Lisp_Object Qinhibit_modification_hooks;
61 static void signal_before_change (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
63 #define CHECK_MARKERS() \
64 do \
65 { \
66 if (check_markers_debug_flag) \
67 check_markers (); \
68 } \
69 while (0)
71 static void
72 check_markers (void)
74 register struct Lisp_Marker *tail;
75 int multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
77 for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
79 if (tail->buffer->text != current_buffer->text)
80 abort ();
81 if (tail->charpos > Z)
82 abort ();
83 if (tail->bytepos > Z_BYTE)
84 abort ();
85 if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (tail->bytepos)))
86 abort ();
90 /* Move gap to position CHARPOS.
91 Note that this can quit! */
93 void
94 move_gap (ptrdiff_t charpos)
96 move_gap_both (charpos, charpos_to_bytepos (charpos));
99 /* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
100 Note that this can quit! */
102 void
103 move_gap_both (ptrdiff_t charpos, ptrdiff_t bytepos)
105 if (bytepos < GPT_BYTE)
106 gap_left (charpos, bytepos, 0);
107 else if (bytepos > GPT_BYTE)
108 gap_right (charpos, bytepos);
111 /* Move the gap to a position less than the current GPT.
112 BYTEPOS describes the new position as a byte position,
113 and CHARPOS is the corresponding char position.
114 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
116 static void
117 gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, int newgap)
119 register unsigned char *to, *from;
120 register ptrdiff_t i;
121 ptrdiff_t new_s1;
123 if (!newgap)
124 BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
126 i = GPT_BYTE;
127 to = GAP_END_ADDR;
128 from = GPT_ADDR;
129 new_s1 = GPT_BYTE;
131 /* Now copy the characters. To move the gap down,
132 copy characters up. */
134 while (1)
136 /* I gets number of characters left to copy. */
137 i = new_s1 - bytepos;
138 if (i == 0)
139 break;
140 /* If a quit is requested, stop copying now.
141 Change BYTEPOS to be where we have actually moved the gap to. */
142 if (QUITP)
144 bytepos = new_s1;
145 charpos = BYTE_TO_CHAR (bytepos);
146 break;
148 /* Move at most 32000 chars before checking again for a quit. */
149 if (i > 32000)
150 i = 32000;
151 new_s1 -= i;
152 from -= i, to -= i;
153 memmove (to, from, i);
156 /* Adjust buffer data structure, to put the gap at BYTEPOS.
157 BYTEPOS is where the loop above stopped, which may be what
158 was specified or may be where a quit was detected. */
159 GPT_BYTE = bytepos;
160 GPT = charpos;
161 if (bytepos < charpos)
162 abort ();
163 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
164 QUIT;
167 /* Move the gap to a position greater than the current GPT.
168 BYTEPOS describes the new position as a byte position,
169 and CHARPOS is the corresponding char position. */
171 static void
172 gap_right (ptrdiff_t charpos, ptrdiff_t bytepos)
174 register unsigned char *to, *from;
175 register ptrdiff_t i;
176 ptrdiff_t new_s1;
178 BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
180 i = GPT_BYTE;
181 from = GAP_END_ADDR;
182 to = GPT_ADDR;
183 new_s1 = GPT_BYTE;
185 /* Now copy the characters. To move the gap up,
186 copy characters down. */
188 while (1)
190 /* I gets number of characters left to copy. */
191 i = bytepos - new_s1;
192 if (i == 0)
193 break;
194 /* If a quit is requested, stop copying now.
195 Change BYTEPOS to be where we have actually moved the gap to. */
196 if (QUITP)
198 bytepos = new_s1;
199 charpos = BYTE_TO_CHAR (bytepos);
200 break;
202 /* Move at most 32000 chars before checking again for a quit. */
203 if (i > 32000)
204 i = 32000;
205 new_s1 += i;
206 memmove (to, from, i);
207 from += i, to += i;
210 GPT = charpos;
211 GPT_BYTE = bytepos;
212 if (bytepos < charpos)
213 abort ();
214 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
215 QUIT;
218 /* Adjust all markers for a deletion
219 whose range in bytes is FROM_BYTE to TO_BYTE.
220 The range in charpos is FROM to TO.
222 This function assumes that the gap is adjacent to
223 or inside of the range being deleted. */
225 void
226 adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte,
227 ptrdiff_t to, ptrdiff_t to_byte)
229 Lisp_Object marker;
230 register struct Lisp_Marker *m;
231 register ptrdiff_t charpos;
233 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
235 charpos = m->charpos;
237 if (charpos > Z)
238 abort ();
240 /* If the marker is after the deletion,
241 relocate by number of chars / bytes deleted. */
242 if (charpos > to)
244 m->charpos -= to - from;
245 m->bytepos -= to_byte - from_byte;
247 /* Here's the case where a marker is inside text being deleted. */
248 else if (charpos > from)
250 if (! m->insertion_type)
251 { /* Normal markers will end up at the beginning of the
252 re-inserted text after undoing a deletion, and must be
253 adjusted to move them to the correct place. */
254 XSETMISC (marker, m);
255 record_marker_adjustment (marker, from - charpos);
257 else if (charpos < to)
258 { /* Before-insertion markers will automatically move forward
259 upon re-inserting the deleted text, so we have to arrange
260 for them to move backward to the correct position. */
261 XSETMISC (marker, m);
262 record_marker_adjustment (marker, to - charpos);
264 m->charpos = from;
265 m->bytepos = from_byte;
267 /* Here's the case where a before-insertion marker is immediately
268 before the deleted region. */
269 else if (charpos == from && m->insertion_type)
271 /* Undoing the change uses normal insertion, which will
272 incorrectly make MARKER move forward, so we arrange for it
273 to then move backward to the correct place at the beginning
274 of the deleted region. */
275 XSETMISC (marker, m);
276 record_marker_adjustment (marker, to - from);
282 /* Adjust markers for an insertion that stretches from FROM / FROM_BYTE
283 to TO / TO_BYTE. We have to relocate the charpos of every marker
284 that points after the insertion (but not their bytepos).
286 When a marker points at the insertion point,
287 we advance it if either its insertion-type is t
288 or BEFORE_MARKERS is true. */
290 static void
291 adjust_markers_for_insert (ptrdiff_t from, ptrdiff_t from_byte,
292 ptrdiff_t to, ptrdiff_t to_byte, int before_markers)
294 struct Lisp_Marker *m;
295 int adjusted = 0;
296 ptrdiff_t nchars = to - from;
297 ptrdiff_t nbytes = to_byte - from_byte;
299 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
301 eassert (m->bytepos >= m->charpos
302 && m->bytepos - m->charpos <= Z_BYTE - Z);
304 if (m->bytepos == from_byte)
306 if (m->insertion_type || before_markers)
308 m->bytepos = to_byte;
309 m->charpos = to;
310 if (m->insertion_type)
311 adjusted = 1;
314 else if (m->bytepos > from_byte)
316 m->bytepos += nbytes;
317 m->charpos += nchars;
321 /* Adjusting only markers whose insertion-type is t may result in
322 - disordered start and end in overlays, and
323 - disordered overlays in the slot `overlays_before' of current_buffer. */
324 if (adjusted)
326 fix_start_end_in_overlays (from, to);
327 fix_overlays_before (current_buffer, from, to);
331 /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
333 This is used only when the value of point changes due to an insert
334 or delete; it does not represent a conceptual change in point as a
335 marker. In particular, point is not crossing any interval
336 boundaries, so there's no need to use the usual SET_PT macro. In
337 fact it would be incorrect to do so, because either the old or the
338 new value of point is out of sync with the current set of
339 intervals. */
341 static void
342 adjust_point (ptrdiff_t nchars, ptrdiff_t nbytes)
344 SET_BUF_PT_BOTH (current_buffer, PT + nchars, PT_BYTE + nbytes);
345 /* In a single-byte buffer, the two positions must be equal. */
346 eassert (PT_BYTE >= PT && PT_BYTE - PT <= ZV_BYTE - ZV);
349 /* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
350 length OLD_CHARS (OLD_BYTES) to a new text of length NEW_CHARS
351 (NEW_BYTES). It is assumed that OLD_CHARS > 0, i.e., this is not
352 an insertion. */
354 static void
355 adjust_markers_for_replace (ptrdiff_t from, ptrdiff_t from_byte,
356 ptrdiff_t old_chars, ptrdiff_t old_bytes,
357 ptrdiff_t new_chars, ptrdiff_t new_bytes)
359 register struct Lisp_Marker *m;
360 ptrdiff_t prev_to_byte = from_byte + old_bytes;
361 ptrdiff_t diff_chars = new_chars - old_chars;
362 ptrdiff_t diff_bytes = new_bytes - old_bytes;
364 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
366 if (m->bytepos >= prev_to_byte)
368 m->charpos += diff_chars;
369 m->bytepos += diff_bytes;
371 else if (m->bytepos > from_byte)
373 m->charpos = from;
374 m->bytepos = from_byte;
378 CHECK_MARKERS ();
382 void
383 buffer_overflow (void)
385 error ("Maximum buffer size exceeded");
388 /* Make the gap NBYTES_ADDED bytes longer. */
390 static void
391 make_gap_larger (ptrdiff_t nbytes_added)
393 Lisp_Object tem;
394 ptrdiff_t real_gap_loc;
395 ptrdiff_t real_gap_loc_byte;
396 ptrdiff_t old_gap_size;
397 ptrdiff_t current_size = Z_BYTE - BEG_BYTE + GAP_SIZE;
398 enum { enough_for_a_while = 2000 };
400 if (BUF_BYTES_MAX - current_size < nbytes_added)
401 buffer_overflow ();
403 /* If we have to get more space, get enough to last a while;
404 but do not exceed the maximum buffer size. */
405 nbytes_added = min (nbytes_added + enough_for_a_while,
406 BUF_BYTES_MAX - current_size);
408 enlarge_buffer_text (current_buffer, nbytes_added);
410 /* Prevent quitting in move_gap. */
411 tem = Vinhibit_quit;
412 Vinhibit_quit = Qt;
414 real_gap_loc = GPT;
415 real_gap_loc_byte = GPT_BYTE;
416 old_gap_size = GAP_SIZE;
418 /* Call the newly allocated space a gap at the end of the whole space. */
419 GPT = Z + GAP_SIZE;
420 GPT_BYTE = Z_BYTE + GAP_SIZE;
421 GAP_SIZE = nbytes_added;
423 /* Move the new gap down to be consecutive with the end of the old one.
424 This adjusts the markers properly too. */
425 gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1);
427 /* Now combine the two into one large gap. */
428 GAP_SIZE += old_gap_size;
429 GPT = real_gap_loc;
430 GPT_BYTE = real_gap_loc_byte;
432 /* Put an anchor. */
433 *(Z_ADDR) = 0;
435 Vinhibit_quit = tem;
438 #if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
440 /* Make the gap NBYTES_REMOVED bytes shorter. */
442 static void
443 make_gap_smaller (ptrdiff_t nbytes_removed)
445 Lisp_Object tem;
446 ptrdiff_t real_gap_loc;
447 ptrdiff_t real_gap_loc_byte;
448 ptrdiff_t real_Z;
449 ptrdiff_t real_Z_byte;
450 ptrdiff_t real_beg_unchanged;
451 ptrdiff_t new_gap_size;
453 /* Make sure the gap is at least 20 bytes. */
454 if (GAP_SIZE - nbytes_removed < 20)
455 nbytes_removed = GAP_SIZE - 20;
457 /* Prevent quitting in move_gap. */
458 tem = Vinhibit_quit;
459 Vinhibit_quit = Qt;
461 real_gap_loc = GPT;
462 real_gap_loc_byte = GPT_BYTE;
463 new_gap_size = GAP_SIZE - nbytes_removed;
464 real_Z = Z;
465 real_Z_byte = Z_BYTE;
466 real_beg_unchanged = BEG_UNCHANGED;
468 /* Pretend that the last unwanted part of the gap is the entire gap,
469 and that the first desired part of the gap is part of the buffer
470 text. */
471 memset (GPT_ADDR, 0, new_gap_size);
472 GPT += new_gap_size;
473 GPT_BYTE += new_gap_size;
474 Z += new_gap_size;
475 Z_BYTE += new_gap_size;
476 GAP_SIZE = nbytes_removed;
478 /* Move the unwanted pretend gap to the end of the buffer. This
479 adjusts the markers properly too. */
480 gap_right (Z, Z_BYTE);
482 enlarge_buffer_text (current_buffer, -nbytes_removed);
484 /* Now restore the desired gap. */
485 GAP_SIZE = new_gap_size;
486 GPT = real_gap_loc;
487 GPT_BYTE = real_gap_loc_byte;
488 Z = real_Z;
489 Z_BYTE = real_Z_byte;
490 BEG_UNCHANGED = real_beg_unchanged;
492 /* Put an anchor. */
493 *(Z_ADDR) = 0;
495 Vinhibit_quit = tem;
498 #endif /* USE_MMAP_FOR_BUFFERS || REL_ALLOC || DOUG_LEA_MALLOC */
500 void
501 make_gap (ptrdiff_t nbytes_added)
503 if (nbytes_added >= 0)
504 make_gap_larger (nbytes_added);
505 #if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
506 else
507 make_gap_smaller (-nbytes_added);
508 #endif
511 /* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
512 FROM_MULTIBYTE says whether the incoming text is multibyte.
513 TO_MULTIBYTE says whether to store the text as multibyte.
514 If FROM_MULTIBYTE != TO_MULTIBYTE, we convert.
516 Return the number of bytes stored at TO_ADDR. */
518 ptrdiff_t
519 copy_text (const unsigned char *from_addr, unsigned char *to_addr,
520 ptrdiff_t nbytes, int from_multibyte, int to_multibyte)
522 if (from_multibyte == to_multibyte)
524 memcpy (to_addr, from_addr, nbytes);
525 return nbytes;
527 else if (from_multibyte)
529 ptrdiff_t nchars = 0;
530 ptrdiff_t bytes_left = nbytes;
532 while (bytes_left > 0)
534 int thislen, c;
535 c = STRING_CHAR_AND_LENGTH (from_addr, thislen);
536 if (! ASCII_CHAR_P (c))
537 c &= 0xFF;
538 *to_addr++ = c;
539 from_addr += thislen;
540 bytes_left -= thislen;
541 nchars++;
543 return nchars;
545 else
547 unsigned char *initial_to_addr = to_addr;
549 /* Convert single-byte to multibyte. */
550 while (nbytes > 0)
552 int c = *from_addr++;
554 if (!ASCII_CHAR_P (c))
556 c = BYTE8_TO_CHAR (c);
557 to_addr += CHAR_STRING (c, to_addr);
558 nbytes--;
560 else
561 /* Special case for speed. */
562 *to_addr++ = c, nbytes--;
564 return to_addr - initial_to_addr;
568 /* Insert a string of specified length before point.
569 This function judges multibyteness based on
570 enable_multibyte_characters in the current buffer;
571 it never converts between single-byte and multibyte.
573 DO NOT use this for the contents of a Lisp string or a Lisp buffer!
574 prepare_to_modify_buffer could relocate the text. */
576 void
577 insert (const char *string, ptrdiff_t nbytes)
579 if (nbytes > 0)
581 ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
582 insert_1_both (string, len, nbytes, 0, 1, 0);
583 opoint = PT - len;
584 signal_after_change (opoint, 0, len);
585 update_compositions (opoint, PT, CHECK_BORDER);
589 /* Likewise, but inherit text properties from neighboring characters. */
591 void
592 insert_and_inherit (const char *string, ptrdiff_t nbytes)
594 if (nbytes > 0)
596 ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
597 insert_1_both (string, len, nbytes, 1, 1, 0);
598 opoint = PT - len;
599 signal_after_change (opoint, 0, len);
600 update_compositions (opoint, PT, CHECK_BORDER);
604 /* Insert the character C before point. Do not inherit text properties. */
606 void
607 insert_char (int c)
609 unsigned char str[MAX_MULTIBYTE_LENGTH];
610 int len;
612 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
613 len = CHAR_STRING (c, str);
614 else
616 len = 1;
617 str[0] = c;
620 insert ((char *) str, len);
623 /* Insert the null-terminated string S before point. */
625 void
626 insert_string (const char *s)
628 insert (s, strlen (s));
631 /* Like `insert' except that all markers pointing at the place where
632 the insertion happens are adjusted to point after it.
633 Don't use this function to insert part of a Lisp string,
634 since gc could happen and relocate it. */
636 void
637 insert_before_markers (const char *string, ptrdiff_t nbytes)
639 if (nbytes > 0)
641 ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
642 insert_1_both (string, len, nbytes, 0, 1, 1);
643 opoint = PT - len;
644 signal_after_change (opoint, 0, len);
645 update_compositions (opoint, PT, CHECK_BORDER);
649 /* Likewise, but inherit text properties from neighboring characters. */
651 void
652 insert_before_markers_and_inherit (const char *string,
653 ptrdiff_t nbytes)
655 if (nbytes > 0)
657 ptrdiff_t len = chars_in_text ((unsigned char *) string, nbytes), opoint;
658 insert_1_both (string, len, nbytes, 1, 1, 1);
659 opoint = PT - len;
660 signal_after_change (opoint, 0, len);
661 update_compositions (opoint, PT, CHECK_BORDER);
665 /* Subroutine used by the insert functions above. */
667 void
668 insert_1 (const char *string, ptrdiff_t nbytes,
669 int inherit, int prepare, int before_markers)
671 insert_1_both (string, chars_in_text ((unsigned char *) string, nbytes),
672 nbytes, inherit, prepare, before_markers);
676 #ifdef BYTE_COMBINING_DEBUG
678 /* See if the bytes before POS/POS_BYTE combine with bytes
679 at the start of STRING to form a single character.
680 If so, return the number of bytes at the start of STRING
681 which combine in this way. Otherwise, return 0. */
684 count_combining_before (const unsigned char *string, ptrdiff_t length,
685 ptrdiff_t pos, ptrdiff_t pos_byte)
687 int len, combining_bytes;
688 const unsigned char *p;
690 if (NILP (current_buffer->enable_multibyte_characters))
691 return 0;
693 /* At first, we can exclude the following cases:
694 (1) STRING[0] can't be a following byte of multibyte sequence.
695 (2) POS is the start of the current buffer.
696 (3) A character before POS is not a multibyte character. */
697 if (length == 0 || CHAR_HEAD_P (*string)) /* case (1) */
698 return 0;
699 if (pos_byte == BEG_BYTE) /* case (2) */
700 return 0;
701 len = 1;
702 p = BYTE_POS_ADDR (pos_byte - 1);
703 while (! CHAR_HEAD_P (*p)) p--, len++;
704 if (! LEADING_CODE_P (*p)) /* case (3) */
705 return 0;
707 combining_bytes = BYTES_BY_CHAR_HEAD (*p) - len;
708 if (combining_bytes <= 0)
709 /* The character preceding POS is, complete and no room for
710 combining bytes (combining_bytes == 0), or an independent 8-bit
711 character (combining_bytes < 0). */
712 return 0;
714 /* We have a combination situation. Count the bytes at STRING that
715 may combine. */
716 p = string + 1;
717 while (!CHAR_HEAD_P (*p) && p < string + length)
718 p++;
720 return (combining_bytes < p - string ? combining_bytes : p - string);
723 /* See if the bytes after POS/POS_BYTE combine with bytes
724 at the end of STRING to form a single character.
725 If so, return the number of bytes after POS/POS_BYTE
726 which combine in this way. Otherwise, return 0. */
729 count_combining_after (const unsigned char *string,
730 ptrdiff_t length, ptrdiff_t pos, ptrdiff_t pos_byte)
732 ptrdiff_t opos_byte = pos_byte;
733 ptrdiff_t i;
734 ptrdiff_t bytes;
735 unsigned char *bufp;
737 if (NILP (current_buffer->enable_multibyte_characters))
738 return 0;
740 /* At first, we can exclude the following cases:
741 (1) The last byte of STRING is an ASCII.
742 (2) POS is the last of the current buffer.
743 (3) A character at POS can't be a following byte of multibyte
744 character. */
745 if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */
746 return 0;
747 if (pos_byte == Z_BYTE) /* case (2) */
748 return 0;
749 bufp = BYTE_POS_ADDR (pos_byte);
750 if (CHAR_HEAD_P (*bufp)) /* case (3) */
751 return 0;
753 i = length - 1;
754 while (i >= 0 && ! CHAR_HEAD_P (string[i]))
756 i--;
758 if (i < 0)
760 /* All characters in STRING are not character head. We must
761 check also preceding bytes at POS. We are sure that the gap
762 is at POS. */
763 unsigned char *p = BEG_ADDR;
764 i = pos_byte - 2;
765 while (i >= 0 && ! CHAR_HEAD_P (p[i]))
766 i--;
767 if (i < 0 || !LEADING_CODE_P (p[i]))
768 return 0;
770 bytes = BYTES_BY_CHAR_HEAD (p[i]);
771 return (bytes <= pos_byte - 1 - i + length
773 : bytes - (pos_byte - 1 - i + length));
775 if (!LEADING_CODE_P (string[i]))
776 return 0;
778 bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
779 bufp++, pos_byte++;
780 while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
782 return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
785 #endif
788 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
789 starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS
790 are the same as in insert_1. */
792 void
793 insert_1_both (const char *string,
794 ptrdiff_t nchars, ptrdiff_t nbytes,
795 int inherit, int prepare, int before_markers)
797 if (nchars == 0)
798 return;
800 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
801 nchars = nbytes;
803 if (prepare)
804 /* Do this before moving and increasing the gap,
805 because the before-change hooks might move the gap
806 or make it smaller. */
807 prepare_to_modify_buffer (PT, PT, NULL);
809 if (PT != GPT)
810 move_gap_both (PT, PT_BYTE);
811 if (GAP_SIZE < nbytes)
812 make_gap (nbytes - GAP_SIZE);
814 #ifdef BYTE_COMBINING_DEBUG
815 if (count_combining_before (string, nbytes, PT, PT_BYTE)
816 || count_combining_after (string, nbytes, PT, PT_BYTE))
817 abort ();
818 #endif
820 /* Record deletion of the surrounding text that combines with
821 the insertion. This, together with recording the insertion,
822 will add up to the right stuff in the undo list. */
823 record_insert (PT, nchars);
824 MODIFF++;
825 CHARS_MODIFF = MODIFF;
827 memcpy (GPT_ADDR, string, nbytes);
829 GAP_SIZE -= nbytes;
830 GPT += nchars;
831 ZV += nchars;
832 Z += nchars;
833 GPT_BYTE += nbytes;
834 ZV_BYTE += nbytes;
835 Z_BYTE += nbytes;
836 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
838 if (GPT_BYTE < GPT)
839 abort ();
841 /* The insert may have been in the unchanged region, so check again. */
842 if (Z - GPT < END_UNCHANGED)
843 END_UNCHANGED = Z - GPT;
845 adjust_overlays_for_insert (PT, nchars);
846 adjust_markers_for_insert (PT, PT_BYTE,
847 PT + nchars, PT_BYTE + nbytes,
848 before_markers);
850 if (BUF_INTERVALS (current_buffer) != 0)
851 offset_intervals (current_buffer, PT, nchars);
853 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
854 set_text_properties (make_number (PT), make_number (PT + nchars),
855 Qnil, Qnil, Qnil);
857 adjust_point (nchars, nbytes);
859 CHECK_MARKERS ();
862 /* Insert the part of the text of STRING, a Lisp object assumed to be
863 of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes)
864 starting at position POS / POS_BYTE. If the text of STRING has properties,
865 copy them into the buffer.
867 It does not work to use `insert' for this, because a GC could happen
868 before we copy the stuff into the buffer, and relocate the string
869 without insert noticing. */
871 void
872 insert_from_string (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
873 ptrdiff_t length, ptrdiff_t length_byte, int inherit)
875 ptrdiff_t opoint = PT;
877 if (SCHARS (string) == 0)
878 return;
880 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
881 inherit, 0);
882 signal_after_change (opoint, 0, PT - opoint);
883 update_compositions (opoint, PT, CHECK_BORDER);
886 /* Like `insert_from_string' except that all markers pointing
887 at the place where the insertion happens are adjusted to point after it. */
889 void
890 insert_from_string_before_markers (Lisp_Object string,
891 ptrdiff_t pos, ptrdiff_t pos_byte,
892 ptrdiff_t length, ptrdiff_t length_byte,
893 int inherit)
895 ptrdiff_t opoint = PT;
897 if (SCHARS (string) == 0)
898 return;
900 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
901 inherit, 1);
902 signal_after_change (opoint, 0, PT - opoint);
903 update_compositions (opoint, PT, CHECK_BORDER);
906 /* Subroutine of the insertion functions above. */
908 static void
909 insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
910 ptrdiff_t nchars, ptrdiff_t nbytes,
911 int inherit, int before_markers)
913 struct gcpro gcpro1;
914 ptrdiff_t outgoing_nbytes = nbytes;
915 INTERVAL intervals;
917 /* Make OUTGOING_NBYTES describe the text
918 as it will be inserted in this buffer. */
920 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
921 outgoing_nbytes = nchars;
922 else if (! STRING_MULTIBYTE (string))
923 outgoing_nbytes
924 = count_size_as_multibyte (SDATA (string) + pos_byte,
925 nbytes);
927 GCPRO1 (string);
928 /* Do this before moving and increasing the gap,
929 because the before-change hooks might move the gap
930 or make it smaller. */
931 prepare_to_modify_buffer (PT, PT, NULL);
933 if (PT != GPT)
934 move_gap_both (PT, PT_BYTE);
935 if (GAP_SIZE < outgoing_nbytes)
936 make_gap (outgoing_nbytes - GAP_SIZE);
937 UNGCPRO;
939 /* Copy the string text into the buffer, perhaps converting
940 between single-byte and multibyte. */
941 copy_text (SDATA (string) + pos_byte, GPT_ADDR, nbytes,
942 STRING_MULTIBYTE (string),
943 ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
945 #ifdef BYTE_COMBINING_DEBUG
946 /* We have copied text into the gap, but we have not altered
947 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
948 to these functions and get the same results as we would
949 have got earlier on. Meanwhile, PT_ADDR does point to
950 the text that has been stored by copy_text. */
951 if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
952 || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
953 abort ();
954 #endif
956 record_insert (PT, nchars);
957 MODIFF++;
958 CHARS_MODIFF = MODIFF;
960 GAP_SIZE -= outgoing_nbytes;
961 GPT += nchars;
962 ZV += nchars;
963 Z += nchars;
964 GPT_BYTE += outgoing_nbytes;
965 ZV_BYTE += outgoing_nbytes;
966 Z_BYTE += outgoing_nbytes;
967 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
969 if (GPT_BYTE < GPT)
970 abort ();
972 /* The insert may have been in the unchanged region, so check again. */
973 if (Z - GPT < END_UNCHANGED)
974 END_UNCHANGED = Z - GPT;
976 adjust_overlays_for_insert (PT, nchars);
977 adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
978 PT_BYTE + outgoing_nbytes,
979 before_markers);
981 offset_intervals (current_buffer, PT, nchars);
983 intervals = STRING_INTERVALS (string);
984 /* Get the intervals for the part of the string we are inserting. */
985 if (nbytes < SBYTES (string))
986 intervals = copy_intervals (intervals, pos, nchars);
988 /* Insert those intervals. */
989 graft_intervals_into_buffer (intervals, PT, nchars,
990 current_buffer, inherit);
992 adjust_point (nchars, outgoing_nbytes);
994 CHECK_MARKERS ();
997 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
998 starting at GPT_ADDR. */
1000 void
1001 insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes)
1003 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1004 nchars = nbytes;
1006 record_insert (GPT, nchars);
1007 MODIFF++;
1009 GAP_SIZE -= nbytes;
1010 GPT += nchars;
1011 ZV += nchars;
1012 Z += nchars;
1013 GPT_BYTE += nbytes;
1014 ZV_BYTE += nbytes;
1015 Z_BYTE += nbytes;
1016 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1018 if (GPT_BYTE < GPT)
1019 abort ();
1021 adjust_overlays_for_insert (GPT - nchars, nchars);
1022 adjust_markers_for_insert (GPT - nchars, GPT_BYTE - nbytes,
1023 GPT, GPT_BYTE, 0);
1025 if (BUF_INTERVALS (current_buffer) != 0)
1027 offset_intervals (current_buffer, GPT - nchars, nchars);
1028 graft_intervals_into_buffer (NULL_INTERVAL, GPT - nchars, nchars,
1029 current_buffer, 0);
1032 if (GPT - nchars < PT)
1033 adjust_point (nchars, nbytes);
1035 CHECK_MARKERS ();
1038 /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
1039 current buffer. If the text in BUF has properties, they are absorbed
1040 into the current buffer.
1042 It does not work to use `insert' for this, because a malloc could happen
1043 and relocate BUF's text before the copy happens. */
1045 void
1046 insert_from_buffer (struct buffer *buf,
1047 ptrdiff_t charpos, ptrdiff_t nchars, int inherit)
1049 ptrdiff_t opoint = PT;
1051 insert_from_buffer_1 (buf, charpos, nchars, inherit);
1052 signal_after_change (opoint, 0, PT - opoint);
1053 update_compositions (opoint, PT, CHECK_BORDER);
1056 static void
1057 insert_from_buffer_1 (struct buffer *buf,
1058 ptrdiff_t from, ptrdiff_t nchars, int inherit)
1060 ptrdiff_t chunk, chunk_expanded;
1061 ptrdiff_t from_byte = buf_charpos_to_bytepos (buf, from);
1062 ptrdiff_t to_byte = buf_charpos_to_bytepos (buf, from + nchars);
1063 ptrdiff_t incoming_nbytes = to_byte - from_byte;
1064 ptrdiff_t outgoing_nbytes = incoming_nbytes;
1065 INTERVAL intervals;
1067 /* Make OUTGOING_NBYTES describe the text
1068 as it will be inserted in this buffer. */
1070 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1071 outgoing_nbytes = nchars;
1072 else if (NILP (BVAR (buf, enable_multibyte_characters)))
1074 ptrdiff_t outgoing_before_gap = 0;
1075 ptrdiff_t outgoing_after_gap = 0;
1077 if (from < BUF_GPT (buf))
1079 chunk = BUF_GPT_BYTE (buf) - from_byte;
1080 if (chunk > incoming_nbytes)
1081 chunk = incoming_nbytes;
1082 outgoing_before_gap
1083 = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
1084 chunk);
1086 else
1087 chunk = 0;
1089 if (chunk < incoming_nbytes)
1090 outgoing_after_gap
1091 = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf,
1092 from_byte + chunk),
1093 incoming_nbytes - chunk);
1095 outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
1098 /* Do this before moving and increasing the gap,
1099 because the before-change hooks might move the gap
1100 or make it smaller. */
1101 prepare_to_modify_buffer (PT, PT, NULL);
1103 if (PT != GPT)
1104 move_gap_both (PT, PT_BYTE);
1105 if (GAP_SIZE < outgoing_nbytes)
1106 make_gap (outgoing_nbytes - GAP_SIZE);
1108 if (from < BUF_GPT (buf))
1110 chunk = BUF_GPT_BYTE (buf) - from_byte;
1111 if (chunk > incoming_nbytes)
1112 chunk = incoming_nbytes;
1113 /* Record number of output bytes, so we know where
1114 to put the output from the second copy_text. */
1115 chunk_expanded
1116 = copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
1117 GPT_ADDR, chunk,
1118 ! NILP (BVAR (buf, enable_multibyte_characters)),
1119 ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1121 else
1122 chunk_expanded = chunk = 0;
1124 if (chunk < incoming_nbytes)
1125 copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
1126 GPT_ADDR + chunk_expanded, incoming_nbytes - chunk,
1127 ! NILP (BVAR (buf, enable_multibyte_characters)),
1128 ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1130 #ifdef BYTE_COMBINING_DEBUG
1131 /* We have copied text into the gap, but we have not altered
1132 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1133 to these functions and get the same results as we would
1134 have got earlier on. Meanwhile, GPT_ADDR does point to
1135 the text that has been stored by copy_text. */
1136 if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
1137 || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
1138 abort ();
1139 #endif
1141 record_insert (PT, nchars);
1142 MODIFF++;
1143 CHARS_MODIFF = MODIFF;
1145 GAP_SIZE -= outgoing_nbytes;
1146 GPT += nchars;
1147 ZV += nchars;
1148 Z += nchars;
1149 GPT_BYTE += outgoing_nbytes;
1150 ZV_BYTE += outgoing_nbytes;
1151 Z_BYTE += outgoing_nbytes;
1152 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1154 if (GPT_BYTE < GPT)
1155 abort ();
1157 /* The insert may have been in the unchanged region, so check again. */
1158 if (Z - GPT < END_UNCHANGED)
1159 END_UNCHANGED = Z - GPT;
1161 adjust_overlays_for_insert (PT, nchars);
1162 adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
1163 PT_BYTE + outgoing_nbytes,
1166 if (BUF_INTERVALS (current_buffer) != 0)
1167 offset_intervals (current_buffer, PT, nchars);
1169 /* Get the intervals for the part of the string we are inserting. */
1170 intervals = BUF_INTERVALS (buf);
1171 if (nchars < BUF_Z (buf) - BUF_BEG (buf))
1173 if (buf == current_buffer && PT <= from)
1174 from += nchars;
1175 intervals = copy_intervals (intervals, from, nchars);
1178 /* Insert those intervals. */
1179 graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
1181 adjust_point (nchars, outgoing_nbytes);
1184 /* Record undo information and adjust markers and position keepers for
1185 a replacement of a text PREV_TEXT at FROM to a new text of LEN
1186 chars (LEN_BYTE bytes) which resides in the gap just after
1187 GPT_ADDR.
1189 PREV_TEXT nil means the new text was just inserted. */
1191 static void
1192 adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
1193 Lisp_Object prev_text, ptrdiff_t len, ptrdiff_t len_byte)
1195 ptrdiff_t nchars_del = 0, nbytes_del = 0;
1197 #ifdef BYTE_COMBINING_DEBUG
1198 if (count_combining_before (GPT_ADDR, len_byte, from, from_byte)
1199 || count_combining_after (GPT_ADDR, len_byte, from, from_byte))
1200 abort ();
1201 #endif
1203 if (STRINGP (prev_text))
1205 nchars_del = SCHARS (prev_text);
1206 nbytes_del = SBYTES (prev_text);
1209 /* Update various buffer positions for the new text. */
1210 GAP_SIZE -= len_byte;
1211 ZV += len; Z+= len;
1212 ZV_BYTE += len_byte; Z_BYTE += len_byte;
1213 GPT += len; GPT_BYTE += len_byte;
1214 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1216 if (nchars_del > 0)
1217 adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1218 len, len_byte);
1219 else
1220 adjust_markers_for_insert (from, from_byte,
1221 from + len, from_byte + len_byte, 0);
1223 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1225 if (nchars_del > 0)
1226 record_delete (from, prev_text);
1227 record_insert (from, len);
1230 if (len > nchars_del)
1231 adjust_overlays_for_insert (from, len - nchars_del);
1232 else if (len < nchars_del)
1233 adjust_overlays_for_delete (from, nchars_del - len);
1234 if (BUF_INTERVALS (current_buffer) != 0)
1236 offset_intervals (current_buffer, from, len - nchars_del);
1239 if (from < PT)
1240 adjust_point (len - nchars_del, len_byte - nbytes_del);
1242 /* As byte combining will decrease Z, we must check this again. */
1243 if (Z - GPT < END_UNCHANGED)
1244 END_UNCHANGED = Z - GPT;
1246 CHECK_MARKERS ();
1248 if (len == 0)
1249 evaporate_overlays (from);
1250 MODIFF++;
1251 CHARS_MODIFF = MODIFF;
1254 /* Record undo information, adjust markers and position keepers for an
1255 insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE). The
1256 text already exists in the current buffer but character length (TO
1257 - FROM) may be incorrect, the correct length is NEWLEN. */
1259 void
1260 adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1261 ptrdiff_t to, ptrdiff_t to_byte, ptrdiff_t newlen)
1263 ptrdiff_t len = to - from, len_byte = to_byte - from_byte;
1265 if (GPT != to)
1266 move_gap_both (to, to_byte);
1267 GAP_SIZE += len_byte;
1268 GPT -= len; GPT_BYTE -= len_byte;
1269 ZV -= len; ZV_BYTE -= len_byte;
1270 Z -= len; Z_BYTE -= len_byte;
1271 adjust_after_replace (from, from_byte, Qnil, newlen, len_byte);
1274 /* Replace the text from character positions FROM to TO with NEW,
1275 If PREPARE is nonzero, call prepare_to_modify_buffer.
1276 If INHERIT, the newly inserted text should inherit text properties
1277 from the surrounding non-deleted text. */
1279 /* Note that this does not yet handle markers quite right.
1280 Also it needs to record a single undo-entry that does a replacement
1281 rather than a separate delete and insert.
1282 That way, undo will also handle markers properly.
1284 But if MARKERS is 0, don't relocate markers. */
1286 void
1287 replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1288 int prepare, int inherit, int markers)
1290 ptrdiff_t inschars = SCHARS (new);
1291 ptrdiff_t insbytes = SBYTES (new);
1292 ptrdiff_t from_byte, to_byte;
1293 ptrdiff_t nbytes_del, nchars_del;
1294 struct gcpro gcpro1;
1295 INTERVAL intervals;
1296 ptrdiff_t outgoing_insbytes = insbytes;
1297 Lisp_Object deletion;
1299 CHECK_MARKERS ();
1301 GCPRO1 (new);
1302 deletion = Qnil;
1304 if (prepare)
1306 ptrdiff_t range_length = to - from;
1307 prepare_to_modify_buffer (from, to, &from);
1308 to = from + range_length;
1311 UNGCPRO;
1313 /* Make args be valid. */
1314 if (from < BEGV)
1315 from = BEGV;
1316 if (to > ZV)
1317 to = ZV;
1319 from_byte = CHAR_TO_BYTE (from);
1320 to_byte = CHAR_TO_BYTE (to);
1322 nchars_del = to - from;
1323 nbytes_del = to_byte - from_byte;
1325 if (nbytes_del <= 0 && insbytes == 0)
1326 return;
1328 /* Make OUTGOING_INSBYTES describe the text
1329 as it will be inserted in this buffer. */
1331 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1332 outgoing_insbytes = inschars;
1333 else if (! STRING_MULTIBYTE (new))
1334 outgoing_insbytes
1335 = count_size_as_multibyte (SDATA (new), insbytes);
1337 GCPRO1 (new);
1339 /* Make sure the gap is somewhere in or next to what we are deleting. */
1340 if (from > GPT)
1341 gap_right (from, from_byte);
1342 if (to < GPT)
1343 gap_left (to, to_byte, 0);
1345 /* Even if we don't record for undo, we must keep the original text
1346 because we may have to recover it because of inappropriate byte
1347 combining. */
1348 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1349 deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
1351 GAP_SIZE += nbytes_del;
1352 ZV -= nchars_del;
1353 Z -= nchars_del;
1354 ZV_BYTE -= nbytes_del;
1355 Z_BYTE -= nbytes_del;
1356 GPT = from;
1357 GPT_BYTE = from_byte;
1358 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1360 if (GPT_BYTE < GPT)
1361 abort ();
1363 if (GPT - BEG < BEG_UNCHANGED)
1364 BEG_UNCHANGED = GPT - BEG;
1365 if (Z - GPT < END_UNCHANGED)
1366 END_UNCHANGED = Z - GPT;
1368 if (GAP_SIZE < outgoing_insbytes)
1369 make_gap (outgoing_insbytes - GAP_SIZE);
1371 /* Copy the string text into the buffer, perhaps converting
1372 between single-byte and multibyte. */
1373 copy_text (SDATA (new), GPT_ADDR, insbytes,
1374 STRING_MULTIBYTE (new),
1375 ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
1377 #ifdef BYTE_COMBINING_DEBUG
1378 /* We have copied text into the gap, but we have not marked
1379 it as part of the buffer. So we can use the old FROM and FROM_BYTE
1380 here, for both the previous text and the following text.
1381 Meanwhile, GPT_ADDR does point to
1382 the text that has been stored by copy_text. */
1383 if (count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte)
1384 || count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte))
1385 abort ();
1386 #endif
1388 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1390 /* Record the insertion first, so that when we undo,
1391 the deletion will be undone first. Thus, undo
1392 will insert before deleting, and thus will keep
1393 the markers before and after this text separate. */
1394 record_insert (from + SCHARS (deletion), inschars);
1395 record_delete (from, deletion);
1398 GAP_SIZE -= outgoing_insbytes;
1399 GPT += inschars;
1400 ZV += inschars;
1401 Z += inschars;
1402 GPT_BYTE += outgoing_insbytes;
1403 ZV_BYTE += outgoing_insbytes;
1404 Z_BYTE += outgoing_insbytes;
1405 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1407 if (GPT_BYTE < GPT)
1408 abort ();
1410 /* Adjust the overlay center as needed. This must be done after
1411 adjusting the markers that bound the overlays. */
1412 adjust_overlays_for_delete (from, nchars_del);
1413 adjust_overlays_for_insert (from, inschars);
1415 /* Adjust markers for the deletion and the insertion. */
1416 if (markers)
1417 adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1418 inschars, outgoing_insbytes);
1420 offset_intervals (current_buffer, from, inschars - nchars_del);
1422 /* Get the intervals for the part of the string we are inserting--
1423 not including the combined-before bytes. */
1424 intervals = STRING_INTERVALS (new);
1425 /* Insert those intervals. */
1426 graft_intervals_into_buffer (intervals, from, inschars,
1427 current_buffer, inherit);
1429 /* Relocate point as if it were a marker. */
1430 if (from < PT)
1431 adjust_point ((from + inschars - (PT < to ? PT : to)),
1432 (from_byte + outgoing_insbytes
1433 - (PT_BYTE < to_byte ? PT_BYTE : to_byte)));
1435 if (outgoing_insbytes == 0)
1436 evaporate_overlays (from);
1438 CHECK_MARKERS ();
1440 MODIFF++;
1441 CHARS_MODIFF = MODIFF;
1442 UNGCPRO;
1444 signal_after_change (from, nchars_del, GPT - from);
1445 update_compositions (from, GPT, CHECK_BORDER);
1448 /* Replace the text from character positions FROM to TO with
1449 the text in INS of length INSCHARS.
1450 Keep the text properties that applied to the old characters
1451 (extending them to all the new chars if there are more new chars).
1453 Note that this does not yet handle markers quite right.
1455 If MARKERS is nonzero, relocate markers.
1457 Unlike most functions at this level, never call
1458 prepare_to_modify_buffer and never call signal_after_change. */
1460 void
1461 replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
1462 ptrdiff_t to, ptrdiff_t to_byte,
1463 const char *ins, ptrdiff_t inschars, ptrdiff_t insbytes,
1464 int markers)
1466 ptrdiff_t nbytes_del, nchars_del;
1468 CHECK_MARKERS ();
1470 nchars_del = to - from;
1471 nbytes_del = to_byte - from_byte;
1473 if (nbytes_del <= 0 && insbytes == 0)
1474 return;
1476 /* Make sure the gap is somewhere in or next to what we are deleting. */
1477 if (from > GPT)
1478 gap_right (from, from_byte);
1479 if (to < GPT)
1480 gap_left (to, to_byte, 0);
1482 GAP_SIZE += nbytes_del;
1483 ZV -= nchars_del;
1484 Z -= nchars_del;
1485 ZV_BYTE -= nbytes_del;
1486 Z_BYTE -= nbytes_del;
1487 GPT = from;
1488 GPT_BYTE = from_byte;
1489 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1491 if (GPT_BYTE < GPT)
1492 abort ();
1494 if (GPT - BEG < BEG_UNCHANGED)
1495 BEG_UNCHANGED = GPT - BEG;
1496 if (Z - GPT < END_UNCHANGED)
1497 END_UNCHANGED = Z - GPT;
1499 if (GAP_SIZE < insbytes)
1500 make_gap (insbytes - GAP_SIZE);
1502 /* Copy the replacement text into the buffer. */
1503 memcpy (GPT_ADDR, ins, insbytes);
1505 #ifdef BYTE_COMBINING_DEBUG
1506 /* We have copied text into the gap, but we have not marked
1507 it as part of the buffer. So we can use the old FROM and FROM_BYTE
1508 here, for both the previous text and the following text.
1509 Meanwhile, GPT_ADDR does point to
1510 the text that has been stored by copy_text. */
1511 if (count_combining_before (GPT_ADDR, insbytes, from, from_byte)
1512 || count_combining_after (GPT_ADDR, insbytes, from, from_byte))
1513 abort ();
1514 #endif
1516 GAP_SIZE -= insbytes;
1517 GPT += inschars;
1518 ZV += inschars;
1519 Z += inschars;
1520 GPT_BYTE += insbytes;
1521 ZV_BYTE += insbytes;
1522 Z_BYTE += insbytes;
1523 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1525 if (GPT_BYTE < GPT)
1526 abort ();
1528 /* Adjust the overlay center as needed. This must be done after
1529 adjusting the markers that bound the overlays. */
1530 if (nchars_del != inschars)
1532 adjust_overlays_for_insert (from, inschars);
1533 adjust_overlays_for_delete (from + inschars, nchars_del);
1536 /* Adjust markers for the deletion and the insertion. */
1537 if (markers
1538 && ! (nchars_del == 1 && inschars == 1 && nbytes_del == insbytes))
1539 adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1540 inschars, insbytes);
1542 offset_intervals (current_buffer, from, inschars - nchars_del);
1544 /* Relocate point as if it were a marker. */
1545 if (from < PT && (nchars_del != inschars || nbytes_del != insbytes))
1547 if (PT < to)
1548 /* PT was within the deleted text. Move it to FROM. */
1549 adjust_point (from - PT, from_byte - PT_BYTE);
1550 else
1551 adjust_point (inschars - nchars_del, insbytes - nbytes_del);
1554 if (insbytes == 0)
1555 evaporate_overlays (from);
1557 CHECK_MARKERS ();
1559 MODIFF++;
1560 CHARS_MODIFF = MODIFF;
1563 /* Delete characters in current buffer
1564 from FROM up to (but not including) TO.
1565 If TO comes before FROM, we delete nothing. */
1567 void
1568 del_range (ptrdiff_t from, ptrdiff_t to)
1570 del_range_1 (from, to, 1, 0);
1573 /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
1574 RET_STRING says to return the deleted text. */
1576 Lisp_Object
1577 del_range_1 (ptrdiff_t from, ptrdiff_t to, int prepare, int ret_string)
1579 ptrdiff_t from_byte, to_byte;
1580 Lisp_Object deletion;
1581 struct gcpro gcpro1;
1583 /* Make args be valid */
1584 if (from < BEGV)
1585 from = BEGV;
1586 if (to > ZV)
1587 to = ZV;
1589 if (to <= from)
1590 return Qnil;
1592 if (prepare)
1594 ptrdiff_t range_length = to - from;
1595 prepare_to_modify_buffer (from, to, &from);
1596 to = min (ZV, from + range_length);
1599 from_byte = CHAR_TO_BYTE (from);
1600 to_byte = CHAR_TO_BYTE (to);
1602 deletion = del_range_2 (from, from_byte, to, to_byte, ret_string);
1603 GCPRO1 (deletion);
1604 signal_after_change (from, to - from, 0);
1605 update_compositions (from, from, CHECK_HEAD);
1606 UNGCPRO;
1607 return deletion;
1610 /* Like del_range_1 but args are byte positions, not char positions. */
1612 void
1613 del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte, int prepare)
1615 ptrdiff_t from, to;
1617 /* Make args be valid */
1618 if (from_byte < BEGV_BYTE)
1619 from_byte = BEGV_BYTE;
1620 if (to_byte > ZV_BYTE)
1621 to_byte = ZV_BYTE;
1623 if (to_byte <= from_byte)
1624 return;
1626 from = BYTE_TO_CHAR (from_byte);
1627 to = BYTE_TO_CHAR (to_byte);
1629 if (prepare)
1631 ptrdiff_t old_from = from, old_to = Z - to;
1632 ptrdiff_t range_length = to - from;
1633 prepare_to_modify_buffer (from, to, &from);
1634 to = from + range_length;
1636 if (old_from != from)
1637 from_byte = CHAR_TO_BYTE (from);
1638 if (to > ZV)
1640 to = ZV;
1641 to_byte = ZV_BYTE;
1643 else if (old_to == Z - to)
1644 to_byte = CHAR_TO_BYTE (to);
1647 del_range_2 (from, from_byte, to, to_byte, 0);
1648 signal_after_change (from, to - from, 0);
1649 update_compositions (from, from, CHECK_HEAD);
1652 /* Like del_range_1, but positions are specified both as charpos
1653 and bytepos. */
1655 void
1656 del_range_both (ptrdiff_t from, ptrdiff_t from_byte,
1657 ptrdiff_t to, ptrdiff_t to_byte, int prepare)
1659 /* Make args be valid */
1660 if (from_byte < BEGV_BYTE)
1661 from_byte = BEGV_BYTE;
1662 if (to_byte > ZV_BYTE)
1663 to_byte = ZV_BYTE;
1665 if (to_byte <= from_byte)
1666 return;
1668 if (from < BEGV)
1669 from = BEGV;
1670 if (to > ZV)
1671 to = ZV;
1673 if (prepare)
1675 ptrdiff_t old_from = from, old_to = Z - to;
1676 ptrdiff_t range_length = to - from;
1677 prepare_to_modify_buffer (from, to, &from);
1678 to = from + range_length;
1680 if (old_from != from)
1681 from_byte = CHAR_TO_BYTE (from);
1682 if (to > ZV)
1684 to = ZV;
1685 to_byte = ZV_BYTE;
1687 else if (old_to == Z - to)
1688 to_byte = CHAR_TO_BYTE (to);
1691 del_range_2 (from, from_byte, to, to_byte, 0);
1692 signal_after_change (from, to - from, 0);
1693 update_compositions (from, from, CHECK_HEAD);
1696 /* Delete a range of text, specified both as character positions
1697 and byte positions. FROM and TO are character positions,
1698 while FROM_BYTE and TO_BYTE are byte positions.
1699 If RET_STRING is true, the deleted area is returned as a string. */
1701 Lisp_Object
1702 del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
1703 ptrdiff_t to, ptrdiff_t to_byte, int ret_string)
1705 register ptrdiff_t nbytes_del, nchars_del;
1706 Lisp_Object deletion;
1708 CHECK_MARKERS ();
1710 nchars_del = to - from;
1711 nbytes_del = to_byte - from_byte;
1713 /* Make sure the gap is somewhere in or next to what we are deleting. */
1714 if (from > GPT)
1715 gap_right (from, from_byte);
1716 if (to < GPT)
1717 gap_left (to, to_byte, 0);
1719 #ifdef BYTE_COMBINING_DEBUG
1720 if (count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
1721 Z_BYTE - to_byte, from, from_byte))
1722 abort ();
1723 #endif
1725 if (ret_string || ! EQ (BVAR (current_buffer, undo_list), Qt))
1726 deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
1727 else
1728 deletion = Qnil;
1730 /* Relocate all markers pointing into the new, larger gap
1731 to point at the end of the text before the gap.
1732 Do this before recording the deletion,
1733 so that undo handles this after reinserting the text. */
1734 adjust_markers_for_delete (from, from_byte, to, to_byte);
1736 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1737 record_delete (from, deletion);
1738 MODIFF++;
1739 CHARS_MODIFF = MODIFF;
1741 /* Relocate point as if it were a marker. */
1742 if (from < PT)
1743 adjust_point (from - (PT < to ? PT : to),
1744 from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte));
1746 offset_intervals (current_buffer, from, - nchars_del);
1748 /* Adjust the overlay center as needed. This must be done after
1749 adjusting the markers that bound the overlays. */
1750 adjust_overlays_for_delete (from, nchars_del);
1752 GAP_SIZE += nbytes_del;
1753 ZV_BYTE -= nbytes_del;
1754 Z_BYTE -= nbytes_del;
1755 ZV -= nchars_del;
1756 Z -= nchars_del;
1757 GPT = from;
1758 GPT_BYTE = from_byte;
1759 if (GAP_SIZE > 0 && !current_buffer->text->inhibit_shrinking)
1760 /* Put an anchor, unless called from decode_coding_object which
1761 needs to access the previous gap contents. */
1762 *(GPT_ADDR) = 0;
1764 if (GPT_BYTE < GPT)
1765 abort ();
1767 if (GPT - BEG < BEG_UNCHANGED)
1768 BEG_UNCHANGED = GPT - BEG;
1769 if (Z - GPT < END_UNCHANGED)
1770 END_UNCHANGED = Z - GPT;
1772 CHECK_MARKERS ();
1774 evaporate_overlays (from);
1776 return deletion;
1779 /* Call this if you're about to change the region of BUFFER from
1780 character positions START to END. This checks the read-only
1781 properties of the region, calls the necessary modification hooks,
1782 and warns the next redisplay that it should pay attention to that
1783 area.
1785 If PRESERVE_CHARS_MODIFF is non-zero, do not update CHARS_MODIFF.
1786 Otherwise set CHARS_MODIFF to the new value of MODIFF. */
1788 void
1789 modify_region (struct buffer *buffer, ptrdiff_t start, ptrdiff_t end,
1790 int preserve_chars_modiff)
1792 struct buffer *old_buffer = current_buffer;
1794 if (buffer != old_buffer)
1795 set_buffer_internal (buffer);
1797 prepare_to_modify_buffer (start, end, NULL);
1799 BUF_COMPUTE_UNCHANGED (buffer, start - 1, end);
1801 if (MODIFF <= SAVE_MODIFF)
1802 record_first_change ();
1803 MODIFF++;
1804 if (! preserve_chars_modiff)
1805 CHARS_MODIFF = MODIFF;
1807 BVAR (buffer, point_before_scroll) = Qnil;
1809 if (buffer != old_buffer)
1810 set_buffer_internal (old_buffer);
1813 /* Check that it is okay to modify the buffer between START and END,
1814 which are char positions.
1816 Run the before-change-function, if any. If intervals are in use,
1817 verify that the text to be modified is not read-only, and call
1818 any modification properties the text may have.
1820 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1821 by holding its value temporarily in a marker. */
1823 void
1824 prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
1825 ptrdiff_t *preserve_ptr)
1827 struct buffer *base_buffer;
1829 if (!NILP (BVAR (current_buffer, read_only)))
1830 Fbarf_if_buffer_read_only ();
1832 /* Let redisplay consider other windows than selected_window
1833 if modifying another buffer. */
1834 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
1835 ++windows_or_buffers_changed;
1837 if (BUF_INTERVALS (current_buffer) != 0)
1839 if (preserve_ptr)
1841 Lisp_Object preserve_marker;
1842 struct gcpro gcpro1;
1843 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil);
1844 GCPRO1 (preserve_marker);
1845 verify_interval_modification (current_buffer, start, end);
1846 *preserve_ptr = marker_position (preserve_marker);
1847 unchain_marker (XMARKER (preserve_marker));
1848 UNGCPRO;
1850 else
1851 verify_interval_modification (current_buffer, start, end);
1854 /* For indirect buffers, use the base buffer to check clashes. */
1855 if (current_buffer->base_buffer != 0)
1856 base_buffer = current_buffer->base_buffer;
1857 else
1858 base_buffer = current_buffer;
1860 #ifdef CLASH_DETECTION
1861 if (!NILP (BVAR (base_buffer, file_truename))
1862 /* Make binding buffer-file-name to nil effective. */
1863 && !NILP (BVAR (base_buffer, filename))
1864 && SAVE_MODIFF >= MODIFF)
1865 lock_file (BVAR (base_buffer, file_truename));
1866 #else
1867 /* At least warn if this file has changed on disk since it was visited. */
1868 if (!NILP (BVAR (base_buffer, filename))
1869 && SAVE_MODIFF >= MODIFF
1870 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
1871 && !NILP (Ffile_exists_p (BVAR (base_buffer, filename))))
1872 call1 (intern ("ask-user-about-supersession-threat"),
1873 BVAR (base_buffer,filename));
1874 #endif /* not CLASH_DETECTION */
1876 /* If `select-active-regions' is non-nil, save the region text. */
1877 if (!NILP (BVAR (current_buffer, mark_active))
1878 && !inhibit_modification_hooks
1879 && XMARKER (BVAR (current_buffer, mark))->buffer
1880 && NILP (Vsaved_region_selection)
1881 && (EQ (Vselect_active_regions, Qonly)
1882 ? EQ (CAR_SAFE (Vtransient_mark_mode), Qonly)
1883 : (!NILP (Vselect_active_regions)
1884 && !NILP (Vtransient_mark_mode))))
1886 ptrdiff_t b = XMARKER (BVAR (current_buffer, mark))->charpos;
1887 ptrdiff_t e = PT;
1888 if (b < e)
1889 Vsaved_region_selection = make_buffer_string (b, e, 0);
1890 else if (b > e)
1891 Vsaved_region_selection = make_buffer_string (e, b, 0);
1894 signal_before_change (start, end, preserve_ptr);
1896 if (current_buffer->newline_cache)
1897 invalidate_region_cache (current_buffer,
1898 current_buffer->newline_cache,
1899 start - BEG, Z - end);
1900 if (current_buffer->width_run_cache)
1901 invalidate_region_cache (current_buffer,
1902 current_buffer->width_run_cache,
1903 start - BEG, Z - end);
1905 Vdeactivate_mark = Qt;
1908 /* These macros work with an argument named `preserve_ptr'
1909 and a local variable named `preserve_marker'. */
1911 #define PRESERVE_VALUE \
1912 if (preserve_ptr && NILP (preserve_marker)) \
1913 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
1915 #define RESTORE_VALUE \
1916 if (! NILP (preserve_marker)) \
1918 *preserve_ptr = marker_position (preserve_marker); \
1919 unchain_marker (XMARKER (preserve_marker)); \
1922 #define PRESERVE_START_END \
1923 if (NILP (start_marker)) \
1924 start_marker = Fcopy_marker (start, Qnil); \
1925 if (NILP (end_marker)) \
1926 end_marker = Fcopy_marker (end, Qnil);
1928 #define FETCH_START \
1929 (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
1931 #define FETCH_END \
1932 (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
1934 /* Set a variable to nil if an error occurred.
1935 Don't change the variable if there was no error.
1936 VAL is a cons-cell (VARIABLE . NO-ERROR-FLAG).
1937 VARIABLE is the variable to maybe set to nil.
1938 NO-ERROR-FLAG is nil if there was an error,
1939 anything else meaning no error (so this function does nothing). */
1940 static Lisp_Object
1941 reset_var_on_error (Lisp_Object val)
1943 if (NILP (XCDR (val)))
1944 Fset (XCAR (val), Qnil);
1945 return Qnil;
1948 /* Signal a change to the buffer immediately before it happens.
1949 START_INT and END_INT are the bounds of the text to be changed.
1951 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1952 by holding its value temporarily in a marker. */
1954 static void
1955 signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int,
1956 ptrdiff_t *preserve_ptr)
1958 Lisp_Object start, end;
1959 Lisp_Object start_marker, end_marker;
1960 Lisp_Object preserve_marker;
1961 struct gcpro gcpro1, gcpro2, gcpro3;
1962 ptrdiff_t count = SPECPDL_INDEX ();
1964 if (inhibit_modification_hooks)
1965 return;
1967 start = make_number (start_int);
1968 end = make_number (end_int);
1969 preserve_marker = Qnil;
1970 start_marker = Qnil;
1971 end_marker = Qnil;
1972 GCPRO3 (preserve_marker, start_marker, end_marker);
1974 specbind (Qinhibit_modification_hooks, Qt);
1976 /* If buffer is unmodified, run a special hook for that case. The
1977 check for Vfirst_change_hook is just a minor optimization. */
1978 if (SAVE_MODIFF >= MODIFF
1979 && !NILP (Vfirst_change_hook))
1981 PRESERVE_VALUE;
1982 PRESERVE_START_END;
1983 Frun_hooks (1, &Qfirst_change_hook);
1986 /* Now run the before-change-functions if any. */
1987 if (!NILP (Vbefore_change_functions))
1989 Lisp_Object args[3];
1990 Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil);
1992 PRESERVE_VALUE;
1993 PRESERVE_START_END;
1995 /* Mark before-change-functions to be reset to nil in case of error. */
1996 record_unwind_protect (reset_var_on_error, rvoe_arg);
1998 /* Actually run the hook functions. */
1999 args[0] = Qbefore_change_functions;
2000 args[1] = FETCH_START;
2001 args[2] = FETCH_END;
2002 Frun_hook_with_args (3, args);
2004 /* There was no error: unarm the reset_on_error. */
2005 XSETCDR (rvoe_arg, Qt);
2008 if (current_buffer->overlays_before || current_buffer->overlays_after)
2010 PRESERVE_VALUE;
2011 report_overlay_modification (FETCH_START, FETCH_END, 0,
2012 FETCH_START, FETCH_END, Qnil);
2015 if (! NILP (start_marker))
2016 free_marker (start_marker);
2017 if (! NILP (end_marker))
2018 free_marker (end_marker);
2019 RESTORE_VALUE;
2020 UNGCPRO;
2022 unbind_to (count, Qnil);
2025 /* Signal a change immediately after it happens.
2026 CHARPOS is the character position of the start of the changed text.
2027 LENDEL is the number of characters of the text before the change.
2028 (Not the whole buffer; just the part that was changed.)
2029 LENINS is the number of characters in that part of the text
2030 after the change. */
2032 void
2033 signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
2035 ptrdiff_t count = SPECPDL_INDEX ();
2036 if (inhibit_modification_hooks)
2037 return;
2039 /* If we are deferring calls to the after-change functions
2040 and there are no before-change functions,
2041 just record the args that we were going to use. */
2042 if (! NILP (Vcombine_after_change_calls)
2043 && NILP (Vbefore_change_functions)
2044 && !current_buffer->overlays_before
2045 && !current_buffer->overlays_after)
2047 Lisp_Object elt;
2049 if (!NILP (combine_after_change_list)
2050 && current_buffer != XBUFFER (combine_after_change_buffer))
2051 Fcombine_after_change_execute ();
2053 elt = Fcons (make_number (charpos - BEG),
2054 Fcons (make_number (Z - (charpos - lendel + lenins)),
2055 Fcons (make_number (lenins - lendel), Qnil)));
2056 combine_after_change_list
2057 = Fcons (elt, combine_after_change_list);
2058 combine_after_change_buffer = Fcurrent_buffer ();
2060 return;
2063 if (!NILP (combine_after_change_list))
2064 Fcombine_after_change_execute ();
2066 specbind (Qinhibit_modification_hooks, Qt);
2068 if (!NILP (Vafter_change_functions))
2070 Lisp_Object args[4];
2071 Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil);
2073 /* Mark after-change-functions to be reset to nil in case of error. */
2074 record_unwind_protect (reset_var_on_error, rvoe_arg);
2076 /* Actually run the hook functions. */
2077 args[0] = Qafter_change_functions;
2078 XSETFASTINT (args[1], charpos);
2079 XSETFASTINT (args[2], charpos + lenins);
2080 XSETFASTINT (args[3], lendel);
2081 Frun_hook_with_args (4, args);
2083 /* There was no error: unarm the reset_on_error. */
2084 XSETCDR (rvoe_arg, Qt);
2087 if (current_buffer->overlays_before || current_buffer->overlays_after)
2088 report_overlay_modification (make_number (charpos),
2089 make_number (charpos + lenins),
2091 make_number (charpos),
2092 make_number (charpos + lenins),
2093 make_number (lendel));
2095 /* After an insertion, call the text properties
2096 insert-behind-hooks or insert-in-front-hooks. */
2097 if (lendel == 0)
2098 report_interval_modification (make_number (charpos),
2099 make_number (charpos + lenins));
2101 unbind_to (count, Qnil);
2104 static Lisp_Object
2105 Fcombine_after_change_execute_1 (Lisp_Object val)
2107 Vcombine_after_change_calls = val;
2108 return val;
2111 DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
2112 Scombine_after_change_execute, 0, 0, 0,
2113 doc: /* This function is for use internally in `combine-after-change-calls'. */)
2114 (void)
2116 ptrdiff_t count = SPECPDL_INDEX ();
2117 ptrdiff_t beg, end, change;
2118 ptrdiff_t begpos, endpos;
2119 Lisp_Object tail;
2121 if (NILP (combine_after_change_list))
2122 return Qnil;
2124 /* It is rare for combine_after_change_buffer to be invalid, but
2125 possible. It can happen when combine-after-change-calls is
2126 non-nil, and insertion calls a file handler (e.g. through
2127 lock_file) which scribbles into a temp file -- cyd */
2128 if (!BUFFERP (combine_after_change_buffer)
2129 || NILP (BVAR (XBUFFER (combine_after_change_buffer), name)))
2131 combine_after_change_list = Qnil;
2132 return Qnil;
2135 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
2137 Fset_buffer (combine_after_change_buffer);
2139 /* # chars unchanged at beginning of buffer. */
2140 beg = Z - BEG;
2141 /* # chars unchanged at end of buffer. */
2142 end = beg;
2143 /* Total amount of insertion (negative for deletion). */
2144 change = 0;
2146 /* Scan the various individual changes,
2147 accumulating the range info in BEG, END and CHANGE. */
2148 for (tail = combine_after_change_list; CONSP (tail);
2149 tail = XCDR (tail))
2151 Lisp_Object elt;
2152 ptrdiff_t thisbeg, thisend, thischange;
2154 /* Extract the info from the next element. */
2155 elt = XCAR (tail);
2156 if (! CONSP (elt))
2157 continue;
2158 thisbeg = XINT (XCAR (elt));
2160 elt = XCDR (elt);
2161 if (! CONSP (elt))
2162 continue;
2163 thisend = XINT (XCAR (elt));
2165 elt = XCDR (elt);
2166 if (! CONSP (elt))
2167 continue;
2168 thischange = XINT (XCAR (elt));
2170 /* Merge this range into the accumulated range. */
2171 change += thischange;
2172 if (thisbeg < beg)
2173 beg = thisbeg;
2174 if (thisend < end)
2175 end = thisend;
2178 /* Get the current start and end positions of the range
2179 that was changed. */
2180 begpos = BEG + beg;
2181 endpos = Z - end;
2183 /* We are about to handle these, so discard them. */
2184 combine_after_change_list = Qnil;
2186 /* Now run the after-change functions for real.
2187 Turn off the flag that defers them. */
2188 record_unwind_protect (Fcombine_after_change_execute_1,
2189 Vcombine_after_change_calls);
2190 signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
2191 update_compositions (begpos, endpos, CHECK_ALL);
2193 return unbind_to (count, Qnil);
2196 void
2197 syms_of_insdel (void)
2199 staticpro (&combine_after_change_list);
2200 staticpro (&combine_after_change_buffer);
2201 combine_after_change_list = Qnil;
2202 combine_after_change_buffer = Qnil;
2204 DEFVAR_BOOL ("check-markers-debug-flag", check_markers_debug_flag,
2205 doc: /* Non-nil means enable debugging checks for invalid marker positions. */);
2206 check_markers_debug_flag = 0;
2207 DEFVAR_LISP ("combine-after-change-calls", Vcombine_after_change_calls,
2208 doc: /* Used internally by the `combine-after-change-calls' macro. */);
2209 Vcombine_after_change_calls = Qnil;
2211 DEFVAR_BOOL ("inhibit-modification-hooks", inhibit_modification_hooks,
2212 doc: /* Non-nil means don't run any of the hooks that respond to buffer changes.
2213 This affects `before-change-functions' and `after-change-functions',
2214 as well as hooks attached to text properties and overlays. */);
2215 inhibit_modification_hooks = 0;
2216 DEFSYM (Qinhibit_modification_hooks, "inhibit-modification-hooks");
2218 defsubr (&Scombine_after_change_execute);