commit f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6 from: rsc date: Thu May 25 06:25:28 2006 UTC new libacme 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 +#include +#include +#include <9pclient.h> +#include + +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; inr; 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 + +