vBulletin Search Engine Optimization
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| Hiya folks. This is an mg diff that could use some testing (and/or eyes) The original bug was fairly simple: Inserting a file resulted in an incorrect line-number count for a buffer (M-X insert-file, M-> to see what I mean. the line count in the status bar is off by one) Chasing this bug meant finding a few more, mostly, with respect to setting a mark, editing the buffer, and then later swapping dot-and-mark. This diff should clean it all up. (and clean up some error handling, remove some dead code) If you use mg, please try this diff by opening and inserting files into buffers and verifying that the reported line count is correct Also, try setting the mark, editing the buffer (deleting, inserting in the marked region), and swapping point-mark to see that the reported line numbers are ok there, too, -kj Index: file.c ================================================== ================= RCS file: /cvs/src/usr.bin/mg/file.c,v retrieving revision 1.63 diff -u -r1.63 file.c --- file.c 17 Nov 2006 08:45:31 -0000 1.63 +++ file.c 21 Dec 2006 19:40:12 -0000 @@ -337,34 +337,32 @@ (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 @@ 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 @@ linesize = newsize; if (s == FIOERR) goto endoffile; - goto doneread; + goto retry; } default: ewprintf("Unknown code %d reading file", s); @@ -407,8 +407,6 @@ } } endoffile: - undo_add_insert(olp, opos, siz - 1); - /* ignore errors */ ffclose(NULL); /* don't zap an error */ @@ -421,7 +419,17 @@ /* 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; Index: fileio.c ================================================== ================= RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.79 diff -u -r1.79 fileio.c --- fileio.c 19 Nov 2006 16:51:19 -0000 1.79 +++ fileio.c 21 Dec 2006 19:40:14 -0000 @@ -139,6 +139,7 @@ * 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) Index: line.c ================================================== ================= RCS file: /cvs/src/usr.bin/mg/line.c,v retrieving revision 1.43 diff -u -r1.43 line.c --- line.c 17 Nov 2006 08:45:31 -0000 1.43 +++ line.c 21 Dec 2006 19:40:16 -0000 @@ -309,6 +309,13 @@ 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 @@ 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 @@ 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 @@ * 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 @@ /* 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) { |