|
|
1.1 ! root 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 distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "lisp.h" ! 24: #include "buffer.h" ! 25: #include "window.h" ! 26: ! 27: /* Move gap to position `pos'. ! 28: Note that this can quit! */ ! 29: ! 30: move_gap (pos) ! 31: int pos; ! 32: { ! 33: if (bf_p2 != bf_gap + bf_p1) ! 34: abort (); ! 35: ! 36: if (pos <= bf_s1) ! 37: gap_left (pos); ! 38: else if (pos > bf_s1 + 1) ! 39: gap_right (pos); ! 40: } ! 41: ! 42: gap_left (pos) ! 43: register int pos; ! 44: { ! 45: register unsigned char *to, *from; ! 46: register int i; ! 47: int new_s1; ! 48: ! 49: pos--; ! 50: ! 51: if (unchanged_modified == bf_modified) ! 52: { ! 53: beg_unchanged = pos; ! 54: end_unchanged = bf_s1 + bf_s2 - pos; ! 55: } ! 56: else ! 57: { ! 58: if (bf_s2 < end_unchanged) ! 59: end_unchanged = bf_s2; ! 60: if (pos < beg_unchanged) ! 61: beg_unchanged = pos; ! 62: } ! 63: ! 64: i = bf_s1 + 1; ! 65: to = &bf_p2[i]; ! 66: from = &bf_p1[i]; ! 67: new_s1 = bf_s1; ! 68: ! 69: /* Now copy the characters. To move the gap down, ! 70: copy characters up. */ ! 71: ! 72: while (1) ! 73: { ! 74: /* I gets number of characters left to copy. */ ! 75: i = new_s1 - pos; ! 76: if (i == 0) ! 77: break; ! 78: /* If a quit is requested, stop copying now. ! 79: Change POS to be where we have actually moved the gap to. */ ! 80: if (QUITP) ! 81: { ! 82: pos = new_s1; ! 83: break; ! 84: } ! 85: /* Move at most 32000 chars before checking again for a quit. */ ! 86: if (i > 32000) ! 87: i = 32000; ! 88: new_s1 -= i; ! 89: while (--i >= 0) ! 90: *--to = *--from; ! 91: } ! 92: ! 93: /* Adjust markers, and buffer data structure, to put the gap at POS. ! 94: POS is where the loop above stopped, which may be what was specified ! 95: or may be where a quit was detected. */ ! 96: adjust_markers (pos + 1, bf_s1 + 1, bf_gap); ! 97: bf_s2 += bf_s1 - pos; ! 98: bf_s1 = pos; ! 99: QUIT; ! 100: } ! 101: ! 102: gap_right (pos) ! 103: register int pos; ! 104: { ! 105: register unsigned char *to, *from; ! 106: register int i; ! 107: int new_s1; ! 108: ! 109: pos--; ! 110: ! 111: if (unchanged_modified == bf_modified) ! 112: { ! 113: beg_unchanged = pos; ! 114: end_unchanged = bf_s1 + bf_s2 - pos; ! 115: } ! 116: else ! 117: { ! 118: if (bf_s1 + bf_s2 - pos < end_unchanged) ! 119: end_unchanged = bf_s1 + bf_s2 - pos; ! 120: if (bf_s1 < beg_unchanged) ! 121: beg_unchanged = bf_s1; ! 122: } ! 123: ! 124: i = bf_s1 + 1; ! 125: from = &bf_p2[i]; ! 126: to = &bf_p1[i]; ! 127: new_s1 = bf_s1; ! 128: ! 129: /* Now copy the characters. To move the gap up, ! 130: copy characters down. */ ! 131: ! 132: while (1) ! 133: { ! 134: /* I gets number of characters left to copy. */ ! 135: i = pos - new_s1; ! 136: if (i == 0) ! 137: break; ! 138: /* If a quit is requested, stop copying now. ! 139: Change POS to be where we have actually moved the gap to. */ ! 140: if (QUITP) ! 141: { ! 142: pos = new_s1; ! 143: break; ! 144: } ! 145: /* Move at most 32000 chars before checking again for a quit. */ ! 146: if (i > 32000) ! 147: i = 32000; ! 148: new_s1 += i; ! 149: while (--i >= 0) ! 150: *to++ = *from++; ! 151: } ! 152: ! 153: adjust_markers (bf_s1 + bf_gap + 1, pos + bf_gap + 1, - bf_gap); ! 154: bf_s2 += bf_s1 - pos; ! 155: bf_s1 = pos; ! 156: QUIT; ! 157: } ! 158: ! 159: /* Add `amount' to the position of every marker in the current buffer ! 160: whose current position is between `from' (exclusive) and `to' (inclusive). ! 161: Also, any markers past the outside of that interval, in the direction ! 162: of adjustment, are first moved back to the near end of the interval ! 163: and then adjusted by `amount'. */ ! 164: ! 165: adjust_markers (from, to, amount) ! 166: register int from, to, amount; ! 167: { ! 168: Lisp_Object marker; ! 169: register struct Lisp_Marker *m; ! 170: register int mpos; ! 171: ! 172: marker = bf_cur->markers; ! 173: ! 174: while (!NULL (marker)) ! 175: { ! 176: m = XMARKER (marker); ! 177: mpos = m->bufpos; ! 178: if (amount > 0) ! 179: { ! 180: if (mpos > to && mpos < to + amount) ! 181: mpos = to + amount; ! 182: } ! 183: else ! 184: { ! 185: if (mpos > from + amount && mpos <= from) ! 186: mpos = from + amount; ! 187: } ! 188: if (mpos > from && mpos <= to) ! 189: mpos += amount; ! 190: if (m->bufpos != mpos) ! 191: m->bufpos = mpos, m->modified++; ! 192: marker = m->chain; ! 193: } ! 194: } ! 195: ! 196: /* make sure that the gap in the current buffer is at least k ! 197: characters wide */ ! 198: ! 199: make_gap (k) ! 200: int k; ! 201: { ! 202: register unsigned char *p1, *p2, *lim; ! 203: ! 204: if (bf_gap >= k) ! 205: return; ! 206: ! 207: k += 2000; /* Get more than just enough */ ! 208: ! 209: p1 = (unsigned char *) realloc (bf_p1 + 1, bf_s1 + bf_s2 + k); ! 210: if (p1 == 0) ! 211: memory_full (); ! 212: ! 213: k -= bf_gap; /* Amount of increase. */ ! 214: ! 215: /* Record new location of text */ ! 216: bf_p1 = p1 - 1; ! 217: ! 218: /* Transfer the new free space from the end to the gap ! 219: by shifting the second segment upward */ ! 220: p2 = bf_p1 + 1 + bf_s1 + bf_s2 + bf_gap; ! 221: p1 = p2 + k; ! 222: lim = p2 - bf_s2; ! 223: while (lim < p2) ! 224: *--p1 = *--p2; ! 225: ! 226: /* Finish updating text location data */ ! 227: bf_gap += k; ! 228: bf_p2 = bf_p1 + bf_gap; ! 229: ! 230: /* Don't wait for next SetBfp; make it permanent now. */ ! 231: bf_cur->text = bf_text; ! 232: ! 233: /* adjust markers */ ! 234: adjust_markers (bf_s1 + 1, bf_s1 + bf_s2 + bf_gap + 1, k); ! 235: } ! 236: ! 237: /* Insert the character c before point */ ! 238: ! 239: insert_char (c) ! 240: unsigned char c; ! 241: { ! 242: InsCStr (&c, 1); ! 243: } ! 244: ! 245: /* Insert the null-terminated string s before point */ ! 246: ! 247: InsStr (s) ! 248: char *s; ! 249: { ! 250: InsCStr (s, strlen (s)); ! 251: } ! 252: ! 253: /* Insert a string of specified length before point */ ! 254: ! 255: InsCStr (string, length) ! 256: register unsigned char *string; ! 257: register length; ! 258: { ! 259: if (length<1) ! 260: return; ! 261: ! 262: prepare_to_modify_buffer (); ! 263: ! 264: if (point != bf_s1 + 1) ! 265: move_gap (point); ! 266: if (bf_gap < length) ! 267: make_gap (length); ! 268: ! 269: record_insert (point, length); ! 270: bf_modified++; ! 271: ! 272: bcopy (string, bf_p1 + point, length); ! 273: ! 274: bf_gap -= length; ! 275: bf_p2 -= length; ! 276: bf_s1 += length; ! 277: point += length; ! 278: } ! 279: ! 280: /* like InsCStr except that all markers pointing at the place where ! 281: the insertion happens are adjusted to point after it. */ ! 282: ! 283: insert_before_markers (string, length) ! 284: unsigned char *string; ! 285: register int length; ! 286: { ! 287: register int opoint = point; ! 288: InsCStr (string, length); ! 289: adjust_markers (opoint - 1, opoint, length); ! 290: } ! 291: ! 292: /* Delete characters in current buffer ! 293: from `from' up to (but not incl) `to' */ ! 294: ! 295: del_range (from, to) ! 296: register int from, to; ! 297: { ! 298: register int numdel; ! 299: ! 300: /* Make args be valid */ ! 301: if (from < FirstCharacter) ! 302: from = FirstCharacter; ! 303: if (to > NumCharacters) ! 304: to = NumCharacters + 1; ! 305: ! 306: if ((numdel = to - from) <= 0) ! 307: return; ! 308: ! 309: /* Make sure the gap is somewhere in or next to what we are deleting */ ! 310: if (from - 1 > bf_s1) ! 311: gap_right (from); ! 312: if (to - 1 < bf_s1) ! 313: gap_left (to); ! 314: ! 315: prepare_to_modify_buffer (); ! 316: record_delete (from, numdel); ! 317: bf_modified++; ! 318: ! 319: /* Relocate point as if it were a marker. */ ! 320: if (from < point) ! 321: { ! 322: if (point < to) ! 323: point = from; ! 324: else ! 325: point -= numdel; ! 326: } ! 327: ! 328: /* Relocate all markers pointing into the new, larger gap ! 329: to point at the end of the text before the gap. */ ! 330: adjust_markers (to + bf_gap, to + bf_gap, - numdel - bf_gap); ! 331: ! 332: bf_gap += numdel; ! 333: bf_p2 += numdel; ! 334: bf_s2 -= to - 1 - bf_s1; ! 335: bf_s1 = from - 1; ! 336: ! 337: if (bf_s1 < beg_unchanged) ! 338: beg_unchanged = bf_s1; ! 339: if (bf_s2 < end_unchanged) ! 340: end_unchanged = bf_s2; ! 341: } ! 342: ! 343: modify_region (start, end) ! 344: int start, end; ! 345: { ! 346: prepare_to_modify_buffer (); ! 347: if (start - 1 < beg_unchanged || unchanged_modified == bf_modified) ! 348: beg_unchanged = start - 1; ! 349: if (bf_s1 + bf_s2 + 1 - end < end_unchanged ! 350: || unchanged_modified == bf_modified) ! 351: end_unchanged = bf_s1 + bf_s2 + 1 - end; ! 352: bf_modified++; ! 353: } ! 354: ! 355: prepare_to_modify_buffer () ! 356: { ! 357: if (!NULL (bf_cur->read_only)) ! 358: Fbarf_if_buffer_read_only(); ! 359: ! 360: #ifdef CLASH_DETECTION ! 361: if (!NULL (bf_cur->filename) ! 362: && bf_cur->save_modified >= bf_modified) ! 363: lock_file (bf_cur->filename); ! 364: #else ! 365: /* At least warn if this file has changed on disk since it was visited. */ ! 366: if (!NULL (bf_cur->filename) ! 367: && bf_cur->save_modified >= bf_modified ! 368: && NULL (Fverify_visited_file_modtime (Fcurrent_buffer ())) ! 369: && !NULL (Ffile_exists_p (bf_cur->filename))) ! 370: call1 (intern ("ask-user-about-supersession-threat"), ! 371: bf_cur->filename); ! 372: #endif /* not CLASH_DETECTION */ ! 373: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.