|
|
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.