#include #include #include #include #include "dat.h" void mainctl(void*); void startcmd(char *[], int*, int*, int*); void stdout2body(void*); int stdin, stdout, notepg; int dirty = 0; Window *win; int hostpt; void usage(void) { threadprint(2, "usage: win [command]\n"); threadexitsall("usage"); } void threadmain(int argc, char *argv[]) { int i, j; char *dir, *tag, *name; char buf[1024], **av; ARGBEGIN{ }ARGEND if(argc == 0){ av = emalloc(3*sizeof(char*)); av[0] = "rc"; av[1] = "-i"; name = getenv("sysname"); }else{ av = argv; name = utfrrune(av[0], '/'); if(name) name++; else name = av[0]; } if(getwd(buf, sizeof buf) == 0) dir = "/"; else dir = buf; dir = estrdup(dir); tag = estrdup(dir); tag = eappend(estrdup(tag), "/-", name); win = newwindow(); winname(win, tag); wintagwrite(win, "Send Noscroll", 5+8); threadcreate(mainctl, win, STACK); startpipe(); startcmd(av, &stdin, &stdout, ¬epg); proccreate(stdout2body, nil, STACK); strcpy(buf, "win"); j = 3; for(i=0; ictl, "scroll"); winsetdump(win, dir, buf); } int EQUAL(char *s, char *t) { while(tolower(*s) == tolower(*t++)) if(*s++ == '\0') return 1; return 0; } int command(Window *w, char *s) { while(*s==' ' || *s=='\t' || *s=='\n') s++; if(strcmp(s, "Delete")==0){ windel(w, 1); threadexitsall(nil); return 1; } if(strcmp(s, "Del")==0){ if(windel(w, 0)) threadexitsall(nil); return 1; } if(EQUAL(s, "scroll")){ ctlprint(w->ctl, "scroll\nshow"); return 1; } if(EQUAL(s, "noscroll")){ ctlprint(w->ctl, "noscroll"); return 1; } return 0; } int sendinput(Window *w, ulong q0, ulong q1) { char *buf, *s, *t; int nsent, m, n; buf = emalloc((q1-q0)*UTFmax+1); n = winread(w, q0, q1, buf); s = buf; while(n > 0){ t = strpbrk(s, "\n\004"); if(t == nil) break; m = (t+1)-s; if(*t == '\n') write(stdin, s, m); else write(stdin, s, m-1); n -= m; s += m; } /* calculate number of runes sent */ *s = '\0'; nsent = utflen(buf); free(buf); return nsent; } void sendit(char *s) { int n; char tmp[32]; n = strlen(s); write(win->body, s, n); if(s[n-1]!='\n' && s[n-1]!='\004') write(win->body, "\n", 1); winselect(win, "$", 1); seek(win->addr, 0UL, 0); if(read(win->addr, tmp, 2*12) == 2*12) hostpt += sendinput(win, hostpt, atol(tmp)); } void execevent(Window *w, Event *e, int (*command)(Window*, char*)) { Event *ea, *e2; int na; char *s, *t; ea = nil; e2 = nil; if(e->flag & 2) e2 = recvp(w->cevent); if(e->flag & 8){ ea = recvp(w->cevent); na = ea->nb; recvp(w->cevent); }else na = 0; s = e->b; /* if it's a known command, do it */ if((e->flag&2) && e->nb==0) s = e2->b; if(na){ t = emalloc(strlen(s)+1+na+1); sprint(t, "%s %s", s, ea->b); s = t; } /* if it's a long message, it can't be for us anyway */ if(!command(w, s) && s[0]!='\0'){ /* send it as typed text */ /* if it's a built-in from the tag, send it back */ if(e->flag & 1) threadprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); else /* send text to main window */ sendit(s); } if(na) free(s); } void mainctl(void *v) { Window *w; Event *e; int delta; char tmp[32]; w = v; proccreate(wineventproc, w, STACK); hostpt = 0; winsetaddr(w, "0", 0); for(;;){ e = recvp(w->cevent); switch(e->c1){ default: Unknown: threadprint(2, "unknown message %c%c\n", e->c1, e->c2); break; case 'S': /* output to stdout */ write(w->data, e->b, e->nb); threadprint(w->ctl, "dot=addr\n"); hostpt += e->nr; break; case 'E': /* write to body; can't affect us */ break; case 'F': /* generated by our actions; ignore */ break; case 'K': switch(e->c2){ case 'D': if(e->q1 < hostpt) hostpt -= (e->q1-e->q0); else if(e->q0 < hostpt) hostpt = e->q0; break; case 'I': if(e->nr>0 && e->r[e->nr-1]==0x7F){ /* do full reset of state, just in case we've lost track */ write(notepg, "interrupt", 9); winselect(w, "$", 1); ctlprint(w->ctl, "dot=addr"); tmp[0] = 0; seek(w->addr, 0, 0); read(w->addr, tmp, 24); hostpt = atoi(tmp); break; } delta = e->q1-e->q0; if(e->q1 < hostpt) hostpt += delta; else if(e->q0>=hostpt && e->nr>0 && (e->r[e->nr-1]=='\n' || e->r[e->nr-1]=='\004')) hostpt += sendinput(w, hostpt, e->q1); break; } break; case 'M': switch(e->c2){ case 'x': case 'X': execevent(w, e, command); break; case 'l': /* reflect all searches back to acme */ case 'L': if(e->flag & 2) recvp(w->cevent); winwriteevent(w, e); break; case 'I': if(e->q1 < hostpt) hostpt += e->q1-e->q0; else hostpt += sendinput(w, hostpt, e->q1); break; case 'D': if(e->q1 < hostpt) hostpt -= (e->q1-e->q0); else if(e->q0 < hostpt) hostpt = e->q0; break; case 'd': /* modify away; we don't care */ case 'i': break; default: goto Unknown; } } } } /* turn writes to stdout (seen as reads by us) into pseudo-events. e->nr is set but not e->r */ void stdout2body(void*) { int i, j, w, n, partial, nb; Event *e[4], *ep; Rune r; char *t, tmp[UTFmax]; for(i=0; ic1 = 'S'; } n = 0; partial = 0; for(;;){ ep = e[n]; n = (n+1) % nelem(e); nb = partial+read(stdout, ep->b+partial, EVENTSIZE-partial-1); /* -1 to leave terminal \0 */ if(nb <= 0) break; if(strlen(ep->b) < nb){ /* nulls in data */ t = emalloc(nb+1); for(i=j=0; ib[i] != '\0') t[j++] = ep->b[i]; memmove(ep->b, t, j); nb = j; free(t); } /* process bytes into runes, transferring terminal partial runes into next buffer */ for(i=j=0; ib+i, nb-i); i+=w,j++) w = chartorune(&r, ep->b+i); memmove(tmp, ep->b+i, nb-i); ep->nb = i; ep->nr = j; ep->b[i] = '\0'; ep->r[j] = L'\0'; sendp(win->cevent, ep); partial = nb-i; memmove(e[n]->b, tmp, partial); } threadexitsall(nil); } enum { NARGS = 100, NARGCHAR = 8*1024, EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR }; struct Exec { char **argv; Channel *cpid; }; int lookinbin(char *s) { if(s[0] == '/') return 0; if(s[0]=='.' && s[1]=='/') return 0; if(s[0]=='.' && s[1]=='.' && s[2]=='/') return 0; return 1; } /* adapted from mail. not entirely free of details from that environment */ void execproc(void *v) { struct Exec *e; char *cmd, **av; Channel *cpid; e = v; rfork(RFFDG); av = e->argv; close(0); open("/dev/cons", OREAD); close(1); open("/dev/cons", OWRITE); dup(1, 2); cpid = e->cpid; free(e); procexec(cpid, av[0], av); if(lookinbin(av[0])){ cmd = estrstrdup("/bin/", av[0]); procexec(cpid, cmd, av); } sendul(cpid, 0UL); threadexits("can't exec"); } void startcmd(char *argv[], int *stdin, int *stdout, int *notepg) { struct Exec *e; Channel *cpid; char buf[64]; int pid; e = emalloc(sizeof(struct Exec)); if(bind("#|", "/dev/acme", MREPL) < 0) error("can't bind pipe: %r"); bind("/dev/acme/data", "/dev/cons", MREPL); e->argv = argv; cpid = chancreate(sizeof(ulong), 0); e->cpid = cpid; proccreate(execproc, e, EXECSTACK); do pid = recvul(cpid); while(pid == -1); if(pid == 0){ error("can't exec %s: %r", argv[0]); threadexitsall("can't exec"); } sprint(buf, "/proc/%d/notepg", pid); *notepg = open(buf, OWRITE); *stdin = open("/dev/acme/data1", OWRITE); *stdout = open("/dev/acme/data1", OREAD); sprint(buf, "/mnt/wsys/%d", win->id); bind(buf, "/dev/acme", MREPL); }