insdel.c 22.7 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Buffer insertion/deletion and gap motion for GNU Emacs.
2
   Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */


21
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
22
#include "lisp.h"
23
#include "intervals.h"
Jim Blandy's avatar
Jim Blandy committed
24 25
#include "buffer.h"
#include "window.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
26
#include "blockinput.h"
Jim Blandy's avatar
Jim Blandy committed
27

28 29
static void insert_1 ();
static void insert_from_string_1 ();
30
static void insert_from_buffer_1 ();
Karl Heuer's avatar
Karl Heuer committed
31 32 33
static void gap_left ();
static void gap_right ();
static void adjust_markers ();
Karl Heuer's avatar
Karl Heuer committed
34
static void adjust_point ();
35

Jim Blandy's avatar
Jim Blandy committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/* Move gap to position `pos'.
   Note that this can quit!  */

move_gap (pos)
     int pos;
{
  if (pos < GPT)
    gap_left (pos, 0);
  else if (pos > GPT)
    gap_right (pos);
}

/* Move the gap to POS, which is less than the current GPT.
   If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged.  */

Karl Heuer's avatar
Karl Heuer committed
51
static void
Jim Blandy's avatar
Jim Blandy committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
gap_left (pos, newgap)
     register int pos;
     int newgap;
{
  register unsigned char *to, *from;
  register int i;
  int new_s1;

  pos--;

  if (!newgap)
    {
      if (unchanged_modified == MODIFF)
	{
	  beg_unchanged = pos;
	  end_unchanged = Z - pos - 1;
	}
      else
	{
	  if (Z - GPT < end_unchanged)
	    end_unchanged = Z - GPT;
	  if (pos < beg_unchanged)
	    beg_unchanged = pos;
	}
    }

  i = GPT;
  to = GAP_END_ADDR;
  from = GPT_ADDR;
  new_s1 = GPT - BEG;

  /* Now copy the characters.  To move the gap down,
     copy characters up.  */

  while (1)
    {
      /* I gets number of characters left to copy.  */
      i = new_s1 - pos;
      if (i == 0)
	break;
      /* If a quit is requested, stop copying now.
	 Change POS to be where we have actually moved the gap to.  */
      if (QUITP)
	{
	  pos = new_s1;
	  break;
	}
      /* Move at most 32000 chars before checking again for a quit.  */
      if (i > 32000)
	i = 32000;
#ifdef GAP_USE_BCOPY
      if (i >= 128
	  /* bcopy is safe if the two areas of memory do not overlap
	     or on systems where bcopy is always safe for moving upward.  */
	  && (BCOPY_UPWARD_SAFE
	      || to - from >= 128))
	{
	  /* If overlap is not safe, avoid it by not moving too many
	     characters at once.  */
	  if (!BCOPY_UPWARD_SAFE && i > to - from)
	    i = to - from;
	  new_s1 -= i;
	  from -= i, to -= i;
	  bcopy (from, to, i);
	}
      else
#endif
	{
	  new_s1 -= i;
	  while (--i >= 0)
	    *--to = *--from;
	}
    }

  /* Adjust markers, and buffer data structure, to put the gap at POS.
     POS is where the loop above stopped, which may be what was specified
     or may be where a quit was detected.  */
  adjust_markers (pos + 1, GPT, GAP_SIZE);
  GPT = pos + 1;
  QUIT;
}

