Commit Diff


commit - 34ca7ee3bff4fca54164345f20a16a1958bddcc2
commit + 6e2cec77b292cc2285e369ec01faa877ea91dbdd
blob - /dev/null
blob + f3acfca22cac1dfab9881af5c8d5e4f90cd8b47f (mode 644)
--- /dev/null
+++ 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);
+}
blob - /dev/null
blob + ef8b7b619faef8eae2326b75f8a374d2a381fdc1 (mode 644)
--- /dev/null
+++ 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);
+}