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