Karl Heuer's avatar
Karl Heuer committed
134
static void
Jim Blandy's avatar
Jim Blandy committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
gap_right (pos)
     register int pos;
{
  register unsigned char *to, *from;
  register int i;
  int new_s1;

  pos--;

  if (unchanged_modified == MODIFF)
    {
      beg_unchanged = pos;
      end_unchanged = Z - pos - 1;
    }
  else
    {
      if (Z - pos - 1 < end_unchanged)
	end_unchanged = Z - pos - 1;
      if (GPT - BEG < beg_unchanged)
	beg_unchanged = GPT - BEG;
    }

  i = GPT;
  from = GAP_END_ADDR;
  to = GPT_ADDR;
  new_s1 = GPT - 1;

  /* Now copy the characters.  To move the gap up,
     copy characters down.  */

  while (1)
    {
      /* I gets number of characters left to copy.  */
      i = pos - new_s1;
      if (i == 0)
	break;
      /* If a quit is requested, stop copying now.
	 Change POS to be where we have actually moved the gap to.  */
      if (QUITP)
	{
	  pos = new_s1;
	  break;
	}
      /* Move at most 32000 chars before checking again for a quit.  */
      if (i > 32000)
	i = 32000;
#ifdef GAP_USE_BCOPY
      if (i >= 128
	  /* bcopy is safe if the two areas of memory do not overlap
	     or on systems where bcopy is always safe for moving downward.  */
	  && (BCOPY_DOWNWARD_SAFE
	      || from - to >= 128))
	{
	  /* If overlap is not safe, avoid it by not moving too many
	     characters at once.  */
	  if (!BCOPY_DOWNWARD_SAFE && i > from - to)
	    i = from - to;
	  new_s1 += i;
	  bcopy (from, to, i);
	  from += i, to += i;
	}
      else
#endif
	{
	  new_s1 += i;
	  while (--i >= 0)
	    *to++ = *from++;
	}
    }

  adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
  GPT = pos + 1;
  QUIT;
}

/* Add `amount' to the position of every marker in the current buffer
   whose current position is between `from' (exclusive) and `to' (inclusive).
   Also, any markers past the outside of that interval, in the direction
   of adjustment, are first moved back to the near end of the interval
   and then adjusted by `amount'.  */

Karl Heuer's avatar
Karl Heuer committed
216
static void
Jim Blandy's avatar
Jim Blandy committed
217 218 219 220 221 222 223 224 225
adjust_markers (from, to, amount)
     register int from, to, amount;
{
  Lisp_Object marker;
  register struct Lisp_Marker *m;
  register int mpos;

  marker = current_buffer->markers;

Jim Blandy's avatar
Jim Blandy committed
226
  while (!NILP (marker))
Jim Blandy's avatar
Jim Blandy committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    {
      m = XMARKER (marker);
      mpos = m->bufpos;
      if (amount > 0)
	{
	  if (mpos > to && mpos < to + amount)
	    mpos = to + amount;
	}
      else
	{
	  if (mpos > from + amount && mpos <= from)
	    mpos = from + amount;
	}
      if (mpos > from && mpos <= to)
	mpos += amount;
      m->bufpos = mpos;
      marker = m->chain;
    }
}
Karl Heuer's avatar
Karl Heuer committed
246 247 248 249 250 251 252 253 254 255 256 257 258

/* Add the specified amount to point.  This is used only when the value
   of point changes due to an insert or delete; it does not represent
   a conceptual change in point as a marker.  In particular, point is
   not crossing any interval boundaries, so there's no need to use the
   usual SET_PT macro.  In fact it would be incorrect to do so, because
   either the old or the new value of point is out of synch with the
   current set of intervals.  */
static void
adjust_point (amount)
{
  current_buffer->text.pt += amount;
}
Jim Blandy's avatar
Jim Blandy committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272

/* Make the gap INCREMENT characters longer.  */

make_gap (increment)
     int increment;
{
  unsigned char *result;
  Lisp_Object tem;
  int real_gap_loc;
  int old_gap_size;

  /* If we have to get more space, get enough to last a while.  */
  increment += 2000;

273
  BLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
274
  result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
275

Jim Blandy's avatar
Jim Blandy committed
276
  if (result == 0)
277 278 279 280 281 282
    {
      UNBLOCK_INPUT;
      memory_full ();
    }

  /* We can't unblock until the new address is properly stored.  */
Jim Blandy's avatar
Jim Blandy committed
283
  BEG_ADDR = result;
284
  UNBLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

  /* Prevent quitting in move_gap.  */
  tem = Vinhibit_quit;
  Vinhibit_quit = Qt;

  real_gap_loc = GPT;
  old_gap_size = GAP_SIZE;

  /* Call the newly allocated space a gap at the end of the whole space.  */
  GPT = Z + GAP_SIZE;
  GAP_SIZE = increment;

  /* Move the new gap down to be consecutive with the end of the old one.
     This adjusts the markers properly too.  */
  gap_left (real_gap_loc + old_gap_size, 1);

  /* Now combine the two into one large gap.  */
  GAP_SIZE += old_gap_size;
  GPT = real_gap_loc;

  Vinhibit_quit = tem;
}

