Index | Thread | Search

From:
Walter Alejandro Iglesias <wai@roquesor.com>
Subject:
vi(1) count paste bug. New diff.
To:
tech@openbsd.org
Date:
Sun, 10 Aug 2025 12:05:21 +0200

Download raw body.

Thread
New approach diff for this bug:

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

Perhaps some people won't like the size of this new version of my patch,
especially considering it does the same thing as the previous one (this
is NOT the second alternative I promised in bugs@ message), it takes up
space because I had to add an argument to the put() function and modify
this function in several files.

What motivated me to look for a second solution is that the first one
seemed a bit hackish to me (the whole vi/v_put.c is kind of a hack, to
tell the truth), so I looked for a more robust approach which also would
allowed me, in the future, to deal with a second issue (this is more an
inconvenience than a bug) related to "where the cursor lands" behavior.

This version implements the count prefix in the function put() itself
(common/put.c), this means that the whole string with repetitions is
loaded into the same buffer before it is pasted.  With this approach, to
modify the "where the cursor lands" behavior (in case there's consensus
in doing this) will take modifying just one line.


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	9 Aug 2025 14:53:56 -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;
 	char *bp, *p, *t;
 
 	if (cbp == NULL) {
@@ -78,10 +78,14 @@ put(SCR *sp, CB *cbp, CHAR_T *namep, MAR
 		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);
+			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);
@@ -126,8 +134,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	9 Aug 2025 14:53:56 -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	9 Aug 2025 14:53:56 -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	9 Aug 2025 14:53:56 -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	9 Aug 2025 14:53:56 -0000
@@ -43,15 +43,14 @@ 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);
+	vp->m_start = vp->m_final;
+	if (INTERRUPTED(sp))
+		return (1);
 	return (0);
 }
 
@@ -74,15 +73,14 @@ 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);
+	vp->m_start = vp->m_final;
+	if (INTERRUPTED(sp))
+		return (1);
 	return (0);
 }
 

-- 
Walter