Import of original zoneinfo code and database - tzcode
[minix3.git] / commands / elvis / modify.c
blobaf7914601018ea5adc579ceda9346f4e9bc009a3
1 /* modify.c */
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 */
9 #include "config.h"
10 #include "vi.h"
12 #ifdef DEBUG2
13 # include <stdio.h>
14 static FILE *dbg;
16 /*VARARGS1*/
17 debout(msg, arg1, arg2, arg3, arg4, arg5)
18 char *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
20 if (!dbg)
22 dbg = fopen("debug.out", "w");
23 if (!dbg)
24 return;
25 setbuf(dbg, (FILE *)0);
27 fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
29 #endif /* DEBUG2 */
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 */
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 */
43 #ifdef DEBUG2
44 debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
45 #endif
47 /* if not deleting anything, quit now */
48 if (frommark == tomark)
50 return;
53 /* This is a change */
54 changes++;
55 significant = TRUE;
57 /* supply clues to the redraw module */
58 redrawrange(markline(frommark), markline(tomark), markline(frommark));
60 /* adjust marks 'a through 'z and '' as needed */
61 l = markline(tomark);
62 for (i = 0; i < NMARKS; i++)
64 if (mark[i] < frommark)
66 continue;
68 else if (mark[i] < tomark)
70 mark[i] = MARK_UNSET;
72 else if (markline(mark[i]) == l)
74 if (markline(frommark) == l)
76 mark[i] -= markidx(tomark) - markidx(frommark);
78 else
80 mark[i] -= markidx(tomark);
83 else
85 mark[i] -= MARK_AT_LINE(l - markline(frommark));
89 /* Reporting... */
90 if (markidx(frommark) == 0 && markidx(tomark) == 0)
92 rptlines = markline(tomark) - markline(frommark);
93 rptlabel = "deleted";
96 /* find the block containing frommark */
97 l = markline(frommark);
98 for (i = 1; lnum[i] < l; i++)
102 /* process each affected block... */
103 for (m = frommark;
104 m < tomark && lnum[i] < INFINITY;
105 m = MARK_AT_LINE(lnum[i - 1] + 1))
107 /* fetch the block */
108 blk = blkget(i);
110 /* find the mark in the block */
111 scan = blk->c;
112 for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
114 while (*scan++ != '\n')
118 scan += markidx(m);
120 /* figure out where the changes to this block end */
121 if (markline(tomark) > lnum[i])
123 cpy = blk->c + BLKSIZE;
125 else if (markline(tomark) == markline(m))
127 cpy = scan - markidx(m) + markidx(tomark);
129 else
131 cpy = scan;
132 for (l = markline(tomark) - markline(m);
133 l > 0;
134 l--)
136 while (*cpy++ != '\n')
140 cpy += markidx(tomark);
143 /* delete the stuff by moving chars within this block */
144 while (cpy < blk->c + BLKSIZE)
146 *scan++ = *cpy++;
148 while (scan < blk->c + BLKSIZE)
150 *scan++ = '\0';
153 /* adjust tomark to allow for lines deleted from this block */
154 tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
156 /* if this block isn't empty now, then advance i */
157 if (*blk->c)
159 i++;
162 /* the buffer has changed. Update hdr and lnum. */
163 blkdirty(blk);
166 /* must have at least 1 line */
167 if (nlines == 0)
169 blk = blkadd(1);
170 blk->c[0] = '\n';
171 blkdirty(blk);
172 cursor = MARK_FIRST;
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 */
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;
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)
204 return;
207 /* This is a change */
208 changes++;
209 significant = TRUE;
211 /* count the number of lines in the new text */
212 for (scan = newtext, lastpart = addlines = 0; *scan; )
214 if (*scan++ == '\n')
216 addlines++;
217 lastpart = 0;
219 else
221 lastpart++;
225 /* Reporting... */
226 if (lastpart == 0 && markidx(atmark) == 0)
228 rptlines = addlines;
229 rptlabel = "added";
232 /* extract the line# from atmark */
233 l = markline(atmark);
235 /* supply clues to the redraw module */
236 if ((markidx(atmark) == 0 && lastpart == 0) || addlines == 0)
238 redrawrange(l, l, l + addlines);
240 else
242 /* make sure the last line gets redrawn -- it was
243 * split, so its appearance has changed
245 redrawrange(l, l + 1L, l + addlines + 1L);
248 /* adjust marks 'a through 'z and '' as needed */
249 for (i = 0; i < NMARKS; i++)
251 if (mark[i] < atmark)
253 /* earlier line, or earlier in same line: no change */
254 continue;
256 else if (markline(mark[i]) > l)
258 /* later line: move down a whole number of lines */
259 mark[i] += MARK_AT_LINE(addlines);
261 else
263 /* later in same line */
264 if (addlines > 0)
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
271 mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
273 else
275 /* totally within this line: move right */
276 mark[i] += lastpart;
281 /* get the block to be modified */
282 for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
285 blk = blkget(blkno);
286 buf = *blk;
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--)
293 while (*newptr++ != '\n')
297 newptr += markidx(atmark);
299 /* keep start of old block */
300 build = blk->c + (int)(newptr - buf.c);
302 /* fill this block (or blocks) from the newtext string */
303 while (*newtext)
305 while (*newtext && build < blk->c + BLKSIZE - 1)
307 *build++ = *newtext++;
309 if (*newtext)
311 /* save the excess */
312 for (scan = linebuf.c + BLKSIZE;
313 build > blk->c && build[-1] != '\n';
316 *--scan = *--build;
319 /* write the block */
320 while (build < blk->c + BLKSIZE)
322 *build++ = '\0';
324 blkdirty(blk);
326 /* add another block */
327 blkno++;
328 blk = blkadd(blkno);
330 /* copy in the excess from last time */
331 for (build = blk->c; scan < linebuf.c + BLKSIZE; )
333 *build++ = *scan++;
338 /* fill this block(s) from remainder of orig block */
339 while (newptr < buf.c + BLKSIZE && *newptr)
341 while (newptr < buf.c + BLKSIZE
342 && *newptr
343 && build < blk->c + BLKSIZE - 1)
345 *build++ = *newptr++;
347 if (newptr < buf.c + BLKSIZE && *newptr)
349 /* save the excess */
350 for (scan = linebuf.c + BLKSIZE;
351 build > blk->c && build[-1] != '\n';
354 *--scan = *--build;
357 /* write the block */
358 while (build < blk->c + BLKSIZE)
360 *build++ = '\0';
362 blkdirty(blk);
364 /* add another block */
365 blkno++;
366 blk = blkadd(blkno);
368 /* copy in the excess from last time */
369 for (build = blk->c; scan < linebuf.c + BLKSIZE; )
371 *build++ = *scan++;
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))
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)
383 /* we can! Copy text from following to blk */
384 for (scan = following->c; *scan; )
386 *build++ = *scan++;
388 while (build < blk->c + BLKSIZE)
390 *build++ = '\0';
392 blkdirty(blk);
394 /* pretend the following was the last blk */
395 blk = following;
396 build = blk->c;
400 /* that last block is dirty by now */
401 while (build < blk->c + BLKSIZE)
403 *build++ = '\0';
405 blkdirty(blk);
409 /* change the text of a file */
410 void change(frommark, tomark, newtext)
411 MARK frommark, tomark;
412 char *newtext;
414 int i;
415 long l;
416 char *text;
417 BLK *blk;
419 #ifdef DEBUG2
420 debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
421 #endif
423 /* optimize for single-character replacement */
424 if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
426 /* find the block containing frommark */
427 l = markline(frommark);
428 for (i = 1; lnum[i] < l; i++)
432 /* get the block */
433 blk = blkget(i);
435 /* find the line within the block */
436 for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
438 if (*text == '\n')
440 i--;
444 /* replace the char */
445 text += markidx(frommark);
446 if (*text == newtext[0])
448 /* no change was needed - same char */
449 return;
451 else if (*text != '\n')
453 /* This is a change */
454 changes++;
455 significant = TRUE;
456 ChangeText
458 *text = newtext[0];
459 blkdirty(blk);
461 redrawrange(markline(frommark), markline(tomark), markline(frommark));
462 return;
464 /* else it is a complex change involving newline... */
467 /* couldn't optimize, so do delete & add */
468 ChangeText
470 delete(frommark, tomark);
471 add(frommark, newtext);
472 rptlabel = "changed";