/* Insert a string of specified length before point.
309 310
   DO NOT use this for the contents of a Lisp string or a Lisp buffer!
   prepare_to_modify_buffer could relocate the text.  */
Jim Blandy's avatar
Jim Blandy committed
311 312 313 314 315

insert (string, length)
     register unsigned char *string;
     register length;
{
316 317
  if (length > 0)
    {
318 319 320 321 322 323 324 325 326 327 328 329
      insert_1 (string, length, 0);
      signal_after_change (PT-length, 0, length);
    }
}

insert_and_inherit (string, length)
     register unsigned char *string;
     register length;
{
  if (length > 0)
    {
      insert_1 (string, length, 1);
Karl Heuer's avatar
Karl Heuer committed
330
      signal_after_change (PT-length, 0, length);
331 332
    }
}
Jim Blandy's avatar
Jim Blandy committed
333

334
static void
335
insert_1 (string, length, inherit)
336 337
     register unsigned char *string;
     register length;
338
     int inherit;
339 340
{
  register Lisp_Object temp;
Jim Blandy's avatar
Jim Blandy committed
341 342

  /* Make sure point-max won't overflow after this insertion.  */
343
  XSETINT (temp, length + Z);
Jim Blandy's avatar
Jim Blandy committed
344 345 346
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

Karl Heuer's avatar
Karl Heuer committed
347
  prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
348

Karl Heuer's avatar
Karl Heuer committed
349 350
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
351 352 353
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
354
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
355 356 357 358
  MODIFF++;

  bcopy (string, GPT_ADDR, length);

359 360 361 362 363
#ifdef USE_TEXT_PROPERTIES
  if (current_buffer->intervals != 0)
    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
    offset_intervals (current_buffer, PT, length);
#endif
364

Jim Blandy's avatar
Jim Blandy committed
365 366 367 368
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
Karl Heuer's avatar
Karl Heuer committed
369
  adjust_point (length);
370

371 372
#ifdef USE_TEXT_PROPERTIES
  if (!inherit && current_buffer->intervals != 0)
373 374
    Fset_text_properties (make_number (PT - length), make_number (PT),
			  Qnil, Qnil);
375
#endif
Jim Blandy's avatar
Jim Blandy committed
376 377
}

378 379 380 381 382 383
/* Insert the part of the text of STRING, a Lisp object assumed to be
   of type string, consisting of the LENGTH characters starting at
   position POS.  If the text of STRING has properties, they are absorbed
   into the buffer.

   It does not work to use `insert' for this, because a GC could happen
Jim Blandy's avatar
Jim Blandy committed
384 385
   before we bcopy the stuff into the buffer, and relocate the string
   without insert noticing.  */
386

387
insert_from_string (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
388 389
     Lisp_Object string;
     register int pos, length;
390
     int inherit;
391 392 393 394
{
  if (length > 0)
    {
      insert_from_string_1 (string, pos, length, inherit);
Karl Heuer's avatar
Karl Heuer committed
395
      signal_after_change (PT-length, 0, length);
396 397 398 399 400 401 402 403
    }
}

static void
insert_from_string_1 (string, pos, length, inherit)
     Lisp_Object string;
     register int pos, length;
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
404 405 406 407 408
{
  register Lisp_Object temp;
  struct gcpro gcpro1;

  /* Make sure point-max won't overflow after this insertion.  */
409
  XSETINT (temp, length + Z);
Jim Blandy's avatar
Jim Blandy committed
410 411 412 413
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

  GCPRO1 (string);
Karl Heuer's avatar
Karl Heuer committed
414
  prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
415

Karl Heuer's avatar
Karl Heuer committed
416 417
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
418 419 420
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
421
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
422 423 424 425 426
  MODIFF++;
  UNGCPRO;

  bcopy (XSTRING (string)->data, GPT_ADDR, length);

427
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
Karl Heuer's avatar
Karl Heuer committed
428
  offset_intervals (current_buffer, PT, length);
429

Jim Blandy's avatar
Jim Blandy committed
430 431 432 433
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
434 435

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
Karl Heuer's avatar
Karl Heuer committed
436
  graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
437
			       current_buffer, inherit);
438

Karl Heuer's avatar
Karl Heuer committed
439
  adjust_point (length);
Jim Blandy's avatar
Jim Blandy committed
440 441
}

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
/* Insert text from BUF, starting at POS and having length LENGTH, into the
   current buffer.  If the text in BUF has properties, they are absorbed
   into the current buffer.

   It does not work to use `insert' for this, because a malloc could happen
   and relocate BUF's text before the bcopy happens.  */

