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