Index | Thread | Search

From:
Walter Alejandro Iglesias <wai@roquesor.com>
Subject:
Re: vi(1) count paste bug. New diff.
To:
tech@openbsd.org
Date:
Sat, 16 Aug 2025 16:58:57 +0200

Download raw body.

Thread
Hello list,

Remember that this is about this bug:

   https://marc.info/?l=openbsd-bugs&m=175456507407063&w=2

On Wed, Aug 13, 2025 at 03:33:25PM +0200, Walter Alejandro Iglesias wrote:
> My last patch introduced a regression.  Below the fixed version with
> some simplification of the code.

I always say that simplifying is dangerous.  I learned my own lesson. :-)

In my last patch, I fell into the temptation of merging the empty line
and line mode put conditionals into one (put(), common/put.c, l. 77),
what introduced another regression.  I reverted that change and things
work again as expected.


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	16 Aug 2025 14:33:11 -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) {
@@ -77,11 +77,15 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR
 	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, MAR
 	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, 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 +137,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	16 Aug 2025 14:33:11 -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	16 Aug 2025 14:33:11 -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	16 Aug 2025 14:33:11 -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	16 Aug 2025 14:33:11 -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