<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/rsc/9pfilt.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/rsc/9pfilt.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
#include &lt;u.h&gt;
#include &lt;libc.h&gt;
#include &lt;auth.h&gt;
#include &lt;fcall.h&gt;
#include &lt;thread.h&gt;
#include &lt;ctype.h&gt;

void
usage(void)
{
	threadprint(2, "9pfilt [-abc] oldsrvfile newsrvname\n");
	exits("usage");
}

void postfd(char*, int);

typedef struct Win Win;
typedef struct Req Req;
struct Win {
	char *name;

	QLock;
	int passing;

	int numgen;
	int id;
	int ctlfd;
	int addrfd;
	int bodyfd;
	int datafd;
	int tagfd;
	int eventfd;

	int msgfd;	/* where messages come from */
	Channel *rx;	/* channel to receive messages */
	Channel *tx;	/* channel to send messages on */
	Req *reqlist;	/* actual messages */
	Req **elist;
};

struct Req {
	Fcall f;
	char buf[MAXFDATA+MAXMSG];
	long n;
	int num;
	int passed;
	Req *link;
};

/* read messages from fromfd and send them to rx channel */
void
filterproc(void *a)
{
	Win *w;
	Req *r;

	w = a;
	for(;;){
		r = mallocz(sizeof *r, 1);
		assert(r != nil);
		r-&gt;n = sizeof r-&gt;buf;
		if(getS(w-&gt;msgfd, r-&gt;buf, &amp;r-&gt;f, &amp;r-&gt;n))
			break;
		sendp(w-&gt;rx, r);
	}
	threadexitsall("read failed");
}

void
newwin(Win *w, char *name, int msgfd, Channel *rx, Channel *tx)
{
	int fd;
	char buf[30], *p;

	w-&gt;name = name;
	w-&gt;msgfd = msgfd;

	fd = open("/dev/new/ctl", ORDWR);
	if(fd &lt; 0)
		sysfatal("open /dev/new/ctl: %r");

	if(read(fd, buf, 12) != 12)
		sysfatal("read id");

	w-&gt;ctlfd = fd;
	w-&gt;id = atoi(buf);
	sprint(buf, "/dev/%d/", w-&gt;id);
	p = buf+strlen(buf);
	strcpy(p, "addr");
	w-&gt;addrfd = open(buf, ORDWR);
	if(w-&gt;addrfd &lt; 0)
		sysfatal("addr %s: %r", buf);
	strcpy(p, "body");
	w-&gt;bodyfd = open(buf, OWRITE);
	if(w-&gt;bodyfd &lt; 0)
		sysfatal("body %s: %r", buf);
	strcpy(p, "data");
	w-&gt;datafd = open(buf, ORDWR);
	if(w-&gt;datafd &lt; 0)
		sysfatal("body %s: %r", buf);
	strcpy(p, "tag");
	w-&gt;tagfd = open(buf, ORDWR);
	if(w-&gt;tagfd &lt; 0)
		sysfatal("tag %s: %r", buf);
	strcpy(p, "event");
	w-&gt;eventfd = open(buf, OREAD);
	if(w-&gt;eventfd &lt; 0)
		sysfatal("event %s: %r", buf);

	w-&gt;rx = rx;
	w-&gt;tx = tx;
	w-&gt;elist = &amp;w-&gt;reqlist;
}

Req*
copy(Req *r)
{
	Req *n;

	n = mallocz(sizeof *n, 1);
	assert(n != nil);
	*n = *r;
	n-&gt;link = nil;
	return n;
}

void
tag(Win *w, char *name)
{
	threadprint(w-&gt;ctlfd, "cleartag\n");
	threadprint(w-&gt;tagfd, "Look %s", name);
}

int
gettext(Win *w, char *buf, long a, long b)
{
	int n;
	threadprint(w-&gt;addrfd, "#%ld,#%ld", a, b);
	seek(w-&gt;datafd, 0, 0);
	if((n=read(w-&gt;datafd, buf, b-a)) != b-a)
		threadprint(2, "warning: read %ld ret %d\n", b-a, n);
	return n;
}

void
settext(Win *w, char *buf, long a, long b)
{
	threadprint(w-&gt;addrfd, "#%ld,#%ld", a, b);
	seek(w-&gt;datafd, 0, 0);
	write(w-&gt;datafd, buf, strlen(buf));
}

void
refreshwin(Win *w)
{
//	threadprint(w-&gt;addrfd, ",");
//	threadprint(w-&gt;datafd, "");
}

