/* This file contains the low-level file modification functions:
* delete(frommark, tomark) - removes line or portions of lines
* add(frommark, text) - inserts new text
* change(frommark, tomark, text) - delete, then add
debout(msg
, arg1
, arg2
, arg3
, arg4
, arg5
)
char *msg
, *arg1
, *arg2
, *arg3
, *arg4
, *arg5
;
dbg
= fopen("debug.out", "w");
fprintf(dbg
, msg
, arg1
, arg2
, arg3
, arg4
, arg5
);
/* delete a range of text from the file */
void delete(frommark
, tomark
)
MARK frommark
; /* first char to be deleted */
MARK tomark
; /* AFTER last char to be deleted */
int i
; /* used to move thru logical blocks */
REG
char *scan
; /* used to scan thru text of the blk */
REG
char *cpy
; /* used when copying chars */
BLK
*blk
; /* a text block */
long l
; /* a line number */
MARK m
; /* a traveling version of frommark */
debout("delete(%ld.%d, %ld.%d)\n", markline(frommark
), markidx(frommark
), markline(tomark
), markidx(tomark
));
/* if not deleting anything, quit now */
/* supply clues to the redraw module */
redrawrange(markline(frommark
), markline(tomark
), markline(frommark
));
/* adjust marks 'a through 'z and '' as needed */
for (i
= 0; i
< NMARKS
; i
++)
else if (mark
[i
] < tomark
)
else if (markline(mark
[i
]) == l
)
if (markline(frommark
) == l
)
mark
[i
] -= markidx(tomark
) - markidx(frommark
);
mark
[i
] -= markidx(tomark
);
mark
[i
] -= MARK_AT_LINE(l
- markline(frommark
));
if (markidx(frommark
) == 0 && markidx(tomark
) == 0)
rptlines
= markline(tomark
) - markline(frommark
);
/* find the block containing frommark */
for (i
= 1; lnum
[i
] < l
; i
++)
/* process each affected block... */
m
< tomark
&& lnum
[i
] < INFINITY
;
m
= MARK_AT_LINE(lnum
[i
- 1] + 1))
/* find the mark in the block */
for (l
= markline(m
) - lnum
[i
- 1] - 1; l
> 0; l
--)
/* figure out where the changes to this block end */
if (markline(tomark
) > lnum
[i
])
else if (markline(tomark
) == markline(m
))
cpy
= scan
- markidx(m
) + markidx(tomark
);
for (l
= markline(tomark
) - markline(m
);
/* delete the stuff by moving chars within this block */
while (cpy
< blk
->c
+ BLKSIZE
)
while (scan
< blk
->c
+ BLKSIZE
)
/* adjust tomark to allow for lines deleted from this block */
tomark
-= MARK_AT_LINE(lnum
[i
] + 1 - markline(m
));
/* if this block isn't empty now, then advance i */
/* the buffer has changed. Update hdr and lnum. */
/* must have at least 1 line */
/* add some text at a specific place in the file */
void add(atmark
, newtext
)
MARK atmark
; /* where to insert the new text */
char *newtext
; /* NUL-terminated string to insert */
REG
char *scan
; /* used to move through string */
REG
char *build
; /* used while copying chars */
int addlines
; /* number of lines we're adding */
int lastpart
; /* size of last partial line */
BLK
*blk
; /* the block to be modified */
int blkno
; /* the logical block# of (*blk) */
REG
char *newptr
; /* where new text starts in blk */
BLK buf
; /* holds chars from orig blk */
BLK linebuf
; /* holds part of line that didn't fit */
BLK
*following
; /* the BLK following the last BLK */
debout("add(%ld.%d, \"%s\")\n", markline(atmark
), markidx(atmark
), newtext
);
/* if not adding anything, return now */
/* count the number of lines in the new text */
for (scan
= newtext
, lastpart
= addlines
= 0; *scan
; )
if (lastpart
== 0 && markidx(atmark
) == 0)
/* extract the line# from atmark */
/* supply clues to the redraw module */
if ((markidx(atmark
) == 0 && lastpart
== 0) || addlines
== 0)
redrawrange(l
, l
, l
+ addlines
);
/* make sure the last line gets redrawn -- it was
* split, so its appearance has changed
redrawrange(l
, l
+ 1L, l
+ addlines
+ 1L);
/* adjust marks 'a through 'z and '' as needed */
for (i
= 0; i
< NMARKS
; i
++)
/* earlier line, or earlier in same line: no change */
else if (markline(mark
[i
]) > l
)
/* later line: move down a whole number of lines */
mark
[i
] += MARK_AT_LINE(addlines
);
/* multi-line add, which split this line:
* move down, and possibly left or right,
* depending on where the split was and how
* much text was inserted after the last \n
mark
[i
] += MARK_AT_LINE(addlines
) + lastpart
- markidx(atmark
);
/* totally within this line: move right */
/* get the block to be modified */
for (blkno
= 1; lnum
[blkno
] < l
&& lnum
[blkno
+ 1] < INFINITY
; blkno
++)
/* figure out where the new text starts */
for (newptr
= buf
.c
, l
= markline(atmark
) - lnum
[blkno
- 1] - 1;
while (*newptr
++ != '\n')
newptr
+= markidx(atmark
);
/* keep start of old block */
build
= blk
->c
+ (int)(newptr
- buf
.c
);
/* fill this block (or blocks) from the newtext string */
while (*newtext
&& build
< blk
->c
+ BLKSIZE
- 1)
for (scan
= linebuf
.c
+ BLKSIZE
;
build
> blk
->c
&& build
[-1] != '\n';
while (build
< blk
->c
+ BLKSIZE
)
/* copy in the excess from last time */
for (build
= blk
->c
; scan
< linebuf
.c
+ BLKSIZE
; )
/* fill this block(s) from remainder of orig block */
while (newptr
< buf
.c
+ BLKSIZE
&& *newptr
)
while (newptr
< buf
.c
+ BLKSIZE
&& build
< blk
->c
+ BLKSIZE
- 1)
if (newptr
< buf
.c
+ BLKSIZE
&& *newptr
)
for (scan
= linebuf
.c
+ BLKSIZE
;
build
> blk
->c
&& build
[-1] != '\n';
while (build
< blk
->c
+ BLKSIZE
)
/* copy in the excess from last time */
for (build
= blk
->c
; scan
< linebuf
.c
+ BLKSIZE
; )
/* see if we can combine our last block with the following block */
if (lnum
[blkno
] < nlines
&& lnum
[blkno
+ 1] - lnum
[blkno
] < (BLKSIZE
>> 6))
/* hey, we probably can! Get the following block & see... */
following
= blkget(blkno
+ 1);
if (strlen(following
->c
) + (build
- blk
->c
) < BLKSIZE
- 1)
/* we can! Copy text from following to blk */
for (scan
= following
->c
; *scan
; )
while (build
< blk
->c
+ BLKSIZE
)
/* pretend the following was the last blk */
/* that last block is dirty by now */
while (build
< blk
->c
+ BLKSIZE
)
/* change the text of a file */
void change(frommark
, tomark
, newtext
)
debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark
), markidx(frommark
), markline(tomark
), markidx(tomark
), newtext
);
/* optimize for single-character replacement */
if (frommark
+ 1 == tomark
&& newtext
[0] && !newtext
[1] && newtext
[0] != '\n')
/* find the block containing frommark */
for (i
= 1; lnum
[i
] < l
; i
++)
/* find the line within the block */
for (text
= blk
->c
, i
= l
- lnum
[i
- 1] - 1; i
> 0; text
++)
text
+= markidx(frommark
);
/* no change was needed - same char */
redrawrange(markline(frommark
), markline(tomark
), markline(frommark
));
/* else it is a complex change involving newline... */
/* couldn't optimize, so do delete & add */
delete(frommark
, tomark
);