1: /* Buffer insertion/deletion and gap motion for GNU Emacs. 2: Copyright (C) 1985 Richard M. Stallman. 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: 29: GapTo (pos) 30: int pos; 31: { 32: if (bf_p2 != bf_gap + bf_p1) 33: abort (); 34: 35: if (pos <= bf_s1) 36: gap_left (pos); 37: else if (pos > bf_s1 + 1) 38: gap_right (pos); 39: } 40: 41: gap_left (pos) 42: register int pos; 43: { 44: register unsigned char *to, *from; 45: register int i; 46: 47: pos--; 48: 49: if (unchanged_modified == bf_modified) 50: { 51: beg_unchanged = pos; 52: end_unchanged = bf_s1 + bf_s2 - pos; 53: } 54: else 55: { 56: if (bf_s2 < end_unchanged) 57: end_unchanged = bf_s2; 58: if (pos < beg_unchanged) 59: beg_unchanged = pos; 60: } 61: 62: adjust_markers (pos + 1, bf_s1 + 1, bf_gap); 63: 64: to = bf_p2; 65: from = bf_p1; 66: 67: i = bf_s1 + 1; 68: while (--i > pos) 69: to[i] = from[i]; 70: 71: bf_s2 += bf_s1 - pos; 72: bf_s1 = pos; 73: } 74: 75: gap_right (pos) 76: register int pos; 77: { 78: register unsigned char *to, *from; 79: register int i; 80: 81: pos--; 82: 83: if (unchanged_modified == bf_modified) 84: { 85: beg_unchanged = pos; 86: end_unchanged = bf_s1 + bf_s2 - pos; 87: } 88: else 89: { 90: if (bf_s1 + bf_s2 - pos < end_unchanged) 91: end_unchanged = bf_s1 + bf_s2 - pos; 92: if (bf_s1 < beg_unchanged) 93: beg_unchanged = bf_s1; 94: } 95: 96: adjust_markers (bf_s1 + bf_gap + 1, pos + bf_gap + 1, - bf_gap); 97: 98: from = bf_p2; 99: to = bf_p1; 100: 101: i = bf_s1; 102: while (++i <= pos) 103: to[i] = from[i]; 104: 105: bf_s2 += bf_s1 - pos; 106: bf_s1 = pos; 107: } 108: 109: /* Add `amount' to the position of every marker in the current buffer 110: whose current position is between `from' (exclusive) and `to' (inclusive). 111: Also, any markers past the outside of that interval, in the direction 112: of adjustment, are first moved back to the near end of the interval 113: and then adjusted by `amount'. */ 114: 115: adjust_markers (from, to, amount) 116: register int from, to, amount; 117: { 118: Lisp_Object marker; 119: register struct Lisp_Marker *m; 120: register int mpos; 121: 122: marker = bf_cur->markers; 123: 124: while (!NULL (marker)) 125: { 126: m = XMARKER (marker); 127: mpos = m->bufpos; 128: if (amount > 0) 129: { 130: if (mpos > to && mpos < to + amount) 131: mpos = to + amount; 132: } 133: else 134: { 135: if (mpos > from + amount && mpos <= from) 136: mpos = from + amount; 137: } 138: if (mpos > from && mpos <= to) 139: mpos += amount; 140: if (m->bufpos != mpos) 141: m->bufpos = mpos, m->modified++; 142: marker = m->chain; 143: } 144: } 145: 146: /* make sure that the gap in the current buffer is at least k 147: characters wide */ 148: 149: make_gap (k) 150: int k; 151: { 152: register unsigned char *p1, *p2, *lim; 153: 154: if (bf_gap >= k) 155: return; 156: 157: k += 2000; /* Get more than just enough */ 158: 159: p1 = (unsigned char *) realloc (bf_p1 + 1, bf_s1 + bf_s2 + k); 160: if (p1 == 0) 161: memory_full (); 162: 163: k -= bf_gap; /* Amount of increase. */ 164: 165: /* Record new location of text */ 166: bf_p1 = p1 - 1; 167: 168: /* Transfer the new free space from the end to the gap 169: by shifting the second segment upward */ 170: p2 = bf_p1 + 1 + bf_s1 + bf_s2 + bf_gap; 171: p1 = p2 + k; 172: lim = p2 - bf_s2; 173: while (lim < p2) 174: *--p1 = *--p2; 175: 176: /* Finish updating text location data */ 177: bf_gap += k; 178: bf_p2 = bf_p1 + bf_gap; 179: 180: /* Don't wait for next SetBfp; make it permanent now. */ 181: bf_cur->text = bf_text; 182: 183: /* adjust markers */ 184: adjust_markers (bf_s1 + 1, bf_s1 + bf_s2 + bf_gap + 1, k); 185: } 186: 187: /* Insert the character c before point */ 188: 189: insert_char (c) 190: unsigned char c; 191: { 192: InsCStr (&c, 1); 193: } 194: 195: /* Insert the null-terminated string s before point */ 196: 197: InsStr (s) 198: char *s; 199: { 200: InsCStr (s, strlen (s)); 201: } 202: 203: /* Insert a string of specified length before point */ 204: 205: InsCStr (string, length) 206: register unsigned char *string; 207: register length; 208: { 209: if (length<1) 210: return; 211: 212: prepare_to_modify_buffer (); 213: RecordInsert (point, length); 214: bf_modified++; 215: 216: if (point != bf_s1 + 1) 217: GapTo (point); 218: if (bf_gap < length) 219: make_gap (length); 220: 221: bcopy (string, bf_p1 + point, length); 222: 223: bf_gap -= length; 224: bf_p2 -= length; 225: bf_s1 += length; 226: point += length; 227: } 228: 229: /* like InsCStr except that all markers pointing at the place where 230: the insertion happens are adjusted to point after it. */ 231: 232: insert_before_markers (string, length) 233: unsigned char *string; 234: register int length; 235: { 236: register int opoint = point; 237: InsCStr (string, length); 238: adjust_markers (opoint - 1, opoint, length); 239: } 240: 241: /* Delete characters in current buffer 242: from `from' up to (but not incl) `to' */ 243: 244: del_range (from, to) 245: register int from, to; 246: { 247: register int numdel; 248: 249: /* Make args be valid */ 250: if (from < FirstCharacter) 251: from = FirstCharacter; 252: if (to > NumCharacters) 253: to = NumCharacters + 1; 254: 255: if ((numdel = to - from) <= 0) 256: return; 257: 258: if (from < point) 259: { 260: if (point < to) 261: point = from; 262: else 263: point -= numdel; 264: } 265: 266: /* Make sure the gap is somewhere in or next to what we are deleting */ 267: if (from - 1 > bf_s1) 268: gap_right (from); 269: if (to - 1 < bf_s1) 270: gap_left (to); 271: 272: prepare_to_modify_buffer (); 273: RecordDelete (from, numdel); 274: bf_modified++; 275: 276: /* All markers pointing between from and to, inclusive, 277: should now point at from. */ 278: adjust_markers (to, to, -numdel); 279: 280: bf_gap += numdel; 281: bf_p2 += numdel; 282: bf_s2 -= to - 1 - bf_s1; 283: bf_s1 = from - 1; 284: 285: if (bf_s1 < beg_unchanged) 286: beg_unchanged = bf_s1; 287: if (bf_s2 < end_unchanged) 288: end_unchanged = bf_s2; 289: } 290: 291: modify_region (start, end) 292: int start, end; 293: { 294: prepare_to_modify_buffer (); 295: if (start - 1 < beg_unchanged || unchanged_modified == bf_modified) 296: beg_unchanged = start - 1; 297: if (bf_s1 + bf_s2 + 1 - end < end_unchanged 298: || unchanged_modified == bf_modified) 299: end_unchanged = bf_s1 + bf_s2 + 1 - end; 300: bf_modified++; 301: } 302: 303: prepare_to_modify_buffer () 304: { 305: if (!NULL (bf_cur->read_only)) 306: Fbarf_if_buffer_read_only(); 307: 308: #ifdef CLASH_DETECTION 309: if (!NULL (bf_cur->filename) 310: && bf_cur->save_modified >= bf_modified) 311: lock_file (bf_cur->filename); 312: #endif /* CLASH_DETECTION */ 313: }