1 /* Buffer insertion/deletion and gap motion for GNU Emacs.
2 Copyright (C) 1985, 1986 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "intervals.h"
27 /* Nonzero means don't allow protected fields to be modified. */
29 extern int check_protected_fields
;
31 /* Move gap to position `pos'.
32 Note that this can quit! */
43 /* Move the gap to POS, which is less than the current GPT.
44 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
46 gap_left (pos
, newgap
)
50 register unsigned char *to
, *from
;
58 if (unchanged_modified
== MODIFF
)
61 end_unchanged
= Z
- pos
- 1;
65 if (Z
- GPT
< end_unchanged
)
66 end_unchanged
= Z
- GPT
;
67 if (pos
< beg_unchanged
)
77 /* Now copy the characters. To move the gap down,
78 copy characters up. */
82 /* I gets number of characters left to copy. */
86 /* If a quit is requested, stop copying now.
87 Change POS to be where we have actually moved the gap to. */
93 /* Move at most 32000 chars before checking again for a quit. */
98 /* bcopy is safe if the two areas of memory do not overlap
99 or on systems where bcopy is always safe for moving upward. */
100 && (BCOPY_UPWARD_SAFE
101 || to
- from
>= 128))
103 /* If overlap is not safe, avoid it by not moving too many
104 characters at once. */
105 if (!BCOPY_UPWARD_SAFE
&& i
> to
- from
)
120 /* Adjust markers, and buffer data structure, to put the gap at POS.
121 POS is where the loop above stopped, which may be what was specified
122 or may be where a quit was detected. */
123 adjust_markers (pos
+ 1, GPT
, GAP_SIZE
);
131 register unsigned char *to
, *from
;
137 if (unchanged_modified
== MODIFF
)
140 end_unchanged
= Z
- pos
- 1;
144 if (Z
- pos
- 1 < end_unchanged
)
145 end_unchanged
= Z
- pos
- 1;
146 if (GPT
- BEG
< beg_unchanged
)
147 beg_unchanged
= GPT
- BEG
;
155 /* Now copy the characters. To move the gap up,
156 copy characters down. */
160 /* I gets number of characters left to copy. */
164 /* If a quit is requested, stop copying now.
165 Change POS to be where we have actually moved the gap to. */
171 /* Move at most 32000 chars before checking again for a quit. */
176 /* bcopy is safe if the two areas of memory do not overlap
177 or on systems where bcopy is always safe for moving downward. */
178 && (BCOPY_DOWNWARD_SAFE
179 || from
- to
>= 128))
181 /* If overlap is not safe, avoid it by not moving too many
182 characters at once. */
183 if (!BCOPY_DOWNWARD_SAFE
&& i
> from
- to
)
198 adjust_markers (GPT
+ GAP_SIZE
, pos
+ 1 + GAP_SIZE
, - GAP_SIZE
);
203 /* Add `amount' to the position of every marker in the current buffer
204 whose current position is between `from' (exclusive) and `to' (inclusive).
205 Also, any markers past the outside of that interval, in the direction
206 of adjustment, are first moved back to the near end of the interval
207 and then adjusted by `amount'. */
209 adjust_markers (from
, to
, amount
)
210 register int from
, to
, amount
;
213 register struct Lisp_Marker
*m
;
216 marker
= current_buffer
->markers
;
218 while (!NILP (marker
))
220 m
= XMARKER (marker
);
224 if (mpos
> to
&& mpos
< to
+ amount
)
229 if (mpos
> from
+ amount
&& mpos
<= from
)
230 mpos
= from
+ amount
;
232 if (mpos
> from
&& mpos
<= to
)
239 /* Make the gap INCREMENT characters longer. */
244 unsigned char *result
;
249 /* If we have to get more space, get enough to last a while. */
252 result
= BUFFER_REALLOC (BEG_ADDR
, (Z
- BEG
+ GAP_SIZE
+ increment
));
257 /* Prevent quitting in move_gap. */
262 old_gap_size
= GAP_SIZE
;
264 /* Call the newly allocated space a gap at the end of the whole space. */
266 GAP_SIZE
= increment
;
268 /* Move the new gap down to be consecutive with the end of the old one.
269 This adjusts the markers properly too. */
270 gap_left (real_gap_loc
+ old_gap_size
, 1);
272 /* Now combine the two into one large gap. */
273 GAP_SIZE
+= old_gap_size
;
279 /* Insert a string of specified length before point.
280 DO NOT use this for the contents of a Lisp string!
281 prepare_to_modify_buffer could relocate the string. */
283 insert (string
, length
)
284 register unsigned char *string
;
287 register Lisp_Object temp
;
292 /* Make sure point-max won't overflow after this insertion. */
293 XSET (temp
, Lisp_Int
, length
+ Z
);
294 if (length
+ Z
!= XINT (temp
))
295 error ("maximum buffer size exceeded");
297 prepare_to_modify_buffer (point
, point
);
301 if (GAP_SIZE
< length
)
302 make_gap (length
- GAP_SIZE
);
304 record_insert (point
, length
);
307 bcopy (string
, GPT_ADDR
, length
);
309 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
310 offset_intervals (current_buffer
, point
, length
);
316 SET_PT (point
+ length
);
318 signal_after_change (point
-length
, 0, length
);
321 /* Insert the part of the text of STRING, a Lisp object assumed to be
322 of type string, consisting of the LENGTH characters starting at
323 position POS. If the text of STRING has properties, they are absorbed
326 It does not work to use `insert' for this, because a GC could happen
327 before we bcopy the stuff into the buffer, and relocate the string
328 without insert noticing. */
330 insert_from_string (string
, pos
, length
)
332 register int pos
, length
;
334 register Lisp_Object temp
;
340 /* Make sure point-max won't overflow after this insertion. */
341 XSET (temp
, Lisp_Int
, length
+ Z
);
342 if (length
+ Z
!= XINT (temp
))
343 error ("maximum buffer size exceeded");
346 prepare_to_modify_buffer (point
, point
);
350 if (GAP_SIZE
< length
)
351 make_gap (length
- GAP_SIZE
);
353 record_insert (point
, length
);
357 bcopy (XSTRING (string
)->data
, GPT_ADDR
, length
);
359 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
360 offset_intervals (current_buffer
, point
, length
);
367 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
368 graft_intervals_into_buffer (XSTRING (string
)->intervals
, point
,
371 SET_PT (point
+ length
);
373 signal_after_change (point
-length
, 0, length
);
376 /* Insert the character C before point */
385 /* Insert the null-terminated string S before point */
391 insert (s
, strlen (s
));
394 /* Like `insert' except that all markers pointing at the place where
395 the insertion happens are adjusted to point after it.
396 Don't use this function to insert part of a Lisp string,
397 since gc could happen and relocate it. */
399 insert_before_markers (string
, length
)
400 unsigned char *string
;
403 register int opoint
= point
;
404 insert (string
, length
);
405 adjust_markers (opoint
- 1, opoint
, length
);
408 /* Insert part of a Lisp string, relocating markers after. */
410 insert_from_string_before_markers (string
, pos
, length
)
412 register int pos
, length
;
414 register int opoint
= point
;
415 insert_from_string (string
, pos
, length
);
416 adjust_markers (opoint
- 1, opoint
, length
);
419 /* Delete characters in current buffer
420 from FROM up to (but not including) TO. */
423 register int from
, to
;
427 /* Make args be valid */
433 if ((numdel
= to
- from
) <= 0)
436 /* Make sure the gap is somewhere in or next to what we are deleting. */
442 prepare_to_modify_buffer (from
, to
);
444 record_delete (from
, numdel
);
447 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
448 offset_intervals (current_buffer
, point
, - numdel
);
450 /* Relocate point as if it were a marker. */
456 SET_PT (point
- numdel
);
459 /* Relocate all markers pointing into the new, larger gap
460 to point at the end of the text before the gap. */
461 adjust_markers (to
+ GAP_SIZE
, to
+ GAP_SIZE
, - numdel
- GAP_SIZE
);
468 if (GPT
- BEG
< beg_unchanged
)
469 beg_unchanged
= GPT
- BEG
;
470 if (Z
- GPT
< end_unchanged
)
471 end_unchanged
= Z
- GPT
;
473 signal_after_change (from
, numdel
, 0);
476 modify_region (start
, end
)
479 prepare_to_modify_buffer (start
, end
);
481 if (start
- 1 < beg_unchanged
|| unchanged_modified
== MODIFF
)
482 beg_unchanged
= start
- 1;
483 if (Z
- end
< end_unchanged
484 || unchanged_modified
== MODIFF
)
485 end_unchanged
= Z
- end
;
489 /* Check that it is okay to modify the buffer between START and END.
490 Run the before-change-function, if any. If intervals are in use,
491 verify that the text to be modified is not read-only, and call
492 any modification properties the text may have. */
494 prepare_to_modify_buffer (start
, end
)
495 Lisp_Object start
, end
;
497 if (!NILP (current_buffer
->read_only
))
498 Fbarf_if_buffer_read_only ();
500 #if 0 /* Superceded by interval code */
501 if (check_protected_fields
)
502 Fregion_fields (start
, end
, Qnil
, Qt
);
505 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
506 verify_interval_modification (current_buffer
, start
, end
);
508 #ifdef CLASH_DETECTION
509 if (!NILP (current_buffer
->filename
)
510 && current_buffer
->save_modified
>= MODIFF
)
511 lock_file (current_buffer
->filename
);
513 /* At least warn if this file has changed on disk since it was visited. */
514 if (!NILP (current_buffer
->filename
)
515 && current_buffer
->save_modified
>= MODIFF
516 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
517 && !NILP (Ffile_exists_p (current_buffer
->filename
)))
518 call1 (intern ("ask-user-about-supersession-threat"),
519 current_buffer
->filename
);
520 #endif /* not CLASH_DETECTION */
522 signal_before_change (start
, end
);
526 before_change_function_restore (value
)
529 Vbefore_change_function
= value
;
533 after_change_function_restore (value
)
536 Vafter_change_function
= value
;
539 /* Signal a change to the buffer immediatly before it happens.
540 START and END are the bounds of the text to be changed,
543 signal_before_change (start
, end
)
544 Lisp_Object start
, end
;
546 /* If buffer is unmodified, run a special hook for that case. */
547 if (current_buffer
->save_modified
>= MODIFF
548 && !NILP (Vfirst_change_function
))
550 call0 (Vfirst_change_function
);
552 /* Now in any case run the before-change-function if any. */
553 if (!NILP (Vbefore_change_function
))
555 int count
= specpdl_ptr
- specpdl
;
556 Lisp_Object function
;
558 function
= Vbefore_change_function
;
559 record_unwind_protect (after_change_function_restore
,
560 Vafter_change_function
);
561 record_unwind_protect (before_change_function_restore
,
562 Vbefore_change_function
);
563 Vafter_change_function
= Qnil
;
564 Vbefore_change_function
= Qnil
;
566 call2 (function
, start
, end
);
567 unbind_to (count
, Qnil
);
571 /* Signal a change immediatly after it happens.
572 POS is the address of the start of the changed text.
573 LENDEL is the number of characters of the text before the change.
574 (Not the whole buffer; just the part that was changed.)
575 LENINS is the number of characters in the changed text. */
577 signal_after_change (pos
, lendel
, lenins
)
578 int pos
, lendel
, lenins
;
580 if (!NILP (Vafter_change_function
))
582 int count
= specpdl_ptr
- specpdl
;
583 Lisp_Object function
;
584 function
= Vafter_change_function
;
586 record_unwind_protect (after_change_function_restore
,
587 Vafter_change_function
);
588 record_unwind_protect (before_change_function_restore
,
589 Vbefore_change_function
);
590 Vafter_change_function
= Qnil
;
591 Vbefore_change_function
= Qnil
;
593 call3 (function
, make_number (pos
), make_number (pos
+ lenins
),
594 make_number (lendel
));
595 unbind_to (count
, Qnil
);