aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/fortune.c90
-rw-r--r--src/cmd/win.c656
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);
+}