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