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