shithub: Nail

ref: 2d076037d8dddd20eaeb72f6ed31c8a359ce978b
dir: /win.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <regexp.h>

#include "mail.h"

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 != ' ')
		sysfatal("event number syntax: %c(%d)", c, c);
	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')
		sysfatal("unterminated message");
	return e->action;
}

void
winsendevent(Win *w, Event *e)
{
	Bprint(w->event, "%c%c%d %d\n", e->action, e->type, e->q0, e->q1);
	Bflush(w->event);
}

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->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");
	if((w->io = ioproc()) == nil)
		sysfatal("ioproc alloc: %r");
	w->id = atoi(buf);
	w->event = bwinopen(w, "event", OREAD);
	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);
}

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;
}