jehanne/sys/src/cmd/acme/aux/win/fs.c

157 lines
3.1 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <lib9.h>
#include <9P2000.h>
#include <thread.h>
#include <9p.h>
#include "dat.h"
Channel *fschan;
Channel *writechan;
static File *devcons, *devnew;
static void
fsread(Req *r)
{
Fsevent e;
if(r->fid->file == devnew){
if(r->fid->aux==nil){
respond(r, "phase error");
return;
}
readstr(r, r->fid->aux);
respond(r, nil);
return;
}
assert(r->fid->file == devcons);
e.type = 'r';
e.r = r;
send(fschan, &e);
}
static void
fsflush(Req *r)
{
Fsevent e;
e.type = 'f';
e.r = r;
send(fschan, &e);
}
static void
fswrite(Req *r)
{
static Event *e[4];
Event *ep;
int i, j, ei, nb, wid, pid;
Rune rune;
char *s;
char tmp[UTFmax], *t;
static int n, partial;
if(r->fid->file == devnew){
if(r->fid->aux){
respond(r, "already created a window");
return;
}
s = emalloc(r->ifcall.count+1);
memmove(s, r->ifcall.data, r->ifcall.count);
s[r->ifcall.count] = 0;
pid = strtol(s, &t, 0);
if(*t==' ')
t++;
i = newpipewin(pid, t);
free(s);
s = emalloc(32);
sprint(s, "%lud", (uint32_t)i);
r->fid->aux = s;
r->ofcall.count = r->ifcall.count;
respond(r, nil);
return;
}
assert(r->fid->file == devcons);
if(e[0] == nil){
for(i=0; i<nelem(e); i++){
e[i] = emalloc(sizeof(Event));
e[i]->c1 = 'S';
}
}
ep = e[n];
n = (n+1)%nelem(e);
assert(r->ifcall.count <= 8192); /* is this guaranteed by lib9p? */
nb = r->ifcall.count;
memmove(ep->b+partial, r->ifcall.data, nb);
nb += partial;
ep->b[nb] = '\0';
if(strlen(ep->b) < nb){ /* nulls in data */
t = ep->b;
for(i=j=0; i<nb; i++)
if(ep->b[i] != '\0')
t[j++] = ep->b[i];
nb = j;
t[j] = '\0';
}
ei = nb>8192? 8192 : nb;
/* process bytes into runes, transferring terminal partial runes into next buffer */
for(i=j=0; i<ei && fullrune(ep->b+i, ei-i); i+=wid,j++)
wid = chartorune(&rune, ep->b+i);
memmove(tmp, ep->b+i, nb-i);
partial = nb-i;
ep->nb = i;
ep->nr = j;
ep->b[i] = '\0';
if(i != 0){
sendp(win->cevent, ep);
recvp(writechan);
}
partial = nb-i;
memmove(e[n]->b, tmp, partial);
r->ofcall.count = r->ifcall.count;
respond(r, nil);
}
void
fsdestroyfid(Fid *fid)
{
if(fid->aux)
free(fid->aux);
}
Srv fs = {
.read= fsread,
.write= fswrite,
.flush= fsflush,
.destroyfid= fsdestroyfid,
.leavefdsopen= 1,
};
void
mountcons(void)
{
fschan = chancreate(sizeof(Fsevent), 0);
writechan = chancreate(sizeof(void*), 0);
fs.tree = alloctree("win", "win", DMDIR|0555, nil);
devcons = createfile(fs.tree->root, "cons", "win", 0666, nil);
if(devcons == nil)
sysfatal("creating /dev/cons: %r");
devnew = createfile(fs.tree->root, "wnew", "win", 0666, nil);
if(devnew == nil)
sysfatal("creating /dev/wnew: %r");
threadpostmountsrv(&fs, nil, "/dev", MBEFORE);
}