872 lines · 14.6 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <fcall.h>#include <9pclient.h>#include "term.h"  #define	EVENTSIZE	256#define	STACK	32768 typedef struct Event Event;typedef struct Q Q; struct Event{	int	c1;	int	c2;	int	q0;	int	q1;	int	flag;	int	nb;	int	nr;	char	b[EVENTSIZE*UTFmax+1];	Rune	r[EVENTSIZE+1];}; Event blank = {	'M',	'X',	0, 0, 0, 1, 1,	{ ' ', 0 },	{ ' ', 0 }}; struct Q{	QLock	lk;	int		p;	int		k;}; Q	q; CFid *eventfd;CFid *addrfd;CFid *datafd;CFid *ctlfd;/* int bodyfd; */ char	*typing;int	ntypeb;int	ntyper;int	ntypebreak;int	debug;int	rcfd;int	cook = 1;int	password;int	israw(int); char *name; char **prog;Channel *cwait;int pid = -1; int	label(char*, int);void	error(char*, ...);void	stdinproc(void*);void	stdoutproc(void*);void	type(Event*, int, CFid*, CFid*);void	sende(Event*, int, CFid*, CFid*, CFid*, int);char	*onestring(int, char**);int	delete(Event*);void	deltype(uint, uint);void	sendbs(int, int);void	runproc(void*); intfsfidprint(CFid *fid, char *fmt, ...){	char buf[256];	va_list arg;	int n; 	va_start(arg, fmt);	n = vsnprint(buf, sizeof buf, fmt, arg);	va_end(arg);	return fswrite(fid, buf, n);} voidusage(void){	fprint(2, "usage: win cmd args...\n");	threadexitsall("usage");} voidwaitthread(void *v){	recvp(cwait);	threadexitsall(nil);} voidhangupnote(void *a, char *msg){	if(strcmp(msg, "hangup") == 0 && pid != 0){		postnote(PNGROUP, pid, "hangup");		noted(NDFLT);	}	if(strstr(msg, "child")){		char buf[128];		int n; 		n = awaitnohang(buf, sizeof buf-1);		if(n > 0){			buf[n] = 0;			if(atoi(buf) == pid)				threadexitsall(0);		}		noted(NCONT);	}	noted(NDFLT);} voidthreadmain(int argc, char **argv){	int fd, id;	char buf[256];	char buf1[128];	CFsys *fs;	char *dump;	char *xargv[2];		dump = onestring(argc, argv); 	ARGBEGIN{	case 'd':		debug = 1;		break;	case 'n':		name = EARGF(usage());		break;	default:		usage();	}ARGEND 	prog = argv; 	if(argc == 0){		argc = 1;		argv = xargv;		argv[0] = getenv("FORTH");		if(argv[0] == nil)			argv[0] = "gforth";		argv[1] = 0;	} 	if(name == nil){		if(argc > 0)			name = argv[0];		else{			name = sysname();			if(name == nil)				name = "gnot";		}	} 	/*	 * notedisable("sys: write on closed pipe");	 * not okay to disable the note, because that	 * gets inherited by the subshell, so that something	 * as simple as "yes | sed 10q" never exits.	 * call notifyoff instead.  (is notedisable ever safe?)	 */	notifyoff("sys: write on closed pipe"); 	noteenable("sys: child");	notify(hangupnote); 	if((fs = nsmount("acme", "")) == 0)		sysfatal("nsmount acme: %r");	ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);	if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)		sysfatal("ctl: %r");	id = atoi(buf);	snprint(buf, sizeof buf, "%d", id);	putenv("winid", buf);	sprint(buf, "%d/tag", id);	fd = fsopenfd(fs, buf, OWRITE|OCEXEC);	write(fd, " Send", 1+4);	close(fd);	sprint(buf, "%d/event", id);	eventfd = fsopen(fs, buf, ORDWR|OCEXEC);	sprint(buf, "%d/addr", id);	addrfd = fsopen(fs, buf, ORDWR|OCEXEC);	sprint(buf, "%d/data", id);	datafd = fsopen(fs, buf, ORDWR|OCEXEC);	sprint(buf, "%d/body", id);/*	bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */	if(eventfd==nil || addrfd==nil || datafd==nil)		sysfatal("data files: %r");/*	if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)		sysfatal("data files: %r");*/	fsunmount(fs); 	cwait = threadwaitchan();	threadcreate(waitthread, nil, STACK);	pid = rcstart(argc, argv, &rcfd, nil);	if(pid == -1)		sysfatal("exec failed"); 	getwd(buf1, sizeof buf1);	sprint(buf, "name %s/-%s\n0\n", buf1, name);	fswrite(ctlfd, buf, strlen(buf));	sprint(buf, "dumpdir %s/\n", buf1);	fswrite(ctlfd, buf, strlen(buf));	sprint(buf, "dump %s\n", dump);	fswrite(ctlfd, buf, strlen(buf));	sprint(buf, "scroll");	fswrite(ctlfd, buf, strlen(buf));		updatewinsize(25, 80, 0, 0);	proccreate(stdoutproc, nil, STACK);	stdinproc(nil);} voiderror(char *s, ...){	va_list arg;		if(s){		va_start(arg, s);		s = vsmprint(s, arg);		va_end(arg);		fprint(2, "win: %s: %r\n", s);	}	if(pid != -1)		postnote(PNGROUP, pid, "hangup");	threadexitsall(s);} char*onestring(int argc, char **argv){	char *p;	int i, n;	static char buf[1024]; 	if(argc == 0)		return "";	p = buf;	for(i=0; i<argc; i++){		n = strlen(argv[i]);		if(p+n+1 >= buf+sizeof buf)			break;		memmove(p, argv[i], n);		p += n;		*p++ = ' ';	}	p[-1] = 0;	return buf;} intgetec(CFid *efd){	static char buf[8192];	static char *bufp;	static int nbuf; 	if(nbuf == 0){		nbuf = fsread(efd, buf, sizeof buf);		if(nbuf <= 0)			error(nil);		bufp = buf;	}	--nbuf;	return *bufp++;} intgeten(CFid *efd){	int n, c; 	n = 0;	while('0'<=(c=getec(efd)) && c<='9')		n = n*10+(c-'0');	if(c != ' ')		error("event number syntax");	return n;} intgeter(CFid *efd, char *buf, int *nb){	Rune r;	int n; 	r = getec(efd);	buf[0] = r;	n = 1;	if(r < Runeself)		goto Return;	while(!fullrune(buf, n))		buf[n++] = getec(efd);	chartorune(&r, buf);    Return:	*nb = n;	return r;} voidgete(CFid *efd, Event *e){	int i, nb; 	e->c1 = getec(efd);	e->c2 = getec(efd);	e->q0 = geten(efd);	e->q1 = geten(efd);	e->flag = geten(efd);	e->nr = geten(efd);	if(e->nr > EVENTSIZE)		error("event string too long");	e->nb = 0;	for(i=0; i<e->nr; i++){		e->r[i] = geter(efd, e->b+e->nb, &nb);		e->nb += nb;	}	e->r[e->nr] = 0;	e->b[e->nb] = 0;	if(getec(efd) != '\n')		error("event syntax 2");} intnrunes(char *s, int nb){	int i, n;	Rune r; 	n = 0;	for(i=0; i<nb; n++)		i += chartorune(&r, s+i);	return n;} voidbodyinsert(Event *e){	if(e->nr == 1 && e->r[0] == 0x7F) {		char buf[1];		fsprint(addrfd, "#%ud,#%ud", e->q0, e->q1);		fswrite(datafd, "", 0);		buf[0] = 0x7F;		write(rcfd, buf, 1);		return;	}	if(e->q0 < q.p){		if(debug)			fprint(2, "shift typing %d... ", e->q1-e->q0);		q.p += e->q1-e->q0;	}	else if(e->q0 <= q.p+ntyper){		if(debug)			fprint(2, "type->.. ");		type(e, rcfd, addrfd, datafd);	}} voidbodydelete(Event *e){	int n;	n = delete(e);	q.p -= n;	if(israw(rcfd) && e->q1 >= q.p+n)		sendbs(rcfd, n);} voidstdinproc(void *v){	CFid *cfd = ctlfd;	CFid *efd = eventfd;	CFid *dfd = datafd;	CFid *afd = addrfd;	int fd0 = rcfd;	Event e, e2, e3, e4; 	USED(v); 	for(;;){		if(debug)			fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);		gete(efd, &e);		if(debug)			fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);		qlock(&q.lk);		switch(e.c1){		default:		Unknown:			print("unknown message %c%c\n", e.c1, e.c2);			break; 		case 'E':			switch(e.c2){			case 'I':				bodyinsert(&e);				break;			case 'D':				bodydelete(&e);				break;					case 'i':	/* write to tag; can't affect us */			case 'd':				break;						default:				goto Unknown;			}			break; 		case 'F':	/* generated by our actions; ignore */			break; 		case 'K':		case 'M':			switch(e.c2){			case 'I':				bodyinsert(&e);				break;			case 'D':				bodydelete(&e);				break;			case 'x':			case 'X':				if(e.flag & 2)					gete(efd, &e2);				if(e.flag & 8){					gete(efd, &e3);					gete(efd, &e4);				}				if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){					/* send it straight back */					fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);					break;				}				if(e.q0==e.q1 && (e.flag&2)){					e2.flag = e.flag;					e = e2;				}				char buf[100];				snprint(buf, sizeof buf, "%.*S", e.nr, e.r);				if(cistrcmp(buf, "cook") == 0) {					cook = 1;					break;				}				if(cistrcmp(buf, "nocook") == 0) {					cook = 0;					break;				}				if(e.flag & 8){					if(e.q1 != e.q0){						sende(&e, fd0, cfd, afd, dfd, 0);						sende(&blank, fd0, cfd, afd, dfd, 0);					}					sende(&e3, fd0, cfd, afd, dfd, 1);				}else	 if(e.q1 != e.q0)					sende(&e, fd0, cfd, afd, dfd, 1);				break; 			case 'l':			case 'L':				/* just send it back */				if(e.flag & 2)					gete(efd, &e2);				fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);				break; 			case 'd':			case 'i':				break; 			default:				goto Unknown;			}		}		qunlock(&q.lk);	}} 

Lines 1–500 of 872.