Update disk requirements.
[bpt/emacs.git] / src / insdel.c
CommitLineData
b45433b3 1/* Buffer insertion/deletion and gap motion for GNU Emacs.
f8c25f1b 2 Copyright (C) 1985, 1986, 1993, 1994, 1995 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
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
b45433b3 22#include "lisp.h"
679194a6 23#include "intervals.h"
b45433b3
JB
24#include "buffer.h"
25#include "window.h"
d014bf88 26#include "blockinput.h"
b45433b3 27
14f6194b
RS
28#define min(x, y) ((x) < (y) ? (x) : (y))
29
395ec62e 30static void insert_from_string_1 ();
ef29f213 31static void insert_from_buffer_1 ();
2bcaed71
KH
32static void gap_left ();
33static void gap_right ();
34static void adjust_markers ();
a27a38d8 35static void adjust_point ();
395ec62e 36
b45433b3
JB
37/* Move gap to position `pos'.
38 Note that this can quit! */
39
c660b094 40void
b45433b3
JB
41move_gap (pos)
42 int pos;
43{
44 if (pos < GPT)
45 gap_left (pos, 0);
46 else if (pos > GPT)
47 gap_right (pos);
48}
49
50/* Move the gap to POS, which is less than the current GPT.
51 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
52
2bcaed71 53static void
b45433b3
JB
54gap_left (pos, newgap)
55 register int pos;
56 int newgap;
57{
58 register unsigned char *to, *from;
59 register int i;
60 int new_s1;
61
62 pos--;
63
64 if (!newgap)
65 {
66 if (unchanged_modified == MODIFF)
67 {
68 beg_unchanged = pos;
69 end_unchanged = Z - pos - 1;
70 }
71 else
72 {
73 if (Z - GPT < end_unchanged)
74 end_unchanged = Z - GPT;
75 if (pos < beg_unchanged)
76 beg_unchanged = pos;
77 }
78 }
79
80 i = GPT;
81 to = GAP_END_ADDR;
82 from = GPT_ADDR;
83 new_s1 = GPT - BEG;
84
85 /* Now copy the characters. To move the gap down,
86 copy characters up. */
87
88 while (1)
89 {
90 /* I gets number of characters left to copy. */
91 i = new_s1 - pos;
92 if (i == 0)
93 break;
94 /* If a quit is requested, stop copying now.
95 Change POS to be where we have actually moved the gap to. */
96 if (QUITP)
97 {
98 pos = new_s1;
99 break;
100 }
101 /* Move at most 32000 chars before checking again for a quit. */
102 if (i > 32000)
103 i = 32000;
104#ifdef GAP_USE_BCOPY
105 if (i >= 128
106 /* bcopy is safe if the two areas of memory do not overlap
107 or on systems where bcopy is always safe for moving upward. */
108 && (BCOPY_UPWARD_SAFE
109 || to - from >= 128))
110 {
111 /* If overlap is not safe, avoid it by not moving too many
112 characters at once. */
113 if (!BCOPY_UPWARD_SAFE && i > to - from)
114 i = to - from;
115 new_s1 -= i;
116 from -= i, to -= i;
117 bcopy (from, to, i);
118 }
119 else
120#endif
121 {
122 new_s1 -= i;
123 while (--i >= 0)
124 *--to = *--from;
125 }
126 }
127
128 /* Adjust markers, and buffer data structure, to put the gap at POS.
129 POS is where the loop above stopped, which may be what was specified
130 or may be where a quit was detected. */
131 adjust_markers (pos + 1, GPT, GAP_SIZE);
132 GPT = pos + 1;
133 QUIT;
134}
135
2bcaed71 136static void
b45433b3
JB
137gap_right (pos)
138 register int pos;
139{
140 register unsigned char *to, *from;
141 register int i;
142 int new_s1;
143
144 pos--;
145
146 if (unchanged_modified == MODIFF)
147 {
148 beg_unchanged = pos;
149 end_unchanged = Z - pos - 1;
150 }
151 else
152 {
153 if (Z - pos - 1 < end_unchanged)
154 end_unchanged = Z - pos - 1;
155 if (GPT - BEG < beg_unchanged)
156 beg_unchanged = GPT - BEG;
157 }
158
159 i = GPT;
160 from = GAP_END_ADDR;
161 to = GPT_ADDR;
162 new_s1 = GPT - 1;
163
164 /* Now copy the characters. To move the gap up,
165 copy characters down. */
166
167 while (1)
168 {
169 /* I gets number of characters left to copy. */
170 i = pos - new_s1;
171 if (i == 0)
172 break;
173 /* If a quit is requested, stop copying now.
174 Change POS to be where we have actually moved the gap to. */
175 if (QUITP)
176 {
177 pos = new_s1;
178 break;
179 }
180 /* Move at most 32000 chars before checking again for a quit. */
181 if (i > 32000)
182 i = 32000;
183#ifdef GAP_USE_BCOPY
184 if (i >= 128
185 /* bcopy is safe if the two areas of memory do not overlap
186 or on systems where bcopy is always safe for moving downward. */
187 && (BCOPY_DOWNWARD_SAFE
188 || from - to >= 128))
189 {
190 /* If overlap is not safe, avoid it by not moving too many
191 characters at once. */
192 if (!BCOPY_DOWNWARD_SAFE && i > from - to)
193 i = from - to;
194 new_s1 += i;
195 bcopy (from, to, i);
196 from += i, to += i;
197 }
198 else
199#endif
200 {
201 new_s1 += i;
202 while (--i >= 0)
203 *to++ = *from++;
204 }
205 }
206
207 adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
208 GPT = pos + 1;
209 QUIT;
210}
211
212/* Add `amount' to the position of every marker in the current buffer
213 whose current position is between `from' (exclusive) and `to' (inclusive).
214 Also, any markers past the outside of that interval, in the direction
215 of adjustment, are first moved back to the near end of the interval
216 and then adjusted by `amount'. */
217
2bcaed71 218static void
b45433b3
JB
219adjust_markers (from, to, amount)
220 register int from, to, amount;
221{
222 Lisp_Object marker;
223 register struct Lisp_Marker *m;
224 register int mpos;
225
9fbf87cd 226 marker = BUF_MARKERS (current_buffer);
b45433b3 227
d427b66a 228 while (!NILP (marker))
b45433b3
JB
229 {
230 m = XMARKER (marker);
231 mpos = m->bufpos;
232 if (amount > 0)
233 {
234 if (mpos > to && mpos < to + amount)
235 mpos = to + amount;
236 }
237 else
238 {
239 if (mpos > from + amount && mpos <= from)
240 mpos = from + amount;
241 }
242 if (mpos > from && mpos <= to)
243 mpos += amount;
244 m->bufpos = mpos;
245 marker = m->chain;
246 }
247}
a27a38d8
KH
248
249/* Add the specified amount to point. This is used only when the value
250 of point changes due to an insert or delete; it does not represent
251 a conceptual change in point as a marker. In particular, point is
252 not crossing any interval boundaries, so there's no need to use the
253 usual SET_PT macro. In fact it would be incorrect to do so, because
254 either the old or the new value of point is out of synch with the
255 current set of intervals. */
256static void
257adjust_point (amount)
29eb72ac 258 int amount;
a27a38d8 259{
9fbf87cd 260 BUF_PT (current_buffer) += amount;
a27a38d8 261}
b45433b3
JB
262\f
263/* Make the gap INCREMENT characters longer. */
264
c660b094 265void
b45433b3
JB
266make_gap (increment)
267 int increment;
268{
269 unsigned char *result;
270 Lisp_Object tem;
271 int real_gap_loc;
272 int old_gap_size;
273
274 /* If we have to get more space, get enough to last a while. */
275 increment += 2000;
276
94056516
RS
277 /* Don't allow a buffer size that won't fit in an int
278 even if it will fit in a Lisp integer.
279 That won't work because so many places use `int'. */
280
14f6194b
RS
281 if (Z - BEG + GAP_SIZE + increment
282 >= ((unsigned) 1 << (min (INTBITS, VALBITS) - 1)))
283 error ("Buffer exceeds maximum size");
94056516 284
9ac0d9e0 285 BLOCK_INPUT;
b45433b3 286 result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
9ac0d9e0 287
b45433b3 288 if (result == 0)
270c2138
RS
289 {
290 UNBLOCK_INPUT;
291 memory_full ();
292 }
293
294 /* We can't unblock until the new address is properly stored. */
b45433b3 295 BEG_ADDR = result;
270c2138 296 UNBLOCK_INPUT;
b45433b3
JB
297
298 /* Prevent quitting in move_gap. */
299 tem = Vinhibit_quit;
300 Vinhibit_quit = Qt;
301
302 real_gap_loc = GPT;
303 old_gap_size = GAP_SIZE;
304
305 /* Call the newly allocated space a gap at the end of the whole space. */
306 GPT = Z + GAP_SIZE;
307 GAP_SIZE = increment;
308
309 /* Move the new gap down to be consecutive with the end of the old one.
310 This adjusts the markers properly too. */
311 gap_left (real_gap_loc + old_gap_size, 1);
312
313 /* Now combine the two into one large gap. */
314 GAP_SIZE += old_gap_size;
315 GPT = real_gap_loc;
316
317 Vinhibit_quit = tem;
318}
319\f
320/* Insert a string of specified length before point.
ef29f213
KH
321 DO NOT use this for the contents of a Lisp string or a Lisp buffer!
322 prepare_to_modify_buffer could relocate the text. */
b45433b3 323
c660b094 324void
b45433b3
JB
325insert (string, length)
326 register unsigned char *string;
327 register length;
328{
395ec62e
KH
329 if (length > 0)
330 {
c660b094 331 insert_1 (string, length, 0, 1);
cd11ef31
RS
332 signal_after_change (PT-length, 0, length);
333 }
334}
335
c660b094 336void
cd11ef31
RS
337insert_and_inherit (string, length)
338 register unsigned char *string;
339 register length;
340{
341 if (length > 0)
342 {
c660b094 343 insert_1 (string, length, 1, 1);
2bcaed71 344 signal_after_change (PT-length, 0, length);
395ec62e
KH
345 }
346}
b45433b3 347
c660b094
KH
348void
349insert_1 (string, length, inherit, prepare)
395ec62e 350 register unsigned char *string;
c660b094
KH
351 register int length;
352 int inherit, prepare;
395ec62e
KH
353{
354 register Lisp_Object temp;
b45433b3 355
c660b094
KH
356 if (prepare)
357 prepare_to_modify_buffer (PT, PT);
b45433b3 358
2bcaed71
KH
359 if (PT != GPT)
360 move_gap (PT);
b45433b3
JB
361 if (GAP_SIZE < length)
362 make_gap (length - GAP_SIZE);
363
2bcaed71 364 record_insert (PT, length);
b45433b3
JB
365 MODIFF++;
366
367 bcopy (string, GPT_ADDR, length);
368
648c4c55 369#ifdef USE_TEXT_PROPERTIES
9fbf87cd 370 if (BUF_INTERVALS (current_buffer) != 0)
648c4c55
RS
371 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
372 offset_intervals (current_buffer, PT, length);
373#endif
679194a6 374
b45433b3
JB
375 GAP_SIZE -= length;
376 GPT += length;
377 ZV += length;
378 Z += length;
adde4858 379 adjust_overlays_for_insert (PT, length);
a27a38d8 380 adjust_point (length);
cd11ef31 381
648c4c55 382#ifdef USE_TEXT_PROPERTIES
9fbf87cd 383 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
cd11ef31
RS
384 Fset_text_properties (make_number (PT - length), make_number (PT),
385 Qnil, Qnil);
648c4c55 386#endif
b45433b3
JB
387}
388
679194a6
JA
389/* Insert the part of the text of STRING, a Lisp object assumed to be
390 of type string, consisting of the LENGTH characters starting at
391 position POS. If the text of STRING has properties, they are absorbed
392 into the buffer.
393
394 It does not work to use `insert' for this, because a GC could happen
7e1ea612
JB
395 before we bcopy the stuff into the buffer, and relocate the string
396 without insert noticing. */
679194a6 397
c660b094 398void
9391e591 399insert_from_string (string, pos, length, inherit)
b45433b3
JB
400 Lisp_Object string;
401 register int pos, length;
9391e591 402 int inherit;
395ec62e
KH
403{
404 if (length > 0)
405 {
406 insert_from_string_1 (string, pos, length, inherit);
2bcaed71 407 signal_after_change (PT-length, 0, length);
395ec62e
KH
408 }
409}
410
411static void
412insert_from_string_1 (string, pos, length, inherit)
413 Lisp_Object string;
414 register int pos, length;
415 int inherit;
b45433b3
JB
416{
417 register Lisp_Object temp;
418 struct gcpro gcpro1;
419
b45433b3 420 /* Make sure point-max won't overflow after this insertion. */
eb7db9e6 421 XSETINT (temp, length + Z);
b45433b3
JB
422 if (length + Z != XINT (temp))
423 error ("maximum buffer size exceeded");
424
425 GCPRO1 (string);
2bcaed71 426 prepare_to_modify_buffer (PT, PT);
b45433b3 427
2bcaed71
KH
428 if (PT != GPT)
429 move_gap (PT);
b45433b3
JB
430 if (GAP_SIZE < length)
431 make_gap (length - GAP_SIZE);
432
2bcaed71 433 record_insert (PT, length);
b45433b3
JB
434 MODIFF++;
435 UNGCPRO;
436
437 bcopy (XSTRING (string)->data, GPT_ADDR, length);
438
679194a6 439 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2bcaed71 440 offset_intervals (current_buffer, PT, length);
679194a6 441
b45433b3
JB
442 GAP_SIZE -= length;
443 GPT += length;
444 ZV += length;
445 Z += length;
adde4858 446 adjust_overlays_for_insert (PT, length);
679194a6
JA
447
448 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2bcaed71 449 graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
9391e591 450 current_buffer, inherit);
679194a6 451
a27a38d8 452 adjust_point (length);
b45433b3
JB
453}
454
ef29f213
KH
455/* Insert text from BUF, starting at POS and having length LENGTH, into the
456 current buffer. If the text in BUF has properties, they are absorbed
457 into the current buffer.
458
459 It does not work to use `insert' for this, because a malloc could happen
460 and relocate BUF's text before the bcopy happens. */
461
462void
463insert_from_buffer (buf, pos, length, inherit)
464 struct buffer *buf;
465 int pos, length;
466 int inherit;
467{
468 if (length > 0)
469 {
470 insert_from_buffer_1 (buf, pos, length, inherit);
471 signal_after_change (PT-length, 0, length);
472 }
473}
474
475static void
476insert_from_buffer_1 (buf, pos, length, inherit)
477 struct buffer *buf;
478 int pos, length;
479 int inherit;
480{
481 register Lisp_Object temp;
482 int chunk;
483
484 /* Make sure point-max won't overflow after this insertion. */
485 XSETINT (temp, length + Z);
486 if (length + Z != XINT (temp))
487 error ("maximum buffer size exceeded");
488
489 prepare_to_modify_buffer (PT, PT);
490
491 if (PT != GPT)
492 move_gap (PT);
493 if (GAP_SIZE < length)
494 make_gap (length - GAP_SIZE);
495
496 record_insert (PT, length);
497 MODIFF++;
498
499 if (pos < BUF_GPT (buf))
500 {
61bd0e9c
RS
501 chunk = BUF_GPT (buf) - pos;
502 if (chunk > length)
503 chunk = length;
ef29f213
KH
504 bcopy (BUF_CHAR_ADDRESS (buf, pos), GPT_ADDR, chunk);
505 }
506 else
507 chunk = 0;
508 if (chunk < length)
509 bcopy (BUF_CHAR_ADDRESS (buf, pos + chunk),
510 GPT_ADDR + chunk, length - chunk);
511
512#ifdef USE_TEXT_PROPERTIES
9fbf87cd 513 if (BUF_INTERVALS (current_buffer) != 0)
ef29f213
KH
514 offset_intervals (current_buffer, PT, length);
515#endif
516
517 GAP_SIZE -= length;
518 GPT += length;
519 ZV += length;
520 Z += length;
adde4858 521 adjust_overlays_for_insert (PT, length);
ef29f213
KH
522 adjust_point (length);
523
524 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
9fbf87cd
RS
525 graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
526 pos, length),
ef29f213
KH
527 PT - length, length, current_buffer, inherit);
528}
529
b45433b3
JB
530/* Insert the character C before point */
531
532void
533insert_char (c)
534 unsigned char c;
535{
536 insert (&c, 1);
537}
538
539/* Insert the null-terminated string S before point */
540
541void
542insert_string (s)
543 char *s;
544{
545 insert (s, strlen (s));
546}
547
548/* Like `insert' except that all markers pointing at the place where
549 the insertion happens are adjusted to point after it.
550 Don't use this function to insert part of a Lisp string,
551 since gc could happen and relocate it. */
552
c660b094 553void
b45433b3
JB
554insert_before_markers (string, length)
555 unsigned char *string;
556 register int length;
557{
395ec62e
KH
558 if (length > 0)
559 {
2bcaed71 560 register int opoint = PT;
c660b094 561 insert_1 (string, length, 0, 1);
395ec62e 562 adjust_markers (opoint - 1, opoint, length);
2bcaed71 563 signal_after_change (PT-length, 0, length);
395ec62e 564 }
b45433b3
JB
565}
566
c660b094 567void
598fb6fe
RS
568insert_before_markers_and_inherit (string, length)
569 unsigned char *string;
570 register int length;
571{
572 if (length > 0)
573 {
574 register int opoint = PT;
c660b094 575 insert_1 (string, length, 1, 1);
598fb6fe
RS
576 adjust_markers (opoint - 1, opoint, length);
577 signal_after_change (PT-length, 0, length);
578 }
579}
580
b45433b3
JB
581/* Insert part of a Lisp string, relocating markers after. */
582
c660b094 583void
9391e591 584insert_from_string_before_markers (string, pos, length, inherit)
b45433b3
JB
585 Lisp_Object string;
586 register int pos, length;
9391e591 587 int inherit;
b45433b3 588{
395ec62e
KH
589 if (length > 0)
590 {
2bcaed71 591 register int opoint = PT;
395ec62e
KH
592 insert_from_string_1 (string, pos, length, inherit);
593 adjust_markers (opoint - 1, opoint, length);
2bcaed71 594 signal_after_change (PT-length, 0, length);
395ec62e 595 }
b45433b3
JB
596}
597\f
598/* Delete characters in current buffer
599 from FROM up to (but not including) TO. */
600
c660b094 601void
b45433b3
JB
602del_range (from, to)
603 register int from, to;
47c64747 604{
c660b094 605 del_range_1 (from, to, 1);
47c64747
RS
606}
607
608/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */
609
c660b094 610void
47c64747
RS
611del_range_1 (from, to, prepare)
612 register int from, to, prepare;
b45433b3
JB
613{
614 register int numdel;
615
616 /* Make args be valid */
617 if (from < BEGV)
618 from = BEGV;
619 if (to > ZV)
620 to = ZV;
621
622 if ((numdel = to - from) <= 0)
623 return;
624
625 /* Make sure the gap is somewhere in or next to what we are deleting. */
626 if (from > GPT)
627 gap_right (from);
628 if (to < GPT)
629 gap_left (to, 0);
630
47c64747
RS
631 if (prepare)
632 prepare_to_modify_buffer (from, to);
b45433b3 633
be09561e
RS
634 record_delete (from, numdel);
635 MODIFF++;
636
b45433b3 637 /* Relocate point as if it were a marker. */
2bcaed71 638 if (from < PT)
a27a38d8 639 adjust_point (from - (PT < to ? PT : to));
b45433b3 640
16032db6 641 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
83010cd6 642 offset_intervals (current_buffer, from, - numdel);
16032db6 643
b45433b3
JB
644 /* Relocate all markers pointing into the new, larger gap
645 to point at the end of the text before the gap. */
646 adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
647
adde4858 648 /* Adjust the overlay center as needed. This must be done after
a7f38d28 649 adjusting the markers that bound the overlays. */
adde4858
KH
650 adjust_overlays_for_delete (from, numdel);
651
b45433b3
JB
652 GAP_SIZE += numdel;
653 ZV -= numdel;
654 Z -= numdel;
655 GPT = from;
656
657 if (GPT - BEG < beg_unchanged)
658 beg_unchanged = GPT - BEG;
659 if (Z - GPT < end_unchanged)
660 end_unchanged = Z - GPT;
661
d386034e 662 evaporate_overlays (from);
b45433b3
JB
663 signal_after_change (from, numdel, 0);
664}
665\f
04a759c8
JB
666/* Call this if you're about to change the region of BUFFER from START
667 to END. This checks the read-only properties of the region, calls
668 the necessary modification hooks, and warns the next redisplay that
669 it should pay attention to that area. */
c660b094 670void
04a759c8
JB
671modify_region (buffer, start, end)
672 struct buffer *buffer;
b45433b3
JB
673 int start, end;
674{
04a759c8
JB
675 struct buffer *old_buffer = current_buffer;
676
677 if (buffer != old_buffer)
678 set_buffer_internal (buffer);
679
b45433b3
JB
680 prepare_to_modify_buffer (start, end);
681
682 if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
683 beg_unchanged = start - 1;
684 if (Z - end < end_unchanged
685 || unchanged_modified == MODIFF)
686 end_unchanged = Z - end;
83010cd6 687
9fbf87cd 688 if (MODIFF <= SAVE_MODIFF)
83010cd6 689 record_first_change ();
b45433b3 690 MODIFF++;
04a759c8 691
069cdc4f
RS
692 buffer->point_before_scroll = Qnil;
693
04a759c8
JB
694 if (buffer != old_buffer)
695 set_buffer_internal (old_buffer);
b45433b3
JB
696}
697
698/* Check that it is okay to modify the buffer between START and END.
679194a6
JA
699 Run the before-change-function, if any. If intervals are in use,
700 verify that the text to be modified is not read-only, and call
701 any modification properties the text may have. */
b45433b3 702
c660b094 703void
b45433b3
JB
704prepare_to_modify_buffer (start, end)
705 Lisp_Object start, end;
706{
d427b66a 707 if (!NILP (current_buffer->read_only))
b45433b3
JB
708 Fbarf_if_buffer_read_only ();
709
679194a6 710 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
9fbf87cd 711 if (BUF_INTERVALS (current_buffer) != 0)
648c4c55 712 verify_interval_modification (current_buffer, start, end);
b45433b3
JB
713
714#ifdef CLASH_DETECTION
f173b650 715 if (!NILP (current_buffer->file_truename)
9fbf87cd 716 && SAVE_MODIFF >= MODIFF)
f173b650 717 lock_file (current_buffer->file_truename);
b45433b3
JB
718#else
719 /* At least warn if this file has changed on disk since it was visited. */
d427b66a 720 if (!NILP (current_buffer->filename)
9fbf87cd 721 && SAVE_MODIFF >= MODIFF
d427b66a
JB
722 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
723 && !NILP (Ffile_exists_p (current_buffer->filename)))
b45433b3
JB
724 call1 (intern ("ask-user-about-supersession-threat"),
725 current_buffer->filename);
726#endif /* not CLASH_DETECTION */
727
728 signal_before_change (start, end);
2f545eea 729
56e1065e
JB
730 if (current_buffer->newline_cache)
731 invalidate_region_cache (current_buffer,
732 current_buffer->newline_cache,
733 start - BEG, Z - end);
734 if (current_buffer->width_run_cache)
735 invalidate_region_cache (current_buffer,
736 current_buffer->width_run_cache,
737 start - BEG, Z - end);
738
2f545eea 739 Vdeactivate_mark = Qt;
b45433b3
JB
740}
741\f
742static Lisp_Object
743before_change_function_restore (value)
744 Lisp_Object value;
745{
746 Vbefore_change_function = value;
747}
748
749static Lisp_Object
750after_change_function_restore (value)
751 Lisp_Object value;
752{
753 Vafter_change_function = value;
754}
755
e45fb8bf
RS
756static Lisp_Object
757before_change_functions_restore (value)
758 Lisp_Object value;
759{
760 Vbefore_change_functions = value;
761}
762
763static Lisp_Object
764after_change_functions_restore (value)
765 Lisp_Object value;
766{
767 Vafter_change_functions = value;
768}
769
eb8c3be9 770/* Signal a change to the buffer immediately before it happens.
b45433b3
JB
771 START and END are the bounds of the text to be changed,
772 as Lisp objects. */
773
c660b094 774void
b45433b3
JB
775signal_before_change (start, end)
776 Lisp_Object start, end;
777{
778 /* If buffer is unmodified, run a special hook for that case. */
9fbf87cd 779 if (SAVE_MODIFF >= MODIFF
dbc4e1c1
JB
780 && !NILP (Vfirst_change_hook)
781 && !NILP (Vrun_hooks))
782 call1 (Vrun_hooks, Qfirst_change_hook);
783
b45433b3 784 /* Now in any case run the before-change-function if any. */
d427b66a 785 if (!NILP (Vbefore_change_function))
b45433b3
JB
786 {
787 int count = specpdl_ptr - specpdl;
788 Lisp_Object function;
789
790 function = Vbefore_change_function;
e45fb8bf 791
b45433b3
JB
792 record_unwind_protect (after_change_function_restore,
793 Vafter_change_function);
794 record_unwind_protect (before_change_function_restore,
795 Vbefore_change_function);
e45fb8bf
RS
796 record_unwind_protect (after_change_functions_restore,
797 Vafter_change_functions);
798 record_unwind_protect (before_change_functions_restore,
799 Vbefore_change_functions);
b45433b3
JB
800 Vafter_change_function = Qnil;
801 Vbefore_change_function = Qnil;
e45fb8bf
RS
802 Vafter_change_functions = Qnil;
803 Vbefore_change_functions = Qnil;
b45433b3
JB
804
805 call2 (function, start, end);
806 unbind_to (count, Qnil);
807 }
e45fb8bf
RS
808
809 /* Now in any case run the before-change-function if any. */
810 if (!NILP (Vbefore_change_functions))
811 {
812 int count = specpdl_ptr - specpdl;
813 Lisp_Object functions;
814
815 functions = Vbefore_change_functions;
816
817 record_unwind_protect (after_change_function_restore,
818 Vafter_change_function);
819 record_unwind_protect (before_change_function_restore,
820 Vbefore_change_function);
821 record_unwind_protect (after_change_functions_restore,
822 Vafter_change_functions);
823 record_unwind_protect (before_change_functions_restore,
824 Vbefore_change_functions);
825 Vafter_change_function = Qnil;
826 Vbefore_change_function = Qnil;
827 Vafter_change_functions = Qnil;
828 Vbefore_change_functions = Qnil;
829
830 while (CONSP (functions))
831 {
832 call2 (XCONS (functions)->car, start, end);
833 functions = XCONS (functions)->cdr;
834 }
835 unbind_to (count, Qnil);
836 }
d07c0804
RS
837
838 if (!NILP (current_buffer->overlays_before)
839 || !NILP (current_buffer->overlays_after))
835220e8 840 report_overlay_modification (start, end, 0, start, end, Qnil);
b45433b3
JB
841}
842
eb8c3be9 843/* Signal a change immediately after it happens.
b45433b3
JB
844 POS is the address of the start of the changed text.
845 LENDEL is the number of characters of the text before the change.
846 (Not the whole buffer; just the part that was changed.)
d07c0804
RS
847 LENINS is the number of characters in the changed text.
848
849 (Hence POS + LENINS - LENDEL is the position after the changed text.) */
b45433b3 850
c660b094 851void
b45433b3
JB
852signal_after_change (pos, lendel, lenins)
853 int pos, lendel, lenins;
854{
d427b66a 855 if (!NILP (Vafter_change_function))
b45433b3
JB
856 {
857 int count = specpdl_ptr - specpdl;
858 Lisp_Object function;
859 function = Vafter_change_function;
860
861 record_unwind_protect (after_change_function_restore,
862 Vafter_change_function);
863 record_unwind_protect (before_change_function_restore,
864 Vbefore_change_function);
e45fb8bf
RS
865 record_unwind_protect (after_change_functions_restore,
866 Vafter_change_functions);
867 record_unwind_protect (before_change_functions_restore,
868 Vbefore_change_functions);
b45433b3
JB
869 Vafter_change_function = Qnil;
870 Vbefore_change_function = Qnil;
e45fb8bf
RS
871 Vafter_change_functions = Qnil;
872 Vbefore_change_functions = Qnil;
b45433b3
JB
873
874 call3 (function, make_number (pos), make_number (pos + lenins),
875 make_number (lendel));
876 unbind_to (count, Qnil);
877 }
e45fb8bf
RS
878 if (!NILP (Vafter_change_functions))
879 {
880 int count = specpdl_ptr - specpdl;
881 Lisp_Object functions;
882 functions = Vafter_change_functions;
883
884 record_unwind_protect (after_change_function_restore,
885 Vafter_change_function);
886 record_unwind_protect (before_change_function_restore,
887 Vbefore_change_function);
888 record_unwind_protect (after_change_functions_restore,
889 Vafter_change_functions);
890 record_unwind_protect (before_change_functions_restore,
891 Vbefore_change_functions);
892 Vafter_change_function = Qnil;
893 Vbefore_change_function = Qnil;
894 Vafter_change_functions = Qnil;
895 Vbefore_change_functions = Qnil;
896
897 while (CONSP (functions))
898 {
899 call3 (XCONS (functions)->car,
900 make_number (pos), make_number (pos + lenins),
901 make_number (lendel));
902 functions = XCONS (functions)->cdr;
903 }
904 unbind_to (count, Qnil);
905 }
d07c0804
RS
906
907 if (!NILP (current_buffer->overlays_before)
908 || !NILP (current_buffer->overlays_after))
835220e8 909 report_overlay_modification (make_number (pos),
d07c0804
RS
910 make_number (pos + lenins - lendel),
911 1,
912 make_number (pos), make_number (pos + lenins),
913 make_number (lendel));
b45433b3 914}