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