diff options
-rw-r--r-- | btsd.c | 71 | ||||
-rw-r--r-- | dat.h | 23 | ||||
-rw-r--r-- | fns.h | 7 | ||||
-rw-r--r-- | mkfile | 1 | ||||
-rw-r--r-- | parse.c | 96 | ||||
-rw-r--r-- | util.c | 6 |
6 files changed, 182 insertions, 22 deletions
@@ -8,6 +8,25 @@ #include "dat.h" #include "fns.h" +enum { + CMid, + CMplay, + CMlayout, + CMshoot, + CMgetmatches, + CMwatch, + CMleave, +}; +Cmdtab clcmd[] = { + CMid, "id", 2, + CMplay, "play", 1, + CMlayout, "layout", 2, + CMshoot, "shoot", 2, + CMgetmatches, "watch", 1, + CMwatch, "watch", 2, + CMleave, "leave", 1, +}; + int debug; Channel *playerq; @@ -195,8 +214,10 @@ playerproc(void *arg) { Player *my; Match *m; - char *s, *f[2]; - int nf, mid; + Cmdbuf *cb; + Cmdtab *ct; + char *s; + int mid; my = arg; @@ -220,27 +241,30 @@ playerproc(void *arg) if(debug) fprint(2, "[%d] rcvd '%s'\n", getpid(), s); + cb = parsecmd(s, strlen(s)); + ct = lookupcmd(cb, clcmd, nelem(clcmd)); + if(ct == nil) + goto Nocmd; + if(my->name[0] == 0){ - nf = tokenize(s, f, nelem(f)); - if(nf == 2 && strcmp(f[0], "id") == 0 && strlen(f[1]) > 0) - snprint(my->name, sizeof my->name, "%s", f[1]); + if(ct->index == CMid && strlen(cb->f[1]) > 0) + snprint(my->name, sizeof my->name, "%s", cb->f[1]); else chanprint(my->io.out, "id\n"); }else switch(my->state){ case Waiting0: - nf = tokenize(s, f, nelem(f)); - if(nf == 1 && strcmp(f[0], "play") == 0) + if(ct->index == CMplay) sendp(playerq, my); - else if(nf == 1 && strcmp(f[0], "watch") == 0){ + else if(ct->index == CMgetmatches){ rlock(&theaterlk); chanprint(my->io.out, "matches\n"); for(m = theater.next; m != &theater; m = m->next) - chanprint(my->io.out, "%d %s %s\n", m->id, m->pl[0]->name, m->pl[1]->name); + chanprint(my->io.out, "m %d %s %s\n", m->id, m->pl[0]->name, m->pl[1]->name); chanprint(my->io.out, "end\n"); runlock(&theaterlk); - }else if(nf == 2 && strcmp(f[0], "watch") == 0){ - mid = strtoul(f[1], nil, 10); + }else if(ct->index == CMwatch){ + mid = strtoul(cb->f[1], nil, 10); m = getmatch(mid); if(m == nil) chanprint(my->io.out, "no such match\n"); @@ -249,14 +273,15 @@ playerproc(void *arg) } break; case Watching: - nf = tokenize(s, f, nelem(f)); - if(nf == 1 && strcmp(f[0], "leave") == 0) + if(ct->index == CMleave) sendp(my->battle->ctl, newmsg(my, estrdup("leave seat"))); break; default: if(my->battle != nil) sendp(my->battle->data, newmsg(my, estrdup(s))); } +Nocmd: + free(cb); free(s); break; case CTL: @@ -288,11 +313,11 @@ battleproc(void *arg) { Msg *msg; Match *m; + Cmdbuf *cb; + Cmdtab *ct; Player *p, *op; Stands stands; - char *f[2]; uint n0; - int nf; Point2 cell; char *coords[5]; @@ -324,12 +349,15 @@ battleproc(void *arg) p = msg->from; op = p == m->pl[0]? m->pl[1]: m->pl[0]; - nf = tokenize(msg->body, f, nelem(f)); + cb = parsecmd(msg->body, strlen(msg->body)); + ct = lookupcmd(cb, clcmd, nelem(clcmd)); + if(ct == nil) + goto Nocmd; switch(p->state){ case Outlaying: - if(nf == 2 && strcmp(f[0], "layout") == 0) - if(gettokens(f[1], coords, nelem(coords), ",") == nelem(coords)){ + if(ct->index == CMlayout) + if(gettokens(cb->f[1], coords, nelem(coords), ",") == nelem(coords)){ if(debug) fprint(2, "rcvd layout from %s @ %s\n", p->name, p->nci->raddr); for(i = 0; i < nelem(coords); i++){ @@ -355,8 +383,8 @@ battleproc(void *arg) } break; case Playing: - if(nf == 2 && strcmp(f[0], "shoot") == 0){ - cell = coords2cell(f[1]); + if(ct->index == CMshoot){ + cell = coords2cell(cb->f[1]); switch(gettile(op, cell)){ case Tship: settile(op, cell, Thit); @@ -389,7 +417,8 @@ Swapturn: } break; } - +Nocmd: + free(cb); freemsg(msg); break; case CTL: @@ -129,9 +129,30 @@ struct Menulist char *title; Rectangle r, sr; /* content and scroll rects */ int high; /* [-1,nitems) where -1 is none */ + int off; /* entry offset ∈ [0, nitems-Maxvisitems] */ void (*add)(Menulist*, int, char*); void (*clear)(Menulist*); - void (*update)(Menulist*, Mousectl*); + int (*update)(Menulist*, Mousectl*, Channel*); void (*draw)(Menulist*, Image*); }; + +/* + * Kernel-style command parser + */ +typedef struct Cmdbuf Cmdbuf; +typedef struct Cmdtab Cmdtab; + +struct Cmdbuf +{ + char *buf; + char **f; + int nf; +}; + +struct Cmdtab +{ + int index; /* used by client to switch on result */ + char *cmd; /* command name */ + int narg; /* expected #args; 0 ==> variadic */ +}; @@ -22,9 +22,16 @@ int shiplen(int); char *shipname(int); char *statename(int); int max(int, int); +int min(int, int); /* * menulist */ Menulist *newmenulist(int, char*); void delmenulist(Menulist*); + +/* + * parse + */ +Cmdbuf *parsecmd(char*, int); +Cmdtab *lookupcmd(Cmdbuf*, Cmdtab*, int); @@ -8,6 +8,7 @@ TARG=\ OFILES=\ alloc.$O\ + parse.$O\ util.$O\ menulist.$O\ @@ -0,0 +1,96 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <mouse.h> +#include <keyboard.h> +#include <geometry.h> +#include "dat.h" +#include "fns.h" + + +/* + * Generous estimate of number of fields, including terminal nil pointer + */ +static int +ncmdfield(char *p, int n) +{ + int white, nwhite; + char *ep; + int nf; + + if(p == nil) + return 1; + + nf = 0; + ep = p+n; + white = 1; /* first text will start field */ + while(p < ep){ + nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */ + if(white && !nwhite) /* beginning of field */ + nf++; + white = nwhite; + } + return nf+1; /* +1 for nil */ +} + +/* + * parse a command written to a device + */ +Cmdbuf * +parsecmd(char *p, int n) +{ + Cmdbuf *cb; + int nf; + char *sp; + + nf = ncmdfield(p, n); + + /* allocate Cmdbuf plus string pointers plus copy of string including \0 */ + sp = emalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1); + cb = (Cmdbuf*)sp; + cb->f = (char**)(&cb[1]); + cb->buf = (char*)(&cb->f[nf]); + + memmove(cb->buf, p, n); + + /* dump new line and null terminate */ + if(n > 0 && cb->buf[n-1] == '\n') + n--; + cb->buf[n] = '\0'; + + cb->nf = tokenize(cb->buf, cb->f, nf-1); + cb->f[cb->nf] = nil; + + return cb; +} + +/* + * Look up entry in table + */ +Cmdtab * +lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab) +{ + int i; + Cmdtab *ct; + + if(cb->nf == 0){ + werrstr("empty command"); + return nil; + } + + for(ct = ctab, i=0; i<nctab; i++, ct++){ + if(strcmp(ct->cmd, cb->f[0]) != 0) + continue; + if(ct->narg != 0 && ct->narg != cb->nf){ +// werrstr("wrong #args in command"); +// return nil; + /* allow the same cmd name for different commands */ + continue; + } + return ct; + } + + werrstr("unknown command"); + return nil; +} @@ -147,3 +147,9 @@ max(int a, int b) { return a > b? a: b; } + +int +min(int a, int b) +{ + return a < b? a: b; +} |