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