From: Walter Alejandro Iglesias Subject: Re: vi(1) count paste bug. New diff. To: tech@openbsd.org Date: Wed, 13 Aug 2025 15:33:23 +0200 My last patch introduced a regression. Below the fixed version with some simplification of the code. Index: common/put.c =================================================================== RCS file: /cvs/src/usr.bin/vi/common/put.c,v diff -u -p -r1.16 put.c --- common/put.c 27 May 2016 09:18:11 -0000 1.16 +++ common/put.c 13 Aug 2025 13:08:37 -0000 @@ -27,16 +27,16 @@ * put -- * Put text buffer contents into the file. * - * PUBLIC: int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int); + * PUBLIC: int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int, int); */ int -put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) +put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append, int cnt) { CHAR_T name; TEXT *ltp, *tp; recno_t lno; size_t blen, clen, len; - int rval; + int rval, i, isempty; char *bp, *p, *t; if (cbp == NULL) { @@ -74,28 +74,23 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR * Historical practice is that the cursor ends at the first character * in the file. */ - if (cp->lno == 1) { - if (db_last(sp, &lno)) - return (1); - if (lno == 0) { - for (; tp; ++lno, ++sp->rptlines[L_ADDED], + if (cp->lno == 1 && db_last(sp, &lno)) + return (1); + + /* If a line mode buffer, append each new line into the file. */ + if (F_ISSET(cbp, CB_LMODE)) { + if (lno != 0) { + lno = append ? cp->lno : cp->lno - 1; + rp->lno = lno + 1; + } + for (i = cnt; i > 0; i--) { + for (; tp; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) if (db_append(sp, 1, lno, tp->lb, tp->len)) return (1); - rp->lno = 1; - rp->cno = 0; - return (0); + tp = TAILQ_FIRST(&cbp->textq); } - } - - /* If a line mode buffer, append each new line into the file. */ - if (F_ISSET(cbp, CB_LMODE)) { - lno = append ? cp->lno : cp->lno - 1; - rp->lno = lno + 1; - for (; tp; - ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) - if (db_append(sp, 1, lno, tp->lb, tp->len)) - return (1); rp->cno = 0; (void)nonblank(sp, rp->lno, &rp->cno); return (0); @@ -111,8 +106,11 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR * Get the first line. */ lno = cp->lno; - if (db_get(sp, lno, DBG_FATAL, &p, &len)) - return (1); + if (db_eget(sp, lno, &p, &len, &isempty)) { + if (!isempty) + return (1); + len = 0; + } GET_SPACE_RET(sp, bp, blen, tp->len + len + 1); t = bp; @@ -126,8 +124,10 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR /* First line from the CB. */ if (tp->len != 0) { - memcpy(t, tp->lb, tp->len); - t += tp->len; + for (i = cnt; i > 0; i--) { + memcpy(t, tp->lb, tp->len); + t += tp->len; + } } /* Calculate length left in the original line. */ Index: ex/ex_move.c =================================================================== RCS file: /cvs/src/usr.bin/vi/ex/ex_move.c,v diff -u -p -r1.11 ex_move.c --- ex/ex_move.c 6 Jan 2016 22:28:52 -0000 1.11 +++ ex/ex_move.c 13 Aug 2025 13:08:37 -0000 @@ -59,7 +59,7 @@ ex_copy(SCR *sp, EXCMD *cmdp) /* Put the text into place. */ tm.lno = cmdp->lineno; tm.cno = 0; - if (put(sp, &cb, NULL, &tm, &m, 1)) + if (put(sp, &cb, NULL, &tm, &m, 1,1)) rval = 1; else { /* Index: ex/ex_put.c =================================================================== RCS file: /cvs/src/usr.bin/vi/ex/ex_put.c,v diff -u -p -r1.6 ex_put.c --- ex/ex_put.c 12 Nov 2014 04:28:41 -0000 1.6 +++ ex/ex_put.c 13 Aug 2025 13:08:37 -0000 @@ -39,7 +39,7 @@ ex_put(SCR *sp, EXCMD *cmdp) m.cno = sp->cno; if (put(sp, NULL, FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, - &cmdp->addr1, &m, 1)) + &cmdp->addr1, &m, 1, 1)) return (1); sp->lno = m.lno; sp->cno = m.cno; Index: include/com_extern.h =================================================================== RCS file: /cvs/src/usr.bin/vi/include/com_extern.h,v diff -u -p -r1.16 com_extern.h --- include/com_extern.h 21 May 2019 09:24:58 -0000 1.16 +++ include/com_extern.h 13 Aug 2025 13:08:37 -0000 @@ -81,7 +81,7 @@ int f_w300(SCR *, OPTION *, char *, u_lo int f_w1200(SCR *, OPTION *, char *, u_long *); int f_w9600(SCR *, OPTION *, char *, u_long *); int f_window(SCR *, OPTION *, char *, u_long *); -int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int); +int put(SCR *, CB *, CHAR_T *, MARK *, MARK *, int, int); int rcv_tmp(SCR *, EXF *, char *); int rcv_init(SCR *); int rcv_sync(SCR *, u_int); Index: vi/v_put.c =================================================================== RCS file: /cvs/src/usr.bin/vi/vi/v_put.c,v diff -u -p -r1.8 v_put.c --- vi/v_put.c 27 May 2016 09:18:12 -0000 1.8 +++ vi/v_put.c 13 Aug 2025 13:08:37 -0000 @@ -43,15 +43,11 @@ v_Put(SCR *sp, VICMD *vp) * Historic vi did not support a count with the 'p' and 'P' * commands. It's useful, so we do. */ - for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { - if (put(sp, NULL, - F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, - &vp->m_start, &vp->m_final, 0)) - return (1); - vp->m_start = vp->m_final; - if (INTERRUPTED(sp)) - return (1); - } + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (put(sp, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 0, cnt)) + return (1); + return (0); } @@ -74,15 +70,11 @@ v_put(SCR *sp, VICMD *vp) * Historic vi did not support a count with the 'p' and 'P' * commands. It's useful, so we do. */ - for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { - if (put(sp, NULL, - F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, - &vp->m_start, &vp->m_final, 1)) - return (1); - vp->m_start = vp->m_final; - if (INTERRUPTED(sp)) - return (1); - } + cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; + if (put(sp, NULL, F_ISSET(vp, VC_BUFFER) ? &vp->buffer : NULL, + &vp->m_start, &vp->m_final, 1, cnt)) + return (1); + return (0); } -- Walter