source: trunk/minix/commands/elvis/modify.c@ 21

Last change on this file since 21 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.6 KB
Line 
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>
14static FILE *dbg;
15
16/*VARARGS1*/
17debout(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 */
32void 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 */
178void 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 */
410void 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}
Note: See TracBrowser for help on using the repository browser.