insdel.c 23.2 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Buffer insertion/deletion and gap motion for GNU Emacs.
Karl Heuer's avatar
Karl Heuer committed
2
   Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
3 4 5 6 7

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
Karl Heuer's avatar
Karl Heuer committed
8
the Free Software Foundation; either version 2, or (at your option)
Jim Blandy's avatar
Jim Blandy committed
9 10 11 12 13 14 15 16 17 18 19 20
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
#define min(x, y) ((x) < (y) ? (x) : (y))

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

Jim Blandy's avatar
Jim Blandy committed
37 38 39
/* Move gap to position `pos'.
   Note that this can quit!  */

40
void
Jim Blandy's avatar
Jim Blandy committed
41 42 43 44 45 46 47 48 49 50 51 52
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
53
static void
Jim Blandy's avatar
Jim Blandy committed
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 134 135
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
136
static void
Jim Blandy's avatar
Jim Blandy committed
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 216 217
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
218
static void
Jim Blandy's avatar
Jim Blandy committed
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;

226
  marker = BUF_MARKERS (current_buffer);
Jim Blandy's avatar
Jim Blandy committed
227

Jim Blandy's avatar
Jim Blandy committed
228
  while (!NILP (marker))
Jim Blandy's avatar
Jim Blandy committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    {
      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
248 249 250 251 252 253 254 255 256 257

/* 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)
258
     int amount;
Karl Heuer's avatar
Karl Heuer committed
259
{
260
  BUF_PT (current_buffer) += amount;
Karl Heuer's avatar
Karl Heuer committed
261
}
Jim Blandy's avatar
Jim Blandy committed
262 263 264

/* Make the gap INCREMENT characters longer.  */

265
void
Jim Blandy's avatar
Jim Blandy committed
266 267 268 269 270 271 272 273 274 275 276
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;

277 278 279 280
  /* Don't allow a buffer size that won't fit in an int
     even if it will fit in a Lisp integer.
     That won't work because so many places use `int'.  */
     
281 282 283
  if (Z - BEG + GAP_SIZE + increment
      >= ((unsigned) 1 << (min (INTBITS, VALBITS) - 1)))
    error ("Buffer exceeds maximum size");
284

285
  BLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
286
  result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
287

Jim Blandy's avatar
Jim Blandy committed
288
  if (result == 0)
289 290 291 292 293 294
    {
      UNBLOCK_INPUT;
      memory_full ();
    }

  /* We can't unblock until the new address is properly stored.  */
Jim Blandy's avatar
Jim Blandy committed
295
  BEG_ADDR = result;
296
  UNBLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

  /* 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.
321 322
   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
323

324
void
Jim Blandy's avatar
Jim Blandy committed
325 326 327 328
insert (string, length)
     register unsigned char *string;
     register length;
{
329 330
  if (length > 0)
    {
331
      insert_1 (string, length, 0, 1);
332 333 334 335
      signal_after_change (PT-length, 0, length);
    }
}

336
void
337 338 339 340 341 342
insert_and_inherit (string, length)
     register unsigned char *string;
     register length;
{
  if (length > 0)
    {
343
      insert_1 (string, length, 1, 1);
Karl Heuer's avatar
Karl Heuer committed
344
      signal_after_change (PT-length, 0, length);
345 346
    }
}
Jim Blandy's avatar
Jim Blandy committed
347

348 349
void
insert_1 (string, length, inherit, prepare)
350
     register unsigned char *string;
351 352
     register int length;
     int inherit, prepare;
353 354
{
  register Lisp_Object temp;
Jim Blandy's avatar
Jim Blandy committed
355

356 357
  if (prepare)
    prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
358

Karl Heuer's avatar
Karl Heuer committed
359 360
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
361 362 363
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
364
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
365 366 367 368
  MODIFF++;

  bcopy (string, GPT_ADDR, length);

369
#ifdef USE_TEXT_PROPERTIES
370
  if (BUF_INTERVALS (current_buffer) != 0)
371 372 373
    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
    offset_intervals (current_buffer, PT, length);
#endif
374

Jim Blandy's avatar
Jim Blandy committed
375 376 377 378
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
379
  adjust_overlays_for_insert (PT, length);
Karl Heuer's avatar
Karl Heuer committed
380
  adjust_point (length);
381

382
#ifdef USE_TEXT_PROPERTIES
383
  if (!inherit && BUF_INTERVALS (current_buffer) != 0)
384 385
    Fset_text_properties (make_number (PT - length), make_number (PT),
			  Qnil, Qnil);
386
#endif
Jim Blandy's avatar
Jim Blandy committed
387 388
}

389 390 391 392 393 394
/* 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
395 396
   before we bcopy the stuff into the buffer, and relocate the string
   without insert noticing.  */
397

398
void
399
insert_from_string (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
400 401
     Lisp_Object string;
     register int pos, length;
402
     int inherit;
403 404 405 406
{
  if (length > 0)
    {
      insert_from_string_1 (string, pos, length, inherit);
Karl Heuer's avatar
Karl Heuer committed
407
      signal_after_change (PT-length, 0, length);
408 409 410 411 412 413 414 415
    }
}

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
416 417 418 419 420
{
  register Lisp_Object temp;
  struct gcpro gcpro1;

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

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

Karl Heuer's avatar
Karl Heuer committed
428 429
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
430 431 432
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
433
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
434 435 436 437 438
  MODIFF++;
  UNGCPRO;

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

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

Jim Blandy's avatar
Jim Blandy committed
442 443 444 445
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
446
  adjust_overlays_for_insert (PT, length);
447 448

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

Karl Heuer's avatar
Karl Heuer committed
452
  adjust_point (length);
Jim Blandy's avatar
Jim Blandy committed
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 488 489 490 491 492 493 494 495 496 497 498 499 500
/* 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))
    {
501 502 503
      chunk = BUF_GPT (buf) - pos;
      if (chunk > length)
	chunk = length;
504 505 506 507 508 509 510 511 512
      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
513
  if (BUF_INTERVALS (current_buffer) != 0)
514 515 516 517 518 519 520
    offset_intervals (current_buffer, PT, length);
#endif

  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
521
  adjust_overlays_for_insert (PT, length);
522 523 524
  adjust_point (length);

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
525 526
  graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
					       pos, length),
527 528 529
			       PT - length, length, current_buffer, inherit);
}

Jim Blandy's avatar
Jim Blandy committed
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
/* 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.  */

553
void
Jim Blandy's avatar
Jim Blandy committed
554 555 556 557
insert_before_markers (string, length)
     unsigned char *string;
     register int length;
{
558 559
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
560
      register int opoint = PT;
561
      insert_1 (string, length, 0, 1);
562
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
563
      signal_after_change (PT-length, 0, length);
564
    }
Jim Blandy's avatar
Jim Blandy committed
565 566
}

567
void
568 569 570 571 572 573 574
insert_before_markers_and_inherit (string, length)
     unsigned char *string;
     register int length;
{
  if (length > 0)
    {
      register int opoint = PT;
575
      insert_1 (string, length, 1, 1);
576 577 578 579 580
      adjust_markers (opoint - 1, opoint, length);
      signal_after_change (PT-length, 0, length);
    }
}

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

583
void
584
insert_from_string_before_markers (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
585 586
     Lisp_Object string;
     register int pos, length;
587
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
588
{
589 590
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
591
      register int opoint = PT;
592 593
      insert_from_string_1 (string, pos, length, inherit);
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
594
      signal_after_change (PT-length, 0, length);
595
    }
Jim Blandy's avatar
Jim Blandy committed
596 597 598 599 600
}

/* Delete characters in current buffer
   from FROM up to (but not including) TO.  */

601
void
Jim Blandy's avatar
Jim Blandy committed
602 603
del_range (from, to)
     register int from, to;
604
{
605
  del_range_1 (from, to, 1);
606 607 608 609
}

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

610
void
611 612
del_range_1 (from, to, prepare)
     register int from, to, prepare;
Jim Blandy's avatar
Jim Blandy committed
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
{
  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);

631 632
  if (prepare)
    prepare_to_modify_buffer (from, to);
Jim Blandy's avatar
Jim Blandy committed
633

634 635 636
  record_delete (from, numdel);
  MODIFF++;

Jim Blandy's avatar
Jim Blandy committed
637
  /* Relocate point as if it were a marker.  */
Karl Heuer's avatar
Karl Heuer committed
638
  if (from < PT)
Karl Heuer's avatar
Karl Heuer committed
639
    adjust_point (from - (PT < to ? PT : to));
Jim Blandy's avatar
Jim Blandy committed
640

641
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
642
  offset_intervals (current_buffer, from, - numdel);
643

Jim Blandy's avatar
Jim Blandy committed
644 645 646 647
  /* 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);

648
  /* Adjust the overlay center as needed.  This must be done after
Karl Heuer's avatar
Karl Heuer committed
649
     adjusting the markers that bound the overlays.  */
650 651
  adjust_overlays_for_delete (from, numdel);

Jim Blandy's avatar
Jim Blandy committed
652 653 654 655 656 657 658 659 660 661
  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;

662
  evaporate_overlays (from);
Jim Blandy's avatar
Jim Blandy committed
663 664 665
  signal_after_change (from, numdel, 0);
}

666 667 668 669
/* 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.  */
670
void
671 672
modify_region (buffer, start, end)
     struct buffer *buffer;
Jim Blandy's avatar
Jim Blandy committed
673 674
     int start, end;
{
675 676 677 678 679
  struct buffer *old_buffer = current_buffer;

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

Jim Blandy's avatar
Jim Blandy committed
680 681 682 683 684 685 686
  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;
687

688
  if (MODIFF <= SAVE_MODIFF)
689
    record_first_change ();
Jim Blandy's avatar
Jim Blandy committed
690
  MODIFF++;
691

692 693
  buffer->point_before_scroll = Qnil;

694 695
  if (buffer != old_buffer)
    set_buffer_internal (old_buffer);
Jim Blandy's avatar
Jim Blandy committed
696 697 698
}

/* Check that it is okay to modify the buffer between START and END.
699 700 701
   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
702

703
void
Jim Blandy's avatar
Jim Blandy committed
704 705 706
prepare_to_modify_buffer (start, end)
     Lisp_Object start, end;
{
Jim Blandy's avatar
Jim Blandy committed
707
  if (!NILP (current_buffer->read_only))
Jim Blandy's avatar
Jim Blandy committed
708 709
    Fbarf_if_buffer_read_only ();

710
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
711
  if (BUF_INTERVALS (current_buffer) != 0)
712
    verify_interval_modification (current_buffer, start, end);
Jim Blandy's avatar
Jim Blandy committed
713 714

#ifdef CLASH_DETECTION
715
  if (!NILP (current_buffer->file_truename)
716
      && SAVE_MODIFF >= MODIFF)
717
    lock_file (current_buffer->file_truename);
Jim Blandy's avatar
Jim Blandy committed
718 719
#else
  /* At least warn if this file has changed on disk since it was visited.  */
Jim Blandy's avatar
Jim Blandy committed
720
  if (!NILP (current_buffer->filename)
721
      && SAVE_MODIFF >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
722 723
      && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
      && !NILP (Ffile_exists_p (current_buffer->filename)))
Jim Blandy's avatar
Jim Blandy committed
724 725 726 727 728
    call1 (intern ("ask-user-about-supersession-threat"),
	   current_buffer->filename);
#endif /* not CLASH_DETECTION */

  signal_before_change (start, end);
729

730 731 732 733 734 735 736 737 738
  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);

