aboutsummaryrefslogtreecommitdiff
path: root/src/libacme/acme.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-05-25 06:25:28 +0000
committerrsc <devnull@localhost>2006-05-25 06:25:28 +0000
commitf3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6 (patch)
treeda260702524241156de68695021820397e83f1ac /src/libacme/acme.c
parent603d6d896f9932b125b240fe4da82f7a41012a62 (diff)
downloadplan9port-f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6.tar.gz
plan9port-f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6.tar.bz2
plan9port-f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6.zip
new libacme
Diffstat (limited to 'src/libacme/acme.c')
-rw-r--r--src/libacme/acme.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/src/libacme/acme.c b/src/libacme/acme.c
new file mode 100644
index 00000000..35d222d5
--- /dev/null
+++ b/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;
+}