diff options
-rw-r--r-- | src/cmd/fortune.c | 90 | ||||
-rw-r--r-- | src/cmd/win.c | 656 |
2 files changed, 746 insertions, 0 deletions
diff --git a/src/cmd/fortune.c b/src/cmd/fortune.c new file mode 100644 index 00000000..f3acfca2 --- /dev/null +++ b/src/cmd/fortune.c @@ -0,0 +1,90 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#define index findex +char choice[2048]; +char index[] = "/sys/games/lib/fortunes.index"; +char fortunes[] = "/sys/games/lib/fortunes"; + +#define lrand rand + +void +main(int argc, char *argv[]) +{ + int i; + long offs; + uchar off[4]; + int ix, nix; + int newindex, oldindex; + char *p; + Dir *fbuf, *ixbuf; + Biobuf *f, g; + + newindex = 0; + oldindex = 0; + ix = offs = 0; + if((f=Bopen(argc>1?argv[1]:fortunes, OREAD)) == 0){ + print("Misfortune!\n"); + exits("misfortune"); + } + ixbuf = nil; + if(argc == 1){ + ix = open(index, OREAD); + if(ix>=0){ + oldindex = 1; + ixbuf = dirfstat(ix); + fbuf = dirfstat(Bfildes(f)); + if(ixbuf == nil || fbuf == nil){ + print("Misfortune?\n"); + exits("misfortune"); + } + if(fbuf->mtime > ixbuf->mtime){ + nix = create(index, OWRITE, 0666); + if(nix >= 0){ + close(ix); + ix = nix; + newindex = 1; + oldindex = 0; + } + } + }else{ + ix = create(index, OWRITE, 0666); + if(ix >= 0) + newindex = 1; + } + } + if(oldindex){ + seek(ix, lrand()%(ixbuf->length/sizeof(offs))*sizeof(offs), 0); + read(ix, off, sizeof(off)); + Bseek(f, off[0]|(off[1]<<8)|(off[2]<<16)|(off[3]<<24), 0); + p = Brdline(f, '\n'); + if(p){ + p[Blinelen(f)-1] = 0; + strcpy(choice, p); + }else + strcpy(choice, "Misfortune!"); + }else{ + Binit(&g, ix, 1); + srand(getpid()); + for(i=1;;i++){ + if(newindex) + offs = Boffset(f); + p = Brdline(f, '\n'); + if(p == 0) + break; + p[Blinelen(f)-1] = 0; + if(newindex){ + off[0] = offs; + off[1] = offs>>8; + off[2] = offs>>16; + off[3] = offs>>24; + Bwrite(&g, off, sizeof(off)); + } + if(lrand()%i==0) + strcpy(choice, p); + } + } + print("%s\n", choice); + exits(0); +} diff --git a/src/cmd/win.c b/src/cmd/win.c new file mode 100644 index 00000000..ef8b7b61 --- /dev/null +++ b/src/cmd/win.c @@ -0,0 +1,656 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <fcall.h> +#include <fs.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; + +int eventfd; +int addrfd; +int datafd; +int ctlfd; +int bodyfd; + +char *typing; +int ntypeb; +int ntyper; +int ntypebreak; +int debug; + +char **prog; +int p[2]; +Channel *cpid; +int pid = -1; + +void error(char*); +void stdinproc(void*); +void stdoutproc(void*); +void type(Event*, int, int, int); +void sende(Event*, int, int, int, int, int); +char *onestring(int, char**); +int delete(Event*); +void deltype(uint, uint); +void runproc(void*); + +void +usage(void) +{ + fprint(2, "usage: win cmd args...\n"); + threadexitsall("usage"); +} + +int +nopipes(void *v, char *msg) +{ + USED(v); + if(strcmp(msg, "sys: write on closed pipe") == 0) + return 1; + return 0; +} + +void +threadmain(int argc, char **argv) +{ + int fd, id; + char buf[256]; + char buf1[128]; + char *name; + Fsys *fs; + + ARGBEGIN{ + case 'd': + debug = 1; + break; + default: + usage(); + }ARGEND + + prog = argv; + + if(argc > 0) + name = argv[0]; + else + name = "gnot"; + + threadnotify(nopipes, 1); + if((fs = nsmount("acme", "")) < 0) + sysfatal("nsmount acme: %r"); + ctlfd = fsopenfd(fs, "new/ctl", ORDWR|OCEXEC); + if(ctlfd < 0 || read(ctlfd, buf, 12) != 12) + sysfatal("ctl: %r"); + id = atoi(buf); + sprint(buf, "%d/tag", id); + fd = fsopenfd(fs, buf, OWRITE|OCEXEC); + write(fd, " Send Delete", 12); + close(fd); + sprint(buf, "%d/event", id); + eventfd = fsopenfd(fs, buf, ORDWR|OCEXEC); + sprint(buf, "%d/addr", id); + addrfd = fsopenfd(fs, buf, ORDWR|OCEXEC); + sprint(buf, "%d/data", id); + datafd = fsopenfd(fs, buf, ORDWR|OCEXEC); + sprint(buf, "%d/body", id); + bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); + if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0) + sysfatal("data files: %r"); + fsunmount(fs); + + if(pipe(p) < 0) + sysfatal("pipe: %r"); + + cpid = chancreate(sizeof(ulong), 1); + threadcreate(runproc, nil, STACK); + pid = recvul(cpid); + if(pid == -1) + sysfatal("exec failed"); + + getwd(buf1, sizeof buf1); + sprint(buf, "name %s/-%s\n0\n", buf1, name); + write(ctlfd, buf, strlen(buf)); + sprint(buf, "dumpdir %s/\n", buf1); + write(ctlfd, buf, strlen(buf)); + sprint(buf, "dump %s\n", onestring(argc, argv)); + write(ctlfd, buf, strlen(buf)); + +// proccreate(stdoutproc, nil, STACK); + stdinproc(nil); +} + +char *shell[] = { "rc", "-i", 0 }; +void +runproc(void *v) +{ + int fd[3]; + char *sh; + + USED(v); + + fd[0] = p[1]; + fd[1] = bodyfd; + fd[2] = bodyfd; +// fd[1] = p[1]; +// fd[2] = p[1]; + + if(prog[0] == nil){ + prog = shell; + if((sh = getenv("SHELL")) != nil) + shell[0] = sh; + } + threadexec(cpid, fd, prog[0], prog); + threadexits(nil); +} + +void +error(char *s) +{ + if(s) + fprint(2, "win: %s: %r\n", s); + else + s = "kill"; + 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(int efd) +{ + static char buf[8192]; + static char *bufp; + static int nbuf; + + if(nbuf == 0){ + nbuf = read(efd, buf, sizeof buf); + if(nbuf <= 0) + error(nil); + bufp = buf; + } + --nbuf; + return *bufp++; +} + +int +geten(int 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(int 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(int 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 +stdinproc(void *v) +{ + int cfd = ctlfd; + int efd = eventfd; + int dfd = datafd; + int afd = addrfd; + int fd0 = p[0]; + 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': /* write to body; can't affect us */ + if(debug) + fprint(2, "shift typing %d... ", e.q1-e.q0); + q.p += e.q1-e.q0; + break; + + case 'F': /* generated by our actions; ignore */ + break; + + case 'K': + case 'M': + switch(e.c2){ + case 'I': + 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, fd0, afd, dfd); + } + break; + + case 'D': + q.p -= delete(&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 */ + fprint(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; + } + 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); + fprint(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); + } +} + +void +stdoutproc(void *v) +{ + int fd1 = p[0]; + int afd = addrfd; + int dfd = datafd; + int n, m, w, npart; + char *buf, *s, *t; + Rune r; + char x[16], hold[UTFmax]; + + USED(v); + threadnotify(nopipes, 1); + buf = malloc(8192+UTFmax+1); + npart = 0; + for(;;){ + n = read(fd1, buf+npart, 8192); + if(n < 0) + error(nil); + if(n == 0) + continue; + + /* squash NULs */ + s = memchr(buf+npart, 0, n); + if(s){ + for(t=s; s<buf+npart+n; s++) + if(*t = *s) /* assign = */ + t++; + n = t-(buf+npart); + } + + n += npart; + + /* hold on to final partial rune */ + npart = 0; + while(n>0 && (buf[n-1]&0xC0)){ + --n; + npart++; + if((buf[n]&0xC0)!=0x80){ + if(fullrune(buf+n, npart)){ + w = chartorune(&r, buf+n); + n += w; + npart -= w; + } + break; + } + } + if(n > 0){ + memmove(hold, buf+n, npart); + buf[n] = 0; + qlock(&q.lk); + m = sprint(x, "#%d", q.p); + if(write(afd, x, m) != m) + error("stdout writing address"); + if(write(dfd, buf, n) != n) + error("stdout writing body"); + q.p += nrunes(buf, n); + qunlock(&q.lk); + memmove(buf, hold, npart); + } + } +} + +int +delete(Event *e) +{ + uint q0, q1; + int deltap; + + q0 = e->q0; + q1 = e->q1; + if(q1 <= q.p) + return e->q1-e->q0; + if(q0 >= q.p+ntyper) + return 0; + deltap = 0; + if(q0 < q.p){ + deltap = q.p-q0; + q0 = 0; + }else + q0 -= q.p; + if(q1 > q.p+ntyper) + q1 = ntyper; + else + q1 -= q.p; + deltype(q0, q1); + return deltap; +} + +void +addtype(int c, uint p0, char *b, int nb, int nr) +{ + int i, w; + Rune r; + uint p; + char *b0; + + for(i=0; i<nb; i+=w){ + w = chartorune(&r, b+i); + if((r==0x7F||r==3) && c=='K'){ + postnote(PNGROUP, pid, "interrupt"); + /* toss all typing */ + q.p += ntyper+nr; + ntypebreak = 0; + ntypeb = 0; + ntyper = 0; + /* buglet: more than one delete ignored */ + return; + } + if(r=='\n' || r==0x04) + ntypebreak++; + } + typing = realloc(typing, ntypeb+nb); + if(typing == nil) + error("realloc"); + if(p0 == ntyper) + memmove(typing+ntypeb, b, nb); + else{ + b0 = typing; + for(p=0; p<p0 && b0<typing+ntypeb; p++){ + w = chartorune(&r, b0+i); + b0 += w; + } + if(p != p0) + error("typing: findrune"); + memmove(b0+nb, b0, (typing+ntypeb)-b0); + memmove(b0, b, nb); + } + ntypeb += nb; + ntyper += nr; +} + +void +sendtype(int fd0) +{ + int i, n, nr; + + while(ntypebreak){ + for(i=0; i<ntypeb; i++) + if(typing[i]=='\n' || typing[i]==0x04){ + n = i + (typing[i] == '\n'); + i++; + if(write(fd0, typing, n) != n) + error("sending to program"); + nr = nrunes(typing, i); + q.p += nr; + ntyper -= nr; + ntypeb -= i; + memmove(typing, typing+i, ntypeb); + ntypebreak--; + goto cont2; + } + print("no breakchar\n"); + ntypebreak = 0; +cont2: + } +} + +void +deltype(uint p0, uint p1) +{ + int w; + uint p, b0, b1; + Rune r; + + /* advance to p0 */ + b0 = 0; + for(p=0; p<p0 && b0<ntypeb; p++){ + w = chartorune(&r, typing+b0); + b0 += w; + } + if(p != p0) + error("deltype 1"); + /* advance to p1 */ + b1 = b0; + for(; p<p1 && b1<ntypeb; p++){ + w = chartorune(&r, typing+b1); + b1 += w; + if(r=='\n' || r==0x04) + ntypebreak--; + } + if(p != p1) + error("deltype 2"); + memmove(typing+b0, typing+b1, ntypeb-b1); + ntypeb -= b1-b0; + ntyper -= p1-p0; +} + +void +type(Event *e, int fd0, int afd, int dfd) +{ + int m, n, nr; + char buf[128]; + + if(e->nr > 0) + addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr); + else{ + m = e->q0; + while(m < e->q1){ + n = sprint(buf, "#%d", m); + write(afd, buf, n); + n = read(dfd, buf, sizeof buf); + nr = nrunes(buf, n); + while(m+nr > e->q1){ + do; while(n>0 && (buf[--n]&0xC0)==0x80); + --nr; + } + if(n == 0) + break; + addtype(e->c1, m-q.p, buf, n, nr); + m += nr; + } + } + sendtype(fd0); +} + +void +sende(Event *e, int fd0, int cfd, int afd, int dfd, int donl) +{ + int l, m, n, nr, lastc, end; + char abuf[16], buf[128]; + + end = q.p+ntyper; + l = sprint(abuf, "#%d", end); + write(afd, abuf, l); + if(e->nr > 0){ + write(dfd, e->b, e->nb); + addtype(e->c1, ntyper, e->b, e->nb, e->nr); + lastc = e->r[e->nr-1]; + }else{ + m = e->q0; + lastc = 0; + while(m < e->q1){ + n = sprint(buf, "#%d", m); + write(afd, buf, n); + n = read(dfd, buf, sizeof buf); + nr = nrunes(buf, n); + while(m+nr > e->q1){ + do; while(n>0 && (buf[--n]&0xC0)==0x80); + --nr; + } + if(n == 0) + break; + l = sprint(abuf, "#%d", end); + write(afd, abuf, l); + write(dfd, buf, n); + addtype(e->c1, ntyper, buf, n, nr); + lastc = buf[n-1]; + m += nr; + end += nr; + } + } + if(donl && lastc!='\n'){ + write(dfd, "\n", 1); + addtype(e->c1, ntyper, "\n", 1, 1); + } + write(cfd, "dot=addr", 8); + sendtype(fd0); +} |