diff options
author | Kjell Wooding <kjell@cvs.openbsd.org> | 2006-12-24 01:20:54 +0000 |
---|---|---|
committer | Kjell Wooding <kjell@cvs.openbsd.org> | 2006-12-24 01:20:54 +0000 |
commit | 4d5358fd7c257f9f2610a68567e988f001a69287 (patch) | |
tree | 2392c3e51afb0494630a3271595517f7ff06bea2 | |
parent | b18c2eb6dbffaecb00c0d437c38db98d75734a5a (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.c | 42 | ||||
-rw-r--r-- | usr.bin/mg/fileio.c | 3 | ||||
-rw-r--r-- | usr.bin/mg/line.c | 26 |
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, <ext(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) { |