Mercurial > hg > xemacs-beta
annotate src/insdel.c @ 4976:16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-02-04 Ben Wing <ben@xemacs.org>
* alloc.c (release_breathing_space):
* alloc.c (resize_string):
* alloc.c (sweep_lcrecords_1):
* alloc.c (SWEEP_FIXED_TYPE_BLOCK_1):
* alloc.c (ADDITIONAL_FREE_compiled_function):
* alloc.c (compact_string_chars):
* alloc.c (ADDITIONAL_FREE_string):
* alloc.c (sweep_strings):
* alloca.c (xemacs_c_alloca):
* alsaplay.c (alsa_play_sound_file):
* buffer.c (init_initial_directory):
* buffer.h:
* buffer.h (BUFFER_FREE):
* console-stream.c (stream_delete_console):
* console-tty.c (free_tty_console_struct):
* data.c (Fnumber_to_string):
* device-gtk.c (gtk_init_device):
* device-gtk.c (free_gtk_device_struct):
* device-gtk.c (gtk_delete_device):
* device-msw.c (mswindows_delete_device):
* device-msw.c (msprinter_delete_device):
* device-tty.c (free_tty_device_struct):
* device-tty.c (tty_delete_device):
* device-x.c (x_init_device):
* device-x.c (free_x_device_struct):
* device-x.c (x_delete_device):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-x.c (dbox_descriptor_to_widget_value):
* dired-msw.c (Fmswindows_insert_directory):
* dired.c (free_user_cache):
* dired.c (user_name_completion_unwind):
* doc.c (unparesseuxify_doc_string):
* doc.c (Fsubstitute_command_keys):
* doprnt.c (emacs_doprnt_1):
* dumper.c (pdump_load_finish):
* dumper.c (pdump_file_free):
* dumper.c (pdump_file_unmap):
* dynarr.c:
* dynarr.c (Dynarr_free):
* editfns.c (uncache_home_directory):
* editfns.c (Fset_time_zone_rule):
* elhash.c:
* elhash.c (pdump_reorganize_hash_table):
* elhash.c (maphash_unwind):
* emacs.c (make_arg_list_1):
* emacs.c (free_argc_argv):
* emacs.c (sort_args):
* emacs.c (Frunning_temacs_p):
* emodules.c (attempt_module_delete):
* eval.c (free_pointer):
* event-Xt.c (unselect_filedesc):
* event-Xt.c (emacs_Xt_select_process):
* event-gtk.c (unselect_filedesc):
* event-gtk.c (dragndrop_data_received):
* event-msw.c (winsock_closer):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (mswindows_wnd_proc):
* event-stream.c (finalize_command_builder):
* event-stream.c (free_command_builder):
* extents.c (free_gap_array):
* extents.c (free_extent_list):
* extents.c (free_soe):
* extents.c (extent_fragment_delete):
* extents.c (extent_priority_sort_function):
* file-coding.c (make_coding_system_1):
* file-coding.c (coding_finalizer):
* file-coding.c (set_coding_stream_coding_system):
* file-coding.c (chain_finalize_coding_stream_1):
* file-coding.c (chain_finalize):
* file-coding.c (free_detection_state):
* file-coding.c (coding_category_symbol_to_id):
* fileio.c:
* fileio.c (Ffile_name_directory):
* fileio.c (if):
* fileio.c (Ffile_symlink_p):
* filelock.c (FREE_LOCK_INFO):
* filelock.c (current_lock_owner):
* font-mgr.c (Ffc_name_unparse):
* font-mgr.c (Ffc_pattern_duplicate):
* frame-gtk.c (gtk_delete_frame):
* frame-msw.c (mswindows_delete_frame):
* frame-msw.c (msprinter_delete_frame):
* frame-x.c (x_cde_destroy_callback):
* frame-x.c (Fcde_start_drag_internal):
* frame-x.c (x_cde_transfer_callback):
* frame-x.c (x_delete_frame):
* frame.c (update_frame_title):
* frame.c (Fset_frame_pointer):
* gc.c (register_for_finalization):
* gccache-gtk.c (free_gc_cache):
* gccache-gtk.c (gc_cache_lookup):
* gccache-x.c (free_gc_cache):
* gccache-x.c (gc_cache_lookup):
* glyphs-eimage.c:
* glyphs-eimage.c (jpeg_instantiate_unwind):
* glyphs-eimage.c (gif_instantiate_unwind):
* glyphs-eimage.c (png_instantiate_unwind):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate_unwind):
* glyphs-gtk.c (convert_EImage_to_GDKImage):
* glyphs-gtk.c (gtk_finalize_image_instance):
* glyphs-gtk.c (gtk_init_image_instance_from_eimage):
* glyphs-gtk.c (gtk_xpm_instantiate):
* glyphs-msw.c (convert_EImage_to_DIBitmap):
* glyphs-msw.c (mswindows_init_image_instance_from_eimage):
* glyphs-msw.c (mswindows_initialize_image_instance_mask):
* glyphs-msw.c (xpm_to_eimage):
* glyphs-msw.c (mswindows_xpm_instantiate):
* glyphs-msw.c (xbm_create_bitmap_from_data):
* glyphs-msw.c (mswindows_finalize_image_instance):
* glyphs-x.c (convert_EImage_to_XImage):
* glyphs-x.c (x_finalize_image_instance):
* glyphs-x.c (x_init_image_instance_from_eimage):
* glyphs-x.c (x_xpm_instantiate):
* gui-x.c (free_popup_widget_value_tree):
* hash.c (free_hash_table):
* hash.c (grow_hash_table):
* hash.c (pregrow_hash_table_if_necessary):
* imgproc.c (build_EImage_quantable):
* insdel.c (uninit_buffer_text):
* intl-win32.c (convert_multibyte_to_internal_malloc):
* intl.c:
* intl.c (Fset_current_locale):
* keymap.c:
* keymap.c (where_is_recursive_mapper):
* keymap.c (where_is_internal):
* lisp.h:
* lisp.h (xfree):
* lstream.c (Lstream_close):
* lstream.c (resizing_buffer_closer):
* mule-coding.c:
* mule-coding.c (iso2022_finalize_detection_state):
* nt.c:
* nt.c (mswindows_get_long_filename):
* nt.c (nt_get_resource):
* nt.c (init_mswindows_environment):
* nt.c (get_cached_volume_information):
* nt.c (mswindows_opendir):
* nt.c (mswindows_closedir):
* nt.c (mswindows_readdir):
* nt.c (mswindows_stat):
* nt.c (mswindows_getdcwd):
* nt.c (Fmswindows_long_file_name):
* ntplay.c (nt_play_sound_file):
* ntplay.c (play_sound_data_1):
* number-gmp.c (gmp_free):
* number-gmp.c (init_number_gmp):
* number-mp.c (bignum_to_string):
* number-mp.c (BIGNUM_TO_TYPE):
* number.c (bignum_print):
* number.c (bignum_convfree):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-gtk.c (gtk_finalize_color_instance):
* objects-gtk.c (gtk_finalize_font_instance):
* objects-msw.c (mswindows_finalize_color_instance):
* objects-msw.c (mswindows_finalize_font_instance):
* objects-tty.c (tty_finalize_color_instance):
* objects-tty.c (tty_finalize_font_instance):
* objects-tty.c (tty_font_list):
* objects-x.c (x_finalize_color_instance):
* objects-x.c (x_finalize_font_instance):
* process.c:
* process.c (finalize_process):
* realpath.c:
* redisplay.c (add_propagation_runes):
* regex.c:
* regex.c (xfree):
* regex.c (REGEX_FREE_STACK):
* regex.c (FREE_STACK_RETURN):
* regex.c (regex_compile):
* regex.c (regexec):
* regex.c (regfree):
* scrollbar-gtk.c (gtk_free_scrollbar_instance):
* scrollbar-gtk.c (gtk_release_scrollbar_instance):
* scrollbar-msw.c (mswindows_free_scrollbar_instance):
* scrollbar-msw.c (unshow_that_mofo):
* scrollbar-x.c (x_free_scrollbar_instance):
* scrollbar-x.c (x_release_scrollbar_instance):
* select-gtk.c (emacs_gtk_selection_handle):
* select-msw.c (mswindows_own_selection):
* select-x.c:
* select-x.c (x_handle_selection_request):
* select-x.c (unexpect_property_change):
* select-x.c (x_handle_property_notify):
* select-x.c (receive_incremental_selection):
* select-x.c (x_get_window_property_as_lisp_data):
* select-x.c (Fx_get_cutbuffer_internal):
* specifier.c (finalize_specifier):
* syntax.c (uninit_buffer_syntax_cache):
* sysdep.c (qxe_allocating_getcwd):
* sysdep.c (qxe_lstat):
* sysdep.c (copy_in_passwd):
* sysdep.c (qxe_ctime):
* sysdep.c (closedir):
* sysdep.c (DIRSIZ):
* termcap.c (tgetent):
* termcap.c (tprint):
* tests.c (Ftest_data_format_conversion):
* text.c (new_dfc_convert_copy_data):
* text.h (eifree):
* text.h (eito_alloca):
* text.h (eito_external):
* toolbar-msw.c (mswindows_output_toolbar):
* ui-gtk.c (CONVERT_RETVAL):
* ui-gtk.c (__allocate_object_storage):
* unicode.c (free_from_unicode_table):
* unicode.c (free_to_unicode_table):
* unicode.c (free_charset_unicode_tables):
* win32.c (mswindows_read_link_1):
Rename: xfree(VAL, TYPE)->xfree(VAL)
Command used:
gr 'xfree *\((.*),.*\);' 'xfree (\1);' *.[ch]
Followed by grepping for 'xfree.*,' and fixing anything left.
Rationale: Having to specify the TYPE argument is annoying and
error-prone. It was originally put in to work around warnings
due to strict aliasing but years and years ago I rewrote it
in a way that doesn't use the TYPE argument at all and no one
has complained since then. (And anyway, XEmacs is far from
ever being in compliance with strict aliasing and would require
far-reaching changes to get that way.)
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Thu, 04 Feb 2010 07:28:14 -0600 |
parents | 304aebb79cd3 |
children | 6f2158fa75ed |
rev | line source |
---|---|
428 | 1 /* Buffer insertion/deletion and gap motion for XEmacs. |
2 Copyright (C) 1985, 1986, 1991, 1992, 1993, 1994, 1995 | |
3 Free Software Foundation, Inc. | |
4 Copyright (C) 1995 Sun Microsystems, Inc. | |
2367 | 5 Copyright (C) 2001, 2002, 2003, 2004 Ben Wing. |
428 | 6 |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Mule 2.0, FSF 19.30. Diverges significantly. */ | |
25 | |
26 /* This file has been Mule-ized. */ | |
27 | |
853 | 28 /* Original file from FSF, 1991. |
29 Some changes for extents, c. 1991 by unknown Lucid author. | |
30 Completely rewritten December 1994, for Mule implementation by Ben Wing; | |
31 all buffer modification code ripped out of other files and consolidated | |
32 here. | |
33 Indirect buffers written c. 1997? by Hrvoje Niksic. | |
34 */ | |
428 | 35 |
36 #include <config.h> | |
37 #include "lisp.h" | |
38 | |
39 #include "buffer.h" | |
40 #include "device.h" | |
41 #include "frame.h" | |
42 #include "extents.h" | |
43 #include "insdel.h" | |
44 #include "lstream.h" | |
45 #include "redisplay.h" | |
46 #include "line-number.h" | |
47 | |
48 /* Various macros modelled along the lines of those in buffer.h. | |
49 Purposefully omitted from buffer.h because files other than this | |
50 one should not be using them. */ | |
51 | |
52 /* Address of beginning of buffer. This is an lvalue because | |
53 BUFFER_ALLOC needs it to be. */ | |
54 #define BUF_BEG_ADDR(buf) ((buf)->text->beg) | |
55 | |
56 /* Set the address of beginning of buffer. */ | |
57 #define SET_BUF_BEG_ADDR(buf, addr) do { (buf)->text->beg = (addr); } while (0) | |
58 | |
59 /* Gap size. */ | |
60 #define BUF_GAP_SIZE(buf) ((buf)->text->gap_size + 0) | |
61 #define BUF_END_GAP_SIZE(buf) ((buf)->text->end_gap_size + 0) | |
62 /* Set gap size. */ | |
63 #define SET_BUF_GAP_SIZE(buf, value) \ | |
64 do { (buf)->text->gap_size = (value); } while (0) | |
65 #define SET_BUF_END_GAP_SIZE(buf, value) \ | |
66 do { (buf)->text->end_gap_size = (value); } while (0) | |
67 | |
826 | 68 #define BUF_GPT_ADDR(buf) (BUF_BEG_ADDR (buf) + BYTE_BUF_GPT (buf) - 1) |
428 | 69 |
70 /* Set gap location. */ | |
2367 | 71 #define SET_BOTH_BUF_GPT(buf, cval, bval) \ |
72 do \ | |
73 { \ | |
74 (buf)->text->gpt = (bval); \ | |
75 (buf)->text->bufgpt = (cval); \ | |
76 } while (0) | |
428 | 77 |
78 /* Set end of buffer. */ | |
2367 | 79 #define SET_BOTH_BUF_Z(buf, cval, bval) \ |
428 | 80 do \ |
81 { \ | |
2367 | 82 (buf)->text->z = (bval); \ |
83 (buf)->text->bufz = (cval); \ | |
428 | 84 } while (0) |
85 | |
86 /* Under Mule, we maintain two sentinels in the buffer: one at the | |
87 beginning of the gap, and one at the end of the buffer. This | |
88 allows us to move forward, examining bytes looking for the | |
89 end of a character, and not worry about running off the end. | |
90 We do not need corresponding sentinels when moving backwards | |
91 because we do not have to look past the beginning of a character | |
92 to find the beginning of the character. | |
93 | |
94 Every time we change the beginning of the gap, we have to | |
95 call SET_GAP_SENTINEL(). | |
96 | |
97 Every time we change the total size (characters plus gap) | |
98 of the buffer, we have to call SET_END_SENTINEL(). | |
99 */ | |
100 | |
101 | |
102 #ifdef MULE | |
103 # define GAP_CAN_HOLD_SIZE_P(buf, len) (BUF_GAP_SIZE (buf) >= (len) + 1) | |
104 # define SET_GAP_SENTINEL(buf) (*BUF_GPT_ADDR (buf) = 0) | |
105 # define BUF_END_SENTINEL_SIZE 1 | |
106 # define SET_END_SENTINEL(buf) \ | |
826 | 107 (*(BUF_BEG_ADDR (buf) + BUF_GAP_SIZE (buf) + BYTE_BUF_Z (buf) - 1) = 0) |
428 | 108 #else |
109 # define GAP_CAN_HOLD_SIZE_P(buf, len) (BUF_GAP_SIZE (buf) >= (len)) | |
110 # define SET_GAP_SENTINEL(buf) | |
111 # define BUF_END_SENTINEL_SIZE 0 | |
112 # define SET_END_SENTINEL(buf) | |
113 #endif | |
114 | |
115 | |
116 /************************************************************************/ | |
117 /* point and marker adjustment */ | |
118 /************************************************************************/ | |
119 | |
120 /* just_set_point() is the only place `PT' is an lvalue in all of emacs. | |
121 This function is called from set_buffer_point(), which is the function | |
122 that the SET_PT and BUF_SET_PT macros expand into, and from the | |
123 routines below that insert and delete text. (This is in cases where | |
124 the point marker logically doesn't move but PT (being a byte index) | |
125 needs to get adjusted.) */ | |
126 | |
127 /* Set point to a specified value. This is used only when the value | |
128 of point changes due to an insert or delete; it does not represent | |
129 a conceptual change in point as a marker. In particular, point is | |
130 not crossing any interval boundaries, so there's no need to use the | |
131 usual SET_PT macro. In fact it would be incorrect to do so, because | |
132 either the old or the new value of point is out of synch with the | |
133 current set of intervals. */ | |
134 | |
135 /* This gets called more than enough to make the function call | |
136 overhead a significant factor so we've turned it into a macro. */ | |
665 | 137 #define JUST_SET_POINT(buf, charbpos, ind) \ |
428 | 138 do \ |
139 { \ | |
665 | 140 buf->bufpt = (charbpos); \ |
428 | 141 buf->pt = (ind); \ |
142 } while (0) | |
143 | |
144 /* Set a buffer's point. */ | |
145 | |
146 void | |
665 | 147 set_buffer_point (struct buffer *buf, Charbpos charbpos, Bytebpos bytpos) |
428 | 148 { |
826 | 149 assert (bytpos >= BYTE_BUF_BEGV (buf) && bytpos <= BYTE_BUF_ZV (buf)); |
150 if (bytpos == BYTE_BUF_PT (buf)) | |
428 | 151 return; |
665 | 152 JUST_SET_POINT (buf, charbpos, bytpos); |
428 | 153 MARK_POINT_CHANGED; |
154 assert (MARKERP (buf->point_marker)); | |
665 | 155 XMARKER (buf->point_marker)->membpos = |
156 bytebpos_to_membpos (buf, bytpos); | |
428 | 157 |
158 /* FSF makes sure that PT is not being set within invisible text. | |
159 However, this is the wrong place for that check. The check | |
160 should happen only at the next redisplay. */ | |
161 | |
162 /* Some old coder said: | |
163 | |
164 "If there were to be hooks which were run when point entered/left an | |
165 extent, this would be the place to put them. | |
166 | |
167 However, it's probably the case that such hooks should be implemented | |
168 using a post-command-hook instead, to avoid running the hooks as a | |
169 result of intermediate motion inside of save-excursions, for example." | |
170 | |
171 I definitely agree with this. PT gets moved all over the place | |
172 and it would be a Bad Thing for any hooks to get called, both for | |
173 the reason above and because many callers are not prepared for | |
174 a GC within this function. --ben | |
175 */ | |
176 } | |
177 | |
178 /* Do the correct marker-like adjustment on MPOS (see below). FROM, TO, | |
179 and AMOUNT are as in adjust_markers(). If MPOS doesn't need to be | |
180 adjusted, nothing will happen. */ | |
665 | 181 Membpos |
182 do_marker_adjustment (Membpos mpos, Membpos from, | |
183 Membpos to, Bytecount amount) | |
428 | 184 { |
185 if (amount > 0) | |
186 { | |
187 if (mpos > to && mpos < to + amount) | |
188 mpos = to + amount; | |
189 } | |
190 else | |
191 { | |
192 if (mpos > from + amount && mpos <= from) | |
193 mpos = from + amount; | |
194 } | |
195 if (mpos > from && mpos <= to) | |
196 mpos += amount; | |
197 return mpos; | |
198 } | |
199 | |
200 /* Do the following: | |
201 | |
202 (1) Add `amount' to the position of every marker in the current buffer | |
203 whose current position is between `from' (exclusive) and `to' (inclusive). | |
204 | |
205 (2) 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'. | |
208 | |
209 This function is called in two different cases: when a region of | |
210 characters adjacent to the gap is moved, causing the gap to shift | |
211 to the other side of the region (in this case, `from' and `to' | |
212 point to the old position of the region and there should be no | |
213 markers affected by (2) because they would be inside the gap), | |
214 or when a region of characters adjacent to the gap is wiped out, | |
215 causing the gap to increase to include the region (in this case, | |
216 `from' and `to' are the same, both pointing to the boundary | |
217 between the gap and the deleted region, and there are no markers | |
218 affected by (1)). | |
219 | |
220 The reason for the use of exclusive and inclusive is that markers at | |
221 the gap always sit at the beginning, not at the end. | |
222 */ | |
223 | |
224 static void | |
665 | 225 adjust_markers (struct buffer *buf, Membpos from, Membpos to, |
428 | 226 Bytecount amount) |
227 { | |
440 | 228 Lisp_Marker *m; |
428 | 229 |
230 for (m = BUF_MARKERS (buf); m; m = marker_next (m)) | |
665 | 231 m->membpos = do_marker_adjustment (m->membpos, from, to, amount); |
428 | 232 } |
233 | |
234 /* Adjust markers whose insertion-type is t | |
235 for an insertion of AMOUNT characters at POS. */ | |
236 | |
237 static void | |
665 | 238 adjust_markers_for_insert (struct buffer *buf, Membpos ind, Bytecount amount) |
428 | 239 { |
440 | 240 Lisp_Marker *m; |
428 | 241 |
242 for (m = BUF_MARKERS (buf); m; m = marker_next (m)) | |
243 { | |
665 | 244 if (m->insertion_type && m->membpos == ind) |
245 m->membpos += amount; | |
428 | 246 } |
247 } | |
248 | |
249 | |
250 /************************************************************************/ | |
251 /* Routines for dealing with the gap */ | |
252 /************************************************************************/ | |
253 | |
254 /* maximum amount of memory moved in a single chunk. Increasing this | |
255 value improves gap-motion efficiency but decreases QUIT responsiveness | |
256 time. Was 32000 but today's processors are faster and files are | |
257 bigger. --ben */ | |
258 #define GAP_MOVE_CHUNK 300000 | |
259 | |
2367 | 260 /* Move the gap to CPOS/BPOS, which is less than the current GPT. */ |
428 | 261 |
262 static void | |
2367 | 263 gap_left (struct buffer *buf, Charbpos cpos, Bytebpos bpos) |
428 | 264 { |
867 | 265 Ibyte *to, *from; |
428 | 266 Bytecount i; |
665 | 267 Bytebpos new_s1; |
428 | 268 struct buffer *mbuf; |
269 Lisp_Object bufcons; | |
270 | |
271 from = BUF_GPT_ADDR (buf); | |
272 to = from + BUF_GAP_SIZE (buf); | |
826 | 273 new_s1 = BYTE_BUF_GPT (buf); |
428 | 274 |
275 /* Now copy the characters. To move the gap down, | |
276 copy characters up. */ | |
277 | |
278 while (1) | |
279 { | |
280 /* I gets number of characters left to copy. */ | |
2367 | 281 i = new_s1 - bpos; |
428 | 282 if (i == 0) |
283 break; | |
284 /* If a quit is requested, stop copying now. | |
2367 | 285 Change BPOS to be where we have actually moved the gap to. */ |
428 | 286 if (QUITP) |
287 { | |
2367 | 288 bpos = new_s1; |
289 cpos = bytebpos_to_charbpos (buf, bpos); | |
428 | 290 break; |
291 } | |
292 /* Move at most GAP_MOVE_CHUNK chars before checking again for a quit. */ | |
293 if (i > GAP_MOVE_CHUNK) | |
294 i = GAP_MOVE_CHUNK; | |
440 | 295 |
2367 | 296 if (i >= 10) /* was 128 but memmove() should be extremely efficient |
297 nowadays */ | |
428 | 298 { |
299 new_s1 -= i; | |
440 | 300 from -= i; |
301 to -= i; | |
428 | 302 memmove (to, from, i); |
303 } | |
304 else | |
305 { | |
306 new_s1 -= i; | |
307 while (--i >= 0) | |
308 *--to = *--from; | |
309 } | |
310 } | |
311 | |
2367 | 312 /* Adjust markers, and buffer data structure, to put the gap at BPOS. |
313 BPOS is where the loop above stopped, which may be what was specified | |
428 | 314 or may be where a quit was detected. */ |
315 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
316 { | |
2367 | 317 adjust_markers (mbuf, bpos, BYTE_BUF_GPT (mbuf), BUF_GAP_SIZE (mbuf)); |
428 | 318 } |
319 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
320 { | |
2367 | 321 adjust_extents (wrap_buffer (mbuf), bpos, BYTE_BUF_GPT (mbuf), |
428 | 322 BUF_GAP_SIZE (mbuf)); |
323 } | |
2367 | 324 SET_BOTH_BUF_GPT (buf, cpos, bpos); |
428 | 325 SET_GAP_SENTINEL (buf); |
326 #ifdef ERROR_CHECK_EXTENTS | |
327 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
328 { | |
771 | 329 sledgehammer_extent_check (wrap_buffer (mbuf)); |
428 | 330 } |
331 #endif | |
332 QUIT; | |
333 } | |
334 | |
335 static void | |
2367 | 336 gap_right (struct buffer *buf, Charbpos cpos, Bytebpos bpos) |
428 | 337 { |
867 | 338 Ibyte *to, *from; |
428 | 339 Bytecount i; |
665 | 340 Bytebpos new_s1; |
428 | 341 struct buffer *mbuf; |
342 Lisp_Object bufcons; | |
343 | |
344 to = BUF_GPT_ADDR (buf); | |
345 from = to + BUF_GAP_SIZE (buf); | |
826 | 346 new_s1 = BYTE_BUF_GPT (buf); |
428 | 347 |
348 /* Now copy the characters. To move the gap up, | |
349 copy characters down. */ | |
350 | |
351 while (1) | |
352 { | |
353 /* I gets number of characters left to copy. */ | |
2367 | 354 i = bpos - new_s1; |
428 | 355 if (i == 0) |
356 break; | |
357 /* If a quit is requested, stop copying now. | |
2367 | 358 Change BPOS to be where we have actually moved the gap to. */ |
428 | 359 if (QUITP) |
360 { | |
2367 | 361 bpos = new_s1; |
362 cpos = bytebpos_to_charbpos (buf, bpos); | |
428 | 363 break; |
364 } | |
365 /* Move at most GAP_MOVE_CHUNK chars before checking again for a quit. */ | |
366 if (i > GAP_MOVE_CHUNK) | |
367 i = GAP_MOVE_CHUNK; | |
440 | 368 |
2367 | 369 if (i >= 10) /* was 128 but memmove() should be extremely efficient |
370 nowadays */ | |
428 | 371 { |
372 new_s1 += i; | |
373 memmove (to, from, i); | |
440 | 374 from += i; |
375 to += i; | |
428 | 376 } |
377 else | |
378 { | |
379 new_s1 += i; | |
380 while (--i >= 0) | |
381 *to++ = *from++; | |
382 } | |
383 } | |
384 | |
385 { | |
386 int gsize = BUF_GAP_SIZE (buf); | |
387 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
388 { | |
2367 | 389 adjust_markers (mbuf, BYTE_BUF_GPT (mbuf) + gsize, bpos + gsize, - gsize); |
428 | 390 } |
391 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
392 { | |
826 | 393 adjust_extents (wrap_buffer (mbuf), BYTE_BUF_GPT (mbuf) + gsize, |
2367 | 394 bpos + gsize, - gsize); |
428 | 395 } |
2367 | 396 SET_BOTH_BUF_GPT (buf, cpos, bpos); |
428 | 397 SET_GAP_SENTINEL (buf); |
398 #ifdef ERROR_CHECK_EXTENTS | |
399 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
400 { | |
771 | 401 sledgehammer_extent_check (wrap_buffer (mbuf)); |
428 | 402 } |
403 #endif | |
404 } | |
2367 | 405 if (bpos == BYTE_BUF_Z (buf)) |
428 | 406 { |
407 /* merge gap with end gap */ | |
408 | |
409 SET_BUF_GAP_SIZE (buf, BUF_GAP_SIZE (buf) + BUF_END_GAP_SIZE (buf)); | |
410 SET_BUF_END_GAP_SIZE (buf, 0); | |
411 SET_END_SENTINEL (buf); | |
412 } | |
413 | |
414 QUIT; | |
415 } | |
416 | |
2367 | 417 /* Move gap to position `bpos'. |
428 | 418 Note that this can quit! */ |
419 | |
420 static void | |
2367 | 421 move_gap (struct buffer *buf, Charbpos cpos, Bytebpos bpos) |
428 | 422 { |
423 if (! BUF_BEG_ADDR (buf)) | |
2500 | 424 ABORT (); |
2367 | 425 if (bpos < BYTE_BUF_GPT (buf)) |
426 gap_left (buf, cpos, bpos); | |
427 else if (bpos > BYTE_BUF_GPT (buf)) | |
428 gap_right (buf, cpos, bpos); | |
428 | 429 } |
430 | |
431 /* Merge the end gap into the gap */ | |
432 | |
433 static void | |
434 merge_gap_with_end_gap (struct buffer *buf) | |
435 { | |
436 Lisp_Object tem; | |
2367 | 437 Charbpos real_gap_loc_char; |
438 Bytebpos real_gap_loc_byte; | |
428 | 439 Bytecount old_gap_size; |
440 Bytecount increment; | |
441 | |
442 increment = BUF_END_GAP_SIZE (buf); | |
443 SET_BUF_END_GAP_SIZE (buf, 0); | |
444 | |
445 if (increment > 0) | |
446 { | |
447 /* Prevent quitting in move_gap. */ | |
448 tem = Vinhibit_quit; | |
449 Vinhibit_quit = Qt; | |
450 | |
2367 | 451 real_gap_loc_char = BUF_GPT (buf); |
452 real_gap_loc_byte = BYTE_BUF_GPT (buf); | |
428 | 453 old_gap_size = BUF_GAP_SIZE (buf); |
454 | |
455 /* Pretend the end gap is the gap */ | |
2367 | 456 SET_BOTH_BUF_GPT (buf, BUF_Z (buf) + BUF_GAP_SIZE (buf), |
457 BYTE_BUF_Z (buf) + BUF_GAP_SIZE (buf)); | |
428 | 458 SET_BUF_GAP_SIZE (buf, increment); |
459 | |
460 /* Move the new gap down to be consecutive with the end of the old one. | |
461 This adjusts the markers properly too. */ | |
2367 | 462 gap_left (buf, real_gap_loc_char + old_gap_size, |
463 real_gap_loc_byte + old_gap_size); | |
428 | 464 |
465 /* Now combine the two into one large gap. */ | |
466 SET_BUF_GAP_SIZE (buf, BUF_GAP_SIZE (buf) + old_gap_size); | |
2367 | 467 SET_BOTH_BUF_GPT (buf, real_gap_loc_char, real_gap_loc_byte); |
428 | 468 SET_GAP_SENTINEL (buf); |
469 | |
470 /* We changed the total size of the buffer (including gap), | |
471 so we need to fix up the end sentinel. */ | |
472 SET_END_SENTINEL (buf); | |
473 | |
474 Vinhibit_quit = tem; | |
475 } | |
476 } | |
477 | |
478 /* Make the gap INCREMENT bytes longer. */ | |
479 | |
480 static void | |
481 make_gap (struct buffer *buf, Bytecount increment) | |
482 { | |
867 | 483 Ibyte *result; |
428 | 484 Lisp_Object tem; |
2367 | 485 Charbpos real_gap_loc_char; |
486 Bytebpos real_gap_loc_byte; | |
428 | 487 Bytecount old_gap_size; |
488 | |
489 /* If we have to get more space, get enough to last a while. We use | |
490 a geometric progression that saves on realloc space. */ | |
826 | 491 increment += 2000 + ((BYTE_BUF_Z (buf) - BYTE_BUF_BEG (buf)) / 8); |
492 /* Make sure the gap is always aligned properly in case we're using a | |
493 16-bit or 32-bit fixed-width format. (Other sizes should already be | |
494 aligned in such a case.) */ | |
495 increment = MAX_ALIGN_SIZE (increment); | |
428 | 496 |
497 if (increment > BUF_END_GAP_SIZE (buf)) | |
498 { | |
499 /* Don't allow a buffer size that won't fit in an int | |
500 even if it will fit in a Lisp integer. | |
501 That won't work because so many places use `int'. */ | |
502 | |
503 if (BUF_Z (buf) - BUF_BEG (buf) + BUF_GAP_SIZE (buf) + increment | |
504 > EMACS_INT_MAX) | |
563 | 505 out_of_memory ("Maximum buffer size exceeded", Qunbound); |
428 | 506 |
507 result = BUFFER_REALLOC (buf->text->beg, | |
826 | 508 BYTE_BUF_Z (buf) - BYTE_BUF_BEG (buf) + |
428 | 509 BUF_GAP_SIZE (buf) + increment + |
510 BUF_END_SENTINEL_SIZE); | |
511 if (result == 0) | |
512 memory_full (); | |
513 | |
514 SET_BUF_BEG_ADDR (buf, result); | |
515 } | |
516 else | |
517 increment = BUF_END_GAP_SIZE (buf); | |
518 | |
519 /* Prevent quitting in move_gap. */ | |
520 tem = Vinhibit_quit; | |
521 Vinhibit_quit = Qt; | |
522 | |
2367 | 523 real_gap_loc_char = BUF_GPT (buf); |
524 real_gap_loc_byte = BYTE_BUF_GPT (buf); | |
428 | 525 old_gap_size = BUF_GAP_SIZE (buf); |
526 | |
527 /* Call the newly allocated space a gap at the end of the whole space. */ | |
2367 | 528 SET_BOTH_BUF_GPT (buf, BUF_Z (buf) + BUF_GAP_SIZE (buf), |
529 BYTE_BUF_Z (buf) + BUF_GAP_SIZE (buf)); | |
428 | 530 SET_BUF_GAP_SIZE (buf, increment); |
531 | |
532 SET_BUF_END_GAP_SIZE (buf, 0); | |
533 | |
534 /* Move the new gap down to be consecutive with the end of the old one. | |
535 This adjusts the markers properly too. */ | |
2367 | 536 gap_left (buf, real_gap_loc_char + old_gap_size, |
537 real_gap_loc_byte + old_gap_size); | |
428 | 538 |
539 /* Now combine the two into one large gap. */ | |
540 SET_BUF_GAP_SIZE (buf, BUF_GAP_SIZE (buf) + old_gap_size); | |
2367 | 541 SET_BOTH_BUF_GPT (buf, real_gap_loc_char, real_gap_loc_byte); |
428 | 542 SET_GAP_SENTINEL (buf); |
543 | |
544 /* We changed the total size of the buffer (including gap), | |
545 so we need to fix up the end sentinel. */ | |
546 SET_END_SENTINEL (buf); | |
547 | |
548 Vinhibit_quit = tem; | |
549 } | |
550 | |
551 | |
552 /************************************************************************/ | |
553 /* Before/after-change processing */ | |
554 /************************************************************************/ | |
555 | |
556 /* Those magic changes ... */ | |
557 | |
558 static void | |
665 | 559 buffer_signal_changed_region (struct buffer *buf, Charbpos start, |
560 Charbpos end) | |
428 | 561 { |
562 /* The changed region is recorded as the number of unchanged | |
563 characters from the beginning and from the end of the | |
564 buffer. This obviates much of the need of shifting the | |
565 region around to compensate for insertions and deletions. | |
566 */ | |
567 if (buf->changes->begin_unchanged < 0 || | |
568 buf->changes->begin_unchanged > start - BUF_BEG (buf)) | |
569 buf->changes->begin_unchanged = start - BUF_BEG (buf); | |
570 if (buf->changes->end_unchanged < 0 || | |
571 buf->changes->end_unchanged > BUF_Z (buf) - end) | |
572 buf->changes->end_unchanged = BUF_Z (buf) - end; | |
573 } | |
574 | |
575 void | |
665 | 576 buffer_extent_signal_changed_region (struct buffer *buf, Charbpos start, |
577 Charbpos end) | |
428 | 578 { |
579 if (buf->changes->begin_extent_unchanged < 0 || | |
580 buf->changes->begin_extent_unchanged > start - BUF_BEG (buf)) | |
581 buf->changes->begin_extent_unchanged = start - BUF_BEG (buf); | |
582 if (buf->changes->end_extent_unchanged < 0 || | |
583 buf->changes->end_extent_unchanged > BUF_Z (buf) - end) | |
584 buf->changes->end_extent_unchanged = BUF_Z (buf) - end; | |
585 } | |
586 | |
587 void | |
588 buffer_reset_changes (struct buffer *buf) | |
589 { | |
590 buf->changes->begin_unchanged = -1; | |
591 buf->changes->end_unchanged = -1; | |
592 buf->changes->begin_extent_unchanged = -1; | |
593 buf->changes->end_extent_unchanged = -1; | |
594 buf->changes->newline_was_deleted = 0; | |
595 } | |
596 | |
597 static void | |
665 | 598 signal_after_change (struct buffer *buf, Charbpos start, Charbpos orig_end, |
599 Charbpos new_end); | |
428 | 600 |
601 | |
602 /* Call the after-change-functions according to the changes made so far | |
603 and treat all further changes as single until the outermost | |
604 multiple change exits. This is called when the outermost multiple | |
605 change exits and when someone is trying to make a change that violates | |
606 the constraints specified in begin_multiple_change(), typically | |
607 when nested multiple-change sessions occur. (There are smarter ways of | |
608 dealing with nested multiple changes, but these rarely occur so there's | |
609 probably no point in it.) */ | |
610 | |
611 /* #### This needs to keep track of what actually changed and only | |
612 call the after-change functions on that region. */ | |
613 | |
614 static void | |
615 cancel_multiple_change (struct buffer *buf) | |
616 { | |
617 /* This function can GC */ | |
618 /* Call the after-change-functions except when they've already been | |
619 called or when there were no changes made to the buffer at all. */ | |
620 if (buf->text->changes->mc_begin != 0 && | |
621 buf->text->changes->mc_begin_signaled) | |
622 { | |
665 | 623 Charbpos real_mc_begin = buf->text->changes->mc_begin; |
428 | 624 buf->text->changes->mc_begin = 0; |
625 | |
626 signal_after_change (buf, real_mc_begin, buf->text->changes->mc_orig_end, | |
627 buf->text->changes->mc_new_end); | |
628 } | |
629 else | |
630 { | |
631 buf->text->changes->mc_begin = 0; | |
632 } | |
633 } | |
634 | |
635 /* this is an unwind_protect, to ensure that the after-change-functions | |
636 get called even in a non-local exit. */ | |
637 | |
638 static Lisp_Object | |
639 multiple_change_finish_up (Lisp_Object buffer) | |
640 { | |
641 struct buffer *buf = XBUFFER (buffer); | |
642 | |
643 /* #### I don't know whether or not it should even be possible to | |
644 get here with a dead buffer (though given how it is called I can | |
645 see how it might be). In any case, there isn't time before 19.14 | |
646 to find out. */ | |
647 if (!BUFFER_LIVE_P (buf)) | |
648 return Qnil; | |
649 | |
650 /* This function can GC */ | |
651 buf->text->changes->in_multiple_change = 0; /* do this first so that | |
652 errors in the after-change | |
653 functions don't mess things | |
654 up. */ | |
655 cancel_multiple_change (buf); | |
656 return Qnil; | |
657 } | |
658 | |
659 /* Call this function when you're about to make a number of buffer changes | |
660 that should be considered a single change. (e.g. `replace-match' calls | |
661 this.) You need to specify the START and END of the region that is | |
662 going to be changed so that the before-change-functions are called | |
663 with the correct arguments. The after-change region is calculated | |
664 automatically, however, and if changes somehow or other happen outside | |
665 of the specified region, that will also be handled correctly. | |
666 | |
667 begin_multiple_change() returns a number (actually a specpdl depth) | |
438 | 668 that you must pass to end_multiple_change() when you are done. |
669 | |
670 FSF Emacs 20 implements a similar feature, accessible from Lisp | |
671 through a `combine-after-change-calls' special form, which is | |
672 essentially equivalent to this function. We should consider | |
673 whether we want to introduce a similar Lisp form. */ | |
428 | 674 |
675 int | |
665 | 676 begin_multiple_change (struct buffer *buf, Charbpos start, Charbpos end) |
428 | 677 { |
678 /* This function can GC */ | |
679 int count = -1; | |
680 if (buf->text->changes->in_multiple_change) | |
681 { | |
682 if (buf->text->changes->mc_begin != 0 && | |
683 (start < buf->text->changes->mc_begin || | |
684 end > buf->text->changes->mc_new_end)) | |
685 cancel_multiple_change (buf); | |
686 } | |
687 else | |
688 { | |
689 Lisp_Object buffer; | |
690 | |
691 buf->text->changes->mc_begin = start; | |
692 buf->text->changes->mc_orig_end = buf->text->changes->mc_new_end = end; | |
693 buf->text->changes->mc_begin_signaled = 0; | |
694 count = specpdl_depth (); | |
793 | 695 buffer = wrap_buffer (buf); |
428 | 696 record_unwind_protect (multiple_change_finish_up, buffer); |
697 } | |
698 buf->text->changes->in_multiple_change++; | |
699 /* We don't call before-change-functions until signal_before_change() | |
700 is called, in case there is a read-only or other error. */ | |
701 return count; | |
702 } | |
703 | |
704 void | |
705 end_multiple_change (struct buffer *buf, int count) | |
706 { | |
707 assert (buf->text->changes->in_multiple_change > 0); | |
708 buf->text->changes->in_multiple_change--; | |
709 if (!buf->text->changes->in_multiple_change) | |
771 | 710 unbind_to (count); |
428 | 711 } |
712 | |
713 static int inside_change_hook; | |
714 | |
715 static Lisp_Object | |
716 change_function_restore (Lisp_Object buffer) | |
717 { | |
718 /* We should first reset the variable and then change the buffer, | |
719 because Fset_buffer() can throw. */ | |
720 inside_change_hook = 0; | |
438 | 721 if (XBUFFER (buffer) != current_buffer) |
722 Fset_buffer (buffer); | |
428 | 723 return Qnil; |
724 } | |
725 | |
726 static int in_first_change; | |
727 | |
728 static Lisp_Object | |
729 first_change_hook_restore (Lisp_Object buffer) | |
730 { | |
731 in_first_change = 0; | |
732 Fset_buffer (buffer); | |
733 return Qnil; | |
734 } | |
735 | |
736 /* Signal an initial modification to the buffer. */ | |
737 | |
738 static void | |
739 signal_first_change (struct buffer *buf) | |
740 { | |
741 /* This function can GC */ | |
793 | 742 Lisp_Object buffer = wrap_buffer (current_buffer); |
743 | |
428 | 744 |
745 if (!in_first_change) | |
746 { | |
747 if (!NILP (symbol_value_in_buffer (Qfirst_change_hook, buffer))) | |
748 { | |
749 int speccount = specpdl_depth (); | |
750 record_unwind_protect (first_change_hook_restore, buffer); | |
751 set_buffer_internal (buf); | |
752 in_first_change = 1; | |
853 | 753 run_hook_trapping_problems |
1333 | 754 (Qchange, Qfirst_change_hook, |
853 | 755 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); |
771 | 756 unbind_to (speccount); |
428 | 757 } |
758 } | |
759 } | |
760 | |
761 /* Signal a change to the buffer immediately before it happens. | |
762 START and END are the bounds of the text to be changed. */ | |
763 | |
764 static void | |
665 | 765 signal_before_change (struct buffer *buf, Charbpos start, Charbpos end) |
428 | 766 { |
767 /* This function can GC */ | |
768 struct buffer *mbuf; | |
769 Lisp_Object bufcons; | |
770 | |
771 if (!inside_change_hook) | |
772 { | |
773 Lisp_Object buffer; | |
438 | 774 int speccount; |
428 | 775 |
776 /* Are we in a multiple-change session? */ | |
777 if (buf->text->changes->in_multiple_change && | |
778 buf->text->changes->mc_begin != 0) | |
779 { | |
780 /* If we're violating the constraints of the session, | |
781 call the after-change-functions as necessary for the | |
782 changes already made and treat further changes as | |
783 single. */ | |
784 if (start < buf->text->changes->mc_begin || | |
785 end > buf->text->changes->mc_new_end) | |
786 cancel_multiple_change (buf); | |
787 /* Do nothing if this is not the first change in the session. */ | |
788 else if (buf->text->changes->mc_begin_signaled) | |
789 return; | |
790 else | |
791 { | |
792 /* First time through; call the before-change-functions | |
793 specifying the entire region to be changed. (Note that | |
794 we didn't call before-change-functions in | |
795 begin_multiple_change() because the buffer might be | |
796 read-only, etc.) */ | |
797 start = buf->text->changes->mc_begin; | |
798 end = buf->text->changes->mc_new_end; | |
799 } | |
800 } | |
801 | |
802 /* If buffer is unmodified, run a special hook for that case. */ | |
803 if (BUF_SAVE_MODIFF (buf) >= BUF_MODIFF (buf)) | |
804 { | |
805 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
806 { | |
807 signal_first_change (mbuf); | |
808 } | |
809 } | |
810 | |
811 /* Now in any case run the before-change-functions if any. */ | |
438 | 812 speccount = specpdl_depth (); |
813 record_unwind_protect (change_function_restore, Fcurrent_buffer ()); | |
814 inside_change_hook = 1; | |
428 | 815 |
816 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
817 { | |
793 | 818 buffer = wrap_buffer (mbuf); |
428 | 819 if (!NILP (symbol_value_in_buffer (Qbefore_change_functions, buffer)) |
820 /* Obsolete, for compatibility */ | |
821 || !NILP (symbol_value_in_buffer (Qbefore_change_function, buffer))) | |
822 { | |
823 set_buffer_internal (buf); | |
853 | 824 va_run_hook_with_args_trapping_problems |
1333 | 825 (Qchange, Qbefore_change_functions, 2, |
853 | 826 make_int (start), make_int (end), |
827 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); | |
428 | 828 /* Obsolete, for compatibility */ |
853 | 829 va_run_hook_with_args_trapping_problems |
1333 | 830 (Qchange, Qbefore_change_function, 2, |
853 | 831 make_int (start), make_int (end), |
832 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); | |
428 | 833 } |
834 } | |
835 | |
438 | 836 /* Make sure endpoints remain valid. before-change-functions |
837 might have modified the buffer. */ | |
838 if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf); | |
839 if (start > BUF_ZV (buf)) start = BUF_ZV (buf); | |
840 if (end < BUF_BEGV (buf)) end = BUF_BEGV (buf); | |
841 if (end > BUF_ZV (buf)) end = BUF_ZV (buf); | |
842 | |
428 | 843 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
844 { | |
826 | 845 report_extent_modification (wrap_buffer (mbuf), start, end, 0); |
428 | 846 } |
771 | 847 unbind_to (speccount); |
428 | 848 |
849 /* Only now do we indicate that the before-change-functions have | |
850 been called, in case some function throws out. */ | |
851 buf->text->changes->mc_begin_signaled = 1; | |
852 } | |
853 } | |
854 | |
855 /* Signal a change immediately after it happens. | |
665 | 856 START is the charbpos of the start of the changed text. |
857 ORIG_END is the charbpos of the end of the before-changed text. | |
858 NEW_END is the charbpos of the end of the after-changed text. | |
428 | 859 */ |
860 | |
861 static void | |
665 | 862 signal_after_change (struct buffer *buf, Charbpos start, Charbpos orig_end, |
863 Charbpos new_end) | |
428 | 864 { |
865 /* This function can GC */ | |
866 struct buffer *mbuf; | |
867 Lisp_Object bufcons; | |
868 | |
869 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
870 { | |
871 /* always do this. */ | |
872 buffer_signal_changed_region (mbuf, start, new_end); | |
873 } | |
826 | 874 #ifdef USE_C_FONT_LOCK |
428 | 875 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
876 { | |
877 /* #### This seems inefficient. Wouldn't it be better to just | |
878 keep one cache per base buffer? */ | |
879 font_lock_maybe_update_syntactic_caches (mbuf, start, orig_end, new_end); | |
880 } | |
826 | 881 #endif /* USE_C_FONT_LOCK */ |
428 | 882 |
883 if (!inside_change_hook) | |
884 { | |
885 Lisp_Object buffer; | |
438 | 886 int speccount; |
428 | 887 |
888 if (buf->text->changes->in_multiple_change && | |
889 buf->text->changes->mc_begin != 0) | |
890 { | |
891 assert (start >= buf->text->changes->mc_begin && | |
892 start <= buf->text->changes->mc_new_end); | |
893 assert (orig_end >= buf->text->changes->mc_begin && | |
894 orig_end <= buf->text->changes->mc_new_end); | |
895 buf->text->changes->mc_new_end += new_end - orig_end; | |
896 return; /* after-change-functions signalled when all changes done */ | |
897 } | |
898 | |
438 | 899 speccount = specpdl_depth (); |
900 record_unwind_protect (change_function_restore, Fcurrent_buffer ()); | |
901 inside_change_hook = 1; | |
428 | 902 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
903 { | |
793 | 904 buffer = wrap_buffer (mbuf); |
428 | 905 |
906 if (!NILP (symbol_value_in_buffer (Qafter_change_functions, buffer)) | |
907 /* Obsolete, for compatibility */ | |
908 || !NILP (symbol_value_in_buffer (Qafter_change_function, buffer))) | |
909 { | |
910 set_buffer_internal (buf); | |
911 /* The actual after-change functions take slightly | |
912 different arguments than what we were passed. */ | |
853 | 913 va_run_hook_with_args_trapping_problems |
1333 | 914 (Qchange, Qafter_change_functions, 3, |
853 | 915 make_int (start), make_int (new_end), |
916 make_int (orig_end - start), | |
917 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); | |
428 | 918 /* Obsolete, for compatibility */ |
853 | 919 va_run_hook_with_args_trapping_problems |
1333 | 920 (Qchange, Qafter_change_function, 3, |
853 | 921 make_int (start), make_int (new_end), |
922 make_int (orig_end - start), | |
923 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); | |
428 | 924 } |
925 } | |
926 | |
438 | 927 /* Make sure endpoints remain valid. after-change-functions |
928 might have modified the buffer. */ | |
929 if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf); | |
930 if (start > BUF_ZV (buf)) start = BUF_ZV (buf); | |
931 if (new_end < BUF_BEGV (buf)) new_end = BUF_BEGV (buf); | |
932 if (new_end > BUF_ZV (buf)) new_end = BUF_ZV (buf); | |
933 if (orig_end < BUF_BEGV (buf)) orig_end = BUF_BEGV (buf); | |
934 if (orig_end > BUF_ZV (buf)) orig_end = BUF_ZV (buf); | |
935 | |
428 | 936 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
937 { | |
793 | 938 buffer = wrap_buffer (mbuf); |
438 | 939 report_extent_modification (buffer, start, new_end, 1); |
428 | 940 } |
771 | 941 unbind_to (speccount); /* sets inside_change_hook back to 0 */ |
428 | 942 } |
943 } | |
944 | |
945 /* Call this if you're about to change the region of BUFFER from START | |
946 to END. This checks the read-only properties of the region, calls | |
947 the necessary modification hooks, and warns the next redisplay that | |
948 it should pay attention to that area. */ | |
949 | |
950 static void | |
665 | 951 prepare_to_modify_buffer (struct buffer *buf, Charbpos start, Charbpos end, |
428 | 952 int lockit) |
953 { | |
954 /* This function can GC */ | |
955 /* dmoore - This function can also kill the buffer buf, the current | |
956 buffer, and do anything it pleases. So if you call it, be | |
957 careful. */ | |
958 struct buffer *mbuf; | |
959 Lisp_Object buffer, bufcons; | |
960 struct gcpro gcpro1; | |
961 | |
962 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
963 { | |
853 | 964 check_allowed_operation (OPERATION_MODIFY_BUFFER_TEXT, |
965 wrap_buffer (mbuf), Qnil); | |
428 | 966 barf_if_buffer_read_only (mbuf, start, end); |
967 } | |
968 | |
969 /* if this is the first modification, see about locking the buffer's | |
970 file */ | |
793 | 971 buffer = wrap_buffer (buf); |
428 | 972 GCPRO1 (buffer); |
973 if (!NILP (buf->filename) && lockit && | |
974 BUF_SAVE_MODIFF (buf) >= BUF_MODIFF (buf)) | |
975 { | |
758 | 976 #ifdef CLASH_DETECTION |
977 if (!NILP (buf->file_truename)) | |
978 /* Make binding buffer-file-name to nil effective. */ | |
979 lock_file (buf->file_truename); | |
980 #else | |
428 | 981 /* At least warn if this file has changed on disk since it was visited.*/ |
982 if (NILP (Fverify_visited_file_modtime (buffer)) | |
983 && !NILP (Ffile_exists_p (buf->filename))) | |
984 call1_in_buffer (buf, intern ("ask-user-about-supersession-threat"), | |
985 buf->filename); | |
986 #endif /* not CLASH_DETECTION */ | |
987 } | |
988 UNGCPRO; | |
989 | |
990 /* #### dmoore - is this reasonable in case of buf being killed above? */ | |
991 if (!BUFFER_LIVE_P (buf)) | |
992 return; | |
993 | |
994 signal_before_change (buf, start, end); | |
995 | |
996 #ifdef REGION_CACHE_NEEDS_WORK | |
997 if (buf->newline_cache) | |
998 invalidate_region_cache (buf, | |
999 buf->newline_cache, | |
1000 start - BUF_BEG (buf), BUF_Z (buf) - end); | |
1001 if (buf->width_run_cache) | |
1002 invalidate_region_cache (buf, | |
1003 buf->width_run_cache, | |
1004 start - BUF_BEG (buf), BUF_Z (buf) - end); | |
1005 #endif | |
1006 | |
1007 #if 0 /* FSFmacs */ | |
1008 Vdeactivate_mark = Qt; | |
1009 #endif | |
1010 | |
1011 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1012 { | |
1013 mbuf->point_before_scroll = Qnil; | |
1014 } | |
1015 } | |
1016 | |
1017 | |
1018 /************************************************************************/ | |
1019 /* Insertion of strings */ | |
1020 /************************************************************************/ | |
1021 | |
1022 void | |
867 | 1023 fixup_internal_substring (const Ibyte *nonreloc, Lisp_Object reloc, |
428 | 1024 Bytecount offset, Bytecount *len) |
1025 { | |
1026 assert ((nonreloc && NILP (reloc)) || (!nonreloc && STRINGP (reloc))); | |
1027 | |
1028 if (*len < 0) | |
1029 { | |
1030 if (nonreloc) | |
442 | 1031 *len = strlen ((const char *) nonreloc) - offset; |
428 | 1032 else |
1033 *len = XSTRING_LENGTH (reloc) - offset; | |
1034 } | |
800 | 1035 #ifdef ERROR_CHECK_TEXT |
428 | 1036 assert (*len >= 0); |
1037 if (STRINGP (reloc)) | |
1038 { | |
1039 assert (offset >= 0 && offset <= XSTRING_LENGTH (reloc)); | |
1040 assert (offset + *len <= XSTRING_LENGTH (reloc)); | |
1041 } | |
1042 #endif | |
1043 } | |
1044 | |
665 | 1045 /* Insert a string into BUF at Charbpos POS. The string data comes |
428 | 1046 from one of two sources: constant, non-relocatable data (specified |
1047 in NONRELOC), or a Lisp string object (specified in RELOC), which | |
1048 is relocatable and may have extent data that needs to be copied | |
1049 into the buffer. OFFSET and LENGTH specify the substring of the | |
1050 data that is actually to be inserted. As a special case, if POS | |
1051 is -1, insert the string at point and move point to the end of the | |
1052 string. | |
1053 | |
1054 Normally, markers at the insertion point end up before the | |
1055 inserted string. If INSDEL_BEFORE_MARKERS is set in flags, however, | |
1056 they end up after the string. | |
1057 | |
1058 INSDEL_NO_LOCKING is kludgy and is used when insert-file-contents is | |
1059 visiting a new file; it inhibits the locking checks normally done | |
1060 before modifying a buffer. Similar checks were already done | |
1061 in the higher-level Lisp functions calling insert-file-contents. */ | |
1062 | |
1063 Charcount | |
665 | 1064 buffer_insert_string_1 (struct buffer *buf, Charbpos pos, |
867 | 1065 const Ibyte *nonreloc, Lisp_Object reloc, |
428 | 1066 Bytecount offset, Bytecount length, |
1067 int flags) | |
1068 { | |
1069 /* This function can GC */ | |
1070 struct gcpro gcpro1; | |
826 | 1071 Bytebpos bytepos; |
1072 Bytecount length_in_buffer; | |
428 | 1073 Charcount cclen; |
1074 int move_point = 0; | |
1075 struct buffer *mbuf; | |
1076 Lisp_Object bufcons; | |
1077 | |
1078 /* Defensive steps just in case a buffer gets deleted and a calling | |
1079 function doesn't notice it. */ | |
1080 if (!BUFFER_LIVE_P (buf)) | |
1081 return 0; | |
1082 | |
1083 fixup_internal_substring (nonreloc, reloc, offset, &length); | |
1084 | |
1085 if (pos == -1) | |
1086 { | |
1087 pos = BUF_PT (buf); | |
1088 move_point = 1; | |
1089 } | |
1090 | |
1091 #ifdef I18N3 | |
1092 /* #### See the comment in print_internal(). If this buffer is marked | |
1093 as translatable, then Fgettext() should be called on obj if it | |
1094 is a string. */ | |
1095 #endif | |
1096 | |
1097 /* Make sure that point-max won't exceed the size of an emacs int. */ | |
1098 if ((length + BUF_Z (buf)) > EMACS_INT_MAX) | |
563 | 1099 out_of_memory ("Maximum buffer size exceeded", Qunbound); |
428 | 1100 |
1101 /* theoretically not necessary -- caller should GCPRO. | |
1102 #### buffer_insert_from_buffer_1() doesn't! */ | |
1103 GCPRO1 (reloc); | |
1104 | |
1105 prepare_to_modify_buffer (buf, pos, pos, !(flags & INSDEL_NO_LOCKING)); | |
1106 | |
1107 /* Defensive steps in case the before-change-functions fuck around */ | |
1108 if (!BUFFER_LIVE_P (buf)) | |
1109 { | |
1110 UNGCPRO; | |
1111 /* Bad bad pre-change function. */ | |
1112 return 0; | |
1113 } | |
1114 | |
1115 /* Make args be valid again. prepare_to_modify_buffer() might have | |
1116 modified the buffer. */ | |
1117 if (pos < BUF_BEGV (buf)) | |
1118 pos = BUF_BEGV (buf); | |
1119 if (pos > BUF_ZV (buf)) | |
1120 pos = BUF_ZV (buf); | |
1121 | |
826 | 1122 bytepos = charbpos_to_bytebpos (buf, pos); |
771 | 1123 |
428 | 1124 /* string may have been relocated up to this point */ |
1125 if (STRINGP (reloc)) | |
771 | 1126 { |
793 | 1127 cclen = string_offset_byte_to_char_len (reloc, offset, length); |
771 | 1128 nonreloc = XSTRING_DATA (reloc); |
1129 } | |
1130 else | |
1131 cclen = bytecount_to_charcount (nonreloc + offset, length); | |
826 | 1132 /* &&#### Here we check if the text can't fit into the format of the buffer, |
1133 and if so convert it to another format (either default or 32-bit-fixed, | |
1134 according to some flag; if no flag, use default). */ | |
1135 | |
1136 length_in_buffer = copy_text_between_formats (nonreloc + offset, length, | |
1137 FORMAT_DEFAULT, | |
1138 STRINGP (reloc) ? reloc : Qnil, | |
1139 NULL, 0, | |
1140 BUF_FORMAT (buf), | |
1141 wrap_buffer (buf), | |
1142 NULL); | |
428 | 1143 |
826 | 1144 if (bytepos != BYTE_BUF_GPT (buf)) |
428 | 1145 /* #### if debug-on-quit is invoked and the user changes the |
1146 buffer, bad things can happen. This is a rampant problem | |
1147 in Emacs. */ | |
2367 | 1148 move_gap (buf, pos, bytepos); /* may QUIT */ |
826 | 1149 if (! GAP_CAN_HOLD_SIZE_P (buf, length_in_buffer)) |
428 | 1150 { |
826 | 1151 if (BUF_END_GAP_SIZE (buf) >= length_in_buffer) |
428 | 1152 merge_gap_with_end_gap (buf); |
1153 else | |
826 | 1154 make_gap (buf, length_in_buffer - BUF_GAP_SIZE (buf)); |
428 | 1155 } |
1156 | |
826 | 1157 /* At this point, no more QUITting or processing of Lisp code. Buffer is |
1158 in a consistent state. Following code puts buffer in an inconsistent | |
1159 state and can be considered a "critical section". */ | |
1160 | |
428 | 1161 insert_invalidate_line_number_cache (buf, pos, nonreloc + offset, length); |
1162 | |
1163 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1164 { | |
1165 record_insert (mbuf, pos, cclen); | |
1166 } | |
1167 | |
1168 BUF_MODIFF (buf)++; | |
1169 MARK_BUFFERS_CHANGED; | |
1170 | |
826 | 1171 /* string may have been relocated up to this point #### if string is |
1172 modified during quit processing, bad things can happen. */ | |
428 | 1173 if (STRINGP (reloc)) |
1174 nonreloc = XSTRING_DATA (reloc); | |
1175 | |
853 | 1176 memcpy (BUF_GPT_ADDR (buf), nonreloc + offset, length); |
1177 | |
826 | 1178 copy_text_between_formats (nonreloc + offset, length, FORMAT_DEFAULT, |
1179 STRINGP (reloc) ? reloc : Qnil, | |
1180 BUF_GPT_ADDR (buf), length_in_buffer, | |
1181 BUF_FORMAT (buf), wrap_buffer (buf), NULL); | |
1182 | |
1183 SET_BUF_GAP_SIZE (buf, BUF_GAP_SIZE (buf) - length_in_buffer); | |
2367 | 1184 SET_BOTH_BUF_GPT (buf, BUF_GPT (buf) + cclen, |
1185 BYTE_BUF_GPT (buf) + length_in_buffer); | |
428 | 1186 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
1187 { | |
826 | 1188 SET_BOTH_BUF_ZV (mbuf, BUF_ZV (mbuf) + cclen, |
1189 BYTE_BUF_ZV (mbuf) + length_in_buffer); | |
428 | 1190 } |
826 | 1191 SET_BOTH_BUF_Z (buf, BUF_Z (buf) + cclen, BYTE_BUF_Z (buf) + length_in_buffer); |
428 | 1192 SET_GAP_SENTINEL (buf); |
771 | 1193 |
1194 | |
428 | 1195 #ifdef MULE |
826 | 1196 buffer_mule_signal_inserted_region (buf, pos, length_in_buffer, cclen); |
1197 /* Update our count of ASCII, 8-bit and 16-bit chars and the | |
1198 entirely-one-byte flag */ | |
1199 { | |
867 | 1200 const Ibyte *ptr = nonreloc + offset; |
1201 const Ibyte *ptrend = ptr + length; | |
826 | 1202 |
1203 while (ptr < ptrend) | |
1204 { | |
867 | 1205 Ichar ch = itext_ichar (ptr); |
1206 if (ichar_ascii_p (ch)) | |
826 | 1207 buf->text->num_ascii_chars++; |
867 | 1208 if (ichar_8_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1209 buf->text->num_8_bit_fixed_chars++; |
867 | 1210 if (ichar_16_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1211 buf->text->num_16_bit_fixed_chars++; |
867 | 1212 INC_IBYTEPTR (ptr); |
826 | 1213 } |
1214 | |
1215 buf->text->entirely_one_byte_p = | |
1216 (BUF_FORMAT (buf) == FORMAT_8_BIT_FIXED || | |
1217 (BUF_FORMAT (buf) == FORMAT_DEFAULT && BUF_Z (buf) == BYTE_BUF_Z (buf))); | |
1218 } | |
428 | 1219 #endif |
1220 | |
1221 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1222 { | |
826 | 1223 process_extents_for_insertion (wrap_buffer (mbuf), bytepos, |
1224 length_in_buffer); | |
428 | 1225 } |
1226 | |
1227 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1228 { | |
826 | 1229 /* We know the gap is at BYTEPOS so the cast is OK. */ |
1230 adjust_markers_for_insert (mbuf, (Membpos) bytepos, length_in_buffer); | |
428 | 1231 } |
1232 | |
1233 /* Point logically doesn't move, but may need to be adjusted because | |
1234 it's a byte index. point-marker doesn't change because it's a | |
1235 memory index. */ | |
1236 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1237 { | |
826 | 1238 if (BYTE_BUF_PT (mbuf) > bytepos) |
428 | 1239 JUST_SET_POINT (mbuf, BUF_PT (mbuf) + cclen, |
826 | 1240 BYTE_BUF_PT (mbuf) + length_in_buffer); |
428 | 1241 } |
1242 | |
1243 /* Well, point might move. */ | |
1244 if (move_point) | |
826 | 1245 BYTE_BUF_SET_PT (buf, bytepos + length_in_buffer); |
428 | 1246 |
1247 if (STRINGP (reloc)) | |
1248 { | |
1249 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1250 { | |
826 | 1251 splice_in_string_extents (reloc, mbuf, bytepos, length, offset); |
428 | 1252 } |
1253 } | |
1254 | |
1255 if (flags & INSDEL_BEFORE_MARKERS) | |
1256 { | |
1257 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1258 { | |
826 | 1259 /* bytepos - 1 is correct because the FROM argument is exclusive. |
665 | 1260 I formerly used DEC_BYTEBPOS() but that caused problems at the |
428 | 1261 beginning of the buffer. */ |
826 | 1262 adjust_markers (mbuf, bytepos - 1, bytepos, length_in_buffer); |
428 | 1263 } |
1264 } | |
1265 | |
826 | 1266 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
1267 { | |
3250 | 1268 signal_syntax_cache_extent_adjust (mbuf); |
826 | 1269 } |
1270 | |
428 | 1271 signal_after_change (buf, pos, pos, pos + cclen); |
1272 | |
1273 UNGCPRO; | |
1274 | |
1275 return cclen; | |
1276 } | |
1277 | |
1278 | |
1279 /* The following functions are interfaces onto the above function, | |
1280 for inserting particular sorts of data. In all the functions, | |
1281 BUF and POS specify the buffer and location where the insertion is | |
1282 to take place. (If POS is -1, text is inserted at point and point | |
1283 moves forward past the text.) FLAGS is as above. */ | |
1284 | |
1285 Charcount | |
665 | 1286 buffer_insert_raw_string_1 (struct buffer *buf, Charbpos pos, |
867 | 1287 const Ibyte *nonreloc, Bytecount length, |
428 | 1288 int flags) |
1289 { | |
1290 /* This function can GC */ | |
1291 return buffer_insert_string_1 (buf, pos, nonreloc, Qnil, 0, length, | |
1292 flags); | |
1293 } | |
1294 | |
1295 Charcount | |
665 | 1296 buffer_insert_lisp_string_1 (struct buffer *buf, Charbpos pos, Lisp_Object str, |
428 | 1297 int flags) |
1298 { | |
1299 /* This function can GC */ | |
1300 return buffer_insert_string_1 (buf, pos, 0, str, 0, | |
1301 XSTRING_LENGTH (str), | |
1302 flags); | |
1303 } | |
1304 | |
1305 /* Insert the null-terminated string S (in external format). */ | |
1306 | |
1307 Charcount | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
3250
diff
changeset
|
1308 buffer_insert_ascstring_1 (struct buffer *buf, Charbpos pos, const Ascbyte *s, |
428 | 1309 int flags) |
1310 { | |
1311 /* This function can GC */ | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
3250
diff
changeset
|
1312 const CIbyte *translated = GETTEXT (s); |
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
3250
diff
changeset
|
1313 ASSERT_ASCTEXT_ASCII (s); |
867 | 1314 return buffer_insert_string_1 (buf, pos, (const Ibyte *) translated, Qnil, |
428 | 1315 0, strlen (translated), flags); |
1316 } | |
1317 | |
1318 Charcount | |
867 | 1319 buffer_insert_emacs_char_1 (struct buffer *buf, Charbpos pos, Ichar ch, |
428 | 1320 int flags) |
1321 { | |
1322 /* This function can GC */ | |
867 | 1323 Ibyte str[MAX_ICHAR_LEN]; |
1324 Bytecount len = set_itext_ichar (str, ch); | |
428 | 1325 return buffer_insert_string_1 (buf, pos, str, Qnil, 0, len, flags); |
1326 } | |
1327 | |
1328 Charcount | |
665 | 1329 buffer_insert_c_char_1 (struct buffer *buf, Charbpos pos, char c, |
428 | 1330 int flags) |
1331 { | |
1332 /* This function can GC */ | |
867 | 1333 return buffer_insert_emacs_char_1 (buf, pos, (Ichar) (unsigned char) c, |
428 | 1334 flags); |
1335 } | |
1336 | |
1337 Charcount | |
665 | 1338 buffer_insert_from_buffer_1 (struct buffer *buf, Charbpos pos, |
1339 struct buffer *buf2, Charbpos pos2, | |
428 | 1340 Charcount length, int flags) |
1341 { | |
1342 /* This function can GC */ | |
1343 Lisp_Object str = make_string_from_buffer (buf2, pos2, length); | |
1344 return buffer_insert_string_1 (buf, pos, 0, str, 0, | |
1345 XSTRING_LENGTH (str), flags); | |
1346 } | |
1347 | |
1348 | |
1349 /************************************************************************/ | |
1350 /* Deletion of ranges */ | |
1351 /************************************************************************/ | |
1352 | |
1353 /* Delete characters in buffer from FROM up to (but not including) TO. */ | |
1354 | |
1355 void | |
665 | 1356 buffer_delete_range (struct buffer *buf, Charbpos from, Charbpos to, int flags) |
428 | 1357 { |
1358 /* This function can GC */ | |
1359 Charcount numdel; | |
826 | 1360 Bytebpos byte_from, byte_to; |
1361 Bytecount byte_numdel; | |
428 | 1362 EMACS_INT shortage; |
1363 struct buffer *mbuf; | |
1364 Lisp_Object bufcons; | |
826 | 1365 int do_move_gap = 0; |
428 | 1366 |
1367 /* Defensive steps just in case a buffer gets deleted and a calling | |
1368 function doesn't notice it. */ | |
1369 if (!BUFFER_LIVE_P (buf)) | |
1370 return; | |
1371 | |
1372 /* Make args be valid */ | |
1373 if (from < BUF_BEGV (buf)) | |
1374 from = BUF_BEGV (buf); | |
1375 if (to > BUF_ZV (buf)) | |
1376 to = BUF_ZV (buf); | |
1377 if ((numdel = to - from) <= 0) | |
1378 return; | |
1379 | |
1380 prepare_to_modify_buffer (buf, from, to, !(flags & INSDEL_NO_LOCKING)); | |
1381 | |
1382 /* Defensive steps in case the before-change-functions fuck around */ | |
1383 if (!BUFFER_LIVE_P (buf)) | |
1384 /* Bad bad pre-change function. */ | |
1385 return; | |
1386 | |
1387 /* Make args be valid again. prepare_to_modify_buffer() might have | |
1388 modified the buffer. */ | |
1389 if (from < BUF_BEGV (buf)) | |
1390 from = BUF_BEGV (buf); | |
1391 if (to > BUF_ZV (buf)) | |
1392 to = BUF_ZV (buf); | |
1393 if ((numdel = to - from) <= 0) | |
1394 return; | |
1395 | |
826 | 1396 byte_from = charbpos_to_bytebpos (buf, from); |
1397 byte_to = charbpos_to_bytebpos (buf, to); | |
1398 byte_numdel = byte_to - byte_from; | |
1399 | |
1400 if (to == BUF_Z (buf) && | |
1401 byte_from > BYTE_BUF_GPT (buf)) | |
1402 /* avoid moving the gap just to delete from the bottom. */ | |
1403 do_move_gap = 0; | |
1404 else | |
1405 { | |
1406 /* Make sure the gap is somewhere in or next to what we are deleting. */ | |
1407 /* NOTE: Can QUIT! */ | |
1408 if (byte_to < BYTE_BUF_GPT (buf)) | |
2367 | 1409 gap_left (buf, to, byte_to); |
826 | 1410 if (byte_from > BYTE_BUF_GPT (buf)) |
2367 | 1411 gap_right (buf, from, byte_from); |
826 | 1412 do_move_gap = 1; |
1413 } | |
1414 | |
1415 /* At this point, no more QUITting or processing of Lisp code. Buffer is | |
1416 in a consistent state. Following code puts buffer in an inconsistent | |
1417 state and can be considered a "critical section". */ | |
1418 | |
1419 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1420 { | |
1421 record_delete (mbuf, from, numdel); | |
1422 } | |
1423 BUF_MODIFF (buf)++; | |
1424 MARK_BUFFERS_CHANGED; | |
1425 | |
1426 /* We used to do the following before the gap move. But that might QUIT, | |
1427 and (as a result of this) the gap code always leaves the buffer in | |
1428 a consistent state. Therefore, it's totally safe to do these operations | |
1429 now, and just as well not before, as we're making state changes | |
1430 related to the deletion. */ | |
1431 | |
428 | 1432 /* Redisplay needs to know if a newline was in the deleted region. |
1433 If we've already marked the changed region as having a deleted | |
1434 newline there is no use in performing the check. */ | |
1435 if (!buf->changes->newline_was_deleted) | |
1436 { | |
1437 scan_buffer (buf, '\n', from, to, 1, &shortage, 1); | |
1438 if (!shortage) | |
1439 { | |
1440 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1441 { | |
1442 mbuf->changes->newline_was_deleted = 1; | |
1443 } | |
1444 } | |
1445 } | |
1446 | |
1447 delete_invalidate_line_number_cache (buf, from, to); | |
1448 | |
826 | 1449 #ifdef MULE |
1450 /* Update our count of ASCII, 8-bit and 16-bit chars and the | |
1451 entirely-one-byte flag */ | |
1452 { | |
1453 Bytebpos i; | |
428 | 1454 |
826 | 1455 for (i = byte_from; i < byte_to; i = next_bytebpos (buf, i)) |
1456 { | |
867 | 1457 Ichar ch = BYTE_BUF_FETCH_CHAR (buf, i); |
1458 if (ichar_ascii_p (ch)) | |
826 | 1459 buf->text->num_ascii_chars--; |
867 | 1460 if (ichar_8_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1461 buf->text->num_8_bit_fixed_chars--; |
867 | 1462 if (ichar_16_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1463 buf->text->num_16_bit_fixed_chars--; |
1464 } | |
1465 } | |
1466 #endif /* MULE */ | |
428 | 1467 |
826 | 1468 /* #### Point used to be modified here, but this causes problems |
1469 with MULE, as point is used to calculate bytebpos's, and if the | |
1470 offset in byte_numdel causes point to move to a non first-byte | |
1471 location, causing some other function to throw an assertion | |
1472 in ASSERT_VALID_BYTEBPOS. I've moved the code to right after | |
1473 the other movements and adjustments, but before the gap is | |
1474 moved. -- jh 970813 */ | |
428 | 1475 |
826 | 1476 /* Detach any extents that are completely within the range [FROM, TO], |
1477 if the extents are detachable. | |
1478 | |
1479 This must come AFTER record_delete(), so that the appropriate extents | |
1480 will be present to be recorded, and BEFORE the gap size is increased, | |
1481 as otherwise we will be confused about where the extents end. */ | |
1482 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1483 { | |
1484 process_extents_for_deletion (wrap_buffer (mbuf), byte_from, byte_to, 0); | |
428 | 1485 } |
1486 | |
826 | 1487 /* Relocate all markers pointing into the new, larger gap to |
1488 point at the end of the text before the gap. */ | |
1489 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1490 { | |
1491 adjust_markers (mbuf, | |
1492 (byte_to + BUF_GAP_SIZE (mbuf)), | |
1493 (byte_to + BUF_GAP_SIZE (mbuf)), | |
1494 (- byte_numdel - | |
1495 (do_move_gap ? BUF_GAP_SIZE (mbuf) : 0))); | |
1496 } | |
1497 | |
1498 /* Relocate any extent endpoints just like markers. */ | |
1499 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1500 { | |
1501 adjust_extents_for_deletion (wrap_buffer (mbuf), byte_from, byte_to, | |
1502 BUF_GAP_SIZE (mbuf), | |
1503 byte_numdel, | |
1504 do_move_gap ? BUF_GAP_SIZE (mbuf) : 0); | |
1505 } | |
1506 | |
1507 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1508 { | |
1509 /* Relocate point as if it were a marker. */ | |
1510 if (byte_from < BYTE_BUF_PT (mbuf)) | |
1511 { | |
1512 if (BYTE_BUF_PT (mbuf) < byte_to) | |
1513 JUST_SET_POINT (mbuf, from, byte_from); | |
1514 else | |
1515 JUST_SET_POINT (mbuf, BUF_PT (mbuf) - numdel, | |
1516 BYTE_BUF_PT (mbuf) - byte_numdel); | |
1517 } | |
1518 } | |
1519 | |
1520 if (do_move_gap) | |
1521 SET_BUF_GAP_SIZE (buf, BUF_GAP_SIZE (buf) + byte_numdel); | |
1522 else | |
1523 SET_BUF_END_GAP_SIZE (buf, BUF_END_GAP_SIZE (buf) + byte_numdel); | |
1524 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1525 { | |
1526 SET_BOTH_BUF_ZV (mbuf, BUF_ZV (mbuf) - numdel, | |
1527 BYTE_BUF_ZV (mbuf) - byte_numdel); | |
1528 } | |
1529 SET_BOTH_BUF_Z (buf, BUF_Z (buf) - numdel, BYTE_BUF_Z (buf) - byte_numdel); | |
1530 if (do_move_gap) | |
2367 | 1531 SET_BOTH_BUF_GPT (buf, from, byte_from); |
826 | 1532 SET_GAP_SENTINEL (buf); |
1533 | |
428 | 1534 #ifdef MULE |
826 | 1535 buffer_mule_signal_deleted_region (buf, from, to, byte_from, byte_to); |
1536 buf->text->entirely_one_byte_p = | |
1537 (BUF_FORMAT (buf) == FORMAT_8_BIT_FIXED || | |
1538 (BUF_FORMAT (buf) == FORMAT_DEFAULT && BUF_Z (buf) == BYTE_BUF_Z (buf))); | |
428 | 1539 #endif |
1540 | |
1541 #ifdef ERROR_CHECK_EXTENTS | |
1542 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1543 { | |
771 | 1544 sledgehammer_extent_check (wrap_buffer (mbuf)); |
428 | 1545 } |
1546 #endif | |
1547 | |
826 | 1548 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) |
1549 { | |
3250 | 1550 signal_syntax_cache_extent_adjust (mbuf); |
826 | 1551 } |
1552 | |
1553 /* &&#### Here we consider converting the buffer from default to | |
1554 8-bit-fixed if is entirely 8-bit-fixed chars and has been that way for | |
1555 a long time, e.g. 20 minutes. And if the buffer just switched to all | |
1556 8-bit-fixed chars, start the timer. */ | |
428 | 1557 signal_after_change (buf, from, to, from); |
1558 } | |
1559 | |
1560 | |
1561 /************************************************************************/ | |
1562 /* Replacement of characters */ | |
1563 /************************************************************************/ | |
1564 | |
1565 /* Replace the character at POS in buffer B with CH. */ | |
1566 | |
1567 void | |
867 | 1568 buffer_replace_char (struct buffer *buf, Charbpos pos, Ichar ch, |
428 | 1569 int not_real_change, int force_lock_check) |
1570 { | |
1571 /* This function can GC */ | |
867 | 1572 Ibyte newstr[MAX_ICHAR_LEN]; |
826 | 1573 Bytecount newlen; |
867 | 1574 Ichar oldch; |
428 | 1575 |
1576 /* Defensive steps just in case a buffer gets deleted and a calling | |
1577 function doesn't notice it. */ | |
1578 if (!BUFFER_LIVE_P (buf)) | |
1579 return; | |
1580 | |
867 | 1581 newlen = set_itext_ichar_fmt (newstr, ch, BUF_FORMAT (buf), |
826 | 1582 wrap_buffer (buf)); |
1583 oldch = BUF_FETCH_CHAR (buf, pos); | |
867 | 1584 if (ichar_fits_in_format (ch, BUF_FORMAT (buf), wrap_buffer (buf)) && |
1585 newlen == ichar_len_fmt (oldch, BUF_FORMAT (buf))) | |
428 | 1586 { |
1587 struct buffer *mbuf; | |
1588 Lisp_Object bufcons; | |
1589 | |
1590 /* then we can just replace the text. */ | |
1591 prepare_to_modify_buffer (buf, pos, pos + 1, | |
1592 !not_real_change || force_lock_check); | |
1593 /* Defensive steps in case the before-change-functions fuck around */ | |
1594 if (!BUFFER_LIVE_P (buf)) | |
1595 /* Bad bad pre-change function. */ | |
1596 return; | |
1597 | |
1598 /* Make args be valid again. prepare_to_modify_buffer() might have | |
1599 modified the buffer. */ | |
1600 if (pos < BUF_BEGV (buf)) | |
1601 pos = BUF_BEGV (buf); | |
1602 if (pos >= BUF_ZV (buf)) | |
1603 pos = BUF_ZV (buf) - 1; | |
1604 if (pos < BUF_BEGV (buf)) | |
1605 /* no more characters in buffer! */ | |
1606 return; | |
1607 | |
1608 if (BUF_FETCH_CHAR (buf, pos) == '\n') | |
1609 { | |
1610 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1611 { | |
1612 mbuf->changes->newline_was_deleted = 1; | |
1613 } | |
1614 } | |
1615 MARK_BUFFERS_CHANGED; | |
1616 if (!not_real_change) | |
1617 { | |
1618 MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons) | |
1619 { | |
1620 record_change (mbuf, pos, 1); | |
1621 } | |
1622 BUF_MODIFF (buf)++; | |
1623 } | |
826 | 1624 |
1625 #ifdef MULE | |
867 | 1626 if (ichar_ascii_p (oldch)) |
826 | 1627 buf->text->num_ascii_chars--; |
867 | 1628 if (ichar_8_bit_fixed_p (oldch, wrap_buffer (buf))) |
826 | 1629 buf->text->num_8_bit_fixed_chars--; |
867 | 1630 if (ichar_16_bit_fixed_p (oldch, wrap_buffer (buf))) |
826 | 1631 buf->text->num_16_bit_fixed_chars--; |
867 | 1632 if (ichar_ascii_p (ch)) |
826 | 1633 buf->text->num_ascii_chars++; |
867 | 1634 if (ichar_8_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1635 buf->text->num_8_bit_fixed_chars++; |
867 | 1636 if (ichar_16_bit_fixed_p (ch, wrap_buffer (buf))) |
826 | 1637 buf->text->num_16_bit_fixed_chars++; |
1638 #endif /* MULE */ | |
1639 | |
428 | 1640 memcpy (BUF_BYTE_ADDRESS (buf, pos), newstr, newlen); |
1641 | |
1642 signal_after_change (buf, pos, pos + 1, pos + 1); | |
1643 | |
1644 /* We do not have to adjust the Mule data; we just replaced a | |
1645 character with another of the same number of bytes. */ | |
1646 } | |
1647 else | |
1648 { | |
1649 /* | |
1650 * Must implement as deletion followed by insertion. | |
1651 * | |
1652 * Make a note to move point forward later in the one situation | |
1653 * where it is needed, a delete/insert one position behind | |
1654 * point. Point will drift backward by one position and stay | |
1655 * there otherwise. | |
1656 */ | |
1657 int movepoint = (pos == BUF_PT (buf) - 1); | |
1658 | |
1659 buffer_delete_range (buf, pos, pos + 1, 0); | |
1660 /* Defensive steps in case the before-change-functions fuck around */ | |
1661 if (!BUFFER_LIVE_P (buf)) | |
1662 /* Bad bad pre-change function. */ | |
1663 return; | |
1664 | |
1665 /* Make args be valid again. prepare_to_modify_buffer() might have | |
1666 modified the buffer. */ | |
1667 if (pos < BUF_BEGV (buf)) | |
1668 pos = BUF_BEGV (buf); | |
1669 if (pos >= BUF_ZV (buf)) | |
1670 pos = BUF_ZV (buf) - 1; | |
1671 if (pos < BUF_BEGV (buf)) | |
1672 /* no more characters in buffer! */ | |
1673 return; | |
1674 /* | |
1675 * -1 as the pos argument means to move point forward with the | |
1676 * insertion, which we must do if the deletion moved point | |
1677 * backward so that it now equals the insertion point. | |
1678 */ | |
1679 buffer_insert_string_1 (buf, (movepoint ? -1 : pos), | |
1680 newstr, Qnil, 0, newlen, 0); | |
1681 } | |
1682 } | |
1683 | |
1684 | |
1685 /************************************************************************/ | |
1686 /* Other functions */ | |
1687 /************************************************************************/ | |
1688 | |
1689 /* Make a string from a buffer. This needs to take into account the gap, | |
1690 and add any necessary extents from the buffer. */ | |
1691 | |
1692 static Lisp_Object | |
665 | 1693 make_string_from_buffer_1 (struct buffer *buf, Charbpos pos, Charcount length, |
428 | 1694 int no_extents) |
1695 { | |
1696 /* This function can GC */ | |
826 | 1697 Bytebpos bytepos = charbpos_to_bytebpos (buf, pos); |
1698 Bytecount bytelen = charbpos_to_bytebpos (buf, pos + length) - bytepos; | |
1699 Bytecount needed = copy_buffer_text_out (buf, bytepos, bytelen, NULL, 0, | |
1700 FORMAT_DEFAULT, Qnil, NULL); | |
1701 Lisp_Object val = make_uninit_string (needed); | |
428 | 1702 |
1703 struct gcpro gcpro1; | |
1704 GCPRO1 (val); | |
1705 | |
1706 if (!no_extents) | |
826 | 1707 add_string_extents (val, buf, bytepos, bytelen); |
1708 copy_buffer_text_out (buf, bytepos, bytelen, XSTRING_DATA (val), needed, | |
1709 FORMAT_DEFAULT, Qnil, NULL); | |
771 | 1710 init_string_ascii_begin (val); |
1711 sledgehammer_check_ascii_begin (val); | |
1712 | |
428 | 1713 UNGCPRO; |
1714 return val; | |
1715 } | |
1716 | |
1717 Lisp_Object | |
665 | 1718 make_string_from_buffer (struct buffer *buf, Charbpos pos, Charcount length) |
428 | 1719 { |
1720 return make_string_from_buffer_1 (buf, pos, length, 0); | |
1721 } | |
1722 | |
1723 Lisp_Object | |
665 | 1724 make_string_from_buffer_no_extents (struct buffer *buf, Charbpos pos, |
428 | 1725 Charcount length) |
1726 { | |
1727 return make_string_from_buffer_1 (buf, pos, length, 1); | |
1728 } | |
1729 | |
1730 void | |
665 | 1731 barf_if_buffer_read_only (struct buffer *buf, Charbpos from, Charbpos to) |
428 | 1732 { |
1733 Lisp_Object buffer; | |
1734 Lisp_Object iro; | |
1735 | |
793 | 1736 buffer = wrap_buffer (buf); |
428 | 1737 back: |
1738 iro = (buf == current_buffer ? Vinhibit_read_only : | |
1739 symbol_value_in_buffer (Qinhibit_read_only, buffer)); | |
1740 if (!LISTP (iro)) | |
1741 return; | |
1742 if (NILP (iro) && !NILP (buf->read_only)) | |
1743 { | |
1744 Fsignal (Qbuffer_read_only, (list1 (buffer))); | |
1745 goto back; | |
1746 } | |
1747 if (from > 0) | |
1748 { | |
1749 if (to < 0) | |
1750 to = from; | |
1751 verify_extent_modification (buffer, | |
665 | 1752 charbpos_to_bytebpos (buf, from), |
1753 charbpos_to_bytebpos (buf, to), | |
428 | 1754 iro); |
1755 } | |
1756 } | |
1757 | |
1758 | |
1759 /************************************************************************/ | |
1760 /* initialization */ | |
1761 /************************************************************************/ | |
1762 | |
1763 void | |
1764 reinit_vars_of_insdel (void) | |
1765 { | |
1766 inside_change_hook = 0; | |
1767 in_first_change = 0; | |
1768 } | |
1769 | |
1770 void | |
1771 vars_of_insdel (void) | |
1772 { | |
1773 } | |
1774 | |
1775 void | |
1776 init_buffer_text (struct buffer *b) | |
1777 { | |
1778 if (!b->base_buffer) | |
1779 { | |
1780 SET_BUF_GAP_SIZE (b, 20); | |
1781 BUFFER_ALLOC (b->text->beg, BUF_GAP_SIZE (b) + BUF_END_SENTINEL_SIZE); | |
1782 if (! BUF_BEG_ADDR (b)) | |
1783 memory_full (); | |
1784 | |
1785 SET_BUF_END_GAP_SIZE (b, 0); | |
2367 | 1786 SET_BOTH_BUF_GPT (b, 1, 1); |
428 | 1787 SET_BOTH_BUF_Z (b, 1, 1); |
1788 SET_GAP_SENTINEL (b); | |
1789 SET_END_SENTINEL (b); | |
2367 | 1790 |
428 | 1791 #ifdef MULE |
2367 | 1792 b->text->entirely_one_byte_p = 1; |
428 | 1793 |
2367 | 1794 #ifdef OLD_BYTE_CHAR |
1795 b->text->mule_bufmin = b->text->mule_bufmax = 1; | |
1796 b->text->mule_bytmin = b->text->mule_bytmax = 1; | |
1797 #endif | |
428 | 1798 |
2367 | 1799 b->text->cached_charpos = 1; |
1800 b->text->cached_bytepos = 1; | |
1801 | |
826 | 1802 /* &&#### Set to FORMAT_8_BIT_FIXED when that code is working */ |
1803 BUF_FORMAT (b) = FORMAT_DEFAULT; | |
428 | 1804 #endif /* MULE */ |
1805 b->text->line_number_cache = Qnil; | |
1806 | |
1807 BUF_MODIFF (b) = 1; | |
1808 BUF_SAVE_MODIFF (b) = 1; | |
1809 | |
1810 JUST_SET_POINT (b, 1, 1); | |
1811 SET_BOTH_BUF_BEGV (b, 1, 1); | |
1812 SET_BOTH_BUF_ZV (b, 1, 1); | |
1813 | |
1814 b->text->changes = xnew_and_zero (struct buffer_text_change_data); | |
1815 } | |
1816 else | |
1817 { | |
826 | 1818 JUST_SET_POINT (b, BUF_PT (b->base_buffer), BYTE_BUF_PT (b->base_buffer)); |
428 | 1819 SET_BOTH_BUF_BEGV (b, BUF_BEGV (b->base_buffer), |
826 | 1820 BYTE_BUF_BEGV (b->base_buffer)); |
428 | 1821 SET_BOTH_BUF_ZV (b, BUF_ZV (b->base_buffer), |
826 | 1822 BYTE_BUF_ZV (b->base_buffer)); |
428 | 1823 } |
1824 | |
1825 b->changes = xnew_and_zero (struct each_buffer_change_data); | |
1826 BUF_FACECHANGE (b) = 1; | |
1827 | |
1828 #ifdef REGION_CACHE_NEEDS_WORK | |
1829 b->newline_cache = 0; | |
1830 b->width_run_cache = 0; | |
1831 b->width_table = Qnil; | |
1832 #endif | |
1833 } | |
1834 | |
1835 void | |
1836 uninit_buffer_text (struct buffer *b) | |
1837 { | |
1838 if (!b->base_buffer) | |
1839 { | |
1840 BUFFER_FREE (b->text->beg); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1841 xfree (b->text->changes); |
428 | 1842 } |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1843 xfree (b->changes); |
428 | 1844 |
1845 #ifdef REGION_CACHE_NEEDS_WORK | |
1846 if (b->newline_cache) | |
1847 { | |
1848 free_region_cache (b->newline_cache); | |
1849 b->newline_cache = 0; | |
1850 } | |
1851 if (b->width_run_cache) | |
1852 { | |
1853 free_region_cache (b->width_run_cache); | |
1854 b->width_run_cache = 0; | |
1855 } | |
1856 b->width_table = Qnil; | |
1857 #endif | |
1858 } |