xref: /plan9/acme/bin/source/win/main.c (revision 940d0206b9eb611696bdeb9aaf03c1c58a0a4c6f)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <fcall.h>
69a747e4fSDavid du Colombier #include <9p.h>
79a747e4fSDavid du Colombier #include <ctype.h>
87dd7cddfSDavid du Colombier #include "dat.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier void	mainctl(void*);
119a747e4fSDavid du Colombier void	startcmd(char *[], int*);
127dd7cddfSDavid du Colombier void	stdout2body(void*);
137dd7cddfSDavid du Colombier 
149a747e4fSDavid du Colombier int	debug;
159a747e4fSDavid du Colombier int	notepg;
16d9306527SDavid du Colombier int	eraseinput;
177dd7cddfSDavid du Colombier int	dirty = 0;
187dd7cddfSDavid du Colombier 
199a747e4fSDavid du Colombier Window *win;		/* the main window */
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier void
usage(void)227dd7cddfSDavid du Colombier usage(void)
237dd7cddfSDavid du Colombier {
249a747e4fSDavid du Colombier 	fprint(2, "usage: win [command]\n");
257dd7cddfSDavid du Colombier 	threadexitsall("usage");
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier void
threadmain(int argc,char * argv[])297dd7cddfSDavid du Colombier threadmain(int argc, char *argv[])
307dd7cddfSDavid du Colombier {
317dd7cddfSDavid du Colombier 	int i, j;
327dd7cddfSDavid du Colombier 	char *dir, *tag, *name;
337dd7cddfSDavid du Colombier 	char buf[1024], **av;
347dd7cddfSDavid du Colombier 
359a747e4fSDavid du Colombier 	quotefmtinstall();
369a747e4fSDavid du Colombier 	rfork(RFNAMEG);
377dd7cddfSDavid du Colombier 	ARGBEGIN{
389a747e4fSDavid du Colombier 	case 'd':
399a747e4fSDavid du Colombier 		debug = 1;
40d3c05884SDavid du Colombier 		chatty9p++;
419a747e4fSDavid du Colombier 		break;
42d9306527SDavid du Colombier 	case 'e':
43d9306527SDavid du Colombier 		eraseinput = 1;
44d9306527SDavid du Colombier 		break;
453ff48bf5SDavid du Colombier 	case 'D':
463ff48bf5SDavid du Colombier {extern int _threaddebuglevel;
473ff48bf5SDavid du Colombier 		_threaddebuglevel = 1<<20;
483ff48bf5SDavid du Colombier }
497dd7cddfSDavid du Colombier 	}ARGEND
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	if(argc == 0){
527dd7cddfSDavid du Colombier 		av = emalloc(3*sizeof(char*));
537dd7cddfSDavid du Colombier 		av[0] = "rc";
547dd7cddfSDavid du Colombier 		av[1] = "-i";
557dd7cddfSDavid du Colombier 		name = getenv("sysname");
567dd7cddfSDavid du Colombier 	}else{
577dd7cddfSDavid du Colombier 		av = argv;
587dd7cddfSDavid du Colombier 		name = utfrrune(av[0], '/');
597dd7cddfSDavid du Colombier 		if(name)
607dd7cddfSDavid du Colombier 			name++;
617dd7cddfSDavid du Colombier 		else
627dd7cddfSDavid du Colombier 			name = av[0];
637dd7cddfSDavid du Colombier 	}
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	if(getwd(buf, sizeof buf) == 0)
667dd7cddfSDavid du Colombier 		dir = "/";
677dd7cddfSDavid du Colombier 	else
687dd7cddfSDavid du Colombier 		dir = buf;
697dd7cddfSDavid du Colombier 	dir = estrdup(dir);
707dd7cddfSDavid du Colombier 	tag = estrdup(dir);
717dd7cddfSDavid du Colombier 	tag = eappend(estrdup(tag), "/-", name);
727dd7cddfSDavid du Colombier 	win = newwindow();
73b8661318SDavid du Colombier 	snprint(buf, sizeof buf, "%d", win->id);
74b8661318SDavid du Colombier 	putenv("winid", buf);
757dd7cddfSDavid du Colombier 	winname(win, tag);
767dd7cddfSDavid du Colombier 	wintagwrite(win, "Send Noscroll", 5+8);
777dd7cddfSDavid du Colombier 	threadcreate(mainctl, win, STACK);
789a747e4fSDavid du Colombier 	mountcons();
799a747e4fSDavid du Colombier 	threadcreate(fsloop, nil, STACK);
807dd7cddfSDavid du Colombier 	startpipe();
819a747e4fSDavid du Colombier 	startcmd(av, &notepg);
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	strcpy(buf, "win");
847dd7cddfSDavid du Colombier 	j = 3;
857dd7cddfSDavid du Colombier 	for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){
867dd7cddfSDavid du Colombier 		strcpy(buf+j, " ");
877dd7cddfSDavid du Colombier 		strcpy(buf+j+1, argv[i]);
887dd7cddfSDavid du Colombier 		j += 1+strlen(argv[i]);
897dd7cddfSDavid du Colombier 	}
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	ctlprint(win->ctl, "scroll");
927dd7cddfSDavid du Colombier 	winsetdump(win, dir, buf);
937dd7cddfSDavid du Colombier }
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier int
EQUAL(char * s,char * t)967dd7cddfSDavid du Colombier EQUAL(char *s, char *t)
977dd7cddfSDavid du Colombier {
987dd7cddfSDavid du Colombier 	while(tolower(*s) == tolower(*t++))
997dd7cddfSDavid du Colombier 		if(*s++ == '\0')
1007dd7cddfSDavid du Colombier 			return 1;
1017dd7cddfSDavid du Colombier 	return 0;
1027dd7cddfSDavid du Colombier }
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier int
command(Window * w,char * s)1057dd7cddfSDavid du Colombier command(Window *w, char *s)
1067dd7cddfSDavid du Colombier {
1077dd7cddfSDavid du Colombier 	while(*s==' ' || *s=='\t' || *s=='\n')
1087dd7cddfSDavid du Colombier 		s++;
1093c2ddefeSDavid du Colombier 	if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){
110*940d0206SDavid du Colombier 		write(notepg, "hangup", 6);
1117dd7cddfSDavid du Colombier 		windel(w, 1);
1127dd7cddfSDavid du Colombier 		threadexitsall(nil);
1137dd7cddfSDavid du Colombier 		return 1;
1147dd7cddfSDavid du Colombier 	}
1157dd7cddfSDavid du Colombier 	if(EQUAL(s, "scroll")){
1167dd7cddfSDavid du Colombier 		ctlprint(w->ctl, "scroll\nshow");
1177dd7cddfSDavid du Colombier 		return 1;
1187dd7cddfSDavid du Colombier 	}
1197dd7cddfSDavid du Colombier 	if(EQUAL(s, "noscroll")){
1207dd7cddfSDavid du Colombier 		ctlprint(w->ctl, "noscroll");
1217dd7cddfSDavid du Colombier 		return 1;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 	return 0;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
1269a747e4fSDavid du Colombier static long
utfncpy(char * to,char * from,int n)1279a747e4fSDavid du Colombier utfncpy(char *to, char *from, int n)
1289a747e4fSDavid du Colombier {
1299a747e4fSDavid du Colombier 	char *end, *e;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	e = to+n;
1329a747e4fSDavid du Colombier 	if(to >= e)
1339a747e4fSDavid du Colombier 		return 0;
1349a747e4fSDavid du Colombier 	end = memccpy(to, from, '\0', e - to);
1359a747e4fSDavid du Colombier 	if(end == nil){
1369a747e4fSDavid du Colombier 		end = e;
1379a747e4fSDavid du Colombier 		if(end[-1]&0x80){
1389a747e4fSDavid du Colombier 			if(end-2>=to && (end[-2]&0xE0)==0xC0)
1399a747e4fSDavid du Colombier 				return end-to;
1409a747e4fSDavid du Colombier 			if(end-3>=to && (end[-3]&0xF0)==0xE0)
1419a747e4fSDavid du Colombier 				return end-to;
1429a747e4fSDavid du Colombier 			while(end>to && (*--end&0xC0)==0x80)
1439a747e4fSDavid du Colombier 				;
1449a747e4fSDavid du Colombier 		}
1459a747e4fSDavid du Colombier 	}else
1469a747e4fSDavid du Colombier 		end--;
1479a747e4fSDavid du Colombier 	return end - to;
1489a747e4fSDavid du Colombier }
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier /* sendinput and fsloop run in the same proc (can't interrupt each other). */
1519a747e4fSDavid du Colombier static Req *q;
1529a747e4fSDavid du Colombier static Req **eq;
1539a747e4fSDavid du Colombier static int
__sendinput(Window * w,ulong q0,ulong q1)154d9306527SDavid du Colombier __sendinput(Window *w, ulong q0, ulong q1)
1559a747e4fSDavid du Colombier {
1569a747e4fSDavid du Colombier 	char *s, *t;
1579a747e4fSDavid du Colombier 	int n, nb, eofchar;
1589a747e4fSDavid du Colombier 	static int partial;
1599a747e4fSDavid du Colombier 	static char tmp[UTFmax];
1609a747e4fSDavid du Colombier 	Req *r;
1619a747e4fSDavid du Colombier 	Rune rune;
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier 	if(!q)
1649a747e4fSDavid du Colombier 		return 0;
1659a747e4fSDavid du Colombier 
1669a747e4fSDavid du Colombier 	r = q;
1679a747e4fSDavid du Colombier 	n = 0;
1689a747e4fSDavid du Colombier 	if(partial){
1699a747e4fSDavid du Colombier 	Partial:
1709a747e4fSDavid du Colombier 		nb = partial;
1719a747e4fSDavid du Colombier 		if(nb > r->ifcall.count)
1729a747e4fSDavid du Colombier 			nb = r->ifcall.count;
1739a747e4fSDavid du Colombier 		memmove(r->ofcall.data, tmp, nb);
1749a747e4fSDavid du Colombier 		if(nb!=partial)
1759a747e4fSDavid du Colombier 			memmove(tmp, tmp+nb, partial-nb);
1769a747e4fSDavid du Colombier 		partial -= nb;
1779a747e4fSDavid du Colombier 		q = r->aux;
1789a747e4fSDavid du Colombier 		if(q == nil)
1799a747e4fSDavid du Colombier 			eq = &q;
1809a747e4fSDavid du Colombier 		r->aux = nil;
1819a747e4fSDavid du Colombier 		r->ofcall.count = nb;
1829a747e4fSDavid du Colombier 		if(debug)
1839a747e4fSDavid du Colombier 			fprint(2, "satisfy read with partial\n");
1849a747e4fSDavid du Colombier 		respond(r, nil);
1859a747e4fSDavid du Colombier 		return n;
1869a747e4fSDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	if(q0==q1)
1889a747e4fSDavid du Colombier 		return 0;
1899a747e4fSDavid du Colombier 	s = emalloc((q1-q0)*UTFmax+1);
1909a747e4fSDavid du Colombier 	n = winread(w, q0, q1, s);
1919a747e4fSDavid du Colombier 	s[n] = '\0';
1929a747e4fSDavid du Colombier 	t = strpbrk(s, "\n\004");
1939a747e4fSDavid du Colombier 	if(t == nil){
1949a747e4fSDavid du Colombier 		free(s);
1959a747e4fSDavid du Colombier 		return 0;
1969a747e4fSDavid du Colombier 	}
1979a747e4fSDavid du Colombier 	r = q;
1989a747e4fSDavid du Colombier 	eofchar = 0;
1999a747e4fSDavid du Colombier 	if(*t == '\004'){
2009a747e4fSDavid du Colombier 		eofchar = 1;
2019a747e4fSDavid du Colombier 		*t = '\0';
2029a747e4fSDavid du Colombier 	}else
2039a747e4fSDavid du Colombier 		*++t = '\0';
2049a747e4fSDavid du Colombier 	nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count);
2059a747e4fSDavid du Colombier 	if(nb==0 && s<t && r->ifcall.count > 0){
2069a747e4fSDavid du Colombier 		partial = utfncpy(tmp, s, UTFmax);
2079a747e4fSDavid du Colombier 		assert(partial > 0);
2089a747e4fSDavid du Colombier 		chartorune(&rune, tmp);
2099a747e4fSDavid du Colombier 		partial = runelen(rune);
2109a747e4fSDavid du Colombier 		free(s);
2119a747e4fSDavid du Colombier 		n = 1;
2129a747e4fSDavid du Colombier 		goto Partial;
2139a747e4fSDavid du Colombier 	}
2149a747e4fSDavid du Colombier 	n = utfnlen(r->ofcall.data, nb);
2159a747e4fSDavid du Colombier 	if(nb==strlen(s) && eofchar)
2169a747e4fSDavid du Colombier 		n++;
2179a747e4fSDavid du Colombier 	r->ofcall.count = nb;
2189a747e4fSDavid du Colombier 	q = r->aux;
2199a747e4fSDavid du Colombier 	if(q == nil)
2209a747e4fSDavid du Colombier 		eq = &q;
2219a747e4fSDavid du Colombier 	r->aux = nil;
2229a747e4fSDavid du Colombier 	if(debug)
2239a747e4fSDavid du Colombier 		fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data);
2249a747e4fSDavid du Colombier 	respond(r, nil);
2259a747e4fSDavid du Colombier 	return n;
2269a747e4fSDavid du Colombier }
2279a747e4fSDavid du Colombier 
228d9306527SDavid du Colombier static int
_sendinput(Window * w,ulong q0,ulong * q1)229d9306527SDavid du Colombier _sendinput(Window *w, ulong q0, ulong *q1)
230d9306527SDavid du Colombier {
231d9306527SDavid du Colombier 	char buf[32];
232d9306527SDavid du Colombier 	int n;
233d9306527SDavid du Colombier 
234d9306527SDavid du Colombier 	n = __sendinput(w, q0, *q1);
235d9306527SDavid du Colombier 	if(!n || !eraseinput)
236d9306527SDavid du Colombier 		return n;
237d9306527SDavid du Colombier 	/* erase q0 to q0+n */
238d9306527SDavid du Colombier 	sprint(buf, "#%lud,#%lud", q0, q0+n);
239d9306527SDavid du Colombier 	winsetaddr(w, buf, 0);
240d9306527SDavid du Colombier 	write(w->data, buf, 0);
241d9306527SDavid du Colombier 	*q1 -= n;
242d9306527SDavid du Colombier 	return 0;
243d9306527SDavid du Colombier }
244d9306527SDavid du Colombier 
2457dd7cddfSDavid du Colombier int
sendinput(Window * w,ulong q0,ulong * q1)246d9306527SDavid du Colombier sendinput(Window *w, ulong q0, ulong *q1)
2477dd7cddfSDavid du Colombier {
2489a747e4fSDavid du Colombier 	ulong n;
2499a747e4fSDavid du Colombier 	Req *oq;
2507dd7cddfSDavid du Colombier 
2519a747e4fSDavid du Colombier 	n = 0;
2529a747e4fSDavid du Colombier 	do {
2539a747e4fSDavid du Colombier 		oq = q;
2549a747e4fSDavid du Colombier 		n += _sendinput(w, q0+n, q1);
2559a747e4fSDavid du Colombier 	} while(q != oq);
2569a747e4fSDavid du Colombier 	return n;
2577dd7cddfSDavid du Colombier }
2589a747e4fSDavid du Colombier 
2599a747e4fSDavid du Colombier Event esendinput;
2609a747e4fSDavid du Colombier void
fsloop(void *)2619a747e4fSDavid du Colombier fsloop(void*)
2629a747e4fSDavid du Colombier {
2639a747e4fSDavid du Colombier 	Fsevent e;
2649a747e4fSDavid du Colombier 	Req **l, *r;
2659a747e4fSDavid du Colombier 
2669a747e4fSDavid du Colombier 	eq = &q;
2679a747e4fSDavid du Colombier 	memset(&esendinput, 0, sizeof esendinput);
2689a747e4fSDavid du Colombier 	esendinput.c1 = 'C';
2699a747e4fSDavid du Colombier 	for(;;){
2709a747e4fSDavid du Colombier 		while(recv(fschan, &e) == -1)
2719a747e4fSDavid du Colombier 			;
2729a747e4fSDavid du Colombier 		r = e.r;
2739a747e4fSDavid du Colombier 		switch(e.type){
2749a747e4fSDavid du Colombier 		case 'r':
2759a747e4fSDavid du Colombier 			*eq = r;
2769a747e4fSDavid du Colombier 			r->aux = nil;
2779a747e4fSDavid du Colombier 			eq = &r->aux;
2789a747e4fSDavid du Colombier 			/* call sendinput with hostpt and endpt */
2799a747e4fSDavid du Colombier 			sendp(win->cevent, &esendinput);
2809a747e4fSDavid du Colombier 			break;
2819a747e4fSDavid du Colombier 		case 'f':
2829a747e4fSDavid du Colombier 			for(l=&q; *l; l=&(*l)->aux){
2839a747e4fSDavid du Colombier 				if(*l == r->oldreq){
284d3c05884SDavid du Colombier 					*l = (*l)->aux;
2859a747e4fSDavid du Colombier 					if(*l == nil)
2869a747e4fSDavid du Colombier 						eq = l;
287d3c05884SDavid du Colombier 					respond(r->oldreq, "interrupted");
2889a747e4fSDavid du Colombier 					break;
2899a747e4fSDavid du Colombier 				}
2909a747e4fSDavid du Colombier 			}
2919a747e4fSDavid du Colombier 			respond(r, nil);
2929a747e4fSDavid du Colombier 			break;
2939a747e4fSDavid du Colombier 		}
2949a747e4fSDavid du Colombier 	}
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
sendit(char * s)2987dd7cddfSDavid du Colombier sendit(char *s)
2997dd7cddfSDavid du Colombier {
3009a747e4fSDavid du Colombier //	char tmp[32];
3017dd7cddfSDavid du Colombier 
3029a747e4fSDavid du Colombier 	write(win->body, s, strlen(s));
3039a747e4fSDavid du Colombier /*
3049a747e4fSDavid du Colombier  * RSC: The problem here is that other procs can call sendit,
3059a747e4fSDavid du Colombier  * so we lose our single-threadedness if we call sendinput.
3069a747e4fSDavid du Colombier  * In fact, we don't even have the right queue memory,
3079a747e4fSDavid du Colombier  * I think that we'll get a write event from the body write above,
3089a747e4fSDavid du Colombier  * and we can do the sendinput then, from our single thread.
3099a747e4fSDavid du Colombier  *
3109a747e4fSDavid du Colombier  * I still need to figure out how to test this assertion for
3119a747e4fSDavid du Colombier  * programs that use /srv/win*
3129a747e4fSDavid du Colombier  *
3139a747e4fSDavid du Colombier 	winselect(win, "$", 0);
3147dd7cddfSDavid du Colombier 	seek(win->addr, 0UL, 0);
3157dd7cddfSDavid du Colombier 	if(read(win->addr, tmp, 2*12) == 2*12)
3169a747e4fSDavid du Colombier 		hostpt += sendinput(win, hostpt, atol(tmp), );
3179a747e4fSDavid du Colombier  */
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier void
execevent(Window * w,Event * e,int (* command)(Window *,char *))3217dd7cddfSDavid du Colombier execevent(Window *w, Event *e, int (*command)(Window*, char*))
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	Event *ea, *e2;
3249a747e4fSDavid du Colombier 	int n, na, len, needfree;
3257dd7cddfSDavid du Colombier 	char *s, *t;
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	ea = nil;
3287dd7cddfSDavid du Colombier 	e2 = nil;
3297dd7cddfSDavid du Colombier 	if(e->flag & 2)
3307dd7cddfSDavid du Colombier 		e2 = recvp(w->cevent);
3317dd7cddfSDavid du Colombier 	if(e->flag & 8){
3327dd7cddfSDavid du Colombier 		ea = recvp(w->cevent);
3337dd7cddfSDavid du Colombier 		na = ea->nb;
3347dd7cddfSDavid du Colombier 		recvp(w->cevent);
3357dd7cddfSDavid du Colombier 	}else
3367dd7cddfSDavid du Colombier 		na = 0;
3379a747e4fSDavid du Colombier 
3389a747e4fSDavid du Colombier 	needfree = 0;
3397dd7cddfSDavid du Colombier 	s = e->b;
3409a747e4fSDavid du Colombier 	if(e->nb==0 && (e->flag&2)){
3417dd7cddfSDavid du Colombier 		s = e2->b;
3429a747e4fSDavid du Colombier 		e->q0 = e2->q0;
3439a747e4fSDavid du Colombier 		e->q1 = e2->q1;
3449a747e4fSDavid du Colombier 		e->nb = e2->nb;
3457dd7cddfSDavid du Colombier 	}
3469a747e4fSDavid du Colombier 	if(e->nb==0 && e->q0<e->q1){
3479a747e4fSDavid du Colombier 		/* fetch data from window */
3489a747e4fSDavid du Colombier 		s = emalloc((e->q1-e->q0)*UTFmax+2);
3499a747e4fSDavid du Colombier 		n = winread(w, e->q0, e->q1, s);
3509a747e4fSDavid du Colombier 		s[n] = '\0';
3519a747e4fSDavid du Colombier 		needfree = 1;
3529a747e4fSDavid du Colombier 	}else
3539a747e4fSDavid du Colombier 	if(na){
3549a747e4fSDavid du Colombier 		t = emalloc(strlen(s)+1+na+2);
3559a747e4fSDavid du Colombier 		sprint(t, "%s %s", s, ea->b);
3569a747e4fSDavid du Colombier 		if(needfree)
3579a747e4fSDavid du Colombier 			free(s);
3589a747e4fSDavid du Colombier 		s = t;
3599a747e4fSDavid du Colombier 		needfree = 1;
3609a747e4fSDavid du Colombier 	}
3619a747e4fSDavid du Colombier 
3629a747e4fSDavid du Colombier 	/* if it's a known command, do it */
3637dd7cddfSDavid du Colombier 	/* if it's a long message, it can't be for us anyway */
3647dd7cddfSDavid du Colombier 	if(!command(w, s) && s[0]!='\0'){	/* send it as typed text */
3657dd7cddfSDavid du Colombier 		/* if it's a built-in from the tag, send it back */
3667dd7cddfSDavid du Colombier 		if(e->flag & 1)
3679a747e4fSDavid du Colombier 			fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
3689a747e4fSDavid du Colombier 		else{	/* send text to main window */
3699a747e4fSDavid du Colombier 			len = strlen(s);
3709a747e4fSDavid du Colombier 			if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){
3719a747e4fSDavid du Colombier 				if(!needfree){
3729a747e4fSDavid du Colombier 					/* if(needfree), we left room for a newline before */
3739a747e4fSDavid du Colombier 					t = emalloc(len+2);
3749a747e4fSDavid du Colombier 					strcpy(t, s);
3759a747e4fSDavid du Colombier 					s = t;
3769a747e4fSDavid du Colombier 					needfree = 1;
3779a747e4fSDavid du Colombier 				}
3789a747e4fSDavid du Colombier 				s[len++] = '\n';
3799a747e4fSDavid du Colombier 				s[len] = '\0';
3809a747e4fSDavid du Colombier 			}
3817dd7cddfSDavid du Colombier 			sendit(s);
3827dd7cddfSDavid du Colombier 		}
3839a747e4fSDavid du Colombier 	}
3849a747e4fSDavid du Colombier 	if(needfree)
3857dd7cddfSDavid du Colombier 		free(s);
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
3889a747e4fSDavid du Colombier int
hasboundary(Rune * r,int nr)3899a747e4fSDavid du Colombier hasboundary(Rune *r, int nr)
3909a747e4fSDavid du Colombier {
3919a747e4fSDavid du Colombier 	int i;
3929a747e4fSDavid du Colombier 
3939a747e4fSDavid du Colombier 	for(i=0; i<nr; i++)
3949a747e4fSDavid du Colombier 		if(r[i]=='\n' || r[i]=='\004')
3959a747e4fSDavid du Colombier 			return 1;
3969a747e4fSDavid du Colombier 	return 0;
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier 
3997dd7cddfSDavid du Colombier void
mainctl(void * v)4007dd7cddfSDavid du Colombier mainctl(void *v)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 	Window *w;
4037dd7cddfSDavid du Colombier 	Event *e;
404d9306527SDavid du Colombier 	int delta, pendingS, pendingK;
405d9306527SDavid du Colombier 	ulong hostpt, endpt;
4067dd7cddfSDavid du Colombier 	char tmp[32];
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier 	w = v;
4097dd7cddfSDavid du Colombier 	proccreate(wineventproc, w, STACK);
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	hostpt = 0;
4129a747e4fSDavid du Colombier 	endpt = 0;
4137dd7cddfSDavid du Colombier 	winsetaddr(w, "0", 0);
4149a747e4fSDavid du Colombier 	pendingS = 0;
4159a747e4fSDavid du Colombier 	pendingK = 0;
4167dd7cddfSDavid du Colombier 	for(;;){
4179a747e4fSDavid du Colombier 		if(debug)
418d9306527SDavid du Colombier 			fprint(2, "input range %lud-%lud\n", hostpt, endpt);
4197dd7cddfSDavid du Colombier 		e = recvp(w->cevent);
4209a747e4fSDavid du Colombier 		if(debug)
4219a747e4fSDavid du Colombier 			fprint(2, "msg: %C %C %d %d %d %d %q\n",
4229a747e4fSDavid du Colombier 				e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b);
4237dd7cddfSDavid du Colombier 		switch(e->c1){
4247dd7cddfSDavid du Colombier 		default:
4257dd7cddfSDavid du Colombier 		Unknown:
4269a747e4fSDavid du Colombier 			fprint(2, "unknown message %c%c\n", e->c1, e->c2);
4279a747e4fSDavid du Colombier 			break;
4289a747e4fSDavid du Colombier 
4299a747e4fSDavid du Colombier 		case 'C':	/* input needed for /dev/cons */
4309a747e4fSDavid du Colombier 			if(pendingS)
4319a747e4fSDavid du Colombier 				pendingK = 1;
4329a747e4fSDavid du Colombier 			else
433d9306527SDavid du Colombier 				hostpt += sendinput(w, hostpt, &endpt);
4347dd7cddfSDavid du Colombier 			break;
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier 		case 'S':	/* output to stdout */
437d9306527SDavid du Colombier 			sprint(tmp, "#%lud", hostpt);
4389a747e4fSDavid du Colombier 			winsetaddr(w, tmp, 0);
4397dd7cddfSDavid du Colombier 			write(w->data, e->b, e->nb);
4408cd281c0SDavid du Colombier 			pendingS += e->nr;
4417dd7cddfSDavid du Colombier 			break;
4427dd7cddfSDavid du Colombier 
4439a747e4fSDavid du Colombier 		case 'E':	/* write to tag or body; body happens due to sendit */
4449a747e4fSDavid du Colombier 			delta = e->q1-e->q0;
4459a747e4fSDavid du Colombier 			if(e->c2=='I'){
4469a747e4fSDavid du Colombier 				endpt += delta;
4479a747e4fSDavid du Colombier 				if(e->q0 < hostpt)
4489a747e4fSDavid du Colombier 					hostpt += delta;
4499a747e4fSDavid du Colombier 				else
450d9306527SDavid du Colombier 					hostpt += sendinput(w, hostpt, &endpt);
4519a747e4fSDavid du Colombier 				break;
4529a747e4fSDavid du Colombier 			}
4539a747e4fSDavid du Colombier 			if(!islower(e->c2))
4549a747e4fSDavid du Colombier 				fprint(2, "win msg: %C %C %d %d %d %d %q\n",
4559a747e4fSDavid du Colombier 					e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
4567dd7cddfSDavid du Colombier 			break;
4577dd7cddfSDavid du Colombier 
4589a747e4fSDavid du Colombier 		case 'F':	/* generated by our actions (specifically case 'S' above) */
4599a747e4fSDavid du Colombier 			delta = e->q1-e->q0;
460d9306527SDavid du Colombier 			if(e->c2=='D'){
461d9306527SDavid du Colombier 				/* we know about the delete by _sendinput */
462d9306527SDavid du Colombier 				break;
463d9306527SDavid du Colombier 			}
4649a747e4fSDavid du Colombier 			if(e->c2=='I'){
4659a747e4fSDavid du Colombier 				pendingS -= e->q1 - e->q0;
4669a747e4fSDavid du Colombier 				if(pendingS < 0)
4679a747e4fSDavid du Colombier 					fprint(2, "win: pendingS = %d\n", pendingS);
4689a747e4fSDavid du Colombier 				if(e->q0 != hostpt)
469d9306527SDavid du Colombier 					fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt);
4709a747e4fSDavid du Colombier 				endpt += delta;
4719a747e4fSDavid du Colombier 				hostpt += delta;
4729a747e4fSDavid du Colombier 				sendp(writechan, nil);
4739a747e4fSDavid du Colombier 				if(pendingS == 0 && pendingK){
4749a747e4fSDavid du Colombier 					pendingK = 0;
475d9306527SDavid du Colombier 					hostpt += sendinput(w, hostpt, &endpt);
4769a747e4fSDavid du Colombier 				}
4779a747e4fSDavid du Colombier 				break;
4789a747e4fSDavid du Colombier 			}
4799a747e4fSDavid du Colombier 			if(!islower(e->c2))
4809a747e4fSDavid du Colombier 				fprint(2, "win msg: %C %C %d %d %d %d %q\n",
4819a747e4fSDavid du Colombier 					e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
4827dd7cddfSDavid du Colombier 			break;
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 		case 'K':
4859a747e4fSDavid du Colombier 			delta = e->q1-e->q0;
4867dd7cddfSDavid du Colombier 			switch(e->c2){
4877dd7cddfSDavid du Colombier 			case 'D':
4889a747e4fSDavid du Colombier 				endpt -= delta;
4897dd7cddfSDavid du Colombier 				if(e->q1 < hostpt)
4909a747e4fSDavid du Colombier 					hostpt -= delta;
4917dd7cddfSDavid du Colombier 				else if(e->q0 < hostpt)
4927dd7cddfSDavid du Colombier 					hostpt = e->q0;
4937dd7cddfSDavid du Colombier 				break;
4947dd7cddfSDavid du Colombier 			case 'I':
4957dd7cddfSDavid du Colombier 				delta = e->q1 - e->q0;
4969a747e4fSDavid du Colombier 				endpt += delta;
4973ff48bf5SDavid du Colombier 				if(endpt < e->q1)	/* just in case */
4983ff48bf5SDavid du Colombier 					endpt = e->q1;
4999a747e4fSDavid du Colombier 				if(e->q0 < hostpt)
5007dd7cddfSDavid du Colombier 					hostpt += delta;
5013ff48bf5SDavid du Colombier 				if(e->nr>0 && e->r[e->nr-1]==0x7F){
5023ff48bf5SDavid du Colombier 					write(notepg, "interrupt", 9);
5033ff48bf5SDavid du Colombier 					hostpt = endpt;
5043ff48bf5SDavid du Colombier 					break;
5053ff48bf5SDavid du Colombier 				}
5063ff48bf5SDavid du Colombier 				if(e->q0 >= hostpt
5073ff48bf5SDavid du Colombier 				&& hasboundary(e->r, e->nr)){
5089a747e4fSDavid du Colombier 					/*
5099a747e4fSDavid du Colombier 					 * If we are between the S message (which
5109a747e4fSDavid du Colombier 					 * we processed by inserting text in the
5119a747e4fSDavid du Colombier 					 * window) and the F message notifying us
5129a747e4fSDavid du Colombier 					 * that the text has been inserted, then our
5139a747e4fSDavid du Colombier 					 * impression of the hostpt and acme's
5149a747e4fSDavid du Colombier 					 * may be different.  This could be seen if you
5159a747e4fSDavid du Colombier 					 * hit enter a bunch of times in a con
5169a747e4fSDavid du Colombier 					 * session.  To work around the unreliability,
5179a747e4fSDavid du Colombier 					 * only send input if we don't have an S pending.
5189a747e4fSDavid du Colombier 					 * The same race occurs between when a character
5199a747e4fSDavid du Colombier 					 * is typed and when we get notice of it, but
5209a747e4fSDavid du Colombier 					 * since characters tend to be typed at the end
5219a747e4fSDavid du Colombier 					 * of the buffer, we don't run into it.  There's
5229a747e4fSDavid du Colombier 					 * no workaround possible for this typing race,
5239a747e4fSDavid du Colombier 					 * since we can't tell when the user has typed
5249a747e4fSDavid du Colombier 					 * something but we just haven't been notified.
5259a747e4fSDavid du Colombier 					 */
5269a747e4fSDavid du Colombier 					if(pendingS)
5279a747e4fSDavid du Colombier 						pendingK = 1;
5289a747e4fSDavid du Colombier 					else
529d9306527SDavid du Colombier 						hostpt += sendinput(w, hostpt, &endpt);
5309a747e4fSDavid du Colombier 				}
5317dd7cddfSDavid du Colombier 				break;
5327dd7cddfSDavid du Colombier 			}
5337dd7cddfSDavid du Colombier 			break;
5347dd7cddfSDavid du Colombier 
5359a747e4fSDavid du Colombier 		case 'M':	/* mouse */
5369a747e4fSDavid du Colombier 			delta = e->q1-e->q0;
5377dd7cddfSDavid du Colombier 			switch(e->c2){
5387dd7cddfSDavid du Colombier 			case 'x':
5397dd7cddfSDavid du Colombier 			case 'X':
5407dd7cddfSDavid du Colombier 				execevent(w, e, command);
5417dd7cddfSDavid du Colombier 				break;
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier 			case 'l':	/* reflect all searches back to acme */
5447dd7cddfSDavid du Colombier 			case 'L':
5457dd7cddfSDavid du Colombier 				if(e->flag & 2)
5467dd7cddfSDavid du Colombier 					recvp(w->cevent);
5477dd7cddfSDavid du Colombier 				winwriteevent(w, e);
5487dd7cddfSDavid du Colombier 				break;
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier 			case 'I':
5519a747e4fSDavid du Colombier 				endpt += delta;
5529a747e4fSDavid du Colombier 				if(e->q0 < hostpt)
5539a747e4fSDavid du Colombier 					hostpt += delta;
5547dd7cddfSDavid du Colombier 				else
555d9306527SDavid du Colombier 					hostpt += sendinput(w, hostpt, &endpt);
5567dd7cddfSDavid du Colombier 				break;
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier 			case 'D':
5599a747e4fSDavid du Colombier 				endpt -= delta;
5607dd7cddfSDavid du Colombier 				if(e->q1 < hostpt)
5619a747e4fSDavid du Colombier 					hostpt -= delta;
5627dd7cddfSDavid du Colombier 				else if(e->q0 < hostpt)
5637dd7cddfSDavid du Colombier 					hostpt = e->q0;
5647dd7cddfSDavid du Colombier 				break;
5657dd7cddfSDavid du Colombier 			case 'd':	/* modify away; we don't care */
5667dd7cddfSDavid du Colombier 			case 'i':
5677dd7cddfSDavid du Colombier 				break;
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 			default:
5707dd7cddfSDavid du Colombier 				goto Unknown;
5717dd7cddfSDavid du Colombier 			}
5727dd7cddfSDavid du Colombier 		}
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier }
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier enum
5777dd7cddfSDavid du Colombier {
5787dd7cddfSDavid du Colombier 	NARGS		= 100,
5797dd7cddfSDavid du Colombier 	NARGCHAR	= 8*1024,
5807dd7cddfSDavid du Colombier 	EXECSTACK 	= STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
5817dd7cddfSDavid du Colombier };
5827dd7cddfSDavid du Colombier 
5837dd7cddfSDavid du Colombier struct Exec
5847dd7cddfSDavid du Colombier {
5857dd7cddfSDavid du Colombier 	char		**argv;
5867dd7cddfSDavid du Colombier 	Channel	*cpid;
5877dd7cddfSDavid du Colombier };
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier int
lookinbin(char * s)5907dd7cddfSDavid du Colombier lookinbin(char *s)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	if(s[0] == '/')
5937dd7cddfSDavid du Colombier 		return 0;
5947dd7cddfSDavid du Colombier 	if(s[0]=='.' && s[1]=='/')
5957dd7cddfSDavid du Colombier 		return 0;
5967dd7cddfSDavid du Colombier 	if(s[0]=='.' && s[1]=='.' && s[2]=='/')
5977dd7cddfSDavid du Colombier 		return 0;
5987dd7cddfSDavid du Colombier 	return 1;
5997dd7cddfSDavid du Colombier }
6007dd7cddfSDavid du Colombier 
6017dd7cddfSDavid du Colombier /* adapted from mail.  not entirely free of details from that environment */
6027dd7cddfSDavid du Colombier void
execproc(void * v)6037dd7cddfSDavid du Colombier execproc(void *v)
6047dd7cddfSDavid du Colombier {
6057dd7cddfSDavid du Colombier 	struct Exec *e;
6067dd7cddfSDavid du Colombier 	char *cmd, **av;
6077dd7cddfSDavid du Colombier 	Channel *cpid;
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier 	e = v;
6103ff48bf5SDavid du Colombier 	rfork(RFCFDG|RFNOTEG);
6117dd7cddfSDavid du Colombier 	av = e->argv;
6127dd7cddfSDavid du Colombier 	close(0);
6137dd7cddfSDavid du Colombier 	open("/dev/cons", OREAD);
6147dd7cddfSDavid du Colombier 	close(1);
6157dd7cddfSDavid du Colombier 	open("/dev/cons", OWRITE);
6167dd7cddfSDavid du Colombier 	dup(1, 2);
6177dd7cddfSDavid du Colombier 	cpid = e->cpid;
6187dd7cddfSDavid du Colombier 	free(e);
6197dd7cddfSDavid du Colombier 	procexec(cpid, av[0], av);
6207dd7cddfSDavid du Colombier 	if(lookinbin(av[0])){
6217dd7cddfSDavid du Colombier 		cmd = estrstrdup("/bin/", av[0]);
6227dd7cddfSDavid du Colombier 		procexec(cpid, cmd, av);
6237dd7cddfSDavid du Colombier 	}
624afb30c3eSDavid du Colombier 	error("can't exec %s: %r", av[0]);
6257dd7cddfSDavid du Colombier }
6267dd7cddfSDavid du Colombier 
6277dd7cddfSDavid du Colombier void
startcmd(char * argv[],int * notepg)6289a747e4fSDavid du Colombier startcmd(char *argv[], int *notepg)
6297dd7cddfSDavid du Colombier {
6307dd7cddfSDavid du Colombier 	struct Exec *e;
6317dd7cddfSDavid du Colombier 	Channel *cpid;
6327dd7cddfSDavid du Colombier 	char buf[64];
6337dd7cddfSDavid du Colombier 	int pid;
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 	e = emalloc(sizeof(struct Exec));
6367dd7cddfSDavid du Colombier 	e->argv = argv;
6377dd7cddfSDavid du Colombier 	cpid = chancreate(sizeof(ulong), 0);
6387dd7cddfSDavid du Colombier 	e->cpid = cpid;
6399a747e4fSDavid du Colombier 	sprint(buf, "/mnt/wsys/%d", win->id);
6409a747e4fSDavid du Colombier 	bind(buf, "/dev/acme", MREPL);
6417dd7cddfSDavid du Colombier 	proccreate(execproc, e, EXECSTACK);
6427dd7cddfSDavid du Colombier 	do
6437dd7cddfSDavid du Colombier 		pid = recvul(cpid);
6447dd7cddfSDavid du Colombier 	while(pid == -1);
6457dd7cddfSDavid du Colombier 	sprint(buf, "/proc/%d/notepg", pid);
6467dd7cddfSDavid du Colombier 	*notepg = open(buf, OWRITE);
6477dd7cddfSDavid du Colombier }
648