void
insert_from_buffer (buf, pos, length, inherit)
     struct buffer *buf;
     int pos, length;
     int inherit;
{
  if (length > 0)
    {
      insert_from_buffer_1 (buf, pos, length, inherit);
      signal_after_change (PT-length, 0, length);
    }
}

static void
insert_from_buffer_1 (buf, pos, length, inherit)
     struct buffer *buf;
     int pos, length;
     int inherit;
{
  register Lisp_Object temp;
  int chunk;

  /* Make sure point-max won't overflow after this insertion.  */
  XSETINT (temp, length + Z);
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

  prepare_to_modify_buffer (PT, PT);

  if (PT != GPT)
    move_gap (PT);
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

  record_insert (PT, length);
  MODIFF++;

  if (pos < BUF_GPT (buf))
    {
488 489 490
      chunk = BUF_GPT (buf) - pos;
      if (chunk > length)
	chunk = length;
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
      bcopy (BUF_CHAR_ADDRESS (buf, pos), GPT_ADDR, chunk);
    }
  else
    chunk = 0;
  if (chunk < length)
    bcopy (BUF_CHAR_ADDRESS (buf, pos + chunk),
	   GPT_ADDR + chunk, length - chunk);

#ifdef USE_TEXT_PROPERTIES
  if (current_buffer->intervals != 0)
    offset_intervals (current_buffer, PT, length);
#endif

  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
  adjust_point (length);

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
  graft_intervals_into_buffer (copy_intervals (buf->intervals, pos, length),
			       PT - length, length, current_buffer, inherit);
}

Jim Blandy's avatar
Jim Blandy committed
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
/* Insert the character C before point */

void
insert_char (c)
     unsigned char c;
{
  insert (&c, 1);
}

/* Insert the null-terminated string S before point */

void
insert_string (s)
     char *s;
{
  insert (s, strlen (s));
}

/* Like `insert' except that all markers pointing at the place where
   the insertion happens are adjusted to point after it.
   Don't use this function to insert part of a Lisp string,
   since gc could happen and relocate it.  */

insert_before_markers (string, length)
     unsigned char *string;
     register int length;
{
542 543
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
544
      register int opoint = PT;
545
      insert_1 (string, length, 0);
546
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
547
      signal_after_change (PT-length, 0, length);
548
    }
Jim Blandy's avatar
Jim Blandy committed
549 550
}

551 552 553 554 555 556 557 558 559 560 561 562 563
insert_before_markers_and_inherit (string, length)
     unsigned char *string;
     register int length;
{
  if (length > 0)
    {
      register int opoint = PT;
      insert_1 (string, length, 1);
      adjust_markers (opoint - 1, opoint, length);
      signal_after_change (PT-length, 0, length);
    }
}

Jim Blandy's avatar
Jim Blandy committed
564 565
/* Insert part of a Lisp string, relocating markers after.  */

566
insert_from_string_before_markers (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
567 568
     Lisp_Object string;
     register int pos, length;
569
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
570
{
571 572
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
573
      register int opoint = PT;
574 575
      insert_from_string_1 (string, pos, length, inherit);
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
576
      signal_after_change (PT-length, 0, length);
577
    }
Jim Blandy's avatar
Jim Blandy committed
578 579 580 581 582 583 584
}

/* Delete characters in current buffer
   from FROM up to (but not including) TO.  */

del_range (from, to)
     register int from, to;
585 586 587 588 589 590 591 592
{
  return del_range_1 (from, to, 1);
}

/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.  */

del_range_1 (from, to, prepare)
     register int from, to, prepare;
