(copy_text): In multibyte to unibyte conversion, take
[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"
dfcf069d 29#include "region-cache.h"
b45433b3 30
d206af14
RS
31#ifndef NULL
32#define NULL 0
33#endif
34
14f6194b
RS
35#define min(x, y) ((x) < (y) ? (x) : (y))
36
2b083808 37static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int));
ef29f213 38static void insert_from_buffer_1 ();
3be11131
RS
39static void gap_left P_ ((int, int, int));
40static void gap_right P_ ((int, int));
41static void adjust_markers_gap_motion P_ ((int, int, int));
432f78d2 42static void adjust_markers_for_insert P_ ((int, int, int, int, int, int, int));
3be11131 43static void adjust_markers_for_delete P_ ((int, int, int, int));
7cc3983f 44static void adjust_markers_for_record_delete P_ ((int, int, int, int));
3be11131 45static void adjust_point P_ ((int, int));
395ec62e 46
fb2e7d14
RS
47Lisp_Object Fcombine_after_change_execute ();
48
49/* Non-nil means don't call the after-change-functions right away,
50 just record an element in Vcombine_after_change_calls_list. */
51Lisp_Object Vcombine_after_change_calls;
52
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). */
63Lisp_Object combine_after_change_list;
64
65/* Buffer which combine_after_change_list is about. */
66Lisp_Object combine_after_change_buffer;
2b083808 67\f
60ea6052
RS
68/* Check all markers in the current buffer, looking for something invalid. */
69
70static int check_markers_debug_flag;
71
72#define CHECK_MARKERS() \
73 if (check_markers_debug_flag) \
74 check_markers (); \
75 else
76
77void
78check_markers ()
79{
80 register Lisp_Object tail, prev, next;
81
82 tail = BUF_MARKERS (current_buffer);
83
84 while (XSYMBOL (tail) != XSYMBOL (Qnil))
85 {
86 if (XMARKER (tail)->buffer->text != current_buffer->text)
87 abort ();
88 if (XMARKER (tail)->charpos > Z)
89 abort ();
90 if (XMARKER (tail)->bytepos > Z_BYTE)
91 abort ();
92
93 tail = XMARKER (tail)->chain;
94 }
95}
96\f
3be11131 97/* Move gap to position CHARPOS.
b45433b3
JB
98 Note that this can quit! */
99
c660b094 100void
3be11131
RS
101move_gap (charpos)
102 int charpos;
b45433b3 103{
3be11131 104 move_gap_both (charpos, charpos_to_bytepos (charpos));
b45433b3
JB
105}
106
3be11131
RS
107/* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
108 Note that this can quit! */
109
110void
111move_gap_both (charpos, bytepos)
112 int charpos, bytepos;
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
3be11131
RS
126gap_left (charpos, bytepos, newgap)
127 register int charpos, bytepos;
b45433b3
JB
128 int newgap;
129{
130 register unsigned char *to, *from;
131 register int i;
132 int new_s1;
133
b45433b3
JB
134 if (!newgap)
135 {
894ab630
RS
136 if (unchanged_modified == MODIFF
137 && overlay_unchanged_modified == OVERLAY_MODIFF)
b45433b3 138 {
3be11131
RS
139 beg_unchanged = charpos - BEG;
140 end_unchanged = Z - charpos;
b45433b3
JB
141 }
142 else
143 {
144 if (Z - GPT < end_unchanged)
145 end_unchanged = Z - GPT;
3be11131
RS
146 if (charpos < beg_unchanged)
147 beg_unchanged = charpos - BEG;
b45433b3
JB
148 }
149 }
150
3be11131 151 i = GPT_BYTE;
b45433b3
JB
152 to = GAP_END_ADDR;
153 from = GPT_ADDR;
3be11131 154 new_s1 = GPT_BYTE;
b45433b3
JB
155
156 /* Now copy the characters. To move the gap down,
157 copy characters up. */
158
159 while (1)
160 {
161 /* I gets number of characters left to copy. */
3be11131 162 i = new_s1 - bytepos;
b45433b3
JB
163 if (i == 0)
164 break;
165 /* If a quit is requested, stop copying now.
3be11131 166 Change BYTEPOS to be where we have actually moved the gap to. */
b45433b3
JB
167 if (QUITP)
168 {
3be11131
RS
169 bytepos = new_s1;
170 charpos = BYTE_TO_CHAR (bytepos);
b45433b3
JB
171 break;
172 }
173 /* Move at most 32000 chars before checking again for a quit. */
174 if (i > 32000)
175 i = 32000;
176#ifdef GAP_USE_BCOPY
177 if (i >= 128
178 /* bcopy is safe if the two areas of memory do not overlap
179 or on systems where bcopy is always safe for moving upward. */
180 && (BCOPY_UPWARD_SAFE
181 || to - from >= 128))
182 {
183 /* If overlap is not safe, avoid it by not moving too many
184 characters at once. */
185 if (!BCOPY_UPWARD_SAFE && i > to - from)
186 i = to - from;
187 new_s1 -= i;
188 from -= i, to -= i;
189 bcopy (from, to, i);
190 }
191 else
192#endif
193 {
194 new_s1 -= i;
195 while (--i >= 0)
196 *--to = *--from;
197 }
198 }
199
3be11131
RS
200 /* Adjust markers, and buffer data structure, to put the gap at BYTEPOS.
201 BYTEPOS is where the loop above stopped, which may be what was specified
b45433b3 202 or may be where a quit was detected. */
3be11131
RS
203 adjust_markers_gap_motion (bytepos, GPT_BYTE, GAP_SIZE);
204 GPT_BYTE = bytepos;
205 GPT = charpos;
206 if (bytepos < charpos)
207 abort ();
469ff680 208 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
b45433b3
JB
209 QUIT;
210}
211
3be11131
RS
212/* Move the gap to a position greater than than the current GPT.
213 BYTEPOS describes the new position as a byte position,
214 and CHARPOS is the corresponding char position. */
215
2bcaed71 216static void
3be11131
RS
217gap_right (charpos, bytepos)
218 register int charpos, bytepos;
b45433b3
JB
219{
220 register unsigned char *to, *from;
221 register int i;
222 int new_s1;
223
894ab630
RS
224 if (unchanged_modified == MODIFF
225 && overlay_unchanged_modified == OVERLAY_MODIFF)
b45433b3 226 {
3be11131
RS
227 beg_unchanged = charpos - BEG;
228 end_unchanged = Z - charpos;
b45433b3
JB
229 }
230 else
231 {
3be11131
RS
232 if (Z - charpos - 1 < end_unchanged)
233 end_unchanged = Z - charpos;
b45433b3
JB
234 if (GPT - BEG < beg_unchanged)
235 beg_unchanged = GPT - BEG;
236 }
237
3be11131 238 i = GPT_BYTE;
b45433b3
JB
239 from = GAP_END_ADDR;
240 to = GPT_ADDR;
3be11131 241 new_s1 = GPT_BYTE;
b45433b3
JB
242
243 /* Now copy the characters. To move the gap up,
244 copy characters down. */
245
246 while (1)
247 {
248 /* I gets number of characters left to copy. */
3be11131 249 i = bytepos - new_s1;
b45433b3
JB
250 if (i == 0)
251 break;
252 /* If a quit is requested, stop copying now.
3be11131 253 Change BYTEPOS to be where we have actually moved the gap to. */
b45433b3
JB
254 if (QUITP)
255 {
3be11131
RS
256 bytepos = new_s1;
257 charpos = BYTE_TO_CHAR (bytepos);
b45433b3
JB
258 break;
259 }
260 /* Move at most 32000 chars before checking again for a quit. */
261 if (i > 32000)
262 i = 32000;
263#ifdef GAP_USE_BCOPY
264 if (i >= 128
265 /* bcopy is safe if the two areas of memory do not overlap
266 or on systems where bcopy is always safe for moving downward. */
267 && (BCOPY_DOWNWARD_SAFE
268 || from - to >= 128))
269 {
270 /* If overlap is not safe, avoid it by not moving too many
271 characters at once. */
272 if (!BCOPY_DOWNWARD_SAFE && i > from - to)
273 i = from - to;
274 new_s1 += i;
275 bcopy (from, to, i);
276 from += i, to += i;
277 }
278 else
279#endif
280 {
281 new_s1 += i;
282 while (--i >= 0)
283 *to++ = *from++;
284 }
285 }
286
3be11131
RS
287 adjust_markers_gap_motion (GPT_BYTE + GAP_SIZE, bytepos + GAP_SIZE,
288 - GAP_SIZE);
289 GPT = charpos;
290 GPT_BYTE = bytepos;
291 if (bytepos < charpos)
292 abort ();
469ff680 293 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
b45433b3
JB
294 QUIT;
295}
2b083808 296\f
3be11131
RS
297/* Add AMOUNT to the byte position of every marker in the current buffer
298 whose current byte position is between FROM (exclusive) and TO (inclusive).
8948d317 299
b45433b3
JB
300 Also, any markers past the outside of that interval, in the direction
301 of adjustment, are first moved back to the near end of the interval
8948d317
RS
302 and then adjusted by AMOUNT.
303
304 When the latter adjustment is done, if AMOUNT is negative,
305 we record the adjustment for undo. (This case happens only for
3be11131
RS
306 deletion.)
307
308 The markers' character positions are not altered,
309 because gap motion does not affect character positions. */
310
311int adjust_markers_test;
b45433b3 312
2bcaed71 313static void
3be11131 314adjust_markers_gap_motion (from, to, amount)
b45433b3
JB
315 register int from, to, amount;
316{
80f6e77c
RS
317 /* Now that a marker has a bytepos, not counting the gap,
318 nothing needs to be done here. */
319#if 0
b45433b3
JB
320 Lisp_Object marker;
321 register struct Lisp_Marker *m;
322 register int mpos;
323
9fbf87cd 324 marker = BUF_MARKERS (current_buffer);
b45433b3 325
d427b66a 326 while (!NILP (marker))
b45433b3
JB
327 {
328 m = XMARKER (marker);
80f6e77c 329 mpos = m->bytepos;
b45433b3
JB
330 if (amount > 0)
331 {
332 if (mpos > to && mpos < to + amount)
3be11131
RS
333 {
334 if (adjust_markers_test)
335 abort ();
336 mpos = to + amount;
337 }
b45433b3
JB
338 }
339 else
340 {
8948d317
RS
341 /* Here's the case where a marker is inside text being deleted.
342 AMOUNT can be negative for gap motion, too,
343 but then this range contains no markers. */
b45433b3 344 if (mpos > from + amount && mpos <= from)
8948d317 345 {
3be11131
RS
346 if (adjust_markers_test)
347 abort ();
348 mpos = from + amount;
8948d317 349 }
b45433b3
JB
350 }
351 if (mpos > from && mpos <= to)
352 mpos += amount;
353 m->bufpos = mpos;
354 marker = m->chain;
355 }
80f6e77c 356#endif
b45433b3 357}
2b083808 358\f
3be11131
RS
359/* Adjust all markers for a deletion
360 whose range in bytes is FROM_BYTE to TO_BYTE.
361 The range in charpos is FROM to TO.
362
363 This function assumes that the gap is adjacent to
364 or inside of the range being deleted. */
beecb55b
RS
365
366static void
3be11131
RS
367adjust_markers_for_delete (from, from_byte, to, to_byte)
368 register int from, from_byte, to, to_byte;
369{
370 Lisp_Object marker;
371 register struct Lisp_Marker *m;
372 register int charpos;
3be11131
RS
373
374 marker = BUF_MARKERS (current_buffer);
375
376 while (!NILP (marker))
377 {
378 m = XMARKER (marker);
379 charpos = m->charpos;
380
381 if (charpos > Z)
382 abort ();
383
384 /* If the marker is after the deletion,
80f6e77c 385 relocate by number of chars / bytes deleted. */
3be11131 386 if (charpos > to)
80f6e77c
RS
387 {
388 m->charpos -= to - from;
389 m->bytepos -= to_byte - from_byte;
390 }
3be11131 391
80f6e77c 392 /* Here's the case where a marker is inside text being deleted. */
3be11131
RS
393 else if (charpos > from)
394 {
395 record_marker_adjustment (marker, from - charpos);
396 m->charpos = from;
80f6e77c 397 m->bytepos = from_byte;
3be11131
RS
398 }
399
3be11131
RS
400 marker = m->chain;
401 }
402}
2b083808 403\f
7cc3983f
RS
404/* Adjust all markers for calling record_delete for combining bytes.
405 whose range in bytes is FROM_BYTE to TO_BYTE.
406 The range in charpos is FROM to TO. */
407
408static void
409adjust_markers_for_record_delete (from, from_byte, to, to_byte)
410 register int from, from_byte, to, to_byte;
411{
412 Lisp_Object marker;
413 register struct Lisp_Marker *m;
414 register int charpos;
415
416 marker = BUF_MARKERS (current_buffer);
417
418 while (!NILP (marker))
419 {
420 m = XMARKER (marker);
421 charpos = m->charpos;
422
423 /* If the marker is after the deletion,
424 relocate by number of chars / bytes deleted. */
425 if (charpos > to)
426 ;
427 /* Here's the case where a marker is inside text being deleted. */
428 else if (charpos > from)
429 record_marker_adjustment (marker, from - charpos);
430
431 marker = m->chain;
432 }
433}
434\f
432f78d2
RS
435/* Adjust markers for an insertion that stretches from FROM / FROM_BYTE
436 to TO / TO_BYTE. We have to relocate the charpos of every marker
437 that points after the insertion (but not their bytepos).
3be11131 438
ce97a2d7
RS
439 COMBINED_BEFORE_BYTES is the number of bytes at the start of the insertion
440 that combine into one character with the text before the insertion.
432f78d2 441 COMBINED_AFTER_BYTES is the number of bytes after the insertion
ce97a2d7 442 that combine into one character with the last inserted bytes.
3be11131
RS
443
444 When a marker points at the insertion point,
445 we advance it if either its insertion-type is t
446 or BEFORE_MARKERS is true. */
447
448static void
432f78d2
RS
449adjust_markers_for_insert (from, from_byte, to, to_byte,
450 combined_before_bytes, combined_after_bytes,
451 before_markers)
452 register int from, from_byte, to, to_byte;
453 int combined_before_bytes, combined_after_bytes, before_markers;
beecb55b
RS
454{
455 Lisp_Object marker;
469ff680 456 int adjusted = 0;
3be11131
RS
457 int nchars = to - from;
458 int nbytes = to_byte - from_byte;
beecb55b
RS
459
460 marker = BUF_MARKERS (current_buffer);
461
462 while (!NILP (marker))
463 {
464 register struct Lisp_Marker *m = XMARKER (marker);
1f90a790
RS
465
466 /* In a single-byte buffer, a marker's two positions must be equal.
467 (If this insertion is going to combine characters, Z will
468 become different from Z_BYTE, but they might be the same now.
469 If so, the two OLD positions of the marker should be equal.) */
470 if (Z == Z_BYTE)
471 {
472 if (m->charpos != m->bytepos)
473 abort ();
474 }
475
432f78d2 476 if (m->bytepos == from_byte)
469ff680 477 {
432f78d2
RS
478 if (m->insertion_type || before_markers)
479 {
480 m->bytepos += nbytes + combined_after_bytes;
481 m->charpos += nchars + !!combined_after_bytes;
482 /* Point the marker before the combined character,
483 so that undoing the insertion puts it back where it was. */
484 if (combined_after_bytes)
485 DEC_BOTH (m->charpos, m->bytepos);
486 if (m->insertion_type)
487 adjusted = 1;
488 }
489 else if (combined_before_bytes)
490 {
491 /* This marker doesn't "need relocation",
492 but don't leave it pointing in the middle of a character.
493 Point the marker after the combined character,
494 so that undoing the insertion puts it back where it was. */
ce97a2d7
RS
495
496 /* Here we depend on the fact that the gap is after
497 all of the combining bytes that we are going to skip over. */
498 DEC_BOTH (m->charpos, m->bytepos);
432f78d2
RS
499 INC_BOTH (m->charpos, m->bytepos);
500 }
469ff680 501 }
ce97a2d7
RS
502 /* If a marker was pointing into the combining bytes
503 after the insertion, don't leave it there
504 in the middle of a character. */
505 else if (combined_after_bytes && m->bytepos >= from_byte
506 && m->bytepos < from_byte + combined_after_bytes)
507 {
508 /* Put it after the combining bytes. */
509 m->bytepos = to_byte + combined_after_bytes;
510 m->charpos = to + 1;
511 /* Now move it back before the combined character,
512 so that undoing the insertion will put it where it was. */
513 DEC_BOTH (m->charpos, m->bytepos);
514 }
80f6e77c
RS
515 else if (m->bytepos > from_byte)
516 {
517 m->bytepos += nbytes;
518 m->charpos += nchars;
519 }
3be11131 520
beecb55b
RS
521 marker = m->chain;
522 }
3be11131
RS
523
524 /* Adjusting only markers whose insertion-type is t may result in
525 disordered overlays in the slot `overlays_before'. */
469ff680 526 if (adjusted)
3be11131 527 fix_overlays_before (current_buffer, from, to);
beecb55b
RS
528}
529
3be11131
RS
530/* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
531
532 This is used only when the value of point changes due to an insert
533 or delete; it does not represent a conceptual change in point as a
534 marker. In particular, point is not crossing any interval
535 boundaries, so there's no need to use the usual SET_PT macro. In
536 fact it would be incorrect to do so, because either the old or the
537 new value of point is out of sync with the current set of
538 intervals. */
539
a27a38d8 540static void
3be11131
RS
541adjust_point (nchars, nbytes)
542 int nchars, nbytes;
a27a38d8 543{
3be11131
RS
544 BUF_PT (current_buffer) += nchars;
545 BUF_PT_BYTE (current_buffer) += nbytes;
546
547 /* In a single-byte buffer, the two positions must be equal. */
548 if (ZV == ZV_BYTE
549 && PT != PT_BYTE)
550 abort ();
a27a38d8 551}
b45433b3 552\f
652838b5
KH
553/* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
554 length OLD_CHARS (OLD_BYTES) to a new text of length NEW_CHARS
555 (NEW_BYTES).
556
557 See the comment of adjust_markers_for_insert for the args
558 COMBINED_BEFORE_BYTES and COMBINED_AFTER_BYTES. */
559
560static void
561adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
562 new_chars, new_bytes,
563 combined_before_bytes, combined_after_bytes)
564 int from, from_byte, old_chars, old_bytes, new_chars, new_bytes;
565 int combined_before_bytes, combined_after_bytes;
566{
567 Lisp_Object marker = BUF_MARKERS (current_buffer);
568 int prev_to_byte = from_byte + old_bytes;
569 int diff_chars = new_chars - old_chars;
570 int diff_bytes = new_bytes - old_bytes;
571
572 while (!NILP (marker))
573 {
574 register struct Lisp_Marker *m = XMARKER (marker);
575
576 if (m->bytepos >= prev_to_byte)
577 {
578 if (m->bytepos < prev_to_byte + combined_after_bytes)
579 {
580 /* Put it after the combining bytes. */
581 m->bytepos = from_byte + new_bytes;
582 m->charpos = from + new_chars;
583 }
584 else
585 {
586 m->charpos += diff_chars;
587 m->bytepos += diff_bytes;
588 }
589 if (m->charpos == from + new_chars)
590 record_marker_adjustment (marker, - old_chars);
591 }
592 else if (m->bytepos > from_byte)
593 {
594 record_marker_adjustment (marker, from - m->charpos);
595 m->charpos = from;
596 m->bytepos = from_byte;
597 }
598 else if (m->bytepos == from_byte)
599 {
600 if (combined_before_bytes)
601 {
602 DEC_BOTH (m->charpos, m->bytepos);
603 INC_BOTH (m->charpos, m->bytepos);
604 }
605 }
606
607 marker = m->chain;
608 }
609}
610
611\f
3be11131 612/* Make the gap NBYTES_ADDED bytes longer. */
b45433b3 613
c660b094 614void
3be11131
RS
615make_gap (nbytes_added)
616 int nbytes_added;
b45433b3
JB
617{
618 unsigned char *result;
619 Lisp_Object tem;
620 int real_gap_loc;
3be11131 621 int real_gap_loc_byte;
b45433b3
JB
622 int old_gap_size;
623
624 /* If we have to get more space, get enough to last a while. */
3be11131 625 nbytes_added += 2000;
b45433b3 626
94056516
RS
627 /* Don't allow a buffer size that won't fit in an int
628 even if it will fit in a Lisp integer.
629 That won't work because so many places use `int'. */
630
3be11131 631 if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added
68be917d 632 >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
14f6194b 633 error ("Buffer exceeds maximum size");
94056516 634
9ac0d9e0 635 BLOCK_INPUT;
469ff680 636 /* We allocate extra 1-byte `\0' at the tail for anchoring a search. */
3be11131
RS
637 result = BUFFER_REALLOC (BEG_ADDR, (Z_BYTE - BEG_BYTE
638 + GAP_SIZE + nbytes_added + 1));
9ac0d9e0 639
b45433b3 640 if (result == 0)
270c2138
RS
641 {
642 UNBLOCK_INPUT;
643 memory_full ();
644 }
645
646 /* We can't unblock until the new address is properly stored. */
b45433b3 647 BEG_ADDR = result;
270c2138 648 UNBLOCK_INPUT;
b45433b3
JB
649
650 /* Prevent quitting in move_gap. */
651 tem = Vinhibit_quit;
652 Vinhibit_quit = Qt;
653
654 real_gap_loc = GPT;
3be11131 655 real_gap_loc_byte = GPT_BYTE;
b45433b3
JB
656 old_gap_size = GAP_SIZE;
657
658 /* Call the newly allocated space a gap at the end of the whole space. */
659 GPT = Z + GAP_SIZE;
7d92db58 660 GPT_BYTE = Z_BYTE + GAP_SIZE;
3be11131 661 GAP_SIZE = nbytes_added;
b45433b3
JB
662
663 /* Move the new gap down to be consecutive with the end of the old one.
664 This adjusts the markers properly too. */
3be11131 665 gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1);
b45433b3
JB
666
667 /* Now combine the two into one large gap. */
668 GAP_SIZE += old_gap_size;
669 GPT = real_gap_loc;
3be11131 670 GPT_BYTE = real_gap_loc_byte;
b45433b3 671
469ff680
KH
672 /* Put an anchor. */
673 *(Z_ADDR) = 0;
674
b45433b3
JB
675 Vinhibit_quit = tem;
676}
677\f
2b083808
RS
678/* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
679 FROM_MULTIBYTE says whether the incoming text is multibyte.
680 TO_MULTIBYTE says whether to store the text as multibyte.
681 If FROM_MULTIBYTE != TO_MULTIBYTE, we convert.
682
683 Return the number of bytes stored at TO_ADDR. */
684
685int
686copy_text (from_addr, to_addr, nbytes,
687 from_multibyte, to_multibyte)
688 unsigned char *from_addr;
689 unsigned char *to_addr;
690 int nbytes;
691 int from_multibyte, to_multibyte;
692{
693 if (from_multibyte == to_multibyte)
694 {
695 bcopy (from_addr, to_addr, nbytes);
696 return nbytes;
697 }
698 else if (from_multibyte)
699 {
700 int nchars = 0;
701 int bytes_left = nbytes;
f44cbcd8
KH
702 Lisp_Object tbl = Qnil, temp;
703
704 /* We set the variable tbl to the reverse table of
705 Vnonascii_translation_table in advance. */
706 if (CHAR_TABLE_P (Vnonascii_translation_table))
707 {
708 tbl = Fchar_table_extra_slot (Vnonascii_translation_table,
709 make_number (0));
710 if (!CHAR_TABLE_P (tbl))
711 tbl = Qnil;
712 }
2b083808
RS
713
714 /* Convert multibyte to single byte. */
715 while (bytes_left > 0)
716 {
f44cbcd8
KH
717 int thislen, c, c_save;
718 c = c_save = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
719 if (!SINGLE_BYTE_CHAR_P (c))
720 {
721 if (!NILP (tbl))
722 {
723 temp = Faref (tbl, make_number (c));
724 if (INTEGERP (temp))
725 c = XINT (temp);
726 }
727 else if (nonascii_insert_offset > 0)
728 c -= nonascii_insert_offset;
729 if (c < 128 || c >= 256)
730 c = (c_save & 0177) + 0200;
731 }
732 *to_addr++ = c;
2b083808 733 from_addr += thislen;
7e79b8e0 734 bytes_left -= thislen;
2b083808
RS
735 nchars++;
736 }
737 return nchars;
738 }
739 else
740 {
741 unsigned char *initial_to_addr = to_addr;
742
743 /* Convert single-byte to multibyte. */
744 while (nbytes > 0)
745 {
746 int c = *from_addr++;
747 unsigned char workbuf[4], *str;
748 int len;
749
59a52d50 750 if (c >= 0240 && c < 0400)
2b083808 751 {
59a52d50 752 c = unibyte_char_to_multibyte (c);
2b083808
RS
753 len = CHAR_STRING (c, workbuf, str);
754 bcopy (str, to_addr, len);
755 to_addr += len;
756 nbytes--;
757 }
758 else
759 /* Special case for speed. */
760 *to_addr++ = c, nbytes--;
761 }
762 return to_addr - initial_to_addr;
763 }
764}
765
766/* Return the number of bytes it would take
767 to convert some single-byte text to multibyte.
768 The single-byte text consists of NBYTES bytes at PTR. */
769
770int
771count_size_as_multibyte (ptr, nbytes)
772 unsigned char *ptr;
773 int nbytes;
774{
775 int i;
776 int outgoing_nbytes = 0;
777
778 for (i = 0; i < nbytes; i++)
779 {
780 unsigned int c = *ptr++;
59a52d50
KH
781
782 if (c < 0240)
783 outgoing_nbytes++;
784 else
2b083808 785 {
59a52d50
KH
786 c = unibyte_char_to_multibyte (c);
787 outgoing_nbytes += XINT (Fchar_bytes (make_number (c)));
2b083808 788 }
2b083808
RS
789 }
790
791 return outgoing_nbytes;
792}
793\f
b45433b3 794/* Insert a string of specified length before point.
2b083808
RS
795 This function judges multibyteness based on
796 enable_multibyte_characters in the current buffer;
797 it never converts between single-byte and multibyte.
798
ef29f213
KH
799 DO NOT use this for the contents of a Lisp string or a Lisp buffer!
800 prepare_to_modify_buffer could relocate the text. */
b45433b3 801
c660b094 802void
3be11131 803insert (string, nbytes)
b45433b3 804 register unsigned char *string;
dfcf069d 805 register int nbytes;
b45433b3 806{
3be11131 807 if (nbytes > 0)
395ec62e 808 {
3be11131
RS
809 int opoint = PT;
810 insert_1 (string, nbytes, 0, 1, 0);
811 signal_after_change (opoint, 0, PT - opoint);
cd11ef31
RS
812 }
813}
814
2b083808
RS
815/* Likewise, but inherit text properties from neighboring characters. */
816
c660b094 817void
3be11131 818insert_and_inherit (string, nbytes)
cd11ef31 819 register unsigned char *string;
dfcf069d 820 register int nbytes;
cd11ef31 821{
3be11131 822 if (nbytes > 0)
cd11ef31 823 {
3be11131
RS
824 int opoint = PT;
825 insert_1 (string, nbytes, 1, 1, 0);
826 signal_after_change (opoint, 0, PT - opoint);
395ec62e
KH
827 }
828}
b45433b3 829
2b083808 830/* Insert the character C before point. Do not inherit text properties. */
3be11131 831
c660b094 832void
3be11131
RS
833insert_char (c)
834 int c;
835{
836 unsigned char workbuf[4], *str;
2b083808
RS
837 int len;
838
839 if (! NILP (current_buffer->enable_multibyte_characters))
840 len = CHAR_STRING (c, workbuf, str);
841 else
842 {
843 len = 1;
844 workbuf[0] = c;
845 str = workbuf;
846 }
3be11131
RS
847
848 insert (str, len);
849}
850
2b083808 851/* Insert the null-terminated string S before point. */
3be11131
RS
852
853void
854insert_string (s)
855 char *s;
856{
857 insert (s, strlen (s));
858}
859
860/* Like `insert' except that all markers pointing at the place where
861 the insertion happens are adjusted to point after it.
862 Don't use this function to insert part of a Lisp string,
863 since gc could happen and relocate it. */
864
865void
866insert_before_markers (string, nbytes)
867 unsigned char *string;
868 register int nbytes;
869{
870 if (nbytes > 0)
871 {
872 int opoint = PT;
873
874 insert_1 (string, nbytes, 0, 1, 1);
875 signal_after_change (opoint, 0, PT - opoint);
876 }
877}
878
2b083808
RS
879/* Likewise, but inherit text properties from neighboring characters. */
880
3be11131
RS
881void
882insert_before_markers_and_inherit (string, nbytes)
883 unsigned char *string;
884 register int nbytes;
885{
886 if (nbytes > 0)
887 {
888 int opoint = PT;
889
890 insert_1 (string, nbytes, 1, 1, 1);
891 signal_after_change (opoint, 0, PT - opoint);
892 }
893}
1f90a790 894
3be11131
RS
895/* Subroutine used by the insert functions above. */
896
897void
898insert_1 (string, nbytes, inherit, prepare, before_markers)
395ec62e 899 register unsigned char *string;
3be11131
RS
900 register int nbytes;
901 int inherit, prepare, before_markers;
395ec62e 902{
432f78d2
RS
903 insert_1_both (string, chars_in_text (string, nbytes), nbytes,
904 inherit, prepare, before_markers);
905}
1f90a790 906\f
432f78d2
RS
907/* See if the bytes before POS/POS_BYTE combine with bytes
908 at the start of STRING to form a single character.
ce97a2d7 909 If so, return the number of bytes at the start of STRING
432f78d2 910 which combine in this way. Otherwise, return 0. */
b45433b3 911
432f78d2
RS
912int
913count_combining_before (string, length, pos, pos_byte)
914 unsigned char *string;
915 int length;
916 int pos, pos_byte;
917{
918 int opos = pos, opos_byte = pos_byte;
919 int c;
ce97a2d7 920 unsigned char *p = string;
b45433b3 921
432f78d2
RS
922 if (NILP (current_buffer->enable_multibyte_characters))
923 return 0;
924 if (length == 0 || CHAR_HEAD_P (*string))
925 return 0;
926 if (pos == BEGV)
927 return 0;
928 c = FETCH_BYTE (pos_byte - 1);
929 if (ASCII_BYTE_P (c))
930 return 0;
931 DEC_BOTH (pos, pos_byte);
932 c = FETCH_BYTE (pos_byte);
933 if (! BASE_LEADING_CODE_P (c))
934 return 0;
ce97a2d7
RS
935
936 /* We have a combination situation.
937 Count the bytes at STRING that will combine. */
938 while (!CHAR_HEAD_P (*p) && p < string + length)
939 p++;
940
941 return p - string;
432f78d2 942}
b45433b3 943
432f78d2
RS
944/* See if the bytes after POS/POS_BYTE combine with bytes
945 at the end of STRING to form a single character.
946 If so, return the number of bytes after POS/POS_BYTE
947 which combine in this way. Otherwise, return 0. */
679194a6 948
432f78d2
RS
949int
950count_combining_after (string, length, pos, pos_byte)
951 unsigned char *string;
952 int length;
953 int pos, pos_byte;
954{
955 int opos = pos, opos_byte = pos_byte;
956 int i;
957 int c;
3be11131 958
432f78d2
RS
959 if (NILP (current_buffer->enable_multibyte_characters))
960 return 0;
961 if (length == 0 || ASCII_BYTE_P (string[length - 1]))
962 return 0;
963 i = length - 1;
964 while (i > 0 && ! CHAR_HEAD_P (string[i]))
965 {
966 i--;
967 }
968 if (! BASE_LEADING_CODE_P (string[i]))
969 return 0;
970
971 if (pos == ZV)
972 return 0;
973 c = FETCH_BYTE (pos_byte);
974 if (CHAR_HEAD_P (c))
975 return 0;
976 while (pos_byte < ZV_BYTE)
977 {
978 c = FETCH_BYTE (pos_byte);
979 if (CHAR_HEAD_P (c))
980 break;
981 pos_byte++;
982 }
cd11ef31 983
432f78d2 984 return pos_byte - opos_byte;
b45433b3 985}
2b083808 986
e3a87305
KH
987/* Adjust the position TARGET/TARGET_BYTE for the combining of NBYTES
988 following the position POS/POS_BYTE to the character preceding POS.
989 If TARGET is after POS+NBYTES, we only have to adjust the character
990 position TARGET, else, if TARGET is after POS, we have to adjust
991 both the character position TARGET and the byte position
992 TARGET_BYTE, else we don't have to do any adjustment. */
993
994#define ADJUST_CHAR_POS(target, target_byte) \
995 do { \
996 if (target > pos + nbytes) \
997 target -= nbytes; \
998 else if (target >= pos) \
999 { \
1000 target = pos; \
1001 target_byte = pos_byte + nbytes; \
1002 } \
1003 } while (0)
1004
1f90a790
RS
1005/* Combine NBYTES stray trailing-codes, which were formerly separate
1006 characters, with the preceding character. These bytes
1007 are located after position POS / POS_BYTE, and the preceding character
1008 is located just before that position. */
1009
1010static void
1011combine_bytes (pos, pos_byte, nbytes)
1012 int pos, pos_byte, nbytes;
1013{
1014 /* Adjust all markers. */
1015 adjust_markers_for_delete (pos, pos_byte, pos + nbytes, pos_byte);
1016
1017 adjust_overlays_for_delete (pos, nbytes);
1018
e3a87305
KH
1019 ADJUST_CHAR_POS (BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
1020 ADJUST_CHAR_POS (GPT, GPT_BYTE);
1021 ADJUST_CHAR_POS (Z, Z_BYTE);
1022 ADJUST_CHAR_POS (ZV, ZV_BYTE);
1f90a790
RS
1023
1024 if (BUF_INTERVALS (current_buffer) != 0)
1025 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
1026 offset_intervals (current_buffer, pos, - nbytes);
60ea6052
RS
1027
1028 CHECK_MARKERS ();
1f90a790
RS
1029}
1030\f
2b083808
RS
1031/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
1032 starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS
1033 are the same as in insert_1. */
1034
1035void
1036insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
1037 register unsigned char *string;
1038 register int nchars, nbytes;
1039 int inherit, prepare, before_markers;
1040{
0aa8c4b2 1041 register Lisp_Object temp;
432f78d2 1042 int combined_before_bytes, combined_after_bytes;
2b083808 1043
57404188
KH
1044 if (NILP (current_buffer->enable_multibyte_characters))
1045 nchars = nbytes;
1046
35d63725
RS
1047 if (prepare)
1048 /* Do this before moving and increasing the gap,
1049 because the before-change hooks might move the gap
1050 or make it smaller. */
1051 prepare_to_modify_buffer (PT, PT, NULL);
1052
2b083808
RS
1053 if (PT != GPT)
1054 move_gap_both (PT, PT_BYTE);
1055 if (GAP_SIZE < nbytes)
1056 make_gap (nbytes - GAP_SIZE);
1057
1f90a790
RS
1058 combined_before_bytes
1059 = count_combining_before (string, nbytes, PT, PT_BYTE);
1060 combined_after_bytes
1061 = count_combining_after (string, nbytes, PT, PT_BYTE);
432f78d2
RS
1062
1063 /* Record deletion of the surrounding text that combines with
1064 the insertion. This, together with recording the insertion,
1065 will add up to the right stuff in the undo list.
1066
1067 But there is no need to actually delete the combining bytes
1068 from the buffer and reinsert them. */
1069
1070 if (combined_after_bytes)
7cc3983f 1071 {
0aa8c4b2
RS
1072 Lisp_Object deletion;
1073 deletion = Qnil;
1074
1075 if (! EQ (current_buffer->undo_list, Qt))
1076 deletion = make_buffer_string_both (PT, PT_BYTE,
1077 PT + combined_after_bytes,
1078 PT_BYTE + combined_after_bytes, 1);
628cea90 1079
7cc3983f
RS
1080 adjust_markers_for_record_delete (PT, PT_BYTE,
1081 PT + combined_after_bytes,
1082 PT_BYTE + combined_after_bytes);
0aa8c4b2
RS
1083 if (! EQ (current_buffer->undo_list, Qt))
1084 record_delete (PT, deletion);
7cc3983f 1085 }
432f78d2
RS
1086
1087 if (combined_before_bytes)
7cc3983f 1088 {
0aa8c4b2
RS
1089 Lisp_Object deletion;
1090 deletion = Qnil;
1091
1092 if (! EQ (current_buffer->undo_list, Qt))
1093 deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
1094 PT, PT_BYTE, 1);
7cc3983f
RS
1095 adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
1096 PT, PT_BYTE);
0aa8c4b2
RS
1097 if (! EQ (current_buffer->undo_list, Qt))
1098 record_delete (PT - 1, deletion);
7cc3983f 1099 }
432f78d2 1100
e0c0ed58
RS
1101 record_insert (PT - !!combined_before_bytes,
1102 nchars - combined_before_bytes + !!combined_before_bytes);
2b083808
RS
1103 MODIFF++;
1104
1105 bcopy (string, GPT_ADDR, nbytes);
1106
2b083808 1107 GAP_SIZE -= nbytes;
ce97a2d7
RS
1108 /* When we have combining at the end of the insertion,
1109 this is the character position before the combined character. */
1f90a790
RS
1110 GPT += nchars;
1111 ZV += nchars;
1112 Z += nchars;
2b083808
RS
1113 GPT_BYTE += nbytes;
1114 ZV_BYTE += nbytes;
1115 Z_BYTE += nbytes;
1116 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1f90a790
RS
1117
1118 if (combined_after_bytes)
1119 move_gap_both (GPT + combined_after_bytes,
1120 GPT_BYTE + combined_after_bytes);
1121
1122 if (GPT_BYTE < GPT)
1123 abort ();
1124
1125 adjust_overlays_for_insert (PT, nchars);
432f78d2 1126 adjust_markers_for_insert (PT, PT_BYTE,
1f90a790 1127 PT + nchars, PT_BYTE + nbytes,
432f78d2 1128 combined_before_bytes, combined_after_bytes,
2b083808 1129 before_markers);
ce97a2d7 1130
ce97a2d7 1131#ifdef USE_TEXT_PROPERTIES
1f90a790
RS
1132 if (BUF_INTERVALS (current_buffer) != 0)
1133 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
1134 offset_intervals (current_buffer, PT, nchars);
1135
ce97a2d7 1136 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
1f90a790 1137 Fset_text_properties (make_number (PT), make_number (PT + nchars),
ce97a2d7
RS
1138 Qnil, Qnil);
1139#endif
1140
1f90a790
RS
1141 {
1142 int pos = PT, pos_byte = PT_BYTE;
432f78d2 1143
1f90a790
RS
1144 adjust_point (nchars + combined_after_bytes,
1145 nbytes + combined_after_bytes);
2b083808 1146
1f90a790
RS
1147 if (combined_after_bytes)
1148 combine_bytes (pos + nchars, pos_byte + nbytes, combined_after_bytes);
1149
1150 if (combined_before_bytes)
1151 combine_bytes (pos, pos_byte, combined_before_bytes);
1152 }
2b083808 1153}
3be11131 1154\f
679194a6 1155/* Insert the part of the text of STRING, a Lisp object assumed to be
2b083808
RS
1156 of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes)
1157 starting at position POS / POS_BYTE. If the text of STRING has properties,
1158 copy them into the buffer.
679194a6
JA
1159
1160 It does not work to use `insert' for this, because a GC could happen
7e1ea612
JB
1161 before we bcopy the stuff into the buffer, and relocate the string
1162 without insert noticing. */
679194a6 1163
c660b094 1164void
2b083808 1165insert_from_string (string, pos, pos_byte, length, length_byte, inherit)
b45433b3 1166 Lisp_Object string;
2b083808 1167 register int pos, pos_byte, length, length_byte;
9391e591 1168 int inherit;
395ec62e 1169{
62b82678
RS
1170 int opoint = PT;
1171 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
1172 inherit, 0);
1173 signal_after_change (opoint, 0, PT - opoint);
395ec62e
KH
1174}
1175
2b083808
RS
1176/* Like `insert_from_string' except that all markers pointing
1177 at the place where the insertion happens are adjusted to point after it. */
3be11131
RS
1178
1179void
2b083808
RS
1180insert_from_string_before_markers (string, pos, pos_byte,
1181 length, length_byte, inherit)
395ec62e 1182 Lisp_Object string;
2b083808 1183 register int pos, pos_byte, length, length_byte;
395ec62e 1184 int inherit;
3be11131 1185{
62b82678
RS
1186 int opoint = PT;
1187 insert_from_string_1 (string, pos, pos_byte, length, length_byte,
1188 inherit, 1);
1189 signal_after_change (opoint, 0, PT - opoint);
3be11131
RS
1190}
1191
1192/* Subroutine of the insertion functions above. */
1193
1194static void
2b083808
RS
1195insert_from_string_1 (string, pos, pos_byte, nchars, nbytes,
1196 inherit, before_markers)
3be11131 1197 Lisp_Object string;
2b083808 1198 register int pos, pos_byte, nchars, nbytes;
3be11131 1199 int inherit, before_markers;
b45433b3
JB
1200{
1201 register Lisp_Object temp;
1202 struct gcpro gcpro1;
2b083808 1203 int outgoing_nbytes = nbytes;
432f78d2
RS
1204 int combined_before_bytes, combined_after_bytes;
1205 int adjusted_nchars;
ce97a2d7 1206 INTERVAL intervals;
2b083808
RS
1207
1208 /* Make OUTGOING_NBYTES describe the text
1209 as it will be inserted in this buffer. */
1210
1211 if (NILP (current_buffer->enable_multibyte_characters))
1212 outgoing_nbytes = nchars;
2a1d8be0 1213 else if (! STRING_MULTIBYTE (string))
2b083808
RS
1214 outgoing_nbytes
1215 = count_size_as_multibyte (&XSTRING (string)->data[pos_byte],
1216 nbytes);
b45433b3 1217
b45433b3 1218 GCPRO1 (string);
35d63725
RS
1219 /* Do this before moving and increasing the gap,
1220 because the before-change hooks might move the gap
1221 or make it smaller. */
d206af14 1222 prepare_to_modify_buffer (PT, PT, NULL);
b45433b3 1223
2bcaed71 1224 if (PT != GPT)
3be11131
RS
1225 move_gap_both (PT, PT_BYTE);
1226 if (GAP_SIZE < nbytes)
2b083808 1227 make_gap (outgoing_nbytes - GAP_SIZE);
b45433b3
JB
1228 UNGCPRO;
1229
2b083808
RS
1230 /* Copy the string text into the buffer, perhaps converting
1231 between single-byte and multibyte. */
1232 copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes,
2a1d8be0 1233 STRING_MULTIBYTE (string),
2b083808 1234 ! NILP (current_buffer->enable_multibyte_characters));
b45433b3 1235
432f78d2
RS
1236 /* We have copied text into the gap, but we have not altered
1237 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1238 to these functions and get the same results as we would
1239 have got earlier on. Meanwhile, PT_ADDR does point to
1240 the text that has been stored by copy_text. */
1241
1242 combined_before_bytes
1f90a790 1243 = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
432f78d2 1244 combined_after_bytes
1f90a790 1245 = count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
432f78d2
RS
1246
1247 /* Record deletion of the surrounding text that combines with
1248 the insertion. This, together with recording the insertion,
1249 will add up to the right stuff in the undo list.
1250
1251 But there is no need to actually delete the combining bytes
1252 from the buffer and reinsert them. */
1253
1254 if (combined_after_bytes)
7cc3983f 1255 {
0aa8c4b2
RS
1256 Lisp_Object deletion;
1257 deletion = Qnil;
1258
1259 if (! EQ (current_buffer->undo_list, Qt))
1260 deletion = make_buffer_string_both (PT, PT_BYTE,
1261 PT + combined_after_bytes,
1262 PT_BYTE + combined_after_bytes, 1);
628cea90 1263
7cc3983f
RS
1264 adjust_markers_for_record_delete (PT, PT_BYTE,
1265 PT + combined_after_bytes,
1266 PT_BYTE + combined_after_bytes);
0aa8c4b2
RS
1267 if (! EQ (current_buffer->undo_list, Qt))
1268 record_delete (PT, deletion);
7cc3983f 1269 }
432f78d2
RS
1270
1271 if (combined_before_bytes)
7cc3983f 1272 {
0aa8c4b2
RS
1273 Lisp_Object deletion;
1274 deletion = Qnil;
1275
1276 if (! EQ (current_buffer->undo_list, Qt))
1277 deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
1278 PT, PT_BYTE, 1);
7cc3983f
RS
1279 adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
1280 PT, PT_BYTE);
0aa8c4b2
RS
1281 if (! EQ (current_buffer->undo_list, Qt))
1282 record_delete (PT - 1, deletion);
7cc3983f 1283 }
432f78d2 1284
e0c0ed58
RS
1285 record_insert (PT - !!combined_before_bytes,
1286 nchars - combined_before_bytes + !!combined_before_bytes);
432f78d2
RS
1287 MODIFF++;
1288
7792090e 1289 GAP_SIZE -= outgoing_nbytes;
1f90a790
RS
1290 GPT += nchars;
1291 ZV += nchars;
1292 Z += nchars;
2b083808
RS
1293 GPT_BYTE += outgoing_nbytes;
1294 ZV_BYTE += outgoing_nbytes;
1295 Z_BYTE += outgoing_nbytes;
469ff680 1296 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
3be11131 1297
432f78d2 1298 if (combined_after_bytes)
1f90a790
RS
1299 move_gap_both (GPT + combined_after_bytes,
1300 GPT_BYTE + combined_after_bytes);
432f78d2 1301
3be11131
RS
1302 if (GPT_BYTE < GPT)
1303 abort ();
679194a6 1304
1f90a790
RS
1305 adjust_overlays_for_insert (PT, nchars);
1306 adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
1307 PT_BYTE + outgoing_nbytes,
1308 combined_before_bytes, combined_after_bytes,
1309 before_markers);
ce97a2d7 1310
1f90a790
RS
1311 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
1312 offset_intervals (current_buffer, PT, nchars);
1313
1314 intervals = XSTRING (string)->intervals;
ce97a2d7
RS
1315 /* Get the intervals for the part of the string we are inserting--
1316 not including the combined-before bytes. */
fc932ac6 1317 if (nbytes < STRING_BYTES (XSTRING (string)))
1f90a790 1318 intervals = copy_intervals (intervals, pos, nchars);
ce97a2d7
RS
1319
1320 /* Insert those intervals. */
1f90a790 1321 graft_intervals_into_buffer (intervals, PT, nchars,
9391e591 1322 current_buffer, inherit);
ce97a2d7 1323
1f90a790
RS
1324 {
1325 int pos = PT, pos_byte = PT_BYTE;
1326
1327 adjust_point (nchars + combined_after_bytes,
1328 outgoing_nbytes + combined_after_bytes);
1329
1330 if (combined_after_bytes)
1331 combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
1332 combined_after_bytes);
1333
1334 if (combined_before_bytes)
1335 combine_bytes (pos, pos_byte, combined_before_bytes);
1336 }
b45433b3 1337}
3be11131
RS
1338\f
1339/* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
ef29f213
KH
1340 current buffer. If the text in BUF has properties, they are absorbed
1341 into the current buffer.
1342
1343 It does not work to use `insert' for this, because a malloc could happen
1344 and relocate BUF's text before the bcopy happens. */
1345
1346void
3be11131 1347insert_from_buffer (buf, charpos, nchars, inherit)
ef29f213 1348 struct buffer *buf;
3be11131 1349 int charpos, nchars;
ef29f213
KH
1350 int inherit;
1351{
62b82678 1352 int opoint = PT;
3be11131 1353
62b82678
RS
1354 insert_from_buffer_1 (buf, charpos, nchars, inherit);
1355 signal_after_change (opoint, 0, PT - opoint);
ef29f213
KH
1356}
1357
1358static void
3be11131 1359insert_from_buffer_1 (buf, from, nchars, inherit)
ef29f213 1360 struct buffer *buf;
3be11131 1361 int from, nchars;
ef29f213
KH
1362 int inherit;
1363{
0aa8c4b2 1364 register Lisp_Object temp;
ef29f213 1365 int chunk;
3be11131
RS
1366 int from_byte = buf_charpos_to_bytepos (buf, from);
1367 int to_byte = buf_charpos_to_bytepos (buf, from + nchars);
2b083808
RS
1368 int incoming_nbytes = to_byte - from_byte;
1369 int outgoing_nbytes = incoming_nbytes;
432f78d2
RS
1370 int combined_before_bytes, combined_after_bytes;
1371 int adjusted_nchars;
ce97a2d7 1372 INTERVAL intervals;
2b083808
RS
1373
1374 /* Make OUTGOING_NBYTES describe the text
1375 as it will be inserted in this buffer. */
1376
1377 if (NILP (current_buffer->enable_multibyte_characters))
1378 outgoing_nbytes = nchars;
1379 else if (NILP (buf->enable_multibyte_characters))
1380 outgoing_nbytes
1381 = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
1382 incoming_nbytes);
ef29f213
KH
1383
1384 /* Make sure point-max won't overflow after this insertion. */
2b083808
RS
1385 XSETINT (temp, outgoing_nbytes + Z);
1386 if (outgoing_nbytes + Z != XINT (temp))
3be11131 1387 error ("Maximum buffer size exceeded");
ef29f213 1388
35d63725
RS
1389 /* Do this before moving and increasing the gap,
1390 because the before-change hooks might move the gap
1391 or make it smaller. */
d206af14 1392 prepare_to_modify_buffer (PT, PT, NULL);
ef29f213
KH
1393
1394 if (PT != GPT)
3be11131 1395 move_gap_both (PT, PT_BYTE);
2b083808
RS
1396 if (GAP_SIZE < outgoing_nbytes)
1397 make_gap (outgoing_nbytes - GAP_SIZE);
ef29f213 1398
3be11131 1399 if (from < BUF_GPT (buf))
ef29f213 1400 {
3be11131 1401 chunk = BUF_GPT_BYTE (buf) - from_byte;
2b083808
RS
1402 if (chunk > incoming_nbytes)
1403 chunk = incoming_nbytes;
1404 copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
1405 GPT_ADDR, chunk,
1406 ! NILP (buf->enable_multibyte_characters),
1407 ! NILP (current_buffer->enable_multibyte_characters));
ef29f213
KH
1408 }
1409 else
1410 chunk = 0;
2b083808
RS
1411 if (chunk < incoming_nbytes)
1412 copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
1413 GPT_ADDR + chunk, incoming_nbytes - chunk,
1414 ! NILP (buf->enable_multibyte_characters),
1415 ! NILP (current_buffer->enable_multibyte_characters));
ef29f213 1416
432f78d2
RS
1417 /* We have copied text into the gap, but we have not altered
1418 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1419 to these functions and get the same results as we would
1f90a790 1420 have got earlier on. Meanwhile, GPT_ADDR does point to
432f78d2
RS
1421 the text that has been stored by copy_text. */
1422 combined_before_bytes
1f90a790 1423 = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
432f78d2 1424 combined_after_bytes
1f90a790 1425 = count_combining_after (GPT_ADDR, outgoing_nbytes,
432f78d2
RS
1426 PT, PT_BYTE);
1427
432f78d2
RS
1428 /* Record deletion of the surrounding text that combines with
1429 the insertion. This, together with recording the insertion,
1430 will add up to the right stuff in the undo list.
1431
1432 But there is no need to actually delete the combining bytes
1433 from the buffer and reinsert them. */
1434
1435 if (combined_after_bytes)
7cc3983f 1436 {
0aa8c4b2
RS
1437 Lisp_Object deletion;
1438 deletion = Qnil;
1439
1440 if (! EQ (current_buffer->undo_list, Qt))
1441 deletion = make_buffer_string_both (PT, PT_BYTE,
1442 PT + combined_after_bytes,
1443 PT_BYTE + combined_after_bytes, 1);
628cea90 1444
7cc3983f
RS
1445 adjust_markers_for_record_delete (PT, PT_BYTE,
1446 PT + combined_after_bytes,
1447 PT_BYTE + combined_after_bytes);
0aa8c4b2
RS
1448 if (! EQ (current_buffer->undo_list, Qt))
1449 record_delete (PT, deletion);
7cc3983f 1450 }
432f78d2
RS
1451
1452 if (combined_before_bytes)
7cc3983f 1453 {
0aa8c4b2
RS
1454 Lisp_Object deletion;
1455 deletion = Qnil;
1456
1457 if (! EQ (current_buffer->undo_list, Qt))
1458 deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
1459 PT, PT_BYTE, 1);
7cc3983f
RS
1460 adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
1461 PT, PT_BYTE);
0aa8c4b2
RS
1462 if (! EQ (current_buffer->undo_list, Qt))
1463 record_delete (PT - 1, deletion);
7cc3983f 1464 }
432f78d2 1465
e0c0ed58
RS
1466 record_insert (PT - !!combined_before_bytes,
1467 nchars - combined_before_bytes + !!combined_before_bytes);
432f78d2
RS
1468 MODIFF++;
1469
2b083808 1470 GAP_SIZE -= outgoing_nbytes;
1f90a790
RS
1471 GPT += nchars;
1472 ZV += nchars;
1473 Z += nchars;
2b083808
RS
1474 GPT_BYTE += outgoing_nbytes;
1475 ZV_BYTE += outgoing_nbytes;
1476 Z_BYTE += outgoing_nbytes;
469ff680 1477 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1f90a790
RS
1478
1479 if (combined_after_bytes)
1480 move_gap_both (GPT + combined_after_bytes,
1481 GPT_BYTE + combined_after_bytes);
1482
1483 if (GPT_BYTE < GPT)
1484 abort ();
1485
1486 adjust_overlays_for_insert (PT, nchars);
1487 adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
432f78d2
RS
1488 PT_BYTE + outgoing_nbytes,
1489 combined_before_bytes, combined_after_bytes, 0);
ce97a2d7 1490
1f90a790
RS
1491#ifdef USE_TEXT_PROPERTIES
1492 if (BUF_INTERVALS (current_buffer) != 0)
1493 offset_intervals (current_buffer, PT, nchars);
1494#endif
ce97a2d7
RS
1495
1496 /* Get the intervals for the part of the string we are inserting--
1497 not including the combined-before bytes. */
1498 intervals = BUF_INTERVALS (buf);
1f90a790
RS
1499 if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
1500 intervals = copy_intervals (intervals, from, nchars);
ce97a2d7
RS
1501
1502 /* Insert those intervals. */
1f90a790 1503 graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
ce97a2d7 1504
1f90a790
RS
1505 {
1506 int pos = PT, pos_byte = PT_BYTE;
ce97a2d7 1507
1f90a790
RS
1508 adjust_point (nchars + combined_after_bytes,
1509 outgoing_nbytes + combined_after_bytes);
432f78d2 1510
1f90a790
RS
1511 if (combined_after_bytes)
1512 combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
1513 combined_after_bytes);
3be11131 1514
1f90a790
RS
1515 if (combined_before_bytes)
1516 combine_bytes (pos, pos_byte, combined_before_bytes);
1517 }
b45433b3
JB
1518}
1519\f
2d9eea44 1520/* This function should be called after moving gap to FROM and before
59a52d50
KH
1521 altering text between FROM and TO. This adjusts various position
1522 keepers and markers as if the text is deleted. Don't forget to
1523 call adjust_after_replace after you actually alter the text. */
2d9eea44 1524
1e9c7b7d
KH
1525void
1526adjust_before_replace (from, from_byte, to, to_byte)
1527 int from, from_byte, to, to_byte;
1528{
628cea90 1529 Lisp_Object deletion;
0aa8c4b2
RS
1530
1531 if (! EQ (current_buffer->undo_list, Qt))
1532 deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
628cea90 1533
60ea6052
RS
1534 CHECK_MARKERS ();
1535
1e9c7b7d 1536 adjust_markers_for_delete (from, from_byte, to, to_byte);
0aa8c4b2
RS
1537
1538 if (! EQ (current_buffer->undo_list, Qt))
1539 record_delete (from, deletion);
1540
61415a25 1541 adjust_overlays_for_delete (from, to - from);
1e9c7b7d
KH
1542}
1543
652838b5
KH
1544/* Record undo information and adjust markers and position keepers for
1545 a replacement of a text PREV_TEXT at FROM to a new text of LEN
1546 chars (LEN_BYTE bytes) which resides in the gap just after
1547 GPT_ADDR.
1548
1549 PREV_TEXT nil means the new text was just inserted. */
2d9eea44 1550
1e9c7b7d 1551void
652838b5
KH
1552adjust_after_replace (from, from_byte, prev_text, len, len_byte)
1553 int from, from_byte, len, len_byte;
1554 Lisp_Object prev_text;
1e9c7b7d 1555{
61415a25
KH
1556 int combined_before_bytes
1557 = count_combining_before (GPT_ADDR, len_byte, from, from_byte);
1558 int combined_after_bytes
1559 = count_combining_after (GPT_ADDR, len_byte, from, from_byte);
652838b5 1560 int nchars_del = 0, nbytes_del = 0;
61415a25
KH
1561
1562 if (combined_after_bytes)
7cc3983f 1563 {
0aa8c4b2
RS
1564 Lisp_Object deletion;
1565 deletion = Qnil;
1566
1567 if (! EQ (current_buffer->undo_list, Qt))
1568 deletion = make_buffer_string_both (from, from_byte,
1569 from + combined_after_bytes,
1570 from_byte + combined_after_bytes,
1571 1);
628cea90 1572
7cc3983f
RS
1573 adjust_markers_for_record_delete (from, from_byte,
1574 from + combined_after_bytes,
1575 from_byte + combined_after_bytes);
0aa8c4b2
RS
1576
1577 if (! EQ (current_buffer->undo_list, Qt))
1578 record_delete (from, deletion);
7cc3983f 1579 }
61415a25
KH
1580
1581 if (combined_before_bytes)
7cc3983f 1582 {
0aa8c4b2
RS
1583 Lisp_Object deletion;
1584 deletion = Qnil;
1585
1586 if (! EQ (current_buffer->undo_list, Qt))
1587 deletion = make_buffer_string_both (from - 1, CHAR_TO_BYTE (from - 1),
1588 from, from_byte, 1);
7cc3983f
RS
1589 adjust_markers_for_record_delete (from - 1, CHAR_TO_BYTE (from - 1),
1590 from, from_byte);
0aa8c4b2
RS
1591 if (! EQ (current_buffer->undo_list, Qt))
1592 record_delete (from - 1, deletion);
7cc3983f 1593 }
61415a25
KH
1594
1595 /* Update various buffer positions for the new text. */
1596 GAP_SIZE -= len_byte;
1597 ZV += len; Z+= len;
1598 ZV_BYTE += len_byte; Z_BYTE += len_byte;
1599 GPT += len; GPT_BYTE += len_byte;
1600 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1601
1602 if (combined_after_bytes)
1603 move_gap_both (GPT + combined_after_bytes,
1604 GPT_BYTE + combined_after_bytes);
1605
652838b5
KH
1606 if (STRINGP (prev_text))
1607 {
1608 nchars_del = XSTRING (prev_text)->size;
1609 nbytes_del = STRING_BYTES (XSTRING (prev_text));
1610 }
1611 adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
1612 len, len_byte,
1613 combined_before_bytes, combined_after_bytes);
1614 if (STRINGP (prev_text))
1615 record_delete (from, prev_text);
e0c0ed58
RS
1616 record_insert (from - !!combined_before_bytes,
1617 len - combined_before_bytes + !!combined_before_bytes);
652838b5
KH
1618
1619 if (len > nchars_del)
1620 adjust_overlays_for_insert (from, len - nchars_del);
1621 else if (len < nchars_del)
1622 adjust_overlays_for_delete (from, nchars_del - len);
61415a25
KH
1623#ifdef USE_TEXT_PROPERTIES
1624 if (BUF_INTERVALS (current_buffer) != 0)
652838b5 1625 offset_intervals (current_buffer, from, len - nchars_del);
61415a25
KH
1626#endif
1627
1628 {
1629 int pos = PT, pos_byte = PT_BYTE;
1630
1631 if (from < PT)
652838b5
KH
1632 adjust_point (len - nchars_del + combined_after_bytes,
1633 len_byte - nbytes_del + combined_after_bytes);
61415a25
KH
1634 else if (from == PT && combined_before_bytes)
1635 adjust_point (0, combined_before_bytes);
1636
1637 if (combined_after_bytes)
1638 combine_bytes (from + len, from_byte + len_byte, combined_after_bytes);
1639
1640 if (combined_before_bytes)
1641 combine_bytes (from, from_byte, combined_before_bytes);
1642 }
1643
60ea6052
RS
1644 CHECK_MARKERS ();
1645
1e9c7b7d
KH
1646 if (len == 0)
1647 evaporate_overlays (from);
1648 MODIFF++;
1e9c7b7d
KH
1649}
1650
652838b5
KH
1651/* Record undo information, adjust markers and position keepers for an
1652 insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE). The
1653 text already exists in the current buffer but character length (TO
1654 - FROM) may be incorrect, the correct length is NEWLEN. */
1655
1656void
1657adjust_after_insert (from, from_byte, to, to_byte, newlen)
1658 int from, from_byte, to, to_byte, newlen;
1659{
1660 int len = to - from, len_byte = to_byte - from_byte;
1661
1662 if (GPT != to)
1663 move_gap_both (to, to_byte);
1664 GAP_SIZE += len_byte;
1665 GPT -= len; GPT_BYTE -= len_byte;
1666 ZV -= len; ZV_BYTE -= len_byte;
1667 Z -= len; Z_BYTE -= len_byte;
1668 adjust_after_replace (from, from_byte, Qnil, newlen, len_byte);
1669}
1670
3be11131 1671/* Replace the text from character positions FROM to TO with NEW,
c5ca4d3a
RS
1672 If PREPARE is nonzero, call prepare_to_modify_buffer.
1673 If INHERIT, the newly inserted text should inherit text properties
1674 from the surrounding non-deleted text. */
1675
1676/* Note that this does not yet handle markers quite right.
1677 Also it needs to record a single undo-entry that does a replacement
1678 rather than a separate delete and insert.
1679 That way, undo will also handle markers properly. */
1680
1681void
2db5082f 1682replace_range (from, to, new, prepare, inherit, nomarkers)
c5ca4d3a 1683 Lisp_Object new;
2db5082f 1684 int from, to, prepare, inherit, nomarkers;
c5ca4d3a 1685{
2b083808 1686 int inschars = XSTRING (new)->size;
fc932ac6 1687 int insbytes = STRING_BYTES (XSTRING (new));
3be11131
RS
1688 int from_byte, to_byte;
1689 int nbytes_del, nchars_del;
c5ca4d3a
RS
1690 register Lisp_Object temp;
1691 struct gcpro gcpro1;
432f78d2
RS
1692 int combined_before_bytes, combined_after_bytes;
1693 int adjusted_inschars;
ce97a2d7 1694 INTERVAL intervals;
1f90a790 1695 int outgoing_insbytes = insbytes;
c5ca4d3a 1696
60ea6052
RS
1697 CHECK_MARKERS ();
1698
c5ca4d3a
RS
1699 GCPRO1 (new);
1700
1701 if (prepare)
1702 {
1703 int range_length = to - from;
1704 prepare_to_modify_buffer (from, to, &from);
1705 to = from + range_length;
1706 }
1707
3be11131
RS
1708 UNGCPRO;
1709
c5ca4d3a
RS
1710 /* Make args be valid */
1711 if (from < BEGV)
1712 from = BEGV;
1713 if (to > ZV)
1714 to = ZV;
1715
3be11131
RS
1716 from_byte = CHAR_TO_BYTE (from);
1717 to_byte = CHAR_TO_BYTE (to);
c5ca4d3a 1718
3be11131
RS
1719 nchars_del = to - from;
1720 nbytes_del = to_byte - from_byte;
1721
1722 if (nbytes_del <= 0 && insbytes == 0)
1723 return;
c5ca4d3a 1724
1f90a790
RS
1725 /* Make OUTGOING_INSBYTES describe the text
1726 as it will be inserted in this buffer. */
1727
1728 if (NILP (current_buffer->enable_multibyte_characters))
1729 outgoing_insbytes = inschars;
2a1d8be0 1730 else if (! STRING_MULTIBYTE (new))
1f90a790
RS
1731 outgoing_insbytes
1732 = count_size_as_multibyte (XSTRING (new)->data, insbytes);
1733
c5ca4d3a 1734 /* Make sure point-max won't overflow after this insertion. */
3be11131
RS
1735 XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
1736 if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
1737 error ("Maximum buffer size exceeded");
c5ca4d3a 1738
c5ca4d3a
RS
1739 GCPRO1 (new);
1740
1741 /* Make sure the gap is somewhere in or next to what we are deleting. */
1742 if (from > GPT)
3be11131 1743 gap_right (from, from_byte);
c5ca4d3a 1744 if (to < GPT)
3be11131 1745 gap_left (to, to_byte, 0);
c5ca4d3a 1746
0aa8c4b2
RS
1747 {
1748 Lisp_Object deletion;
1749 deletion = Qnil;
1750
1751 if (! EQ (current_buffer->undo_list, Qt))
1752 deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
628cea90 1753
0aa8c4b2
RS
1754 if (nomarkers)
1755 /* Relocate all markers pointing into the new, larger gap
1756 to point at the end of the text before the gap.
1757 Do this before recording the deletion,
1758 so that undo handles this after reinserting the text. */
1759 adjust_markers_for_delete (from, from_byte, to, to_byte);
c5ca4d3a 1760
0aa8c4b2
RS
1761 if (! EQ (current_buffer->undo_list, Qt))
1762 record_delete (from, deletion);
1763 }
c5ca4d3a 1764
3be11131
RS
1765 GAP_SIZE += nbytes_del;
1766 ZV -= nchars_del;
1767 Z -= nchars_del;
1768 ZV_BYTE -= nbytes_del;
1769 Z_BYTE -= nbytes_del;
c5ca4d3a 1770 GPT = from;
3be11131 1771 GPT_BYTE = from_byte;
c5ca4d3a
RS
1772 *(GPT_ADDR) = 0; /* Put an anchor. */
1773
3be11131
RS
1774 if (GPT_BYTE < GPT)
1775 abort ();
1776
c5ca4d3a
RS
1777 if (GPT - BEG < beg_unchanged)
1778 beg_unchanged = GPT - BEG;
1779 if (Z - GPT < end_unchanged)
1780 end_unchanged = Z - GPT;
1781
3be11131
RS
1782 if (GAP_SIZE < insbytes)
1783 make_gap (insbytes - GAP_SIZE);
c5ca4d3a 1784
1f90a790
RS
1785 /* Copy the string text into the buffer, perhaps converting
1786 between single-byte and multibyte. */
1787 copy_text (XSTRING (new)->data, GPT_ADDR, insbytes,
2a1d8be0 1788 STRING_MULTIBYTE (new),
1f90a790
RS
1789 ! NILP (current_buffer->enable_multibyte_characters));
1790
432f78d2
RS
1791 /* We have copied text into the gap, but we have not altered
1792 PT or PT_BYTE yet. So we can pass PT and PT_BYTE
1793 to these functions and get the same results as we would
1f90a790 1794 have got earlier on. Meanwhile, GPT_ADDR does point to
432f78d2
RS
1795 the text that has been stored by copy_text. */
1796
1797 combined_before_bytes
1f90a790 1798 = count_combining_before (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
432f78d2 1799 combined_after_bytes
1f90a790 1800 = count_combining_after (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
432f78d2
RS
1801
1802 /* Record deletion of the surrounding text that combines with
1803 the insertion. This, together with recording the insertion,
1804 will add up to the right stuff in the undo list.
1805
1806 But there is no need to actually delete the combining bytes
1807 from the buffer and reinsert them. */
1808
1809 if (combined_after_bytes)
7cc3983f 1810 {
0aa8c4b2
RS
1811 Lisp_Object deletion;
1812 deletion = Qnil;
1813
1814 if (! EQ (current_buffer->undo_list, Qt))
1815 deletion = make_buffer_string_both (PT, PT_BYTE,
1816 PT + combined_after_bytes,
1817 PT_BYTE + combined_after_bytes, 1);
628cea90 1818
7cc3983f
RS
1819 adjust_markers_for_record_delete (PT, PT_BYTE,
1820 PT + combined_after_bytes,
1821 PT_BYTE + combined_after_bytes);
0aa8c4b2
RS
1822 if (! EQ (current_buffer->undo_list, Qt))
1823 record_delete (PT, deletion);
7cc3983f 1824 }
432f78d2
RS
1825
1826 if (combined_before_bytes)
7cc3983f 1827 {
0aa8c4b2
RS
1828 Lisp_Object deletion;
1829 deletion = Qnil;
1830
1831 if (! EQ (current_buffer->undo_list, Qt))
1832 deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1),
1833 PT, PT_BYTE, 1);
7cc3983f
RS
1834 adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1),
1835 PT, PT_BYTE);
0aa8c4b2
RS
1836 if (! EQ (current_buffer->undo_list, Qt))
1837 record_delete (PT - 1, deletion);
7cc3983f 1838 }
432f78d2 1839
e0c0ed58
RS
1840 record_insert (PT - !!combined_before_bytes,
1841 inschars - combined_before_bytes + !!combined_before_bytes);
c5ca4d3a 1842
1f90a790
RS
1843 GAP_SIZE -= outgoing_insbytes;
1844 GPT += inschars;
1845 ZV += inschars;
1846 Z += inschars;
1847 GPT_BYTE += outgoing_insbytes;
1848 ZV_BYTE += outgoing_insbytes;
1849 Z_BYTE += outgoing_insbytes;
c5ca4d3a
RS
1850 if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
1851
1f90a790
RS
1852 if (combined_after_bytes)
1853 move_gap_both (GPT + combined_after_bytes,
1854 GPT_BYTE + combined_after_bytes);
1855
3be11131
RS
1856 if (GPT_BYTE < GPT)
1857 abort ();
1858
c5ca4d3a
RS
1859 /* Adjust the overlay center as needed. This must be done after
1860 adjusting the markers that bound the overlays. */
3be11131 1861 adjust_overlays_for_delete (from, nchars_del);
1f90a790 1862 adjust_overlays_for_insert (from, inschars);
2db5082f
RS
1863 if (nomarkers)
1864 adjust_markers_for_insert (from, from_byte,
1865 from + inschars, from_byte + outgoing_insbytes,
1866 combined_before_bytes, combined_after_bytes, 0);
c5ca4d3a 1867
1f90a790
RS
1868#ifdef USE_TEXT_PROPERTIES
1869 offset_intervals (current_buffer, PT, inschars - nchars_del);
ce97a2d7
RS
1870
1871 /* Get the intervals for the part of the string we are inserting--
1872 not including the combined-before bytes. */
1873 intervals = XSTRING (new)->intervals;
ce97a2d7 1874 /* Insert those intervals. */
1f90a790 1875 graft_intervals_into_buffer (intervals, from, inschars,
ce97a2d7 1876 current_buffer, inherit);
1f90a790 1877#endif
c5ca4d3a 1878
1f90a790
RS
1879 /* Relocate point as if it were a marker. */
1880 if (from < PT)
1881 adjust_point ((from + inschars - (PT < to ? PT : to)
1882 + combined_after_bytes),
1883 (from_byte + outgoing_insbytes
1884 - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
1885 + combined_after_bytes));
c5ca4d3a 1886
93b882e8 1887 if (combined_after_bytes)
1f90a790
RS
1888 combine_bytes (from + inschars, from_byte + outgoing_insbytes,
1889 combined_after_bytes);
1890
1891 if (combined_before_bytes)
1892 combine_bytes (from, from_byte, combined_before_bytes);
1893
1894 if (outgoing_insbytes == 0)
1895 evaporate_overlays (from);
93b882e8 1896
60ea6052
RS
1897 CHECK_MARKERS ();
1898
c5ca4d3a
RS
1899 MODIFF++;
1900 UNGCPRO;
1901
1f90a790 1902 signal_after_change (from, nchars_del, PT - from);
c5ca4d3a
RS
1903}
1904\f
b45433b3 1905/* Delete characters in current buffer
3be11131
RS
1906 from FROM up to (but not including) TO.
1907 If TO comes before FROM, we delete nothing. */
b45433b3 1908
c660b094 1909void
b45433b3
JB
1910del_range (from, to)
1911 register int from, to;
47c64747 1912{
c660b094 1913 del_range_1 (from, to, 1);
47c64747
RS
1914}
1915
1916/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */
1917
c660b094 1918void
47c64747 1919del_range_1 (from, to, prepare)
d206af14 1920 int from, to, prepare;
b45433b3 1921{
3be11131
RS
1922 int from_byte, to_byte;
1923
1924 /* Make args be valid */
1925 if (from < BEGV)
1926 from = BEGV;
1927 if (to > ZV)
1928 to = ZV;
1929
1930 if (to <= from)
1931 return;
1932
1933 if (prepare)
1934 {
1935 int range_length = to - from;
1936 prepare_to_modify_buffer (from, to, &from);
1937 to = from + range_length;
1938 }
1939
1940 from_byte = CHAR_TO_BYTE (from);
1941 to_byte = CHAR_TO_BYTE (to);
1942
a66afea0 1943 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
1944}
1945
1946/* Like del_range_1 but args are byte positions, not char positions. */
1947
1948void
1949del_range_byte (from_byte, to_byte, prepare)
1950 int from_byte, to_byte, prepare;
1951{
1952 int from, to;
1953
1954 /* Make args be valid */
1955 if (from_byte < BEGV_BYTE)
1956 from_byte = BEGV_BYTE;
1957 if (to_byte > ZV_BYTE)
1958 to_byte = ZV_BYTE;
1959
1960 if (to_byte <= from_byte)
1961 return;
1962
1963 from = BYTE_TO_CHAR (from_byte);
1964 to = BYTE_TO_CHAR (to_byte);
b45433b3 1965
d206af14
RS
1966 if (prepare)
1967 {
3be11131 1968 int old_from = from, old_to = Z - to;
d206af14
RS
1969 int range_length = to - from;
1970 prepare_to_modify_buffer (from, to, &from);
1971 to = from + range_length;
3be11131
RS
1972
1973 if (old_from != from)
1974 from_byte = CHAR_TO_BYTE (from);
1975 if (old_to == Z - to)
1976 to_byte = CHAR_TO_BYTE (to);
d206af14
RS
1977 }
1978
a66afea0 1979 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
1980}
1981
1982/* Like del_range_1, but positions are specified both as charpos
1983 and bytepos. */
1984
1985void
353800c7
KH
1986del_range_both (from, from_byte, to, to_byte, prepare)
1987 int from, from_byte, to, to_byte, prepare;
3be11131 1988{
b45433b3 1989 /* Make args be valid */
3be11131
RS
1990 if (from_byte < BEGV_BYTE)
1991 from_byte = BEGV_BYTE;
1992 if (to_byte > ZV_BYTE)
1993 to_byte = ZV_BYTE;
1994
1995 if (to_byte <= from_byte)
1996 return;
1997
b45433b3
JB
1998 if (from < BEGV)
1999 from = BEGV;
2000 if (to > ZV)
2001 to = ZV;
2002
3be11131
RS
2003 if (prepare)
2004 {
2005 int old_from = from, old_to = Z - to;
2006 int range_length = to - from;
2007 prepare_to_modify_buffer (from, to, &from);
2008 to = from + range_length;
2009
2010 if (old_from != from)
2011 from_byte = CHAR_TO_BYTE (from);
2012 if (old_to == Z - to)
2013 to_byte = CHAR_TO_BYTE (to);
2014 }
2015
a66afea0 2016 del_range_2 (from, from_byte, to, to_byte);
3be11131
RS
2017}
2018
2019/* Delete a range of text, specified both as character positions
2020 and byte positions. FROM and TO are character positions,
2021 while FROM_BYTE and TO_BYTE are byte positions. */
2022
2023void
a66afea0
KH
2024del_range_2 (from, from_byte, to, to_byte)
2025 int from, from_byte, to, to_byte;
3be11131
RS
2026{
2027 register int nbytes_del, nchars_del;
1f90a790 2028 int combined_after_bytes;
628cea90
RS
2029 Lisp_Object deletion;
2030 int from_byte_1;
3be11131 2031
60ea6052
RS
2032 CHECK_MARKERS ();
2033
3be11131
RS
2034 nchars_del = to - from;
2035 nbytes_del = to_byte - from_byte;
b45433b3
JB
2036
2037 /* Make sure the gap is somewhere in or next to what we are deleting. */
2038 if (from > GPT)
3be11131 2039 gap_right (from, from_byte);
b45433b3 2040 if (to < GPT)
3be11131 2041 gap_left (to, to_byte, 0);
b45433b3 2042
e0c0ed58 2043 combined_after_bytes
e3a87305
KH
2044 = count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
2045 ZV_BYTE - to_byte, from, from_byte);
628cea90
RS
2046 if (combined_after_bytes)
2047 {
2048 from_byte_1 = from_byte;
2049 DEC_POS (from_byte_1);
2050 }
2051 else
2052 from_byte_1 = from_byte;
2053
0aa8c4b2
RS
2054 if (! EQ (current_buffer->undo_list, Qt))
2055 deletion
2056 = make_buffer_string_both (from - !!combined_after_bytes,
2057 from_byte_1,
2058 to + combined_after_bytes,
2059 to_byte + combined_after_bytes, 1);
242beafe
KH
2060 if (combined_after_bytes)
2061 /* COMBINED_AFTER_BYTES nonzero means that the above code moved
2062 the gap. We must move the gap again to a proper place. */
2063 move_gap_both (from, from_byte);
e0c0ed58 2064
8948d317
RS
2065 /* Relocate all markers pointing into the new, larger gap
2066 to point at the end of the text before the gap.
3be11131
RS
2067 Do this before recording the deletion,
2068 so that undo handles this after reinserting the text. */
2069 adjust_markers_for_delete (from, from_byte, to, to_byte);
7cc3983f
RS
2070 if (combined_after_bytes)
2071 {
7cc3983f
RS
2072 /* Adjust markers for the phony deletion
2073 that we are about to call record_undo for. */
2074
2075 /* Here we delete the markers that formerly
2076 pointed at TO ... TO + COMBINED_AFTER_BYTES.
2077 But because of the call to adjust_markers_for_delete, above,
2078 they now point at FROM ... FROM + COMBINED_AFTER_BYTES. */
2079 adjust_markers_for_record_delete (from, from_byte,
2080 from + combined_after_bytes,
2081 from_byte + combined_after_bytes);
2082
2083 adjust_markers_for_record_delete (from - 1, from_byte_1,
2084 from, from_byte);
2085 }
0aa8c4b2
RS
2086 if (! EQ (current_buffer->undo_list, Qt))
2087 record_delete (from - !!combined_after_bytes, deletion);
be09561e
RS
2088 MODIFF++;
2089
b45433b3 2090 /* Relocate point as if it were a marker. */
2bcaed71 2091 if (from < PT)
3be11131
RS
2092 adjust_point (from - (PT < to ? PT : to),
2093 from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte));
b45433b3 2094
16032db6 2095 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
3be11131 2096 offset_intervals (current_buffer, from, - nchars_del);
16032db6 2097
adde4858 2098 /* Adjust the overlay center as needed. This must be done after
a7f38d28 2099 adjusting the markers that bound the overlays. */
e3a87305 2100 adjust_overlays_for_delete (from, nchars_del);
adde4858 2101
3be11131
RS
2102 GAP_SIZE += nbytes_del;
2103 ZV_BYTE -= nbytes_del;
2104 Z_BYTE -= nbytes_del;
2105 ZV -= nchars_del;
2106 Z -= nchars_del;
b45433b3 2107 GPT = from;
3be11131 2108 GPT_BYTE = from_byte;
b45433b3 2109
e0c0ed58
RS
2110 if (combined_after_bytes)
2111 move_gap_both (GPT + combined_after_bytes,
2112 GPT_BYTE + combined_after_bytes);
2113
e3a87305
KH
2114 *(GPT_ADDR) = 0; /* Put an anchor. */
2115
3be11131
RS
2116 if (GPT_BYTE < GPT)
2117 abort ();
2118
b45433b3
JB
2119 if (GPT - BEG < beg_unchanged)
2120 beg_unchanged = GPT - BEG;
2121 if (Z - GPT < end_unchanged)
2122 end_unchanged = Z - GPT;
2123
1f90a790 2124 if (combined_after_bytes)
7cc3983f
RS
2125 {
2126 combine_bytes (from, from_byte, combined_after_bytes);
1f90a790 2127
7cc3983f
RS
2128 record_insert (GPT - 1, 1);
2129 }
1f90a790 2130
60ea6052
RS
2131 CHECK_MARKERS ();
2132
d386034e 2133 evaporate_overlays (from);
3be11131 2134 signal_after_change (from, nchars_del, 0);
b45433b3
JB
2135}
2136\f
3be11131
RS
2137/* Call this if you're about to change the region of BUFFER from
2138 character positions START to END. This checks the read-only
2139 properties of the region, calls the necessary modification hooks,
2140 and warns the next redisplay that it should pay attention to that
2141 area. */
2142
c660b094 2143void
04a759c8
JB
2144modify_region (buffer, start, end)
2145 struct buffer *buffer;
b45433b3
JB
2146 int start, end;
2147{
04a759c8
JB
2148 struct buffer *old_buffer = current_buffer;
2149
2150 if (buffer != old_buffer)
2151 set_buffer_internal (buffer);
2152
d206af14 2153 prepare_to_modify_buffer (start, end, NULL);
b45433b3 2154
894ab630
RS
2155 if (start - 1 < beg_unchanged
2156 || (unchanged_modified == MODIFF
2157 && overlay_unchanged_modified == OVERLAY_MODIFF))
b45433b3
JB
2158 beg_unchanged = start - 1;
2159 if (Z - end < end_unchanged
894ab630
RS
2160 || (unchanged_modified == MODIFF
2161 && overlay_unchanged_modified == OVERLAY_MODIFF))
b45433b3 2162 end_unchanged = Z - end;
83010cd6 2163
9fbf87cd 2164 if (MODIFF <= SAVE_MODIFF)
83010cd6 2165 record_first_change ();
b45433b3 2166 MODIFF++;
04a759c8 2167
069cdc4f
RS
2168 buffer->point_before_scroll = Qnil;
2169
04a759c8
JB
2170 if (buffer != old_buffer)
2171 set_buffer_internal (old_buffer);
b45433b3 2172}
d206af14 2173\f
3be11131
RS
2174/* Check that it is okay to modify the buffer between START and END,
2175 which are char positions.
2176
679194a6
JA
2177 Run the before-change-function, if any. If intervals are in use,
2178 verify that the text to be modified is not read-only, and call
d206af14
RS
2179 any modification properties the text may have.
2180
2181 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
2182 by holding its value temporarily in a marker. */
b45433b3 2183
c660b094 2184void
d206af14 2185prepare_to_modify_buffer (start, end, preserve_ptr)
fb4ee5cd 2186 int start, end;
d206af14 2187 int *preserve_ptr;
b45433b3 2188{
d427b66a 2189 if (!NILP (current_buffer->read_only))
b45433b3
JB
2190 Fbarf_if_buffer_read_only ();
2191
679194a6 2192 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
9fbf87cd 2193 if (BUF_INTERVALS (current_buffer) != 0)
d206af14
RS
2194 {
2195 if (preserve_ptr)
2196 {
2197 Lisp_Object preserve_marker;
2198 struct gcpro gcpro1;
2199 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil);
2200 GCPRO1 (preserve_marker);
2201 verify_interval_modification (current_buffer, start, end);
2202 *preserve_ptr = marker_position (preserve_marker);
2203 unchain_marker (preserve_marker);
2204 UNGCPRO;
2205 }
2206 else
2207 verify_interval_modification (current_buffer, start, end);
2208 }
b45433b3
JB
2209
2210#ifdef CLASH_DETECTION
f173b650 2211 if (!NILP (current_buffer->file_truename)
ab6c5c0c
RS
2212 /* Make binding buffer-file-name to nil effective. */
2213 && !NILP (current_buffer->filename)
9fbf87cd 2214 && SAVE_MODIFF >= MODIFF)
f173b650 2215 lock_file (current_buffer->file_truename);
b45433b3
JB
2216#else
2217 /* At least warn if this file has changed on disk since it was visited. */
d427b66a 2218 if (!NILP (current_buffer->filename)
9fbf87cd 2219 && SAVE_MODIFF >= MODIFF
d427b66a
JB
2220 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
2221 && !NILP (Ffile_exists_p (current_buffer->filename)))
b45433b3
JB
2222 call1 (intern ("ask-user-about-supersession-threat"),
2223 current_buffer->filename);
2224#endif /* not CLASH_DETECTION */
2225
d206af14 2226 signal_before_change (start, end, preserve_ptr);
2f545eea 2227
56e1065e
JB
2228 if (current_buffer->newline_cache)
2229 invalidate_region_cache (current_buffer,
2230 current_buffer->newline_cache,
2231 start - BEG, Z - end);
2232 if (current_buffer->width_run_cache)
2233 invalidate_region_cache (current_buffer,
2234 current_buffer->width_run_cache,
2235 start - BEG, Z - end);
2236
2f545eea 2237 Vdeactivate_mark = Qt;
b45433b3
JB
2238}
2239\f
d206af14
RS
2240/* These macros work with an argument named `preserve_ptr'
2241 and a local variable named `preserve_marker'. */
2242
2243#define PRESERVE_VALUE \
2244 if (preserve_ptr && NILP (preserve_marker)) \
2245 preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
2246
2247#define RESTORE_VALUE \
2248 if (! NILP (preserve_marker)) \
2249 { \
2250 *preserve_ptr = marker_position (preserve_marker); \
2251 unchain_marker (preserve_marker); \
2252 }
2253
b86e0aaf
RS
2254#define PRESERVE_START_END \
2255 if (NILP (start_marker)) \
2256 start_marker = Fcopy_marker (start, Qnil); \
2257 if (NILP (end_marker)) \
2258 end_marker = Fcopy_marker (end, Qnil);
2259
2260#define FETCH_START \
2261 (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
2262
2263#define FETCH_END \
2264 (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
2265
eb8c3be9 2266/* Signal a change to the buffer immediately before it happens.
d206af14
RS
2267 START_INT and END_INT are the bounds of the text to be changed.
2268
2269 If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
2270 by holding its value temporarily in a marker. */
b45433b3 2271
c660b094 2272void
d206af14 2273signal_before_change (start_int, end_int, preserve_ptr)
6022d493 2274 int start_int, end_int;
d206af14 2275 int *preserve_ptr;
b45433b3 2276{
fb4ee5cd 2277 Lisp_Object start, end;
b86e0aaf 2278 Lisp_Object start_marker, end_marker;
d206af14 2279 Lisp_Object preserve_marker;
b86e0aaf 2280 struct gcpro gcpro1, gcpro2, gcpro3;
fb4ee5cd
RS
2281
2282 start = make_number (start_int);
2283 end = make_number (end_int);
d206af14 2284 preserve_marker = Qnil;
b86e0aaf
RS
2285 start_marker = Qnil;
2286 end_marker = Qnil;
2287 GCPRO3 (preserve_marker, start_marker, end_marker);
fb4ee5cd 2288
b45433b3 2289 /* If buffer is unmodified, run a special hook for that case. */
9fbf87cd 2290 if (SAVE_MODIFF >= MODIFF
dbc4e1c1
JB
2291 && !NILP (Vfirst_change_hook)
2292 && !NILP (Vrun_hooks))
d206af14
RS
2293 {
2294 PRESERVE_VALUE;
b86e0aaf 2295 PRESERVE_START_END;
d206af14
RS
2296 call1 (Vrun_hooks, Qfirst_change_hook);
2297 }
dbc4e1c1 2298
3d1e2d9c
RS
2299 /* Run the before-change-function if any.
2300 We don't bother "binding" this variable to nil
2301 because it is obsolete anyway and new code should not use it. */
d427b66a 2302 if (!NILP (Vbefore_change_function))
d206af14
RS
2303 {
2304 PRESERVE_VALUE;
b86e0aaf
RS
2305 PRESERVE_START_END;
2306 call2 (Vbefore_change_function, FETCH_START, FETCH_END);
d206af14 2307 }
e45fb8bf 2308
3d1e2d9c 2309 /* Now run the before-change-functions if any. */
e45fb8bf
RS
2310 if (!NILP (Vbefore_change_functions))
2311 {
3d1e2d9c
RS
2312 Lisp_Object args[3];
2313 Lisp_Object before_change_functions;
2314 Lisp_Object after_change_functions;
2315 struct gcpro gcpro1, gcpro2;
2316
d206af14 2317 PRESERVE_VALUE;
b86e0aaf 2318 PRESERVE_START_END;
d206af14 2319
3d1e2d9c
RS
2320 /* "Bind" before-change-functions and after-change-functions
2321 to nil--but in a way that errors don't know about.
2322 That way, if there's an error in them, they will stay nil. */
2323 before_change_functions = Vbefore_change_functions;
2324 after_change_functions = Vafter_change_functions;
c82c1da0
KH
2325 Vbefore_change_functions = Qnil;
2326 Vafter_change_functions = Qnil;
3d1e2d9c
RS
2327 GCPRO2 (before_change_functions, after_change_functions);
2328
2329 /* Actually run the hook functions. */
2330 args[0] = Qbefore_change_functions;
b86e0aaf
RS
2331 args[1] = FETCH_START;
2332 args[2] = FETCH_END;
3d1e2d9c
RS
2333 run_hook_list_with_args (before_change_functions, 3, args);
2334
2335 /* "Unbind" the variables we "bound" to nil. */
2336 Vbefore_change_functions = before_change_functions;
2337 Vafter_change_functions = after_change_functions;
2338 UNGCPRO;
e45fb8bf 2339 }
d07c0804
RS
2340
2341 if (!NILP (current_buffer->overlays_before)
2342 || !NILP (current_buffer->overlays_after))
d206af14
RS
2343 {
2344 PRESERVE_VALUE;
b86e0aaf
RS
2345 report_overlay_modification (FETCH_START, FETCH_END, 0,
2346 FETCH_START, FETCH_END, Qnil);
d206af14
RS
2347 }
2348
b86e0aaf
RS
2349 if (! NILP (start_marker))
2350 free_marker (start_marker);
2351 if (! NILP (end_marker))
2352 free_marker (end_marker);
d206af14
RS
2353 RESTORE_VALUE;
2354 UNGCPRO;
b45433b3
JB
2355}
2356
eb8c3be9 2357/* Signal a change immediately after it happens.
3be11131 2358 CHARPOS is the character position of the start of the changed text.
b45433b3
JB
2359 LENDEL is the number of characters of the text before the change.
2360 (Not the whole buffer; just the part that was changed.)
8b09e5d0
RS
2361 LENINS is the number of characters in that part of the text
2362 after the change. */
b45433b3 2363
c660b094 2364void
3be11131
RS
2365signal_after_change (charpos, lendel, lenins)
2366 int charpos, lendel, lenins;
b45433b3 2367{
fb2e7d14
RS
2368 /* If we are deferring calls to the after-change functions
2369 and there are no before-change functions,
2370 just record the args that we were going to use. */
2371 if (! NILP (Vcombine_after_change_calls)
2372 && NILP (Vbefore_change_function) && NILP (Vbefore_change_functions)
2373 && NILP (current_buffer->overlays_before)
2374 && NILP (current_buffer->overlays_after))
2375 {
2376 Lisp_Object elt;
2377
2378 if (!NILP (combine_after_change_list)
2379 && current_buffer != XBUFFER (combine_after_change_buffer))
2380 Fcombine_after_change_execute ();
2381
3be11131
RS
2382 elt = Fcons (make_number (charpos - BEG),
2383 Fcons (make_number (Z - (charpos - lendel + lenins)),
fb2e7d14
RS
2384 Fcons (make_number (lenins - lendel), Qnil)));
2385 combine_after_change_list
2386 = Fcons (elt, combine_after_change_list);
2387 combine_after_change_buffer = Fcurrent_buffer ();
2388
2389 return;
2390 }
2391
2392 if (!NILP (combine_after_change_list))
2393 Fcombine_after_change_execute ();
2394
3d1e2d9c
RS
2395 /* Run the after-change-function if any.
2396 We don't bother "binding" this variable to nil
2397 because it is obsolete anyway and new code should not use it. */
d427b66a 2398 if (!NILP (Vafter_change_function))
3d1e2d9c 2399 call3 (Vafter_change_function,
3be11131 2400 make_number (charpos), make_number (charpos + lenins),
3d1e2d9c 2401 make_number (lendel));
b45433b3 2402
e45fb8bf
RS
2403 if (!NILP (Vafter_change_functions))
2404 {
3d1e2d9c
RS
2405 Lisp_Object args[4];
2406 Lisp_Object before_change_functions;
2407 Lisp_Object after_change_functions;
2408 struct gcpro gcpro1, gcpro2;
2409
2410 /* "Bind" before-change-functions and after-change-functions
2411 to nil--but in a way that errors don't know about.
2412 That way, if there's an error in them, they will stay nil. */
2413 before_change_functions = Vbefore_change_functions;
2414 after_change_functions = Vafter_change_functions;
c82c1da0
KH
2415 Vbefore_change_functions = Qnil;
2416 Vafter_change_functions = Qnil;
3d1e2d9c
RS
2417 GCPRO2 (before_change_functions, after_change_functions);
2418
2419 /* Actually run the hook functions. */
2420 args[0] = Qafter_change_functions;
3be11131
RS
2421 XSETFASTINT (args[1], charpos);
2422 XSETFASTINT (args[2], charpos + lenins);
3d1e2d9c
RS
2423 XSETFASTINT (args[3], lendel);
2424 run_hook_list_with_args (after_change_functions,
2425 4, args);
2426
2427 /* "Unbind" the variables we "bound" to nil. */
2428 Vbefore_change_functions = before_change_functions;
2429 Vafter_change_functions = after_change_functions;
2430 UNGCPRO;
e45fb8bf 2431 }
d07c0804
RS
2432
2433 if (!NILP (current_buffer->overlays_before)
2434 || !NILP (current_buffer->overlays_after))
3be11131
RS
2435 report_overlay_modification (make_number (charpos),
2436 make_number (charpos + lenins),
d07c0804 2437 1,
3be11131
RS
2438 make_number (charpos),
2439 make_number (charpos + lenins),
d07c0804 2440 make_number (lendel));
c5ca0786
RS
2441
2442 /* After an insertion, call the text properties
2443 insert-behind-hooks or insert-in-front-hooks. */
2444 if (lendel == 0)
d6b81c0f
AS
2445 report_interval_modification (make_number (charpos),
2446 make_number (charpos + lenins));
b45433b3 2447}
fb2e7d14
RS
2448
2449Lisp_Object
2450Fcombine_after_change_execute_1 (val)
2451 Lisp_Object val;
2452{
2453 Vcombine_after_change_calls = val;
2454 return val;
2455}
2456
2457DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
2458 Scombine_after_change_execute, 0, 0, 0,
2459 "This function is for use internally in `combine-after-change-calls'.")
2460 ()
2461{
2462 register Lisp_Object val;
2463 int count = specpdl_ptr - specpdl;
2464 int beg, end, change;
2465 int begpos, endpos;
2466 Lisp_Object tail;
2467
2468 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
2469
2470 Fset_buffer (combine_after_change_buffer);
2471
2472 /* # chars unchanged at beginning of buffer. */
2473 beg = Z - BEG;
2474 /* # chars unchanged at end of buffer. */
2475 end = beg;
2476 /* Total amount of insertion (negative for deletion). */
2477 change = 0;
2478
2479 /* Scan the various individual changes,
2480 accumulating the range info in BEG, END and CHANGE. */
2481 for (tail = combine_after_change_list; CONSP (tail);
2482 tail = XCONS (tail)->cdr)
2483 {
e688a080
KH
2484 Lisp_Object elt;
2485 int thisbeg, thisend, thischange;
fb2e7d14
RS
2486
2487 /* Extract the info from the next element. */
2488 elt = XCONS (tail)->car;
2489 if (! CONSP (elt))
2490 continue;
2491 thisbeg = XINT (XCONS (elt)->car);
2492
2493 elt = XCONS (elt)->cdr;
2494 if (! CONSP (elt))
2495 continue;
2496 thisend = XINT (XCONS (elt)->car);
2497
2498 elt = XCONS (elt)->cdr;
2499 if (! CONSP (elt))
2500 continue;
2501 thischange = XINT (XCONS (elt)->car);
2502
2503 /* Merge this range into the accumulated range. */
2504 change += thischange;
2505 if (thisbeg < beg)
2506 beg = thisbeg;
2507 if (thisend < end)
2508 end = thisend;
2509 }
2510
2511 /* Get the current start and end positions of the range
2512 that was changed. */
2513 begpos = BEG + beg;
2514 endpos = Z - end;
2515
2516 /* We are about to handle these, so discard them. */
2517 combine_after_change_list = Qnil;
2518
2519 /* Now run the after-change functions for real.
2520 Turn off the flag that defers them. */
2521 record_unwind_protect (Fcombine_after_change_execute_1,
2522 Vcombine_after_change_calls);
2523 signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
2524
2525 return unbind_to (count, val);
2526}
2527\f
dfcf069d 2528void
fb2e7d14
RS
2529syms_of_insdel ()
2530{
2531 staticpro (&combine_after_change_list);
2532 combine_after_change_list = Qnil;
2533
60ea6052
RS
2534 DEFVAR_BOOL ("check-markers-debug-flag", &check_markers_debug_flag,
2535 "Non-nil means enable debugging checks for invalid marker positions.");
2536 check_markers_debug_flag = 0;
fb2e7d14 2537 DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls,
60ea6052 2538 "Used internally by the `combine-after-change-calls' macro.");
fb2e7d14
RS
2539 Vcombine_after_change_calls = Qnil;
2540
2541 defsubr (&Scombine_after_change_execute);
2542}