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