Jim Blandy's avatar
Jim Blandy committed
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
{
  register int numdel;

  /* Make args be valid */
  if (from < BEGV)
    from = BEGV;
  if (to > ZV)
    to = ZV;

  if ((numdel = to - from) <= 0)
    return;

  /* Make sure the gap is somewhere in or next to what we are deleting.  */
  if (from > GPT)
    gap_right (from);
  if (to < GPT)
    gap_left (to, 0);

611 612
  if (prepare)
    prepare_to_modify_buffer (from, to);
Jim Blandy's avatar
Jim Blandy committed
613

614 615 616
  record_delete (from, numdel);
  MODIFF++;

Jim Blandy's avatar
Jim Blandy committed
617
  /* Relocate point as if it were a marker.  */
Karl Heuer's avatar
Karl Heuer committed
618
  if (from < PT)
Karl Heuer's avatar
Karl Heuer committed
619
    adjust_point (from - (PT < to ? PT : to));
Jim Blandy's avatar
Jim Blandy committed
620

621
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
622
  offset_intervals (current_buffer, from, - numdel);
623

Jim Blandy's avatar
Jim Blandy committed
624 625 626 627 628 629 630 631 632 633 634 635 636 637
  /* Relocate all markers pointing into the new, larger gap
     to point at the end of the text before the gap.  */
  adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);

  GAP_SIZE += numdel;
  ZV -= numdel;
  Z -= numdel;
  GPT = from;

  if (GPT - BEG < beg_unchanged)
    beg_unchanged = GPT - BEG;
  if (Z - GPT < end_unchanged)
    end_unchanged = Z - GPT;

638
  evaporate_overlays (from);
Jim Blandy's avatar
Jim Blandy committed
639 640 641
  signal_after_change (from, numdel, 0);
}

642 643 644 645 646 647
/* Call this if you're about to change the region of BUFFER from START
   to END.  This checks the read-only properties of the region, calls
   the necessary modification hooks, and warns the next redisplay that
   it should pay attention to that area.  */
modify_region (buffer, start, end)
     struct buffer *buffer;
Jim Blandy's avatar
Jim Blandy committed
648 649
     int start, end;
{
650 651 652 653 654
  struct buffer *old_buffer = current_buffer;

  if (buffer != old_buffer)
    set_buffer_internal (buffer);

Jim Blandy's avatar
Jim Blandy committed
655 656 657 658 659 660 661
  prepare_to_modify_buffer (start, end);

  if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
    beg_unchanged = start - 1;
  if (Z - end < end_unchanged
      || unchanged_modified == MODIFF)
    end_unchanged = Z - end;
662 663 664

  if (MODIFF <= current_buffer->save_modified)
    record_first_change ();
Jim Blandy's avatar
Jim Blandy committed
665
  MODIFF++;
666 667 668

  if (buffer != old_buffer)
    set_buffer_internal (old_buffer);
Jim Blandy's avatar
Jim Blandy committed
669 670 671
}

/* Check that it is okay to modify the buffer between START and END.
672 673 674
   Run the before-change-function, if any.  If intervals are in use,
   verify that the text to be modified is not read-only, and call
   any modification properties the text may have. */
Jim Blandy's avatar
Jim Blandy committed
675 676 677 678

prepare_to_modify_buffer (start, end)
     Lisp_Object start, end;
{
Jim Blandy's avatar
Jim Blandy committed
679
  if (!NILP (current_buffer->read_only))
Jim Blandy's avatar
Jim Blandy committed
680 681
    Fbarf_if_buffer_read_only ();

682
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
683 684
  if (current_buffer->intervals != 0)
    verify_interval_modification (current_buffer, start, end);
Jim Blandy's avatar
Jim Blandy committed
685 686

#ifdef CLASH_DETECTION
Jim Blandy's avatar
Jim Blandy committed
687
  if (!NILP (current_buffer->filename)
Jim Blandy's avatar
Jim Blandy committed
688 689 690 691
      && current_buffer->save_modified >= MODIFF)
    lock_file (current_buffer->filename);
#else
  /* At least warn if this file has changed on disk since it was visited.  */
Jim Blandy's avatar
Jim Blandy committed
692
  if (!NILP (current_buffer->filename)
Jim Blandy's avatar
Jim Blandy committed
693
      && current_buffer->save_modified >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
694 695
      && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
      && !NILP (Ffile_exists_p (current_buffer->filename)))
Jim Blandy's avatar
Jim Blandy committed
696 697 698 699 700
    call1 (intern ("ask-user-about-supersession-threat"),
	   current_buffer->filename);
#endif /* not CLASH_DETECTION */

  signal_before_change (start, end);
701

702 703 704 705 706 707 708 709 710
  if (current_buffer->newline_cache)
    invalidate_region_cache (current_buffer,
                             current_buffer->newline_cache,
                             start - BEG, Z - end);
  if (current_buffer->width_run_cache)
    invalidate_region_cache (current_buffer,
                             current_buffer->width_run_cache,
                             start - BEG, Z - end);

711
  Vdeactivate_mark = Qt;
Jim Blandy's avatar
Jim Blandy committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
}

