(scheme-font-lock-keywords-1, scheme-font-lock-keywords-2,
[bpt/emacs.git] / src / insdel.c
CommitLineData
b45433b3 1/* Buffer insertion/deletion and gap motion for GNU Emacs.
4a2f9c6a 2 Copyright (C) 1985, 86, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
b45433b3
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7c938215 8the Free Software Foundation; either version 2, or (at your option)
b45433b3
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
b45433b3
JB
20
21
18160b98 22#include <config.h>
b45433b3 23#include "lisp.h"
679194a6 24#include "intervals.h"
b45433b3 25#include "buffer.h"
469ff680 26#include "charset.h"
b45433b3 27#include "window.h"
d014bf88 28#include "blockinput.h"
b45433b3 29
d206af14
RS
30#ifndef NULL
31#define NULL 0
32#endif
33
14f6194b
RS
34#define min(x, y) ((x) < (y) ? (x) : (y))
35
2b083808 36static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int));
ef29f213 37static void insert_from_buffer_1 ();
3be11131
RS
38static void gap_left P_ ((int, int, int));
39static void gap_right P_ ((int, int));
40static void adjust_markers_gap_motion P_ ((int, int, int));
432f78d2 41static void adjust_markers_for_insert P_ ((int, int, int, int, int, int, int));
3be11131
RS
42static void adjust_markers_for_delete P_ ((int, int, int, int));
43static void adjust_point P_ ((int, int));
395ec62e 44
fb2e7d14
RS
45Lisp_Object Fcombine_after_change_execute ();
46
47/* Non-nil means don't call the after-change-functions right away,
48 just record an element in Vcombine_after_change_calls_list. */
49Lisp_Object Vcombine_after_change_calls;
50
51/* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT)
52 describing changes which happened while combine_after_change_calls
53 was nonzero. We use this to decide how to call them
54 once the deferral ends.
55
56 In each element.
57 BEG-UNCHANGED is the number of chars before the changed range.
58 END-UNCHANGED is the number of chars after the changed range,
59 and CHANGE-AMOUNT is the number of characters inserted by the change
60 (negative for a deletion). */
61Lisp_Object combine_after_change_list;
62
63/* Buffer which combine_after_change_list is about. */
64Lisp_Object combine_after_change_buffer;
2b083808 65\f
3be11131 66/* Move gap to position CHARPOS.
b45433b3
JB
67 Note that this can quit! */
68
c660b094 69void
3be11131
RS
70move_gap (charpos)
71 int charpos;
b45433b3 72{
3be11131 73 move_gap_both (charpos, charpos_to_bytepos (charpos));
b45433b3
JB
74}
75
3be11131
RS
76/* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
77 Note that this can quit! */
78
79void
80move_gap_both (charpos, bytepos)
81 int charpos, bytepos;
82{
83 if (bytepos < GPT_BYTE)
84 gap_left (charpos, bytepos, 0);
85 else if (bytepos > GPT_BYTE)
86 gap_right (charpos, bytepos);
87}
88
89/* Move the gap to a position less than the current GPT.
90 BYTEPOS describes the new position as a byte position,
91 and CHARPOS is the corresponding char position.
b45433b3
JB
92 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
93
2bcaed71 94static void
3be11131
RS
95gap_left (charpos, bytepos, newgap)
96 register int charpos, bytepos;
b45433b3
JB
97 int newgap;
98{
99 register unsigned char *to, *from;
100 register int i;
101 int new_s1;
102
b45433b3
JB
103 if (!newgap)
104 {
894ab630
RS
105 if (unchanged_modified == MODIFF
106 && overlay_unchanged_modified == OVERLAY_MODIFF)
b45433b3 107 {
3be11131
RS
108 beg_unchanged = charpos - BEG;
109 end_unchanged = Z - charpos;
b45433b3
JB
110 }
111 else
112 {
113 if (Z - GPT < end_unchanged)
114 end_unchanged = Z - GPT;
3be11131
RS
115 if (charpos < beg_unchanged)
116 beg_unchanged = charpos - BEG;
b45433b3
JB
117 }
118 }
119
3be11131 120 i = GPT_BYTE;
b45433b3
JB
121 to = GAP_END_ADDR;
122 from = GPT_ADDR;
3be11131 123 new_s1 = GPT_BYTE;
b45433b3
JB
124
125 /* Now copy the characters. To move the gap down,
126 copy characters up. */
127
128 while (1)
129 {
130 /* I gets number of characters left to copy. */
3be11131 131 i = new_s1 - bytepos;
b45433b3
JB
132 if (i == 0)
133 break;
134 /* If a quit is requested, stop copying now.
3be11131 135 Change BYTEPOS to be where we have actually moved the gap to. */
b45433b3
JB
136 if (QUITP)
137 {
3be11131
RS
138 bytepos = new_s1;
139 charpos = BYTE_TO_CHAR (bytepos);
b45433b3
JB
140 break;
141 }
142 /* Move at most 32000 chars before checking again for a quit. */
143 if (i > 32000)
144 i = 32000;
145#ifdef GAP_USE_BCOPY
146 if (i >= 128
147 /* bcopy is safe if the two areas of memory do not overlap
148 or on systems where bcopy is always safe for moving upward. */
149 && (BCOPY_UPWARD_SAFE
150 || to - from >= 128))
151 {
152 /* If overlap is not safe, avoid it by not moving too many
153 characters at once. */
154 if (!BCOPY_UPWARD_SAFE && i > to - from)
155 i = to - from;
156 new_s1 -= i;
157 from -= i, to -= i;
158 bcopy (from, to, i);
159 }
160 else
161#endif
162 {
163 new_s1 -= i;
164 while (--i >= 0)
165 *--to = *--from;
166 }
167 }
168
3be11131
RS
169 /* Adjust markers, and buffer data structure, to put the gap at BYTEPOS.
170 BYTEPOS is where the loop above stopped, which may be what was specified
b45433b3 171 or may be where a quit was detected. */
3be11131
RS
172 adjust_markers_gap_motion (bytepos, GPT_BYTE, GAP_SIZE);
173 GPT_BYTE = bytepos;
174 GPT = charpos;
175 if (bytepos < charpos)
176 abort ();
469ff680 177 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
b45433b3
JB
178 QUIT;
179}
180
3be11131
RS
181/* Move the gap to a position greater than than the current GPT.
182 BYTEPOS describes the new position as a byte position,
183 and CHARPOS is the corresponding char position. */
184
2bcaed71 185static void
3be11131
RS
186gap_right (charpos, bytepos)
187 register int charpos, bytepos;
b45433b3
JB
188{
189 register unsigned char *to, *from;
190 register int i;
191 int new_s1;
192
894ab630
RS
193 if (unchanged_modified == MODIFF
194 && overlay_unchanged_modified == OVERLAY_MODIFF)
b45433b3 195 {
3be11131
RS
196 beg_unchanged = charpos - BEG;
197 end_unchanged = Z - charpos;
b45433b3
JB
198 }
199 else
200 {
3be11131
RS
201 if (Z - charpos - 1 < end_unchanged)
202 end_unchanged = Z - charpos;
b45433b3
JB
203 if (GPT - BEG < beg_unchanged)
204 beg_unchanged = GPT - BEG;
205 }
206
3be11131 207 i = GPT_BYTE;
b45433b3
JB
208 from = GAP_END_ADDR;
209 to = GPT_ADDR;
3be11131 210 new_s1 = GPT_BYTE;
b45433b3
JB
211
212 /* Now copy the characters. To move the gap up,
213 copy characters down. */
214
215 while (1)
216 {
217 /* I gets number of characters left to copy. */
3be11131 218 i = bytepos - new_s1;
b45433b3
JB
219 if (i == 0)
220 break;
221 /* If a quit is requested, stop copying now.
3be11131 222 Change BYTEPOS to be where we have actually moved the gap to. */
b45433b3
JB
223 if (QUITP)
224 {
3be11131
RS
225 bytepos = new_s1;
226 charpos = BYTE_TO_CHAR (bytepos);
b45433b3
JB
227 break;
228 }
229 /* Move at most 32000 chars before checking again for a quit. */
230 if (i > 32000)
231 i = 32000;
232#ifdef GAP_USE_BCOPY
233 if (i >= 128
234 /* bcopy is safe if the two areas of memory do not overlap
235 or on systems where bcopy is always safe for moving downward. */
236 && (BCOPY_DOWNWARD_SAFE
237 || from - to >= 128))
238 {
239 /* If overlap is not safe, avoid it by not moving too many
240 characters at once. */
241 if (!BCOPY_DOWNWARD_SAFE && i > from - to)
242 i = from - to;
243 new_s1 += i;
244 bcopy (from, to, i);
245 from += i, to += i;
246 }
247 else
248#endif
249 {
250 new_s1 += i;
251 while (--i >= 0)
252 *to++ = *from++;
253 }
254 }
255
3be11131
RS
256 adjust_markers_gap_motion (GPT_BYTE + GAP_SIZE, bytepos + GAP_SIZE,
257 - GAP_SIZE);
258 GPT = charpos;
259 GPT_BYTE = bytepos;
260 if (bytepos < charpos)
261 abort ();
469ff680 262 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
b45433b3
JB
263 QUIT;
264}
2b083808 265\f
3be11131
RS
266/* Add AMOUNT to the byte position of every marker in the current buffer
267 whose current byte position is between FROM (exclusive) and TO (inclusive).
8948d317 268
b45433b3
JB
269 Also, any markers past the outside of that interval, in the direction
270 of adjustment, are first moved back to the near end of the interval
8948d317
RS
271 and then adjusted by AMOUNT.
272
273 When the latter adjustment is done, if AMOUNT is negative,
274 we record the adjustment for undo. (This case happens only for
3be11131
RS
275 deletion.)
276
277 The markers' character positions are not altered,
278 because gap motion does not affect character positions. */
279
280int adjust_markers_test;
b45433b3 281
2bcaed71 282static void
3be11131 283adjust_markers_gap_motion (from, to, amount)
b45433b3
JB
284 register int from, to, amount;
285{
80f6e77c
RS
286 /* Now that a marker has a bytepos, not counting the gap,
287 nothing needs to be done here. */
288#if 0
b45433b3
JB
289 Lisp_Object marker;
290 register struct Lisp_Marker *m;
291 register int mpos;
292
9fbf87cd 293 marker = BUF_MARKERS (current_buffer);
b45433b3 294
d427b66a 295 while (!NILP (marker))
b45433b3
JB
296 {
297 m = XMARKER (marker);
80f6e77c 298 mpos = m->bytepos;
b45433b3
JB
299 if (amount > 0)
300 {
301 if (mpos > to && mpos < to + amount)
3be11131
RS
302 {
303 if (adjust_markers_test)
304 abort ();
305 mpos = to + amount;
306 }
b45433b3
JB
307 }
308 else
309 {
8948d317
RS
310 /* Here's the case where a marker is inside text being deleted.
311 AMOUNT can be negative for gap motion, too,
312 but then this range contains no markers. */
b45433b3 313 if (mpos > from + amount && mpos <= from)
8948d317 314 {
3be11131
RS
315 if (adjust_markers_test)
316 abort ();
317 mpos = from + amount;
8948d317 318 }
b45433b3
JB
319 }
320 if (mpos > from && mpos <= to)
321 mpos += amount;
322 m->bufpos = mpos;
323 marker = m->chain;
324 }
80f6e77c 325#endif
b45433b3 326}
2b083808 327\f
3be11131
RS
328/* Adjust all markers for a deletion
329 whose range in bytes is FROM_BYTE to TO_BYTE.
330 The range in charpos is FROM to TO.
331
332 This function assumes that the gap is adjacent to
333 or inside of the range being deleted. */
beecb55b
RS
334
335static void
3be11131
RS
336adjust_markers_for_delete (from, from_byte, to, to_byte)
337 register int from, from_byte, to, to_byte;
338{
339 Lisp_Object marker;
340 register struct Lisp_Marker *m;
341 register int charpos;
342 /* This is what GAP_SIZE will be when this deletion is finished. */
343 int coming_gap_size = GAP_SIZE + to_byte - from_byte;
344
345 marker = BUF_MARKERS (current_buffer);
346
347 while (!NILP (marker))
348 {
349 m = XMARKER (marker);
350 charpos = m->charpos;
351
352 if (charpos > Z)
353 abort ();
354
355 /* If the marker is after the deletion,
80f6e77c 356 relocate by number of chars / bytes deleted. */
3be11131 357 if (charpos > to)
80f6e77c
RS
358 {
359 m->charpos -= to - from;
360 m->bytepos -= to_byte - from_byte;
361 }
3be11131 362
80f6e77c 363 /* Here's the case where a marker is inside text being deleted. */
3be11131
RS
364 else if (charpos > from)
365 {
366 record_marker_adjustment (marker, from - charpos);
367 m->charpos = from;
80f6e77c 368 m->bytepos = from_byte;
3be11131
RS
369 }
370
371 /* In a single-byte buffer, a marker's two positions must be equal. */
372 if (Z == Z_BYTE)
373 {
80f6e77c 374 register int i = m->bytepos;
3be11131 375
80f6e77c 376#if 0
3be11131
RS
377 /* We use FROM_BYTE here instead of GPT_BYTE
378 because FROM_BYTE is where the gap will be after the deletion. */
379 if (i > from_byte + coming_gap_size)
380 i -= coming_gap_size;
381 else if (i > from_byte)
382 i = from_byte;
80f6e77c 383#endif
3be11131
RS
384
385 if (m->charpos != i)
386 abort ();
387 }
388
389 marker = m->chain;
390 }
391}
2b083808 392\f
432f78d2
RS
393/* Adjust markers for an insertion that stretches from FROM / FROM_BYTE
394 to TO / TO_BYTE. We have to relocate the charpos of every marker
395 that points after the insertion (but not their bytepos).
3be11131 396
432f78d2
RS
397 COMBINED_BEFORE_BYTES is the number of bytes before the insertion
398 that combines into one character with the first inserted bytes.
399 COMBINED_AFTER_BYTES is the number of bytes after the insertion
400 that combines into one character with the last inserted bytes.
3be11131
RS
401
402 When a marker points at the insertion point,
403 we advance it if either its insertion-type is t
404 or BEFORE_MARKERS is true. */
405
406static void
432f78d2
RS
407adjust_markers_for_insert (from, from_byte, to, to_byte,
408 combined_before_bytes, combined_after_bytes,
409 before_markers)
410 register int from, from_byte, to, to_byte;
411 int combined_before_bytes, combined_after_bytes, before_markers;
beecb55b
RS
412{
413 Lisp_Object marker;
469ff680 414 int adjusted = 0;
3be11131
RS
415 int nchars = to - from;
416 int nbytes = to_byte - from_byte;
beecb55b
RS
417
418 marker = BUF_MARKERS (current_buffer);
419
420 while (!NILP (marker))
421 {
422 register struct Lisp_Marker *m = XMARKER (marker);
432f78d2 423 if (m->bytepos == from_byte)
469ff680 424 {
432f78d2
RS
425 if (m->insertion_type || before_markers)
426 {
427 m->bytepos += nbytes + combined_after_bytes;
428 m->charpos += nchars + !!combined_after_bytes;
429 /* Point the marker before the combined character,
430 so that undoing the insertion puts it back where it was. */
431 if (combined_after_bytes)
432 DEC_BOTH (m->charpos, m->bytepos);
433 if (m->insertion_type)
434 adjusted = 1;
435 }
436 else if (combined_before_bytes)
437 {
438 /* This marker doesn't "need relocation",
439 but don't leave it pointing in the middle of a character.
440 Point the marker after the combined character,
441 so that undoing the insertion puts it back where it was. */
442 m->bytepos -= combined_before_bytes;
443 m->charpos -= 1;
444 INC_BOTH (m->charpos, m->bytepos);
445 }
469ff680 446 }
80f6e77c
RS
447 else if (m->bytepos > from_byte)
448 {
449 m->bytepos += nbytes;
450 m->charpos += nchars;
451 }
3be11131
RS
452
453 /* In a single-byte buffer, a marker's two positions must be equal. */
454 if (Z == Z_BYTE)
455 {
432f78d2 456 if (m->charpos != m->bytepos)
3be11131
RS
457 abort ();
458 }
459
beecb55b
RS
460 marker = m->chain;
461 }
3be11131
RS
462
463 /* Adjusting only markers whose insertion-type is t may result in
464 disordered overlays in the slot `overlays_before'. */
469ff680 465 if (adjusted)
3be11131 466 fix_overlays_before (current_buffer, from, to);
beecb55b
RS
467}
468
3be11131
RS
469/* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
470
471 This is used only when the value of point changes due to an insert
472 or delete; it does not represent a conceptual change in point as a
473 marker. In particular, point is not crossing any interval
474 boundaries, so there's no need to use the usual SET_PT macro. In
475 fact it would be incorrect to do so, because either the old or the
476 new value of point is out of sync with the current set of
477 intervals. */
478
a27a38d8 479static void
3be11131
RS
480adjust_point (nchars, nbytes)
481 int nchars, nbytes;
a27a38d8 482{
3be11131
RS
483 BUF_PT (current_buffer) += nchars;
484 BUF_PT_BYTE (current_buffer) += nbytes;
485
486 /* In a single-byte buffer, the two positions must be equal. */
487 if (ZV == ZV_BYTE
488 && PT != PT_BYTE)
489 abort ();
a27a38d8 490}
b45433b3 491\f
3be11131 492/* Make the gap NBYTES_ADDED bytes longer. */
b45433b3 493
c660b094 494void
3be11131
RS
495make_gap (nbytes_added)
496 int nbytes_added;
b45433b3
JB
497{
498 unsigned char *result;
499 Lisp_Object tem;
500 int real_gap_loc;
3be11131 501 int real_gap_loc_byte;
b45433b3
JB
502 int old_gap_size;
503
504 /* If we have to get more space, get enough to last a while. */
3be11131 505 nbytes_added += 2000;
b45433b3 506
94056516
RS
507 /* Don't allow a buffer size that won't fit in an int
508 even if it will fit in a Lisp integer.
509 That won't work because so many places use `int'. */
510
3be11131 511 if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added
68be917d 512 >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
14f6194b 513 error ("Buffer exceeds maximum size");
94056516 514
9ac0d9e0 515 BLOCK_INPUT;
469ff680 516 /* We allocate extra 1-byte `\0' at the tail for anchoring a search. */
3be11131
RS
517 result = BUFFER_REALLOC (BEG_ADDR, (Z_BYTE - BEG_BYTE
518 + GAP_SIZE + nbytes_added + 1));
9ac0d9e0 519
b45433b3 520 if (result == 0)
270c2138
RS
521 {
522 UNBLOCK_INPUT;
523 memory_full ();
524 }
525
526 /* We can't unblock until the new address is properly stored. */
b45433b3 527 BEG_ADDR = result;
270c2138 528 UNBLOCK_INPUT;
b45433b3
JB
529
530 /* Prevent quitting in move_gap. */
531 tem = Vinhibit_quit;
532 Vinhibit_quit = Qt;
533
534 real_gap_loc = GPT;
3be11131 535 real_gap_loc_byte = GPT_BYTE;
b45433b3
JB
536 old_gap_size = GAP_SIZE;
537
538 /* Call the newly allocated space a gap at the end of the whole space. */
539 GPT = Z + GAP_SIZE;
7d92db58 540 GPT_BYTE = Z_BYTE + GAP_SIZE;
3be11131 541 GAP_SIZE = nbytes_added;
b45433b3
JB
542
543 /* Move the new gap down to be consecutive with the end of the old one.
544 This adjusts the markers properly too. */
3be11131 545 gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1);
b45433b3
JB
546
547 /* Now combine the two into one large gap. */
548 GAP_SIZE += old_gap_size;
549 GPT = real_gap_loc;
3be11131 550 GPT_BYTE = real_gap_loc_byte;
b45433b3 551
469ff680
KH
552 /* Put an anchor. */
553 *(Z_ADDR) = 0;
554
b45433b3
JB
555 Vinhibit_quit = tem;
556}
557\f
2b083808
RS
558/* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
559 FROM_MULTIBYTE says whether the incoming text is multibyte.
560 TO_MULTIBYTE says whether to store the text as multibyte.
561 If FROM_MULTIBYTE != TO_MULTIBYTE, we convert.
562
563 Return the number of bytes stored at TO_ADDR. */
564
565int
566copy_text (from_addr, to_addr, nbytes,
567 from_multibyte, to_multibyte)
568 unsigned char *from_addr;
569 unsigned char *to_addr;
570 int nbytes;
571 int from_multibyte, to_multibyte;
572{
573 if (from_multibyte == to_multibyte)
574 {
575 bcopy (from_addr, to_addr, nbytes);
576 return nbytes;
577 }
578 else if (from_multibyte)
579 {
580 int nchars = 0;
581 int bytes_left = nbytes;
582
583 /* Convert multibyte to single byte. */
584 while (bytes_left > 0)
585 {
586 int thislen, c;
587 c = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
cb97b980 588 *to_addr++ = SINGLE_BYTE_CHAR_P (c) ? c : (c & 0177) + 0200;
2b083808
RS
589 from_addr += thislen;
590 bytes_left--;
591 nchars++;
592 }
593 return nchars;
594 }
595 else
596 {
597 unsigned char *initial_to_addr = to_addr;
598
599 /* Convert single-byte to multibyte. */
600 while (nbytes > 0)
601 {
602 int c = *from_addr++;
603 unsigned char workbuf[4], *str;
604 int len;
605
59a52d50 606 if (c >= 0240 && c < 0400)
2b083808 607 {
59a52d50 608 c = unibyte_char_to_multibyte (c);
2b083808
RS
609 len = CHAR_STRING (c, workbuf, str);
610 bcopy (str, to_addr, len);
611 to_addr += len;
612 nbytes--;
613 }
614 else
615 /* Special case for speed. */
616 *to_addr++ = c, nbytes--;
617 }
618 return to_addr - initial_to_addr;
619 }
620}
621
622/* Return the number of bytes it would take
623 to convert some single-byte text to multibyte.
624 The single-byte text consists of NBYTES bytes at PTR. */
625
626int
627count_size_as_multibyte (ptr, nbytes)
628 unsigned char *ptr;
629 int nbytes;
630{
631 int i;
632 int outgoing_nbytes = 0;
633
634 for (i = 0; i < nbytes; i++)
635 {
636 unsigned int c = *ptr++;
59a52d50
KH
637
638 if (c < 0240)
639 outgoing_nbytes++;
640 else
2b083808 641 {
59a52d50
KH
642 c = unibyte_char_to_multibyte (c);
643 outgoing_nbytes += XINT (Fchar_bytes (make_number (c)));
2b083808 644 }
2b083808
RS
645 }
646
647 return outgoing_nbytes;
648}
649\f
b45433b3 650/* Insert a string of specified length before point.
2b083808
RS
651 This function judges multibyteness based on
652 enable_multibyte_characters in the current buffer;
653 it never converts between single-byte and multibyte.
654
ef29f213
KH
655 DO NOT use this for the contents of a Lisp string or a Lisp buffer!
656 prepare_to_modify_buffer could relocate the text. */
b45433b3 657
c660b094 658void
3be11131 659insert (string, nbytes)
b45433b3 660 register unsigned char *string;
3be11131 661 register nbytes;
b45433b3 662{
3be11131 663 if (nbytes > 0)
395ec62e 664 {
3be11131
RS
665 int opoint = PT;
666 insert_1 (string, nbytes, 0, 1, 0);
667 signal_after_change (opoint, 0, PT - opoint);
cd11ef31
RS
668 }
669}
670
2b083808
RS
671/* Likewise, but inherit text properties from neighboring characters. */
672
c660b094 673void
3be11131 674insert_and_inherit (string, nbytes)
cd11ef31 675 register unsigned char *string;
3be11131 676 register nbytes;
cd11ef31 677{
3be11131 678 if (nbytes > 0)
cd11ef31 679 {
3be11131
RS
680 int opoint = PT;
681 insert_1 (string, nbytes, 1, 1, 0);
682 signal_after_change (opoint, 0, PT - opoint);
395ec62e
KH
683 }
684}
b45433b3 685
2b083808 686/* Insert the character C before point. Do not inherit text properties. */
3be11131 687
c660b094 688void
3be11131
RS
689insert_char (c)
690 int c;
691{
692 unsigned char workbuf[4], *str;
2b083808
RS
693 int len;
694
695 if (! NILP (current_buffer->enable_multibyte_characters))
696 len = CHAR_STRING (c, workbuf, str);
697 else
698 {
699 len = 1;
700 workbuf[0] = c;
701 str = workbuf;
702 }
3be11131
RS
703
704 insert (str, len);
705}
706
2b083808 707/* Insert the null-terminated string S before point. */
3be11131
RS
708
709void
710insert_string (s)
711 char *s;
712{
713 insert (s, strlen (s));
714}
715
716/* Like `insert' except that all markers pointing at the place where
717 the insertion happens are adjusted to point after it.
718 Don't use this function to insert part of a Lisp string,
719 since gc could happen and relocate it. */
720
721void
722insert_before_markers (string, nbytes)
723 unsigned char *string;
724 register int nbytes;
725{
726 if (nbytes > 0)
727 {
728 int opoint = PT;
729
730 insert_1 (string, nbytes, 0, 1, 1);
731 signal_after_change (opoint, 0, PT - opoint);
732 }
733}
734
2b083808
RS
735/* Likewise, but inherit text properties from neighboring characters. */
736
3be11131
RS
737void
738insert_before_markers_and_inherit (string, nbytes)
739 unsigned char *string;
740 register int nbytes;
741{
742 if (nbytes > 0)
743 {
744 int opoint = PT;
745
746 insert_1 (string, nbytes, 1, 1, 1);
747 signal_after_change (opoint, 0, PT - opoint);
748 }
749}
2b083808 750\f
3be11131
RS
751/* Subroutine used by the insert functions above. */
752
753void
754insert_1 (string, nbytes, inherit, prepare, before_markers)
395ec62e 755 register unsigned char *string;
3be11131
RS
756 register int nbytes;
757 int inherit, prepare, before_markers;
395ec62e 758{
432f78d2
RS
759 insert_1_both (string, chars_in_text (string, nbytes), nbytes,
760 inherit, prepare, before_markers);
761}
b45433b3 762
432f78d2
RS
763/* See if the bytes before POS/POS_BYTE combine with bytes
764 at the start of STRING to form a single character.
765 If so, return the number of bytes before POS/POS_BYTE
766 which combine in this way. Otherwise, return 0. */
b45433b3 767
432f78d2
RS
768int
769count_combining_before (string, length, pos, pos_byte)
770 unsigned char *string;
771 int length;
772 int pos, pos_byte;
773{
774 int opos = pos, opos_byte = pos_byte;
775 int c;
b45433b3 776
432f78d2
RS
777 if (NILP (current_buffer->enable_multibyte_characters))
778 return 0;
779 if (length == 0 || CHAR_HEAD_P (*string))
780 return 0;
781 if (pos == BEGV)
782 return 0;
783 c = FETCH_BYTE (pos_byte - 1);
784 if (ASCII_BYTE_P (c))
785 return 0;
786 DEC_BOTH (pos, pos_byte);
787 c = FETCH_BYTE (pos_byte);
788 if (! BASE_LEADING_CODE_P (c))
789 return 0;
790 return opos_byte - pos_byte;
791}
b45433b3 792
432f78d2
RS
793/* See if the bytes after POS/POS_BYTE combine with bytes
794 at the end of STRING to form a single character.
795 If so, return the number of bytes after POS/POS_BYTE
796 which combine in this way. Otherwise, return 0. */
679194a6 797
432f78d2
RS
798int
799count_combining_after (string, length, pos, pos_byte)
800 unsigned char *string;
801 int length;
802 int pos, pos_byte;
803{
804 int opos = pos, opos_byte = pos_byte;
805 int i;
806 int c;
3be11131 807
432f78d2
RS
808 if (NILP (current_buffer->enable_multibyte_characters))
809 return 0;
810 if (length == 0 || ASCII_BYTE_P (string[length - 1]))
811 return 0;
812 i = length - 1;
813 while (i > 0 && ! CHAR_HEAD_P (string[i]))
814 {
815 i--;
816 }
817 if (! BASE_LEADING_CODE_P (string[i]))
818 return 0;
819
820 if (pos == ZV)
821 return 0;
822 c = FETCH_BYTE (pos_byte);
823 if (CHAR_HEAD_P (c))
824 return 0;
825 while (pos_byte < ZV_BYTE)
826 {
827 c = FETCH_BYTE (pos_byte);
828 if (CHAR_HEAD_P (c))
829 break;
830 pos_byte++;
831 }
cd11ef31 832
432f78d2 833 return pos_byte - opos_byte;
b45433b3 834}
2b083808
RS
835
836/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
837 starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS
838 are the same as in insert_1. */
839
840void
841insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
842 register unsigned char *string;
843 register int nchars, nbytes;
844 int inherit, prepare, before_markers;
845{
846 register Lisp_Object temp;
432f78d2
RS
847 int combined_before_bytes, combined_after_bytes;
848 int adjusted_nchars;
2b083808 849
57404188
KH
850 if (NILP (current_buffer->enable_multibyte_characters))
851 nchars = nbytes;
852
2b083808
RS
853 if (PT != GPT)
854 move_gap_both (PT, PT_BYTE);
855 if (GAP_SIZE < nbytes)
856 make_gap (nbytes - GAP_SIZE);
857
432f78d2
RS
858 combined_before_bytes = count_combining_before (string, nbytes, PT, PT_BYTE);
859 combined_after_bytes = count_combining_after (string, nbytes, PT, PT_BYTE);
860
861 /* This is the net amount that Z will increase from this insertion. */
862 adjusted_nchars = nchars - !!combined_before_bytes - !!combined_after_bytes;
863
864 if (prepare)
865 prepare_to_modify_buffer (PT - !!combined_before_bytes,
866 PT + !!combined_after_bytes,
867 NULL);
868
869 /* Record deletion of the surrounding text that combines with
870 the insertion. This, together with recording the insertion,
871 will add up to the right stuff in the undo list.
872
873 But there is no need to actually delete the combining bytes
874 from the buffer and reinsert them. */
875
876 if (combined_after_bytes)
877 record_delete (PT, 1);
878
879 if (combined_before_bytes)
880 record_delete (PT - 1, 1);
881
882 record_insert (PT - !!combined_before_bytes, nchars);
2b083808
RS
883 MODIFF++;
884
885 bcopy (string, GPT_ADDR, nbytes);
886
887#ifdef USE_TEXT_PROPERTIES
888 if (BUF_INTERVALS (current_buffer) != 0)
889 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
432f78d2 890 offset_intervals (current_buffer, PT, adjusted_nchars);
2b083808
RS
891#endif
892
893 GAP_SIZE -= nbytes;
432f78d2
RS
894 GPT += adjusted_nchars;
895 ZV += adjusted_nchars;
896 Z += adjusted_nchars;
2b083808
RS
897 GPT_BYTE += nbytes;
898 ZV_BYTE += nbytes;
899 Z_BYTE += nbytes;
900 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
432f78d2
RS
901 adjust_overlays_for_insert (PT, adjusted_nchars);
902 adjust_markers_for_insert (PT, PT_BYTE,
903 PT + adjusted_nchars, PT_BYTE + nbytes,
904 combined_before_bytes, combined_after_bytes,
2b083808 905 before_markers);
432f78d2
RS
906 adjust_point (adjusted_nchars + !!combined_after_bytes,
907 nbytes + combined_after_bytes);
908
909 if (combined_after_bytes)
910 move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
2b083808
RS
911
912 if (GPT_BYTE < GPT)
913 abort ();
914
915#ifdef USE_TEXT_PROPERTIES
916 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
432f78d2 917 Fset_text_properties (make_number (PT - adjusted_nchars), make_number (PT),
2b083808
RS
918 Qnil, Qnil);
919#endif
920}
3be11131 921\f
679194a6 922/* Insert the part of the text of STRING, a Lisp object assumed to be
2b083808
RS
923 of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes)
924 starting at position POS / POS_BYTE. If the text of STRING has properties,
925 copy them into the buffer.
679194a6
JA
926
927 It does not work to use `insert' for this, because a GC could happen
7e1ea612
JB
928 before we bcopy the stuff into the buffer, and relocate the string
929 without insert noticing. */
679194a6 930
c660b094 931void
2b083808 932insert_from_string (string, pos, pos_byte, length, length_byte, inherit)
b45433b3 933 Lisp_Object string;
2b083808 934 register int pos, pos_byte, length, length_byte;
9391e591 935 int inherit;
395ec62e
KH
936{
937 if (length > 0)
938 {
3be11131 939 int opoint = PT;
2b083808
RS
940 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
941 inherit, 0);
3be11131 942 signal_after_change (opoint, 0, PT - opoint);
395ec62e
KH
943 }
944}
945
2b083808
RS
946/* Like `insert_from_string' except that all markers pointing
947 at the place where the insertion happens are adjusted to point after it. */
3be11131
RS
948
949void
2b083808
RS
950insert_from_string_before_markers (string, pos, pos_byte,
951 length, length_byte, inherit)
395ec62e 952 Lisp_Object string;
2b083808 953 register int pos, pos_byte, length, length_byte;
395ec62e 954 int inherit;
3be11131
RS
955{
956 if (length > 0)
957 {
958 int opoint = PT;
2b083808
RS
959 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
960 inherit, 1);
3be11131
RS
961 signal_after_change (opoint, 0, PT - opoint);
962 }
963}
964
965/* Subroutine of the insertion functions above. */
966
967static void
2b083808
RS
968insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
969 inherit, before_markers)
3be11131 970 Lisp_Object string;
2b083808 971 register int pos, pos_byte, nchars, nbytes;
3be11131 972 int inherit, before_markers;
b45433b3
JB
973{
974 register Lisp_Object temp;
975 struct gcpro gcpro1;
2b083808 976 int outgoing_nbytes = nbytes;
432f78d2
RS
977 int combined_before_bytes, combined_after_bytes;
978 int adjusted_nchars;
2b083808
RS
979
980 /* Make OUTGOING_NBYTES describe the text
981 as it will be inserted in this buffer. */
982
983 if (NILP (current_buffer->enable_multibyte_characters))
984 outgoing_nbytes = nchars;
985 else if (nchars == nbytes)
986 outgoing_nbytes
987 = count_size_as_multibyte (&XSTRING (string)->data[pos_byte],
988 nbytes);
b45433b3 989
b45433b3 990 /* Make sure point-max won't overflow after this insertion. */
2b083808
RS
991 XSETINT (temp, outgoing_nbytes + Z);
992 if (outgoing_nbytes + Z != XINT (temp))
3be11131 993 error ("Maximum buffer size exceeded");
b45433b3
JB
994
995 GCPRO1 (string);
d206af14 996 prepare_to_modify_buffer (PT, PT, NULL);
b45433b3 997
2bcaed71 998 if (PT != GPT)
3be11131
RS
999 move_gap_both (PT, PT_BYTE);
1000 if (GAP_SIZE < nbytes)
2b083808 1001 make_gap (outgoing_nbytes - GAP_SIZE);
b45433b3
JB
1002 UNGCPRO;
1003
2b083808
RS
1004 /* Copy the string text into the buffer, perhaps converting
1005 between single-byte and multibyte. */
1006 copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes,
1007 /* If these are equal, it is a single-byte string.
1008 Its chars are either ASCII, in which case copy_text
1009 won't change it, or single-byte non-ASCII chars,
1010 that need to be changed. */
1011 nchars != nbytes,
1012 ! NILP (current_buffer->enable_multibyte_characters));
b45433b3 1013
432f78d2
RS
1014 /* We have copied text into the gap, but we have not altered
1015 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1016 to these functions and get the same results as we would
1017 have got earlier on. Meanwhile, PT_ADDR does point to
1018 the text that has been stored by copy_text. */
1019
1020 combined_before_bytes
1021 = count_combining_before (XSTRING (string)->data + pos_byte, nbytes,
1022 PT, PT_BYTE);
1023 combined_after_bytes
1024 = count_combining_after (XSTRING (string)->data + pos_byte, nbytes,
1025 PT, PT_BYTE);
1026
1027 /* This is the net amount that Z will increase from this insertion. */
1028 adjusted_nchars = nchars - !!combined_before_bytes - !!combined_after_bytes;
1029
1030 /* Record deletion of the surrounding text that combines with
1031 the insertion. This, together with recording the insertion,
1032 will add up to the right stuff in the undo list.
1033
1034 But there is no need to actually delete the combining bytes
1035 from the buffer and reinsert them. */
1036
1037 if (combined_after_bytes)
1038 record_delete (PT, 1);
1039
1040 if (combined_before_bytes)
1041 record_delete (PT - 1, 1);
1042
1043 record_insert (PT - !!combined_before_bytes, nchars);
1044 MODIFF++;
1045
679194a6 1046 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
432f78d2 1047 offset_intervals (current_buffer, PT, adjusted_nchars);
3be11131 1048
7792090e 1049 GAP_SIZE -= outgoing_nbytes;
432f78d2
RS
1050 GPT += adjusted_nchars;
1051 ZV += adjusted_nchars;
1052 Z += adjusted_nchars;
2b083808
RS
1053 GPT_BYTE += outgoing_nbytes;
1054 ZV_BYTE += outgoing_nbytes;
1055 Z_BYTE += outgoing_nbytes;
469ff680 1056 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
432f78d2
RS
1057 adjust_overlays_for_insert (PT, adjusted_nchars);
1058 adjust_markers_for_insert (PT, PT_BYTE, PT + adjusted_nchars,
2b083808 1059 PT_BYTE + outgoing_nbytes,
432f78d2 1060 combined_before_bytes, combined_after_bytes,
3be11131
RS
1061 before_markers);
1062
432f78d2
RS
1063 if (combined_after_bytes)
1064 move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
1065
3be11131
RS
1066 if (GPT_BYTE < GPT)
1067 abort ();
679194a6 1068
3be11131 1069 graft_intervals_into_buffer (XSTRING (string)->intervals, PT, nchars,
9391e591 1070 current_buffer, inherit);
432f78d2
RS
1071 adjust_point (adjusted_nchars + !!combined_after_bytes,
1072 outgoing_nbytes + combined_after_bytes);
b45433b3 1073}
3be11131
RS
1074\f
1075/* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
ef29f213
KH
1076 current buffer. If the text in BUF has properties, they are absorbed
1077 into the current buffer.
1078
1079 It does not work to use `insert' for this, because a malloc could happen
1080 and relocate BUF's text before the bcopy happens. */
1081
1082void
3be11131 1083insert_from_buffer (buf, charpos, nchars, inherit)
ef29f213 1084 struct buffer *buf;
3be11131 1085 int charpos, nchars;
ef29f213
KH
1086 int inherit;
1087{
3be11131 1088 if (nchars > 0)
ef29f213 1089 {
3be11131
RS
1090 int opoint = PT;
1091
1092 insert_from_buffer_1 (buf, charpos, nchars, inherit);
1093 signal_after_change (opoint, 0, PT - opoint);
ef29f213
KH
1094 }
1095}
1096
1097static void
3be11131 1098insert_from_buffer_1 (buf, from, nchars, inherit)
ef29f213 1099 struct buffer *buf;
3be11131 1100 int from, nchars;
ef29f213
KH
1101 int inherit;
1102{
1103 register Lisp_Object temp;
1104 int chunk;
3be11131
RS
1105 int from_byte = buf_charpos_to_bytepos (buf, from);
1106 int to_byte = buf_charpos_to_bytepos (buf, from + nchars);
2b083808
RS
1107 int incoming_nbytes = to_byte - from_byte;
1108 int outgoing_nbytes = incoming_nbytes;
432f78d2
RS
1109 int combined_before_bytes, combined_after_bytes;
1110 int adjusted_nchars;
2b083808
RS
1111
1112 /* Make OUTGOING_NBYTES describe the text
1113 as it will be inserted in this buffer. */
1114
1115 if (NILP (current_buffer->enable_multibyte_characters))
1116 outgoing_nbytes = nchars;
1117 else if (NILP (buf->enable_multibyte_characters))
1118 outgoing_nbytes
1119 = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
1120 incoming_nbytes);
ef29f213
KH
1121
1122 /* Make sure point-max won't overflow after this insertion. */
2b083808
RS
1123 XSETINT (temp, outgoing_nbytes + Z);
1124 if (outgoing_nbytes + Z != XINT (temp))
3be11131 1125 error ("Maximum buffer size exceeded");
ef29f213 1126
d206af14 1127 prepare_to_modify_buffer (PT, PT, NULL);
ef29f213
KH
1128
1129 if (PT != GPT)
3be11131 1130 move_gap_both (PT, PT_BYTE);
2b083808
RS
1131 if (GAP_SIZE < outgoing_nbytes)
1132 make_gap (outgoing_nbytes - GAP_SIZE);
ef29f213 1133
3be11131 1134 if (from < BUF_GPT (buf))
ef29f213 1135 {
3be11131 1136 chunk = BUF_GPT_BYTE (buf) - from_byte;
2b083808
RS
1137 if (chunk > incoming_nbytes)
1138 chunk = incoming_nbytes;
1139 copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
1140 GPT_ADDR, chunk,
1141 ! NILP (buf->enable_multibyte_characters),
1142 ! NILP (current_buffer->enable_multibyte_characters));
ef29f213
KH
1143 }
1144 else
1145 chunk = 0;
2b083808
RS
1146 if (chunk < incoming_nbytes)
1147 copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
1148 GPT_ADDR + chunk, incoming_nbytes - chunk,
1149 ! NILP (buf->enable_multibyte_characters),
1150 ! NILP (current_buffer->enable_multibyte_characters));
ef29f213 1151
432f78d2
RS
1152 /* We have copied text into the gap, but we have not altered
1153 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1154 to these functions and get the same results as we would
1155 have got earlier on. Meanwhile, PT_ADDR does point to
1156 the text that has been stored by copy_text. */
1157 combined_before_bytes
1158 = count_combining_before (PT_ADDR, outgoing_nbytes, PT, PT_BYTE);
1159 combined_after_bytes
1160 = count_combining_after (PT_ADDR, outgoing_nbytes,
1161 PT, PT_BYTE);
1162
1163 /* This is the net amount that Z will increase from this insertion. */
1164 adjusted_nchars = nchars - !!combined_before_bytes - !!combined_after_bytes;
1165
1166 /* Record deletion of the surrounding text that combines with
1167 the insertion. This, together with recording the insertion,
1168 will add up to the right stuff in the undo list.
1169
1170 But there is no need to actually delete the combining bytes
1171 from the buffer and reinsert them. */
1172
1173 if (combined_after_bytes)
1174 record_delete (PT, 1);
1175
1176 if (combined_before_bytes)
1177 record_delete (PT - 1, 1);
1178
1179 record_insert (PT - !!combined_before_bytes, nchars);
1180 MODIFF++;
1181
ef29f213 1182#ifdef USE_TEXT_PROPERTIES
9fbf87cd 1183 if (BUF_INTERVALS (current_buffer) != 0)
432f78d2 1184 offset_intervals (current_buffer, PT, adjusted_nchars);
ef29f213
KH
1185#endif
1186
2b083808 1187 GAP_SIZE -= outgoing_nbytes;
432f78d2
RS
1188 GPT += adjusted_nchars;
1189 ZV += adjusted_nchars;
1190 Z += adjusted_nchars;
2b083808
RS
1191 GPT_BYTE += outgoing_nbytes;
1192 ZV_BYTE += outgoing_nbytes;
1193 Z_BYTE += outgoing_nbytes;
469ff680 1194 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
432f78d2
RS
1195 adjust_overlays_for_insert (PT, adjusted_nchars);
1196 adjust_markers_for_insert (PT, PT_BYTE, PT + adjusted_nchars,
1197 PT_BYTE + outgoing_nbytes,
1198 combined_before_bytes, combined_after_bytes, 0);
1199 adjust_point (adjusted_nchars + !!combined_after_bytes,
1200 outgoing_nbytes + combined_after_bytes);
1201
1202 if (combined_after_bytes)
1203 move_gap_both (GPT + 1, GPT_BYTE + combined_after_bytes);
3be11131
RS
1204
1205 if (GPT_BYTE < GPT)
1206 abort ();
ef29f213
KH
1207
1208 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
9fbf87cd 1209 graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
3be11131 1210 from, nchars),
432f78d2 1211 PT - adjusted_nchars, adjusted_nchars,
3be11131 1212 current_buffer, inherit);
b45433b3
JB
1213}
1214\f
2d9eea44 1215/* This function should be called after moving gap to FROM and before
59a52d50
KH
1216 altering text between FROM and TO. This adjusts various position
1217 keepers and markers as if the text is deleted. Don't forget to
1218 call adjust_after_replace after you actually alter the text. */
2d9eea44 1219
1e9c7b7d
KH
1220void
1221adjust_before_replace (from, from_byte, to, to_byte)
1222 int from, from_byte, to, to_byte;
1223{
1224 adjust_markers_for_delete (from, from_byte, to, to_byte);
1225 record_delete (from, to - from);
1226}
1227
2d9eea44 1228/* This function should be called after altering the text between FROM
432f78d2
RS
1229 and TO to a new text of LEN chars (LEN_BYTE bytes).
1230 COMBINED_BEFORE_BYTES and COMBINED_AFTER_BYTES are the number
1231 of bytes before (resp. after) the change which combine with
1232 the beginning or end of the replacement text to form one character. */
2d9eea44 1233
1e9c7b7d 1234void
432f78d2
RS
1235adjust_after_replace (from, from_byte, to, to_byte, len, len_byte,
1236 combined_before_bytes, combined_after_bytes)
1e9c7b7d 1237 int from, from_byte, to, to_byte, len, len_byte;
432f78d2 1238 int combined_before_bytes, combined_after_bytes;
1e9c7b7d 1239{
432f78d2
RS
1240 int adjusted_nchars = len - !!combined_before_bytes - !!combined_after_bytes;
1241 record_insert (from - !!combined_before_bytes, len);
1e9c7b7d 1242 if (from < PT)
432f78d2
RS
1243 adjust_point (len - (to - from) + !!combined_after_bytes,
1244 len_byte - (to_byte - from_byte) + combined_after_bytes);
1e9c7b7d 1245#ifdef USE_TEXT_PROPERTIES
432f78d2 1246 offset_intervals (current_buffer, PT, adjusted_nchars - (to - from));
1e9c7b7d
KH
1247#endif
1248 adjust_overlays_for_delete (from, to - from);
432f78d2 1249 adjust_overlays_for_insert (from, adjusted_nchars);
1e9c7b7d 1250 adjust_markers_for_insert (from, from_byte,
432f78d2
RS
1251 from + adjusted_nchars, from_byte + len_byte,
1252 combined_before_bytes, combined_after_bytes, 0);
1e9c7b7d
KH
1253 if (len == 0)
1254 evaporate_overlays (from);
1255 MODIFF++;
1e9c7b7d
KH
1256}
1257
3be11131 1258/* Replace the text from character positions FROM to TO with NEW,
c5ca4d3a
RS
1259 If PREPARE is nonzero, call prepare_to_modify_buffer.
1260 If INHERIT, the newly inserted text should inherit text properties
1261 from the surrounding non-deleted text. */
1262
1263/* Note that this does not yet handle markers quite right.
1264 Also it needs to record a single undo-entry that does a replacement
1265 rather than a separate delete and insert.
1266 That way, undo will also handle markers properly. */
1267
1268void
1269replace_range (from, to, new, prepare, inherit)
1270 Lisp_Object new;
1271 int from, to, prepare, inherit;
1272{
2b083808
RS
1273 int inschars = XSTRING (new)->size;
1274 int insbytes = XSTRING (new)->size_byte;
3be11131
RS
1275 int from_byte, to_byte;
1276 int nbytes_del, nchars_del;
c5ca4d3a
RS
1277 register Lisp_Object temp;
1278 struct gcpro gcpro1;
432f78d2
RS
1279 int combined_before_bytes, combined_after_bytes;
1280 int adjusted_inschars;
c5ca4d3a
RS
1281
1282 GCPRO1 (new);
1283
1284 if (prepare)
1285 {
1286 int range_length = to - from;
1287 prepare_to_modify_buffer (from, to, &from);
1288 to = from + range_length;
1289 }
1290
3be11131
RS
1291 UNGCPRO;
1292
c5ca4d3a
RS
1293 /* Make args be valid */
1294 if (from < BEGV)
1295 from = BEGV;
1296 if (to > ZV)
1297 to = ZV;
1298
3be11131
RS
1299 from_byte = CHAR_TO_BYTE (from);
1300 to_byte = CHAR_TO_BYTE (to);
c5ca4d3a 1301
3be11131
RS
1302 nchars_del = to - from;
1303 nbytes_del = to_byte - from_byte;
1304
1305 if (nbytes_del <= 0 && insbytes == 0)
1306 return;
c5ca4d3a
RS
1307
1308 /* Make sure point-max won't overflow after this insertion. */
3be11131
RS
1309 XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
1310 if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
1311 error ("Maximum buffer size exceeded");
c5ca4d3a 1312
c5ca4d3a
RS
1313 GCPRO1 (new);
1314
1315 /* Make sure the gap is somewhere in or next to what we are deleting. */
1316 if (from > GPT)
3be11131 1317 gap_right (from, from_byte);
c5ca4d3a 1318 if (to < GPT)
3be11131 1319 gap_left (to, to_byte, 0);
c5ca4d3a
RS
1320
1321 /* Relocate all markers pointing into the new, larger gap
1322 to point at the end of the text before the gap.
3be11131
RS
1323 Do this before recording the deletion,
1324 so that undo handles this after reinserting the text. */
1325 adjust_markers_for_delete (from, from_byte, to, to_byte);
c5ca4d3a 1326
3be11131 1327 record_delete (from, nchars_del);
c5ca4d3a 1328
3be11131
RS
1329 GAP_SIZE += nbytes_del;
1330 ZV -= nchars_del;
1331 Z -= nchars_del;
1332 ZV_BYTE -= nbytes_del;
1333 Z_BYTE -= nbytes_del;
c5ca4d3a 1334 GPT = from;
3be11131 1335 GPT_BYTE = from_byte;
c5ca4d3a
RS
1336 *(GPT_ADDR) = 0; /* Put an anchor. */
1337
3be11131
RS
1338 if (GPT_BYTE < GPT)
1339 abort ();
1340
c5ca4d3a
RS
1341 if (GPT - BEG < beg_unchanged)
1342 beg_unchanged = GPT - BEG;
1343 if (Z - GPT < end_unchanged)
1344 end_unchanged = Z - GPT;
1345
3be11131
RS
1346 if (GAP_SIZE < insbytes)
1347 make_gap (insbytes - GAP_SIZE);
c5ca4d3a 1348
432f78d2
RS
1349 /* We have copied text into the gap, but we have not altered
1350 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1351 to these functions and get the same results as we would
1352 have got earlier on. Meanwhile, PT_ADDR does point to
1353 the text that has been stored by copy_text. */
1354
1355 combined_before_bytes
1356 = count_combining_before (XSTRING (new)->data, insbytes, PT, PT_BYTE);
1357 combined_after_bytes
1358 = count_combining_after (XSTRING (new)->data, insbytes, PT, PT_BYTE);
1359
1360 /* This is the net amount that Z will increase from this insertion. */
1361 adjusted_inschars
1362 = inschars - !!combined_before_bytes - !!combined_after_bytes;
1363
1364 /* Record deletion of the surrounding text that combines with
1365 the insertion. This, together with recording the insertion,
1366 will add up to the right stuff in the undo list.
1367
1368 But there is no need to actually delete the combining bytes
1369 from the buffer and reinsert them. */
1370
1371 if (combined_after_bytes)
1372 record_delete (PT, 1);
1373
1374 if (combined_before_bytes)
1375 record_delete (PT - 1, 1);
1376
3be11131 1377 record_insert (from, inschars);
c5ca4d3a 1378
3be11131 1379 bcopy (XSTRING (new)->data, GPT_ADDR, insbytes);
c5ca4d3a
RS
1380
1381 /* Relocate point as if it were a marker. */
1382 if (from < PT)
432f78d2
RS
1383 adjust_point ((from + adjusted_inschars - (PT < to ? PT : to)
1384 + !!combined_after_bytes),
3be11131 1385 (from_byte + insbytes
432f78d2
RS
1386 - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
1387 + combined_after_bytes));
c5ca4d3a
RS
1388
1389#ifdef USE_TEXT_PROPERTIES
432f78d2 1390 offset_intervals (current_buffer, PT, adjusted_inschars - nchars_del);
c5ca4d3a
RS
1391#endif
1392
3be11131 1393 GAP_SIZE -= insbytes;
432f78d2
RS
1394 GPT += adjusted_inschars;
1395 ZV += adjusted_inschars;
1396 Z += adjusted_inschars;
3be11131
RS
1397 GPT_BYTE += insbytes;
1398 ZV_BYTE += insbytes;
1399 ZV_BYTE += insbytes;
c5ca4d3a
RS
1400 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1401
3be11131
RS
1402 if (GPT_BYTE < GPT)
1403 abort ();
1404
c5ca4d3a
RS
1405 /* Adjust the overlay center as needed. This must be done after
1406 adjusting the markers that bound the overlays. */
3be11131 1407 adjust_overlays_for_delete (from, nchars_del);
432f78d2
RS
1408 adjust_overlays_for_insert (from, adjusted_inschars);
1409 adjust_markers_for_insert (from, from_byte, from + adjusted_inschars,
1410 from_byte + insbytes,
1411 combined_before_bytes, combined_after_bytes, 0);
c5ca4d3a
RS
1412
1413#ifdef USE_TEXT_PROPERTIES
1414 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
3be11131
RS
1415 graft_intervals_into_buffer (XSTRING (new)->intervals, from,
1416 inschars, current_buffer, inherit);
c5ca4d3a
RS
1417#endif
1418
3be11131 1419 if (insbytes == 0)
c5ca4d3a
RS
1420 evaporate_overlays (from);
1421
1422 MODIFF++;
1423 UNGCPRO;
1424
432f78d2 1425 signal_after_change (from, nchars_del, adjusted_inschars);
c5ca4d3a
RS
1426}
1427\f
b45433b3 1428/* Delete characters in current buffer
3be11131
RS
1429 from FROM up to (but not including) TO.
1430 If TO comes before FROM, we delete nothing. */
b45433b3 1431
c660b094 1432void
b45433b3
JB
1433del_range (from, to)
1434 register int from, to;
47c64747 1435{
c660b094 1436 del_range_1 (from, to, 1);
47c64747
RS
1437}
1438
1439/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */
1440
c660b094 1441void
47c64747 1442del_range_1 (from, to, prepare)
d206af14 1443 int from, to, prepare;
b45433b3 1444{
3be11131
RS
1445 int from_byte, to_byte;
1446
1447 /* Make args be valid */
1448 if (from < BEGV)
1449 from = BEGV;
1450 if (to > ZV)
1451 to = ZV;
1452
1453 if (to <= from)
1454 return;
1455
1456 if (prepare)
1457 {
1458 int range_length = to - from;
1459 prepare_to_modify_buffer (from, to, &from);
1460 to = from + range_length;
1461 }
1462
1463 from_byte = CHAR_TO_BYTE (from);
1464 to_byte = CHAR_TO_BYTE (to);
1465
a66afea0 1466 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
1467}
1468
1469/* Like del_range_1 but args are byte positions, not char positions. */
1470
1471void
1472del_range_byte (from_byte, to_byte, prepare)
1473 int from_byte, to_byte, prepare;
1474{
1475 int from, to;
1476
1477 /* Make args be valid */
1478 if (from_byte < BEGV_BYTE)
1479 from_byte = BEGV_BYTE;
1480 if (to_byte > ZV_BYTE)
1481 to_byte = ZV_BYTE;
1482
1483 if (to_byte <= from_byte)
1484 return;
1485
1486 from = BYTE_TO_CHAR (from_byte);
1487 to = BYTE_TO_CHAR (to_byte);
b45433b3 1488
d206af14
RS
1489 if (prepare)
1490 {
3be11131 1491 int old_from = from, old_to = Z - to;
d206af14
RS
1492 int range_length = to - from;
1493 prepare_to_modify_buffer (from, to, &from);
1494 to = from + range_length;
3be11131
RS
1495
1496 if (old_from != from)
1497 from_byte = CHAR_TO_BYTE (from);
1498 if (old_to == Z - to)
1499 to_byte = CHAR_TO_BYTE (to);
d206af14
RS
1500 }
1501
a66afea0 1502 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
1503}
1504
1505/* Like del_range_1, but positions are specified both as charpos
1506 and bytepos. */
1507
1508void
353800c7
KH
1509del_range_both (from, from_byte, to, to_byte, prepare)
1510 int from, from_byte, to, to_byte, prepare;
3be11131 1511{
b45433b3 1512 /* Make args be valid */
3be11131
RS
1513 if (from_byte < BEGV_BYTE)
1514 from_byte = BEGV_BYTE;
1515 if (to_byte > ZV_BYTE)
1516 to_byte = ZV_BYTE;
1517
1518 if (to_byte <= from_byte)
1519 return;
1520
b45433b3
JB
1521 if (from < BEGV)
1522 from = BEGV;
1523 if (to > ZV)
1524 to = ZV;
1525
3be11131
RS
1526 if (prepare)
1527 {
1528 int old_from = from, old_to = Z - to;
1529 int range_length = to - from;
1530 prepare_to_modify_buffer (from, to, &from);
1531 to = from + range_length;
1532
1533 if (old_from != from)
1534 from_byte = CHAR_TO_BYTE (from);
1535 if (old_to == Z - to)
1536 to_byte = CHAR_TO_BYTE (to);
1537 }
1538
a66afea0 1539 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
1540}
1541
1542/* Delete a range of text, specified both as character positions
1543 and byte positions. FROM and TO are character positions,
1544 while FROM_BYTE and TO_BYTE are byte positions. */
1545
1546void
a66afea0
KH
1547del_range_2 (from, from_byte, to, to_byte)
1548 int from, from_byte, to, to_byte;
3be11131
RS
1549{
1550 register int nbytes_del, nchars_del;
1551
1552 nchars_del = to - from;
1553 nbytes_del = to_byte - from_byte;
b45433b3
JB
1554
1555 /* Make sure the gap is somewhere in or next to what we are deleting. */
1556 if (from > GPT)
3be11131 1557 gap_right (from, from_byte);
b45433b3 1558 if (to < GPT)
3be11131 1559 gap_left (to, to_byte, 0);
b45433b3 1560
8948d317
RS
1561 /* Relocate all markers pointing into the new, larger gap
1562 to point at the end of the text before the gap.
3be11131
RS
1563 Do this before recording the deletion,
1564 so that undo handles this after reinserting the text. */
1565 adjust_markers_for_delete (from, from_byte, to, to_byte);
8948d317 1566
3be11131 1567 record_delete (from, nchars_del);
be09561e
RS
1568 MODIFF++;
1569
b45433b3 1570 /* Relocate point as if it were a marker. */
2bcaed71 1571 if (from < PT)
3be11131
RS
1572 adjust_point (from - (PT < to ? PT : to),
1573 from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte));
b45433b3 1574
16032db6 1575 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
3be11131 1576 offset_intervals (current_buffer, from, - nchars_del);
16032db6 1577
adde4858 1578 /* Adjust the overlay center as needed. This must be done after
a7f38d28 1579 adjusting the markers that bound the overlays. */
3be11131 1580 adjust_overlays_for_delete (from_byte, nchars_del);
adde4858 1581
3be11131
RS
1582 GAP_SIZE += nbytes_del;
1583 ZV_BYTE -= nbytes_del;
1584 Z_BYTE -= nbytes_del;
1585 ZV -= nchars_del;
1586 Z -= nchars_del;
b45433b3 1587 GPT = from;
3be11131 1588 GPT_BYTE = from_byte;
469ff680 1589 *(GPT_ADDR) = 0; /* Put an anchor. */
b45433b3 1590
3be11131
RS
1591 if (GPT_BYTE < GPT)
1592 abort ();
1593
b45433b3
JB
1594 if (GPT - BEG < beg_unchanged)
1595 beg_unchanged = GPT - BEG;
1596 if (Z - GPT < end_unchanged)
1597 end_unchanged = Z - GPT;
1598
d386034e 1599 evaporate_overlays (from);
3be11131 1600 signal_after_change (from, nchars_del, 0);
b45433b3
JB
1601}
1602\f
3be11131
RS
1603/* Call this if you're about to change the region of BUFFER from
1604 character positions START to END. This checks the read-only
1605 properties of the region, calls the necessary modification hooks,
1606 and warns the next redisplay that it should pay attention to that
1607 area. */
1608
c660b094 1609void
04a759c8
JB
1610modify_region (buffer, start, end)
1611 struct buffer *buffer;
b45433b3
JB
1612 int start, end;
1613{
04a759c8
JB
1614 struct buffer *old_buffer = current_buffer;
1615
1616 if (buffer != old_buffer)
1617 set_buffer_internal (buffer);
1618
d206af14 1619 prepare_to_modify_buffer (start, end, NULL);
b45433b3 1620
894ab630
RS
1621 if (start - 1 < beg_unchanged
1622 || (unchanged_modified == MODIFF
1623 && overlay_unchanged_modified == OVERLAY_MODIFF))
b45433b3
JB
1624 beg_unchanged = start - 1;
1625 if (Z - end < end_unchanged
894ab630
RS
1626 || (unchanged_modified == MODIFF
1627 && overlay_unchanged_modified == OVERLAY_MODIFF))
b45433b3 1628 end_unchanged = Z - end;
83010cd6 1629
9fbf87cd 1630 if (MODIFF <= SAVE_MODIFF)
83010cd6 1631 record_first_change ();
b45433b3 1632 MODIFF++;
04a759c8 1633
069cdc4f
RS
1634 buffer->point_before_scroll = Qnil;
1635
04a759c8
JB
1636 if (buffer != old_buffer)
1637 set_buffer_internal (old_buffer);
b45433b3 1638}
d206af14 1639\f
3be11131
RS
1640/* Check that it is okay to modify the buffer between START and END,
1641 which are char positions.
1642
679194a6
JA
1643 Run the before-change-function, if any. If intervals are in use,
1644 verify that the text to be modified is not read-only, and call
d206af14
RS
1645 any modification properties the text may have.
1646
1647 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1648 by holding its value temporarily in a marker. */
b45433b3 1649
c660b094 1650void
d206af14 1651prepare_to_modify_buffer (start, end, preserve_ptr)
fb4ee5cd 1652 int start, end;
d206af14 1653 int *preserve_ptr;
b45433b3 1654{
d427b66a 1655 if (!NILP (current_buffer->read_only))
b45433b3
JB
1656 Fbarf_if_buffer_read_only ();
1657
679194a6 1658 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
9fbf87cd 1659 if (BUF_INTERVALS (current_buffer) != 0)
d206af14
RS
1660 {
1661 if (preserve_ptr)
1662 {
1663 Lisp_Object preserve_marker;
1664 struct gcpro gcpro1;
1665 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil);
1666 GCPRO1 (preserve_marker);
1667 verify_interval_modification (current_buffer, start, end);
1668 *preserve_ptr = marker_position (preserve_marker);
1669 unchain_marker (preserve_marker);
1670 UNGCPRO;
1671 }
1672 else
1673 verify_interval_modification (current_buffer, start, end);
1674 }
b45433b3
JB
1675
1676#ifdef CLASH_DETECTION
f173b650 1677 if (!NILP (current_buffer->file_truename)
ab6c5c0c
RS
1678 /* Make binding buffer-file-name to nil effective. */
1679 && !NILP (current_buffer->filename)
9fbf87cd 1680 && SAVE_MODIFF >= MODIFF)
f173b650 1681 lock_file (current_buffer->file_truename);
b45433b3
JB
1682#else
1683 /* At least warn if this file has changed on disk since it was visited. */
d427b66a 1684 if (!NILP (current_buffer->filename)
9fbf87cd 1685 && SAVE_MODIFF >= MODIFF
d427b66a
JB
1686 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
1687 && !NILP (Ffile_exists_p (current_buffer->filename)))
b45433b3
JB
1688 call1 (intern ("ask-user-about-supersession-threat"),
1689 current_buffer->filename);
1690#endif /* not CLASH_DETECTION */
1691
d206af14 1692 signal_before_change (start, end, preserve_ptr);
2f545eea 1693
56e1065e
JB
1694 if (current_buffer->newline_cache)
1695 invalidate_region_cache (current_buffer,
1696 current_buffer->newline_cache,
1697 start - BEG, Z - end);
1698 if (current_buffer->width_run_cache)
1699 invalidate_region_cache (current_buffer,
1700 current_buffer->width_run_cache,
1701 start - BEG, Z - end);
1702
2f545eea 1703 Vdeactivate_mark = Qt;
b45433b3
JB
1704}
1705\f
d206af14
RS
1706/* These macros work with an argument named `preserve_ptr'
1707 and a local variable named `preserve_marker'. */
1708
1709#define PRESERVE_VALUE \
1710 if (preserve_ptr && NILP (preserve_marker)) \
1711 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
1712
1713#define RESTORE_VALUE \
1714 if (! NILP (preserve_marker)) \
1715 { \
1716 *preserve_ptr = marker_position (preserve_marker); \
1717 unchain_marker (preserve_marker); \
1718 }
1719
b86e0aaf
RS
1720#define PRESERVE_START_END \
1721 if (NILP (start_marker)) \
1722 start_marker = Fcopy_marker (start, Qnil); \
1723 if (NILP (end_marker)) \
1724 end_marker = Fcopy_marker (end, Qnil);
1725
1726#define FETCH_START \
1727 (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
1728
1729#define FETCH_END \
1730 (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
1731
eb8c3be9 1732/* Signal a change to the buffer immediately before it happens.
d206af14
RS
1733 START_INT and END_INT are the bounds of the text to be changed.
1734
1735 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
1736 by holding its value temporarily in a marker. */
b45433b3 1737
c660b094 1738void
d206af14 1739signal_before_change (start_int, end_int, preserve_ptr)
6022d493 1740 int start_int, end_int;
d206af14 1741 int *preserve_ptr;
b45433b3 1742{
fb4ee5cd 1743 Lisp_Object start, end;
b86e0aaf 1744 Lisp_Object start_marker, end_marker;
d206af14 1745 Lisp_Object preserve_marker;
b86e0aaf 1746 struct gcpro gcpro1, gcpro2, gcpro3;
fb4ee5cd
RS
1747
1748 start = make_number (start_int);
1749 end = make_number (end_int);
d206af14 1750 preserve_marker = Qnil;
b86e0aaf
RS
1751 start_marker = Qnil;
1752 end_marker = Qnil;
1753 GCPRO3 (preserve_marker, start_marker, end_marker);
fb4ee5cd 1754
b45433b3 1755 /* If buffer is unmodified, run a special hook for that case. */
9fbf87cd 1756 if (SAVE_MODIFF >= MODIFF
dbc4e1c1
JB
1757 && !NILP (Vfirst_change_hook)
1758 && !NILP (Vrun_hooks))
d206af14
RS
1759 {
1760 PRESERVE_VALUE;
b86e0aaf 1761 PRESERVE_START_END;
d206af14
RS
1762 call1 (Vrun_hooks, Qfirst_change_hook);
1763 }
dbc4e1c1 1764
3d1e2d9c
RS
1765 /* Run the before-change-function if any.
1766 We don't bother "binding" this variable to nil
1767 because it is obsolete anyway and new code should not use it. */
d427b66a 1768 if (!NILP (Vbefore_change_function))
d206af14
RS
1769 {
1770 PRESERVE_VALUE;
b86e0aaf
RS
1771 PRESERVE_START_END;
1772 call2 (Vbefore_change_function, FETCH_START, FETCH_END);
d206af14 1773 }
e45fb8bf 1774
3d1e2d9c 1775 /* Now run the before-change-functions if any. */
e45fb8bf
RS
1776 if (!NILP (Vbefore_change_functions))
1777 {
3d1e2d9c
RS
1778 Lisp_Object args[3];
1779 Lisp_Object before_change_functions;
1780 Lisp_Object after_change_functions;
1781 struct gcpro gcpro1, gcpro2;
1782
d206af14 1783 PRESERVE_VALUE;
b86e0aaf 1784 PRESERVE_START_END;
d206af14 1785
3d1e2d9c
RS
1786 /* "Bind" before-change-functions and after-change-functions
1787 to nil--but in a way that errors don't know about.
1788 That way, if there's an error in them, they will stay nil. */
1789 before_change_functions = Vbefore_change_functions;
1790 after_change_functions = Vafter_change_functions;
c82c1da0
KH
1791 Vbefore_change_functions = Qnil;
1792 Vafter_change_functions = Qnil;
3d1e2d9c
RS
1793 GCPRO2 (before_change_functions, after_change_functions);
1794
1795 /* Actually run the hook functions. */
1796 args[0] = Qbefore_change_functions;
b86e0aaf
RS
1797 args[1] = FETCH_START;
1798 args[2] = FETCH_END;
3d1e2d9c
RS
1799 run_hook_list_with_args (before_change_functions, 3, args);
1800
1801 /* "Unbind" the variables we "bound" to nil. */
1802 Vbefore_change_functions = before_change_functions;
1803 Vafter_change_functions = after_change_functions;
1804 UNGCPRO;
e45fb8bf 1805 }
d07c0804
RS
1806
1807 if (!NILP (current_buffer->overlays_before)
1808 || !NILP (current_buffer->overlays_after))
d206af14
RS
1809 {
1810 PRESERVE_VALUE;
b86e0aaf
RS
1811 report_overlay_modification (FETCH_START, FETCH_END, 0,
1812 FETCH_START, FETCH_END, Qnil);
d206af14
RS
1813 }
1814
b86e0aaf
RS
1815 if (! NILP (start_marker))
1816 free_marker (start_marker);
1817 if (! NILP (end_marker))
1818 free_marker (end_marker);
d206af14
RS
1819 RESTORE_VALUE;
1820 UNGCPRO;
b45433b3
JB
1821}
1822
eb8c3be9 1823/* Signal a change immediately after it happens.
3be11131 1824 CHARPOS is the character position of the start of the changed text.
b45433b3
JB
1825 LENDEL is the number of characters of the text before the change.
1826 (Not the whole buffer; just the part that was changed.)
8b09e5d0
RS
1827 LENINS is the number of characters in that part of the text
1828 after the change. */
b45433b3 1829
c660b094 1830void
3be11131
RS
1831signal_after_change (charpos, lendel, lenins)
1832 int charpos, lendel, lenins;
b45433b3 1833{
fb2e7d14
RS
1834 /* If we are deferring calls to the after-change functions
1835 and there are no before-change functions,
1836 just record the args that we were going to use. */
1837 if (! NILP (Vcombine_after_change_calls)
1838 && NILP (Vbefore_change_function) && NILP (Vbefore_change_functions)
1839 && NILP (current_buffer->overlays_before)
1840 && NILP (current_buffer->overlays_after))
1841 {
1842 Lisp_Object elt;
1843
1844 if (!NILP (combine_after_change_list)
1845 && current_buffer != XBUFFER (combine_after_change_buffer))
1846 Fcombine_after_change_execute ();
1847
3be11131
RS
1848 elt = Fcons (make_number (charpos - BEG),
1849 Fcons (make_number (Z - (charpos - lendel + lenins)),
fb2e7d14
RS
1850 Fcons (make_number (lenins - lendel), Qnil)));
1851 combine_after_change_list
1852 = Fcons (elt, combine_after_change_list);
1853 combine_after_change_buffer = Fcurrent_buffer ();
1854
1855 return;
1856 }
1857
1858 if (!NILP (combine_after_change_list))
1859 Fcombine_after_change_execute ();
1860
3d1e2d9c
RS
1861 /* Run the after-change-function if any.
1862 We don't bother "binding" this variable to nil
1863 because it is obsolete anyway and new code should not use it. */
d427b66a 1864 if (!NILP (Vafter_change_function))
3d1e2d9c 1865 call3 (Vafter_change_function,
3be11131 1866 make_number (charpos), make_number (charpos + lenins),
3d1e2d9c 1867 make_number (lendel));
b45433b3 1868
e45fb8bf
RS
1869 if (!NILP (Vafter_change_functions))
1870 {
3d1e2d9c
RS
1871 Lisp_Object args[4];
1872 Lisp_Object before_change_functions;
1873 Lisp_Object after_change_functions;
1874 struct gcpro gcpro1, gcpro2;
1875
1876 /* "Bind" before-change-functions and after-change-functions
1877 to nil--but in a way that errors don't know about.
1878 That way, if there's an error in them, they will stay nil. */
1879 before_change_functions = Vbefore_change_functions;
1880 after_change_functions = Vafter_change_functions;
c82c1da0
KH
1881 Vbefore_change_functions = Qnil;
1882 Vafter_change_functions = Qnil;
3d1e2d9c
RS
1883 GCPRO2 (before_change_functions, after_change_functions);
1884
1885 /* Actually run the hook functions. */
1886 args[0] = Qafter_change_functions;
3be11131
RS
1887 XSETFASTINT (args[1], charpos);
1888 XSETFASTINT (args[2], charpos + lenins);
3d1e2d9c
RS
1889 XSETFASTINT (args[3], lendel);
1890 run_hook_list_with_args (after_change_functions,
1891 4, args);
1892
1893 /* "Unbind" the variables we "bound" to nil. */
1894 Vbefore_change_functions = before_change_functions;
1895 Vafter_change_functions = after_change_functions;
1896 UNGCPRO;
e45fb8bf 1897 }
d07c0804
RS
1898
1899 if (!NILP (current_buffer->overlays_before)
1900 || !NILP (current_buffer->overlays_after))
3be11131
RS
1901 report_overlay_modification (make_number (charpos),
1902 make_number (charpos + lenins),
d07c0804 1903 1,
3be11131
RS
1904 make_number (charpos),
1905 make_number (charpos + lenins),
d07c0804 1906 make_number (lendel));
c5ca0786
RS
1907
1908 /* After an insertion, call the text properties
1909 insert-behind-hooks or insert-in-front-hooks. */
1910 if (lendel == 0)
3be11131 1911 report_interval_modification (charpos, charpos + lenins);
b45433b3 1912}
fb2e7d14
RS
1913
1914Lisp_Object
1915Fcombine_after_change_execute_1 (val)
1916 Lisp_Object val;
1917{
1918 Vcombine_after_change_calls = val;
1919 return val;
1920}
1921
1922DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
1923 Scombine_after_change_execute, 0, 0, 0,
1924 "This function is for use internally in `combine-after-change-calls'.")
1925 ()
1926{
1927 register Lisp_Object val;
1928 int count = specpdl_ptr - specpdl;
1929 int beg, end, change;
1930 int begpos, endpos;
1931 Lisp_Object tail;
1932
1933 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
1934
1935 Fset_buffer (combine_after_change_buffer);
1936
1937 /* # chars unchanged at beginning of buffer. */
1938 beg = Z - BEG;
1939 /* # chars unchanged at end of buffer. */
1940 end = beg;
1941 /* Total amount of insertion (negative for deletion). */
1942 change = 0;
1943
1944 /* Scan the various individual changes,
1945 accumulating the range info in BEG, END and CHANGE. */
1946 for (tail = combine_after_change_list; CONSP (tail);
1947 tail = XCONS (tail)->cdr)
1948 {
e688a080
KH
1949 Lisp_Object elt;
1950 int thisbeg, thisend, thischange;
fb2e7d14
RS
1951
1952 /* Extract the info from the next element. */
1953 elt = XCONS (tail)->car;
1954 if (! CONSP (elt))
1955 continue;
1956 thisbeg = XINT (XCONS (elt)->car);
1957
1958 elt = XCONS (elt)->cdr;
1959 if (! CONSP (elt))
1960 continue;
1961 thisend = XINT (XCONS (elt)->car);
1962
1963 elt = XCONS (elt)->cdr;
1964 if (! CONSP (elt))
1965 continue;
1966 thischange = XINT (XCONS (elt)->car);
1967
1968 /* Merge this range into the accumulated range. */
1969 change += thischange;
1970 if (thisbeg < beg)
1971 beg = thisbeg;
1972 if (thisend < end)
1973 end = thisend;
1974 }
1975
1976 /* Get the current start and end positions of the range
1977 that was changed. */
1978 begpos = BEG + beg;
1979 endpos = Z - end;
1980
1981 /* We are about to handle these, so discard them. */
1982 combine_after_change_list = Qnil;
1983
1984 /* Now run the after-change functions for real.
1985 Turn off the flag that defers them. */
1986 record_unwind_protect (Fcombine_after_change_execute_1,
1987 Vcombine_after_change_calls);
1988 signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
1989
1990 return unbind_to (count, val);
1991}
1992\f
1993syms_of_insdel ()
1994{
1995 staticpro (&combine_after_change_list);
1996 combine_after_change_list = Qnil;
1997
1998 DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls,
1999 "Used internally by the `combine-after-change-calls' macro.");
2000 Vcombine_after_change_calls = Qnil;
2001
2002 defsubr (&Scombine_after_change_execute);
2003}