shithub: pplay

Download patch

ref: eb7c19d8d04c872c41c397803ea8f97a9a73a82f
parent: 4f2673e8f15a3e15f897a892e1a5cd2b5dde4138
author: qwx <qwx@sciops.net>
date: Thu Nov 24 14:15:37 EST 2022

multiple fixes over bug-prone buffers vs. position tracking

--- 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;
+usize totalsz_, totalsz;
 static Chunk norris = {.left = &norris, .right = &norris};
 static Chunk *held;
 static uchar plentyofroom[Iochunksz];
@@ -23,7 +23,7 @@
 		dot.from.pos, dot.pos, dot.to.pos);
 	c = r;
 	do{
-		fprint(2, "%#p:%zux ", c, c->bufsz);
+		fprint(2, "%#p:%zux:←%#p→%#p - ", c, c->bufsz, c->left, c->right);
 		assert(c->right->left == c);
 		c = c->right;
 	}while(c != r);
@@ -69,9 +69,11 @@
 {
 	Chunk *c;
 
-	totalsz = 0;
+	totalsz_ = 0;
 	for(c=norris.right; c!=&norris; c=c->right)
-		totalsz += c->bufsz;
+		totalsz_ += c->bufsz;
+	assert(totalsz_ == totalsz);
+	assert(dot.to.pos <= totalsz);
 }
 
 static void
@@ -81,6 +83,7 @@
 	left->right->left = c->left;
 	c->left = left;
 	left->right = c;
+	totalsz += c->bufsz;
 }
 
 static void
@@ -89,8 +92,22 @@
 	c->left->right = c->right;
 	c->right->left = c->left;
 	c->left = c->right = nil;
+	totalsz -= c->bufsz;
 }
 
+static void
+resizechunk(Chunk *c, usize newsz)
+{
+	vlong Δ;
+
+	Δ = newsz - c->bufsz;
+	c->buf = erealloc(c->buf, newsz, c->bufsz);
+	c->bufsz = newsz;
+	if(c->right == &norris && Δ < 0)
+		dot.to.pos += Δ;
+	totalsz += Δ;
+}
+
 /* stupidest possible approach for now: minimal bookkeeping */
 Chunk *
 p2c(usize p, usize *off)
@@ -134,19 +151,21 @@
 int
 setpos(usize off)
 {
-	if(off < dot.from.pos || off > dot.to.pos){
-		werrstr("cannot jump outside of loop bounds\n");
-		return -1;
-	}
 	setrange(0, totalsz);
+	assert(off >= dot.from.pos && off < dot.to.pos);
 	dot.pos = off;
 	return 0;
 }
 
-void
+int
 jump(usize off)
 {
+	if(off < dot.from.pos || off > dot.to.pos){
+		werrstr("cannot jump outside of loop bounds\n");
+		return -1;
+	}
 	dot.pos = off;
+	return 0;
 }
 
 static int
@@ -155,16 +174,14 @@
 	if(held != nil){
 		if(held == c)
 			return 0;
-		else if(cutheld){
-			unlinkchunk(held);
+		else if(cutheld)
 			freechunk(held);
-		}
 	}
 	held = c;
 	cutheld = cut;
 	if(cut){
+		unlinkchunk(c);
 		setpos(dot.from.pos);
-		unlinkchunk(held);
 	}
 	return 0;
 }
@@ -172,16 +189,21 @@
 static Chunk *
 merge(Chunk *left, Chunk *right)
 {
+	usize Δ;
+
+	assert(right != &norris);
 	if(left->buf == nil || right->buf == nil){
 		werrstr("can\'t merge self into void");
 		return nil;
 	}
 	if(left->buf != right->buf){
-		left->buf = erealloc(left->buf, left->bufsz + right->bufsz, left->bufsz);
-		memmove(left->buf + left->bufsz, right->buf, right->bufsz);
-	}else
+		Δ = left->bufsz;
+		resizechunk(left, left->bufsz + right->bufsz);
+		memmove(left->buf + Δ, right->buf, right->bufsz);
+	}else{
 		right->buf = nil;
-	left->bufsz += right->bufsz;
+		left->bufsz += right->bufsz;
+	}
 	unlinkchunk(right);
 	freechunk(right);
 	return 0;
