<?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:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>