Commit Diff


commit - 603d6d896f9932b125b240fe4da82f7a41012a62
commit + f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6
blob - /dev/null
blob + 372a90957229fbc206ff89de13cd80f382a219f4 (mode 644)
--- /dev/null
+++ include/acme.h
@@ -0,0 +1,76 @@
+AUTOLIB(acme);
+
+typedef struct Event Event;
+typedef struct Win Win;
+
+#define	EVENTSIZE	256
+struct Event
+{
+	int	c1;
+	int	c2;
+	int	oq0;
+	int	oq1;
+	int	q0;
+	int	q1;
+	int	flag;
+	int	nb;
+	int	nr;
+	char	text[EVENTSIZE*UTFmax+1];
+	char	arg[EVENTSIZE*UTFmax+1];
+	char	loc[EVENTSIZE*UTFmax+1];
+};
+
+struct Win
+{
+	int id;
+	CFid *ctl;
+	CFid *tag;
+	CFid *body;
+	CFid *addr;
+	CFid *event;
+	CFid *data;
+	CFid *xdata;
+	Channel *c;	/* chan(Event) */
+	Win *next;
+	Win *prev;
+	
+	/* events */
+	int nbuf;
+	char buf[1024];
+	char *bufp;
+	jmp_buf jmp;
+	Event e2;
+	Event e3;
+	Event e4;
+};
+
+Win *newwin(void);
+Win *openwin(int, CFid*);
+
+int eventfmt(Fmt*);
+int pipewinto(Win *w, char *name, int, char *fmt, ...);
+int pipetowin(Win *w, char *name, int, char *fmt, ...);
+char *sysrun(char*, ...);
+int winaddr(Win *w, char *fmt, ...);
+int winctl(Win *w, char *fmt, ...);
+int windel(Win *w, int sure);
+int winfd(Win *w, char *name, int);
+char *winmread(Win *w, char *file);
+int winname(Win *w, char *fmt, ...);
+int winprint(Win *w, char *name, char *fmt, ...);
+int winread(Win *w, char *file, void *a, int n);
+int winseek(Win *w, char *file, int n, int off);
+int winreadaddr(Win *w, uint*);
+int winreadevent(Win *w, Event *e);
+int winwrite(Win *w, char *file, void *a, int n);
+int winwriteevent(Win *w, Event *e);
+int winopenfd(Win *w, char *name, int mode);
+void windeleteall(void);
+void winfree(Win *w);
+void winclosefiles(Win *w);
+Channel *wineventchan(Win *w);
+
+void *erealloc(void*, uint);
+void *emalloc(uint);
+char *estrdup(char*);
+char *evsmprint(char*, va_list);
blob - /dev/null
blob + 35d222d5c7f43ab51bf9f0261498095ec3cee48b (mode 644)
--- /dev/null
+++ src/libacme/acme.c
@@ -0,0 +1,588 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <9pclient.h>
+#include <acme.h>
+
+static CFsys *acmefs;
+static Win *windows;
+static Win *last;
+
+static void
+mountacme(void)
+{
+	if(acmefs == nil){
+		acmefs = nsmount("acme", nil);
+		if(acmefs == nil)
+			sysfatal("cannot mount acme: %r");
+	}
+}
+
+Win*
+newwin(void)
+{
+	CFid *fid;
+	char buf[100];
+	int id, n;
+
+	mountacme();
+	fid = fsopen(acmefs, "new/ctl", ORDWR);
+	if(fid == nil)
+		sysfatal("open new/ctl: %r");
+	n = fsread(fid, buf, sizeof buf-1);
+	if(n <= 0)
+		sysfatal("read new/ctl: %r");
+	buf[n] = 0;
+	id = atoi(buf);
+	if(id == 0)
+		sysfatal("read new/ctl: malformed message: %s", buf);
+
+	return openwin(id, fid);
+}
+
+Win*
+openwin(int id, CFid *ctl)
+{
+	char buf[100];
+	Win *w;
+	
+	mountacme();
+	if(ctl == nil){
+		snprint(buf, sizeof buf, "%d/ctl", id);
+		if((ctl = fsopen(acmefs, buf, ORDWR)) == nil)
+			sysfatal("open %s: %r", buf);
+	}
+	w = emalloc(sizeof *w);
+	w->id = id;
+	w->ctl = ctl;
+	w->next = nil;
+	w->prev = last;
+	if(last)
+		last->next = w;
+	else
+		windows = w;
+	last = w;
+	return w;
+}
+
+void
+winclosefiles(Win *w)
+{
+	if(w->ctl){
+		fsclose(w->ctl);
+		w->ctl = nil;
+	}
+	if(w->body){
+		fsclose(w->body);
+		w->body = nil;
+	}
+	if(w->addr){
+		fsclose(w->addr);
+		w->addr = nil;
+	}
+	if(w->tag){
+		fsclose(w->tag);
+		w->tag = nil;
+	}
+	if(w->event){
+		fsclose(w->event);
+		w->event = nil;
+	}
+	if(w->data){
+		fsclose(w->data);
+		w->data = nil;
+	}
+	if(w->xdata){
+		fsclose(w->xdata);
+		w->xdata = nil;
+	}
+}
+
+void
+winfree(Win *w)
+{
+	winclosefiles(w);
+	if(w->c){
+		chanfree(w->c);
+		w->c = nil;
+	}
+	if(w->next)
+		w->next->prev = w->prev;
+	else
+		last = w->prev;
+	if(w->prev)
+		w->prev->next = w->next;
+	else
+		windows = w->next;
+	free(w);
+}
+
+void
+windeleteall(void)
+{
+	Win *w, *next;
+
+	for(w=windows; w; w=next){
+		next = w->next;
+		winctl(w, "delete");
+	}
+}
+
+static CFid*
+wfid(Win *w, char *name)
+{
+	char buf[100];
+	CFid **fid;
+
+	if(strcmp(name, "ctl") == 0)
+		fid = &w->ctl;
+	else if(strcmp(name, "body") == 0)
+		fid = &w->body;
+	else if(strcmp(name, "addr") == 0)
+		fid = &w->addr;
+	else if(strcmp(name, "tag") == 0)
+		fid = &w->tag;
+	else if(strcmp(name, "event") == 0)
+		fid = &w->event;
+	else if(strcmp(name, "data") == 0)
+		fid = &w->data;
+	else if(strcmp(name, "xdata") == 0)
+		fid = &w->xdata;
+	else{
+		fid = 0;
+		sysfatal("bad window file name %s", name);
+	}
+
+	if(*fid == nil){
+		snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
+		*fid = fsopen(acmefs, buf, ORDWR);
+		if(*fid == nil)
+			sysfatal("open %s: %r", buf);
+	}
+	return *fid;
+}
+
+int
+winopenfd(Win *w, char *name, int mode)
+{
+	char buf[100];
+	
+	snprint(buf, sizeof buf, "%d/%s", w->id, name);
+	return fsopenfd(acmefs, buf, mode);
+}
+
+int
+winctl(Win *w, char *fmt, ...)
+{
+	char *s;
+	va_list arg;
+	CFid *fid;
+	int n;
+
+	va_start(arg, fmt);
+	s = evsmprint(fmt, arg);
+	va_end(arg);
+
+	fid = wfid(w, "ctl");
+	n = fspwrite(fid, s, strlen(s), 0);
+	free(s);
+	return n;
+}
+
+int
+winname(Win *w, char *fmt, ...)
+{
+	char *s;
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	s = evsmprint(fmt, arg);
+	va_end(arg);
+
+	n = winctl(w, "name %s\n", s);
+	free(s);
+	return n;
+}
+
+int
+winprint(Win *w, char *name, char *fmt, ...)
+{
+	char *s;
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	s = evsmprint(fmt, arg);
+	va_end(arg);
+
+	n = fswrite(wfid(w, name), s, strlen(s));
+	free(s);
+	return n;
+}
+
+int
+winaddr(Win *w, char *fmt, ...)
+{
+	char *s;
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	s = evsmprint(fmt, arg);
+	va_end(arg);
+
+	n = fswrite(wfid(w, "addr"), s, strlen(s));
+	free(s);
+	return n;
+}
+
+int
+winreadaddr(Win *w, uint *q1)
+{
+	char buf[40], *p;
+	uint q0;
+	int n;
+	
+	n = fspread(wfid(w, "addr"), buf, sizeof buf-1, 0);
+	if(n <= 0)
+		return -1;
+	buf[n] = 0;
+	q0 = strtoul(buf, &p, 10);
+	if(q1)
+		*q1 = strtoul(p, nil, 10);
+	return q0;
+}
+
+int
+winread(Win *w, char *file, void *a, int n)
+{
+	return fsread(wfid(w, file), a, n);
+}
+
+int
+winwrite(Win *w, char *file, void *a, int n)
+{
+	return fswrite(wfid(w, file), a, n);
+}
+
+char*
+winmread(Win *w, char *file)
+{
+	char *buf;
+	int n, tot, m;
+	
+	m = 128;
+	buf = emalloc(m+1);
+	tot = 0;
+	while((n = fsread(wfid(w, file), buf+tot, m-tot)) > 0){
+		tot += n;
+		if(tot >= m){
+			m += 128;
+			buf = erealloc(buf, m+1);
+		}
+	}
+	if(n < 0){
+		free(buf);
+		return nil;
+	}
+	buf[tot] = 0;
+	return buf;
+}
+
+int
+winseek(Win *w, char *file, int n, int off)
+{
+	return fsseek(wfid(w, file), n, off);
+}
+
+int
+winwriteevent(Win *w, Event *e)
+{
+	char buf[100];
+
+	snprint(buf, sizeof buf, "%c%c%d %d \n", e->c1, e->c2, e->q0, e->q1);
+	return fswrite(wfid(w, "event"), buf, strlen(buf));
+}
+
+int
+windel(Win *w, int sure)
+{
+	return winctl(w, sure ? "delete" : "del");
+}
+
+int
+winfd(Win *w, char *name, int mode)
+{
+	char buf[100];
+
+	snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
+	return fsopenfd(acmefs, buf, mode);
+}
+
+static void
+error(Win *w, char *msg)
+{
+	if(msg == nil)
+		longjmp(w->jmp, 1);
+	fprint(2, "%s: win%d: %s\n", argv0, w->id, msg);
+	longjmp(w->jmp, 2);
+}
+
+static int
+getec(Win *w, CFid *efd)
+{
+	if(w->nbuf <= 0){
+		w->nbuf = fsread(efd, w->buf, sizeof w->buf);
+		if(w->nbuf <= 0)
+			error(w, nil);
+		w->bufp = w->buf;
+	}
+	--w->nbuf;
+	return *w->bufp++;
+}
+
+static int
+geten(Win *w, CFid *efd)
+{
+	int n, c;
+
+	n = 0;
+	while('0'<=(c=getec(w,efd)) && c<='9')
+		n = n*10+(c-'0');
+	if(c != ' ')
+		error(w, "event number syntax");
+	return n;
+}
+
+static int
+geter(Win *w, CFid *efd, char *buf, int *nb)
+{
+	Rune r;
+	int n;
+
+	r = getec(w, efd);
+	buf[0] = r;
+	n = 1;
+	if(r < Runeself)
+		goto Return;
+	while(!fullrune(buf, n))
+		buf[n++] = getec(w, efd);
+	chartorune(&r, buf);
+    Return:
+	*nb = n;
+	return r;
+}
+
+static void
+gete(Win *w, CFid *efd, Event *e)
+{
+	int i, nb;
+
+	e->c1 = getec(w, efd);
+	e->c2 = getec(w, efd);
+	e->q0 = geten(w, efd);
+	e->q1 = geten(w, efd);
+	e->flag = geten(w, efd);
+	e->nr = geten(w, efd);
+	if(e->nr > EVENTSIZE)
+		error(w, "event string too long");
+	e->nb = 0;
+	for(i=0; i<e->nr; i++){
+		/* e->r[i] = */ geter(w, efd, e->text+e->nb, &nb);
+		e->nb += nb;
+	}
+/* 	e->r[e->nr] = 0; */
+	e->text[e->nb] = 0;
+	if(getec(w, efd) != '\n')
+		error(w, "event syntax 2");
+}
+
+int
+winreadevent(Win *w, Event *e)
+{
+	CFid *efd;
+	int r;
+
+	if((r = setjmp(w->jmp)) != 0){
+		if(r == 1)
+			return 0;
+		return -1;
+	}
+	efd = wfid(w, "event");
+	gete(w, efd, e);
+
+	/* expansion */
+	if(e->flag&2){
+		gete(w, efd, &w->e2);
+		if(e->q0==e->q1){
+			w->e2.flag = e->flag;
+			*e = w->e2;
+		}
+	}
+
+	/* chorded argument */
+	if(e->flag&8){
+		gete(w, efd, &w->e3);	/* arg */
+		gete(w, efd, &w->e4);	/* location */
+		strcpy(e->arg, w->e3.text);
+		strcpy(e->loc, w->e4.text);
+	}
+
+	return 1;
+}
+
+int
+eventfmt(Fmt *fmt)
+{
+	Event *e;
+
+	e = va_arg(fmt->args, Event*);
+	return fmtprint(fmt, "%c%c %d %d %d %d %q", e->c1, e->c2, e->q0, e->q1, e->flag, e->nr, e->text);
+}
+
+void*
+emalloc(uint n)
+{
+	void *v;
+
+	v = mallocz(n, 1);
+	if(v == nil)
+		sysfatal("out of memory");
+	return v;
+}
+
+void*
+erealloc(void *v, uint n)
+{
+	v = realloc(v, n);
+	if(v == nil)
+		sysfatal("out of memory");
+	return v;
+}
+
+char*
+estrdup(char *s)
+{
+	s = strdup(s);
+	if(s == nil)
+		sysfatal("out of memory");
+	return s;
+}
+
+char*
+evsmprint(char *s, va_list v)
+{
+	s = vsmprint(s, v);
+	if(s == nil)
+		sysfatal("out of memory");
+	return s;
+}
+
+int
+pipewinto(Win *w, char *name, int errto, char *cmd, ...)
+{
+	va_list arg;
+	char *p;
+	int fd[3], pid;
+
+	va_start(arg, cmd);
+	p = evsmprint(cmd, arg);
+	va_end(arg);
+	fd[0] = winfd(w, name, OREAD);
+	fd[1] = dup(errto, -1);
+	fd[2] = dup(errto, -1);
+	pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
+	free(p);
+	return pid;
+}
+
+int
+pipetowin(Win *w, char *name, int errto, char *cmd, ...)
+{
+	va_list arg;
+	char *p;
+	int fd[3], pid;
+
+	va_start(arg, cmd);
+	p = evsmprint(cmd, arg);
+	va_end(arg);
+	fd[0] = open("/dev/null", OREAD);
+	fd[1] = winfd(w, name, OWRITE);
+	if(errto == 0)
+		fd[2] = dup(fd[1], -1);
+	else
+		fd[2] = dup(errto, -1);
+	pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
+	free(p);
+	return pid;
+}
+
+char*
+sysrun(char *fmt, ...)
+{
+	static char buf[1024];
+	char *cmd;
+	va_list arg;
+	int n, fd[3], p[2], tot;
+
+#undef pipe
+	if(pipe(p) < 0)
+		sysfatal("pipe: %r");
+	fd[0] = open("/dev/null", OREAD);
+	fd[1] = p[1];
+	fd[2] = dup(p[1], -1);
+
+	va_start(arg, fmt);
+	cmd = evsmprint(fmt, arg);
+	va_end(arg);
+	threadspawnl(fd, "rc", "rc", "-Ic", cmd, 0);
+
+	tot = 0;
+	while((n = read(p[0], buf+tot, sizeof buf-tot)) > 0)
+		tot += n;
+	close(p[0]);
+	if(n < 0)
+		return nil;
+	free(cmd);
+	if(tot == sizeof buf)
+		tot--;
+	buf[tot] = 0;
+	while(tot > 0 && isspace(buf[tot-1]))
+		tot--;
+	buf[tot] = 0;
+	if(tot == 0){
+		werrstr("no output");
+		return nil;
+	}
+	return buf;
+}
+
+static void
+eventreader(void *v)
+{
+	Event e[2];
+	Win *w;
+	int i;
+	
+	w = v;
+	i = 0;
+	for(;;){
+		if(winreadevent(w, &e[i]) <= 0)
+			break;
+		sendp(w->c, &e[i]);
+		i = 1-i;	/* toggle */
+	}
+	sendp(w->c, nil);
+	threadexits(nil);
+}
+
+Channel*
+wineventchan(Win *w)
+{
+	if(w->c == nil){
+		w->c = chancreate(sizeof(Event*), 0);
+		threadcreate(eventreader, w, 32*1024);
+	}
+	return w->c;
+}
blob - /dev/null
blob + 4b576c6001f1dd3506bdcf4d60d175114762ae9e (mode 644)
--- /dev/null
+++ src/libacme/mkfile
@@ -0,0 +1,13 @@
+<$PLAN9/src/mkhdr
+
+LIB=libacme.a
+
+OFILES=\
+	acme.$O\
+
+HFILES=\
+	$PLAN9/include/acme.h\
+
+<$PLAN9/src/mksyslib
+
+