xref: /plan9-contrib/acme/news/src/win.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include "win.h"
680ee5cbfSDavid du Colombier 
780ee5cbfSDavid du Colombier Window*
newwindow(void)880ee5cbfSDavid du Colombier newwindow(void)
980ee5cbfSDavid du Colombier {
1080ee5cbfSDavid du Colombier 	char buf[12];
1180ee5cbfSDavid du Colombier 	Window *w;
1280ee5cbfSDavid du Colombier 
1380ee5cbfSDavid du Colombier 	w = emalloc(sizeof(Window));
1480ee5cbfSDavid du Colombier 	w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC);
1580ee5cbfSDavid du Colombier 	if(w->ctl<0 || read(w->ctl, buf, 12)!=12)
1680ee5cbfSDavid du Colombier 		error("can't open window ctl file: %r");
1780ee5cbfSDavid du Colombier 	ctlprint(w->ctl, "noscroll\n");
1880ee5cbfSDavid du Colombier 	w->id = atoi(buf);
1980ee5cbfSDavid du Colombier 	w->event = winopenfile(w, "event");
2080ee5cbfSDavid du Colombier 	w->addr = -1;	/* will be opened when needed */
2180ee5cbfSDavid du Colombier 	w->body = nil;
2280ee5cbfSDavid du Colombier 	w->data = -1;
2380ee5cbfSDavid du Colombier 	w->cevent = chancreate(sizeof(Event*), 0);
2480ee5cbfSDavid du Colombier 	if(w->cevent == nil)
2580ee5cbfSDavid du Colombier 		error("cevent is nil: %r");
2680ee5cbfSDavid du Colombier 	return w;
2780ee5cbfSDavid du Colombier }
2880ee5cbfSDavid du Colombier 
2980ee5cbfSDavid du Colombier void
winsetdump(Window * w,char * dir,char * cmd)3080ee5cbfSDavid du Colombier winsetdump(Window *w, char *dir, char *cmd)
3180ee5cbfSDavid du Colombier {
3280ee5cbfSDavid du Colombier 	if(dir != nil)
3380ee5cbfSDavid du Colombier 		ctlprint(w->ctl, "dumpdir %s\n", dir);
3480ee5cbfSDavid du Colombier 	if(cmd != nil)
3580ee5cbfSDavid du Colombier 		ctlprint(w->ctl, "dump %s\n", cmd);
3680ee5cbfSDavid du Colombier }
3780ee5cbfSDavid du Colombier 
3880ee5cbfSDavid du Colombier void
wineventproc(void * v)3980ee5cbfSDavid du Colombier wineventproc(void *v)
4080ee5cbfSDavid du Colombier {
4180ee5cbfSDavid du Colombier 	Window *w;
4280ee5cbfSDavid du Colombier 	int i;
4380ee5cbfSDavid du Colombier 
4480ee5cbfSDavid du Colombier 	threadsetname("wineventproc");
4580ee5cbfSDavid du Colombier 	w = v;
4680ee5cbfSDavid du Colombier 	for(i=0; ; i++){
4780ee5cbfSDavid du Colombier 		if(i >= NEVENT)
4880ee5cbfSDavid du Colombier 			i = 0;
4980ee5cbfSDavid du Colombier 		wingetevent(w, &w->e[i]);
5080ee5cbfSDavid du Colombier 		sendp(w->cevent, &w->e[i]);
5180ee5cbfSDavid du Colombier 	}
5280ee5cbfSDavid du Colombier }
5380ee5cbfSDavid du Colombier 
5480ee5cbfSDavid du Colombier int
winopenfile(Window * w,char * f)5580ee5cbfSDavid du Colombier winopenfile(Window *w, char *f)
5680ee5cbfSDavid du Colombier {
5780ee5cbfSDavid du Colombier 	char buf[64];
5880ee5cbfSDavid du Colombier 	int fd;
5980ee5cbfSDavid du Colombier 
6080ee5cbfSDavid du Colombier 	sprint(buf, "/mnt/wsys/%d/%s", w->id, f);
6180ee5cbfSDavid du Colombier 	fd = open(buf, ORDWR|OCEXEC);
6280ee5cbfSDavid du Colombier 	if(fd < 0)
6380ee5cbfSDavid du Colombier 		error("can't open window file %s: %r", f);
6480ee5cbfSDavid du Colombier 	return fd;
6580ee5cbfSDavid du Colombier }
6680ee5cbfSDavid du Colombier 
6780ee5cbfSDavid du Colombier void
wintagwrite(Window * w,char * s,int n)6880ee5cbfSDavid du Colombier wintagwrite(Window *w, char *s, int n)
6980ee5cbfSDavid du Colombier {
7080ee5cbfSDavid du Colombier 	int fd;
7180ee5cbfSDavid du Colombier 
7280ee5cbfSDavid du Colombier 	fd = winopenfile(w, "tag");
7380ee5cbfSDavid du Colombier 	if(write(fd, s, n) != n)
7480ee5cbfSDavid du Colombier 		error("tag write: %r");
7580ee5cbfSDavid du Colombier 	close(fd);
7680ee5cbfSDavid du Colombier }
7780ee5cbfSDavid du Colombier 
7880ee5cbfSDavid du Colombier void
winname(Window * w,char * s)7980ee5cbfSDavid du Colombier winname(Window *w, char *s)
8080ee5cbfSDavid du Colombier {
8180ee5cbfSDavid du Colombier 	ctlprint(w->ctl, "name %s\n", s);
8280ee5cbfSDavid du Colombier }
8380ee5cbfSDavid du Colombier 
8480ee5cbfSDavid du Colombier void
winopenbody(Window * w,int mode)8580ee5cbfSDavid du Colombier winopenbody(Window *w, int mode)
8680ee5cbfSDavid du Colombier {
8780ee5cbfSDavid du Colombier 	char buf[256];
8880ee5cbfSDavid du Colombier 
8980ee5cbfSDavid du Colombier 	sprint(buf, "/mnt/wsys/%d/body", w->id);
9080ee5cbfSDavid du Colombier 	w->body = Bopen(buf, mode|OCEXEC);
9180ee5cbfSDavid du Colombier 	if(w->body == nil)
9280ee5cbfSDavid du Colombier 		error("can't open window body file: %r");
9380ee5cbfSDavid du Colombier }
9480ee5cbfSDavid du Colombier 
9580ee5cbfSDavid du Colombier void
winclosebody(Window * w)9680ee5cbfSDavid du Colombier winclosebody(Window *w)
9780ee5cbfSDavid du Colombier {
9880ee5cbfSDavid du Colombier 	if(w->body != nil){
9980ee5cbfSDavid du Colombier 		Bterm(w->body);
10080ee5cbfSDavid du Colombier 		w->body = nil;
10180ee5cbfSDavid du Colombier 	}
10280ee5cbfSDavid du Colombier }
10380ee5cbfSDavid du Colombier 
10480ee5cbfSDavid du Colombier void
winwritebody(Window * w,char * s,int n)10580ee5cbfSDavid du Colombier winwritebody(Window *w, char *s, int n)
10680ee5cbfSDavid du Colombier {
10780ee5cbfSDavid du Colombier 	if(w->body == nil)
10880ee5cbfSDavid du Colombier 		winopenbody(w, OWRITE);
10980ee5cbfSDavid du Colombier 	if(Bwrite(w->body, s, n) != n)
11080ee5cbfSDavid du Colombier 		error("write error to window: %r");
11180ee5cbfSDavid du Colombier }
11280ee5cbfSDavid du Colombier 
11380ee5cbfSDavid du Colombier int
wingetec(Window * w)11480ee5cbfSDavid du Colombier wingetec(Window *w)
11580ee5cbfSDavid du Colombier {
11680ee5cbfSDavid du Colombier 	if(w->nbuf == 0){
11780ee5cbfSDavid du Colombier 		w->nbuf = read(w->event, w->buf, sizeof w->buf);
11880ee5cbfSDavid du Colombier 		if(w->nbuf <= 0){
11980ee5cbfSDavid du Colombier 			/* probably because window has exited, and only called by wineventproc, so just shut down */
12080ee5cbfSDavid du Colombier 			threadexits(nil);
12180ee5cbfSDavid du Colombier 		}
12280ee5cbfSDavid du Colombier 		w->bufp = w->buf;
12380ee5cbfSDavid du Colombier 	}
12480ee5cbfSDavid du Colombier 	w->nbuf--;
12580ee5cbfSDavid du Colombier 	return *w->bufp++;
12680ee5cbfSDavid du Colombier }
12780ee5cbfSDavid du Colombier 
12880ee5cbfSDavid du Colombier int
wingeten(Window * w)12980ee5cbfSDavid du Colombier wingeten(Window *w)
13080ee5cbfSDavid du Colombier {
13180ee5cbfSDavid du Colombier 	int n, c;
13280ee5cbfSDavid du Colombier 
13380ee5cbfSDavid du Colombier 	n = 0;
13480ee5cbfSDavid du Colombier 	while('0'<=(c=wingetec(w)) && c<='9')
13580ee5cbfSDavid du Colombier 		n = n*10+(c-'0');
13680ee5cbfSDavid du Colombier 	if(c != ' ')
13780ee5cbfSDavid du Colombier 		error("event number syntax");
13880ee5cbfSDavid du Colombier 	return n;
13980ee5cbfSDavid du Colombier }
14080ee5cbfSDavid du Colombier 
14180ee5cbfSDavid du Colombier int
wingeter(Window * w,char * buf,int * nb)14280ee5cbfSDavid du Colombier wingeter(Window *w, char *buf, int *nb)
14380ee5cbfSDavid du Colombier {
14480ee5cbfSDavid du Colombier 	Rune r;
14580ee5cbfSDavid du Colombier 	int n;
14680ee5cbfSDavid du Colombier 
14780ee5cbfSDavid du Colombier 	r = wingetec(w);
14880ee5cbfSDavid du Colombier 	buf[0] = r;
14980ee5cbfSDavid du Colombier 	n = 1;
15080ee5cbfSDavid du Colombier 	if(r >= Runeself) {
15180ee5cbfSDavid du Colombier 		while(!fullrune(buf, n))
15280ee5cbfSDavid du Colombier 			buf[n++] = wingetec(w);
15380ee5cbfSDavid du Colombier 		chartorune(&r, buf);
15480ee5cbfSDavid du Colombier 	}
15580ee5cbfSDavid du Colombier 	*nb = n;
15680ee5cbfSDavid du Colombier 	return r;
15780ee5cbfSDavid du Colombier }
15880ee5cbfSDavid du Colombier 
15980ee5cbfSDavid du Colombier void
wingetevent(Window * w,Event * e)16080ee5cbfSDavid du Colombier wingetevent(Window *w, Event *e)
16180ee5cbfSDavid du Colombier {
16280ee5cbfSDavid du Colombier 	int i, nb;
16380ee5cbfSDavid du Colombier 
16480ee5cbfSDavid du Colombier 	e->c1 = wingetec(w);
16580ee5cbfSDavid du Colombier 	e->c2 = wingetec(w);
16680ee5cbfSDavid du Colombier 	e->q0 = wingeten(w);
16780ee5cbfSDavid du Colombier 	e->q1 = wingeten(w);
16880ee5cbfSDavid du Colombier 	e->flag = wingeten(w);
16980ee5cbfSDavid du Colombier 	e->nr = wingeten(w);
17080ee5cbfSDavid du Colombier 	if(e->nr > EVENTSIZE)
17180ee5cbfSDavid du Colombier 		error("event string too long");
17280ee5cbfSDavid du Colombier 	e->nb = 0;
17380ee5cbfSDavid du Colombier 	for(i=0; i<e->nr; i++){
17480ee5cbfSDavid du Colombier 		e->r[i] = wingeter(w, e->b+e->nb, &nb);
17580ee5cbfSDavid du Colombier 		e->nb += nb;
17680ee5cbfSDavid du Colombier 	}
17780ee5cbfSDavid du Colombier 	e->r[e->nr] = 0;
17880ee5cbfSDavid du Colombier 	e->b[e->nb] = 0;
17980ee5cbfSDavid du Colombier 	if(wingetec(w) != '\n')
18080ee5cbfSDavid du Colombier 		error("event syntax error");
18180ee5cbfSDavid du Colombier }
18280ee5cbfSDavid du Colombier 
18380ee5cbfSDavid du Colombier void
winwriteevent(Window * w,Event * e)18480ee5cbfSDavid du Colombier winwriteevent(Window *w, Event *e)
18580ee5cbfSDavid du Colombier {
186*9a747e4fSDavid du Colombier 	fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
18780ee5cbfSDavid du Colombier }
18880ee5cbfSDavid du Colombier 
18980ee5cbfSDavid du Colombier static int
nrunes(char * s,int nb)19080ee5cbfSDavid du Colombier nrunes(char *s, int nb)
19180ee5cbfSDavid du Colombier {
19280ee5cbfSDavid du Colombier 	int i, n;
19380ee5cbfSDavid du Colombier 	Rune r;
19480ee5cbfSDavid du Colombier 
19580ee5cbfSDavid du Colombier 	n = 0;
19680ee5cbfSDavid du Colombier 	for(i=0; i<nb; n++)
19780ee5cbfSDavid du Colombier 		i += chartorune(&r, s+i);
19880ee5cbfSDavid du Colombier 	return n;
19980ee5cbfSDavid du Colombier }
20080ee5cbfSDavid du Colombier 
20180ee5cbfSDavid du Colombier void
winread(Window * w,uint q0,uint q1,char * data)20280ee5cbfSDavid du Colombier winread(Window *w, uint q0, uint q1, char *data)
20380ee5cbfSDavid du Colombier {
20480ee5cbfSDavid du Colombier 	int m, n, nr;
20580ee5cbfSDavid du Colombier 	char buf[256];
20680ee5cbfSDavid du Colombier 
20780ee5cbfSDavid du Colombier 	if(w->addr < 0)
20880ee5cbfSDavid du Colombier 		w->addr = winopenfile(w, "addr");
20980ee5cbfSDavid du Colombier 	if(w->data < 0)
21080ee5cbfSDavid du Colombier 		w->data = winopenfile(w, "data");
21180ee5cbfSDavid du Colombier 	m = q0;
21280ee5cbfSDavid du Colombier 	while(m < q1){
21380ee5cbfSDavid du Colombier 		n = sprint(buf, "#%d", m);
21480ee5cbfSDavid du Colombier 		if(write(w->addr, buf, n) != n)
21580ee5cbfSDavid du Colombier 			error("error writing addr: %r");
21680ee5cbfSDavid du Colombier 		n = read(w->data, buf, sizeof buf);
21780ee5cbfSDavid du Colombier 		if(n <= 0)
21880ee5cbfSDavid du Colombier 			error("reading data: %r");
21980ee5cbfSDavid du Colombier 		nr = nrunes(buf, n);
22080ee5cbfSDavid du Colombier 		while(m+nr >q1){
22180ee5cbfSDavid du Colombier 			do; while(n>0 && (buf[--n]&0xC0)==0x80);
22280ee5cbfSDavid du Colombier 			--nr;
22380ee5cbfSDavid du Colombier 		}
22480ee5cbfSDavid du Colombier 		if(n == 0)
22580ee5cbfSDavid du Colombier 			break;
22680ee5cbfSDavid du Colombier 		memmove(data, buf, n);
22780ee5cbfSDavid du Colombier 		data += n;
22880ee5cbfSDavid du Colombier 		*data = 0;
22980ee5cbfSDavid du Colombier 		m += nr;
23080ee5cbfSDavid du Colombier 	}
23180ee5cbfSDavid du Colombier }
23280ee5cbfSDavid du Colombier 
23380ee5cbfSDavid du Colombier void
windormant(Window * w)23480ee5cbfSDavid du Colombier windormant(Window *w)
23580ee5cbfSDavid du Colombier {
23680ee5cbfSDavid du Colombier 	if(w->addr >= 0){
23780ee5cbfSDavid du Colombier 		close(w->addr);
23880ee5cbfSDavid du Colombier 		w->addr = -1;
23980ee5cbfSDavid du Colombier 	}
24080ee5cbfSDavid du Colombier 	if(w->body != nil){
24180ee5cbfSDavid du Colombier 		Bterm(w->body);
24280ee5cbfSDavid du Colombier 		w->body = nil;
24380ee5cbfSDavid du Colombier 	}
24480ee5cbfSDavid du Colombier 	if(w->data >= 0){
24580ee5cbfSDavid du Colombier 		close(w->data);
24680ee5cbfSDavid du Colombier 		w->data = -1;
24780ee5cbfSDavid du Colombier 	}
24880ee5cbfSDavid du Colombier }
24980ee5cbfSDavid du Colombier 
25080ee5cbfSDavid du Colombier 
25180ee5cbfSDavid du Colombier int
windel(Window * w,int sure)25280ee5cbfSDavid du Colombier windel(Window *w, int sure)
25380ee5cbfSDavid du Colombier {
25480ee5cbfSDavid du Colombier 	if(sure)
25580ee5cbfSDavid du Colombier 		write(w->ctl, "delete\n", 7);
25680ee5cbfSDavid du Colombier 	else if(write(w->ctl, "del\n", 4) != 4)
25780ee5cbfSDavid du Colombier 		return 0;
25880ee5cbfSDavid du Colombier 	/* event proc will die due to read error from event file */
25980ee5cbfSDavid du Colombier 	windormant(w);
26080ee5cbfSDavid du Colombier 	close(w->ctl);
26180ee5cbfSDavid du Colombier 	w->ctl = -1;
26280ee5cbfSDavid du Colombier 	close(w->event);
26380ee5cbfSDavid du Colombier 	w->event = -1;
26480ee5cbfSDavid du Colombier 	return 1;
26580ee5cbfSDavid du Colombier }
26680ee5cbfSDavid du Colombier 
26780ee5cbfSDavid du Colombier void
winclean(Window * w)26880ee5cbfSDavid du Colombier winclean(Window *w)
26980ee5cbfSDavid du Colombier {
27080ee5cbfSDavid du Colombier 	if(w->body)
27180ee5cbfSDavid du Colombier 		Bflush(w->body);
27280ee5cbfSDavid du Colombier 	ctlprint(w->ctl, "clean\n");
27380ee5cbfSDavid du Colombier }
27480ee5cbfSDavid du Colombier 
27580ee5cbfSDavid du Colombier int
winsetaddr(Window * w,char * addr,int errok)27680ee5cbfSDavid du Colombier winsetaddr(Window *w, char *addr, int errok)
27780ee5cbfSDavid du Colombier {
27880ee5cbfSDavid du Colombier 	if(w->addr < 0)
27980ee5cbfSDavid du Colombier 		w->addr = winopenfile(w, "addr");
28080ee5cbfSDavid du Colombier 	if(write(w->addr, addr, strlen(addr)) < 0){
28180ee5cbfSDavid du Colombier 		if(!errok)
28280ee5cbfSDavid du Colombier 			error("error writing addr(%s): %r", addr);
28380ee5cbfSDavid du Colombier 		return 0;
28480ee5cbfSDavid du Colombier 	}
28580ee5cbfSDavid du Colombier 	return 1;
28680ee5cbfSDavid du Colombier }
28780ee5cbfSDavid du Colombier 
28880ee5cbfSDavid du Colombier int
winselect(Window * w,char * addr,int errok)28980ee5cbfSDavid du Colombier winselect(Window *w, char *addr, int errok)
29080ee5cbfSDavid du Colombier {
29180ee5cbfSDavid du Colombier 	if(winsetaddr(w, addr, errok)){
29280ee5cbfSDavid du Colombier 		ctlprint(w->ctl, "dot=addr\n");
29380ee5cbfSDavid du Colombier 		return 1;
29480ee5cbfSDavid du Colombier 	}
29580ee5cbfSDavid du Colombier 	return 0;
29680ee5cbfSDavid du Colombier }
29780ee5cbfSDavid du Colombier 
29880ee5cbfSDavid du Colombier char*
winreadbody(Window * w,int * np)29980ee5cbfSDavid du Colombier winreadbody(Window *w, int *np)	/* can't use readfile because acme doesn't report the length */
30080ee5cbfSDavid du Colombier {
30180ee5cbfSDavid du Colombier 	char *s;
30280ee5cbfSDavid du Colombier 	int m, na, n;
30380ee5cbfSDavid du Colombier 
30480ee5cbfSDavid du Colombier 	if(w->body != nil)
30580ee5cbfSDavid du Colombier 		winclosebody(w);
30680ee5cbfSDavid du Colombier 	winopenbody(w, OREAD);
30780ee5cbfSDavid du Colombier 	s = nil;
30880ee5cbfSDavid du Colombier 	na = 0;
30980ee5cbfSDavid du Colombier 	n = 0;
31080ee5cbfSDavid du Colombier 	for(;;){
31180ee5cbfSDavid du Colombier 		if(na < n+512){
31280ee5cbfSDavid du Colombier 			na += 1024;
31380ee5cbfSDavid du Colombier 			s = realloc(s, na+1);
31480ee5cbfSDavid du Colombier 		}
31580ee5cbfSDavid du Colombier 		m = Bread(w->body, s+n, na-n);
31680ee5cbfSDavid du Colombier 		if(m <= 0)
31780ee5cbfSDavid du Colombier 			break;
31880ee5cbfSDavid du Colombier 		n += m;
31980ee5cbfSDavid du Colombier 	}
32080ee5cbfSDavid du Colombier 	s[n] = 0;
32180ee5cbfSDavid du Colombier 	winclosebody(w);
32280ee5cbfSDavid du Colombier 	*np = n;
32380ee5cbfSDavid du Colombier 	return s;
32480ee5cbfSDavid du Colombier }
325