739
  Vdeactivate_mark = Qt;
Jim Blandy's avatar
Jim Blandy committed
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
}

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;
}

756 757 758 759 760 761 762 763 764 765 766 767 768 769
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;
}

770
/* Signal a change to the buffer immediately before it happens.
Jim Blandy's avatar
Jim Blandy committed
771 772 773
   START and END are the bounds of the text to be changed,
   as Lisp objects.  */

774
void
Jim Blandy's avatar
Jim Blandy committed
775 776 777 778
signal_before_change (start, end)
     Lisp_Object start, end;
{
  /* If buffer is unmodified, run a special hook for that case.  */
779
  if (SAVE_MODIFF >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
780 781 782 783
      && !NILP (Vfirst_change_hook)
      && !NILP (Vrun_hooks))
    call1 (Vrun_hooks, Qfirst_change_hook);

Jim Blandy's avatar
Jim Blandy committed
784
  /* Now in any case run the before-change-function if any.  */
Jim Blandy's avatar
Jim Blandy committed
785
  if (!NILP (Vbefore_change_function))
Jim Blandy's avatar
Jim Blandy committed
786 787 788 789 790
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object function;

      function = Vbefore_change_function;
791

Jim Blandy's avatar
Jim Blandy committed
792 793 794 795
      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
796 797 798 799
      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
800 801
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
802 803
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
804 805 806 807

      call2 (function, start, end);
      unbind_to (count, Qnil);
    }
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836

  /* 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);
    }
837 838 839

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
840
    report_overlay_modification (start, end, 0, start, end, Qnil);
Jim Blandy's avatar
Jim Blandy committed
841 842
}

843
/* Signal a change immediately after it happens.
Jim Blandy's avatar
Jim Blandy committed
844 845 846
   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.)
847 848 849
   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
850

851
void
Jim Blandy's avatar
Jim Blandy committed
852 853 854
signal_after_change (pos, lendel, lenins)
     int pos, lendel, lenins;
{
Jim Blandy's avatar
Jim Blandy committed
855
  if (!NILP (Vafter_change_function))
Jim Blandy's avatar
Jim Blandy committed
856 857 858 859 860 861 862 863 864
    {
      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);
865 866 867 868
      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
869 870
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
871 872
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
873 874 875 876 877

      call3 (function, make_number (pos), make_number (pos + lenins),
	     make_number (lendel));
      unbind_to (count, Qnil);
    }
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
  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);
    }
906 907 908

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
909
    report_overlay_modification (make_number (pos),
910 911 912 913
				 make_number (pos + lenins - lendel),
				 1,
				 make_number (pos), make_number (pos + lenins),
				 make_number (lendel));
Jim Blandy's avatar
Jim Blandy committed
914
}