|
|
1.1 root 1: /* modify.c */
2:
3: /* This file contains the low-level file modification functions:
4: * delete(frommark, tomark) - removes line or portions of lines
5: * add(frommark, text) - inserts new text
6: * change(frommark, tomark, text) - delete, then add
7: */
8:
9: #include "config.h"
10: #include "vi.h"
11:
12: #ifdef DEBUG
13: # include <stdio.h>
14: static FILE *dbg;
15:
16: /*VARARGS1*/
17: debout(msg, arg1, arg2, arg3, arg4, arg5)
18: char *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
19: {
20: if (!dbg)
21: {
22: dbg = fopen("debug.out", "w");
23: setbuf(dbg, (FILE *)0);
24: }
25: fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
26: }
27: #endif /* DEBUG */
28:
29: /* delete a range of text from the file */
30: void delete(frommark, tomark)
31: MARK frommark; /* first char to be deleted */
32: MARK tomark; /* AFTER last char to be deleted */
33: {
34: int i; /* used to move thru logical blocks */
35: REG char *scan; /* used to scan thru text of the blk */
36: REG char *cpy; /* used when copying chars */
37: BLK *blk; /* a text block */
38: long l; /* a line number */
39: MARK m; /* a traveling version of frommark */
40:
41: #ifdef DEBUG
42: debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
43: #endif
44:
45: /* if not deleting anything, quit now */
46: if (frommark == tomark)
47: {
48: return;
49: }
50:
51: /* This is a change */
52: changes++;
53: significant = TRUE;
54:
55: /* if this is a multi-line change, then we'll have to redraw */
56: if (markline(frommark) != markline(tomark))
57: {
58: mustredraw = TRUE;
59: redrawrange(markline(frommark), markline(tomark), markline(frommark));
60: }
61:
62: /* adjust marks 'a through 'z and '' as needed */
63: l = markline(tomark);
64: for (i = 0; i < NMARKS; i++)
65: {
66: if (mark[i] < frommark)
67: {
68: continue;
69: }
70: else if (mark[i] < tomark)
71: {
72: mark[i] = MARK_UNSET;
73: }
74: else if (markline(mark[i]) == l)
75: {
76: if (markline(frommark) == l)
77: {
78: mark[i] -= markidx(tomark) - markidx(frommark);
79: }
80: else
81: {
82: mark[i] -= markidx(tomark);
83: }
84: }
85: else
86: {
87: mark[i] -= MARK_AT_LINE(l - markline(frommark));
88: }
89: }
90:
91: /* Reporting... */
92: if (markidx(frommark) == 0 && markidx(tomark) == 0)
93: {
94: rptlines = markline(tomark) - markline(frommark);
95: rptlabel = "deleted";
96: }
97:
98: /* find the block containing frommark */
99: l = markline(frommark);
100: for (i = 1; lnum[i] < l; i++)
101: {
102: }
103:
104: /* process each affected block... */
105: for (m = frommark;
106: m < tomark && lnum[i] < INFINITY;
107: m = MARK_AT_LINE(lnum[i - 1] + 1))
108: {
109: /* fetch the block */
110: blk = blkget(i);
111:
112: /* find the mark in the block */
113: scan = blk->c;
114: for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
115: {
116: while (*scan++ != '\n')
117: {
118: }
119: }
120: scan += markidx(m);
121:
122: /* figure out where the changes to this block end */
123: if (markline(tomark) > lnum[i])
124: {
125: cpy = blk->c + BLKSIZE;
126: }
127: else if (markline(tomark) == markline(m))
128: {
129: cpy = scan - markidx(m) + markidx(tomark);
130: }
131: else
132: {
133: cpy = scan;
134: for (l = markline(tomark) - markline(m);
135: l > 0;
136: l--)
137: {
138: while (*cpy++ != '\n')
139: {
140: }
141: }
142: cpy += markidx(tomark);
143: }
144:
145: /* delete the stuff by moving chars within this block */
146: while (cpy < blk->c + BLKSIZE)
147: {
148: *scan++ = *cpy++;
149: }
150: while (scan < blk->c + BLKSIZE)
151: {
152: *scan++ = '\0';
153: }
154:
155: /* adjust tomark to allow for lines deleted from this block */
156: tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
157:
158: /* if this block isn't empty now, then advance i */
159: if (*blk->c)
160: {
161: i++;
162: }
163:
164: /* the buffer has changed. Update hdr and lnum. */
165: blkdirty(blk);
166: }
167:
168: /* must have at least 1 line */
169: if (nlines == 0)
170: {
171: blk = blkadd(1);
172: blk->c[0] = '\n';
173: blkdirty(blk);
174: cursor = MARK_FIRST;
175: }
176: }
177:
178:
179: /* add some text at a specific place in the file */
180: void add(atmark, newtext)
181: MARK atmark; /* where to insert the new text */
182: char *newtext; /* NUL-terminated string to insert */
183: {
184: REG char *scan; /* used to move through string */
185: REG char *build; /* used while copying chars */
186: int addlines; /* number of lines we're adding */
187: int lastpart; /* size of last partial line */
188: BLK *blk; /* the block to be modified */
189: int blkno; /* the logical block# of (*blk) */
190: REG char *newptr; /* where new text starts in blk */
191: BLK buf; /* holds chars from orig blk */
192: BLK linebuf; /* holds part of line that didn't fit */
193: BLK *following; /* the BLK following the last BLK */
194: int i;
195: long l;
196:
197: #ifdef DEBUG
198: debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext);
199: #endif
200: #ifdef lint
201: buf.c[0] = 0;
202: #endif
203: /* if not adding anything, return now */
204: if (!*newtext)
205: {
206: return;
207: }
208:
209: /* This is a change */
210: changes++;
211: significant = TRUE;
212:
213: /* count the number of lines in the new text */
214: for (scan = newtext, lastpart = addlines = 0; *scan; )
215: {
216: if (*scan++ == '\n')
217: {
218: addlines++;
219: lastpart = 0;
220: }
221: else
222: {
223: lastpart++;
224: }
225: }
226:
227: /* Reporting... */
228: if (lastpart == 0 && markidx(atmark) == 0)
229: {
230: rptlines = addlines;
231: rptlabel = "added";
232: }
233:
234: /* extract the line# from atmark */
235: l = markline(atmark);
236:
237: /* if more than 0 lines, then we'll have to redraw the screen */
238: if (addlines > 0)
239: {
240: mustredraw = TRUE;
241: if (markidx(atmark) == 0 && lastpart == 0)
242: {
243: redrawrange(l, l, l + addlines);
244: }
245: else
246: {
247: /* make sure the last line gets redrawn -- it was
248: * split, so its appearance has changed
249: */
250: redrawrange(l, l + 1L, l + addlines + 1L);
251: }
252: }
253:
254: /* adjust marks 'a through 'z and '' as needed */
255: for (i = 0; i < NMARKS; i++)
256: {
257: if (mark[i] < atmark)
258: {
259: /* earlier line, or earlier in same line: no change */
260: continue;
261: }
262: else if (markline(mark[i]) > l)
263: {
264: /* later line: move down a whole number of lines */
265: mark[i] += MARK_AT_LINE(addlines);
266: }
267: else
268: {
269: /* later in same line */
270: if (addlines > 0)
271: {
272: /* multi-line add, which split this line:
273: * move down, and possibly left or right,
274: * depending on where the split was and how
275: * much text was inserted after the last \n
276: */
277: mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
278: }
279: else
280: {
281: /* totally within this line: move right */
282: mark[i] += lastpart;
283: }
284: }
285: }
286:
287: /* get the block to be modified */
288: for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
289: {
290: }
291: blk = blkget(blkno);
292: buf = *blk;
293:
294: /* figure out where the new text starts */
295: for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
296: l > 0;
297: l--)
298: {
299: while (*newptr++ != '\n')
300: {
301: }
302: }
303: newptr += markidx(atmark);
304:
305: /* keep start of old block */
306: build = blk->c + (newptr - buf.c);
307:
308: /* fill this block (or blocks) from the newtext string */
309: while (*newtext)
310: {
311: while (*newtext && build < blk->c + BLKSIZE - 1)
312: {
313: *build++ = *newtext++;
314: }
315: if (*newtext)
316: {
317: /* save the excess */
318: for (scan = linebuf.c + BLKSIZE;
319: build > blk->c && build[-1] != '\n';
320: )
321: {
322: *--scan = *--build;
323: }
324:
325: /* write the block */
326: while (build < blk->c + BLKSIZE)
327: {
328: *build++ = '\0';
329: }
330: blkdirty(blk);
331:
332: /* add another block */
333: blkno++;
334: blk = blkadd(blkno);
335:
336: /* copy in the excess from last time */
337: for (build = blk->c; scan < linebuf.c + BLKSIZE; )
338: {
339: *build++ = *scan++;
340: }
341: }
342: }
343:
344: /* fill this block(s) from remainder of orig block */
345: while (newptr < buf.c + BLKSIZE && *newptr)
346: {
347: while (newptr < buf.c + BLKSIZE
348: && *newptr
349: && build < blk->c + BLKSIZE - 1)
350: {
351: *build++ = *newptr++;
352: }
353: if (newptr < buf.c + BLKSIZE && *newptr)
354: {
355: /* save the excess */
356: for (scan = linebuf.c + BLKSIZE;
357: build > blk->c && build[-1] != '\n';
358: )
359: {
360: *--scan = *--build;
361: }
362:
363: /* write the block */
364: while (build < blk->c + BLKSIZE)
365: {
366: *build++ = '\0';
367: }
368: blkdirty(blk);
369:
370: /* add another block */
371: blkno++;
372: blk = blkadd(blkno);
373:
374: /* copy in the excess from last time */
375: for (build = blk->c; scan < linebuf.c + BLKSIZE; )
376: {
377: *build++ = *scan++;
378: }
379: }
380: }
381:
382: /* see if we can combine our last block with the following block */
383: if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
384: {
385: /* hey, we probably can! Get the following block & see... */
386: following = blkget(blkno + 1);
387: if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
388: {
389: /* we can! Copy text from following to blk */
390: for (scan = following->c; *scan; )
391: {
392: *build++ = *scan++;
393: }
394: while (build < blk->c + BLKSIZE)
395: {
396: *build++ = '\0';
397: }
398: blkdirty(blk);
399:
400: /* pretend the following was the last blk */
401: blk = following;
402: build = blk->c;
403: }
404: }
405:
406: /* that last block is dirty by now */
407: while (build < blk->c + BLKSIZE)
408: {
409: *build++ = '\0';
410: }
411: blkdirty(blk);
412: }
413:
414:
415: /* change the text of a file */
416: void change(frommark, tomark, newtext)
417: MARK frommark, tomark;
418: char *newtext;
419: {
420: int i;
421: long l;
422: char *text;
423: BLK *blk;
424:
425: #ifdef DEBUG
426: debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
427: #endif
428:
429: /* optimize for single-character replacement */
430: if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
431: {
432: /* find the block containing frommark */
433: l = markline(frommark);
434: for (i = 1; lnum[i] < l; i++)
435: {
436: }
437:
438: /* get the block */
439: blk = blkget(i);
440:
441: /* find the line within the block */
442: for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
443: {
444: if (*text == '\n')
445: {
446: i--;
447: }
448: }
449:
450: /* replace the char */
451: text += markidx(frommark);
452: if (*text == newtext[0])
453: {
454: /* no change was needed - same char */
455: return;
456: }
457: else if (*text != '\n')
458: {
459: /* This is a change */
460: changes++;
461: significant = TRUE;
462: ChangeText
463: {
464: *text = newtext[0];
465: blkdirty(blk);
466: }
467: return;
468: }
469: /* else it is a complex change involving newline... */
470: }
471:
472: /* couldn't optimize, so do delete & add */
473: ChangeText
474: {
475: delete(frommark, tomark);
476: add(frommark, newtext);
477: rptlabel = "changed";
478: }
479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.