shithub: pplay

Download patch

ref: 52558757dbd1132c18b93d865fcbd84b1a54071a
parent: e7846afe1d81e280898bb40b0966ec0a24b321b7
author: qwx <qwx@sciops.net>
date: Mon Dec 5 23:15:33 EST 2022

increase robustness by always recalculating size

starting over using defensive programming
also fixes a bounding bug

--- a/cmd.c
+++ b/cmd.c
@@ -7,7 +7,7 @@
 /* stupidest implementation with the least amount of state to keep track of */
 
 Dot dot;
-usize totalsz_, totalsz;
+usize totalsz;
 static Chunk norris = {.left = &norris, .right = &norris};
 static Chunk *held;
 static uchar plentyofroom[Iochunksz];
@@ -30,6 +30,33 @@
 	fprint(2, "\n");
 }
 
+static void
+recalcsize(void)
+{
+	int n;
+	Chunk *c;
+
+	for(c=norris.right, n=0; c!=&norris; c=c->right)
+		n += c->bufsz;
+	if(dot.to.pos == totalsz || n < totalsz && dot.to.pos > n)
+		dot.to.pos = n;
+	totalsz = n;
+}
+
+#define ASSERT(x) {if(!(x)) printchunks(&norris); assert((x)); }
+static void
+paranoia(void)
+{
+	Chunk *c;
+
+	ASSERT(dot.pos >= dot.from.pos && dot.pos < dot.to.pos);
+	ASSERT(dot.to.pos <= totalsz);
+	for(c=norris.right; c!=&norris; c=c->right){
+		ASSERT(c->buf != nil);
+		ASSERT((c->bufsz & 3) == 0 && c->bufsz >= Sampsz);
+	}
+}
+
 static Chunk *
 newchunk(usize n)
 {
@@ -65,18 +92,6 @@
 }
 
 static void
-assertsize(void)
-{
-	Chunk *c;
-
-	totalsz_ = 0;
-	for(c=norris.right; c!=&norris; c=c->right)
-		totalsz_ += c->bufsz;
-	assert(totalsz_ == totalsz);
-	assert(dot.to.pos <= totalsz);
-}
-
-static void
 linkchunk(Chunk *left, Chunk *c)
 {
 	c->left->right = left->right;
@@ -83,7 +98,6 @@
 	left->right->left = c->left;
 	c->left = left;
 	left->right = c;
-	totalsz += c->bufsz;
 }
 
 static void
@@ -92,7 +106,6 @@
 	c->left->right = c->right;
 	c->right->left = c->left;
 	c->left = c->right = nil;
-	totalsz -= c->bufsz;
 }
 
 static void
@@ -105,7 +118,6 @@
 	c->bufsz = newsz;
 	if(c->right == &norris && Δ < 0)
 		dot.to.pos += Δ;
-	totalsz += Δ;
 }
 
 /* stupidest possible approach for now: minimal bookkeeping */
@@ -262,6 +274,7 @@
 	Chunk *c;
 
 	if(d->pos >= totalsz){
+		werrstr("out of bounds");
 		*sz = 0;
 		return nil;
 	}
@@ -506,12 +519,8 @@
 			werrstr("readintochunks: nothing read");
 			return nil;
 		}
-	}else if(n > 0 && n < Iochunksz){
+	}else if(n > 0 && n < Iochunksz)
 		resizechunk(c, n);
-		/* kludge! first chunk still unlinked */
-		if(m < Iochunksz)
-			totalsz += Iochunksz - c->bufsz;
-	}
 	return rc;
 }
 
@@ -593,7 +602,7 @@
 		threadexits("failed reading from pipe: %r");
 	close(fd);
 	paste(nil, c);
-	assertsize();
+	recalcsize();
 	redraw(0);
 	threadexits(nil);
 }
@@ -601,7 +610,6 @@
 static int
 pipeline(char *arg, int rr, int wr)
 {
-	assertsize();
 	if(pipe(epfd) < 0)
 		sysfatal("pipe: %r");
 	if(procrfork(rc, arg, mainstacksize, RFFDG|RFNOTEG|RFNAMEG) < 0)
@@ -661,7 +669,7 @@
 int
 cmd(char *s)
 {
-	int n;
+	int n, x;
 	Rune r, r´;
 
 	/* FIXME: avoid potential conflicts with keys in main() */
@@ -677,22 +685,24 @@
 			break;
 		s += n;
 	}
-	assertsize();
 	switch(r){
-	case '<': return pipefrom(s);
-	case '^': return pipethrough(s);
-	case '|': return pipeto(s);
-	case 'c': return copy(s);
-	case 'd': return cut(s);
-	case 'm': return forcemerge(s);
-	case 'p': return paste(s, nil);
+	case '<': x = pipefrom(s); break;
+	case '^': x = pipethrough(s); break;
+	case '|': x = pipeto(s); break;
+	case 'c': x = copy(s); break;
+	case 'd': x = cut(s); break;
+	case 'm': x = forcemerge(s); break;
+	case 'p': x = paste(s, nil); break;
 	case 'q': threadexitsall(nil);
-	case 'r': return readfrom(s);
-	case 'w': return writeto(s);
-	case 'x': return crop(s);
-	default: werrstr("unknown command %C", r); break;
+	case 'r': x = readfrom(s); break;
+	case 'w': x = writeto(s); break;
+	case 'x': x = crop(s); break;
+	default: werrstr("unknown command %C", r); x = -1; break;
 	}
-	return -1;
+	if(debug)
+		paranoia();
+	recalcsize();
+	return x;
 }
 
 int
@@ -703,6 +713,7 @@
 	if((c = readintochunks(fd)) == nil)
 		sysfatal("loadin: %r");
 	linkchunk(&norris, c);
+	recalcsize();
 	setrange(0, totalsz);
 	return 0;
 }