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