static Lisp_Object
before_change_function_restore (value)
     Lisp_Object value;
{
  Vbefore_change_function = value;
}

static Lisp_Object
after_change_function_restore (value)
     Lisp_Object value;
{
  Vafter_change_function = value;
}

728 729 730 731 732 733 734 735 736 737 738 739 740 741
static Lisp_Object
before_change_functions_restore (value)
     Lisp_Object value;
{
  Vbefore_change_functions = value;
}

static Lisp_Object
after_change_functions_restore (value)
     Lisp_Object value;
{
  Vafter_change_functions = value;
}

742
/* Signal a change to the buffer immediately before it happens.
Jim Blandy's avatar
Jim Blandy committed
743 744 745 746 747 748 749 750
   START and END are the bounds of the text to be changed,
   as Lisp objects.  */

signal_before_change (start, end)
     Lisp_Object start, end;
{
  /* If buffer is unmodified, run a special hook for that case.  */
  if (current_buffer->save_modified >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
751 752 753 754
      && !NILP (Vfirst_change_hook)
      && !NILP (Vrun_hooks))
    call1 (Vrun_hooks, Qfirst_change_hook);

Jim Blandy's avatar
Jim Blandy committed
755
  /* Now in any case run the before-change-function if any.  */
Jim Blandy's avatar
Jim Blandy committed
756
  if (!NILP (Vbefore_change_function))
Jim Blandy's avatar
Jim Blandy committed
757 758 759 760 761
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object function;

      function = Vbefore_change_function;
762

Jim Blandy's avatar
Jim Blandy committed
763 764 765 766
      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
767 768 769 770
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
Jim Blandy's avatar
Jim Blandy committed
771 772
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
773 774
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
775 776 777 778

      call2 (function, start, end);
      unbind_to (count, Qnil);
    }
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807

  /* Now in any case run the before-change-function if any.  */
  if (!NILP (Vbefore_change_functions))
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object functions;

      functions = Vbefore_change_functions;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;

      while (CONSP (functions))
	{
	  call2 (XCONS (functions)->car, start, end);
	  functions = XCONS (functions)->cdr;
	}
      unbind_to (count, Qnil);
    }
808 809 810 811

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
    verify_overlay_modification (start, end, 0, start, end, Qnil);
Jim Blandy's avatar
Jim Blandy committed
812 813
}

814
/* Signal a change immediately after it happens.
Jim Blandy's avatar
Jim Blandy committed
815 816 817
   POS is the address of the start of the changed text.
   LENDEL is the number of characters of the text before the change.
   (Not the whole buffer; just the part that was changed.)
818 819 820
   LENINS is the number of characters in the changed text.

   (Hence POS + LENINS - LENDEL is the position after the changed text.)  */
Jim Blandy's avatar
Jim Blandy committed
821 822 823 824

signal_after_change (pos, lendel, lenins)
     int pos, lendel, lenins;
{
Jim Blandy's avatar
Jim Blandy committed
825
  if (!NILP (Vafter_change_function))
Jim Blandy's avatar
Jim Blandy committed
826 827 828 829 830 831 832 833 834
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object function;
      function = Vafter_change_function;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
835 836 837 838
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
Jim Blandy's avatar
Jim Blandy committed
839 840
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
841 842
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
843 844 845 846 847

      call3 (function, make_number (pos), make_number (pos + lenins),
	     make_number (lendel));
      unbind_to (count, Qnil);
    }
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
  if (!NILP (Vafter_change_functions))
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object functions;
      functions = Vafter_change_functions;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;

      while (CONSP (functions))
	{
	  call3 (XCONS (functions)->car,
		 make_number (pos), make_number (pos + lenins),
		 make_number (lendel));
	  functions = XCONS (functions)->cdr;
	}
      unbind_to (count, Qnil);
    }
876 877 878 879 880 881 882 883

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
    verify_overlay_modification (make_number (pos),
				 make_number (pos + lenins - lendel),
				 1,
				 make_number (pos), make_number (pos + lenins),
				 make_number (lendel));
Jim Blandy's avatar
Jim Blandy committed
884
}