Auto-generate EXFUN using make-docfile
[bpt/emacs.git] / src / insdel.c
... / ...
CommitLineData
1/* Buffer insertion/deletion and gap motion for GNU Emacs.
2 Copyright (C) 1985-1986, 1993-1995, 1997-2012
3 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20
21#include <config.h>
22#include <setjmp.h>
23
24#include <intprops.h>
25
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"
33
34static 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);
38static void insert_from_buffer_1 (struct buffer *buf,
39 ptrdiff_t from, ptrdiff_t nchars,
40 int inherit);
41static void gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, int newgap);
42static void gap_right (ptrdiff_t charpos, ptrdiff_t bytepos);
43
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.
48
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). */
54static Lisp_Object combine_after_change_list;
55
56/* Buffer which combine_after_change_list is about. */
57static Lisp_Object combine_after_change_buffer;
58
59Lisp_Object Qinhibit_modification_hooks;
60
61static void signal_before_change (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
62\f
63#define CHECK_MARKERS() \
64 do \
65 { \
66 if (check_markers_debug_flag) \
67 check_markers (); \
68 } \
69 while (0)
70
71static void
72check_markers (void)
73{
74 register struct Lisp_Marker *tail;
75 int multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
76
77 for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
78 {
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 ();
87 }
88}
89\f
90/* Move gap to position CHARPOS.
91 Note that this can quit! */
92
93void
94move_gap (ptrdiff_t charpos)
95{
96 move_gap_both (charpos, charpos_to_bytepos (charpos));
97}
98
99/* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
100 Note that this can quit! */
101
102void
103move_gap_both (ptrdiff_t charpos, ptrdiff_t bytepos)
104{
105 if (bytepos < GPT_BYTE)
106 gap_left (charpos, bytepos, 0);
107 else if (bytepos > GPT_BYTE)
108 gap_right (charpos, bytepos);
109}
110
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. */
115
116static void
117gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, int newgap)
118{
119 register unsigned char *to, *from;
120 register ptrdiff_t i;
121 ptrdiff_t new_s1;
122
123 if (!newgap)
124 BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
125
126 i = GPT_BYTE;
127 to = GAP_END_ADDR;
128 from = GPT_ADDR;
129 new_s1 = GPT_BYTE;
130
131 /* Now copy the characters. To move the gap down,
132 copy characters up. */
133
134 while (1)
135 {
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)
143 {
144 bytepos = new_s1;
145 charpos = BYTE_TO_CHAR (bytepos);
146 break;
147 }
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);
154 }
155
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;
165}
166
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. */
170
171static void
172gap_right (ptrdiff_t charpos, ptrdiff_t bytepos)
173{
174 register unsigned char *to, *from;
175 register ptrdiff_t i;
176 ptrdiff_t new_s1;
177
178 BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
179
180 i = GPT_BYTE;
181 from = GAP_END_ADDR;
182 to = GPT_ADDR;
183 new_s1 = GPT_BYTE;
184
185 /* Now copy the characters. To move the gap up,
186 copy characters down. */
187
188 while (1)
189 {
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)
197 {
198 bytepos = new_s1;
199 charpos = BYTE_TO_CHAR (bytepos);
200 break;
201 }
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;
208 }
209
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;
216}
217\f
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.
221
222 This function assumes that the gap is adjacent to
223 or inside of the range being deleted. */
224
225void
226adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte,
227 ptrdiff_t to, ptrdiff_t to_byte)
228{
229 Lisp_Object marker;
230 register struct Lisp_Marker *m;
231 register ptrdiff_t charpos;
232
233 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
234 {
235 charpos = m->charpos;
236
237 if (charpos > Z)
238 abort ();
239
240 /* If the marker is after the deletion,
241 relocate by number of chars / bytes deleted. */
242 if (charpos > to)
243 {
244 m->charpos -= to - from;
245 m->bytepos -= to_byte - from_byte;
246 }
247 /* Here's the case where a marker is inside text being deleted. */
248 else if (charpos > from)
249 {
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);
256 }
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);
263 }
264 m->charpos = from;
265 m->bytepos = from_byte;
266 }
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)
270 {
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);
277 }
278 }
279}
280
281\f
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).
285
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. */
289
290static void
291adjust_markers_for_insert (ptrdiff_t from, ptrdiff_t from_byte,
292 ptrdiff_t to, ptrdiff_t to_byte, int before_markers)
293{
294 struct Lisp_Marker *m;
295 int adjusted = 0;
296 ptrdiff_t nchars = to - from;
297 ptrdiff_t nbytes = to_byte - from_byte;
298
299 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
300 {
301 eassert (m->bytepos >= m->charpos
302 && m->bytepos - m->charpos <= Z_BYTE - Z);
303
304 if (m->bytepos == from_byte)
305 {
306 if (m->insertion_type || before_markers)
307 {
308 m->bytepos = to_byte;
309 m->charpos = to;
310 if (m->insertion_type)
311 adjusted = 1;
312 }
313 }
314 else if (m->bytepos > from_byte)
315 {
316 m->bytepos += nbytes;
317 m->charpos += nchars;
318 }
319 }
320
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)
325 {
326 fix_start_end_in_overlays (from, to);
327 fix_overlays_before (current_buffer, from, to);
328 }
329}
330
331/* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
332
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. */
340
341static void
342adjust_point (ptrdiff_t nchars, ptrdiff_t nbytes)
343{
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);
347}
348\f
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. */
353
354static void
355adjust_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)
358{
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;
363
364 for (m = BUF_MARKERS (current_buffer); m; m = m->next)
365 {
366 if (m->bytepos >= prev_to_byte)
367 {
368 m->charpos += diff_chars;
369 m->bytepos += diff_bytes;
370 }
371 else if (m->bytepos > from_byte)
372 {
373 m->charpos = from;
374 m->bytepos = from_byte;
375 }
376 }
377
378 CHECK_MARKERS ();
379}
380
381\f
382void
383buffer_overflow (void)
384{
385 error ("Maximum buffer size exceeded");
386}
387
388/* Make the gap NBYTES_ADDED bytes longer. */
389
390static void
391make_gap_larger (ptrdiff_t nbytes_added)
392{
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 };
399
400 if (BUF_BYTES_MAX - current_size < nbytes_added)
401 buffer_overflow ();
402
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);
407
408 enlarge_buffer_text (current_buffer, nbytes_added);
409
410 /* Prevent quitting in move_gap. */
411 tem = Vinhibit_quit;
412 Vinhibit_quit = Qt;
413
414 real_gap_loc = GPT;
415 real_gap_loc_byte = GPT_BYTE;
416 old_gap_size = GAP_SIZE;
417
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;
422
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);
426
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;
431
432 /* Put an anchor. */
433 *(Z_ADDR) = 0;
434
435 Vinhibit_quit = tem;
436}
437
438#if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
439
440/* Make the gap NBYTES_REMOVED bytes shorter. */
441
442static void
443make_gap_smaller (ptrdiff_t nbytes_removed)
444{
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;
452
453 /* Make sure the gap is at least 20 bytes. */
454 if (GAP_SIZE - nbytes_removed < 20)
455 nbytes_removed = GAP_SIZE - 20;
456
457 /* Prevent quitting in move_gap. */
458 tem = Vinhibit_quit;
459 Vinhibit_quit = Qt;
460
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;
467
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;
477
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);
481
482 enlarge_buffer_text (current_buffer, -nbytes_removed);
483
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;
491
492 /* Put an anchor. */
493 *(Z_ADDR) = 0;
494
495 Vinhibit_quit = tem;
496}
497
498#endif /* USE_MMAP_FOR_BUFFERS || REL_ALLOC || DOUG_LEA_MALLOC */
499
500void
501make_gap (ptrdiff_t nbytes_added)
502{
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
509}
510\f
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.
515
516 Return the number of bytes stored at TO_ADDR. */
517
518ptrdiff_t
519copy_text (const unsigned char *from_addr, unsigned char *to_addr,
520 ptrdiff_t nbytes, int from_multibyte, int to_multibyte)
521{
522 if (from_multibyte == to_multibyte)
523 {
524 memcpy (to_addr, from_addr, nbytes);
525 return nbytes;
526 }
527 else if (from_multibyte)
528 {
529 ptrdiff_t nchars = 0;
530 ptrdiff_t bytes_left = nbytes;
531
532 while (bytes_left > 0)
533 {
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++;
542 }
543 return nchars;
544 }
545 else
546 {
547 unsigned char *initial_to_addr = to_addr;
548
549 /* Convert single-byte to multibyte. */
550 while (nbytes > 0)
551 {
552 int c = *from_addr++;
553
554 if (!ASCII_CHAR_P (c))
555 {
556 c = BYTE8_TO_CHAR (c);
557 to_addr += CHAR_STRING (c, to_addr);
558 nbytes--;
559 }
560 else
561 /* Special case for speed. */
562 *to_addr++ = c, nbytes--;
563 }
564 return to_addr - initial_to_addr;
565 }
566}
567\f
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.
572
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. */
575
576void
577insert (const char *string, ptrdiff_t nbytes)
578{
579 if (nbytes > 0)
580 {
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);
586 }
587}
588
589/* Likewise, but inherit text properties from neighboring characters. */
590
591void
592insert_and_inherit (const char *string, ptrdiff_t nbytes)
593{
594 if (nbytes > 0)
595 {
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);
601 }
602}
603
604/* Insert the character C before point. Do not inherit text properties. */
605
606void
607insert_char (int c)
608{
609 unsigned char str[MAX_MULTIBYTE_LENGTH];
610 int len;
611
612 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
613 len = CHAR_STRING (c, str);
614 else
615 {
616 len = 1;
617 str[0] = c;
618 }
619
620 insert ((char *) str, len);
621}
622
623/* Insert the null-terminated string S before point. */
624
625void
626insert_string (const char *s)
627{
628 insert (s, strlen (s));
629}
630
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. */
635
636void
637insert_before_markers (const char *string, ptrdiff_t nbytes)
638{
639 if (nbytes > 0)
640 {
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);
646 }
647}
648
649/* Likewise, but inherit text properties from neighboring characters. */
650
651void
652insert_before_markers_and_inherit (const char *string,
653 ptrdiff_t nbytes)
654{
655 if (nbytes > 0)
656 {
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);
662 }
663}
664
665/* Subroutine used by the insert functions above. */
666
667void
668insert_1 (const char *string, ptrdiff_t nbytes,
669 int inherit, int prepare, int before_markers)
670{
671 insert_1_both (string, chars_in_text ((unsigned char *) string, nbytes),
672 nbytes, inherit, prepare, before_markers);
673}
674
675\f
676#ifdef BYTE_COMBINING_DEBUG
677
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. */
682
683int
684count_combining_before (const unsigned char *string, ptrdiff_t length,
685 ptrdiff_t pos, ptrdiff_t pos_byte)
686{
687 int len, combining_bytes;
688 const unsigned char *p;
689
690 if (NILP (current_buffer->enable_multibyte_characters))
691 return 0;
692
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;
706
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;
713
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++;
719
720 return (combining_bytes < p - string ? combining_bytes : p - string);
721}
722
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. */
727
728int
729count_combining_after (const unsigned char *string,
730 ptrdiff_t length, ptrdiff_t pos, ptrdiff_t pos_byte)
731{
732 ptrdiff_t opos_byte = pos_byte;
733 ptrdiff_t i;
734 ptrdiff_t bytes;
735 unsigned char *bufp;
736
737 if (NILP (current_buffer->enable_multibyte_characters))
738 return 0;
739
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;
752
753 i = length - 1;
754 while (i >= 0 && ! CHAR_HEAD_P (string[i]))
755 {
756 i--;
757 }
758 if (i < 0)
759 {
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;
769
770 bytes = BYTES_BY_CHAR_HEAD (p[i]);
771 return (bytes <= pos_byte - 1 - i + length
772 ? 0
773 : bytes - (pos_byte - 1 - i + length));
774 }
775 if (!LEADING_CODE_P (string[i]))
776 return 0;
777
778 bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
779 bufp++, pos_byte++;
780 while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
781
782 return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
783}
784
785#endif
786
787\f
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. */
791
792void
793insert_1_both (const char *string,
794 ptrdiff_t nchars, ptrdiff_t nbytes,
795 int inherit, int prepare, int before_markers)
796{
797 if (nchars == 0)
798 return;
799
800 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
801 nchars = nbytes;
802
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);
808
809 if (PT != GPT)
810 move_gap_both (PT, PT_BYTE);
811 if (GAP_SIZE < nbytes)
812 make_gap (nbytes - GAP_SIZE);
813
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
819
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;
826
827 memcpy (GPT_ADDR, string, nbytes);
828
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. */
837
838 if (GPT_BYTE < GPT)
839 abort ();
840
841 /* The insert may have been in the unchanged region, so check again. */
842 if (Z - GPT < END_UNCHANGED)
843 END_UNCHANGED = Z - GPT;
844
845 adjust_overlays_for_insert (PT, nchars);
846 adjust_markers_for_insert (PT, PT_BYTE,
847 PT + nchars, PT_BYTE + nbytes,
848 before_markers);
849
850 if (BUF_INTERVALS (current_buffer) != 0)
851 offset_intervals (current_buffer, PT, nchars);
852
853 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
854 set_text_properties (make_number (PT), make_number (PT + nchars),
855 Qnil, Qnil, Qnil);
856
857 adjust_point (nchars, nbytes);
858
859 CHECK_MARKERS ();
860}
861\f
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.
866
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. */
870
871void
872insert_from_string (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
873 ptrdiff_t length, ptrdiff_t length_byte, int inherit)
874{
875 ptrdiff_t opoint = PT;
876
877 if (SCHARS (string) == 0)
878 return;
879
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);
884}
885
886/* Like `insert_from_string' except that all markers pointing
887 at the place where the insertion happens are adjusted to point after it. */
888
889void
890insert_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)
894{
895 ptrdiff_t opoint = PT;
896
897 if (SCHARS (string) == 0)
898 return;
899
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);
904}
905
906/* Subroutine of the insertion functions above. */
907
908static void
909insert_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)
912{
913 struct gcpro gcpro1;
914 ptrdiff_t outgoing_nbytes = nbytes;
915 INTERVAL intervals;
916
917 /* Make OUTGOING_NBYTES describe the text
918 as it will be inserted in this buffer. */
919
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);
926
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);
932
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;
938
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)));
944
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
955
956 record_insert (PT, nchars);
957 MODIFF++;
958 CHARS_MODIFF = MODIFF;
959
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. */
968
969 if (GPT_BYTE < GPT)
970 abort ();
971
972 /* The insert may have been in the unchanged region, so check again. */
973 if (Z - GPT < END_UNCHANGED)
974 END_UNCHANGED = Z - GPT;
975
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);
980
981 offset_intervals (current_buffer, PT, nchars);
982
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);
987
988 /* Insert those intervals. */
989 graft_intervals_into_buffer (intervals, PT, nchars,
990 current_buffer, inherit);
991
992 adjust_point (nchars, outgoing_nbytes);
993
994 CHECK_MARKERS ();
995}
996\f
997/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
998 starting at GPT_ADDR. */
999
1000void
1001insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes)
1002{
1003 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1004 nchars = nbytes;
1005
1006 record_insert (GPT, nchars);
1007 MODIFF++;
1008
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. */
1017
1018 if (GPT_BYTE < GPT)
1019 abort ();
1020
1021 adjust_overlays_for_insert (GPT - nchars, nchars);
1022 adjust_markers_for_insert (GPT - nchars, GPT_BYTE - nbytes,
1023 GPT, GPT_BYTE, 0);
1024
1025 if (BUF_INTERVALS (current_buffer) != 0)
1026 {
1027 offset_intervals (current_buffer, GPT - nchars, nchars);
1028 graft_intervals_into_buffer (NULL_INTERVAL, GPT - nchars, nchars,
1029 current_buffer, 0);
1030 }
1031
1032 if (GPT - nchars < PT)
1033 adjust_point (nchars, nbytes);
1034
1035 CHECK_MARKERS ();
1036}
1037\f
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.
1041
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. */
1044
1045void
1046insert_from_buffer (struct buffer *buf,
1047 ptrdiff_t charpos, ptrdiff_t nchars, int inherit)
1048{
1049 ptrdiff_t opoint = PT;
1050
1051 insert_from_buffer_1 (buf, charpos, nchars, inherit);
1052 signal_after_change (opoint, 0, PT - opoint);
1053 update_compositions (opoint, PT, CHECK_BORDER);
1054}
1055
1056static void
1057insert_from_buffer_1 (struct buffer *buf,
1058 ptrdiff_t from, ptrdiff_t nchars, int inherit)
1059{
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;
1066
1067 /* Make OUTGOING_NBYTES describe the text
1068 as it will be inserted in this buffer. */
1069
1070 if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
1071 outgoing_nbytes = nchars;
1072 else if (NILP (BVAR (buf, enable_multibyte_characters)))
1073 {
1074 ptrdiff_t outgoing_before_gap = 0;
1075 ptrdiff_t outgoing_after_gap = 0;
1076
1077 if (from < BUF_GPT (buf))
1078 {
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);
1085 }
1086 else
1087 chunk = 0;
1088
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);
1094
1095 outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
1096 }
1097
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);
1102
1103 if (PT != GPT)
1104 move_gap_both (PT, PT_BYTE);
1105 if (GAP_SIZE < outgoing_nbytes)
1106 make_gap (outgoing_nbytes - GAP_SIZE);
1107
1108 if (from < BUF_GPT (buf))
1109 {
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)));
1120 }
1121 else
1122 chunk_expanded = chunk = 0;
1123
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)));
1129
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
1140
1141 record_insert (PT, nchars);
1142 MODIFF++;
1143 CHARS_MODIFF = MODIFF;
1144
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. */
1153
1154 if (GPT_BYTE < GPT)
1155 abort ();
1156
1157 /* The insert may have been in the unchanged region, so check again. */
1158 if (Z - GPT < END_UNCHANGED)
1159 END_UNCHANGED = Z - GPT;
1160
1161 adjust_overlays_for_insert (PT, nchars);
1162 adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
1163 PT_BYTE + outgoing_nbytes,
1164 0);
1165
1166 if (BUF_INTERVALS (current_buffer) != 0)
1167 offset_intervals (current_buffer, PT, nchars);
1168
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))
1172 {
1173 if (buf == current_buffer && PT <= from)
1174 from += nchars;
1175 intervals = copy_intervals (intervals, from, nchars);
1176 }
1177
1178 /* Insert those intervals. */
1179 graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
1180
1181 adjust_point (nchars, outgoing_nbytes);
1182}
1183\f
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.
1188
1189 PREV_TEXT nil means the new text was just inserted. */
1190
1191static void
1192adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
1193 Lisp_Object prev_text, ptrdiff_t len, ptrdiff_t len_byte)
1194{
1195 ptrdiff_t nchars_del = 0, nbytes_del = 0;
1196
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
1202
1203 if (STRINGP (prev_text))
1204 {
1205 nchars_del = SCHARS (prev_text);
1206 nbytes_del = SBYTES (prev_text);
1207 }
1208
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. */
1215
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);
1222
1223 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1224 {
1225 if (nchars_del > 0)
1226 record_delete (from, prev_text);
1227 record_insert (from, len);
1228 }
1229
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)
1235 {
1236 offset_intervals (current_buffer, from, len - nchars_del);
1237 }
1238
1239 if (from < PT)
1240 adjust_point (len - nchars_del, len_byte - nbytes_del);
1241
1242 /* As byte combining will decrease Z, we must check this again. */
1243 if (Z - GPT < END_UNCHANGED)
1244 END_UNCHANGED = Z - GPT;
1245
1246 CHECK_MARKERS ();
1247
1248 if (len == 0)
1249 evaporate_overlays (from);
1250 MODIFF++;
1251 CHARS_MODIFF = MODIFF;
1252}
1253
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. */
1258
1259void
1260adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1261 ptrdiff_t to, ptrdiff_t to_byte, ptrdiff_t newlen)
1262{
1263 ptrdiff_t len = to - from, len_byte = to_byte - from_byte;
1264
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);
1272}
1273\f
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. */
1278
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.
1283
1284 But if MARKERS is 0, don't relocate markers. */
1285
1286void
1287replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1288 int prepare, int inherit, int markers)
1289{
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;
1298
1299 CHECK_MARKERS ();
1300
1301 GCPRO1 (new);
1302 deletion = Qnil;
1303
1304 if (prepare)
1305 {
1306 ptrdiff_t range_length = to - from;
1307 prepare_to_modify_buffer (from, to, &from);
1308 to = from + range_length;
1309 }
1310
1311 UNGCPRO;
1312
1313 /* Make args be valid. */
1314 if (from < BEGV)
1315 from = BEGV;
1316 if (to > ZV)
1317 to = ZV;
1318
1319 from_byte = CHAR_TO_BYTE (from);
1320 to_byte = CHAR_TO_BYTE (to);
1321
1322 nchars_del = to - from;
1323 nbytes_del = to_byte - from_byte;
1324
1325 if (nbytes_del <= 0 && insbytes == 0)
1326 return;
1327
1328 /* Make OUTGOING_INSBYTES describe the text
1329 as it will be inserted in this buffer. */
1330
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);
1336
1337 GCPRO1 (new);
1338
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);
1344
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);
1350
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. */
1359
1360 if (GPT_BYTE < GPT)
1361 abort ();
1362
1363 if (GPT - BEG < BEG_UNCHANGED)
1364 BEG_UNCHANGED = GPT - BEG;
1365 if (Z - GPT < END_UNCHANGED)
1366 END_UNCHANGED = Z - GPT;
1367
1368 if (GAP_SIZE < outgoing_insbytes)
1369 make_gap (outgoing_insbytes - GAP_SIZE);
1370
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)));
1376
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
1387
1388 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1389 {
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);
1396 }
1397
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. */
1406
1407 if (GPT_BYTE < GPT)
1408 abort ();
1409
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);
1414
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);
1419
1420 offset_intervals (current_buffer, from, inschars - nchars_del);
1421
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);
1428
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)));
1434
1435 if (outgoing_insbytes == 0)
1436 evaporate_overlays (from);
1437
1438 CHECK_MARKERS ();
1439
1440 MODIFF++;
1441 CHARS_MODIFF = MODIFF;
1442 UNGCPRO;
1443
1444 signal_after_change (from, nchars_del, GPT - from);
1445 update_compositions (from, GPT, CHECK_BORDER);
1446}
1447\f
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).
1452
1453 Note that this does not yet handle markers quite right.
1454
1455 If MARKERS is nonzero, relocate markers.
1456
1457 Unlike most functions at this level, never call
1458 prepare_to_modify_buffer and never call signal_after_change. */
1459
1460void
1461replace_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)
1465{
1466 ptrdiff_t nbytes_del, nchars_del;
1467
1468 CHECK_MARKERS ();
1469
1470 nchars_del = to - from;
1471 nbytes_del = to_byte - from_byte;
1472
1473 if (nbytes_del <= 0 && insbytes == 0)
1474 return;
1475
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);
1481
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. */
1490
1491 if (GPT_BYTE < GPT)
1492 abort ();
1493
1494 if (GPT - BEG < BEG_UNCHANGED)
1495 BEG_UNCHANGED = GPT - BEG;
1496 if (Z - GPT < END_UNCHANGED)
1497 END_UNCHANGED = Z - GPT;
1498
1499 if (GAP_SIZE < insbytes)
1500 make_gap (insbytes - GAP_SIZE);
1501
1502 /* Copy the replacement text into the buffer. */
1503 memcpy (GPT_ADDR, ins, insbytes);
1504
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
1515
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. */
1524
1525 if (GPT_BYTE < GPT)
1526 abort ();
1527
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)
1531 {
1532 adjust_overlays_for_insert (from, inschars);
1533 adjust_overlays_for_delete (from + inschars, nchars_del);
1534 }
1535
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);
1541
1542 offset_intervals (current_buffer, from, inschars - nchars_del);
1543
1544 /* Relocate point as if it were a marker. */
1545 if (from < PT && (nchars_del != inschars || nbytes_del != insbytes))
1546 {
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);
1552 }
1553
1554 if (insbytes == 0)
1555 evaporate_overlays (from);
1556
1557 CHECK_MARKERS ();
1558
1559 MODIFF++;
1560 CHARS_MODIFF = MODIFF;
1561}
1562\f
1563/* Delete characters in current buffer
1564 from FROM up to (but not including) TO.
1565 If TO comes before FROM, we delete nothing. */
1566
1567void
1568del_range (ptrdiff_t from, ptrdiff_t to)
1569{
1570 del_range_1 (from, to, 1, 0);
1571}
1572
1573/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
1574 RET_STRING says to return the deleted text. */
1575
1576Lisp_Object
1577del_range_1 (ptrdiff_t from, ptrdiff_t to, int prepare, int ret_string)
1578{
1579 ptrdiff_t from_byte, to_byte;
1580 Lisp_Object deletion;
1581 struct gcpro gcpro1;
1582
1583 /* Make args be valid */
1584 if (from < BEGV)
1585 from = BEGV;
1586 if (to > ZV)
1587 to = ZV;
1588
1589 if (to <= from)
1590 return Qnil;
1591
1592 if (prepare)
1593 {
1594 ptrdiff_t range_length = to - from;
1595 prepare_to_modify_buffer (from, to, &from);
1596 to = min (ZV, from + range_length);
1597 }
1598
1599 from_byte = CHAR_TO_BYTE (from);
1600 to_byte = CHAR_TO_BYTE (to);
1601
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;
1608}
1609
1610/* Like del_range_1 but args are byte positions, not char positions. */
1611
1612void
1613del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte, int prepare)
1614{
1615 ptrdiff_t from, to;
1616
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;
1622
1623 if (to_byte <= from_byte)
1624 return;
1625
1626 from = BYTE_TO_CHAR (from_byte);
1627 to = BYTE_TO_CHAR (to_byte);
1628
1629 if (prepare)
1630 {
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;
1635
1636 if (old_from != from)
1637 from_byte = CHAR_TO_BYTE (from);
1638 if (to > ZV)
1639 {
1640 to = ZV;
1641 to_byte = ZV_BYTE;
1642 }
1643 else if (old_to == Z - to)
1644 to_byte = CHAR_TO_BYTE (to);
1645 }
1646
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);
1650}
1651
1652/* Like del_range_1, but positions are specified both as charpos
1653 and bytepos. */
1654
1655void
1656del_range_both (ptrdiff_t from, ptrdiff_t from_byte,
1657 ptrdiff_t to, ptrdiff_t to_byte, int prepare)
1658{
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;
1664
1665 if (to_byte <= from_byte)
1666 return;
1667
1668 if (from < BEGV)
1669 from = BEGV;
1670 if (to > ZV)
1671 to = ZV;
1672
1673 if (prepare)
1674 {
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;
1679
1680 if (old_from != from)
1681 from_byte = CHAR_TO_BYTE (from);
1682 if (to > ZV)
1683 {
1684 to = ZV;
1685 to_byte = ZV_BYTE;
1686 }
1687 else if (old_to == Z - to)
1688 to_byte = CHAR_TO_BYTE (to);
1689 }
1690
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);
1694}
1695
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. */
1700
1701Lisp_Object
1702del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
1703 ptrdiff_t to, ptrdiff_t to_byte, int ret_string)
1704{
1705 register ptrdiff_t nbytes_del, nchars_del;
1706 Lisp_Object deletion;
1707
1708 CHECK_MARKERS ();
1709
1710 nchars_del = to - from;
1711 nbytes_del = to_byte - from_byte;
1712
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);
1718
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
1724
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;
1729
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);
1735
1736 if (! EQ (BVAR (current_buffer, undo_list), Qt))
1737 record_delete (from, deletion);
1738 MODIFF++;
1739 CHARS_MODIFF = MODIFF;
1740
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));
1745
1746 offset_intervals (current_buffer, from, - nchars_del);
1747
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);
1751
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;
1763
1764 if (GPT_BYTE < GPT)
1765 abort ();
1766
1767 if (GPT - BEG < BEG_UNCHANGED)
1768 BEG_UNCHANGED = GPT - BEG;
1769 if (Z - GPT < END_UNCHANGED)
1770 END_UNCHANGED = Z - GPT;
1771
1772 CHECK_MARKERS ();
1773
1774 evaporate_overlays (from);
1775
1776 return deletion;
1777}
1778\f
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.
1784
1785 If PRESERVE_CHARS_MODIFF is non-zero, do not update CHARS_MODIFF.
1786 Otherwise set CHARS_MODIFF to the new value of MODIFF. */
1787
1788void
1789modify_region (struct buffer *buffer, ptrdiff_t start, ptrdiff_t end,
1790 int preserve_chars_modiff)
1791{
1792 struct buffer *old_buffer = current_buffer;
1793
1794 if (buffer != old_buffer)
1795 set_buffer_internal (buffer);
1796
1797 prepare_to_modify_buffer (start, end, NULL);
1798
1799 BUF_COMPUTE_UNCHANGED (buffer, start - 1, end);
1800
1801 if (MODIFF <= SAVE_MODIFF)
1802 record_first_change ();
1803 MODIFF++;
1804 if (! preserve_chars_modiff)
1805 CHARS_MODIFF = MODIFF;
1806
1807 BVAR (buffer, point_before_scroll) = Qnil;
1808
1809 if (buffer != old_buffer)
1810 set_buffer_internal (old_buffer);
1811}
1812\f
1813/* Check that it is okay to modify the buffer between START and END,
1814 which are char positions.
1815
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.
1819
1820 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1821 by holding its value temporarily in a marker. */
1822
1823void
1824prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
1825 ptrdiff_t *preserve_ptr)
1826{
1827 struct buffer *base_buffer;
1828
1829 if (!NILP (BVAR (current_buffer, read_only)))
1830 Fbarf_if_buffer_read_only ();
1831
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;
1836
1837 if (BUF_INTERVALS (current_buffer) != 0)
1838 {
1839 if (preserve_ptr)
1840 {
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;
1849 }
1850 else
1851 verify_interval_modification (current_buffer, start, end);
1852 }
1853
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;
1859
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 */
1875
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))))
1885 {
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);
1892 }
1893
1894 signal_before_change (start, end, preserve_ptr);
1895
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);
1904
1905 Vdeactivate_mark = Qt;
1906}
1907\f
1908/* These macros work with an argument named `preserve_ptr'
1909 and a local variable named `preserve_marker'. */
1910
1911#define PRESERVE_VALUE \
1912 if (preserve_ptr && NILP (preserve_marker)) \
1913 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
1914
1915#define RESTORE_VALUE \
1916 if (! NILP (preserve_marker)) \
1917 { \
1918 *preserve_ptr = marker_position (preserve_marker); \
1919 unchain_marker (XMARKER (preserve_marker)); \
1920 }
1921
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);
1927
1928#define FETCH_START \
1929 (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
1930
1931#define FETCH_END \
1932 (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
1933
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). */
1940static Lisp_Object
1941reset_var_on_error (Lisp_Object val)
1942{
1943 if (NILP (XCDR (val)))
1944 Fset (XCAR (val), Qnil);
1945 return Qnil;
1946}
1947
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.
1950
1951 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1952 by holding its value temporarily in a marker. */
1953
1954static void
1955signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int,
1956 ptrdiff_t *preserve_ptr)
1957{
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 ();
1963
1964 if (inhibit_modification_hooks)
1965 return;
1966
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);
1973
1974 specbind (Qinhibit_modification_hooks, Qt);
1975
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))
1980 {
1981 PRESERVE_VALUE;
1982 PRESERVE_START_END;
1983 Frun_hooks (1, &Qfirst_change_hook);
1984 }
1985
1986 /* Now run the before-change-functions if any. */
1987 if (!NILP (Vbefore_change_functions))
1988 {
1989 Lisp_Object args[3];
1990 Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil);
1991
1992 PRESERVE_VALUE;
1993 PRESERVE_START_END;
1994
1995 /* Mark before-change-functions to be reset to nil in case of error. */
1996 record_unwind_protect (reset_var_on_error, rvoe_arg);
1997
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);
2003
2004 /* There was no error: unarm the reset_on_error. */
2005 XSETCDR (rvoe_arg, Qt);
2006 }
2007
2008 if (current_buffer->overlays_before || current_buffer->overlays_after)
2009 {
2010 PRESERVE_VALUE;
2011 report_overlay_modification (FETCH_START, FETCH_END, 0,
2012 FETCH_START, FETCH_END, Qnil);
2013 }
2014
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;
2021
2022 unbind_to (count, Qnil);
2023}
2024
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. */
2031
2032void
2033signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
2034{
2035 ptrdiff_t count = SPECPDL_INDEX ();
2036 if (inhibit_modification_hooks)
2037 return;
2038
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)
2046 {
2047 Lisp_Object elt;
2048
2049 if (!NILP (combine_after_change_list)
2050 && current_buffer != XBUFFER (combine_after_change_buffer))
2051 Fcombine_after_change_execute ();
2052
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 ();
2059
2060 return;
2061 }
2062
2063 if (!NILP (combine_after_change_list))
2064 Fcombine_after_change_execute ();
2065
2066 specbind (Qinhibit_modification_hooks, Qt);
2067
2068 if (!NILP (Vafter_change_functions))
2069 {
2070 Lisp_Object args[4];
2071 Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil);
2072
2073 /* Mark after-change-functions to be reset to nil in case of error. */
2074 record_unwind_protect (reset_var_on_error, rvoe_arg);
2075
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);
2082
2083 /* There was no error: unarm the reset_on_error. */
2084 XSETCDR (rvoe_arg, Qt);
2085 }
2086
2087 if (current_buffer->overlays_before || current_buffer->overlays_after)
2088 report_overlay_modification (make_number (charpos),
2089 make_number (charpos + lenins),
2090 1,
2091 make_number (charpos),
2092 make_number (charpos + lenins),
2093 make_number (lendel));
2094
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));
2100
2101 unbind_to (count, Qnil);
2102}
2103
2104static Lisp_Object
2105Fcombine_after_change_execute_1 (Lisp_Object val)
2106{
2107 Vcombine_after_change_calls = val;
2108 return val;
2109}
2110
2111DEFUN ("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)
2115{
2116 ptrdiff_t count = SPECPDL_INDEX ();
2117 ptrdiff_t beg, end, change;
2118 ptrdiff_t begpos, endpos;
2119 Lisp_Object tail;
2120
2121 if (NILP (combine_after_change_list))
2122 return Qnil;
2123
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)))
2130 {
2131 combine_after_change_list = Qnil;
2132 return Qnil;
2133 }
2134
2135 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
2136
2137 Fset_buffer (combine_after_change_buffer);
2138
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;
2145
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))
2150 {
2151 Lisp_Object elt;
2152 ptrdiff_t thisbeg, thisend, thischange;
2153
2154 /* Extract the info from the next element. */
2155 elt = XCAR (tail);
2156 if (! CONSP (elt))
2157 continue;
2158 thisbeg = XINT (XCAR (elt));
2159
2160 elt = XCDR (elt);
2161 if (! CONSP (elt))
2162 continue;
2163 thisend = XINT (XCAR (elt));
2164
2165 elt = XCDR (elt);
2166 if (! CONSP (elt))
2167 continue;
2168 thischange = XINT (XCAR (elt));
2169
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;
2176 }
2177
2178 /* Get the current start and end positions of the range
2179 that was changed. */
2180 begpos = BEG + beg;
2181 endpos = Z - end;
2182
2183 /* We are about to handle these, so discard them. */
2184 combine_after_change_list = Qnil;
2185
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);
2192
2193 return unbind_to (count, Qnil);
2194}
2195\f
2196void
2197syms_of_insdel (void)
2198{
2199 staticpro (&combine_after_change_list);
2200 staticpro (&combine_after_change_buffer);
2201 combine_after_change_list = Qnil;
2202 combine_after_change_buffer = Qnil;
2203
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;
2210
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.
2213This affects `before-change-functions' and `after-change-functions',
2214as well as hooks attached to text properties and overlays. */);
2215 inhibit_modification_hooks = 0;
2216 DEFSYM (Qinhibit_modification_hooks, "inhibit-modification-hooks");
2217
2218 defsubr (&Scombine_after_change_execute);
2219}