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