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