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