From 9279bdd4d788302023f2b7cd4b13f3508d3bc538 Mon Sep 17 00:00:00 2001 From: millert Date: Sat, 23 Aug 2025 21:02:10 +0000 Subject: [PATCH] vi: fix 'p' command with a count This moves the count support from v_put() to put(). Previously, v_put() would call put() "count" times. Because put() also updates the cursor position, this resulted in the text being pasted in the wrong place after the first call to put(). Moving the "count" loop into put() itself means the cursor position is only updated once. From Walter Alejandro Iglesias --- usr.bin/vi/common/put.c | 47 +++++++++++++++++++++------------ usr.bin/vi/ex/ex_move.c | 4 +-- usr.bin/vi/ex/ex_put.c | 4 +-- usr.bin/vi/include/com_extern.h | 4 +-- usr.bin/vi/vi/v_put.c | 30 ++++++++------------- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/usr.bin/vi/common/put.c b/usr.bin/vi/common/put.c index 18a2172fdea..8c9064785b2 100644 --- a/usr.bin/vi/common/put.c +++ b/usr.bin/vi/common/put.c @@ -1,4 +1,4 @@ -/* $OpenBSD: put.c,v 1.16 2016/05/27 09:18:11 martijn Exp $ */ +/* $OpenBSD: put.c,v 1.17 2025/08/23 21:02:10 millert Exp $ */ /*- * Copyright (c) 1992, 1993, 1994 @@ -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) { @@ -77,11 +77,15 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) if (cp->lno == 1) { if (db_last(sp, &lno)) return (1); - if (lno == 0) { - for (; tp; ++lno, ++sp->rptlines[L_ADDED], - tp = TAILQ_NEXT(tp, q)) - if (db_append(sp, 1, lno, tp->lb, tp->len)) - return (1); + if (lno == 0 && F_ISSET(cbp, CB_LMODE)) { + 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); + tp = TAILQ_FIRST(&cbp->textq); + } rp->lno = 1; rp->cno = 0; return (0); @@ -92,10 +96,14 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) 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); + 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); + tp = TAILQ_FIRST(&cbp->textq); + } rp->cno = 0; (void)nonblank(sp, rp->lno, &rp->cno); return (0); @@ -111,8 +119,11 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) * 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 +137,10 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MARK *cp, MARK *rp, int append) /* 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. */ diff --git a/usr.bin/vi/ex/ex_move.c b/usr.bin/vi/ex/ex_move.c index 9155ef30a04..ffc315e4468 100644 --- a/usr.bin/vi/ex/ex_move.c +++ b/usr.bin/vi/ex/ex_move.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ex_move.c,v 1.11 2016/01/06 22:28:52 millert Exp $ */ +/* $OpenBSD: ex_move.c,v 1.12 2025/08/23 21:02:10 millert Exp $ */ /*- * Copyright (c) 1992, 1993, 1994 @@ -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 { /* diff --git a/usr.bin/vi/ex/ex_put.c b/usr.bin/vi/ex/ex_put.c index d1c463167c6..531fddd74dc 100644 --- a/usr.bin/vi/ex/ex_put.c +++ b/usr.bin/vi/ex/ex_put.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ex_put.c,v 1.6 2014/11/12 04:28:41 bentley Exp $ */ +/* $OpenBSD: ex_put.c,v 1.7 2025/08/23 21:02:10 millert Exp $ */ /*- * Copyright (c) 1992, 1993, 1994 @@ -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; diff --git a/usr.bin/vi/include/com_extern.h b/usr.bin/vi/include/com_extern.h index 675372ba577..46b6f220a1e 100644 --- a/usr.bin/vi/include/com_extern.h +++ b/usr.bin/vi/include/com_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: com_extern.h,v 1.16 2019/05/21 09:24:58 martijn Exp $ */ +/* $OpenBSD: com_extern.h,v 1.17 2025/08/23 21:02:10 millert Exp $ */ int cut(SCR *, CHAR_T *, MARK *, MARK *, int); int cut_line(SCR *, recno_t, size_t, size_t, CB *); @@ -81,7 +81,7 @@ int f_w300(SCR *, OPTION *, char *, u_long *); 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); diff --git a/usr.bin/vi/vi/v_put.c b/usr.bin/vi/vi/v_put.c index 959d4a47698..6ae06b8e368 100644 --- a/usr.bin/vi/vi/v_put.c +++ b/usr.bin/vi/vi/v_put.c @@ -1,4 +1,4 @@ -/* $OpenBSD: v_put.c,v 1.8 2016/05/27 09:18:12 martijn Exp $ */ +/* $OpenBSD: v_put.c,v 1.9 2025/08/23 21:02:10 millert Exp $ */ /*- * Copyright (c) 1992, 1993, 1994 @@ -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); }