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, ¬epg);
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