diff options
| author | Jim Blandy | 1991-01-05 15:12:15 +0000 |
|---|---|---|
| committer | Jim Blandy | 1991-01-05 15:12:15 +0000 |
| commit | b45433b39e5b46fc6bf33c3b0213c3f7e04fafc0 (patch) | |
| tree | b8dd83094ec82f89f102a1227aa2b9eb6169d6c3 /src | |
| parent | 86581d9680f9d645fed687e59f9522e2c005d62a (diff) | |
| download | emacs-b45433b39e5b46fc6bf33c3b0213c3f7e04fafc0.tar.gz emacs-b45433b39e5b46fc6bf33c3b0213c3f7e04fafc0.zip | |
Initial revision
Diffstat (limited to 'src')
| -rw-r--r-- | src/insdel.c | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/src/insdel.c b/src/insdel.c new file mode 100644 index 00000000000..2de7744522e --- /dev/null +++ b/src/insdel.c | |||
| @@ -0,0 +1,570 @@ | |||
| 1 | /* Buffer insertion/deletion and gap motion for GNU Emacs. | ||
| 2 | Copyright (C) 1985, 1986 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 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) | ||
| 9 | any later version. | ||
| 10 | |||
| 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. | ||
| 15 | |||
| 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. */ | ||
| 19 | |||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "lisp.h" | ||
| 23 | #include "buffer.h" | ||
| 24 | #include "window.h" | ||
| 25 | |||
| 26 | /* Nonzero means don't allow protected fields to be modified. */ | ||
| 27 | |||
| 28 | extern int check_protected_fields; | ||
| 29 | |||
| 30 | /* Move gap to position `pos'. | ||
| 31 | Note that this can quit! */ | ||
| 32 | |||
| 33 | move_gap (pos) | ||
| 34 | int pos; | ||
| 35 | { | ||
| 36 | if (pos < GPT) | ||
| 37 | gap_left (pos, 0); | ||
| 38 | else if (pos > GPT) | ||
| 39 | gap_right (pos); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* Move the gap to POS, which is less than the current GPT. | ||
| 43 | If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */ | ||
| 44 | |||
| 45 | gap_left (pos, newgap) | ||
| 46 | register int pos; | ||
| 47 | int newgap; | ||
| 48 | { | ||
| 49 | register unsigned char *to, *from; | ||
| 50 | register int i; | ||
| 51 | int new_s1; | ||
| 52 | |||
| 53 | pos--; | ||
| 54 | |||
| 55 | if (!newgap) | ||
| 56 | { | ||
| 57 | if (unchanged_modified == MODIFF) | ||
| 58 | { | ||
| 59 | beg_unchanged = pos; | ||
| 60 | end_unchanged = Z - pos - 1; | ||
| 61 | } | ||
| 62 | else | ||
| 63 | { | ||
| 64 | if (Z - GPT < end_unchanged) | ||
| 65 | end_unchanged = Z - GPT; | ||
| 66 | if (pos < beg_unchanged) | ||
| 67 | beg_unchanged = pos; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | i = GPT; | ||
| 72 | to = GAP_END_ADDR; | ||
| 73 | from = GPT_ADDR; | ||
| 74 | new_s1 = GPT - BEG; | ||
| 75 | |||
| 76 | /* Now copy the characters. To move the gap down, | ||
| 77 | copy characters up. */ | ||
| 78 | |||
| 79 | while (1) | ||
| 80 | { | ||
| 81 | /* I gets number of characters left to copy. */ | ||
| 82 | i = new_s1 - pos; | ||
| 83 | if (i == 0) | ||
| 84 | break; | ||
| 85 | /* If a quit is requested, stop copying now. | ||
| 86 | Change POS to be where we have actually moved the gap to. */ | ||
| 87 | if (QUITP) | ||
| 88 | { | ||
| 89 | pos = new_s1; | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | /* Move at most 32000 chars before checking again for a quit. */ | ||
| 93 | if (i > 32000) | ||
| 94 | i = 32000; | ||
| 95 | #ifdef GAP_USE_BCOPY | ||
| 96 | if (i >= 128 | ||
| 97 | /* bcopy is safe if the two areas of memory do not overlap | ||
| 98 | or on systems where bcopy is always safe for moving upward. */ | ||
| 99 | && (BCOPY_UPWARD_SAFE | ||
| 100 | || to - from >= 128)) | ||
| 101 | { | ||
| 102 | /* If overlap is not safe, avoid it by not moving too many | ||
| 103 | characters at once. */ | ||
| 104 | if (!BCOPY_UPWARD_SAFE && i > to - from) | ||
| 105 | i = to - from; | ||
| 106 | new_s1 -= i; | ||
| 107 | from -= i, to -= i; | ||
| 108 | bcopy (from, to, i); | ||
| 109 | } | ||
| 110 | else | ||
| 111 | #endif | ||
| 112 | { | ||
| 113 | new_s1 -= i; | ||
| 114 | while (--i >= 0) | ||
| 115 | *--to = *--from; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | /* Adjust markers, and buffer data structure, to put the gap at POS. | ||
| 120 | POS is where the loop above stopped, which may be what was specified | ||
| 121 | or may be where a quit was detected. */ | ||
| 122 | adjust_markers (pos + 1, GPT, GAP_SIZE); | ||
| 123 | GPT = pos + 1; | ||
| 124 | QUIT; | ||
| 125 | } | ||
| 126 | |||
| 127 | gap_right (pos) | ||
| 128 | register int pos; | ||
| 129 | { | ||
| 130 | register unsigned char *to, *from; | ||
| 131 | register int i; | ||
| 132 | int new_s1; | ||
| 133 | |||
| 134 | pos--; | ||
| 135 | |||
| 136 | if (unchanged_modified == MODIFF) | ||
| 137 | { | ||
| 138 | beg_unchanged = pos; | ||
| 139 | end_unchanged = Z - pos - 1; | ||
| 140 | } | ||
| 141 | else | ||
| 142 | { | ||
| 143 | if (Z - pos - 1 < end_unchanged) | ||
| 144 | end_unchanged = Z - pos - 1; | ||
| 145 | if (GPT - BEG < beg_unchanged) | ||
| 146 | beg_unchanged = GPT - BEG; | ||
| 147 | } | ||
| 148 | |||
| 149 | i = GPT; | ||
| 150 | from = GAP_END_ADDR; | ||
| 151 | to = GPT_ADDR; | ||
| 152 | new_s1 = GPT - 1; | ||
| 153 | |||
| 154 | /* Now copy the characters. To move the gap up, | ||
| 155 | copy characters down. */ | ||
| 156 | |||
| 157 | while (1) | ||
| 158 | { | ||
| 159 | /* I gets number of characters left to copy. */ | ||
| 160 | i = pos - new_s1; | ||
| 161 | if (i == 0) | ||
| 162 | break; | ||
| 163 | /* If a quit is requested, stop copying now. | ||
| 164 | Change POS to be where we have actually moved the gap to. */ | ||
| 165 | if (QUITP) | ||
| 166 | { | ||
| 167 | pos = new_s1; | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | /* Move at most 32000 chars before checking again for a quit. */ | ||
| 171 | if (i > 32000) | ||
| 172 | i = 32000; | ||
| 173 | #ifdef GAP_USE_BCOPY | ||
| 174 | if (i >= 128 | ||
| 175 | /* bcopy is safe if the two areas of memory do not overlap | ||
| 176 | or on systems where bcopy is always safe for moving downward. */ | ||
| 177 | && (BCOPY_DOWNWARD_SAFE | ||
| 178 | || from - to >= 128)) | ||
| 179 | { | ||
| 180 | /* If overlap is not safe, avoid it by not moving too many | ||
| 181 | characters at once. */ | ||
| 182 | if (!BCOPY_DOWNWARD_SAFE && i > from - to) | ||
| 183 | i = from - to; | ||
| 184 | new_s1 += i; | ||
| 185 | bcopy (from, to, i); | ||
| 186 | from += i, to += i; | ||
| 187 | } | ||
| 188 | else | ||
| 189 | #endif | ||
| 190 | { | ||
| 191 | new_s1 += i; | ||
| 192 | while (--i >= 0) | ||
| 193 | *to++ = *from++; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE); | ||
| 198 | GPT = pos + 1; | ||
| 199 | QUIT; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* Add `amount' to the position of every marker in the current buffer | ||
| 203 | whose current position is between `from' (exclusive) and `to' (inclusive). | ||
| 204 | Also, any markers past the outside of that interval, in the direction | ||
| 205 | of adjustment, are first moved back to the near end of the interval | ||
| 206 | and then adjusted by `amount'. */ | ||
| 207 | |||
| 208 | adjust_markers (from, to, amount) | ||
| 209 | register int from, to, amount; | ||
| 210 | { | ||
| 211 | Lisp_Object marker; | ||
| 212 | register struct Lisp_Marker *m; | ||
| 213 | register int mpos; | ||
| 214 | |||
| 215 | marker = current_buffer->markers; | ||
| 216 | |||
| 217 | while (!NULL (marker)) | ||
| 218 | { | ||
| 219 | m = XMARKER (marker); | ||
| 220 | mpos = m->bufpos; | ||
| 221 | if (amount > 0) | ||
| 222 | { | ||
| 223 | if (mpos > to && mpos < to + amount) | ||
| 224 | mpos = to + amount; | ||
| 225 | } | ||
| 226 | else | ||
| 227 | { | ||
| 228 | if (mpos > from + amount && mpos <= from) | ||
| 229 | mpos = from + amount; | ||
| 230 | } | ||
| 231 | if (mpos > from && mpos <= to) | ||
| 232 | mpos += amount; | ||
| 233 | m->bufpos = mpos; | ||
| 234 | marker = m->chain; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | /* Make the gap INCREMENT characters longer. */ | ||
| 239 | |||
| 240 | make_gap (increment) | ||
| 241 | int increment; | ||
| 242 | { | ||
| 243 | unsigned char *result; | ||
| 244 | Lisp_Object tem; | ||
| 245 | int real_gap_loc; | ||
| 246 | int old_gap_size; | ||
| 247 | |||
| 248 | /* If we have to get more space, get enough to last a while. */ | ||
| 249 | increment += 2000; | ||
| 250 | |||
| 251 | result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment)); | ||
| 252 | if (result == 0) | ||
| 253 | memory_full (); | ||
| 254 | BEG_ADDR = result; | ||
| 255 | |||
| 256 | /* Prevent quitting in move_gap. */ | ||
| 257 | tem = Vinhibit_quit; | ||
| 258 | Vinhibit_quit = Qt; | ||
| 259 | |||
| 260 | real_gap_loc = GPT; | ||
| 261 | old_gap_size = GAP_SIZE; | ||
| 262 | |||
| 263 | /* Call the newly allocated space a gap at the end of the whole space. */ | ||
| 264 | GPT = Z + GAP_SIZE; | ||
| 265 | GAP_SIZE = increment; | ||
| 266 | |||
| 267 | /* Move the new gap down to be consecutive with the end of the old one. | ||
| 268 | This adjusts the markers properly too. */ | ||
| 269 | gap_left (real_gap_loc + old_gap_size, 1); | ||
| 270 | |||
| 271 | /* Now combine the two into one large gap. */ | ||
| 272 | GAP_SIZE += old_gap_size; | ||
| 273 | GPT = real_gap_loc; | ||
| 274 | |||
| 275 | Vinhibit_quit = tem; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* Insert a string of specified length before point. | ||
| 279 | DO NOT use this for the contents of a Lisp string! | ||
| 280 | prepare_to_modify_buffer could relocate the string. */ | ||
| 281 | |||
| 282 | insert (string, length) | ||
| 283 | register unsigned char *string; | ||
| 284 | register length; | ||
| 285 | { | ||
| 286 | register Lisp_Object temp; | ||
| 287 | |||
| 288 | if (length < 1) | ||
| 289 | return; | ||
| 290 | |||
| 291 | /* Make sure point-max won't overflow after this insertion. */ | ||
| 292 | XSET (temp, Lisp_Int, length + Z); | ||
| 293 | if (length + Z != XINT (temp)) | ||
| 294 | error ("maximum buffer size exceeded"); | ||
| 295 | |||
| 296 | prepare_to_modify_buffer (point, point); | ||
| 297 | |||
| 298 | if (point != GPT) | ||
| 299 | move_gap (point); | ||
| 300 | if (GAP_SIZE < length) | ||
| 301 | make_gap (length - GAP_SIZE); | ||
| 302 | |||
| 303 | record_insert (point, length); | ||
| 304 | MODIFF++; | ||
| 305 | |||
| 306 | bcopy (string, GPT_ADDR, length); | ||
| 307 | |||
| 308 | GAP_SIZE -= length; | ||
| 309 | GPT += length; | ||
| 310 | ZV += length; | ||
| 311 | Z += length; | ||
| 312 | SET_PT (point + length); | ||
| 313 | |||
| 314 | signal_after_change (point-length, 0, length); | ||
| 315 | } | ||
| 316 | |||
| 317 | /* Function to insert part of the text of a string (STRING) | ||
| 318 | consisting of LENGTH characters at position POS. | ||
| 319 | It does not work to use `insert' for this. */ | ||
| 320 | |||
| 321 | insert_from_string (string, pos, length) | ||
| 322 | Lisp_Object string; | ||
| 323 | register int pos, length; | ||
| 324 | { | ||
| 325 | register Lisp_Object temp; | ||
| 326 | struct gcpro gcpro1; | ||
| 327 | |||
| 328 | if (length < 1) | ||
| 329 | return; | ||
| 330 | |||
| 331 | /* Make sure point-max won't overflow after this insertion. */ | ||
| 332 | XSET (temp, Lisp_Int, length + Z); | ||
| 333 | if (length + Z != XINT (temp)) | ||
| 334 | error ("maximum buffer size exceeded"); | ||
| 335 | |||
| 336 | GCPRO1 (string); | ||
| 337 | prepare_to_modify_buffer (point, point); | ||
| 338 | |||
| 339 | if (point != GPT) | ||
| 340 | move_gap (point); | ||
| 341 | if (GAP_SIZE < length) | ||
| 342 | make_gap (length - GAP_SIZE); | ||
| 343 | |||
| 344 | record_insert (point, length); | ||
| 345 | MODIFF++; | ||
| 346 | UNGCPRO; | ||
| 347 | |||
| 348 | bcopy (XSTRING (string)->data, GPT_ADDR, length); | ||
| 349 | |||
| 350 | GAP_SIZE -= length; | ||
| 351 | GPT += length; | ||
| 352 | ZV += length; | ||
| 353 | Z += length; | ||
| 354 | point += length; | ||
| 355 | |||
| 356 | signal_after_change (point-length, 0, length); | ||
| 357 | } | ||
| 358 | |||
| 359 | /* Insert the character C before point */ | ||
| 360 | |||
| 361 | void | ||
| 362 | insert_char (c) | ||
| 363 | unsigned char c; | ||
| 364 | { | ||
| 365 | insert (&c, 1); | ||
| 366 | } | ||
| 367 | |||
| 368 | /* Insert the null-terminated string S before point */ | ||
| 369 | |||
| 370 | void | ||
| 371 | insert_string (s) | ||
| 372 | char *s; | ||
| 373 | { | ||
| 374 | insert (s, strlen (s)); | ||
| 375 | } | ||
| 376 | |||
| 377 | /* Like `insert' except that all markers pointing at the place where | ||
| 378 | the insertion happens are adjusted to point after it. | ||
| 379 | Don't use this function to insert part of a Lisp string, | ||
| 380 | since gc could happen and relocate it. */ | ||
| 381 | |||
| 382 | insert_before_markers (string, length) | ||
| 383 | unsigned char *string; | ||
| 384 | register int length; | ||
| 385 | { | ||
| 386 | register int opoint = point; | ||
| 387 | insert (string, length); | ||
| 388 | adjust_markers (opoint - 1, opoint, length); | ||
| 389 | } | ||
| 390 | |||
| 391 | /* Insert part of a Lisp string, relocating markers after. */ | ||
| 392 | |||
| 393 | insert_from_string_before_markers (string, pos, length) | ||
| 394 | Lisp_Object string; | ||
| 395 | register int pos, length; | ||
| 396 | { | ||
| 397 | register int opoint = point; | ||
| 398 | insert_from_string (string, pos, length); | ||
| 399 | adjust_markers (opoint - 1, opoint, length); | ||
| 400 | } | ||
| 401 | |||
| 402 | /* Delete characters in current buffer | ||
| 403 | from FROM up to (but not including) TO. */ | ||
| 404 | |||
| 405 | del_range (from, to) | ||
| 406 | register int from, to; | ||
| 407 | { | ||
| 408 | register int numdel; | ||
| 409 | |||
| 410 | /* Make args be valid */ | ||
| 411 | if (from < BEGV) | ||
| 412 | from = BEGV; | ||
| 413 | if (to > ZV) | ||
| 414 | to = ZV; | ||
| 415 | |||
| 416 | if ((numdel = to - from) <= 0) | ||
| 417 | return; | ||
| 418 | |||
| 419 | /* Make sure the gap is somewhere in or next to what we are deleting. */ | ||
| 420 | if (from > GPT) | ||
| 421 | gap_right (from); | ||
| 422 | if (to < GPT) | ||
| 423 | gap_left (to, 0); | ||
| 424 | |||
| 425 | prepare_to_modify_buffer (from, to); | ||
| 426 | |||
| 427 | /* Relocate point as if it were a marker. */ | ||
| 428 | if (from < point) | ||
| 429 | { | ||
| 430 | if (point < to) | ||
| 431 | SET_PT (from); | ||
| 432 | else | ||
| 433 | SET_PT (point - numdel); | ||
| 434 | } | ||
| 435 | |||
| 436 | record_delete (from, numdel); | ||
| 437 | MODIFF++; | ||
| 438 | |||
| 439 | /* Relocate all markers pointing into the new, larger gap | ||
| 440 | to point at the end of the text before the gap. */ | ||
| 441 | adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE); | ||
| 442 | |||
| 443 | GAP_SIZE += numdel; | ||
| 444 | ZV -= numdel; | ||
| 445 | Z -= numdel; | ||
| 446 | GPT = from; | ||
| 447 | |||
| 448 | if (GPT - BEG < beg_unchanged) | ||
| 449 | beg_unchanged = GPT - BEG; | ||
| 450 | if (Z - GPT < end_unchanged) | ||
| 451 | end_unchanged = Z - GPT; | ||
| 452 | |||
| 453 | signal_after_change (from, numdel, 0); | ||
| 454 | } | ||
| 455 | |||
| 456 | modify_region (start, end) | ||
| 457 | int start, end; | ||
| 458 | { | ||
| 459 | prepare_to_modify_buffer (start, end); | ||
| 460 | |||
| 461 | if (start - 1 < beg_unchanged || unchanged_modified == MODIFF) | ||
| 462 | beg_unchanged = start - 1; | ||
| 463 | if (Z - end < end_unchanged | ||
| 464 | || unchanged_modified == MODIFF) | ||
| 465 | end_unchanged = Z - end; | ||
| 466 | MODIFF++; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* Check that it is okay to modify the buffer between START and END. | ||
| 470 | Run the before-change-function, if any. */ | ||
| 471 | |||
| 472 | prepare_to_modify_buffer (start, end) | ||
| 473 | Lisp_Object start, end; | ||
| 474 | { | ||
| 475 | if (!NULL (current_buffer->read_only)) | ||
| 476 | Fbarf_if_buffer_read_only (); | ||
| 477 | |||
| 478 | if (check_protected_fields) | ||
| 479 | Fregion_fields (start, end, Qnil, Qt); | ||
| 480 | |||
| 481 | #ifdef CLASH_DETECTION | ||
| 482 | if (!NULL (current_buffer->filename) | ||
| 483 | && current_buffer->save_modified >= MODIFF) | ||
| 484 | lock_file (current_buffer->filename); | ||
| 485 | #else | ||
| 486 | /* At least warn if this file has changed on disk since it was visited. */ | ||
| 487 | if (!NULL (current_buffer->filename) | ||
| 488 | && current_buffer->save_modified >= MODIFF | ||
| 489 | && NULL (Fverify_visited_file_modtime (Fcurrent_buffer ())) | ||
| 490 | && !NULL (Ffile_exists_p (current_buffer->filename))) | ||
| 491 | call1 (intern ("ask-user-about-supersession-threat"), | ||
| 492 | current_buffer->filename); | ||
| 493 | #endif /* not CLASH_DETECTION */ | ||
| 494 | |||
| 495 | signal_before_change (start, end); | ||
| 496 | } | ||
| 497 | |||
| 498 | static Lisp_Object | ||
| 499 | before_change_function_restore (value) | ||
| 500 | Lisp_Object value; | ||
| 501 | { | ||
| 502 | Vbefore_change_function = value; | ||
| 503 | } | ||
| 504 | |||
| 505 | static Lisp_Object | ||
| 506 | after_change_function_restore (value) | ||
| 507 | Lisp_Object value; | ||
| 508 | { | ||
| 509 | Vafter_change_function = value; | ||
| 510 | } | ||
| 511 | |||
| 512 | /* Signal a change to the buffer immediatly before it happens. | ||
| 513 | START and END are the bounds of the text to be changed, | ||
| 514 | as Lisp objects. */ | ||
| 515 | |||
| 516 | signal_before_change (start, end) | ||
| 517 | Lisp_Object start, end; | ||
| 518 | { | ||
| 519 | /* If buffer is unmodified, run a special hook for that case. */ | ||
| 520 | if (current_buffer->save_modified >= MODIFF | ||
| 521 | && !NULL (Vfirst_change_function)) | ||
| 522 | { | ||
| 523 | call0 (Vfirst_change_function); | ||
| 524 | } | ||
| 525 | /* Now in any case run the before-change-function if any. */ | ||
| 526 | if (!NULL (Vbefore_change_function)) | ||
| 527 | { | ||
| 528 | int count = specpdl_ptr - specpdl; | ||
| 529 | Lisp_Object function; | ||
| 530 | |||
| 531 | function = Vbefore_change_function; | ||
| 532 | record_unwind_protect (after_change_function_restore, | ||
| 533 | Vafter_change_function); | ||
| 534 | record_unwind_protect (before_change_function_restore, | ||
| 535 | Vbefore_change_function); | ||
| 536 | Vafter_change_function = Qnil; | ||
| 537 | Vbefore_change_function = Qnil; | ||
| 538 | |||
| 539 | call2 (function, start, end); | ||
| 540 | unbind_to (count, Qnil); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | /* Signal a change immediatly after it happens. | ||
| 545 | POS is the address of the start of the changed text. | ||
| 546 | LENDEL is the number of characters of the text before the change. | ||
| 547 | (Not the whole buffer; just the part that was changed.) | ||
| 548 | LENINS is the number of characters in the changed text. */ | ||
| 549 | |||
| 550 | signal_after_change (pos, lendel, lenins) | ||
| 551 | int pos, lendel, lenins; | ||
| 552 | { | ||
| 553 | if (!NULL (Vafter_change_function)) | ||
| 554 | { | ||
| 555 | int count = specpdl_ptr - specpdl; | ||
| 556 | Lisp_Object function; | ||
| 557 | function = Vafter_change_function; | ||
| 558 | |||
| 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; | ||
| 565 | |||
| 566 | call3 (function, make_number (pos), make_number (pos + lenins), | ||
| 567 | make_number (lendel)); | ||
| 568 | unbind_to (count, Qnil); | ||
| 569 | } | ||
| 570 | } | ||