summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c456
1 files changed, 454 insertions, 2 deletions
diff --git a/main.c b/main.c
index 9b06577..a2bf780 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,460 @@
#include <u.h>
#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include <draw.h>
+
+#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);
}