void
acmewin(void *a)
{
	Win *w;
	char buf[128];
	int n;
	long num[4];
	char *p;
	Req *r;

	w = a;
	threadprint(w-&gt;ctlfd, "name /9p/%s\n", w-&gt;name);
	tag(w, "Pass");
	while((n=read(w-&gt;eventfd, buf, sizeof buf-1)) &gt; 0){
Cont:
		buf[n] = 0;
		num[0] = strtol(buf+2, &amp;p, 10);
		assert(p != nil);
		num[1] = strtol(p, &amp;p, 10);
		assert(p != nil);
		num[2] = strtol(p, &amp;p, 10);
		assert(p != nil);
		num[3] = strtol(p, &amp;p, 10);
		assert(p != nil);
		p++;

		p[num[3]] = 0;

		if(num[2] &amp; 2){
			memmove(buf, p+num[3]+1, n = n - (p-buf) - num[3] - 1);
			goto Cont;
		}

		switch(buf[0]){
		case 'E':	/* write to body or tag file */
		case 'F':	/* other file write */
		case 'K':	/* keyboard */
		case 'M':;	/* mouse */
		}

		switch(buf[1]){
		case 'x':
			if(strcmp(p, "Pass")==0){
				w-&gt;passing = 1;
				tag(w, "Nopass");
			}
			if(strcmp(p, "Nopass")==0){
				w-&gt;passing = 0;
				tag(w, "Pass");
			}
			if(strcmp(p, "Get")==0){
				refreshwin(w);
			}
			break;
		case 'X':
			if(num[1] - num[0] &gt; 30)
				break;

			if(isdigit(p[0])){
				n = atoi(p);
				for(r=w-&gt;reqlist; r; r=r-&gt;link)
					if(r-&gt;num == n)
						break;
				if(r == nil)
					break;
				if(r-&gt;passed)
					break;
				r-&gt;passed = 1;
				sendp(w-&gt;tx, copy(r));
				num[0]--;
				num[1]++;
				gettext(w, buf, num[0], num[1]);
threadprint(1, "get %ld %ld %.*s\n", num[1], num[0], (int)num[1]-num[0], buf);
				if(buf[0] == '[' &amp;&amp; buf[num[1]-num[0]-1] == ']'){
					buf[num[1]-num[0]-1] = 0;
					settext(w, buf+1, num[0], num[1]);
				}
			}
			break;
		}
	}
}

void
reqproc(void *a)
{
	Win *w;
	Req *r;

	w = a;
	while(r = recvp(w-&gt;rx)){
		if(r-&gt;passed){
			write(w-&gt;msgfd, r-&gt;buf, r-&gt;n);
		}
		else if(w-&gt;passing){
			r-&gt;passed = 1;
			sendp(w-&gt;tx, copy(r));
		}
		qlock(w);
		*w-&gt;elist = r;
		w-&gt;elist = &amp;r-&gt;link;
		r-&gt;num = w-&gt;numgen++;
		threadprint(w-&gt;bodyfd, r-&gt;passed ? "%d/ %F\n" :
			"[%d]/ %F\n", r-&gt;num, &amp;r-&gt;f);
		qunlock(w);
	}
}

Win srv, ker;
void
threadmain(int argc, char **argv)
{
	int flag;
	int fd;
	int pfd[2];
	Channel *k, *s;

	rfork(RFNOTEG);
	flag = 0;
	ARGBEGIN{
	case 'a':
		flag |= MAFTER;
		break;
	case 'b':
		flag |= MBEFORE;
		break;
	case 'c':
		flag |= MCREATE;
		break;
	default:
		usage();
	}ARGEND

	if(argc != 2)
		usage();

	fmtinstall('F', fcallconv);
	fmtinstall('D', dirconv);

	if((fd = open(argv[0], ORDWR)) &lt; 0)
		sysfatal("cannot open %s: %r", argv[0]);

	if(pipe(pfd)&lt;0)
		sysfatal("pipe: %r");

	postfd(argv[1], pfd[1]);

	k = chancreate(sizeof(Req*), 32);
	s = chancreate(sizeof(Req*), 32);
	newwin(&amp;srv, "server", fd, k, s);
	newwin(&amp;ker, "kernel", pfd[0], s, k);

	proccreate(filterproc, &amp;ker, 8192);
	proccreate(filterproc, &amp;srv, 8192);
	proccreate(acmewin, &amp;ker, 8192);
	proccreate(acmewin, &amp;srv, 8192);
	proccreate(reqproc, &amp;ker, 8192);
	proccreate(reqproc, &amp;srv, 8192);

	threadexits(0);
}

/*
 *  read a message from fd and convert it.
 *  ignore 0-length messages.
 */
char *
getS(int fd, char *buf, Fcall *f, long *lp)
{
	long m, n;
	int i;
	char *errstr;

	errstr = "EOF";
	n = 0;
	for(i = 0; i &lt; 3; i++){
		n = read(fd, buf, *lp);
		if(n == 0){
			continue;
		}
		if(n &lt; 0)
			return "read error";
		m = convM2S(buf, f, n);
		if(m == 0){
			errstr = "bad type";
			continue;
		}
		*lp = m;
		return 0;
	}
	*lp = n;
	return errstr;
}

void
sysfatal(char *fmt, ...)
{
	char buf[128];
	va_list arg;

	va_start(arg, fmt);
	doprint(buf, buf+sizeof(buf), fmt, arg);
	va_end(arg);
	if(argv0)
		threadprint(2, "%s: %s\n", argv0, buf);
	else
		threadprint(2, "%s\n", buf);

	threadexitsall(buf);
}

void
postfd(char *name, int pfd)
{
	char buf[2*NAMELEN];
	int fd;

	snprint(buf, sizeof buf, "/srv/%s", name);

	fd = create(buf, OWRITE, 0666);
	if(fd == -1)
		sysfatal("postsrv %s", buf);
	fprint(fd, "%d", pfd);
	close(fd);
}

<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:webmaster@plan9.bell-labs.com">webmaster@plan9.bell-labs.com</a>.</span>
</font></center>
</body>
</html>

