From 7c6a945996a1d5510ff1412320ac7d07a0f82851 Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Sun, 11 Feb 2024 00:04:31 +0000 Subject: Start working on it --- main.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 454 insertions(+), 2 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 9b06577..a2bf780 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,460 @@ #include #include +#include +#include +#include <9p.h> +#include + +#include "guifs.h" + +#define Eexist "file does not exist" +#define Enodir "not a directory" +#define Eperm "permission denied" +#define Eoffset "can't write to this file at non-zero offset" +#define Ebadctl "bad ctl message" + +char *username; + +enum { + Qdir, + Qclone, + Qevent, + Qtype, + Qprops, + + Qprop, +}; + +enum { + Fclone, + Fevent, + Ftype, + Fprops, + Fmax, +}; + +GuiElement *root; + +#define QID_TYPE(q) ((q.path) & 0xFF) +#define QID_PROP(q) (((q.path) >> 8) & 0xFF) + +void * +emalloc(ulong size) +{ + void *p = mallocz(size, 1); + if(!p) + sysfatal("malloc failed"); + return p; +} + +void * +erealloc(void *p, ulong size) +{ + p = realloc(p, size); + if(!p) + sysfatal("realloc failed"); + return p; +} + +Qid +mkqid(int type) +{ + static int id = 0; + + Qid q; + q.vers = 0; + q.path = (type & 0xFFFF) | (id << 16); + id++; + switch(type){ + case Qdir: + case Qprops: + q.type = QTDIR; + break; + case Qclone: + case Qevent: + case Qtype: + q.type = QTFILE; + break; + } + return q; +} + +Qid +mkpropqid(int proptag) +{ + return mkqid(Qprop | ((proptag & 0xFF) << 8)); +} + +void +settype(GuiElement *g, int type) +{ + GuiSpec spec = guispecs[type]; + free(g->props); + g->type = type; + + g->nprops = spec.nprops; + g->props = emalloc(sizeof(Prop) * spec.nprops); + for(int i = 0; i < spec.nprops; i++){ + int tag = spec.proptags[i]; + g->props[i].tag = tag; + g->props[i].val = propspecs[tag].def(); + g->props[i].qid = mkpropqid(tag); + } + + updategui(0); /* redraw everything */ +} + +GuiElement * +newgui(GuiElement *parent) +{ + GuiElement *g = emalloc(sizeof(GuiElement)); + memset(g, 0, sizeof(GuiElement)); + g->parent = parent; + g->qid = mkqid(Qdir); + g->qclone = mkqid(Qclone); + g->qevent = mkqid(Qevent); + g->qtype = mkqid(Qtype); + g->qprops = mkqid(Qprops); + + if(parent){ + g->id = parent->nchildren; + parent->nchildren++; + parent->children = erealloc(parent->children, parent->nchildren * sizeof(GuiElement *)); + parent->children[g->id] = g; + } + + settype(g, Gcontainer); + + return g; +} + +GuiElement * +findchild(GuiElement *g, char *name) +{ + char *r; + uvlong id = strtoull(name, &r, 10); + if(*r != 0){ + return nil; + } + + if(id < g->nchildren) + return g->children[id]; + + return nil; +} void -main(void) +fsattach(Req *r) { - print("hello\n"); + if(root == nil){ + GuiElement *g = newgui(nil); + root = g; + settype(g, Gcontainer); + } + + r->fid->aux = root; + r->fid->qid = root->qid; + r->ofcall.qid = r->fid->qid; + + respond(r, nil); +} + +char * +fswalk1(Fid *fid, char *name, Qid *qid) +{ + GuiElement *g = fid->aux; + GuiElement *child; + + switch(QID_TYPE(fid->qid)){ + case Qdir: + if(strcmp(name, "..") == 0){ + if(g->parent == nil) // Root element + *qid = g->qid; + else{ + fid->aux = g->parent; + *qid = g->parent->qid; + } + return nil; + }else if(strcmp(name, "clone") == 0){ + *qid = g->qclone; + return nil; + }else if(strcmp(name, "event") == 0){ + *qid = g->qevent; + return nil; + }else if(strcmp(name, "type") == 0){ + *qid = g->qtype; + return nil; + }else if(strcmp(name, "props") == 0){ + *qid = g->qprops; + return nil; + }else if(child = findchild(g, name)){ + fid->aux = child; + *qid = child->qid; + return nil; + } + return Eexist; + case Qprops: + if(strcmp(name, "..") == 0){ + *qid = g->qid; + return nil; + } + for(int i = 0; i < g->nprops; i++){ + PropSpec spec = propspecs[g->props[i].tag]; + if(strcmp(name, spec.name) == 0){ + *qid = g->props[i].qid; + return nil; + } + } + return Eexist; + default: + return Enodir; + } +} + +char * +fsclone(Fid *old, Fid *new) +{ + new->aux = old->aux; + return nil; +} + +void +fsopen(Req *r) +{ + GuiElement *g = r->fid->aux; + + switch(QID_TYPE(r->fid->qid)){ + case Qdir: + case Qevent: + case Qclone: + case Qprops: + if(r->ifcall.mode != OREAD){ + respond(r, Eperm); + return; + } + break; + } + + if(QID_TYPE(r->fid->qid) == Qclone){ + /* Create a new child gui element */ + GuiElement *child = newgui(g); + + assert(r->fid->qid.vers == child->id); + + /* Update qid version, so a read reports the correct child id */ + assert(memcmp(&r->fid->qid, &g->qclone, sizeof(Qid)) == 0); + g->qclone.vers++; + r->fid->qid = g->qclone; + r->ofcall.qid = g->qclone; + } + + respond(r, nil); +} + +void +fsstat(Req *r) +{ + r->d.qid = r->fid->qid; + r->d.uid = estrdup9p(username); + r->d.gid = estrdup9p(username); + r->d.muid = estrdup9p(username); + switch(QID_TYPE(r->fid->qid)){ + case Qdir: + r->d.name = estrdup9p("/"); + r->d.mode = 0555|DMDIR; + break; + case Qprops: + r->d.name = estrdup9p("/"); + r->d.mode = 0555|DMDIR; + break; + } + + respond(r, nil); +} + +int +dirtreegen(int n, Dir *d, void *aux) +{ + GuiElement *g = aux; + + d->uid = estrdup9p(username); + d->gid = estrdup9p(username); + d->muid = estrdup9p(username); + + if(n < Fmax){ + d->length = 0; + + switch(n){ + case Fclone: + d->mode = 0444; + d->name = estrdup9p("clone"); + d->qid = g->qclone; + break; + case Fevent: + d->mode = 0444; + d->name = estrdup9p("event"); + d->qid = g->qevent; + break; + case Ftype: + d->mode = 0666; + d->name = estrdup9p("type"); + d->qid = g->qtype; + break; + case Fprops: + d->mode = 0555|DMDIR; + d->name = estrdup9p("props"); + d->qid = g->qprops; + break; + } + return 0; + }else + n -= Fmax; + + if(g && n < g->nchildren){ + GuiElement *child = g->children[n]; + + d->mode = DMDIR|0555; + d->qid = child->qid; + + char buf[64]; + snprint(buf, sizeof(buf), "%d", child->id); + d->name = estrdup9p(buf); + return 0; + } + + return -1; +} + +int +proptreegen(int n, Dir *d, void *aux) +{ + GuiElement *g = aux; + + d->uid = estrdup9p(username); + d->gid = estrdup9p(username); + d->muid = estrdup9p(username); + + if(n >= g->nprops) + return -1; + + PropSpec spec = propspecs[g->props[n].tag]; + d->mode = 0666; + d->name = estrdup9p(spec.name); + d->qid = g->props[n].qid; + return 0; +} + +void +fsread(Req *r) +{ + GuiElement *g = r->fid->aux; + char buf[256]; + + switch(QID_TYPE(r->fid->qid)){ + case Qdir: + dirread9p(r, dirtreegen, g); + break; + case Qclone: + snprint(buf, sizeof(buf), "%uld\n", r->fid->qid.vers-1); + readstr(r, buf); + break; + case Qevent: + /* in another thread, wait for events on a channel + * and call readstr on each of them individually. + */ + readstr(r, "eveeent\n"); + break; + case Qtype: + snprint(buf, sizeof(buf), "%s\n", guispecs[g->type].name); + readstr(r, buf); + break; + case Qprops: + dirread9p(r, proptreegen, g); + break; + case Qprop: + { + int tag = QID_PROP(r->fid->qid); + PropSpec spec = propspecs[tag]; + PropVal val = getprop(g, tag); + char *str = spec.print(val); + readstr(r, str); + free(str); + } + break; + } + respond(r, nil); +} + +void +fswrite(Req *r) +{ + GuiElement *g = r->fid->aux; + char *err = nil; + + switch(QID_TYPE(r->fid->qid)){ + case Qtype: + err = "Can't switch type"; + break; + case Qprop: + { + int tag = QID_PROP(r->fid->qid); + PropSpec spec = propspecs[tag]; + PropVal val; + + char *buf = emalloc(r->ifcall.count + 1); + buf[r->ifcall.count] = 0; + memcpy(buf, r->ifcall.data, r->ifcall.count); + err = spec.parse(buf, &val); + if(err == nil) + setprop(g, tag, val); + free(buf); + } + } + + respond(r, err); +} + +Srv fs = { + .attach = fsattach, + .walk1 = fswalk1, + .clone = fsclone, + .open = fsopen, + .stat = fsstat, + .read = fsread, + .write = fswrite, +}; + +void +usage(void) +{ + fprint(2, "usage: %s [-D] [-m mountpoint] [-s srvname] \n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char **argv) +{ + char *mtpt = "/mnt/gui"; + char *srvname = nil; + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 'm': + mtpt = EARGF(usage()); + break; + case 's': + srvname = EARGF(usage()); + break; + default: + usage(); + }ARGEND; + + if(argc > 1) + usage(); + + username = getuser(); + initgraphics(); + threadpostmountsrv(&fs, srvname, mtpt, MREPL); + exits(nil); } -- cgit v1.2.3