X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/00de298745d01c08289fab1b81c1c28795e2561c..59b7fa6569f8b865b6ef688a8531d745f1cc67d4:/src/insdel.c diff --git a/src/insdel.c b/src/insdel.c index e89ad9292b..365819b2cf 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1,5 +1,6 @@ /* Buffer insertion/deletion and gap motion for GNU Emacs. - Copyright (C) 1985, 86,93,94,95,97,98, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1985, 86,93,94,95,97,98, 1999, 2000, 2001 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -32,9 +33,6 @@ Boston, MA 02111-1307, USA. */ #define NULL 0 #endif -#define min(x, y) ((x) < (y) ? (x) : (y)) -#define max(x, y) ((x) > (y) ? (x) : (y)) - static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int)); static void insert_from_buffer_1 (); static void gap_left P_ ((int, int, int)); @@ -65,6 +63,9 @@ Lisp_Object combine_after_change_list; /* Buffer which combine_after_change_list is about. */ Lisp_Object combine_after_change_buffer; + +Lisp_Object Qinhibit_modification_hooks; + /* Check all markers in the current buffer, looking for something invalid. */ @@ -519,10 +520,9 @@ adjust_markers_for_replace (from, from_byte, old_chars, old_bytes, /* Make the gap NBYTES_ADDED bytes longer. */ void -make_gap (nbytes_added) +make_gap_larger (nbytes_added) int nbytes_added; { - unsigned char *result; Lisp_Object tem; int real_gap_loc; int real_gap_loc_byte; @@ -533,10 +533,13 @@ make_gap (nbytes_added) /* Don't allow a buffer size that won't fit in an int even if it will fit in a Lisp integer. - That won't work because so many places use `int'. */ + That won't work because so many places use `int'. + + Make sure we don't introduce overflows in the calculation. */ - if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added - >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1))) + if (Z_BYTE - BEG_BYTE + GAP_SIZE + >= (((EMACS_INT) 1 << (min (VALBITS, BITS_PER_INT) - 1)) - 1 + - nbytes_added)) error ("Buffer exceeds maximum size"); enlarge_buffer_text (current_buffer, nbytes_added); @@ -568,6 +571,78 @@ make_gap (nbytes_added) Vinhibit_quit = tem; } + + +/* Make the gap NBYTES_REMOVED bytes shorted. */ + +void +make_gap_smaller (nbytes_removed) + int nbytes_removed; +{ + Lisp_Object tem; + int real_gap_loc; + int real_gap_loc_byte; + int real_Z; + int real_Z_byte; + int real_beg_unchanged; + int new_gap_size; + + /* Make sure the gap is at least 20 bytes. */ + if (GAP_SIZE - nbytes_removed < 20) + nbytes_removed = GAP_SIZE - 20; + + /* Prevent quitting in move_gap. */ + tem = Vinhibit_quit; + Vinhibit_quit = Qt; + + real_gap_loc = GPT; + real_gap_loc_byte = GPT_BYTE; + new_gap_size = GAP_SIZE - nbytes_removed; + real_Z = Z; + real_Z_byte = Z_BYTE; + real_beg_unchanged = BEG_UNCHANGED; + + /* Pretend that the last unwanted part of the gap is the entire gap, + and that the first desired part of the gap is part of the buffer + text. */ + bzero (GPT_ADDR, new_gap_size); + GPT += new_gap_size; + GPT_BYTE += new_gap_size; + Z += new_gap_size; + Z_BYTE += new_gap_size; + GAP_SIZE = nbytes_removed; + + /* Move the unwanted pretend gap to the end of the buffer. This + adjusts the markers properly too. */ + gap_right (Z, Z_BYTE); + + enlarge_buffer_text (current_buffer, -nbytes_removed); + + /* Now restore the desired gap. */ + GAP_SIZE = new_gap_size; + GPT = real_gap_loc; + GPT_BYTE = real_gap_loc_byte; + Z = real_Z; + Z_BYTE = real_Z_byte; + BEG_UNCHANGED = real_beg_unchanged; + + /* Put an anchor. */ + *(Z_ADDR) = 0; + + Vinhibit_quit = tem; +} + +void +make_gap (nbytes_added) + int nbytes_added; +{ + if (nbytes_added >= 0) + make_gap_larger (nbytes_added); +#if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC + else + make_gap_smaller (-nbytes_added); +#endif +} /* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR. FROM_MULTIBYTE says whether the incoming text is multibyte. @@ -913,6 +988,9 @@ insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers) register int nchars, nbytes; int inherit, prepare, before_markers; { + if (nchars == 0) + return; + if (NILP (current_buffer->enable_multibyte_characters)) nchars = nbytes; @@ -1316,6 +1394,56 @@ adjust_after_replace (from, from_byte, prev_text, len, len_byte) MODIFF++; } +/* Like adjust_after_replace, but doesn't require PREV_TEXT. + This is for use when undo is not enabled in the current buffer. */ + +void +adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del, len, len_byte) + int from, from_byte, nchars_del, nbytes_del, len, len_byte; +{ +#ifdef BYTE_COMBINING_DEBUG + if (count_combining_before (GPT_ADDR, len_byte, from, from_byte) + || count_combining_after (GPT_ADDR, len_byte, from, from_byte)) + abort (); +#endif + + /* Update various buffer positions for the new text. */ + GAP_SIZE -= len_byte; + ZV += len; Z+= len; + ZV_BYTE += len_byte; Z_BYTE += len_byte; + GPT += len; GPT_BYTE += len_byte; + if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ + + if (nchars_del > 0) + adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, + len, len_byte); + else + adjust_markers_for_insert (from, from_byte, + from + len, from_byte + len_byte, 0); + + if (len > nchars_del) + adjust_overlays_for_insert (from, len - nchars_del); + else if (len < nchars_del) + adjust_overlays_for_delete (from, nchars_del - len); + if (BUF_INTERVALS (current_buffer) != 0) + { + offset_intervals (current_buffer, from, len - nchars_del); + } + + if (from < PT) + adjust_point (len - nchars_del, len_byte - nbytes_del); + + /* As byte combining will decrease Z, we must check this again. */ + if (Z - GPT < END_UNCHANGED) + END_UNCHANGED = Z - GPT; + + CHECK_MARKERS (); + + if (len == 0) + evaporate_overlays (from); + MODIFF++; +} + /* Record undo information, adjust markers and position keepers for an insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE). The text already exists in the current buffer but character length (TO @@ -1420,13 +1548,6 @@ replace_range (from, to, new, prepare, inherit, markers) if (! EQ (current_buffer->undo_list, Qt)) deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1); - if (markers) - /* Relocate all markers pointing into the new, larger gap - to point at the end of the text before the gap. - Do this before recording the deletion, - so that undo handles this after reinserting the text. */ - adjust_markers_for_delete (from, from_byte, to, to_byte); - GAP_SIZE += nbytes_del; ZV -= nchars_del; Z -= nchars_del; @@ -1486,10 +1607,11 @@ replace_range (from, to, new, prepare, inherit, markers) adjusting the markers that bound the overlays. */ adjust_overlays_for_delete (from, nchars_del); adjust_overlays_for_insert (from, inschars); + + /* Adjust markers for the deletion and the insertion. */ if (markers) - adjust_markers_for_insert (from, from_byte, - from + inschars, from_byte + outgoing_insbytes, - 0); + adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, + inschars, outgoing_insbytes); offset_intervals (current_buffer, from, inschars - nchars_del); @@ -1553,7 +1675,7 @@ del_range_1 (from, to, prepare, ret_string) { int range_length = to - from; prepare_to_modify_buffer (from, to, &from); - to = from + range_length; + to = min (ZV, from + range_length); } from_byte = CHAR_TO_BYTE (from); @@ -1596,7 +1718,12 @@ del_range_byte (from_byte, to_byte, prepare) if (old_from != from) from_byte = CHAR_TO_BYTE (from); - if (old_to == Z - to) + if (to > ZV) + { + to = ZV; + to_byte = ZV_BYTE; + } + else if (old_to == Z - to) to_byte = CHAR_TO_BYTE (to); } @@ -1635,7 +1762,12 @@ del_range_both (from, from_byte, to, to_byte, prepare) if (old_from != from) from_byte = CHAR_TO_BYTE (from); - if (old_to == Z - to) + if (to > ZV) + { + to = ZV; + to_byte = ZV_BYTE; + } + else if (old_to == Z - to) to_byte = CHAR_TO_BYTE (to); } @@ -1892,6 +2024,8 @@ signal_before_change (start_int, end_int, preserve_ptr) Lisp_Object before_change_functions; Lisp_Object after_change_functions; struct gcpro gcpro1, gcpro2; + struct buffer *old = current_buffer; + struct buffer *new; PRESERVE_VALUE; PRESERVE_START_END; @@ -1911,9 +2045,21 @@ signal_before_change (start_int, end_int, preserve_ptr) args[2] = FETCH_END; run_hook_list_with_args (before_change_functions, 3, args); - /* "Unbind" the variables we "bound" to nil. */ - Vbefore_change_functions = before_change_functions; - Vafter_change_functions = after_change_functions; + /* "Unbind" the variables we "bound" to nil. Beware a + buffer-local hook which changes the buffer when run (e.g. W3). */ + if (old != current_buffer) + { + new = current_buffer; + set_buffer_internal (old); + Vbefore_change_functions = before_change_functions; + Vafter_change_functions = after_change_functions; + set_buffer_internal (new); + } + else + { + Vbefore_change_functions = before_change_functions; + Vafter_change_functions = after_change_functions; + } UNGCPRO; } @@ -1979,6 +2125,8 @@ signal_after_change (charpos, lendel, lenins) Lisp_Object args[4]; Lisp_Object before_change_functions; Lisp_Object after_change_functions; + struct buffer *old = current_buffer; + struct buffer *new; struct gcpro gcpro1, gcpro2; /* "Bind" before-change-functions and after-change-functions @@ -1998,9 +2146,21 @@ signal_after_change (charpos, lendel, lenins) run_hook_list_with_args (after_change_functions, 4, args); - /* "Unbind" the variables we "bound" to nil. */ - Vbefore_change_functions = before_change_functions; - Vafter_change_functions = after_change_functions; + /* "Unbind" the variables we "bound" to nil. Beware a + buffer-local hook which changes the buffer when run (e.g. W3). */ + if (old != current_buffer) + { + new = current_buffer; + set_buffer_internal (old); + Vbefore_change_functions = before_change_functions; + Vafter_change_functions = after_change_functions; + set_buffer_internal (new); + } + else + { + Vbefore_change_functions = before_change_functions; + Vafter_change_functions = after_change_functions; + } UNGCPRO; } @@ -2029,9 +2189,9 @@ Fcombine_after_change_execute_1 (val) } DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, - Scombine_after_change_execute, 0, 0, 0, - "This function is for use internally in `combine-after-change-calls'.") - () + Scombine_after_change_execute, 0, 0, 0, + doc: /* This function is for use internally in `combine-after-change-calls'. */) + () { int count = specpdl_ptr - specpdl; int beg, end, change; @@ -2110,17 +2270,19 @@ syms_of_insdel () combine_after_change_buffer = Qnil; DEFVAR_BOOL ("check-markers-debug-flag", &check_markers_debug_flag, - "Non-nil means enable debugging checks for invalid marker positions."); + doc: /* Non-nil means enable debugging checks for invalid marker positions. */); check_markers_debug_flag = 0; DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls, - "Used internally by the `combine-after-change-calls' macro."); + doc: /* Used internally by the `combine-after-change-calls' macro. */); Vcombine_after_change_calls = Qnil; DEFVAR_BOOL ("inhibit-modification-hooks", &inhibit_modification_hooks, - "Non-nil means don't run any of the hooks that respond to buffer changes.\n\ -This affects `before-change-functions' and `after-change-functions',\n\ -as well as hooks attached to text properties and overlays."); + doc: /* Non-nil means don't run any of the hooks that respond to buffer changes. +This affects `before-change-functions' and `after-change-functions', +as well as hooks attached to text properties and overlays. */); inhibit_modification_hooks = 0; + Qinhibit_modification_hooks = intern ("inhibit-modification-hooks"); + staticpro (&Qinhibit_modification_hooks); defsubr (&Scombine_after_change_execute); }