ref: efc2d967bb2d6ca8ef68bcc43f89bcd0e0f0be3a
dir: /win.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <regexp.h>
#include "mail.h"
enum {
AFbuiltin = 1<<0,
AFexpand = 1<<1,
AFfilename = 1<<2,
AFargbtn = 1<<3,
};
static int
procrd(Biobufhdr *f, void *buf, long len)
{
return ioread(f->aux, f->fid, buf, len);
}
static int
procwr(Biobufhdr *f, void *buf, long len)
{
return iowrite(f->aux, f->fid, buf, len);
}
/*
* NB: this function consumes integers with
* a trailing space, as generated by acme;
* it's not a general purpose number parsing
* function.
*/
static int
evgetnum(Biobuf *f)
{
int c, n;
n = 0;
while('0'<=(c=Bgetc(f)) && c<='9')
n = n*10+(c-'0');
if(c != ' '){
werrstr("event number syntax: %c", c);
return -1;
}
return n;
}
static int
evgetdata(Biobuf *f, Event *e)
{
int i, n, o;
Rune r;
o = 0;
n = evgetnum(f);
for(i = 0; i < n; i++){
if((r = Bgetrune(f)) == -1)
break;
o += runetochar(e->text + o, &r);
}
e->text[o] = 0;
return o;
}
int
winevent(Win *w, Event *e)
{
e->action = Bgetc(w->event);
e->type = Bgetc(w->event);
e->q0 = evgetnum(w->event);
e->q1 = evgetnum(w->event);
e->flags = evgetnum(w->event);
e->ntext = evgetdata(w->event, e);
if(Bgetc(w->event) != '\n'){
werrstr("unterminated message");
return -1;
}
return e->action;
}
void
winreturn(Win *w, Event *e)
{
if(e->flags & (AFexpand|AFargbtn))
return;
fprint(w->revent, "%c%c%d %d\n", e->action, e->type, e->q0, e->q1);
}
int
winopen(Win *w, char *f, int mode)
{
char buf[128];
int fd;
snprint(buf, sizeof(buf), "/mnt/wsys/%d/%s", w->id, f);
if((fd = open(buf, mode|OCEXEC)) == -1)
sysfatal("open %s: %r", buf);
return fd;
}
Biobuf*
bwinopen(Win *w, char *f, int mode)
{
char buf[128];
Biobuf *bfd;
snprint(buf, sizeof(buf), "/mnt/wsys/%d/%s", w->id, f);
if((bfd = Bopen(buf, mode|OCEXEC)) == nil)
sysfatal("open %s: %r", buf);
bfd->aux = w->io;
Biofn(bfd, (mode == OREAD)?procrd:procwr);
return bfd;
}
Biobuf*
bwindata(Win *w, int mode)
{
int fd;
if((fd = dup(w->data, -1)) == -1)
sysfatal("dup: %r");
return Bfdopen(fd, mode);
}
void
wininit(Win *w, char *name)
{
char buf[12];
w->io = ioproc();
w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC);
if(w->ctl < 0)
sysfatal("winopen: %r");
if(read(w->ctl, buf, 12)!=12)
sysfatal("read ctl: %r");
if(fprint(w->ctl, "name %s\n", name) == -1)
sysfatal("write ctl: %r");
if(fprint(w->ctl, "noscroll\n") == -1)
sysfatal("write ctl: %r");
w->id = atoi(buf);
w->event = bwinopen(w, "event", OREAD);
w->revent = winopen(w, "event", OWRITE);
w->addr = winopen(w, "addr", ORDWR);
w->data = winopen(w, "data", ORDWR);
}
void
winclose(Win *w)
{
fprint(w->ctl, "del\n");
if(w->data != -1)
close(w->data);
if(w->addr != -1)
close(w->addr);
if(w->event != nil)
Bterm(w->event);
if(w->io)
closeioproc(w->io);
if(w->ctl != -1)
close(w->ctl);
w->ctl = -1;
w->data = -1;
w->addr = -1;
w->event = nil;
w->io = nil;
}
void
wintagwrite(Win *w, char *s)
{
int fd, n;
n = strlen(s);
fd = winopen(w, "tag", OWRITE);
if(write(fd, s, n) != n)
sysfatal("tag write: %r");
close(fd);
}
int
wineval(Win *w, char *s, ...)
{
char buf[25];
va_list arg;
va_start(arg, s);
vfprint(w->addr, s, arg);
va_end(arg);
if(pread(w->addr, buf, 24, 0) != 24)
return -1;
buf[24] = 0;
return strtol(buf, nil, 10);
}
int
winread(Win *w, int q0, int q1, char *data, int ndata)
{
int m, n, nr;
char *buf;
m = q0;
buf = emalloc(Bufsz);
while(m < q1){
n = sprint(buf, "#%d", m);
if(write(w->addr, buf, n) != n){
fprint(2, "error writing addr: %r");
goto err;
}
n = read(w->data, buf, Bufsz);
if(n <= 0){
fprint(2, "reading data: %r");
goto err;
}
nr = utfnlen(buf, n);
while(m+nr >q1){
do; while(n>0 && (buf[--n]&0xC0)==0x80);
--nr;
}
if(n == 0 || n > ndata)
break;
memmove(data, buf, n);
ndata -= n;
data += n;
*data = 0;
m += nr;
}
free(buf);
return 0;
err:
free(buf);
return -1;
}
char*
winreadsel(Win *w)
{
int n, q0, q1;
char *r;
wingetsel(w, &q0, &q1);
n = UTFmax*(q1-q0);
r = emalloc(n + 1);
if(winread(w, q0, q1, r, n) == -1){
free(r);
return nil;
}
return r;
}
void
wingetsel(Win *w, int *q0, int *q1)
{
char *e, buf[25];
fprint(w->ctl, "addr=dot");
if(pread(w->addr, buf, 24, 0) != 24)
sysfatal("read addr: %r");
buf[24] = 0;
*q0 = strtol(buf, &e, 10);
*q1 = strtol(e, nil, 10);
}
void
winsetsel(Win *w, int q0, int q1)
{
fprint(w->addr, "#%d,#%d", q0, q1);
fprint(w->ctl, "dot=addr");
}
static char*
expandaddr(Win *w, Event *e)
{
static char *delim = "/[ \t\\n<>()\\[\\]]/";
char *s;
int q0, q1, ns;
if(e->q0 != e->q1)
return nil;
q0 = wineval(w, "#%d-%s", e->q0, delim);
if(q0 == -1) /* bad char not found */
q0 = 0;
else /* increment past bad char */
q0++;
q1 = wineval(w, "#%d+%s", e->q0, delim);
if(q1 < 0){
q1 = wineval(w, "$");
if(q1 < 0)
return nil;
}
if(q0 >= q1)
return nil;
ns = (q1-q0)*UTFmax+1;
s = emalloc(ns);
winread(w, q0, q1, s, ns);
return s;
}
char*
matchaddr(Win *w, Event *e)
{
char *s;
if((s = expandaddr(w, e)) != nil)
if(regexec(addrpat, s, nil, 0))
return s;
return nil;
}
int
matchmesg(Win *, char *text)
{
char *p;
if(strncmp(text, mbox.path, strlen(mbox.path)) == 0)
return 1;
if(regexec(mesgpat, text, nil, 0)){
if((p = strchr(text, '/')) != nil)
p[1] = 0;
return 1;
}
return 0;
}