@@ -190,17 +212,16 @@
 static Chunk *
 splitright(Chunk *left, usize off)
 {
-	usize p, Δ;
+	usize Δ;
 	Chunk *c;
 
 	Δ = left->bufsz - off;
+	if(off == 0 || Δ == 0)
+		return left;
 	c = newchunk(Δ);
 	memcpy(c->buf, left->buf+off, Δ);
+	resizechunk(left, off);
 	linkchunk(left, c);
-	left->buf = erealloc(left->buf, off, left->bufsz);
-	left->bufsz = off;
-	p = c2p(c);
-	setrange(p, p+Δ);
 	return c;
 }
 
@@ -314,7 +335,6 @@
 	left = p2c(dot.pos, &p);
 	splitright(left, p);
 	linkchunk(left, c);
-	recalcsize();
 	setrange(dot.pos, dot.pos + c->bufsz);
 	return 1;
 }
@@ -334,8 +354,11 @@
 {
 	Chunk *c;
 
+	if(dot.from.pos == 0 && dot.to.pos == totalsz){
+		werrstr("cut: no range selected");
+		return -1;
+	}
 	c = splitdot();
-	recalcsize();
 	holdchunk(c, 1);
 	return 1;
 }
@@ -355,7 +378,6 @@
 	freechunk(right);
 	right = left->right;
 	linkchunk(left, c);
-	recalcsize();
 	setrange(dot.from.pos, right != &norris ? c2p(right) : totalsz);
 	return 1;
 }
@@ -388,8 +410,7 @@
 	if(dot.from.pos > 0){
 		Δ = c->bufsz - dot.from.pos;
 		memmove(c->buf, c->buf + dot.from.pos, Δ);
-		erealloc(c->buf, Δ, c->bufsz);
-		c->bufsz = Δ;
+		resizechunk(c, Δ);
 		dot.to.pos -= dot.from.pos;
 		dot.from.pos = 0;
 	}
@@ -396,16 +417,13 @@
 	for(Δ=0; c!=&norris; Δ+=c->bufsz, c=c->right)
 		if(Δ + c->bufsz >= dot.to.pos)
 			break;
-	if(dot.to.pos > 0){
-		erealloc(c->buf, dot.to.pos, c->bufsz);
-		c->bufsz = dot.to.pos;
-	}
+	if(dot.to.pos > 0)
+		resizechunk(c, dot.to.pos);
 	for(c=c->right; c!=&norris; c=d){
 		d = c->right;
 		unlinkchunk(c);
 		freechunk(c);
 	}
-	recalcsize();
 	dot.pos = 0;
 	dot.to.pos = totalsz;
 	return 1;
@@ -416,6 +434,10 @@
 {
 	usize p;
 
+	if(dot.from.pos == 0 && dot.to.pos == totalsz){
+		werrstr("merge: won\'t implicitely merge entire buffer\n");
+		return -1;
+	}
 	mergedot(&p);
 	return 0;
 }
@@ -446,8 +468,9 @@
 			return nil;
 		}
 	}
-	c->buf = erealloc(c->buf, off, c->bufsz);
-	c->bufsz = off;
+	resizechunk(c, off);
+	if(m < Iochunksz)	/* kludge! >:( */
+		totalsz += Iochunksz - c->bufsz;
 	return rc;
 }
 
@@ -594,6 +617,7 @@
 			break;
 		s += n;
 	}
+	recalcsize();
 	switch(r){
 	case '<': return pipefrom(s);
 	case '^': return pipethrough(s);
@@ -618,7 +642,6 @@
 	if((c = readintochunks(fd)) == nil)
 		sysfatal("loadin: %r");
 	linkchunk(&norris, c);
-	recalcsize();
 	setrange(0, totalsz);
 	return 0;
 }
--- a/fns.h
+++ b/fns.h
@@ -9,7 +9,7 @@
 void	redraw(int);
 void	initdrw(void);
 void	advance(Dot*, usize);
-void	jump(usize);
+int	jump(usize);
 Chunk*	p2c(usize, usize*);
 void	setrange(usize, usize);
 int	setpos(usize);