shithub: patch

ref: 23dc7aaa3f6a42dc1b8f4a44f6ffefbe025e2979
dir: /page-del/

View raw version
diff 9d43029ff984435111eff658308a44b4f3eee1cc uncommitted
--- a//sys/src/cmd/page.c
+++ b//sys/src/cmd/page.c
@@ -74,7 +74,10 @@
 	Czerox,
 	Cwrite,
 	Cext,
+	Cpop,
 	Cdummy2,
+	Cdelete,
+	Cdummy3,
 	Cquit,
 };
 
@@ -98,7 +101,10 @@
 	[Czerox]	"zerox",	'z', 0, 0,
 	[Cwrite]	"write",	'w', 0, 0,
 	[Cext]		"ext",		'x', 0, 0,
+	[Cpop]		"pop",		'p', 0, 0,
 	[Cdummy2]	"",		0, 0, 0,
+	[Cdelete]	"delete",	'D', 0, 0,
+	[Cdummy3]	"",		0, 0, 0,
 	[Cquit]		"quit",		'q', Kdel, Keof,
 };
 
@@ -134,6 +140,7 @@
 void showpage(Page *);
 void drawpage(Page *);
 Point pagesize(Page *);
+void drawlock(int);
 
 Page*
 addpage(Page *up, char *name, int (*popen)(Page *), void *pdata, int fd)
@@ -987,6 +994,72 @@
 	}
 }
 
+/* doesn't actually free the page entry or touch links to avoid breakage */
+Page*
+freepage(Page *p, Page *prev)
+{
+	Page *next, *up;
+
+	drawlock(0);
+	unloadpage(p);
+	drawlock(1);
+	if(p->fd >= 0)
+		close(p->fd);
+	p->fd = -1;
+	/* not touching p->data */
+	free(p->name);
+	p->name = nil;
+	p->open = nil;
+	next = nextpage(p);
+	up = p->up;
+	if(up->down == p){
+		if(up->tail != p)
+			up->down = next;
+		else
+			up->down = nil;
+	}else if(up->tail == p){
+		up->tail = prev;
+		prev->next = nil;
+	}else
+		prev->next = next;
+	return next;
+}
+
+Page*
+poppage(Page *p, int del)
+{
+	Page *t, *prev, *next;
+
+	if(p == nil)
+		return nil;
+	if(p == root)
+		return p;
+	if(del){
+		if(!(access(p->name, OREAD) == 0 && remove(p->name) == 0
+		|| p->data != nil && access(p->data, OREAD) == 0 && remove(p->data) == 0)){
+			fprint(2, "remove %s: %r", p->name);
+			return p;
+		}
+	}
+	qlock(&pagelock);
+	for(t = p->down, prev = p; t != nil && t->up != p->up; prev = t, t = next){
+		qlock(t);
+		next = freepage(t, prev);
+		qunlock(t);
+	}
+	p->down = nil;
+	prev = prevpage(p);
+	next = freepage(p, prev);
+	qunlock(&pagelock);
+	qunlock(p);
+	if(next != nil){
+		forward = 1;
+		return next;
+	}
+	forward = -1;
+	return prev;
+}
+
 /*
  * A draw operation that touches only the area contained in bot but not in top.
  * mp and sp get aligned with bot.min.
@@ -1462,8 +1535,10 @@
 {
 	char buf[NPATH], *s;
 	Point o;
-	int fd;
+	int fd, del;
+	Page *p;
 
+	del = 0;
 	switch(i){
 	case Corigsize:
 		pos = ZP;
@@ -1547,6 +1622,25 @@
 		break;
 	case Csnarf:
 		writeaddr(current, "/dev/snarf");
+		break;
+	case Cdelete:
+		del = 1;
+		/* wet floor */
+	case Cpop:
+		if(current == nil || !canqlock(current))
+			break;
+		if((p = poppage(current, del)) == current){
+			qunlock(current);
+			break;
+		}
+		if((current = p) == nil){
+			drawlock(0);
+			draw(screen, screen->r, paper, nil, ZP);
+			drawframe(screen->r);
+			drawlock(1);
+			break;
+		}
+		showpage(current);
 		break;
 	case Cnext:
 		forward = 1;