summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Wooding <kjell@cvs.openbsd.org>2006-12-24 01:20:54 +0000
committerKjell Wooding <kjell@cvs.openbsd.org>2006-12-24 01:20:54 +0000
commit4d5358fd7c257f9f2610a68567e988f001a69287 (patch)
tree2392c3e51afb0494630a3271595517f7ff06bea2
parentb18c2eb6dbffaecb00c0d437c38db98d75734a5a (diff)
Fix a bug where inserting a file resulted in an incorrect
line-number count for a buffer (M-X insert-file, M-> to reproduce). While here, fix a number of bugs with incorrect line numbers after swap point-and-mark Originally reported via debian's bug tracking system. Fix tested by Han Boetes and Deanna Phillips.
-rw-r--r--usr.bin/mg/file.c42
-rw-r--r--usr.bin/mg/fileio.c3
-rw-r--r--usr.bin/mg/line.c26
3 files changed, 49 insertions, 22 deletions
diff --git a/usr.bin/mg/file.c b/usr.bin/mg/file.c
index 8b245c57de2..70fb05ff448 100644
--- a/usr.bin/mg/file.c
+++ b/usr.bin/mg/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.63 2006/11/17 08:45:31 kjell Exp $ */
+/* $OpenBSD: file.c,v 1.64 2006/12/24 01:20:53 kjell Exp $ */
/* This file is in the public domain. */
@@ -337,34 +337,32 @@ insertfile(char *fname, char *newname, int replacebuf)
(void)strlcat(bp->b_cwd, "/", sizeof(bp->b_cwd));
}
opos = curwp->w_doto;
-
- /* Open a new line, at point, and start inserting after it. */
- x2 = undo_enable(FALSE);
oline = curwp->w_dotline;
+ /*
+ * Open a new line at dot and start inserting after it.
+ * We will delete this newline after insertion.
+ * Disable undo, as we create the undo record manually.
+ */
+ x2 = undo_enable(FALSE);
(void)lnewline();
olp = lback(curwp->w_dotp);
- if (olp == curbp->b_headp) {
- /* if at end of buffer, create a line to insert before */
- (void)lnewline();
- curwp->w_dotp = lback(curwp->w_dotp);
- }
undo_enable(x2);
- /* don't count fake lines at the end */
nline = 0;
siz = 0;
while ((s = ffgetline(line, linesize, &nbytes)) != FIOERR) {
-doneread:
+retry:
siz += nbytes + 1;
switch (s) {
case FIOSUC:
/* FALLTHRU */
case FIOEOF:
- /* the last line of the file */
++nline;
if ((lp1 = lalloc(nbytes)) == NULL) {
/* keep message on the display */
s = FIOERR;
+ undo_add_insert(olp, opos,
+ siz - nbytes - 1 - 1);
goto endoffile;
}
bcopy(line, &ltext(lp1)[0], nbytes);
@@ -373,8 +371,10 @@ doneread:
lp1->l_fp = curwp->w_dotp;
lp1->l_bp = lp2;
curwp->w_dotp->l_bp = lp1;
- if (s == FIOEOF)
+ if (s == FIOEOF) {
+ undo_add_insert(olp, opos, siz - 1);
goto endoffile;
+ }
break;
case FIOLONG: {
/* a line too long to fit in our buffer */
@@ -398,7 +398,7 @@ doneread:
linesize = newsize;
if (s == FIOERR)
goto endoffile;
- goto doneread;
+ goto retry;
}
default:
ewprintf("Unknown code %d reading file", s);
@@ -407,8 +407,6 @@ doneread:
}
}
endoffile:
- undo_add_insert(olp, opos, siz - 1);
-
/* ignore errors */
ffclose(NULL);
/* don't zap an error */
@@ -421,7 +419,17 @@ endoffile:
/* set mark at the end of the text */
curwp->w_dotp = curwp->w_markp = lback(curwp->w_dotp);
curwp->w_marko = llength(curwp->w_markp);
- (void)ldelnewline();
+ curwp->w_markline = oline + nline + 1;
+ /*
+ * if we are at the end of the file, ldelnewline is a no-op,
+ * but we still need to decrement the line and markline counts
+ * as we've accounted for this fencepost in our arithmetic
+ */
+ if (lforw(curwp->w_dotp) == curwp->w_bufp->b_headp) {
+ curwp->w_bufp->b_lines--;
+ curwp->w_markline--;
+ } else
+ (void)ldelnewline();
curwp->w_dotp = olp;
curwp->w_doto = opos;
curwp->w_dotline = oline;
diff --git a/usr.bin/mg/fileio.c b/usr.bin/mg/fileio.c
index 82e8d978fc5..9a148063ffa 100644
--- a/usr.bin/mg/fileio.c
+++ b/usr.bin/mg/fileio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fileio.c,v 1.79 2006/11/19 16:51:19 deraadt Exp $ */
+/* $OpenBSD: fileio.c,v 1.80 2006/12/24 01:20:53 kjell Exp $ */
/* This file is in the public domain. */
@@ -139,6 +139,7 @@ ffputbuf(struct buffer *bp)
* in the supplied buffer. Stop on end of file or end of
* line. When FIOEOF is returned, there is a valid line
* of data without the normally implied \n.
+ * If the line length exceeds nbuf, FIOLONG is returned.
*/
int
ffgetline(char *buf, int nbuf, int *nbytes)
diff --git a/usr.bin/mg/line.c b/usr.bin/mg/line.c
index 47b341c0cc2..ac600887381 100644
--- a/usr.bin/mg/line.c
+++ b/usr.bin/mg/line.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: line.c,v 1.43 2006/11/17 08:45:31 kjell Exp $ */
+/* $OpenBSD: line.c,v 1.44 2006/12/24 01:20:53 kjell Exp $ */
/* This file is in the public domain. */
@@ -309,6 +309,13 @@ linsert(int n, int c)
return (TRUE);
}
+/*
+ * Do the work of inserting a newline at the given line/offset.
+ * If mark is on the current line, we may have to move the markline
+ * to keep line numbers in sync.
+ * lnewline_at assumes the current buffer is writable. Checking for
+ * this fact should be done by the caller.
+ */
int
lnewline_at(struct line *lp1, int doto)
{
@@ -318,6 +325,14 @@ lnewline_at(struct line *lp1, int doto)
lchange(WFFULL);
+ curwp->w_bufp->b_lines++;
+ /* Check if mark is past dot (even on current line) */
+ if (curwp->w_markline > curwp->w_dotline ||
+ (curwp->w_dotline == curwp->w_markline &&
+ curwp->w_marko >= doto))
+ curwp->w_markline++;
+ curwp->w_dotline++;
+
/* If start of line, allocate a new line instead of copying */
if (doto == 0) {
/* new first part */
@@ -377,8 +392,6 @@ lnewline(void)
ewprintf("Buffer is read only");
return (FALSE);
}
- curwp->w_bufp->b_lines++;
- curwp->w_dotline++;
return (lnewline_at(curwp->w_dotp, curwp->w_doto));
}
@@ -472,7 +485,9 @@ ldelete(RSIZE n, int kflag)
* line is the magic header line always return TRUE; merging the last line
* with the header line can be thought of as always being a successful
* operation. Even if nothing is done, this makes the kill buffer work
- * "right". Easy cases can be done by shuffling data around. Hard cases
+ * "right". If the mark is past the dot (actually, markline > dotline),
+ * decrease the markline accordingly to keep line numbers in sync.
+ * Easy cases can be done by shuffling data around. Hard cases
* require that lines be moved about in memory. Return FALSE on error and
* TRUE if all looks ok. We do not update w_dotline here, as deletes are done
* after moves.
@@ -493,7 +508,10 @@ ldelnewline(void)
/* at the end of the buffer */
if (lp2 == curbp->b_headp)
return (TRUE);
+ /* Keep line counts in sync */
curwp->w_bufp->b_lines--;
+ if (curwp->w_markline > curwp->w_dotline)
+ curwp->w_markline--;
if (lp2->l_used <= lp1->l_size - lp1->l_used) {
bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {