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
17 debout(msg
, arg1
, arg2
, arg3
, arg4
, arg5
)
18 char *msg
, *arg1
, *arg2
, *arg3
, *arg4
, *arg5
;
22 dbg
= fopen("debug.out", "w");
25 setbuf(dbg
, (FILE *)0);
27 fprintf(dbg
, msg
, arg1
, arg2
, arg3
, arg4
, arg5
);
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 */
44 debout("delete(%ld.%d, %ld.%d)\n", markline(frommark
), markidx(frommark
), markline(tomark
), markidx(tomark
));
47 /* if not deleting anything, quit now */
48 if (frommark
== tomark
)
53 /* This is a change */
57 /* supply clues to the redraw module */
58 redrawrange(markline(frommark
), markline(tomark
), markline(frommark
));
60 /* adjust marks 'a through 'z and '' as needed */
62 for (i
= 0; i
< NMARKS
; i
++)
64 if (mark
[i
] < frommark
)
68 else if (mark
[i
] < tomark
)
72 else if (markline(mark
[i
]) == l
)
74 if (markline(frommark
) == l
)
76 mark
[i
] -= markidx(tomark
) - markidx(frommark
);
80 mark
[i
] -= markidx(tomark
);
85 mark
[i
] -= MARK_AT_LINE(l
- markline(frommark
));
90 if (markidx(frommark
) == 0 && markidx(tomark
) == 0)
92 rptlines
= markline(tomark
) - markline(frommark
);
96 /* find the block containing frommark */
97 l
= markline(frommark
);
98 for (i
= 1; lnum
[i
] < l
; i
++)
102 /* process each affected block... */
104 m
< tomark
&& lnum
[i
] < INFINITY
;
105 m
= MARK_AT_LINE(lnum
[i
- 1] + 1))
107 /* fetch the block */
110 /* find the mark in the block */
112 for (l
= markline(m
) - lnum
[i
- 1] - 1; l
> 0; l
--)
114 while (*scan
++ != '\n')
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
);
132 for (l
= markline(tomark
) - markline(m
);
136 while (*cpy
++ != '\n')
140 cpy
+= markidx(tomark
);
143 /* delete the stuff by moving chars within this block */
144 while (cpy
< blk
->c
+ BLKSIZE
)
148 while (scan
< blk
->c
+ BLKSIZE
)
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 */
162 /* the buffer has changed. Update hdr and lnum. */
166 /* must have at least 1 line */
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 */
196 debout("add(%ld.%d, \"%s\")\n", markline(atmark
), markidx(atmark
), newtext
);
201 /* if not adding anything, return now */
207 /* This is a change */
211 /* count the number of lines in the new text */
212 for (scan
= newtext
, lastpart
= addlines
= 0; *scan
; )
226 if (lastpart
== 0 && markidx(atmark
) == 0)
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
);
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 */
256 else if (markline(mark
[i
]) > l
)
258 /* later line: move down a whole number of lines */
259 mark
[i
] += MARK_AT_LINE(addlines
);
263 /* later in same line */
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
);
275 /* totally within this line: move right */
281 /* get the block to be modified */
282 for (blkno
= 1; lnum
[blkno
] < l
&& lnum
[blkno
+ 1] < INFINITY
; blkno
++)
288 /* figure out where the new text starts */
289 for (newptr
= buf
.c
, l
= markline(atmark
) - lnum
[blkno
- 1] - 1;
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 */
305 while (*newtext
&& build
< blk
->c
+ BLKSIZE
- 1)
307 *build
++ = *newtext
++;
311 /* save the excess */
312 for (scan
= linebuf
.c
+ BLKSIZE
;
313 build
> blk
->c
&& build
[-1] != '\n';
319 /* write the block */
320 while (build
< blk
->c
+ BLKSIZE
)
326 /* add another block */
330 /* copy in the excess from last time */
331 for (build
= blk
->c
; scan
< linebuf
.c
+ BLKSIZE
; )
338 /* fill this block(s) from remainder of orig block */
339 while (newptr
< buf
.c
+ BLKSIZE
&& *newptr
)
341 while (newptr
< buf
.c
+ BLKSIZE
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';
357 /* write the block */
358 while (build
< blk
->c
+ BLKSIZE
)
364 /* add another block */
368 /* copy in the excess from last time */
369 for (build
= blk
->c
; scan
< linebuf
.c
+ BLKSIZE
; )
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
; )
388 while (build
< blk
->c
+ BLKSIZE
)
394 /* pretend the following was the last blk */
400 /* that last block is dirty by now */
401 while (build
< blk
->c
+ BLKSIZE
)
409 /* change the text of a file */
410 void change(frommark
, tomark
, newtext
)
411 MARK frommark
, tomark
;
420 debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark
), markidx(frommark
), markline(tomark
), markidx(tomark
), newtext
);
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
++)
435 /* find the line within the block */
436 for (text
= blk
->c
, i
= l
- lnum
[i
- 1] - 1; i
> 0; text
++)
444 /* replace the char */
445 text
+= markidx(frommark
);
446 if (*text
== newtext
[0])
448 /* no change was needed - same char */
451 else if (*text
!= '\n')
453 /* This is a change */
461 redrawrange(markline(frommark
), markline(tomark
), markline(frommark
));
464 /* else it is a complex change involving newline... */
467 /* couldn't optimize, so do delete & add */
470 delete(frommark
, tomark
);
471 add(frommark
, newtext
);
472 rptlabel
= "changed";