|
|
1.1 ! root 1: /* Buffer insertion/deletion and gap motion for GNU Emacs. ! 2: Copyright (C) 1985, 1986, 1990 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: /* Move gap to position `pos'. ! 27: Note that this can quit! */ ! 28: ! 29: move_gap (pos) ! 30: int pos; ! 31: { ! 32: if (pos < GPT) ! 33: gap_left (pos, 0); ! 34: else if (pos > GPT) ! 35: gap_right (pos); ! 36: } ! 37: ! 38: /* Move the gap to POS, which is less than the current GPT. ! 39: If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */ ! 40: ! 41: gap_left (pos, newgap) ! 42: register int pos; ! 43: int newgap; ! 44: { ! 45: register unsigned char *to, *from; ! 46: register int i; ! 47: int new_s1; ! 48: ! 49: pos--; ! 50: ! 51: if (!newgap) ! 52: { ! 53: if (unchanged_modified == MODIFF) ! 54: { ! 55: beg_unchanged = pos; ! 56: end_unchanged = Z - pos - 1; ! 57: } ! 58: else ! 59: { ! 60: if (Z - GPT < end_unchanged) ! 61: end_unchanged = Z - GPT; ! 62: if (pos < beg_unchanged) ! 63: beg_unchanged = pos; ! 64: } ! 65: } ! 66: ! 67: i = GPT; ! 68: to = GAP_END_ADDR; ! 69: from = GPT_ADDR; ! 70: new_s1 = GPT - BEG; ! 71: ! 72: /* Now copy the characters. To move the gap down, ! 73: copy characters up. */ ! 74: ! 75: while (1) ! 76: { ! 77: /* I gets number of characters left to copy. */ ! 78: i = new_s1 - pos; ! 79: if (i == 0) ! 80: break; ! 81: /* If a quit is requested, stop copying now. ! 82: Change POS to be where we have actually moved the gap to. */ ! 83: if (QUITP) ! 84: { ! 85: pos = new_s1; ! 86: break; ! 87: } ! 88: /* Move at most 32000 chars before checking again for a quit. */ ! 89: if (i > 32000) ! 90: i = 32000; ! 91: new_s1 -= i; ! 92: while (--i >= 0) ! 93: *--to = *--from; ! 94: } ! 95: ! 96: /* Adjust markers, and buffer data structure, to put the gap at POS. ! 97: POS is where the loop above stopped, which may be what was specified ! 98: or may be where a quit was detected. */ ! 99: adjust_markers (pos + 1, GPT, GAP_SIZE); ! 100: GPT = pos + 1; ! 101: QUIT; ! 102: } ! 103: ! 104: gap_right (pos) ! 105: register int pos; ! 106: { ! 107: register unsigned char *to, *from; ! 108: register int i; ! 109: int new_s1; ! 110: ! 111: pos--; ! 112: ! 113: if (unchanged_modified == MODIFF) ! 114: { ! 115: beg_unchanged = pos; ! 116: end_unchanged = Z - pos - 1; ! 117: } ! 118: else ! 119: { ! 120: if (Z - pos - 1 < end_unchanged) ! 121: end_unchanged = Z - pos - 1; ! 122: if (GPT - BEG < beg_unchanged) ! 123: beg_unchanged = GPT - BEG; ! 124: } ! 125: ! 126: i = GPT; ! 127: from = GAP_END_ADDR; ! 128: to = GPT_ADDR; ! 129: new_s1 = GPT - 1; ! 130: ! 131: /* Now copy the characters. To move the gap up, ! 132: copy characters down. */ ! 133: ! 134: while (1) ! 135: { ! 136: /* I gets number of characters left to copy. */ ! 137: i = pos - new_s1; ! 138: if (i == 0) ! 139: break; ! 140: /* If a quit is requested, stop copying now. ! 141: Change POS to be where we have actually moved the gap to. */ ! 142: if (QUITP) ! 143: { ! 144: pos = new_s1; ! 145: break; ! 146: } ! 147: /* Move at most 32000 chars before checking again for a quit. */ ! 148: if (i > 32000) ! 149: i = 32000; ! 150: new_s1 += i; ! 151: while (--i >= 0) ! 152: *to++ = *from++; ! 153: } ! 154: ! 155: adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE); ! 156: GPT = pos + 1; ! 157: QUIT; ! 158: } ! 159: ! 160: /* Add `amount' to the position of every marker in the current buffer ! 161: whose current position is between `from' (exclusive) and `to' (inclusive). ! 162: Also, any markers past the outside of that interval, in the direction ! 163: of adjustment, are first moved back to the near end of the interval ! 164: and then adjusted by `amount'. */ ! 165: ! 166: adjust_markers (from, to, amount) ! 167: register int from, to, amount; ! 168: { ! 169: Lisp_Object marker; ! 170: register struct Lisp_Marker *m; ! 171: register int mpos; ! 172: ! 173: marker = current_buffer->markers; ! 174: ! 175: while (!NULL (marker)) ! 176: { ! 177: m = XMARKER (marker); ! 178: mpos = m->bufpos; ! 179: if (amount > 0) ! 180: { ! 181: if (mpos > to && mpos < to + amount) ! 182: mpos = to + amount; ! 183: } ! 184: else ! 185: { ! 186: if (mpos > from + amount && mpos <= from) ! 187: mpos = from + amount; ! 188: } ! 189: if (mpos > from && mpos <= to) ! 190: mpos += amount; ! 191: m->bufpos = mpos; ! 192: marker = m->chain; ! 193: } ! 194: } ! 195: ! 196: /* Make the gap INCREMENT characters longer. */ ! 197: ! 198: make_gap (increment) ! 199: int increment; ! 200: { ! 201: unsigned char *memory; ! 202: Lisp_Object tem; ! 203: int real_gap_loc; ! 204: int old_gap_size; ! 205: ! 206: /* If we have to get more space, get enough to last a while. */ ! 207: increment += 2000; ! 208: ! 209: memory = (unsigned char *) realloc (BEG_ADDR, ! 210: Z - BEG + GAP_SIZE + increment); ! 211: if (memory == 0) ! 212: memory_full (); ! 213: BEG_ADDR = memory; ! 214: ! 215: /* Prevent quitting in move_gap. */ ! 216: tem = Vinhibit_quit; ! 217: Vinhibit_quit = Qt; ! 218: ! 219: real_gap_loc = GPT; ! 220: old_gap_size = GAP_SIZE; ! 221: /* Call the newly allocated space a gap at the end of the whole space. */ ! 222: GPT = Z + GAP_SIZE; ! 223: GAP_SIZE = increment; ! 224: /* Move the new gap down to be consecutive with the end of the old one. ! 225: This adjusts the markers properly too. */ ! 226: gap_left (real_gap_loc + old_gap_size, 1); ! 227: /* Now combine the two into one large gap. */ ! 228: GAP_SIZE += old_gap_size; ! 229: GPT = real_gap_loc; ! 230: ! 231: Vinhibit_quit = tem; ! 232: } ! 233: ! 234: /* Insert the character c before point */ ! 235: ! 236: insert_char (c) ! 237: unsigned char c; ! 238: { ! 239: insert (&c, 1); ! 240: } ! 241: ! 242: /* Insert the null-terminated string s before point */ ! 243: ! 244: InsStr (s) ! 245: char *s; ! 246: { ! 247: insert (s, strlen (s)); ! 248: } ! 249: ! 250: /* Insert a string of specified length before point. ! 251: DO NOT use this for the contents of a Lisp string! ! 252: prepare_to_modify_buffer could relocate the string. */ ! 253: ! 254: insert (string, length) ! 255: register unsigned char *string; ! 256: register length; ! 257: { ! 258: register Lisp_Object temp; ! 259: ! 260: if (length < 1) ! 261: return; ! 262: ! 263: /* Make sure point-max won't overflow after this insertion. */ ! 264: XSET (temp, Lisp_Int, length + Z); ! 265: if (length + Z != XINT (temp)) ! 266: error ("maximum buffer size exceeded"); ! 267: ! 268: prepare_to_modify_buffer (); ! 269: ! 270: if (point != GPT) ! 271: move_gap (point); ! 272: if (GAP_SIZE < length) ! 273: make_gap (length - GAP_SIZE); ! 274: ! 275: record_insert (point, length); ! 276: MODIFF++; ! 277: ! 278: bcopy (string, GPT_ADDR, length); ! 279: ! 280: GAP_SIZE -= length; ! 281: GPT += length; ! 282: ZV += length; ! 283: Z += length; ! 284: point += length; ! 285: } ! 286: ! 287: /* Function to insert part of the text of a string (STRING) consisting ! 288: of LENGTH characters at position POS. ! 289: It does not work to use `insert' for this, becase a GC could happen ! 290: before we bcopy the stuff into the buffer, and relocate the string ! 291: without insert noticing. */ ! 292: insert_from_string (string, pos, length) ! 293: Lisp_Object string; ! 294: register int pos, length; ! 295: { ! 296: register Lisp_Object temp; ! 297: struct gcpro gcpro1; ! 298: ! 299: if (length < 1) ! 300: return; ! 301: ! 302: /* Make sure point-max won't overflow after this insertion. */ ! 303: XSET (temp, Lisp_Int, length + Z); ! 304: if (length + Z != XINT (temp)) ! 305: error ("maximum buffer size exceeded"); ! 306: ! 307: GCPRO1 (string); ! 308: prepare_to_modify_buffer (); ! 309: ! 310: if (point != GPT) ! 311: move_gap (point); ! 312: if (GAP_SIZE < length) ! 313: make_gap (length - GAP_SIZE); ! 314: ! 315: record_insert (point, length); ! 316: MODIFF++; ! 317: UNGCPRO; ! 318: ! 319: bcopy (XSTRING (string)->data, GPT_ADDR, length); ! 320: ! 321: GAP_SIZE -= length; ! 322: GPT += length; ! 323: ZV += length; ! 324: Z += length; ! 325: point += length; ! 326: } ! 327: ! 328: /* Like `insert' except that all markers pointing at the place where ! 329: the insertion happens are adjusted to point after it. ! 330: Don't use this function to insert part of a Lisp string, ! 331: since gc could happen and relocate it. */ ! 332: ! 333: insert_before_markers (string, length) ! 334: unsigned char *string; ! 335: register int length; ! 336: { ! 337: register int opoint = point; ! 338: insert (string, length); ! 339: adjust_markers (opoint - 1, opoint, length); ! 340: } ! 341: ! 342: /* Insert part of a Lisp string, relocating markers after. */ ! 343: ! 344: insert_from_string_before_markers (string, pos, length) ! 345: Lisp_Object string; ! 346: register int pos, length; ! 347: { ! 348: register int opoint = point; ! 349: insert_from_string (string, pos, length); ! 350: adjust_markers (opoint - 1, opoint, length); ! 351: } ! 352: ! 353: /* Delete characters in current buffer ! 354: from `from' up to (but not incl) `to' */ ! 355: ! 356: del_range (from, to) ! 357: register int from, to; ! 358: { ! 359: register int numdel; ! 360: ! 361: /* Make args be valid */ ! 362: if (from < BEGV) ! 363: from = BEGV; ! 364: if (to > ZV) ! 365: to = ZV; ! 366: ! 367: if ((numdel = to - from) <= 0) ! 368: return; ! 369: ! 370: /* Make sure the gap is somewhere in or next to what we are deleting */ ! 371: if (from > GPT) ! 372: gap_right (from); ! 373: if (to < GPT) ! 374: gap_left (to, 0); ! 375: ! 376: prepare_to_modify_buffer (); ! 377: record_delete (from, numdel); ! 378: MODIFF++; ! 379: ! 380: /* Relocate point as if it were a marker. */ ! 381: if (from < point) ! 382: { ! 383: if (point < to) ! 384: point = from; ! 385: else ! 386: point -= numdel; ! 387: } ! 388: ! 389: /* Relocate all markers pointing into the new, larger gap ! 390: to point at the end of the text before the gap. */ ! 391: adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE); ! 392: ! 393: GAP_SIZE += numdel; ! 394: ZV -= numdel; ! 395: Z -= numdel; ! 396: GPT = from; ! 397: ! 398: if (GPT - BEG < beg_unchanged) ! 399: beg_unchanged = GPT - BEG; ! 400: if (Z - GPT < end_unchanged) ! 401: end_unchanged = Z - GPT; ! 402: } ! 403: ! 404: modify_region (start, end) ! 405: int start, end; ! 406: { ! 407: prepare_to_modify_buffer (); ! 408: if (start - 1 < beg_unchanged || unchanged_modified == MODIFF) ! 409: beg_unchanged = start - 1; ! 410: if (Z - end < end_unchanged ! 411: || unchanged_modified == MODIFF) ! 412: end_unchanged = Z - end; ! 413: MODIFF++; ! 414: } ! 415: ! 416: prepare_to_modify_buffer () ! 417: { ! 418: if (!NULL (current_buffer->read_only)) ! 419: Fbarf_if_buffer_read_only(); ! 420: ! 421: #ifdef CLASH_DETECTION ! 422: if (!NULL (current_buffer->filename) ! 423: && current_buffer->save_modified >= MODIFF) ! 424: lock_file (current_buffer->filename); ! 425: #else ! 426: /* At least warn if this file has changed on disk since it was visited. */ ! 427: if (!NULL (current_buffer->filename) ! 428: && current_buffer->save_modified >= MODIFF ! 429: && NULL (Fverify_visited_file_modtime (Fcurrent_buffer ())) ! 430: && !NULL (Ffile_exists_p (current_buffer->filename))) ! 431: call1 (intern ("ask-user-about-supersession-threat"), ! 432: current_buffer->filename); ! 433: #endif /* not CLASH_DETECTION */ ! 434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.