tnew libacme - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit f3b8bf7f4ee326d9de31947584c6e9dbbfa75ce6
 (DIR) parent 603d6d896f9932b125b240fe4da82f7a41012a62
 (HTM) Author: rsc <devnull@localhost>
       Date:   Thu, 25 May 2006 06:25:28 +0000
       
       new libacme
       
       Diffstat:
         A include/acme.h                      |      76 +++++++++++++++++++++++++++++++
         A src/libacme/acme.c                  |     588 +++++++++++++++++++++++++++++++
         A src/libacme/mkfile                  |      13 +++++++++++++
       
       3 files changed, 677 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/include/acme.h b/include/acme.h
       t@@ -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);
 (DIR) diff --git a/src/libacme/acme.c b/src/libacme/acme.c
       t@@ -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;
       +}
 (DIR) diff --git a/src/libacme/mkfile b/src/libacme/mkfile
       t@@ -0,0 +1,13 @@
       +<$PLAN9/src/mkhdr
       +
       +LIB=libacme.a
       +
       +OFILES=\
       +        acme.$O\
       +
       +HFILES=\
       +        $PLAN9/include/acme.h\
       +
       +<$PLAN9/src/mksyslib
       +
       +