#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. Load more
#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*); int fsfidprint(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); } void usage(void) { fprint(2, "usage: win cmd args...\n"); threadexitsall("usage"); } void waitthread(void *v) { recvp(cwait); threadexitsall(nil); } void hangupnote(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); } void threadmain(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); } void error(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; } int getec(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++; } int geten(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; } int geter(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; } void gete(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"); } int nrunes(char *s, int nb) { int i, n; Rune r; n = 0; for(i=0; i<nb; n++) i += chartorune(&r, s+i); return n; } void bodyinsert(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); } } void bodydelete(Event *e) { int n; n = delete(e); q.p -= n; if(israw(rcfd) && e->q1 >= q.p+n) sendbs(rcfd, n); } void stdinproc(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); } }